@axhub/genie 0.2.10 → 0.2.12
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/dist/api-docs.html +2 -2
- package/dist/assets/App-Clb2COtW.js +274 -0
- package/dist/assets/ImagePlaygroundPage-DqhMSbM8.js +106 -0
- package/dist/assets/ImagePlaygroundPage-MEn3NN80.css +1 -0
- package/dist/assets/ReviewApp-CDcLYe-u.js +1 -0
- package/dist/assets/{_basePickBy-DVVb07UV.js → _basePickBy-jUZsM51q.js} +1 -1
- package/dist/assets/{_baseUniq-BtbziL5G.js → _baseUniq-BXglE6_v.js} +1 -1
- package/dist/assets/{arc-BsCC8yBD.js → arc-D-oFCFBv.js} +1 -1
- package/dist/assets/{architectureDiagram-2XIMDMQ5-woFp6eNI.js → architectureDiagram-2XIMDMQ5-DC8bAnQt.js} +1 -1
- package/dist/assets/{blockDiagram-WCTKOSBZ-ya8VAc2k.js → blockDiagram-WCTKOSBZ-C4semIRc.js} +1 -1
- package/dist/assets/{c4Diagram-IC4MRINW-CY1dZmIZ.js → c4Diagram-IC4MRINW-FHj1QO3y.js} +1 -1
- package/dist/assets/channel-BF4woPXX.js +1 -0
- package/dist/assets/{chunk-4BX2VUAB-CR1lAd74.js → chunk-4BX2VUAB-D-LjsQ_s.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-CP98WcFC.js → chunk-55IACEB6-DI3j_d7A.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-D9c7ijAB.js → chunk-FMBD7UC4-BEVnaLFN.js} +1 -1
- package/dist/assets/{chunk-JSJVCQXG-DQAGYOn-.js → chunk-JSJVCQXG-CSxpcErk.js} +1 -1
- package/dist/assets/{chunk-KX2RTZJC-BbTXiDq7.js → chunk-KX2RTZJC-BbuhDN4h.js} +1 -1
- package/dist/assets/{chunk-NQ4KR5QH-BI6AX0dr.js → chunk-NQ4KR5QH-C3x61XQa.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-DB3V2Ifo.js → chunk-QZHKN3VN-DxWOFtPh.js} +1 -1
- package/dist/assets/{chunk-WL4C6EOR-DhzTthv6.js → chunk-WL4C6EOR-Bt2OauD2.js} +1 -1
- package/dist/assets/classDiagram-VBA2DB6C-D2kHlnQ7.js +1 -0
- package/dist/assets/classDiagram-v2-RAHNMMFH-D2kHlnQ7.js +1 -0
- package/dist/assets/clone-CqBvwCJW.js +1 -0
- package/dist/assets/{cose-bilkent-S5V4N54A-BQ09ZE2j.js → cose-bilkent-S5V4N54A-Dexadrue.js} +1 -1
- package/dist/assets/{dagre-KLK3FWXG-Dc2ueD_R.js → dagre-KLK3FWXG-F9U4X2xC.js} +1 -1
- package/dist/assets/{diagram-E7M64L7V-DP-LsQoL.js → diagram-E7M64L7V-B3V17aH3.js} +1 -1
- package/dist/assets/{diagram-IFDJBPK2-Cg6r42cB.js → diagram-IFDJBPK2-CdHAmLL1.js} +1 -1
- package/dist/assets/{diagram-P4PSJMXO-aHsfoUZE.js → diagram-P4PSJMXO-CrTNfk8K.js} +1 -1
- package/dist/assets/{erDiagram-INFDFZHY-qBXJ4aAz.js → erDiagram-INFDFZHY-vDh9SWK9.js} +1 -1
- package/dist/assets/{flowDiagram-PKNHOUZH-D_13emJM.js → flowDiagram-PKNHOUZH-DpltMg7L.js} +1 -1
- package/dist/assets/{ganttDiagram-A5KZAMGK-BvIcOLwz.js → ganttDiagram-A5KZAMGK-COTk2xur.js} +1 -1
- package/dist/assets/{gitGraphDiagram-K3NZZRJ6-ad0vvNcU.js → gitGraphDiagram-K3NZZRJ6-BNV7bvvj.js} +1 -1
- package/dist/assets/{graph-CeJCMjan.js → graph-Dkeg9oys.js} +1 -1
- package/dist/assets/{highlighted-body-TPN3WLV5-B_novwSz.js → highlighted-body-TPN3WLV5-DaiQEBwR.js} +1 -1
- package/dist/assets/index-DgGmiqsP.css +1 -0
- package/dist/assets/index-DvA901Vs.js +2 -0
- package/dist/assets/{infoDiagram-LFFYTUFH-lOxAqb3m.js → infoDiagram-LFFYTUFH-CZioW3Gt.js} +1 -1
- package/dist/assets/{ishikawaDiagram-PHBUUO56-DIr-51gj.js → ishikawaDiagram-PHBUUO56-BbqR3i1B.js} +1 -1
- package/dist/assets/{journeyDiagram-4ABVD52K-CYcIW0ZU.js → journeyDiagram-4ABVD52K-wfb-WHzl.js} +1 -1
- package/dist/assets/{kanban-definition-K7BYSVSG-C1ZK616a.js → kanban-definition-K7BYSVSG-B3c4y3VN.js} +1 -1
- package/dist/assets/{layout-CI2RM-v6.js → layout-Xr9Z2VGF.js} +1 -1
- package/dist/assets/{linear-DE7bISck.js → linear-JBmzAJtl.js} +1 -1
- package/dist/assets/{mermaid-O7DHMXV3-XxAJo8EK.js → mermaid-O7DHMXV3-fDuyNLKe.js} +238 -220
- package/dist/assets/{mindmap-definition-YRQLILUH-Dz6EFjmn.js → mindmap-definition-YRQLILUH-B5NTN_jD.js} +1 -1
- package/dist/assets/{pieDiagram-SKSYHLDU-DPpEzUed.js → pieDiagram-SKSYHLDU-CuO98GVu.js} +1 -1
- package/dist/assets/{quadrantDiagram-337W2JSQ-xdoXNet7.js → quadrantDiagram-337W2JSQ-LL3f4vLf.js} +1 -1
- package/dist/assets/{requirementDiagram-Z7DCOOCP-DUq8H3CL.js → requirementDiagram-Z7DCOOCP-Di-2O6LH.js} +1 -1
- package/dist/assets/{sankeyDiagram-WA2Y5GQK-CmqEUxRu.js → sankeyDiagram-WA2Y5GQK-9lHqrXqR.js} +1 -1
- package/dist/assets/{sequenceDiagram-2WXFIKYE-DhtXRNiH.js → sequenceDiagram-2WXFIKYE-BQu-SoGr.js} +1 -1
- package/dist/assets/{stateDiagram-RAJIS63D-Dj0HOlbN.js → stateDiagram-RAJIS63D-BUxvd2BC.js} +1 -1
- package/dist/assets/stateDiagram-v2-FVOUBMTO-CDVexTiR.js +1 -0
- package/dist/assets/{timeline-definition-YZTLITO2-DUuJzZB5.js → timeline-definition-YZTLITO2-oP47UEU6.js} +1 -1
- package/dist/assets/{treemap-KZPCXAKY-DpYBQ0qr.js → treemap-KZPCXAKY-BRjDo2aE.js} +1 -1
- package/dist/assets/{vendor-codemirror-CMHSJ_9p.js → vendor-codemirror-BiCeS-y4.js} +1 -1
- package/dist/assets/{vendor-react-xmA_f8ig.js → vendor-react-DVlYPmi3.js} +1 -1
- package/dist/assets/{vennDiagram-LZ73GAT5-DpePUyOd.js → vennDiagram-LZ73GAT5-DrRqcDqo.js} +1 -1
- package/dist/assets/{xychartDiagram-JWTSCODW-Cfp1I4_U.js → xychartDiagram-JWTSCODW-DUXrymAi.js} +1 -1
- package/dist/index.html +4 -4
- package/package.json +25 -6
- package/scripts/refresh-acp-default-capabilities.mjs +160 -0
- package/server/acp-runtime/client.js +1137 -181
- package/server/acp-runtime/command-overrides.js +48 -0
- package/server/acp-runtime/index.js +576 -16
- package/server/acp-runtime/registry.js +6 -4
- package/server/acp-runtime/session-store.js +235 -92
- package/server/database/db.js +12 -3
- package/server/external-agent/ws.js +212 -11
- package/server/index.js +156 -53
- package/server/projects-watcher-config.js +4 -0
- package/server/projects.js +485 -125
- package/server/routes/cc-connect.js +5 -4
- package/server/routes/codex.js +24 -0
- package/server/routes/commands.js +166 -10
- package/server/routes/runs.js +641 -0
- package/server/routes/session-core.js +357 -109
- package/server/session-core/eventStore.js +0 -121
- package/server/session-core/providerAdapters.js +644 -163
- package/server/session-core/providerDiscovery.js +66 -38
- package/server/session-core/runRegistry.js +244 -0
- package/server/session-core/runtimeState.js +75 -3
- package/server/session-core/runtimeWriter.js +132 -10
- package/server/utils/codexImagePlayground.js +479 -0
- package/server/utils/localTerminal.js +56 -0
- package/server/utils/shellCommand.js +70 -0
- package/shared/acpCapabilities.js +393 -0
- package/shared/acpDefaultCapabilities.generated.json +141 -0
- package/shared/conversationEvents.js +425 -121
- package/dist/assets/App-CYCCsgwf.js +0 -264
- package/dist/assets/ReviewApp-0srHIXwb.js +0 -1
- package/dist/assets/channel-BMhScXFe.js +0 -1
- package/dist/assets/classDiagram-VBA2DB6C-CMIxlWcT.js +0 -1
- package/dist/assets/classDiagram-v2-RAHNMMFH-CMIxlWcT.js +0 -1
- package/dist/assets/clone-BPqOt4r3.js +0 -1
- package/dist/assets/index-C514cLyb.js +0 -2
- package/dist/assets/index-h1DBl_g3.css +0 -1
- package/dist/assets/stateDiagram-v2-FVOUBMTO-C9utf5gv.js +0 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import os from 'os';
|
|
2
|
+
|
|
3
|
+
function quoteForPosix(value) {
|
|
4
|
+
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function quoteForPowerShell(value) {
|
|
8
|
+
return `"${String(value).replace(/`/g, '``').replace(/"/g, '`"')}"`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function buildPosixProviderCommand({ provider = 'claude', sessionId = null, hasSession = false } = {}) {
|
|
12
|
+
const normalizedProvider = String(provider || 'claude').trim().toLowerCase();
|
|
13
|
+
const normalizedSessionId = typeof sessionId === 'string' ? sessionId.trim() : '';
|
|
14
|
+
const shouldResume = Boolean(hasSession && normalizedSessionId);
|
|
15
|
+
|
|
16
|
+
switch (normalizedProvider) {
|
|
17
|
+
case 'codex':
|
|
18
|
+
return shouldResume ? `codex resume ${quoteForPosix(normalizedSessionId)}` : 'codex';
|
|
19
|
+
case 'gemini':
|
|
20
|
+
return shouldResume ? `npx -y @google/gemini-cli --resume ${quoteForPosix(normalizedSessionId)}` : 'npx -y @google/gemini-cli';
|
|
21
|
+
case 'opencode':
|
|
22
|
+
return shouldResume ? `opencode --session ${quoteForPosix(normalizedSessionId)}` : 'opencode';
|
|
23
|
+
case 'claude':
|
|
24
|
+
default:
|
|
25
|
+
return shouldResume ? `claude --resume ${quoteForPosix(normalizedSessionId)} || claude` : 'claude';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function buildPowerShellProviderCommand({ provider = 'claude', sessionId = null, hasSession = false } = {}) {
|
|
30
|
+
const normalizedProvider = String(provider || 'claude').trim().toLowerCase();
|
|
31
|
+
const normalizedSessionId = typeof sessionId === 'string' ? sessionId.trim() : '';
|
|
32
|
+
const shouldResume = Boolean(hasSession && normalizedSessionId);
|
|
33
|
+
|
|
34
|
+
switch (normalizedProvider) {
|
|
35
|
+
case 'codex':
|
|
36
|
+
return shouldResume ? `codex resume ${quoteForPowerShell(normalizedSessionId)}` : 'codex';
|
|
37
|
+
case 'gemini':
|
|
38
|
+
return shouldResume ? `npx -y @google/gemini-cli --resume ${quoteForPowerShell(normalizedSessionId)}` : 'npx -y @google/gemini-cli';
|
|
39
|
+
case 'opencode':
|
|
40
|
+
return shouldResume ? `opencode --session ${quoteForPowerShell(normalizedSessionId)}` : 'opencode';
|
|
41
|
+
case 'claude':
|
|
42
|
+
default:
|
|
43
|
+
return shouldResume
|
|
44
|
+
? `claude --resume ${quoteForPowerShell(normalizedSessionId)}; if ($LASTEXITCODE -ne 0) { claude }`
|
|
45
|
+
: 'claude';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function buildShellCommand({
|
|
50
|
+
projectPath,
|
|
51
|
+
provider = 'claude',
|
|
52
|
+
sessionId = null,
|
|
53
|
+
hasSession = false,
|
|
54
|
+
initialCommand = null,
|
|
55
|
+
isPlainShell = false,
|
|
56
|
+
platform = os.platform()
|
|
57
|
+
}) {
|
|
58
|
+
const projectDirectory = String(projectPath || '').trim();
|
|
59
|
+
const isWindows = platform === 'win32';
|
|
60
|
+
const cdCommand = isWindows
|
|
61
|
+
? `Set-Location -Path ${quoteForPowerShell(projectDirectory)}`
|
|
62
|
+
: `cd ${quoteForPosix(projectDirectory)}`;
|
|
63
|
+
const providerCommand = isPlainShell
|
|
64
|
+
? String(initialCommand || '')
|
|
65
|
+
: isWindows
|
|
66
|
+
? buildPowerShellProviderCommand({ provider, sessionId, hasSession })
|
|
67
|
+
: buildPosixProviderCommand({ provider, sessionId, hasSession });
|
|
68
|
+
|
|
69
|
+
return `${cdCommand}; ${providerCommand}`;
|
|
70
|
+
}
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
export const ACP_CAPABILITY_KEYS = ['model', 'mode', 'thought_level'];
|
|
2
|
+
export const ACP_CAPABILITY_CACHE_TTL_MS = 30 * 60 * 1000;
|
|
3
|
+
export const ACP_DEFAULT_CAPABILITY_SCHEMA_VERSION = 1;
|
|
4
|
+
|
|
5
|
+
function cloneJsonValue(value) {
|
|
6
|
+
if (value === undefined) return undefined;
|
|
7
|
+
return JSON.parse(JSON.stringify(value));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function normalizeString(value) {
|
|
11
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function normalizeAcpCommandKey(command) {
|
|
15
|
+
return normalizeString(command?.name ?? command?.command ?? command?.id)
|
|
16
|
+
.replace(/^\/+/, '')
|
|
17
|
+
.toLowerCase();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalizeCapabilityOption(option, index = 0) {
|
|
21
|
+
if (option == null) return null;
|
|
22
|
+
|
|
23
|
+
if (typeof option === 'string' || typeof option === 'number' || typeof option === 'boolean') {
|
|
24
|
+
const value = String(option).trim();
|
|
25
|
+
return value ? { value, label: value, description: '', order: index } : null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (typeof option !== 'object' || Array.isArray(option)) return null;
|
|
29
|
+
|
|
30
|
+
const rawValue = option.value ?? option.id ?? option.modeId ?? option.const ?? option.enum?.[0] ?? option.name;
|
|
31
|
+
const value = normalizeString(rawValue);
|
|
32
|
+
if (!value) return null;
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
value,
|
|
36
|
+
label: normalizeString(option.label ?? option.title ?? option.name ?? option.description) || value,
|
|
37
|
+
description: normalizeString(option.description),
|
|
38
|
+
...(option.default === true ? { default: true } : {}),
|
|
39
|
+
order: Number.isInteger(option.order) ? option.order : index
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function collectSelectOptions(options) {
|
|
44
|
+
if (!Array.isArray(options)) return [];
|
|
45
|
+
|
|
46
|
+
return options.flatMap((option, index) => {
|
|
47
|
+
if (Array.isArray(option?.options)) {
|
|
48
|
+
return option.options.map((item, childIndex) => normalizeCapabilityOption(item, childIndex)).filter(Boolean);
|
|
49
|
+
}
|
|
50
|
+
return normalizeCapabilityOption(option, index) || [];
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function collectSchemaOptions(schema) {
|
|
55
|
+
if (!schema || typeof schema !== 'object') return [];
|
|
56
|
+
|
|
57
|
+
const direct =
|
|
58
|
+
(Array.isArray(schema.options) && schema.options) ||
|
|
59
|
+
(Array.isArray(schema.enum) && schema.enum) ||
|
|
60
|
+
(Array.isArray(schema.oneOf) && schema.oneOf) ||
|
|
61
|
+
(Array.isArray(schema.anyOf) && schema.anyOf) ||
|
|
62
|
+
[];
|
|
63
|
+
|
|
64
|
+
return collectSelectOptions(direct);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function dedupeOptions(options = []) {
|
|
68
|
+
const seen = new Set();
|
|
69
|
+
return options.filter((option) => {
|
|
70
|
+
const value = normalizeString(option?.value);
|
|
71
|
+
if (!value || seen.has(value)) return false;
|
|
72
|
+
seen.add(value);
|
|
73
|
+
return true;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function normalizeAcpConfigOptions(value) {
|
|
78
|
+
const configOptions = Array.isArray(value?.configOptions)
|
|
79
|
+
? value.configOptions
|
|
80
|
+
: Array.isArray(value)
|
|
81
|
+
? value
|
|
82
|
+
: [];
|
|
83
|
+
|
|
84
|
+
return configOptions
|
|
85
|
+
.filter((option) => {
|
|
86
|
+
if (!option || typeof option !== 'object') return false;
|
|
87
|
+
return normalizeString(option.key ?? option.id ?? option.category);
|
|
88
|
+
})
|
|
89
|
+
.map((option) => ({
|
|
90
|
+
key: normalizeString(option.key ?? option.id ?? option.category),
|
|
91
|
+
id: normalizeString(option.id ?? option.key),
|
|
92
|
+
category: normalizeString(option.category),
|
|
93
|
+
type: normalizeString(option.type),
|
|
94
|
+
name: normalizeString(option.name),
|
|
95
|
+
description: normalizeString(option.description),
|
|
96
|
+
value: cloneJsonValue(option.value ?? option.currentValue),
|
|
97
|
+
currentValue: cloneJsonValue(option.currentValue),
|
|
98
|
+
options: Array.isArray(option.options) ? cloneJsonValue(option.options) : [],
|
|
99
|
+
schema: option.schema && typeof option.schema === 'object' ? cloneJsonValue(option.schema) : null
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function normalizeAcpModeState(value) {
|
|
104
|
+
if (!value || typeof value !== 'object') return null;
|
|
105
|
+
|
|
106
|
+
const availableModes = Array.isArray(value.availableModes)
|
|
107
|
+
? value.availableModes
|
|
108
|
+
.map((mode, index) => {
|
|
109
|
+
if (!mode || typeof mode !== 'object') return null;
|
|
110
|
+
const id = normalizeString(mode.id ?? mode.modeId ?? mode.value);
|
|
111
|
+
if (!id) return null;
|
|
112
|
+
return {
|
|
113
|
+
id,
|
|
114
|
+
name: normalizeString(mode.name ?? mode.label ?? id) || id,
|
|
115
|
+
description: mode.description == null ? null : String(mode.description),
|
|
116
|
+
order: index
|
|
117
|
+
};
|
|
118
|
+
})
|
|
119
|
+
.filter(Boolean)
|
|
120
|
+
: [];
|
|
121
|
+
const currentModeId = normalizeString(value.currentModeId ?? value.currentMode?.modeId ?? value.currentMode?.id);
|
|
122
|
+
|
|
123
|
+
if (!availableModes.length && !currentModeId) return null;
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
availableModes,
|
|
127
|
+
currentModeId: currentModeId || availableModes[0]?.id || null
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function normalizeAcpTokenUsage(value) {
|
|
132
|
+
if (!value || typeof value !== 'object') return null;
|
|
133
|
+
|
|
134
|
+
if (value.used == null || (value.total == null && value.size == null)) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const used = Number(value.used);
|
|
139
|
+
const total = Number(value.total ?? value.size);
|
|
140
|
+
if (!Number.isFinite(used) || used < 0 || !Number.isFinite(total) || total < 0) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const safeUsed = Math.round(used);
|
|
145
|
+
const safeTotal = Math.round(total);
|
|
146
|
+
const percentage = safeTotal > 0
|
|
147
|
+
? Math.min(100, Math.max(0, Math.round((safeUsed / safeTotal) * 100)))
|
|
148
|
+
: 0;
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
used: safeUsed,
|
|
152
|
+
total: safeTotal,
|
|
153
|
+
percentage,
|
|
154
|
+
remaining: Math.max(0, safeTotal - safeUsed),
|
|
155
|
+
cost: value.cost && typeof value.cost === 'object' ? cloneJsonValue(value.cost) : null
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function normalizeAcpAvailableCommands(value) {
|
|
160
|
+
const availableCommands = Array.isArray(value?.availableCommands)
|
|
161
|
+
? value.availableCommands
|
|
162
|
+
: Array.isArray(value)
|
|
163
|
+
? value
|
|
164
|
+
: [];
|
|
165
|
+
|
|
166
|
+
return availableCommands
|
|
167
|
+
.map((command) => {
|
|
168
|
+
if (!command || typeof command !== 'object' || Array.isArray(command)) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const name = normalizeString(command.name ?? command.command ?? command.id).replace(/^\/+/, '');
|
|
173
|
+
if (!name) return null;
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
name,
|
|
177
|
+
description: command.description == null ? '' : String(command.description),
|
|
178
|
+
input: command.input && typeof command.input === 'object' ? cloneJsonValue(command.input) : null,
|
|
179
|
+
source: 'acp'
|
|
180
|
+
};
|
|
181
|
+
})
|
|
182
|
+
.filter(Boolean);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function capabilityFromConfigOption(option) {
|
|
186
|
+
const key = normalizeString(option?.category) || normalizeString(option?.key);
|
|
187
|
+
if (!ACP_CAPABILITY_KEYS.includes(key)) return null;
|
|
188
|
+
|
|
189
|
+
const currentValueOption = normalizeCapabilityOption(option.currentValue);
|
|
190
|
+
const valueOption = normalizeCapabilityOption(option.value);
|
|
191
|
+
const options = dedupeOptions([
|
|
192
|
+
...collectSelectOptions(option.options),
|
|
193
|
+
...collectSchemaOptions(option.schema),
|
|
194
|
+
...(currentValueOption ? [currentValueOption] : valueOption ? [valueOption] : [])
|
|
195
|
+
]);
|
|
196
|
+
const currentValue = currentValueOption?.value || valueOption?.value || options.find((item) => item.default)?.value || '';
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
key,
|
|
200
|
+
configId: normalizeString(option.id) || normalizeString(option.key) || key,
|
|
201
|
+
configKey: normalizeString(option.key) || normalizeString(option.id) || key,
|
|
202
|
+
category: normalizeString(option.category) || key,
|
|
203
|
+
description: normalizeString(option.description),
|
|
204
|
+
value: option.value === undefined ? null : cloneJsonValue(option.value),
|
|
205
|
+
currentValue,
|
|
206
|
+
options,
|
|
207
|
+
schema: option.schema && typeof option.schema === 'object' ? cloneJsonValue(option.schema) : null
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function capabilityFromModeState(modeState) {
|
|
212
|
+
const normalized = normalizeAcpModeState(modeState);
|
|
213
|
+
if (!normalized) return null;
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
key: 'mode',
|
|
217
|
+
description: '',
|
|
218
|
+
value: normalized.currentModeId,
|
|
219
|
+
currentValue: normalized.currentModeId || '',
|
|
220
|
+
options: normalized.availableModes.map((mode, index) => ({
|
|
221
|
+
value: mode.id,
|
|
222
|
+
label: mode.name || mode.id,
|
|
223
|
+
description: mode.description || '',
|
|
224
|
+
order: index
|
|
225
|
+
})),
|
|
226
|
+
modeState: normalized
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function mergeCapability(previous, next) {
|
|
231
|
+
if (!previous) return next || null;
|
|
232
|
+
if (!next) return previous;
|
|
233
|
+
|
|
234
|
+
const options = Array.isArray(next.options)
|
|
235
|
+
? dedupeOptions(next.options)
|
|
236
|
+
: dedupeOptions(Array.isArray(previous.options) ? previous.options : []);
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
...previous,
|
|
240
|
+
...next,
|
|
241
|
+
options,
|
|
242
|
+
currentValue: Object.prototype.hasOwnProperty.call(next, 'currentValue')
|
|
243
|
+
? (next.currentValue || '')
|
|
244
|
+
: (previous.currentValue || '')
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function buildAcpCapabilities({
|
|
249
|
+
configOptions = [],
|
|
250
|
+
modeState = null,
|
|
251
|
+
tokenUsage = null,
|
|
252
|
+
availableCommands = [],
|
|
253
|
+
provider = null,
|
|
254
|
+
source = 'session',
|
|
255
|
+
agentVersion = null,
|
|
256
|
+
updatedAt = null
|
|
257
|
+
} = {}) {
|
|
258
|
+
const capabilities = {};
|
|
259
|
+
|
|
260
|
+
for (const option of normalizeAcpConfigOptions(configOptions)) {
|
|
261
|
+
const capability = capabilityFromConfigOption(option);
|
|
262
|
+
if (capability) {
|
|
263
|
+
capabilities[capability.key] = mergeCapability(capabilities[capability.key], capability);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const modeCapability = capabilityFromModeState(modeState);
|
|
268
|
+
if (modeCapability) {
|
|
269
|
+
capabilities.mode = mergeCapability(capabilities.mode, modeCapability);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
provider: provider ? normalizeString(provider).toLowerCase() : null,
|
|
274
|
+
source,
|
|
275
|
+
updatedAt: updatedAt || new Date().toISOString(),
|
|
276
|
+
ttl: ACP_CAPABILITY_CACHE_TTL_MS,
|
|
277
|
+
agentVersion: agentVersion || null,
|
|
278
|
+
capabilities,
|
|
279
|
+
metadata: {
|
|
280
|
+
tokenUsage: normalizeAcpTokenUsage(tokenUsage),
|
|
281
|
+
availableCommands: normalizeAcpAvailableCommands(availableCommands)
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function mergeAcpAvailableCommands(previousCommands = [], nextCommands = []) {
|
|
287
|
+
const merged = [];
|
|
288
|
+
const seen = new Set();
|
|
289
|
+
|
|
290
|
+
for (const command of [
|
|
291
|
+
...normalizeAcpAvailableCommands(nextCommands),
|
|
292
|
+
...normalizeAcpAvailableCommands(previousCommands)
|
|
293
|
+
]) {
|
|
294
|
+
const key = normalizeAcpCommandKey(command);
|
|
295
|
+
if (!key || seen.has(key)) continue;
|
|
296
|
+
seen.add(key);
|
|
297
|
+
merged.push(command);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return merged;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function mergeAcpCapabilitySnapshots(previous = null, next = null) {
|
|
304
|
+
if (!previous) return next || null;
|
|
305
|
+
if (!next) return previous;
|
|
306
|
+
|
|
307
|
+
const capabilities = { ...(previous.capabilities || {}) };
|
|
308
|
+
for (const key of ACP_CAPABILITY_KEYS) {
|
|
309
|
+
capabilities[key] = mergeCapability(capabilities[key], next.capabilities?.[key]);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
...previous,
|
|
314
|
+
...next,
|
|
315
|
+
capabilities,
|
|
316
|
+
metadata: {
|
|
317
|
+
...(previous.metadata || {}),
|
|
318
|
+
...(next.metadata || {}),
|
|
319
|
+
tokenUsage: next.metadata?.tokenUsage || previous.metadata?.tokenUsage || null,
|
|
320
|
+
availableCommands: mergeAcpAvailableCommands(
|
|
321
|
+
previous.metadata?.availableCommands,
|
|
322
|
+
next.metadata?.availableCommands
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function normalizeCapabilitySnapshot(provider, snapshot, { source = null, updatedAt = null } = {}) {
|
|
329
|
+
if (!snapshot || typeof snapshot !== 'object' || Array.isArray(snapshot)) {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const normalizedProvider = normalizeString(snapshot.provider || provider).toLowerCase();
|
|
334
|
+
if (!normalizedProvider) {
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return {
|
|
339
|
+
...cloneJsonValue(snapshot),
|
|
340
|
+
provider: normalizedProvider,
|
|
341
|
+
source: source || normalizeString(snapshot.source) || 'generated-default',
|
|
342
|
+
updatedAt: normalizeString(snapshot.updatedAt) || updatedAt || new Date().toISOString(),
|
|
343
|
+
ttl: Number.isFinite(Number(snapshot.ttl)) && Number(snapshot.ttl) > 0
|
|
344
|
+
? Number(snapshot.ttl)
|
|
345
|
+
: ACP_CAPABILITY_CACHE_TTL_MS,
|
|
346
|
+
agentVersion: snapshot.agentVersion || null,
|
|
347
|
+
capabilities: snapshot.capabilities && typeof snapshot.capabilities === 'object'
|
|
348
|
+
? cloneJsonValue(snapshot.capabilities)
|
|
349
|
+
: {},
|
|
350
|
+
metadata: snapshot.metadata && typeof snapshot.metadata === 'object'
|
|
351
|
+
? {
|
|
352
|
+
...cloneJsonValue(snapshot.metadata),
|
|
353
|
+
tokenUsage: normalizeAcpTokenUsage(snapshot.metadata.tokenUsage),
|
|
354
|
+
availableCommands: normalizeAcpAvailableCommands(snapshot.metadata.availableCommands)
|
|
355
|
+
}
|
|
356
|
+
: {
|
|
357
|
+
tokenUsage: null,
|
|
358
|
+
availableCommands: []
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export function normalizeAcpDefaultCapabilityRegistry(value = {}) {
|
|
364
|
+
const generatedAt = normalizeString(value?.generatedAt) || new Date().toISOString();
|
|
365
|
+
const providers = {};
|
|
366
|
+
const rawProviders = value?.providers && typeof value.providers === 'object'
|
|
367
|
+
? value.providers
|
|
368
|
+
: {};
|
|
369
|
+
|
|
370
|
+
for (const [providerName, snapshot] of Object.entries(rawProviders)) {
|
|
371
|
+
const normalized = normalizeCapabilitySnapshot(providerName, snapshot, {
|
|
372
|
+
source: 'generated-default',
|
|
373
|
+
updatedAt: generatedAt
|
|
374
|
+
});
|
|
375
|
+
if (normalized) {
|
|
376
|
+
providers[normalized.provider] = normalized;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return {
|
|
381
|
+
schemaVersion: Number(value?.schemaVersion) || ACP_DEFAULT_CAPABILITY_SCHEMA_VERSION,
|
|
382
|
+
generatedAt,
|
|
383
|
+
providers
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export function getAcpDefaultCapabilitySnapshot(registry, provider) {
|
|
388
|
+
const normalizedRegistry = normalizeAcpDefaultCapabilityRegistry(registry);
|
|
389
|
+
const normalizedProvider = normalizeString(provider).toLowerCase();
|
|
390
|
+
return normalizedProvider
|
|
391
|
+
? normalizedRegistry.providers[normalizedProvider] || null
|
|
392
|
+
: null;
|
|
393
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"generatedAt": "2026-05-14T03:19:23.238Z",
|
|
4
|
+
"providers": {
|
|
5
|
+
"codex": {
|
|
6
|
+
"provider": "codex",
|
|
7
|
+
"source": "generated-default",
|
|
8
|
+
"updatedAt": "2026-05-14T03:19:23.238Z",
|
|
9
|
+
"ttl": 1800000,
|
|
10
|
+
"agentVersion": null,
|
|
11
|
+
"capabilities": {
|
|
12
|
+
"model": {
|
|
13
|
+
"key": "model",
|
|
14
|
+
"description": "Choose which model Codex should use",
|
|
15
|
+
"value": "gpt-5.5",
|
|
16
|
+
"currentValue": "gpt-5.5",
|
|
17
|
+
"options": [
|
|
18
|
+
{
|
|
19
|
+
"value": "gpt-5.5",
|
|
20
|
+
"label": "GPT-5.5",
|
|
21
|
+
"description": "Frontier model for complex coding, research, and real-world work.",
|
|
22
|
+
"order": 0
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"value": "gpt-5.4",
|
|
26
|
+
"label": "gpt-5.4",
|
|
27
|
+
"description": "Strong model for everyday coding.",
|
|
28
|
+
"order": 1
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"value": "gpt-5.4-mini",
|
|
32
|
+
"label": "GPT-5.4-Mini",
|
|
33
|
+
"description": "Small, fast, and cost-efficient model for simpler coding tasks.",
|
|
34
|
+
"order": 2
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"value": "gpt-5.3-codex",
|
|
38
|
+
"label": "gpt-5.3-codex",
|
|
39
|
+
"description": "Coding-optimized model.",
|
|
40
|
+
"order": 3
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"value": "gpt-5.2",
|
|
44
|
+
"label": "gpt-5.2",
|
|
45
|
+
"description": "Optimized for professional work and long-running agents.",
|
|
46
|
+
"order": 4
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"schema": null
|
|
50
|
+
},
|
|
51
|
+
"mode": {
|
|
52
|
+
"key": "mode",
|
|
53
|
+
"description": "Choose an approval and sandboxing preset for your session",
|
|
54
|
+
"value": "auto",
|
|
55
|
+
"currentValue": "auto",
|
|
56
|
+
"options": [
|
|
57
|
+
{
|
|
58
|
+
"value": "read-only",
|
|
59
|
+
"label": "Read Only",
|
|
60
|
+
"description": "Codex can read files in the current workspace. Approval is required to edit files or access the internet.",
|
|
61
|
+
"order": 0
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"value": "auto",
|
|
65
|
+
"label": "Default",
|
|
66
|
+
"description": "Codex can read and edit files in the current workspace, and run commands. Approval is required to access the internet or edit other files. (Identical to Agent mode)",
|
|
67
|
+
"order": 1
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"value": "full-access",
|
|
71
|
+
"label": "Full Access",
|
|
72
|
+
"description": "Codex can edit files outside this workspace and access the internet without asking for approval. Exercise caution when using.",
|
|
73
|
+
"order": 2
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"schema": null,
|
|
77
|
+
"modeState": {
|
|
78
|
+
"availableModes": [
|
|
79
|
+
{
|
|
80
|
+
"id": "read-only",
|
|
81
|
+
"name": "Read Only",
|
|
82
|
+
"description": "Codex can read files in the current workspace. Approval is required to edit files or access the internet.",
|
|
83
|
+
"order": 0
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"id": "auto",
|
|
87
|
+
"name": "Default",
|
|
88
|
+
"description": "Codex can read and edit files in the current workspace, and run commands. Approval is required to access the internet or edit other files. (Identical to Agent mode)",
|
|
89
|
+
"order": 1
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "full-access",
|
|
93
|
+
"name": "Full Access",
|
|
94
|
+
"description": "Codex can edit files outside this workspace and access the internet without asking for approval. Exercise caution when using.",
|
|
95
|
+
"order": 2
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"currentModeId": "auto"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"thought_level": {
|
|
102
|
+
"key": "thought_level",
|
|
103
|
+
"description": "Choose how much reasoning effort the model should use",
|
|
104
|
+
"value": "xhigh",
|
|
105
|
+
"currentValue": "xhigh",
|
|
106
|
+
"options": [
|
|
107
|
+
{
|
|
108
|
+
"value": "low",
|
|
109
|
+
"label": "Low",
|
|
110
|
+
"description": "Fast responses with lighter reasoning",
|
|
111
|
+
"order": 0
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"value": "medium",
|
|
115
|
+
"label": "Medium",
|
|
116
|
+
"description": "Balances speed and reasoning depth for everyday tasks",
|
|
117
|
+
"order": 1
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"value": "high",
|
|
121
|
+
"label": "High",
|
|
122
|
+
"description": "Greater reasoning depth for complex problems",
|
|
123
|
+
"order": 2
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"value": "xhigh",
|
|
127
|
+
"label": "Xhigh",
|
|
128
|
+
"description": "Extra high reasoning depth for complex problems",
|
|
129
|
+
"order": 3
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
"schema": null
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"metadata": {
|
|
136
|
+
"tokenUsage": null,
|
|
137
|
+
"availableCommands": []
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|