Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions src/cli/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,17 @@ export function maskApiKey(key: string): string {
if (key.length <= 8) return "****";
return key.slice(0, 4) + "****" + key.slice(-4);
}

export async function loadConfigFromFile(filePath: string): Promise<StoredConfig> {
const content = await readFile(filePath, "utf-8");
const importedConfig = JSON.parse(content) as StoredConfig;
return importedConfig;
}

export async function mergeConfigFromFile(filePath: string): Promise<StoredConfig> {
const importedConfig = await loadConfigFromFile(filePath);
const existingConfig = await loadStoredConfig();
const mergedConfig = { ...existingConfig, ...importedConfig };
await saveStoredConfig(mergedConfig);
return mergedConfig;
}
48 changes: 43 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ import {
saveStoredConfig,
getConfigPath,
maskApiKey,
mergeConfigFromFile,
type StoredConfig,
} from "./cli/config.js";
import type { AIProvider } from "./config.js";

interface CliArgs {
command: "run" | "config" | "cluster";
configAction?: "set" | "get" | "list" | "path";
configAction?: "set" | "get" | "list" | "path" | "load";
configKey?: string;
configValue?: string;
configFilePath?: string;
clusterAction?: "add" | "remove" | "list" | "use" | "status";
clusterName?: string;
clusterContext?: string;
Expand All @@ -46,9 +48,13 @@ function parseArgs(): CliArgs {
// Check for config subcommand
if (args[0] === "config") {
result.command = "config";
result.configAction = args[1] as "set" | "get" | "list" | "path";
result.configKey = args[2];
result.configValue = args[3];
result.configAction = args[1] as "set" | "get" | "list" | "path" | "load";
if (result.configAction === "load") {
result.configFilePath = args[2];
} else {
result.configKey = args[2];
result.configValue = args[3];
}
return result;
}

Expand Down Expand Up @@ -116,6 +122,7 @@ CONFIG COMMANDS:
triagent config get <key> Get a configuration value
triagent config list List all configuration values
triagent config path Show config file path
triagent config load <file> Load configuration from a JSON file

CONFIG KEYS:
aiProvider - AI provider (openai, anthropic, google)
Expand Down Expand Up @@ -453,8 +460,39 @@ async function handleConfigCommand(args: CliArgs): Promise<void> {
console.log(path);
break;
}
case "load": {
if (!args.configFilePath) {
console.error("Usage: triagent config load <file>");
process.exit(1);
}
try {
const mergedConfig = await mergeConfigFromFile(args.configFilePath);
console.log(`✅ Configuration loaded from ${args.configFilePath}`);
console.log("\nMerged configuration:");
for (const [key, value] of Object.entries(mergedConfig)) {
if (value === undefined) continue;
if (key === "apiKey") {
console.log(` ${key}: ${maskApiKey(String(value))}`);
} else if (typeof value === "object") {
console.log(` ${key}: ${JSON.stringify(value)}`);
} else {
console.log(` ${key}: ${value}`);
}
}
} catch (error) {
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
console.error(`❌ File not found: ${args.configFilePath}`);
} else if (error instanceof SyntaxError) {
console.error(`❌ Invalid JSON in file: ${args.configFilePath}`);
} else {
console.error(`❌ Failed to load config: ${error}`);
}
process.exit(1);
}
break;
}
default:
console.error("Usage: triagent config <set|get|list|path> [key] [value]");
console.error("Usage: triagent config <set|get|list|path|load> [key] [value]");
process.exit(1);
}
}
Expand Down
Loading