mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 02:29:33 +01:00
The owner's answer to the PR's open question: the switch does not also pass --sandbox workspace-write. Settings, wiki, skill and release note now state the consequence: a folder Codex runs read-only keeps the network closed and asks per command. A golden test pins the decision by name, and the stale launch-defaults comments now name networkAccess. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
50 lines
2.5 KiB
TypeScript
50 lines
2.5 KiB
TypeScript
/**
|
|
* @fileoverview Launch-time defaults from synced App Settings, driven by registry data.
|
|
*
|
|
* A CLI entry declares `capabilities.launchDefaults` (launch param -> settings key; today
|
|
* only codex: `model`, `reasoningEffort` and `networkAccess`), and
|
|
* `applyLaunchDefaults()` fills those settings into the entry's `launch.legacyConfigField`
|
|
* object, setting ONLY the fields the caller left unset. Persisted values are re-validated
|
|
* with `SettingsUpdateSchema`, so a hand-edited settings.json can never smuggle an
|
|
* unchecked value onto the command line.
|
|
*
|
|
* Scope is the caller's decision: the create and quick-start routes apply it to local
|
|
* launches only, never to remote, Docker or custom-endpoint launches. Nothing here writes
|
|
* a CLI's own config files.
|
|
*/
|
|
|
|
import { getCli } from '../config/cli-registry/registry.js';
|
|
import { SettingsUpdateSchema } from './schemas.js';
|
|
import { readJsonConfig, SETTINGS_PATH } from './route-helpers.js';
|
|
|
|
/**
|
|
* Return `configs` with the launch defaults of `mode`'s registry entry filled into its
|
|
* legacy config object (e.g. `codexConfig`). Every other field of `configs` is passed
|
|
* through untouched, and `configs` itself comes back unchanged (same object) when the entry
|
|
* declares no defaults, `customEndpoint` is set, or no setting names a value.
|
|
*/
|
|
export async function applyLaunchDefaults<T extends object>(
|
|
mode: string,
|
|
configs: T,
|
|
customEndpoint = false
|
|
): Promise<T> {
|
|
const entry = getCli(mode);
|
|
const declared = entry?.capabilities.launchDefaults;
|
|
const field = entry?.launch.legacyConfigField;
|
|
if (customEndpoint || !declared || field === undefined) return configs;
|
|
|
|
const settings = await readJsonConfig<Record<string, unknown>>(SETTINGS_PATH, 'CLI launch defaults', {});
|
|
const aliases = entry.launch.legacyConfigAliases ?? {};
|
|
const current = (configs as Record<string, unknown>)[field] as Record<string, unknown> | undefined;
|
|
const defaults: Record<string, unknown> = {};
|
|
for (const [param, settingKey] of Object.entries(declared)) {
|
|
const parsed = SettingsUpdateSchema.shape[settingKey].safeParse(settings[settingKey]);
|
|
// '' and an off switch are the settings' "leave it to the CLI" value, the same as unset.
|
|
const value = parsed.success ? parsed.data || undefined : undefined;
|
|
const wireKey = aliases[param] ?? param;
|
|
if (value !== undefined && (current?.[wireKey] ?? undefined) === undefined) defaults[wireKey] = value;
|
|
}
|
|
if (Object.keys(defaults).length === 0) return configs;
|
|
return { ...configs, [field]: { ...current, ...defaults } };
|
|
}
|