## 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>
187 lines
5.2 KiB
TypeScript
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;
|