Description
In main() (index.mjs:628-647), the config file is written up to 3 times in a single run:
- Line 628 —
saveConfig(config, configPath) — always executed.
- Line 637 —
writeFile(configPath, ...) — if --select-agents flag is set.
- Line 647 —
writeFile(configPath, ...) — if --custom-costs flag is set.
Code references
// index.mjs:628 — first write (always)
await saveConfig(config, configPath);
// index.mjs:633-639 — second write (conditional)
if (cliArgs["select-agents"]) {
const updated = await selectAgentModels(config, modelNames, "nexos-ai");
if (updated) {
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
}
}
// index.mjs:641-647 — third write (conditional)
if (cliArgs["custom-costs"]) {
const updated = await configureCustomCosts(config, modelNames, "nexos-ai", supportedModelsOnly);
if (updated) {
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
}
}
Impact
- The first write at line 628 is always wasted when either
--select-agents or --custom-costs is used, because those modes mutate the config object in-place and then write again.
- The second write (line 637) includes incomplete data when
--custom-costs is also used — the custom costs haven't been applied yet.
- Lines 637 and 647 duplicate the serialization logic from
serializeConfig() — they inline JSON.stringify(config, null, 2) + "\n" instead of using the existing helper.
- Three sequential writes to the same file means three
fsync operations (depending on OS), which is unnecessary.
Proposed fix
Move the single write to the end of main(), after all interactive configuration is complete:
// Process models, select agents, configure costs...
// Then write once:
await saveConfig(config, configPath);
Alternatively, if intermediate saves are desired for crash safety during interactive modes, at minimum deduplicate using saveConfig() and skip the initial write when interactive flags are present.
Acceptance criteria
Test cases
test("should write config exactly once with --select-agents", async () => {
// Setup: mock API, mock prompts for agent selection
process.argv = ["node", "index.mjs", "--select-agents"];
// ... setup mocks, mock prompts return selections
await main();
const configWrites = mockWriteFile.mock.calls.filter(
([path]) => path.includes("opencode.json")
);
expect(configWrites).toHaveLength(1);
// Verify the single write contains agent configuration
const writtenConfig = JSON.parse(configWrites[0][1]);
expect(writtenConfig.agent).toBeDefined();
});
test("should write config exactly once with --select-agents --custom-costs", async () => {
process.argv = ["node", "index.mjs", "--select-agents", "--custom-costs"];
// ... setup mocks
await main();
const configWrites = mockWriteFile.mock.calls.filter(
([path]) => path.includes("opencode.json")
);
expect(configWrites).toHaveLength(1);
// Verify the single write contains both agent and cost data
const writtenConfig = JSON.parse(configWrites[0][1]);
expect(writtenConfig.agent).toBeDefined();
expect(writtenConfig.provider["nexos-ai"].models).toBeDefined();
});
🤖 Generated with Claude Code
Description
In
main()(index.mjs:628-647), the config file is written up to 3 times in a single run:saveConfig(config, configPath)— always executed.writeFile(configPath, ...)— if--select-agentsflag is set.writeFile(configPath, ...)— if--custom-costsflag is set.Code references
Impact
--select-agentsor--custom-costsis used, because those modes mutate theconfigobject in-place and then write again.--custom-costsis also used — the custom costs haven't been applied yet.serializeConfig()— they inlineJSON.stringify(config, null, 2) + "\n"instead of using the existing helper.fsyncoperations (depending on OS), which is unnecessary.Proposed fix
Move the single write to the end of
main(), after all interactive configuration is complete:Alternatively, if intermediate saves are desired for crash safety during interactive modes, at minimum deduplicate using
saveConfig()and skip the initial write when interactive flags are present.Acceptance criteria
--select-agents --custom-costs, the config file is written exactly once (after all interactive steps complete).serializeConfig()helper is used for all writes (no inlineJSON.stringify).Test cases
🤖 Generated with Claude Code