agentloom 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -2
- package/dist/commands/init.js +1 -0
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.js +34 -11
- package/dist/core/codex.d.ts +3 -0
- package/dist/core/codex.js +72 -0
- package/dist/core/copy.js +6 -4
- package/dist/core/migration.js +2 -27
- package/dist/core/scope.d.ts +2 -0
- package/dist/core/scope.js +69 -8
- package/dist/sync/index.js +7 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,8 @@ npx agentloom init
|
|
|
12
12
|
|
|
13
13
|
That's all you need. Agentloom picks up your existing provider configs, migrates them into a unified `.agents/` directory, and syncs everything back out to all your tools. From here on, manage your agents, commands, rules, skills, and MCP servers in one place and run `agentloom sync` whenever you make changes.
|
|
14
14
|
|
|
15
|
+
`agentloom init` is the provider-to-canonical bootstrap step. After that, `agentloom sync` is one-way: it reads from `.agents/` and writes provider-native outputs. If you intentionally want to pull provider state back into canonical `.agents/`, rerun `agentloom init`.
|
|
16
|
+
|
|
15
17
|
## Install
|
|
16
18
|
|
|
17
19
|
```bash
|
|
@@ -200,13 +202,24 @@ claude:
|
|
|
200
202
|
model: sonnet
|
|
201
203
|
codex:
|
|
202
204
|
model: gpt-5-codex
|
|
203
|
-
|
|
204
|
-
|
|
205
|
+
model_reasoning_effort: medium
|
|
206
|
+
web_search: true
|
|
205
207
|
---
|
|
206
208
|
|
|
207
209
|
You are a strict reviewer...
|
|
208
210
|
```
|
|
209
211
|
|
|
212
|
+
For Codex, provider-native config keys are passed through to the generated
|
|
213
|
+
`.codex/agents/<role>.toml` as a thin layer. Prefer Codex's native snake_case
|
|
214
|
+
keys such as `approval_policy`, `approvals_reviewer`, or `web_search`. Existing
|
|
215
|
+
camelCase aliases like `reasoningEffort` are still normalized for
|
|
216
|
+
backward-compatibility.
|
|
217
|
+
|
|
218
|
+
Current `codex-cli 0.121.0` exposes spawn-time controls such as `fork_context` and
|
|
219
|
+
`fork_turns` only on the `spawn_agent` tool path, not in static role/config
|
|
220
|
+
files, so Codex itself will warn or ignore them if you place them under
|
|
221
|
+
`codex:` in canonical frontmatter today.
|
|
222
|
+
|
|
210
223
|
## Command schema
|
|
211
224
|
|
|
212
225
|
Canonical commands are markdown files. Frontmatter is optional. When present,
|
package/dist/commands/init.js
CHANGED
package/dist/commands/sync.d.ts
CHANGED
package/dist/commands/sync.js
CHANGED
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { parseProvidersFlag } from "../core/argv.js";
|
|
5
5
|
import { getSyncHelpText } from "../core/copy.js";
|
|
6
6
|
import { formatMigrationSummary, initializeCanonicalLayout, migrateProviderStateToCanonical, MigrationConflictError, } from "../core/migration.js";
|
|
7
|
+
import { hasInitializedCanonicalLayout, resolveScopeForSync, } from "../core/scope.js";
|
|
7
8
|
import { getNonInteractiveMode, resolvePathsForCommand, } from "./entity-utils.js";
|
|
8
9
|
import { formatSyncSummary, resolveProvidersForSync, syncFromCanonical, } from "../sync/index.js";
|
|
9
10
|
export async function runSyncCommand(argv, cwd) {
|
|
@@ -21,29 +22,42 @@ export async function runScopedSyncCommand(options) {
|
|
|
21
22
|
const nonInteractive = getNonInteractiveMode(options.argv);
|
|
22
23
|
let cleanupDryRunPaths;
|
|
23
24
|
try {
|
|
24
|
-
const
|
|
25
|
+
const shouldMigrateProviderState = Boolean(options.migrateProviderState);
|
|
26
|
+
const paths = shouldMigrateProviderState
|
|
27
|
+
? await resolvePathsForCommand(options.argv, options.cwd)
|
|
28
|
+
: await resolveScopeForSync({
|
|
29
|
+
cwd: options.cwd,
|
|
30
|
+
global: Boolean(options.argv.global),
|
|
31
|
+
local: Boolean(options.argv.local),
|
|
32
|
+
interactive: !nonInteractive,
|
|
33
|
+
});
|
|
25
34
|
const explicitProviders = parseProvidersFlag(options.argv.providers);
|
|
26
35
|
const providers = await resolveProvidersForSync({
|
|
27
36
|
paths,
|
|
28
37
|
explicitProviders,
|
|
29
38
|
nonInteractive,
|
|
30
39
|
});
|
|
40
|
+
if (!shouldMigrateProviderState) {
|
|
41
|
+
assertInitializedCanonicalStateExists(paths);
|
|
42
|
+
}
|
|
31
43
|
const dryRun = Boolean(options.argv["dry-run"]);
|
|
32
44
|
const effectivePaths = dryRun
|
|
33
45
|
? createDryRunCanonicalPaths(paths)
|
|
34
46
|
: { paths, cleanup: undefined };
|
|
35
47
|
cleanupDryRunPaths = effectivePaths.cleanup;
|
|
36
48
|
initializeCanonicalLayout(effectivePaths.paths, providers);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
if (shouldMigrateProviderState) {
|
|
50
|
+
const migrationSummary = await migrateProviderStateToCanonical({
|
|
51
|
+
paths: effectivePaths.paths,
|
|
52
|
+
providers,
|
|
53
|
+
target: options.target,
|
|
54
|
+
yes: Boolean(options.argv.yes),
|
|
55
|
+
nonInteractive,
|
|
56
|
+
dryRun,
|
|
57
|
+
materializeCanonical: dryRun,
|
|
58
|
+
});
|
|
59
|
+
console.log(formatMigrationSummary(migrationSummary));
|
|
60
|
+
}
|
|
47
61
|
if (options.skipSync) {
|
|
48
62
|
return;
|
|
49
63
|
}
|
|
@@ -69,6 +83,15 @@ export async function runScopedSyncCommand(options) {
|
|
|
69
83
|
cleanupDryRunPaths?.();
|
|
70
84
|
}
|
|
71
85
|
}
|
|
86
|
+
function assertInitializedCanonicalStateExists(paths) {
|
|
87
|
+
if (hasInitializedCanonicalLayout(paths)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const initCommand = paths.scope === "global"
|
|
91
|
+
? "agentloom init --global"
|
|
92
|
+
: "agentloom init --local";
|
|
93
|
+
throw new Error(`No initialized canonical .agents state found at ${paths.agentsRoot}.\nRun \`${initCommand}\` to bootstrap from provider configs first, or use \`agentloom add\` to create canonical content before syncing.`);
|
|
94
|
+
}
|
|
72
95
|
function createDryRunCanonicalPaths(paths) {
|
|
73
96
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "agentloom-dry-run-"));
|
|
74
97
|
const tempAgentsRoot = path.join(tempRoot, ".agents");
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function normalizeCodexConfigForToml(providerConfig: Record<string, unknown>): Record<string, unknown>;
|
|
2
|
+
export declare function cloneCodexProviderConfig(providerConfig: Record<string, unknown>): Record<string, unknown>;
|
|
3
|
+
export declare function stripManagedCodexInstructionKeys(providerConfig: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { isObject } from "./fs.js";
|
|
2
|
+
const MANAGED_INSTRUCTION_KEYS = new Set([
|
|
3
|
+
"developerInstructions",
|
|
4
|
+
"developer_instructions",
|
|
5
|
+
"modelInstructionsFile",
|
|
6
|
+
"model_instructions_file",
|
|
7
|
+
]);
|
|
8
|
+
const LEGACY_CODEX_ALIASES = {
|
|
9
|
+
approvalPolicy: "approval_policy",
|
|
10
|
+
reasoningEffort: "model_reasoning_effort",
|
|
11
|
+
reasoningSummary: "model_reasoning_summary",
|
|
12
|
+
sandboxMode: "sandbox_mode",
|
|
13
|
+
verbosity: "model_verbosity",
|
|
14
|
+
webSearch: "web_search",
|
|
15
|
+
};
|
|
16
|
+
export function normalizeCodexConfigForToml(providerConfig) {
|
|
17
|
+
const normalized = normalizeCodexValueForToml(providerConfig);
|
|
18
|
+
if (!isObject(normalized)) {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
for (const key of MANAGED_INSTRUCTION_KEYS) {
|
|
22
|
+
delete normalized[key];
|
|
23
|
+
}
|
|
24
|
+
return normalized;
|
|
25
|
+
}
|
|
26
|
+
export function cloneCodexProviderConfig(providerConfig) {
|
|
27
|
+
const cloned = cloneCodexValue(providerConfig);
|
|
28
|
+
if (!isObject(cloned)) {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
return cloned;
|
|
32
|
+
}
|
|
33
|
+
export function stripManagedCodexInstructionKeys(providerConfig) {
|
|
34
|
+
const cleaned = cloneCodexProviderConfig(providerConfig);
|
|
35
|
+
for (const key of MANAGED_INSTRUCTION_KEYS) {
|
|
36
|
+
delete cleaned[key];
|
|
37
|
+
}
|
|
38
|
+
return cleaned;
|
|
39
|
+
}
|
|
40
|
+
function normalizeCodexValueForToml(value) {
|
|
41
|
+
if (Array.isArray(value)) {
|
|
42
|
+
return value.map((entry) => normalizeCodexValueForToml(entry));
|
|
43
|
+
}
|
|
44
|
+
if (!isObject(value)) {
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
|
|
48
|
+
toSnakeCase(key),
|
|
49
|
+
normalizeCodexValueForToml(entry),
|
|
50
|
+
]));
|
|
51
|
+
}
|
|
52
|
+
function cloneCodexValue(value) {
|
|
53
|
+
if (Array.isArray(value)) {
|
|
54
|
+
return value.map((entry) => cloneCodexValue(entry));
|
|
55
|
+
}
|
|
56
|
+
if (!isObject(value)) {
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, cloneCodexValue(entry)]));
|
|
60
|
+
}
|
|
61
|
+
function toSnakeCase(key) {
|
|
62
|
+
if (Object.prototype.hasOwnProperty.call(LEGACY_CODEX_ALIASES, key)) {
|
|
63
|
+
return LEGACY_CODEX_ALIASES[key];
|
|
64
|
+
}
|
|
65
|
+
if (!/[A-Z]/.test(key)) {
|
|
66
|
+
return key;
|
|
67
|
+
}
|
|
68
|
+
return key
|
|
69
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
|
70
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
71
|
+
.toLowerCase();
|
|
72
|
+
}
|
package/dist/core/copy.js
CHANGED
|
@@ -9,11 +9,11 @@ Usage:
|
|
|
9
9
|
|
|
10
10
|
Aggregate commands:
|
|
11
11
|
add <source> Import agents/commands/mcp/rules/skills from a source
|
|
12
|
-
init Bootstrap canonical files
|
|
12
|
+
init Bootstrap canonical files from provider configs, then sync
|
|
13
13
|
find <query> Search remote + local entities
|
|
14
14
|
update [source] Refresh lockfile-managed imports
|
|
15
15
|
upgrade Install the latest CLI release
|
|
16
|
-
sync
|
|
16
|
+
sync Generate provider outputs from canonical .agents
|
|
17
17
|
delete <source|name...> Delete imported entities by source or name(s)
|
|
18
18
|
|
|
19
19
|
Entity commands:
|
|
@@ -134,7 +134,9 @@ Behavior:
|
|
|
134
134
|
`;
|
|
135
135
|
}
|
|
136
136
|
export function getSyncHelpText() {
|
|
137
|
-
return `
|
|
137
|
+
return `Generate provider-specific outputs from canonical .agents data.
|
|
138
|
+
|
|
139
|
+
Use \`agentloom init\` when you want to bootstrap or re-import provider configs into canonical state.
|
|
138
140
|
|
|
139
141
|
Usage:
|
|
140
142
|
agentloom sync [options]
|
|
@@ -148,7 +150,7 @@ Options:
|
|
|
148
150
|
`;
|
|
149
151
|
}
|
|
150
152
|
export function getInitHelpText() {
|
|
151
|
-
return `Bootstrap canonical .agents files
|
|
153
|
+
return `Bootstrap canonical .agents files from existing provider configs, then sync providers.
|
|
152
154
|
|
|
153
155
|
Usage:
|
|
154
156
|
agentloom init [options]
|
package/dist/core/migration.js
CHANGED
|
@@ -6,6 +6,7 @@ import TOML from "@iarna/toml";
|
|
|
6
6
|
import matter from "gray-matter";
|
|
7
7
|
import YAML from "yaml";
|
|
8
8
|
import { buildAgentMarkdown, parseAgentsDir } from "./agents.js";
|
|
9
|
+
import { cloneCodexProviderConfig, stripManagedCodexInstructionKeys, } from "./codex.js";
|
|
9
10
|
import { normalizeCommandArgumentsForCanonical, parseCommandsDir, } from "./commands.js";
|
|
10
11
|
import { ensureDir, isObject, readJsonIfExists, slugify } from "./fs.js";
|
|
11
12
|
import { readLockfile, writeLockfile } from "./lockfile.js";
|
|
@@ -394,33 +395,7 @@ function readCodexProviderAgents(paths) {
|
|
|
394
395
|
const description = isObject(roleEntry) && typeof roleEntry.description === "string"
|
|
395
396
|
? roleEntry.description.trim()
|
|
396
397
|
: roleName;
|
|
397
|
-
const providerConfig =
|
|
398
|
-
if (typeof roleToml.model === "string") {
|
|
399
|
-
providerConfig.model = roleToml.model;
|
|
400
|
-
}
|
|
401
|
-
if (typeof roleToml.model_reasoning_effort === "string") {
|
|
402
|
-
providerConfig.reasoningEffort = roleToml.model_reasoning_effort;
|
|
403
|
-
}
|
|
404
|
-
if (typeof roleToml.model_reasoning_summary === "string") {
|
|
405
|
-
providerConfig.reasoningSummary = roleToml.model_reasoning_summary;
|
|
406
|
-
}
|
|
407
|
-
if (typeof roleToml.model_verbosity === "string") {
|
|
408
|
-
providerConfig.verbosity = roleToml.model_verbosity;
|
|
409
|
-
}
|
|
410
|
-
if (typeof roleToml.approval_policy === "string") {
|
|
411
|
-
providerConfig.approvalPolicy = roleToml.approval_policy;
|
|
412
|
-
}
|
|
413
|
-
if (typeof roleToml.sandbox_mode === "string") {
|
|
414
|
-
providerConfig.sandboxMode = roleToml.sandbox_mode;
|
|
415
|
-
}
|
|
416
|
-
if (typeof roleToml.web_search === "boolean") {
|
|
417
|
-
providerConfig.webSearch = roleToml.web_search;
|
|
418
|
-
}
|
|
419
|
-
if (typeof providerConfig.webSearch !== "boolean" &&
|
|
420
|
-
isObject(roleToml.tools) &&
|
|
421
|
-
typeof roleToml.tools.web_search === "boolean") {
|
|
422
|
-
providerConfig.webSearch = roleToml.tools.web_search;
|
|
423
|
-
}
|
|
398
|
+
const providerConfig = stripManagedCodexInstructionKeys(cloneCodexProviderConfig(roleToml));
|
|
424
399
|
records.push({
|
|
425
400
|
provider: "codex",
|
|
426
401
|
sourcePath: roleTomlPath,
|
package/dist/core/scope.d.ts
CHANGED
|
@@ -5,5 +5,7 @@ export interface ScopeResolutionOptions {
|
|
|
5
5
|
local?: boolean;
|
|
6
6
|
interactive?: boolean;
|
|
7
7
|
}
|
|
8
|
+
export declare function hasInitializedCanonicalLayout(paths: Pick<ScopePaths, "agentsRoot" | "agentsDir" | "commandsDir" | "rulesDir" | "skillsDir" | "mcpPath" | "lockPath" | "manifestPath">): boolean;
|
|
8
9
|
export declare function buildScopePaths(cwd: string, scope: Scope, homeDir?: string): ScopePaths;
|
|
9
10
|
export declare function resolveScope(options: ScopeResolutionOptions): Promise<ScopePaths>;
|
|
11
|
+
export declare function resolveScopeForSync(options: ScopeResolutionOptions): Promise<ScopePaths>;
|
package/dist/core/scope.js
CHANGED
|
@@ -3,6 +3,24 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { cancel, isCancel, select } from "@clack/prompts";
|
|
5
5
|
import { getGlobalSettingsPath, readSettings } from "./settings.js";
|
|
6
|
+
function directoryHasEntries(dirPath) {
|
|
7
|
+
return fs.existsSync(dirPath) && fs.readdirSync(dirPath).length > 0;
|
|
8
|
+
}
|
|
9
|
+
export function hasInitializedCanonicalLayout(paths) {
|
|
10
|
+
if (!fs.existsSync(paths.agentsRoot) ||
|
|
11
|
+
!fs.statSync(paths.agentsRoot).isDirectory()) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (fs.existsSync(paths.mcpPath) ||
|
|
15
|
+
fs.existsSync(paths.lockPath) ||
|
|
16
|
+
fs.existsSync(paths.manifestPath)) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return (directoryHasEntries(paths.agentsDir) ||
|
|
20
|
+
directoryHasEntries(paths.commandsDir) ||
|
|
21
|
+
directoryHasEntries(paths.rulesDir) ||
|
|
22
|
+
directoryHasEntries(paths.skillsDir));
|
|
23
|
+
}
|
|
6
24
|
export function buildScopePaths(cwd, scope, homeDir = os.homedir()) {
|
|
7
25
|
const workspaceRoot = cwd;
|
|
8
26
|
const agentsRoot = scope === "local"
|
|
@@ -37,33 +55,76 @@ export async function resolveScope(options) {
|
|
|
37
55
|
if (!interactive) {
|
|
38
56
|
return buildScopePaths(cwd, hasLocalAgents ? "local" : "global");
|
|
39
57
|
}
|
|
40
|
-
const
|
|
41
|
-
const
|
|
58
|
+
const defaultScope = getDefaultScope();
|
|
59
|
+
const selected = await promptForScopeSelection({
|
|
60
|
+
hasLocalAgents,
|
|
61
|
+
defaultScope,
|
|
62
|
+
});
|
|
63
|
+
return buildScopePaths(cwd, selected);
|
|
64
|
+
}
|
|
65
|
+
export async function resolveScopeForSync(options) {
|
|
66
|
+
const { cwd } = options;
|
|
67
|
+
if (options.global && options.local) {
|
|
68
|
+
throw new Error("Use either --global or --local, not both.");
|
|
69
|
+
}
|
|
70
|
+
if (options.global)
|
|
71
|
+
return buildScopePaths(cwd, "global");
|
|
72
|
+
if (options.local)
|
|
73
|
+
return buildScopePaths(cwd, "local");
|
|
74
|
+
const localPaths = buildScopePaths(cwd, "local");
|
|
75
|
+
const globalPaths = buildScopePaths(cwd, "global");
|
|
76
|
+
const hasLocalAgents = fs.existsSync(localPaths.agentsRoot);
|
|
77
|
+
const hasLocalCanonical = hasInitializedCanonicalLayout(localPaths);
|
|
78
|
+
const hasGlobalCanonical = hasInitializedCanonicalLayout(globalPaths);
|
|
79
|
+
const interactive = options.interactive ?? (process.stdin.isTTY && process.stdout.isTTY);
|
|
80
|
+
if (!interactive) {
|
|
81
|
+
return hasLocalAgents ? localPaths : globalPaths;
|
|
82
|
+
}
|
|
83
|
+
if (hasLocalAgents && hasGlobalCanonical) {
|
|
84
|
+
const selected = await promptForScopeSelection({
|
|
85
|
+
hasLocalAgents: true,
|
|
86
|
+
defaultScope: getDefaultScope(globalPaths.homeDir),
|
|
87
|
+
});
|
|
88
|
+
return buildScopePaths(cwd, selected, globalPaths.homeDir);
|
|
89
|
+
}
|
|
90
|
+
if (hasLocalCanonical)
|
|
91
|
+
return localPaths;
|
|
92
|
+
if (hasGlobalCanonical)
|
|
93
|
+
return globalPaths;
|
|
94
|
+
if (hasLocalAgents)
|
|
95
|
+
return localPaths;
|
|
96
|
+
throw new Error(`No initialized canonical .agents state found at ${localPaths.agentsRoot} or ${globalPaths.agentsRoot}.\nRun \`agentloom init --local\` or \`agentloom init --global\` to bootstrap from provider configs first, or use \`agentloom add\` to create canonical content before syncing.`);
|
|
97
|
+
}
|
|
98
|
+
function getDefaultScope(homeDir = os.homedir()) {
|
|
99
|
+
const globalSettings = readSettings(getGlobalSettingsPath(homeDir));
|
|
100
|
+
return globalSettings.lastScope === "local" ? "local" : "global";
|
|
101
|
+
}
|
|
102
|
+
async function promptForScopeSelection(options) {
|
|
42
103
|
const selected = await select({
|
|
43
104
|
message: "Choose scope for this command",
|
|
44
105
|
options: [
|
|
45
106
|
{
|
|
46
107
|
value: "local",
|
|
47
108
|
label: ".agents in this repository",
|
|
48
|
-
hint: hasLocalAgents
|
|
49
|
-
? defaultScope === "local"
|
|
109
|
+
hint: options.hasLocalAgents
|
|
110
|
+
? options.defaultScope === "local"
|
|
50
111
|
? "default"
|
|
51
112
|
: undefined
|
|
52
|
-
: defaultScope === "local"
|
|
113
|
+
: options.defaultScope === "local"
|
|
53
114
|
? "default (creates .agents)"
|
|
54
115
|
: "creates .agents",
|
|
55
116
|
},
|
|
56
117
|
{
|
|
57
118
|
value: "global",
|
|
58
119
|
label: "~/.agents shared config",
|
|
59
|
-
hint: defaultScope === "global" ? "default" : undefined,
|
|
120
|
+
hint: options.defaultScope === "global" ? "default" : undefined,
|
|
60
121
|
},
|
|
61
122
|
],
|
|
62
|
-
initialValue: defaultScope,
|
|
123
|
+
initialValue: options.defaultScope,
|
|
63
124
|
});
|
|
64
125
|
if (isCancel(selected)) {
|
|
65
126
|
cancel("Operation cancelled.");
|
|
66
127
|
process.exit(1);
|
|
67
128
|
}
|
|
68
|
-
return
|
|
129
|
+
return selected;
|
|
69
130
|
}
|
package/dist/sync/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import YAML from "yaml";
|
|
|
6
6
|
import { ALL_PROVIDERS } from "../types.js";
|
|
7
7
|
import { getProviderConfig, isProviderEnabled, parseAgentsDir, } from "../core/agents.js";
|
|
8
8
|
import { parseCommandsDir, renderCommandForProvider, } from "../core/commands.js";
|
|
9
|
+
import { normalizeCodexConfigForToml } from "../core/codex.js";
|
|
9
10
|
import { parseRulesDir, renderRuleForCursor, upsertManagedRuleBlocks, } from "../core/rules.js";
|
|
10
11
|
import { ensureDir, isObject, readJsonIfExists, readTextIfExists, relativePosix, removeFileIfExists, slugify, toPosixPath, writeJsonAtomic, writeTextAtomic, } from "../core/fs.js";
|
|
11
12
|
import { readManifest, writeManifest } from "../core/manifest.js";
|
|
@@ -869,33 +870,15 @@ function resolveCodexDeveloperInstructions(agentBody, providerConfig) {
|
|
|
869
870
|
providerConfig.developerInstructions.trim() !== "") {
|
|
870
871
|
return providerConfig.developerInstructions.trim();
|
|
871
872
|
}
|
|
873
|
+
if (typeof providerConfig.developer_instructions === "string" &&
|
|
874
|
+
providerConfig.developer_instructions.trim() !== "") {
|
|
875
|
+
return providerConfig.developer_instructions.trim();
|
|
876
|
+
}
|
|
872
877
|
return agentBody.trimStart().trimEnd();
|
|
873
878
|
}
|
|
874
879
|
function buildCodexRoleToml(developerInstructions, providerConfig) {
|
|
875
|
-
const roleToml =
|
|
876
|
-
|
|
877
|
-
};
|
|
878
|
-
if (typeof providerConfig.model === "string") {
|
|
879
|
-
roleToml.model = providerConfig.model;
|
|
880
|
-
}
|
|
881
|
-
if (typeof providerConfig.reasoningEffort === "string") {
|
|
882
|
-
roleToml.model_reasoning_effort = providerConfig.reasoningEffort;
|
|
883
|
-
}
|
|
884
|
-
if (typeof providerConfig.reasoningSummary === "string") {
|
|
885
|
-
roleToml.model_reasoning_summary = providerConfig.reasoningSummary;
|
|
886
|
-
}
|
|
887
|
-
if (typeof providerConfig.verbosity === "string") {
|
|
888
|
-
roleToml.model_verbosity = providerConfig.verbosity;
|
|
889
|
-
}
|
|
890
|
-
if (typeof providerConfig.approvalPolicy === "string") {
|
|
891
|
-
roleToml.approval_policy = providerConfig.approvalPolicy;
|
|
892
|
-
}
|
|
893
|
-
if (typeof providerConfig.sandboxMode === "string") {
|
|
894
|
-
roleToml.sandbox_mode = providerConfig.sandboxMode;
|
|
895
|
-
}
|
|
896
|
-
if (typeof providerConfig.webSearch === "boolean") {
|
|
897
|
-
roleToml.web_search = providerConfig.webSearch;
|
|
898
|
-
}
|
|
880
|
+
const roleToml = normalizeCodexConfigForToml(providerConfig);
|
|
881
|
+
roleToml.developer_instructions = developerInstructions;
|
|
899
882
|
return roleToml;
|
|
900
883
|
}
|
|
901
884
|
function mapMcpServers(servers, allowedKeys) {
|