@platless/axom-cli 0.5.9 → 0.6.36
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 +18 -5
- package/dist/axom-patch/cli/README.md +100 -12
- package/dist/axom-patch/cli/account-limits/generate.py +15 -12
- package/dist/axom-patch/cli/account-limits/kimi-proxy.mjs +20 -3
- package/dist/axom-patch/cli/claude-account-limits.json +9 -9
- package/dist/axom-patch/cli/codex-account-limits.json +11 -11
- package/dist/axom-patch/cli/codex-terminal-output.json +16 -0
- package/dist/axom-patch/cli/commandcode-account-limits.json +9 -9
- package/dist/axom-patch/cli/kimi-quota.mjs +12 -0
- package/dist/axom-patch/cli/kimi-subagents.mjs +173 -0
- package/dist/axom-patch/cli/nightly-task.md +55 -13
- package/dist/axom-patch/cli/probes/codex-terminal-output.mjs +33 -0
- package/dist/axom-patch/cli/probes/kimi-subagent-subwork.mjs +82 -0
- package/dist/axom-patch/cli/qoder/dist/axom-acp-compat.mjs +1591 -0
- package/dist/axom-patch/cli/qoder/releases/1.1.75.json +360 -0
- package/dist/axom-patch/cli/qoder-background-terminal.md +13 -6
- package/dist/axom-patch/cli/qoder-foreground-output.md +14 -8
- package/dist/axom-patch/cli/qoder-native-acp.json +227 -0
- package/dist/axom-patch/cli/qoder-steering.md +20 -25
- package/dist/axom-patch/cli/qoder-subagent-subwork.md +17 -68
- package/dist/axom-patch/cli/runtime.json +16 -18
- package/dist/axom-patch/cli/zcode-account-limits.json +10 -11
- package/dist/axom-patch/cli/zcode-models.json +1 -2
- package/dist/axom-patch/cli/zcode-subagent-subwork.json +9 -10
- package/dist/cli.js +4 -36
- package/dist/commands/knowledge.js +47 -0
- package/dist/commands/update.js +65 -3
- package/dist/commands/workstation.js +73 -7
- package/dist/install/claude/commands.js +13 -13
- package/dist/mcp.js +1 -1
- package/dist/native/darwin-arm64/axom-quic +0 -0
- package/dist/workstation/acp/acpAgents.js +102 -98
- package/dist/workstation/acp/acpClient.js +26 -0
- package/dist/workstation/acp/builds/install/npm.js +99 -10
- package/dist/workstation/acp/initializeResponse.js +6 -1
- package/dist/workstation/acp/managedPatches.js +189 -25
- package/dist/workstation/acp/managedRuntime.js +314 -0
- package/dist/workstation/acp/patchAssets.js +40 -0
- package/dist/workstation/acp/processor/checkpoint.js +25 -34
- package/dist/workstation/acp/processor/control.js +5 -78
- package/dist/workstation/acp/processor/runtime.js +5 -81
- package/dist/workstation/acp/processor/session.js +51 -80
- package/dist/workstation/acp/processor/state.js +6 -13
- package/dist/workstation/acp/processor/step.js +3 -20
- package/dist/workstation/acp/processor/test/fixtureLog.js +9 -16
- package/dist/workstation/acp/processor/updates.js +131 -105
- package/dist/workstation/acp/processorSession.js +8 -172
- package/dist/workstation/acp/registry/catalog.js +65 -39
- package/dist/workstation/acp/registry/launch.js +16 -1
- package/dist/workstation/acp/switching.js +0 -3
- package/dist/workstation/acp/test/fakeAgent.js +13 -0
- package/dist/workstation/acp/test/keeperWorld.js +28 -0
- package/dist/workstation/acp/test/raw/sources.js +16 -130
- package/dist/workstation/acp/test/realAdapter.js +1 -47
- package/dist/workstation/acp/test/scriptAgent.js +11 -3
- package/dist/workstation/agentFlow.js +1 -1
- package/dist/workstation/agentSessions.js +38 -143
- package/dist/workstation/channels/management.js +95 -11
- package/dist/workstation/channels/url.js +1 -1
- package/dist/workstation/config.js +16 -4
- package/dist/workstation/connection/encryptedChannel.js +4 -1
- package/dist/workstation/control/bindingStore.js +200 -0
- package/dist/workstation/control/commands.js +124 -0
- package/dist/workstation/control/daemonIdentity.js +53 -0
- package/dist/workstation/control/enrollment.js +106 -0
- package/dist/workstation/control/inspect.js +71 -0
- package/dist/workstation/control/locks.js +63 -0
- package/dist/workstation/control/protocol.js +40 -0
- package/dist/workstation/control/restartGuard.js +46 -0
- package/dist/workstation/control/runtimeClient.js +97 -0
- package/dist/workstation/control/runtimeHost.js +148 -0
- package/dist/workstation/control/serverIdentity.js +35 -0
- package/dist/workstation/daemon.js +106 -6
- package/dist/workstation/daemonctl.js +77 -14
- package/dist/workstation/desktopControl/audio.js +99 -0
- package/dist/workstation/desktopControl/capabilities.js +92 -0
- package/dist/workstation/desktopControl/captureModes.js +9 -0
- package/dist/workstation/desktopControl/captureTargetLabel.js +9 -0
- package/dist/workstation/desktopControl/deviceSockets.js +246 -0
- package/dist/workstation/desktopControl/helperProcess.js +353 -0
- package/dist/workstation/desktopControl/lobby.js +129 -0
- package/dist/workstation/desktopControl/macProvider.js +155 -0
- package/dist/workstation/desktopControl/media.js +331 -0
- package/dist/workstation/desktopControl/nativeProvider.js +1018 -0
- package/dist/workstation/desktopControl/networkEvidence.js +43 -0
- package/dist/workstation/desktopControl/overview.js +58 -0
- package/dist/workstation/desktopControl/protocol.js +302 -0
- package/dist/workstation/desktopControl/quicMedia.js +240 -0
- package/dist/workstation/desktopControl/rateController.js +226 -0
- package/dist/workstation/desktopControl/supervisor.js +1681 -0
- package/dist/workstation/desktopControl/transport.js +27 -0
- package/dist/workstation/desktopControl/wallpaper.js +78 -0
- package/dist/workstation/files/credentials.js +142 -0
- package/dist/workstation/files/text.js +42 -8
- package/dist/workstation/keepers/kit/bundle.js +21 -17
- package/dist/workstation/keepers/kit/launcher.js +47 -7
- package/dist/workstation/keepers/kit/paths.js +2 -1
- package/dist/workstation/managedInstall.js +57 -0
- package/dist/workstation/protocol/agent.js +2 -15
- package/dist/workstation/protocol/management.js +93 -4
- package/dist/workstation/protocol/runtimeDiagnostics.js +15 -0
- package/dist/workstation/rd/artifact.js +119 -0
- package/dist/workstation/rd/control.js +119 -0
- package/dist/workstation/rd/display.js +29 -0
- package/dist/workstation/rd/provider.js +222 -0
- package/dist/workstation/rd/sessions.js +391 -0
- package/dist/workstation/rd/state.js +45 -0
- package/dist/workstation/rd/update.js +171 -0
- package/dist/workstation/rd/upkeep.js +38 -0
- package/dist/workstation/register.js +27 -37
- package/dist/workstation/service/installer.js +104 -13
- package/dist/workstation/service/launchd.js +1 -0
- package/dist/workstation/storageMetrics.js +118 -0
- package/dist/workstation/systemMetrics.js +44 -92
- package/dist/workstation/toolchain.js +94 -0
- package/dist/workstation/tools/browser.js +28 -4
- package/dist/workstation/update/artifact.js +2 -1
- package/dist/workstation/update/globalInstall.js +116 -0
- package/dist/workstation/update/npmInstaller.js +49 -23
- package/dist/workstation/update/rdRollback.js +145 -0
- package/dist/workstation/update/runUpdate.js +3 -2
- package/dist/workstation/update/watchdog.js +16790 -334
- package/package.json +5 -5
- package/skills/axom/SKILL.md +11 -11
- package/skills/axom-definition/SKILL.md +3 -3
- package/skills/axom-platform/SKILL.md +3 -3
- package/dist/axom-patch/cli/probes/qoder-steering.mjs +0 -89
- package/dist/axom-patch/cli/probes/qoder-subagent-origin.mjs +0 -61
- package/dist/axom-patch/cli/qoder-steering.json +0 -52
- package/dist/axom-patch/cli/qoder-subagent-origin.json +0 -73
- package/dist/commands/guide.js +0 -38
- package/dist/runtime-deps/qoder-sdk/package-lock.json +0 -1189
- package/dist/runtime-deps/qoder-sdk/package.json +0 -8
- package/dist/workstation/acp/delegationMcp.js +0 -24
- package/dist/workstation/acp/processor/sideChannel.js +0 -80
- package/dist/workstation/acp/qoderStartup.js +0 -45
- package/dist/workstation/acp/test/raw/qoderCaptures.js +0 -125
- package/dist/workstation/qoderAdapter/backgroundProcess.js +0 -118
- package/dist/workstation/qoderAdapter/backgroundTerminal.js +0 -193
- package/dist/workstation/qoderAdapter/backgroundTerminalFold.js +0 -372
- package/dist/workstation/qoderAdapter/callbackContext.js +0 -76
- package/dist/workstation/qoderAdapter/completedContinuation.js +0 -139
- package/dist/workstation/qoderAdapter/contract.js +0 -78
- package/dist/workstation/qoderAdapter/foregroundOutput.js +0 -36
- package/dist/workstation/qoderAdapter/history.js +0 -85
- package/dist/workstation/qoderAdapter/identityIndex.js +0 -191
- package/dist/workstation/qoderAdapter/inputQueue.js +0 -42
- package/dist/workstation/qoderAdapter/main.js +0 -95
- package/dist/workstation/qoderAdapter/mapper.js +0 -117
- package/dist/workstation/qoderAdapter/observerPlugin.js +0 -245
- package/dist/workstation/qoderAdapter/observerReceiver.js +0 -187
- package/dist/workstation/qoderAdapter/permissions.js +0 -61
- package/dist/workstation/qoderAdapter/profile.js +0 -93
- package/dist/workstation/qoderAdapter/sdkDriver.js +0 -48
- package/dist/workstation/qoderAdapter/sdkRuntime.js +0 -93
- package/dist/workstation/qoderAdapter/sdkRuntimeInstall.js +0 -145
- package/dist/workstation/qoderAdapter/session.js +0 -319
- package/dist/workstation/qoderAdapter/subagentMeta.js +0 -28
- package/dist/workstation/qoderAdapter/subwork.js +0 -85
- package/dist/workstation/qoderAdapter/taskControl.js +0 -38
- package/dist/workstation/qoderAdapter/taskLedger.js +0 -163
- package/dist/workstation/qoderAdapter/usage.js +0 -37
- /package/dist/workstation/{qoderAdapter/types.js → desktopControl/provider.js} +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {readdir, readFile} from 'node:fs/promises';
|
|
2
|
+
import {homedir} from 'node:os';
|
|
3
|
+
import {join} from 'node:path';
|
|
4
|
+
|
|
5
|
+
const record = value => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
6
|
+
const text = value => typeof value === 'string' ? value : '';
|
|
7
|
+
const terminalStates = new Map([['completed', 'completed'], ['failed', 'failed'], ['killed', 'cancelled'], ['aborted', 'cancelled'], ['lost', 'disconnected'], ['cancelled', 'cancelled']]);
|
|
8
|
+
const terminal = value => terminalStates.get(value);
|
|
9
|
+
const field = (body, name) => body.split('\n\n', 1)[0].match(new RegExp(`^${name}: ([^\\r\\n]+)$`, 'm'))?.[1];
|
|
10
|
+
const notification = (sessionId, update) => ({jsonrpc: '2.0', method: 'session/update', params: {sessionId, update}});
|
|
11
|
+
const outputText = update => typeof update.rawOutput === 'string' ? update.rawOutput : (update.content ?? [])
|
|
12
|
+
.filter(block => block.type === 'content' && block.content?.type === 'text').map(block => block.content.text).join('\n');
|
|
13
|
+
|
|
14
|
+
export class KimiSubagents {
|
|
15
|
+
constructor(emit, {home = process.env.KIMI_CODE_HOME ?? join(homedir(), '.kimi-code')} = {}) {
|
|
16
|
+
this.emit = emit;
|
|
17
|
+
this.home = home;
|
|
18
|
+
this.enabled = false;
|
|
19
|
+
this.requests = new Map();
|
|
20
|
+
this.sessions = new Map();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
fromClient(message) {
|
|
24
|
+
if (!record(message)) return;
|
|
25
|
+
if (message.method === 'initialize') {
|
|
26
|
+
const capabilities = message.params?.clientCapabilities;
|
|
27
|
+
this.enabled = record(capabilities?.subagents) || capabilities?._meta?.jetbrains?.air?.capabilities?.includes('nativeSubagentSessions') === true;
|
|
28
|
+
}
|
|
29
|
+
if (message.id !== undefined && ['initialize', 'session/prompt', 'session/delete', 'session/close'].includes(message.method)) this.requests.set(message.id, {method: message.method, sessionId: message.params?.sessionId});
|
|
30
|
+
if (message.method === 'session/load') this.sessions.delete(message.params?.sessionId);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
session(id) {
|
|
34
|
+
let session = this.sessions.get(id);
|
|
35
|
+
if (!session) {
|
|
36
|
+
session = {calls: new Map(), agents: new Map()};
|
|
37
|
+
this.sessions.set(id, session);
|
|
38
|
+
}
|
|
39
|
+
return session;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
send(sessionId, update) {
|
|
43
|
+
this.emit(notification(sessionId, update));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
spawn(sessionId, session, callId, spec, index) {
|
|
47
|
+
const known = spec.resume && session.agents.get(spec.resume);
|
|
48
|
+
const nativeCallId = callId.replace(/^\d+:/, '');
|
|
49
|
+
const child = {id: known?.id ?? `kimi-agent:${sessionId}:${nativeCallId}:${index}`, name: spec.name, task: spec.task, callId, done: false};
|
|
50
|
+
if (!known) this.send(sessionId, {sessionUpdate: 'subagent_spawned', subagentSessionId: child.id, name: child.name, task: child.task, capabilities: {}});
|
|
51
|
+
else this.send(sessionId, {sessionUpdate: 'subagent_state_update', subagentSessionId: child.id, _meta: {axom: {state: 'running'}}});
|
|
52
|
+
return child;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
start(sessionId, session, call, update) {
|
|
56
|
+
const args = update.rawInput;
|
|
57
|
+
if (!record(args) || call.children.length) return;
|
|
58
|
+
const name = text(args.subagent_type) || 'coder';
|
|
59
|
+
const specs = call.kind === 'AgentSwarm'
|
|
60
|
+
? [...Object.entries(record(args.resume_agent_ids) ? args.resume_agent_ids : {}).map(([resume, task]) => ({resume, task: text(task), name})),
|
|
61
|
+
...(Array.isArray(args.items) ? args.items : []).filter(item => typeof item === 'string').map(item => ({name: `${name}: ${item}`, task: text(args.prompt_template).replaceAll('{{item}}', item), item}))]
|
|
62
|
+
: [{name, task: text(args.prompt), resume: text(args.resume)}];
|
|
63
|
+
call.args = args;
|
|
64
|
+
call.children = specs.slice(0, 128).map((spec, index) => ({...this.spawn(sessionId, session, call.id, spec, index), item: spec.item}));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
finish(sessionId, child, state, body) {
|
|
68
|
+
if (child.done) return;
|
|
69
|
+
child.done = true;
|
|
70
|
+
if (body) this.send(child.id, {sessionUpdate: 'agent_message_chunk', content: {type: 'text', text: body}});
|
|
71
|
+
this.send(sessionId, {sessionUpdate: 'subagent_state_update', subagentSessionId: child.id, state});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
complete(sessionId, session, call, update) {
|
|
75
|
+
if (!call.children.length) {
|
|
76
|
+
call.children = [this.spawn(sessionId, session, call.id, {name: call.kind, task: ''}, 0)];
|
|
77
|
+
}
|
|
78
|
+
const body = outputText(update);
|
|
79
|
+
if (call.kind === 'AgentSwarm') {
|
|
80
|
+
const results = [...body.matchAll(/<subagent\b([^>]*)>([\s\S]*?)<\/subagent>/g)];
|
|
81
|
+
const attribute = (attributes, name) => attributes.match(new RegExp(`(?:^| )${name}="([^"]*)"`))?.[1];
|
|
82
|
+
for (const [index, child] of call.children.entries()) {
|
|
83
|
+
const result = results[index];
|
|
84
|
+
const agentId = result && attribute(result[1], 'agent_id');
|
|
85
|
+
if (agentId) session.agents.set(agentId, child);
|
|
86
|
+
this.finish(sessionId, child, result ? terminal(attribute(result[1], 'outcome')) ?? 'failed' : 'failed', result?.[2] ?? body);
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const child = call.children[0];
|
|
91
|
+
const agentId = field(body, 'agent_id');
|
|
92
|
+
if (agentId) session.agents.set(agentId, child);
|
|
93
|
+
const taskId = field(body, 'task_id');
|
|
94
|
+
if (field(body, 'status') === 'running' && taskId && /^[a-z0-9]+(?:-[a-z0-9]+)*-[0-9a-z]{8}$/.test(taskId)) {
|
|
95
|
+
child.background = {taskId, agentId};
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const state = field(body, 'stop_reason') === 'cancelled' ? 'cancelled' : terminal(field(body, 'status')) ?? (update.status === 'failed' ? 'failed' : 'completed');
|
|
99
|
+
const summary = body.match(/\n\[summary\]\n([\s\S]*?)(?:\n\nresume_hint:|$)/)?.[1];
|
|
100
|
+
this.finish(sessionId, child, state, summary ?? body);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fromAgent(message) {
|
|
104
|
+
if (!record(message)) return false;
|
|
105
|
+
if (!message.method && message.id !== undefined) {
|
|
106
|
+
const request = this.requests.get(message.id);
|
|
107
|
+
this.requests.delete(message.id);
|
|
108
|
+
if (['session/delete', 'session/close'].includes(request?.method) && !message.error) this.sessions.delete(request.sessionId);
|
|
109
|
+
if (this.enabled && request?.method === 'initialize' && message.result?.agentCapabilities) {
|
|
110
|
+
if (record(message.result.agentCapabilities.sessionCapabilities?.subagents)) {
|
|
111
|
+
this.enabled = false;
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
message.result.agentCapabilities.sessionCapabilities ??= {};
|
|
115
|
+
message.result.agentCapabilities.sessionCapabilities.subagents = {};
|
|
116
|
+
}
|
|
117
|
+
if (request?.method === 'session/prompt' && (message.error || message.result?.stopReason === 'cancelled')) {
|
|
118
|
+
const session = this.sessions.get(request.sessionId);
|
|
119
|
+
for (const call of session?.calls.values() ?? []) for (const child of call.children) {
|
|
120
|
+
if (!child.background) this.finish(request.sessionId, child, message.error ? 'failed' : 'cancelled', '');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (!this.enabled || message.method !== 'session/update') return false;
|
|
125
|
+
const {sessionId, update} = message.params ?? {};
|
|
126
|
+
if (!sessionId || !record(update) || !['tool_call', 'tool_call_update'].includes(update.sessionUpdate)) return false;
|
|
127
|
+
if (typeof update.toolCallId !== 'string' || !update.toolCallId) return false;
|
|
128
|
+
const session = this.session(sessionId);
|
|
129
|
+
const id = update.toolCallId;
|
|
130
|
+
let call = session.calls.get(id);
|
|
131
|
+
if (!call) {
|
|
132
|
+
const title = text(update.name) || text(update.title);
|
|
133
|
+
const kind = title === 'AgentSwarm' || title.startsWith('Launching agent swarm:') ? 'AgentSwarm'
|
|
134
|
+
: title === 'Agent' || /^Launching (?:background )?.+ agent:/.test(title) ? 'Agent' : undefined;
|
|
135
|
+
if (!kind) return false;
|
|
136
|
+
call = {id, kind, children: []};
|
|
137
|
+
session.calls.set(id, call);
|
|
138
|
+
}
|
|
139
|
+
this.start(sessionId, session, call, update);
|
|
140
|
+
if (['completed', 'failed'].includes(update.status)) this.complete(sessionId, session, call, update);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async poll() {
|
|
145
|
+
if (this.polling) return;
|
|
146
|
+
this.polling = true;
|
|
147
|
+
try {
|
|
148
|
+
for (const [sessionId, session] of this.sessions) {
|
|
149
|
+
const children = [...session.calls.values()].flatMap(call => call.children).filter(child => child.background && !child.done);
|
|
150
|
+
if (!children.length || !/^session_[a-zA-Z0-9-]+$/.test(sessionId)) continue;
|
|
151
|
+
if (!session.directory) {
|
|
152
|
+
for (const workspace of await readdir(join(this.home, 'sessions'), {withFileTypes: true}).catch(() => [])) {
|
|
153
|
+
if (!workspace.isDirectory()) continue;
|
|
154
|
+
const directory = join(this.home, 'sessions', workspace.name, sessionId);
|
|
155
|
+
const state = await readFile(join(directory, 'state.json'), 'utf8').then(JSON.parse).catch(() => null);
|
|
156
|
+
if (state?.id === sessionId) {session.directory = directory; break;}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (!session.directory) continue;
|
|
160
|
+
for (const child of children) {
|
|
161
|
+
const {taskId, agentId} = child.background;
|
|
162
|
+
const directory = join(session.directory, 'agents', 'main', 'tasks');
|
|
163
|
+
const task = await readFile(join(directory, `${taskId}.json`), 'utf8').then(JSON.parse).catch(() => null);
|
|
164
|
+
if (task?.taskId !== taskId || task.kind !== 'agent' || task.agentId !== agentId) continue;
|
|
165
|
+
const state = terminal(task.status);
|
|
166
|
+
if (!state) continue;
|
|
167
|
+
const body = await readFile(join(directory, taskId, 'output.log'), 'utf8').catch(() => text(task.stopReason));
|
|
168
|
+
if (this.sessions.get(sessionId) === session) this.finish(sessionId, child, state, body);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
} finally {this.polling = false;}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# Nightly 任务:catalog agent 版本升级
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> 流程总入口与全部经验教训见 **[`../DAILY_UPGRADE_CHECK.md`](../DAILY_UPGRADE_CHECK.md)**(唯一权威
|
|
4
|
+
> runbook)。本文件保留 Qoder 原生 ACP 的候选认证门槛细节;两文冲突时以 runbook 为准。
|
|
5
|
+
|
|
6
|
+
供 AI 周期执行的任务说明。Qoder 原生 ACP 候选优先遵循下面的完整认证门槛;发现新版本身不授权改钉版本。**默认产出是把 catalog / runtime.json 的钉版本升到上游最新**:
|
|
4
7
|
对每个有新版本的 agent,判定新版本是否已解决补丁问题(或官方提供了可替代方案),已解决走下线,
|
|
5
8
|
没解决就把补丁移植到新版本并把钉版本升上去。「只分析不升级」是例外,只允许用在判定不了、
|
|
6
9
|
且报告里写明了缺什么证据/设备的情况。
|
|
@@ -8,6 +11,42 @@
|
|
|
8
11
|
与每周一 09:00 的 [`scripts/check-upstream-patches.py`](../../scripts/check-upstream-patches.py)
|
|
9
12
|
(launchd,覆盖全部组件、只产报告)互补:本任务只管 **CLI catalog / adapter 补丁层**,但执行升级。
|
|
10
13
|
|
|
14
|
+
|
|
15
|
+
## Qoder 原生 ACP 候选认证门槛
|
|
16
|
+
|
|
17
|
+
本节覆盖其他段落对 Qoder 的自动升钉建议。先发现官方精确版本,再使用
|
|
18
|
+
`qoder/scripts/build.mjs` 和 `generate.mjs` 生成独立候选;始终运行 `bin.qodercli`
|
|
19
|
+
并记录 `bin.args:["--acp"]`、完整主包文件哈希、现有 ordered recipe `patchDigest`、
|
|
20
|
+
所需平台原生工具身份与哈希。新版本如果无法通过结构化钩子生成,应报告并停止。
|
|
21
|
+
|
|
22
|
+
在 authoring checkout 上执行(Node 必须满足候选策略;不安装定时任务):
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
export EV=/home/admin/agent-artifacts/qoder-nightly-YYYYMMDD
|
|
26
|
+
export TMPDIR="$EV/tmp"
|
|
27
|
+
mkdir -p "$TMPDIR"
|
|
28
|
+
# beaver 外部 npm 下载前加载 ~/.config/vpn/proxy.env。
|
|
29
|
+
# CANDIDATE 为生成的主包目录,其同级 .release.json / .recipe.json 是输入。
|
|
30
|
+
# EVIDENCE 必须位于同一隔离 npm install 的祖先 node_modules 可解析的位置。
|
|
31
|
+
node axom-patch/cli/qoder/scripts/certify.mjs --candidate "$CANDIDATE" --evidence "$EVIDENCE" --platform linux --arch x64 --auth-home "$AUTH_SOURCE_HOME"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`--auth-home` 只把允许的认证文件复制到新 HOME,不复用原始配置或历史。省略时仅跑
|
|
35
|
+
真实 initialize。工具的依赖须用隔离 npm install --ignore-scripts 安装;需要的原生
|
|
36
|
+
helper 只能在新 staging 中设置执行位。认证工具从实际 Node、候选和依赖重算绑定,
|
|
37
|
+
错误平台标签、缺项、重复、陈旧摘要、失败、坏工件或 synthetic 证据均不能通过。
|
|
38
|
+
每次输出新 `run-*` 目录,`result.json` 与 `result.sha256` 禁止覆盖旧结果。
|
|
39
|
+
|
|
40
|
+
后续真实 UI、legacy migration、安装及各平台检查的记录放入 `$EVIDENCE/records/`;
|
|
41
|
+
按 README 的 schema 绑定同一候选、suite、Node、平台、工具和依赖。执行同一命令加
|
|
42
|
+
`--collect-only` 重新验证字节和工件再归并;它不会运行模型或信任旧 PASS 标签。
|
|
43
|
+
不要同时导入一个检查的多次记录,重复即拒绝。直接 ACP next 不等于 insert-button。
|
|
44
|
+
|
|
45
|
+
只有 15 个必需检查在目标平台全部真实 PASS,才可提出钉版本变更。实际 UI、Windows
|
|
46
|
+
或迁移缺失必须报告 NOT_PASS,保留当前钉版本;合成 fixture 只验证 schema。
|
|
47
|
+
不自动发布、升钉、安装 cron、推送或部署。候选/release/historyVersions/suite 变更后
|
|
48
|
+
旧证据作废,必须对最终字节重新执行。
|
|
49
|
+
|
|
11
50
|
## 钉版本规则(本任务的前提)
|
|
12
51
|
|
|
13
52
|
- **Axom 给适配器打了补丁(package_patches 配方 / native_extensions 包装)⇒ 必须钉版本**。
|
|
@@ -41,7 +80,7 @@
|
|
|
41
80
|
|
|
42
81
|
```bash
|
|
43
82
|
cd <repo>
|
|
44
|
-
curl -s --max-time 30 https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json -o /
|
|
83
|
+
curl -s --max-time 30 https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json -o $EV/acp-registry.json
|
|
45
84
|
for p in pi-acp @agentclientprotocol/claude-agent-acp @agentclientprotocol/codex-acp \
|
|
46
85
|
command-code zcode-acp-server @qoder-ai/qodercli; do npm view "$p" version; done
|
|
47
86
|
gh pr view 458 -R agentclientprotocol/registry --json state,title # kimi-code 收录
|
|
@@ -57,7 +96,7 @@ python3 -c "import json;d=json.load(open('$HOME/.axom/workstation/acp-adapters/b
|
|
|
57
96
|
| claude-acp | npm @agentclientprotocol/claude-agent-acp | catalog.ts `distribution` | claude-account-limits + launchEnv |
|
|
58
97
|
| codex-acp | npm @agentclientprotocol/codex-acp | catalog.ts `distribution` | codex-account-limits + launchEnv |
|
|
59
98
|
| pi-acp | npm pi-acp | catalog.ts `distribution` | pi-steering、pi-subagent-subwork |
|
|
60
|
-
| qoder | npm @qoder-ai/qodercli | runtime.json
|
|
99
|
+
| qoder | npm @qoder-ai/qodercli@1.1.75 | catalog.ts 固定 `--acp` + `qoder-native-acp` package patch;runtime.json `install_policies` 禁用 npm scripts | qoder-native-acp |
|
|
61
100
|
| kimi-code | GitHub release 二进制 | catalog.ts `supplement` | native extension kimi-proxy |
|
|
62
101
|
| command-code | npm command-code | catalog.ts `supplement` | commandcode-account-limits |
|
|
63
102
|
| zcode-acp | npm zcode-acp-server | catalog.ts `supplement` | zcode-account-limits、zcode-models、zcode-subagent-subwork |
|
|
@@ -82,7 +121,7 @@ python3 -c "import json;d=json.load(open('$HOME/.axom/workstation/acp-adapters/b
|
|
|
82
121
|
|
|
83
122
|
## 第 3 步:移植补丁到新版本
|
|
84
123
|
|
|
85
|
-
1. **取 pristine**:`mkdir
|
|
124
|
+
1. **取 pristine**:`mkdir -p "$EV/pristine" && cd "$EV/pristine" && npm pack <pkg>@<ver>` 解包
|
|
86
125
|
(antigravity 用 curl 拉 darwin-arm64 zip)。
|
|
87
126
|
2. **先问「还需要吗」**:
|
|
88
127
|
- 配额类:grep 新版本有无原生 `accountRateLimits` / 等价能力;没有 → 仍需要。
|
|
@@ -91,16 +130,18 @@ python3 -c "import json;d=json.load(open('$HOME/.axom/workstation/acp-adapters/b
|
|
|
91
130
|
3. **account-limits 类配方**(claude/codex/commandcode/zcode):改 `account-limits/generate.py`
|
|
92
131
|
里的版本号与锚点串(`count==1` 断言失败 = 上游改了形状,对照新 pristine 修锚点),指向新
|
|
93
132
|
pristine 目录重跑,生成新配方 JSON。
|
|
94
|
-
4. **手工配方**(zcode-models、zcode-subagent-subwork
|
|
95
|
-
pristine 里是否仍唯一存在;压缩标识符改名(如 `gnd`→`Ocd`、`as`→`cs
|
|
96
|
-
|
|
97
|
-
|
|
133
|
+
4. **手工配方**(zcode-models、zcode-subagent-subwork):对每个 edit 检查 `before` 在新
|
|
134
|
+
pristine 里是否仍唯一存在;压缩标识符改名(如 `gnd`→`Ocd`、`as`→`cs`)就**同步改锚点和载荷**。
|
|
135
|
+
Qoder 使用官方 1.1.75 的 `qoder-native-acp.json`,不再维护旧 steering/subagent 配方;
|
|
136
|
+
`patchDigest` 必须由生成器按完整 recipe(含 asset)重算。Qoder 与其他包补丁一样,
|
|
137
|
+
安装和启动只依赖 Catalog 钉版本、配方锚点和哈希;行为/平台认证仅用于升级或退休判断,
|
|
138
|
+
不得成为普通安装的前置条件。
|
|
98
139
|
5. **验证**(缺一不可):
|
|
99
140
|
- 顺序应用配方到 pristine 副本,逐 edit 核对 before/after sha256;
|
|
100
|
-
-
|
|
101
|
-
|
|
102
|
-
-
|
|
103
|
-
|
|
141
|
+
- 需要行为证据的候选可运行 `node axom-patch/cli/qoder/scripts/certify.mjs`,并保存每个
|
|
142
|
+
check 的原始记录、候选 digest、Node/tool identity 和平台信息;这些记录只用于升级/退休判断;
|
|
143
|
+
- `manifest.json` 的 `compatible_versions` 与配方 `versions` 同步(`acp/qoderPatches.test.ts` 会断言);
|
|
144
|
+
- 生成器/认证器结构变化时修复对应断言并重新生成 release,不通过手工修改 certification 绕过 gate。
|
|
104
145
|
|
|
105
146
|
## 第 4 步:升钉版本(编辑集,同一提交改完)
|
|
106
147
|
|
|
@@ -123,6 +164,7 @@ cd axom-cli
|
|
|
123
164
|
npx vitest run src/workstation/acp/patchAssets.test.ts src/workstation/acp/managedPatches.test.ts \
|
|
124
165
|
src/workstation/acp/registry/catalog.test.ts src/workstation/acp/acpAgents.test.ts
|
|
125
166
|
npm run build # 含 copy-patches 的台账工件校验
|
|
167
|
+
npm run test:qoder-patch # Qoder 补丁模块与生成器(npm test 也会跑)
|
|
126
168
|
cd ..
|
|
127
169
|
python3 scripts/check-upstream-patches.py --offline
|
|
128
170
|
```
|
|
@@ -148,5 +190,5 @@ claude 旧 override 用例);与 `git stash` 前后对照失败集一致即
|
|
|
148
190
|
| antigravity-acp | —(补钉 1.3.0 后升) | **1.4.0** | registry 1.4.0 | 真实 1.4.0 .par 经 proxy 实测:透传无损、能力注入成功;配额 READ 留真机 |
|
|
149
191
|
| command-code | 1.74.3 | **1.82.1** | npm 1.82.1 | 上游仍无配额能力;handler map 改名(u/dn→m/hn)锚点已跟,generate.py 移植 |
|
|
150
192
|
| zcode-acp | 0.69.3 | **0.69.4** | npm 0.69.4 | 三份配方目标文件字节一致(versions 双版本);subagent 探针补丁副本过、pristine 复现缺失 |
|
|
151
|
-
| qoder | 1.1.
|
|
193
|
+
| qoder | 1.1.74 adapter | **1.1.75 native ACP** | npm `@qoder-ai/qodercli@1.1.75` | `qoder-native-acp` recipe 已生成;真实行为/平台 evidence 只作为后续升级或退休依据,不阻塞当前安装 |
|
|
152
194
|
| kimi-code | 2.1.1 | 2.1.1 | registry 未收录 | 无新版(GitHub release 同版) |
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import vm from 'node:vm';
|
|
5
|
+
|
|
6
|
+
const packageRoot = process.argv[2];
|
|
7
|
+
assert.ok(packageRoot, 'Pass the codex-acp package directory');
|
|
8
|
+
const source = readFileSync(path.join(packageRoot, 'dist/index.js'), 'utf8');
|
|
9
|
+
const helpers = source.slice(source.indexOf('function usesTerminal(item)'), source.indexOf('function startFacts(item)')) +
|
|
10
|
+
source.slice(source.indexOf('function completionFacts(item,'), source.indexOf('function searchTitle(')) +
|
|
11
|
+
source.slice(source.indexOf('function toTerminalToolStatus(status)'), source.indexOf('// src/tool-calls/reporters/CommandReporter.ts'));
|
|
12
|
+
const context = vm.createContext({});
|
|
13
|
+
vm.runInContext(helpers, context);
|
|
14
|
+
for (const streamed of [false, true]) {
|
|
15
|
+
for (const status of ['completed', 'failed']) {
|
|
16
|
+
context.item = {
|
|
17
|
+
id: 'terminal-output-probe', source: 'unifiedExec', commandActions: [],
|
|
18
|
+
status, exitCode: status === 'completed' ? 0 : 7,
|
|
19
|
+
aggregatedOutput: 'BEGIN\nEND\n',
|
|
20
|
+
};
|
|
21
|
+
context.streamed = streamed;
|
|
22
|
+
const facts = vm.runInContext('completionFacts(item, streamed, false)', context);
|
|
23
|
+
if (process.argv.includes('--expect-bug')) {
|
|
24
|
+
assert.equal(facts.opaqueResult, undefined);
|
|
25
|
+
} else {
|
|
26
|
+
assert.equal(facts.opaqueResult.formatted_output, context.item.aggregatedOutput);
|
|
27
|
+
assert.equal(facts.opaqueResult.exit_code, context.item.exitCode);
|
|
28
|
+
}
|
|
29
|
+
assert.equal(facts.status, status);
|
|
30
|
+
assert.equal(facts.terminalExit.exitCode, context.item.exitCode);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
console.log(process.argv.includes('--expect-bug') ? 'Confirmed missing complete terminal result' : 'Complete terminal results pass: streamed/unstreamed and completed/failed');
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import {spawn} from 'node:child_process';
|
|
3
|
+
import {createInterface} from 'node:readline';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
|
|
6
|
+
const binary = process.argv[2];
|
|
7
|
+
assert.ok(binary, 'Usage: node kimi-subagent-subwork.mjs /path/to/managed/kimi');
|
|
8
|
+
const child = spawn(process.execPath, [fileURLToPath(new URL('../account-limits/kimi-proxy.mjs', import.meta.url)), binary, 'acp'], {stdio: ['pipe', 'pipe', 'inherit']});
|
|
9
|
+
const pending = new Map();
|
|
10
|
+
const updates = [];
|
|
11
|
+
const sessions = [];
|
|
12
|
+
let nextId = 1;
|
|
13
|
+
const write = message => child.stdin.write(JSON.stringify(message) + '\n');
|
|
14
|
+
const request = (method, params) => new Promise((resolve, reject) => {
|
|
15
|
+
const id = nextId++;
|
|
16
|
+
const timer = setTimeout(() => {pending.delete(id); reject(new Error(`Timeout: ${method}`));}, 90000);
|
|
17
|
+
pending.set(id, {resolve, reject, timer});
|
|
18
|
+
write({jsonrpc: '2.0', id, method, params});
|
|
19
|
+
});
|
|
20
|
+
createInterface({input: child.stdout}).on('line', line => {
|
|
21
|
+
let message;
|
|
22
|
+
try {message = JSON.parse(line);} catch {return;}
|
|
23
|
+
if (message.method === 'session/update') updates.push(message.params);
|
|
24
|
+
if (message.method === 'session/request_permission') {
|
|
25
|
+
const option = message.params.options.find(option => option.kind === 'allow_once');
|
|
26
|
+
write({jsonrpc: '2.0', id: message.id, result: {outcome: option ? {outcome: 'selected', optionId: option.optionId} : {outcome: 'cancelled'}}});
|
|
27
|
+
}
|
|
28
|
+
const waiter = !message.method && pending.get(message.id);
|
|
29
|
+
if (!waiter) return;
|
|
30
|
+
pending.delete(message.id);
|
|
31
|
+
clearTimeout(waiter.timer);
|
|
32
|
+
if (message.error) waiter.reject(new Error(JSON.stringify(message.error)));
|
|
33
|
+
else waiter.resolve(message.result);
|
|
34
|
+
});
|
|
35
|
+
child.on('exit', code => {
|
|
36
|
+
for (const waiter of pending.values()) {clearTimeout(waiter.timer); waiter.reject(new Error(`Kimi exited: ${code}`));}
|
|
37
|
+
pending.clear();
|
|
38
|
+
});
|
|
39
|
+
const prompt = (sessionId, text) => request('session/prompt', {sessionId, prompt: [{type: 'text', text}]});
|
|
40
|
+
const create = async () => {
|
|
41
|
+
const session = await request('session/new', {cwd: '/tmp', mcpServers: []});
|
|
42
|
+
sessions.push(session.sessionId);
|
|
43
|
+
return session.sessionId;
|
|
44
|
+
};
|
|
45
|
+
const states = () => updates.filter(({update}) => update.sessionUpdate === 'subagent_state_update' && update.state);
|
|
46
|
+
try {
|
|
47
|
+
const initialized = await request('initialize', {protocolVersion: 1, clientCapabilities: {subagents: {}, _meta: {jetbrains: {air: {version: 1, capabilities: ['nativeSubagentSessions', 'asyncTasks']}}}}, clientInfo: {name: 'axom-kimi-subagent-probe', version: '1.0.0'}});
|
|
48
|
+
assert.ok(initialized.agentCapabilities.sessionCapabilities.subagents);
|
|
49
|
+
assert.ok(initialized.agentCapabilities._meta['axom/accountRateLimits']);
|
|
50
|
+
console.log('agent', JSON.stringify(initialized.agentInfo));
|
|
51
|
+
const foreground = await create();
|
|
52
|
+
await prompt(foreground, 'ACP rendering verification. Use Agent exactly once, subagent_type explore, prompt "Return the exact literal KIMI_FOREGROUND_OK; do not use tools, read files or run commands." Wait for its result, then repeat the literal. Do not use any other tools or modify files.');
|
|
53
|
+
const spawn = updates.find(({sessionId, update}) => sessionId === foreground && update.sessionUpdate === 'subagent_spawned');
|
|
54
|
+
assert.ok(spawn, 'Foreground dispatch');
|
|
55
|
+
assert.ok(states().some(({sessionId, update}) => sessionId === foreground && update.state === 'completed'));
|
|
56
|
+
assert.ok(updates.some(({sessionId, update}) => sessionId === spawn.update.subagentSessionId && update.content?.text.includes('KIMI_FOREGROUND_OK')));
|
|
57
|
+
assert.ok(!updates.some(({update}) => update.title === 'Agent' || update.title?.startsWith('Launching explore agent:')), 'No duplicate Agent tool card');
|
|
58
|
+
const beforeResume = updates.length;
|
|
59
|
+
await prompt(foreground, 'Use Agent exactly once with resume="agent-0" and prompt="Return KIMI_RESUME_OK without tools." Do not set subagent_type. Wait for its result, then repeat it. No other tools or file changes.');
|
|
60
|
+
assert.ok(updates.slice(beforeResume).some(({update}) => update.sessionUpdate === 'subagent_state_update' && update.subagentSessionId === spawn.update.subagentSessionId && update.state === 'completed'), 'Resume reuses child identity');
|
|
61
|
+
assert.ok(!updates.slice(beforeResume).some(({update}) => update.sessionUpdate === 'subagent_spawned'));
|
|
62
|
+
console.log('PASS foreground + resume');
|
|
63
|
+
|
|
64
|
+
const background = await create();
|
|
65
|
+
await prompt(background, 'ACP background rendering verification. Use Agent exactly once with run_in_background=true, subagent_type explore, prompt="Return the exact literal KIMI_BACKGROUND_OK without tools, file access or commands." After the launch receipt say launched and finish your turn. Do not wait, poll or call any other tools.');
|
|
66
|
+
const deadline = Date.now() + 45000;
|
|
67
|
+
while (!states().some(({sessionId, update}) => sessionId === background && update.state === 'completed') && Date.now() < deadline) await new Promise(resolve => setTimeout(resolve, 100));
|
|
68
|
+
assert.ok(states().some(({sessionId, update}) => sessionId === background && update.state === 'completed'), 'Background terminal after launch receipt');
|
|
69
|
+
const backgroundChild = updates.find(({sessionId, update}) => sessionId === background && update.sessionUpdate === 'subagent_spawned')?.update.subagentSessionId;
|
|
70
|
+
assert.ok(updates.some(({sessionId, update}) => sessionId === backgroundChild && update.content?.text.includes('KIMI_BACKGROUND_OK')), 'Background output');
|
|
71
|
+
console.log('PASS background late output + terminal');
|
|
72
|
+
|
|
73
|
+
const beforeLoad = updates.length;
|
|
74
|
+
await request('session/load', {sessionId: foreground, cwd: '/tmp', mcpServers: []});
|
|
75
|
+
assert.ok(updates.slice(beforeLoad).some(({update}) => update.sessionUpdate === 'subagent_spawned' && update.subagentSessionId === spawn.update.subagentSessionId), 'Load reconstructs stable child identity');
|
|
76
|
+
console.log('PASS load replay');
|
|
77
|
+
console.log(JSON.stringify({sessions: sessions.length, children: updates.filter(({update}) => update.sessionUpdate === 'subagent_spawned').length, terminals: states().map(({update}) => update.state)}));
|
|
78
|
+
} finally {
|
|
79
|
+
for (const sessionId of sessions) await request('session/delete', {sessionId}).catch(error => console.error('cleanup', error.message));
|
|
80
|
+
child.stdin.end();
|
|
81
|
+
child.kill();
|
|
82
|
+
}
|