agentinit 1.23.0 → 1.25.0
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/CHANGELOG.md +17 -0
- package/README.md +24 -2
- package/dist/agents/CodexCliAgent.js +1 -1
- package/dist/agents/CodexCliAgent.js.map +1 -1
- package/dist/cli.js +932 -45
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +113 -8
- package/dist/commands/agent.js.map +1 -1
- package/dist/core/agentSettings/adapters/claude.d.ts.map +1 -1
- package/dist/core/agentSettings/adapters/claude.js +140 -2
- package/dist/core/agentSettings/adapters/claude.js.map +1 -1
- package/dist/core/agentSettings/adapters/codex.d.ts +3 -0
- package/dist/core/agentSettings/adapters/codex.d.ts.map +1 -0
- package/dist/core/agentSettings/adapters/codex.js +121 -0
- package/dist/core/agentSettings/adapters/codex.js.map +1 -0
- package/dist/core/agentSettings/adapters/opencode.d.ts +3 -0
- package/dist/core/agentSettings/adapters/opencode.d.ts.map +1 -0
- package/dist/core/agentSettings/adapters/opencode.js +134 -0
- package/dist/core/agentSettings/adapters/opencode.js.map +1 -0
- package/dist/core/agentSettings/registry.d.ts.map +1 -1
- package/dist/core/agentSettings/registry.js +4 -0
- package/dist/core/agentSettings/registry.js.map +1 -1
- package/dist/core/agentSettings/settingsManager.d.ts +4 -1
- package/dist/core/agentSettings/settingsManager.d.ts.map +1 -1
- package/dist/core/agentSettings/settingsManager.js +277 -27
- package/dist/core/agentSettings/settingsManager.js.map +1 -1
- package/dist/core/agentSettings/types.d.ts +34 -3
- package/dist/core/agentSettings/types.d.ts.map +1 -1
- package/dist/core/agentSettings/valueParser.d.ts.map +1 -1
- package/dist/core/agentSettings/valueParser.js +20 -0
- package/dist/core/agentSettings/valueParser.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { expandTilde } from '../../../utils/paths.js';
|
|
4
|
+
const SUPPORTED_SCOPES = ['global', 'project'];
|
|
5
|
+
const PERMISSION_ACTIONS = ['allow', 'ask', 'deny'];
|
|
6
|
+
function firstExistingPath(paths, fallback) {
|
|
7
|
+
return paths.find(candidate => existsSync(candidate)) ?? fallback;
|
|
8
|
+
}
|
|
9
|
+
function setting(key, valueType, title, description, options = {}) {
|
|
10
|
+
const definition = {
|
|
11
|
+
agent: 'opencode',
|
|
12
|
+
key,
|
|
13
|
+
nativePath: options.nativePath ?? key.split('.'),
|
|
14
|
+
title,
|
|
15
|
+
description,
|
|
16
|
+
valueType,
|
|
17
|
+
scopes: options.scopes ?? SUPPORTED_SCOPES,
|
|
18
|
+
defaultScope: options.defaultScope ?? 'global',
|
|
19
|
+
category: options.category ?? 'settings',
|
|
20
|
+
risk: options.risk ?? 'safe',
|
|
21
|
+
};
|
|
22
|
+
if (options.allowedValues) {
|
|
23
|
+
definition.allowedValues = options.allowedValues;
|
|
24
|
+
}
|
|
25
|
+
if (options.deprecated !== undefined) {
|
|
26
|
+
definition.deprecated = options.deprecated;
|
|
27
|
+
}
|
|
28
|
+
if (options.replacement) {
|
|
29
|
+
definition.replacement = options.replacement;
|
|
30
|
+
}
|
|
31
|
+
return definition;
|
|
32
|
+
}
|
|
33
|
+
export const opencodeSettingsAdapter = {
|
|
34
|
+
agent: 'opencode',
|
|
35
|
+
displayName: 'OpenCode',
|
|
36
|
+
format: 'jsonc',
|
|
37
|
+
definitions: [
|
|
38
|
+
setting('model', 'string', 'Model', 'Default model identifier in provider/model format (e.g. anthropic/claude-sonnet-4-5).', {
|
|
39
|
+
category: 'model',
|
|
40
|
+
}),
|
|
41
|
+
setting('small_model', 'string', 'Small model', 'Small model used for tasks such as title generation, in provider/model format.', {
|
|
42
|
+
category: 'model',
|
|
43
|
+
}),
|
|
44
|
+
setting('provider', 'object', 'Providers', 'Custom OpenCode provider configurations and model overrides.', {
|
|
45
|
+
category: 'provider',
|
|
46
|
+
risk: 'security-sensitive',
|
|
47
|
+
}),
|
|
48
|
+
setting('default_agent', 'string', 'Default agent', 'Default primary agent to use when none is specified.', {
|
|
49
|
+
category: 'agent',
|
|
50
|
+
}),
|
|
51
|
+
setting('autoupdate', 'booleanOrEnum', 'Auto update', 'Control automatic updates: true, false, or notify.', {
|
|
52
|
+
allowedValues: ['notify'],
|
|
53
|
+
scopes: ['global'],
|
|
54
|
+
defaultScope: 'global',
|
|
55
|
+
category: 'runtime',
|
|
56
|
+
}),
|
|
57
|
+
setting('shell', 'string', 'Shell', 'Default shell to use for terminal and bash tool execution.', {
|
|
58
|
+
category: 'runtime',
|
|
59
|
+
}),
|
|
60
|
+
setting('share', 'enum', 'Share', 'Control sharing behavior: manual, auto, or disabled.', {
|
|
61
|
+
allowedValues: ['manual', 'auto', 'disabled'],
|
|
62
|
+
category: 'sharing',
|
|
63
|
+
}),
|
|
64
|
+
setting('username', 'string', 'Username', 'Custom username displayed in conversations instead of system username.', {
|
|
65
|
+
category: 'ui',
|
|
66
|
+
}),
|
|
67
|
+
setting('logLevel', 'enum', 'Log level', 'Log verbosity level.', {
|
|
68
|
+
allowedValues: ['DEBUG', 'INFO', 'WARN', 'ERROR'],
|
|
69
|
+
category: 'runtime',
|
|
70
|
+
}),
|
|
71
|
+
setting('snapshot', 'boolean', 'Snapshot tracking', 'Enable or disable filesystem snapshot tracking for undo/redo.', {
|
|
72
|
+
category: 'runtime',
|
|
73
|
+
}),
|
|
74
|
+
setting('permission.*', 'enum', 'Default permission', 'Fallback permission rule for all tools: allow, ask, or deny.', {
|
|
75
|
+
nativePath: ['permission', '*'],
|
|
76
|
+
category: 'permissions',
|
|
77
|
+
risk: 'security-sensitive',
|
|
78
|
+
allowedValues: PERMISSION_ACTIONS,
|
|
79
|
+
}),
|
|
80
|
+
setting('permission.bash', 'enum', 'Bash permission', 'Permission rule for shell command execution.', {
|
|
81
|
+
category: 'permissions',
|
|
82
|
+
risk: 'security-sensitive',
|
|
83
|
+
allowedValues: PERMISSION_ACTIONS,
|
|
84
|
+
}),
|
|
85
|
+
setting('permission.read', 'enum', 'Read permission', 'Permission rule for file reads.', {
|
|
86
|
+
category: 'permissions',
|
|
87
|
+
allowedValues: PERMISSION_ACTIONS,
|
|
88
|
+
}),
|
|
89
|
+
setting('permission.edit', 'enum', 'Edit permission', 'Permission rule for editing and writing files.', {
|
|
90
|
+
category: 'permissions',
|
|
91
|
+
risk: 'risky',
|
|
92
|
+
allowedValues: PERMISSION_ACTIONS,
|
|
93
|
+
}),
|
|
94
|
+
setting('permission.webfetch', 'enum', 'Web fetch permission', 'Permission rule for fetching external URLs.', {
|
|
95
|
+
category: 'permissions',
|
|
96
|
+
allowedValues: PERMISSION_ACTIONS,
|
|
97
|
+
}),
|
|
98
|
+
setting('permission.task', 'enum', 'Task permission', 'Permission rule for spawning subagent tasks.', {
|
|
99
|
+
category: 'permissions',
|
|
100
|
+
allowedValues: PERMISSION_ACTIONS,
|
|
101
|
+
}),
|
|
102
|
+
setting('permission.websearch', 'enum', 'Web search permission', 'Permission rule for web search operations.', {
|
|
103
|
+
category: 'permissions',
|
|
104
|
+
allowedValues: PERMISSION_ACTIONS,
|
|
105
|
+
}),
|
|
106
|
+
setting('compaction.auto', 'boolean', 'Auto compaction', 'Enable automatic context compaction when context is full.', {
|
|
107
|
+
category: 'compaction',
|
|
108
|
+
}),
|
|
109
|
+
setting('tool_output.max_lines', 'positiveInteger', 'Tool output max lines', 'Maximum lines of tool output before truncation.', {
|
|
110
|
+
category: 'output',
|
|
111
|
+
}),
|
|
112
|
+
setting('tool_output.max_bytes', 'positiveInteger', 'Tool output max bytes', 'Maximum bytes of tool output before truncation.', {
|
|
113
|
+
category: 'output',
|
|
114
|
+
}),
|
|
115
|
+
],
|
|
116
|
+
getSettingsPath(scope, projectPath) {
|
|
117
|
+
switch (scope) {
|
|
118
|
+
case 'global':
|
|
119
|
+
return firstExistingPath([
|
|
120
|
+
expandTilde('~/.config/opencode/opencode.jsonc'),
|
|
121
|
+
expandTilde('~/.config/opencode/opencode.json'),
|
|
122
|
+
expandTilde('~/.config/opencode/config.json'),
|
|
123
|
+
], expandTilde('~/.config/opencode/opencode.json'));
|
|
124
|
+
case 'project':
|
|
125
|
+
return firstExistingPath([
|
|
126
|
+
join(projectPath, '.opencode', 'opencode.jsonc'),
|
|
127
|
+
join(projectPath, '.opencode', 'opencode.json'),
|
|
128
|
+
], join(projectPath, '.opencode', 'opencode.json'));
|
|
129
|
+
case 'local':
|
|
130
|
+
throw new Error('OpenCode settings do not support local scope. Use --global or --project.');
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../../../src/core/agentSettings/adapters/opencode.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/core/agentSettings/registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/core/agentSettings/registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAQxG,wBAAgB,wBAAwB,IAAI,oBAAoB,EAAE,CAEjE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAEvF;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,sBAAsB,GAAG,SAAS,CAExG;AAED,wBAAgB,aAAa,CAAC,UAAU,EAAE,sBAAsB,GAAG,uBAAuB,CAKzF"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { claudeSettingsAdapter } from './adapters/claude.js';
|
|
2
|
+
import { codexSettingsAdapter } from './adapters/codex.js';
|
|
3
|
+
import { opencodeSettingsAdapter } from './adapters/opencode.js';
|
|
2
4
|
const ADAPTERS = [
|
|
3
5
|
claudeSettingsAdapter,
|
|
6
|
+
codexSettingsAdapter,
|
|
7
|
+
opencodeSettingsAdapter,
|
|
4
8
|
];
|
|
5
9
|
export function getAgentSettingsAdapters() {
|
|
6
10
|
return [...ADAPTERS];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/core/agentSettings/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/core/agentSettings/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAGjE,MAAM,QAAQ,GAA2B;IACvC,qBAAqB;IACrB,oBAAoB;IACpB,uBAAuB;CACxB,CAAC;AAEF,MAAM,UAAU,wBAAwB;IACtC,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAa;IACnD,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAa,EAAE,GAAW;IAClE,OAAO,uBAAuB,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;AAChG,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,UAAkC;IAC9D,OAAO;QACL,GAAG,UAAU;QACb,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;KAC5C,CAAC;AACJ,CAAC"}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import type { AgentHookAddOptions, AgentHookMatcher, AgentHookRemoveOptions, AgentHookWriteResult, AgentSettingReadOptions, AgentSettingsSchema, AgentSettingSetOptions, AgentSettingsWriteResult } from './types.js';
|
|
1
|
+
import type { AgentApiKeyAction, AgentApiKeyOptions, AgentApiKeyResult, AgentHookAddOptions, AgentHookMatcher, AgentHookRemoveOptions, AgentHookWriteResult, AgentSettingReadOptions, AgentSettingsList, AgentSettingsSchema, AgentSettingSetOptions, AgentSettingsWriteResult } from './types.js';
|
|
2
2
|
export declare class AgentSettingsManager {
|
|
3
3
|
getSupportedAgents(): string[];
|
|
4
4
|
getSchema(agent: string): AgentSettingsSchema;
|
|
5
|
+
listSettings(agent: string, options?: AgentSettingReadOptions): Promise<AgentSettingsList>;
|
|
5
6
|
get(agent: string, key?: string, options?: AgentSettingReadOptions): Promise<unknown>;
|
|
6
7
|
set(agent: string, key: string, rawValue: string, options?: AgentSettingSetOptions): Promise<AgentSettingsWriteResult>;
|
|
7
8
|
unset(agent: string, key: string, options?: AgentSettingSetOptions): Promise<AgentSettingsWriteResult>;
|
|
8
9
|
listHooks(agent: string, event?: string, options?: AgentSettingReadOptions): Promise<Record<string, AgentHookMatcher[]> | AgentHookMatcher[]>;
|
|
9
10
|
addHook(agent: string, event: string, command: string, options?: AgentHookAddOptions): Promise<AgentHookWriteResult>;
|
|
10
11
|
removeHook(agent: string, event: string, commandOrName: string, options?: AgentHookRemoveOptions): Promise<AgentHookWriteResult>;
|
|
12
|
+
getApiKeyStatus(agent: string, apiKey: string, options?: AgentApiKeyOptions): Promise<AgentApiKeyResult>;
|
|
13
|
+
updateApiKeyTrust(agent: string, action: AgentApiKeyAction, apiKey: string, options?: AgentApiKeyOptions): Promise<AgentApiKeyResult>;
|
|
11
14
|
}
|
|
12
15
|
//# sourceMappingURL=settingsManager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settingsManager.d.ts","sourceRoot":"","sources":["../../../src/core/agentSettings/settingsManager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"settingsManager.d.ts","sourceRoot":"","sources":["../../../src/core/agentSettings/settingsManager.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EAEjB,mBAAmB,EAInB,gBAAgB,EAChB,sBAAsB,EACtB,oBAAoB,EAEpB,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,EAEnB,sBAAsB,EACtB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AA8WpB,qBAAa,oBAAoB;IAC/B,kBAAkB,IAAI,MAAM,EAAE;IAI9B,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB;IAcvC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAkD9F,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B,GAAG,OAAO,CAAC,OAAO,CAAC;IA4CzF,GAAG,CACP,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,wBAAwB,CAAC;IAkC9B,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAgC1G,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,GAAG,gBAAgB,EAAE,CAAC;IAoCjJ,OAAO,CACX,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,oBAAoB,CAAC;IA4C1B,UAAU,CACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,oBAAoB,CAAC;IAmD1B,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAuB5G,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA4ChJ"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as TOML from '@iarna/toml';
|
|
2
|
+
import { parse as parseJsonc } from 'jsonc-parser';
|
|
1
3
|
import { readFileIfExists, writeFile } from '../../utils/fs.js';
|
|
2
4
|
import { getEffectiveAgentSettingsDefaultScopeSync } from '../userConfig.js';
|
|
3
5
|
import { parseAgentSettingValue } from './valueParser.js';
|
|
@@ -13,8 +15,22 @@ const HOOK_EVENT_ALIASES = {
|
|
|
13
15
|
stop: 'Stop',
|
|
14
16
|
'session-start': 'SessionStart',
|
|
15
17
|
'session-end': 'SessionEnd',
|
|
18
|
+
'user-prompt-submit': 'UserPromptSubmit',
|
|
16
19
|
};
|
|
17
20
|
const HOOK_EVENTS = new Set(Object.values(HOOK_EVENT_ALIASES));
|
|
21
|
+
const CLAUDE_API_KEY_RESPONSES_DEFINITION = {
|
|
22
|
+
agent: 'claude',
|
|
23
|
+
key: 'customApiKeyResponses',
|
|
24
|
+
nativePath: ['customApiKeyResponses'],
|
|
25
|
+
title: 'Custom API key responses',
|
|
26
|
+
description: 'Remembered custom API key trust responses.',
|
|
27
|
+
valueType: 'object',
|
|
28
|
+
scopes: ['global'],
|
|
29
|
+
defaultScope: 'global',
|
|
30
|
+
category: 'auth',
|
|
31
|
+
risk: 'security-sensitive',
|
|
32
|
+
store: 'globalConfig',
|
|
33
|
+
};
|
|
18
34
|
function assertObject(value, path) {
|
|
19
35
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
20
36
|
throw new Error(`${path} contains JSON that is not an object.`);
|
|
@@ -144,6 +160,50 @@ function buildHookCommand(command, name) {
|
|
|
144
160
|
...(name ? { name } : {}),
|
|
145
161
|
};
|
|
146
162
|
}
|
|
163
|
+
function normalizeApiKeyForConfig(apiKey) {
|
|
164
|
+
const trimmed = apiKey.trim();
|
|
165
|
+
if (!trimmed) {
|
|
166
|
+
throw new Error('API key cannot be empty.');
|
|
167
|
+
}
|
|
168
|
+
return trimmed.slice(-20);
|
|
169
|
+
}
|
|
170
|
+
function getApiKeyResponses(config) {
|
|
171
|
+
const current = config.customApiKeyResponses;
|
|
172
|
+
if (current !== undefined && (!current || typeof current !== 'object' || Array.isArray(current))) {
|
|
173
|
+
throw new Error('Existing customApiKeyResponses value is not an object.');
|
|
174
|
+
}
|
|
175
|
+
const responses = (current ?? {});
|
|
176
|
+
const approved = responses.approved ?? [];
|
|
177
|
+
const rejected = responses.rejected ?? [];
|
|
178
|
+
if (!Array.isArray(approved) || !approved.every(value => typeof value === 'string')) {
|
|
179
|
+
throw new Error('Existing customApiKeyResponses.approved value must be an array of strings.');
|
|
180
|
+
}
|
|
181
|
+
if (!Array.isArray(rejected) || !rejected.every(value => typeof value === 'string')) {
|
|
182
|
+
throw new Error('Existing customApiKeyResponses.rejected value must be an array of strings.');
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
approved,
|
|
186
|
+
rejected,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function getApiKeyStatusFromResponses(responses, fingerprint) {
|
|
190
|
+
if (responses.approved.includes(fingerprint)) {
|
|
191
|
+
return 'approved';
|
|
192
|
+
}
|
|
193
|
+
if (responses.rejected.includes(fingerprint)) {
|
|
194
|
+
return 'rejected';
|
|
195
|
+
}
|
|
196
|
+
return 'unknown';
|
|
197
|
+
}
|
|
198
|
+
function setApiKeyResponses(config, approved, rejected) {
|
|
199
|
+
config.customApiKeyResponses = {
|
|
200
|
+
...(config.customApiKeyResponses && typeof config.customApiKeyResponses === 'object' && !Array.isArray(config.customApiKeyResponses)
|
|
201
|
+
? config.customApiKeyResponses
|
|
202
|
+
: {}),
|
|
203
|
+
approved,
|
|
204
|
+
rejected,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
147
207
|
function deleteNestedValue(config, path) {
|
|
148
208
|
const parents = [];
|
|
149
209
|
let current = config;
|
|
@@ -178,27 +238,91 @@ function resolveProjectPath(projectPath) {
|
|
|
178
238
|
return projectPath ?? process.cwd();
|
|
179
239
|
}
|
|
180
240
|
function resolveScope(definition, scope) {
|
|
181
|
-
const
|
|
241
|
+
const defaultScope = getEffectiveAgentSettingsDefaultScopeSync();
|
|
242
|
+
const resolvedScope = scope ?? (definition.store === 'globalConfig' && !definition.scopes.includes(defaultScope) ? definition.defaultScope : defaultScope);
|
|
182
243
|
if (!definition.scopes.includes(resolvedScope)) {
|
|
183
244
|
throw new Error(`"${definition.key}" does not support ${resolvedScope} scope. Supported scopes: ${definition.scopes.join(', ')}.`);
|
|
184
245
|
}
|
|
185
246
|
return resolvedScope;
|
|
186
247
|
}
|
|
187
|
-
|
|
248
|
+
function getSupportedSettingScopes(adapter) {
|
|
249
|
+
return [...new Set(adapter.definitions.flatMap(definition => definition.scopes))];
|
|
250
|
+
}
|
|
251
|
+
function resolveFullReadScope(adapter, scope) {
|
|
252
|
+
const resolvedScope = scope ?? getEffectiveAgentSettingsDefaultScopeSync();
|
|
253
|
+
const supportedScopes = getSupportedSettingScopes(adapter);
|
|
254
|
+
if (!supportedScopes.includes(resolvedScope)) {
|
|
255
|
+
throw new Error(`Agent ${adapter.agent} settings do not support ${resolvedScope} scope. Supported scopes: ${supportedScopes.join(', ')}.`);
|
|
256
|
+
}
|
|
257
|
+
return resolvedScope;
|
|
258
|
+
}
|
|
259
|
+
async function readConfigObject(adapter, path) {
|
|
188
260
|
const content = await readFileIfExists(path);
|
|
189
261
|
if (!content) {
|
|
190
262
|
return {};
|
|
191
263
|
}
|
|
264
|
+
if (adapter.format === 'toml') {
|
|
265
|
+
try {
|
|
266
|
+
return assertObject(TOML.parse(content), path);
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
if (error instanceof SyntaxError || error instanceof Error) {
|
|
270
|
+
throw new Error(`${path} contains invalid TOML.`);
|
|
271
|
+
}
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
192
275
|
try {
|
|
193
|
-
|
|
276
|
+
const errors = [];
|
|
277
|
+
const value = adapter.format === 'jsonc'
|
|
278
|
+
? parseJsonc(content, errors, { allowTrailingComma: true })
|
|
279
|
+
: JSON.parse(content);
|
|
280
|
+
if (errors.length > 0) {
|
|
281
|
+
throw new SyntaxError('Invalid JSONC');
|
|
282
|
+
}
|
|
283
|
+
return assertObject(value, path);
|
|
194
284
|
}
|
|
195
285
|
catch (error) {
|
|
196
286
|
if (error instanceof SyntaxError) {
|
|
197
|
-
throw new Error(`${path} contains invalid JSON.`);
|
|
287
|
+
throw new Error(`${path} contains invalid ${adapter.format === 'jsonc' ? 'JSONC' : 'JSON'}.`);
|
|
198
288
|
}
|
|
199
289
|
throw error;
|
|
200
290
|
}
|
|
201
291
|
}
|
|
292
|
+
function stringifyConfigObject(adapter, config) {
|
|
293
|
+
if (adapter.format === 'toml') {
|
|
294
|
+
return TOML.stringify(config);
|
|
295
|
+
}
|
|
296
|
+
return `${JSON.stringify(config, null, 2)}\n`;
|
|
297
|
+
}
|
|
298
|
+
function summarizeSettingValue(value) {
|
|
299
|
+
if (value === undefined) {
|
|
300
|
+
return 'not set';
|
|
301
|
+
}
|
|
302
|
+
if (Array.isArray(value)) {
|
|
303
|
+
return `set (array, ${value.length} item${value.length === 1 ? '' : 's'})`;
|
|
304
|
+
}
|
|
305
|
+
if (value && typeof value === 'object') {
|
|
306
|
+
return 'set (object)';
|
|
307
|
+
}
|
|
308
|
+
return JSON.stringify(value);
|
|
309
|
+
}
|
|
310
|
+
async function writeConfigObject(adapter, path, config) {
|
|
311
|
+
await writeFile(path, stringifyConfigObject(adapter, config));
|
|
312
|
+
}
|
|
313
|
+
function assertHookEventSupported(adapter, event) {
|
|
314
|
+
if (adapter.hookEvents && !adapter.hookEvents.includes(event)) {
|
|
315
|
+
throw new Error(`Agent ${adapter.agent} does not support ${event} hooks. Supported: ${adapter.hookEvents.join(', ')}.`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function resolveHookScope(adapter, scope) {
|
|
319
|
+
const resolvedScope = scope ?? getEffectiveAgentSettingsDefaultScopeSync();
|
|
320
|
+
const supportedScopes = adapter.hookScopes ?? ['global', 'project', 'local'];
|
|
321
|
+
if (!supportedScopes.includes(resolvedScope)) {
|
|
322
|
+
throw new Error(`Agent ${adapter.agent} hooks do not support ${resolvedScope} scope. Supported scopes: ${supportedScopes.join(', ')}.`);
|
|
323
|
+
}
|
|
324
|
+
return resolvedScope;
|
|
325
|
+
}
|
|
202
326
|
export class AgentSettingsManager {
|
|
203
327
|
getSupportedAgents() {
|
|
204
328
|
return getAgentSettingsAdapters().map(adapter => adapter.agent);
|
|
@@ -215,23 +339,84 @@ export class AgentSettingsManager {
|
|
|
215
339
|
settings: adapter.definitions.map(toSchemaEntry),
|
|
216
340
|
};
|
|
217
341
|
}
|
|
342
|
+
async listSettings(agent, options = {}) {
|
|
343
|
+
const adapter = getAgentSettingsAdapter(agent);
|
|
344
|
+
if (!adapter) {
|
|
345
|
+
throw new Error(`Unsupported agent settings adapter: ${agent}. Supported: ${this.getSupportedAgents().join(', ')}`);
|
|
346
|
+
}
|
|
347
|
+
const scope = resolveFullReadScope(adapter, options.scope);
|
|
348
|
+
const projectPath = resolveProjectPath(options.projectPath);
|
|
349
|
+
const configByPath = new Map();
|
|
350
|
+
const readConfigForDefinition = async (definition) => {
|
|
351
|
+
const path = adapter.getSettingsPath(scope, projectPath, definition);
|
|
352
|
+
const cached = configByPath.get(path);
|
|
353
|
+
if (cached) {
|
|
354
|
+
return cached;
|
|
355
|
+
}
|
|
356
|
+
const config = await readConfigObject(adapter, path);
|
|
357
|
+
configByPath.set(path, config);
|
|
358
|
+
return config;
|
|
359
|
+
};
|
|
360
|
+
const settings = [];
|
|
361
|
+
for (const definition of adapter.definitions) {
|
|
362
|
+
const schemaEntry = toSchemaEntry(definition);
|
|
363
|
+
if (!definition.scopes.includes(scope)) {
|
|
364
|
+
settings.push({
|
|
365
|
+
...schemaEntry,
|
|
366
|
+
currentStatus: 'not-applicable',
|
|
367
|
+
currentSummary: 'n/a',
|
|
368
|
+
});
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
const config = await readConfigForDefinition(definition);
|
|
372
|
+
const value = getNestedValue(config, definition.nativePath);
|
|
373
|
+
settings.push({
|
|
374
|
+
...schemaEntry,
|
|
375
|
+
currentStatus: value === undefined ? 'not-set' : 'set',
|
|
376
|
+
currentSummary: summarizeSettingValue(value),
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
agent: adapter.agent,
|
|
381
|
+
displayName: adapter.displayName,
|
|
382
|
+
scope,
|
|
383
|
+
settings,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
218
386
|
async get(agent, key, options = {}) {
|
|
219
387
|
const adapter = getAgentSettingsAdapter(agent);
|
|
220
388
|
if (!adapter) {
|
|
221
389
|
throw new Error(`Unsupported agent settings adapter: ${agent}. Supported: ${this.getSupportedAgents().join(', ')}`);
|
|
222
390
|
}
|
|
223
391
|
if (!key) {
|
|
224
|
-
const scope = options.scope
|
|
392
|
+
const scope = resolveFullReadScope(adapter, options.scope);
|
|
225
393
|
const path = adapter.getSettingsPath(scope, resolveProjectPath(options.projectPath));
|
|
226
|
-
|
|
394
|
+
const config = await readConfigObject(adapter, path);
|
|
395
|
+
if (scope !== 'global') {
|
|
396
|
+
return config;
|
|
397
|
+
}
|
|
398
|
+
const globalConfigDefinitions = adapter.definitions.filter(definition => definition.store === 'globalConfig' && definition.scopes.includes('global'));
|
|
399
|
+
if (globalConfigDefinitions.length === 0) {
|
|
400
|
+
return config;
|
|
401
|
+
}
|
|
402
|
+
const globalConfigPath = adapter.getSettingsPath('global', resolveProjectPath(options.projectPath), globalConfigDefinitions[0]);
|
|
403
|
+
const globalConfig = await readConfigObject(adapter, globalConfigPath);
|
|
404
|
+
const result = { ...config };
|
|
405
|
+
for (const definition of globalConfigDefinitions) {
|
|
406
|
+
const value = getNestedValue(globalConfig, definition.nativePath);
|
|
407
|
+
if (value !== undefined) {
|
|
408
|
+
setNestedValue(result, definition.nativePath, value);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return result;
|
|
227
412
|
}
|
|
228
413
|
const definition = getAgentSettingDefinition(agent, key);
|
|
229
414
|
if (!definition) {
|
|
230
415
|
throw new Error(`Unknown ${agent} setting: ${key}.`);
|
|
231
416
|
}
|
|
232
417
|
const scope = resolveScope(definition, options.scope);
|
|
233
|
-
const path = adapter.getSettingsPath(scope, resolveProjectPath(options.projectPath));
|
|
234
|
-
const config = await
|
|
418
|
+
const path = adapter.getSettingsPath(scope, resolveProjectPath(options.projectPath), definition);
|
|
419
|
+
const config = await readConfigObject(adapter, path);
|
|
235
420
|
return getNestedValue(config, definition.nativePath);
|
|
236
421
|
}
|
|
237
422
|
async set(agent, key, rawValue, options = {}) {
|
|
@@ -244,13 +429,13 @@ export class AgentSettingsManager {
|
|
|
244
429
|
throw new Error(`Unknown ${agent} setting: ${key}.`);
|
|
245
430
|
}
|
|
246
431
|
const scope = resolveScope(definition, options.scope);
|
|
247
|
-
const path = adapter.getSettingsPath(scope, resolveProjectPath(options.projectPath));
|
|
248
|
-
const config = await
|
|
432
|
+
const path = adapter.getSettingsPath(scope, resolveProjectPath(options.projectPath), definition);
|
|
433
|
+
const config = await readConfigObject(adapter, path);
|
|
249
434
|
const previousValue = getNestedValue(config, definition.nativePath);
|
|
250
435
|
const value = parseAgentSettingValue(definition, rawValue, options.parseJson);
|
|
251
436
|
setNestedValue(config, definition.nativePath, value);
|
|
252
437
|
if (!options.dryRun) {
|
|
253
|
-
await
|
|
438
|
+
await writeConfigObject(adapter, path, config);
|
|
254
439
|
}
|
|
255
440
|
return {
|
|
256
441
|
agent,
|
|
@@ -272,12 +457,12 @@ export class AgentSettingsManager {
|
|
|
272
457
|
throw new Error(`Unknown ${agent} setting: ${key}.`);
|
|
273
458
|
}
|
|
274
459
|
const scope = resolveScope(definition, options.scope);
|
|
275
|
-
const path = adapter.getSettingsPath(scope, resolveProjectPath(options.projectPath));
|
|
276
|
-
const config = await
|
|
460
|
+
const path = adapter.getSettingsPath(scope, resolveProjectPath(options.projectPath), definition);
|
|
461
|
+
const config = await readConfigObject(adapter, path);
|
|
277
462
|
const previousValue = getNestedValue(config, definition.nativePath);
|
|
278
463
|
deleteNestedValue(config, definition.nativePath);
|
|
279
464
|
if (!options.dryRun) {
|
|
280
|
-
await
|
|
465
|
+
await writeConfigObject(adapter, path, config);
|
|
281
466
|
}
|
|
282
467
|
return {
|
|
283
468
|
agent,
|
|
@@ -293,14 +478,18 @@ export class AgentSettingsManager {
|
|
|
293
478
|
if (!adapter) {
|
|
294
479
|
throw new Error(`Unsupported agent settings adapter: ${agent}. Supported: ${this.getSupportedAgents().join(', ')}`);
|
|
295
480
|
}
|
|
296
|
-
if (
|
|
481
|
+
if (!adapter.hookEvents) {
|
|
297
482
|
throw new Error(`Agent ${agent} does not support hook management.`);
|
|
298
483
|
}
|
|
299
|
-
const
|
|
484
|
+
const hookEvent = event ? normalizeHookEvent(event) : undefined;
|
|
485
|
+
if (hookEvent) {
|
|
486
|
+
assertHookEventSupported(adapter, hookEvent);
|
|
487
|
+
}
|
|
488
|
+
const scope = resolveHookScope(adapter, options.scope);
|
|
300
489
|
const path = adapter.getSettingsPath(scope, resolveProjectPath(options.projectPath));
|
|
301
|
-
const config = await
|
|
302
|
-
if (
|
|
303
|
-
return getHookMatchers(config,
|
|
490
|
+
const config = await readConfigObject(adapter, path);
|
|
491
|
+
if (hookEvent) {
|
|
492
|
+
return getHookMatchers(config, hookEvent);
|
|
304
493
|
}
|
|
305
494
|
const hooks = getNestedValue(config, ['hooks']);
|
|
306
495
|
if (hooks === undefined) {
|
|
@@ -320,13 +509,14 @@ export class AgentSettingsManager {
|
|
|
320
509
|
if (!adapter) {
|
|
321
510
|
throw new Error(`Unsupported agent settings adapter: ${agent}. Supported: ${this.getSupportedAgents().join(', ')}`);
|
|
322
511
|
}
|
|
323
|
-
if (
|
|
512
|
+
if (!adapter.hookEvents) {
|
|
324
513
|
throw new Error(`Agent ${agent} does not support hook management.`);
|
|
325
514
|
}
|
|
326
515
|
const hookEvent = normalizeHookEvent(event);
|
|
327
|
-
|
|
516
|
+
assertHookEventSupported(adapter, hookEvent);
|
|
517
|
+
const scope = resolveHookScope(adapter, options.scope);
|
|
328
518
|
const path = adapter.getSettingsPath(scope, resolveProjectPath(options.projectPath));
|
|
329
|
-
const config = await
|
|
519
|
+
const config = await readConfigObject(adapter, path);
|
|
330
520
|
const hook = buildHookCommand(command, options.name);
|
|
331
521
|
const matchers = getHookMatchers(config, hookEvent);
|
|
332
522
|
const matcher = options.matcher ?? '*';
|
|
@@ -342,7 +532,7 @@ export class AgentSettingsManager {
|
|
|
342
532
|
}
|
|
343
533
|
setHookMatchers(config, hookEvent, matchers);
|
|
344
534
|
if (!options.dryRun) {
|
|
345
|
-
await
|
|
535
|
+
await writeConfigObject(adapter, path, config);
|
|
346
536
|
}
|
|
347
537
|
return {
|
|
348
538
|
agent,
|
|
@@ -358,13 +548,14 @@ export class AgentSettingsManager {
|
|
|
358
548
|
if (!adapter) {
|
|
359
549
|
throw new Error(`Unsupported agent settings adapter: ${agent}. Supported: ${this.getSupportedAgents().join(', ')}`);
|
|
360
550
|
}
|
|
361
|
-
if (
|
|
551
|
+
if (!adapter.hookEvents) {
|
|
362
552
|
throw new Error(`Agent ${agent} does not support hook management.`);
|
|
363
553
|
}
|
|
364
554
|
const hookEvent = normalizeHookEvent(event);
|
|
365
|
-
|
|
555
|
+
assertHookEventSupported(adapter, hookEvent);
|
|
556
|
+
const scope = resolveHookScope(adapter, options.scope);
|
|
366
557
|
const path = adapter.getSettingsPath(scope, resolveProjectPath(options.projectPath));
|
|
367
|
-
const config = await
|
|
558
|
+
const config = await readConfigObject(adapter, path);
|
|
368
559
|
const matchers = getHookMatchers(config, hookEvent);
|
|
369
560
|
let removed = 0;
|
|
370
561
|
const nextMatchers = matchers
|
|
@@ -384,7 +575,7 @@ export class AgentSettingsManager {
|
|
|
384
575
|
.filter(entry => entry.hooks.length > 0);
|
|
385
576
|
setHookMatchers(config, hookEvent, nextMatchers);
|
|
386
577
|
if (!options.dryRun) {
|
|
387
|
-
await
|
|
578
|
+
await writeConfigObject(adapter, path, config);
|
|
388
579
|
}
|
|
389
580
|
return {
|
|
390
581
|
agent,
|
|
@@ -395,5 +586,64 @@ export class AgentSettingsManager {
|
|
|
395
586
|
dryRun: Boolean(options.dryRun),
|
|
396
587
|
};
|
|
397
588
|
}
|
|
589
|
+
async getApiKeyStatus(agent, apiKey, options = {}) {
|
|
590
|
+
const adapter = getAgentSettingsAdapter(agent);
|
|
591
|
+
if (!adapter) {
|
|
592
|
+
throw new Error(`Unsupported agent settings adapter: ${agent}. Supported: ${this.getSupportedAgents().join(', ')}`);
|
|
593
|
+
}
|
|
594
|
+
if (agent !== 'claude') {
|
|
595
|
+
throw new Error(`Agent ${agent} does not support API key trust management.`);
|
|
596
|
+
}
|
|
597
|
+
const path = adapter.getSettingsPath('global', resolveProjectPath(options.projectPath), CLAUDE_API_KEY_RESPONSES_DEFINITION);
|
|
598
|
+
const config = await readConfigObject(adapter, path);
|
|
599
|
+
const fingerprint = normalizeApiKeyForConfig(apiKey);
|
|
600
|
+
const responses = getApiKeyResponses(config);
|
|
601
|
+
return {
|
|
602
|
+
agent,
|
|
603
|
+
path,
|
|
604
|
+
fingerprint,
|
|
605
|
+
status: getApiKeyStatusFromResponses(responses, fingerprint),
|
|
606
|
+
dryRun: false,
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
async updateApiKeyTrust(agent, action, apiKey, options = {}) {
|
|
610
|
+
const adapter = getAgentSettingsAdapter(agent);
|
|
611
|
+
if (!adapter) {
|
|
612
|
+
throw new Error(`Unsupported agent settings adapter: ${agent}. Supported: ${this.getSupportedAgents().join(', ')}`);
|
|
613
|
+
}
|
|
614
|
+
if (agent !== 'claude') {
|
|
615
|
+
throw new Error(`Agent ${agent} does not support API key trust management.`);
|
|
616
|
+
}
|
|
617
|
+
const path = adapter.getSettingsPath('global', resolveProjectPath(options.projectPath), CLAUDE_API_KEY_RESPONSES_DEFINITION);
|
|
618
|
+
const config = await readConfigObject(adapter, path);
|
|
619
|
+
const fingerprint = normalizeApiKeyForConfig(apiKey);
|
|
620
|
+
const responses = getApiKeyResponses(config);
|
|
621
|
+
const previousStatus = getApiKeyStatusFromResponses(responses, fingerprint);
|
|
622
|
+
let approved = responses.approved.filter(value => value !== fingerprint);
|
|
623
|
+
let rejected = responses.rejected.filter(value => value !== fingerprint);
|
|
624
|
+
if (action === 'approve') {
|
|
625
|
+
approved = [...approved, fingerprint];
|
|
626
|
+
}
|
|
627
|
+
else if (action === 'reject') {
|
|
628
|
+
rejected = [...rejected, fingerprint];
|
|
629
|
+
}
|
|
630
|
+
const status = action === 'approve'
|
|
631
|
+
? 'approved'
|
|
632
|
+
: action === 'reject'
|
|
633
|
+
? 'rejected'
|
|
634
|
+
: 'unknown';
|
|
635
|
+
setApiKeyResponses(config, approved, rejected);
|
|
636
|
+
if (!options.dryRun) {
|
|
637
|
+
await writeConfigObject(adapter, path, config);
|
|
638
|
+
}
|
|
639
|
+
return {
|
|
640
|
+
agent,
|
|
641
|
+
path,
|
|
642
|
+
fingerprint,
|
|
643
|
+
status,
|
|
644
|
+
previousStatus,
|
|
645
|
+
dryRun: Boolean(options.dryRun),
|
|
646
|
+
};
|
|
647
|
+
}
|
|
398
648
|
}
|
|
399
649
|
//# sourceMappingURL=settingsManager.js.map
|