Files
zclaw_openfang/desktop/src/lib/toml-utils.ts
iven 3e81bd3e50 feat(ui): Phase 8 UI/UX optimization and system documentation update
## Sidebar Enhancement
- Change tabs to icon + small label layout for better space utilization
- Add Teams tab with team collaboration entry point

## Settings Page Improvements
- Connect theme toggle to gatewayStore.saveQuickConfig for persistence
- Remove OpenFang backend download section, simplify UI
- Add time range filter to UsageStats (7d/30d/all)
- Add stat cards with icons (sessions, messages, input/output tokens)
- Add token usage overview bar chart
- Add 8 ZCLAW system skill definitions with categories

## Bug Fixes
- Fix ChannelList duplicate content with deduplication logic
- Integrate CreateTriggerModal in TriggersPanel
- Add independent SecurityStatusPanel with 12 default enabled layers
- Change workflow view to use SchedulerPanel as unified entry

## New Components
- CreateTriggerModal: Event trigger creation modal
- HandApprovalModal: Hand approval workflow dialog
- HandParamsForm: Enhanced Hand parameter form
- SecurityLayersPanel: 16-layer security status display

## Architecture
- Add TOML config parsing support (toml-utils.ts, config-parser.ts)
- Add request timeout and retry mechanism (request-helper.ts)
- Add secure token storage (secure-storage.ts, secure_storage.rs)

## Tests
- Add unit tests for config-parser, toml-utils, request-helper
- Add team-client and teamStore tests

## Documentation
- Update SYSTEM_ANALYSIS.md with Phase 8 completion
- UI completion: 100% (30/30 components)
- API coverage: 93% (63/68 endpoints)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 14:12:11 +08:00

187 lines
5.2 KiB
TypeScript

/**
* TOML Utility Functions
*
* Provides TOML parsing and serialization capabilities for OpenFang configuration files.
* Supports environment variable interpolation in the format ${VAR_NAME}.
*
* @module toml-utils
*/
import TOML from 'smol-toml';
/**
* Error class for TOML parsing errors
*/
export class TomlParseError extends Error {
constructor(
message: string,
public readonly cause?: unknown
) {
super(message);
this.name = 'TomlParseError';
}
}
/**
* Error class for TOML serialization errors
*/
export class TomlStringifyError extends Error {
constructor(
message: string,
public readonly cause?: unknown
) {
super(message);
this.name = 'TomlStringifyError';
}
}
/**
* TOML utility functions for parsing and serializing configuration files
*/
export const tomlUtils = {
/**
* Parse a TOML string into a JavaScript object
*
* @param content - The TOML string to parse
* @returns The parsed JavaScript object
* @throws TomlParseError if the TOML content is invalid
*
* @example
* ```typescript
* const config = tomlUtils.parse(`
* [server]
* host = "127.0.0.1"
* port = 4200
* `);
* // config = { server: { host: "127.0.0.1", port: 4200 } }
* ```
*/
parse: <T = Record<string, unknown>>(content: string): T => {
try {
return TOML.parse(content) as T;
} catch (error) {
console.error('[TOML] Parse error:', error);
throw new TomlParseError(
`TOML parse error: ${error instanceof Error ? error.message : String(error)}`,
error
);
}
},
/**
* Serialize a JavaScript object to a TOML string
*
* @param data - The JavaScript object to serialize
* @returns The TOML string representation
* @throws TomlStringifyError if the object cannot be serialized to TOML
*
* @example
* ```typescript
* const toml = tomlUtils.stringify({
* server: { host: "127.0.0.1", port: 4200 }
* });
* ```
*/
stringify: (data: Record<string, unknown>): string => {
try {
return TOML.stringify(data);
} catch (error) {
console.error('[TOML] Stringify error:', error);
throw new TomlStringifyError(
`TOML stringify error: ${error instanceof Error ? error.message : String(error)}`,
error
);
}
},
/**
* Resolve environment variables in TOML content
*
* Replaces ${VAR_NAME} patterns with the corresponding environment variable values.
* If the environment variable is not set, it's replaced with an empty string.
*
* Note: In browser/Tauri context, this function has limited access to environment
* variables. For full resolution, use the Tauri backend to read env vars.
*
* @param content - The TOML content with potential ${VAR_NAME} patterns
* @param envVars - Optional object containing environment variables (for testing or Tauri-provided values)
* @returns The content with environment variables resolved
*
* @example
* ```typescript
* const content = 'api_key = "${OPENAI_API_KEY}"';
* const resolved = tomlUtils.resolveEnvVars(content, { OPENAI_API_KEY: 'sk-...' });
* // resolved = 'api_key = "sk-..."'
* ```
*/
resolveEnvVars: (
content: string,
envVars?: Record<string, string | undefined>
): string => {
return content.replace(/\$\{([^}]+)\}/g, (_, varName: string) => {
// If envVars provided, use them; otherwise try to access from window or return empty
if (envVars) {
return envVars[varName] ?? '';
}
// In browser context, we can't access process.env directly
// This will be handled by passing envVars from Tauri backend
console.warn(
`[TOML] Environment variable ${varName} not resolved - no envVars provided`
);
return '';
});
},
/**
* Parse TOML content with environment variable resolution
*
* Convenience method that combines resolveEnvVars and parse.
*
* @param content - The TOML content with potential ${VAR_NAME} patterns
* @param envVars - Optional object containing environment variables
* @returns The parsed and resolved JavaScript object
*
* @example
* ```typescript
* const config = tomlUtils.parseWithEnvVars(tomlContent, {
* ZHIPU_API_KEY: 'your-api-key'
* });
* ```
*/
parseWithEnvVars: <T = Record<string, unknown>>(
content: string,
envVars?: Record<string, string | undefined>
): T => {
const resolved = tomlUtils.resolveEnvVars(content, envVars);
return tomlUtils.parse<T>(resolved);
},
/**
* Check if a string contains unresolved environment variable placeholders
*
* @param content - The content to check
* @returns true if there are unresolved ${VAR_NAME} patterns
*/
hasUnresolvedEnvVars: (content: string): boolean => {
return /\$\{[^}]+\}/.test(content);
},
/**
* Extract environment variable names from TOML content
*
* @param content - The TOML content to scan
* @returns Array of environment variable names found
*/
extractEnvVarNames: (content: string): string[] => {
const matches = content.matchAll(/\$\{([^}]+)\}/g);
const names = new Set<string>();
for (const match of matches) {
names.add(match[1]);
}
return Array.from(names);
},
};
export default tomlUtils;