@platless/axom-cli 0.1.0 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/authScopes.js +19 -0
- package/dist/axom-patch/cli/README.md +110 -0
- package/dist/axom-patch/cli/pi-steering.json +37 -0
- package/dist/axom-patch/cli/probes/claude-late-async-terminal.mjs +34 -0
- package/dist/axom-patch/cli/probes/pi-steering.mjs +80 -0
- package/dist/axom-patch/cli/probes/qoder-steering.mjs +89 -0
- package/dist/axom-patch/cli/probes/qoder-subagent-origin.mjs +49 -0
- package/dist/axom-patch/cli/qoder-background-terminal.md +81 -0
- package/dist/axom-patch/cli/qoder-foreground-output.md +41 -0
- package/dist/axom-patch/cli/qoder-steering.json +52 -0
- package/dist/axom-patch/cli/qoder-steering.md +30 -0
- package/dist/axom-patch/cli/qoder-subagent-origin.json +73 -0
- package/dist/axom-patch/cli/qoder-subagent-subwork.md +73 -0
- package/dist/axom-patch/cli/runtime.json +37 -0
- package/dist/axom-patch/cli/steering/claude-steering-js.patch +89 -0
- package/dist/axom-patch/cli/steering/claude-steering-types.patch +28 -0
- package/dist/axom-patch/cli/steering/codex-steering.patch +57 -0
- package/dist/axom-patch/cli/steering/pi-steering.js +79 -0
- package/dist/cli.js +9 -1
- package/dist/commands/auth.js +4 -13
- package/dist/commands/execute.js +4 -4
- package/dist/commands/record.js +6 -6
- package/dist/commands/struct.js +4 -4
- package/dist/commands/workstation.js +2 -2
- package/dist/credentials.js +2 -2
- package/dist/install/claude/commands.js +13 -13
- package/dist/mcp.js +32 -14
- package/dist/workstation/acp/acpAgents.js +447 -166
- package/dist/workstation/acp/acpClient.js +232 -18
- package/dist/workstation/acp/acpSession.js +502 -74
- package/dist/workstation/acp/activityBusy.js +43 -0
- package/dist/workstation/acp/activityReporting.js +54 -0
- package/dist/workstation/acp/adoption.js +107 -49
- package/dist/workstation/acp/authUrlSniffer.js +36 -0
- package/dist/workstation/acp/contract.js +11 -6
- package/dist/workstation/acp/delegationMcp.js +24 -0
- package/dist/workstation/acp/draftInterceptor.js +9 -0
- package/dist/workstation/acp/managedPatches.js +228 -0
- package/dist/workstation/acp/patchAssets.js +63 -0
- package/dist/workstation/acp/permission.js +300 -34
- package/dist/workstation/acp/qoderStartup.js +45 -0
- package/dist/workstation/acp/registry/catalog.js +263 -4
- package/dist/workstation/acp/registry/detect.js +55 -0
- package/dist/workstation/acp/sessionScope.js +19 -0
- package/dist/workstation/acp/sessionUpdateMapper.js +39 -21
- package/dist/workstation/acp/terminalLogin.js +197 -0
- package/dist/workstation/acp/test/fakeAgent.js +185 -9
- package/dist/workstation/acp/validate.js +33 -5
- package/dist/workstation/agentSessions.js +532 -44
- package/dist/workstation/channels/agent.js +7 -1
- package/dist/workstation/channels/computer.js +152 -4
- package/dist/workstation/channels/management.js +3 -3
- package/dist/workstation/config.js +3 -1
- package/dist/workstation/connection/encryptedChannel.js +88 -21
- package/dist/workstation/daemon.js +25 -3
- package/dist/workstation/desktop/binding.js +36 -0
- package/dist/workstation/desktop/bridge.js +212 -0
- package/dist/workstation/desktop/flow-control.js +52 -0
- package/dist/workstation/desktop/focused-text.js +130 -0
- package/dist/workstation/desktop/protocol.js +35 -0
- package/dist/workstation/fileOps.js +277 -0
- package/dist/workstation/filePaths.js +174 -0
- package/dist/workstation/fileWorker.js +81 -0
- package/dist/workstation/fileWorkerClient.js +121 -0
- package/dist/workstation/oauth/deviceAuthorization.js +21 -12
- package/dist/workstation/protocol/agent.js +154 -5
- package/dist/workstation/protocol/common.js +6 -0
- package/dist/workstation/protocol/computer.js +92 -3
- package/dist/workstation/qoderAdapter/backgroundProcess.js +106 -0
- package/dist/workstation/qoderAdapter/backgroundTerminal.js +262 -0
- package/dist/workstation/qoderAdapter/completedContinuation.js +139 -0
- package/dist/workstation/qoderAdapter/contract.js +78 -0
- package/dist/workstation/qoderAdapter/foregroundOutput.js +30 -0
- package/dist/workstation/qoderAdapter/history.js +87 -0
- package/dist/workstation/qoderAdapter/identityIndex.js +191 -0
- package/dist/workstation/qoderAdapter/inputQueue.js +42 -0
- package/dist/workstation/qoderAdapter/main.js +93 -0
- package/dist/workstation/qoderAdapter/mapper.js +117 -0
- package/dist/workstation/qoderAdapter/observerPlugin.js +245 -0
- package/dist/workstation/qoderAdapter/observerReceiver.js +187 -0
- package/dist/workstation/qoderAdapter/permissions.js +61 -0
- package/dist/workstation/qoderAdapter/profile.js +93 -0
- package/dist/workstation/qoderAdapter/sdkDriver.js +49 -0
- package/dist/workstation/qoderAdapter/session.js +319 -0
- package/dist/workstation/qoderAdapter/subagentMeta.js +28 -0
- package/dist/workstation/qoderAdapter/subwork.js +77 -0
- package/dist/workstation/qoderAdapter/taskControl.js +38 -0
- package/dist/workstation/qoderAdapter/taskEvent.js +26 -0
- package/dist/workstation/qoderAdapter/taskLedger.js +163 -0
- package/dist/workstation/qoderAdapter/types.js +1 -0
- package/dist/workstation/qoderAdapter/usage.js +37 -0
- package/dist/workstation/register.js +4 -0
- package/dist/workstation/tools/browser.js +394 -0
- package/dist/workstation/tools/client.js +269 -0
- package/dist/workstation/tools/core.js +50 -0
- package/dist/workstation/tools/files.js +525 -0
- package/dist/workstation/tools/keeperProcess.js +114 -0
- package/dist/workstation/tools/terminal.js +214 -0
- package/dist/workstation/tools/validation.js +50 -0
- package/dist/workstation/update/coordinator.js +29 -0
- package/dist/workstation/update/npmInstaller.js +2 -0
- package/dist/workstation/update/ptyPreflight.js +24 -0
- package/dist/workstation/update/taskRegistry.js +44 -20
- package/dist/workstation/update/watchdog.js +66 -0
- package/package.json +14 -4
- package/skills/axom/SKILL.md +55 -17
- package/skills/axom-definition/SKILL.md +32 -32
- package/skills/axom-platform/SKILL.md +39 -39
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Qoder 原生 ACP 插话
|
|
2
|
+
|
|
3
|
+
Qoder 1.1.61 的原生 ACP 将运行中的 `session/prompt` 排队,没有声明或实现
|
|
4
|
+
`_session/steering`。只在实验 SDK adapter 中支持插话,不能让普通 `qoder` 入口出现按钮。
|
|
5
|
+
|
|
6
|
+
`qoder-steering.json` 在 `qoder-subagent-origin.json` 之后应用,逐步核验官方 npm
|
|
7
|
+
包的 SHA-256。只修改 Axom 拥有的不可变副本,不改用户安装的 CLI 或 npm 缓存。
|
|
8
|
+
原生 ACP 的 new/load/resume、模型、权限、MCP、工具和子任务归属继续由 Qoder 处理。
|
|
9
|
+
|
|
10
|
+
补丁在 initialize 顶层声明 `_meta.steering={supported:true,timings:["now"]}`,
|
|
11
|
+
并实现 `_session/steering`。文本通过校验后加入当前会话的专用插话队列,调用原生
|
|
12
|
+
QueryEngine.abort 中断当前执行;原有平台 prompt 保持待完成。原生执行收束后,在
|
|
13
|
+
同一个 QueryEngine、历史、配置与平台回合内处理插话,新的回复完成才返回 prompt。
|
|
14
|
+
这会中断尚未完成的工具;不承诺撤销已经完成的文件或命令副作用。
|
|
15
|
+
|
|
16
|
+
没有运行回合时返回 `promptRequired`,不自行启动无人跟踪的回合。当前仅支持文本和
|
|
17
|
+
`now`;无效输入不打断执行。Stop 与关闭会话优先于插话,真实执行错误继续上报。
|
|
18
|
+
消息队列限 32 条、每条文本限 128 KiB;每次 prompt 收束清理专用队列。它不增加
|
|
19
|
+
数据库字段或第二份 transcript。通用 ACP、服务端和 UI 不增加 Qoder 判断。
|
|
20
|
+
|
|
21
|
+
目前只认证 npm 1.1.61 这份原文件。新包必须重新核验源文件和运行时语义,不按版本号
|
|
22
|
+
猜兼容。显式 command 覆盖继续尊重用户设置,不偷偷把本地 CLI 换成 managed 包。
|
|
23
|
+
|
|
24
|
+
当无补丁的原生 Qoder ACP 自己声明并实现相同插话协议,且普通入口的运行中工具、
|
|
25
|
+
消息落点、Stop、load/resume、模型/权限、子任务与完整基线验收通过时,可移除这份
|
|
26
|
+
配方、runtime 引用和台账项;单独 SDK 探针或版本升级不构成移除依据。
|
|
27
|
+
|
|
28
|
+
验证包括 CLI 的 `nativeSteeringPatch.test.ts`、对官方补丁包执行
|
|
29
|
+
`node axom-patch/cli/probes/qoder-steering.mjs <package>`,以及测试环境普通 `qoder`
|
|
30
|
+
入口的真实模型、REST 和 canvas 界面验收。测试入口名称及具体会话必须写入验收记录。
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "qoder-subagent-origin",
|
|
3
|
+
"package": "@qoder-ai/qodercli",
|
|
4
|
+
"versions": [
|
|
5
|
+
"1.1.61"
|
|
6
|
+
],
|
|
7
|
+
"edits": [
|
|
8
|
+
{
|
|
9
|
+
"file": "bundle/qodercli.js",
|
|
10
|
+
"before_sha256": "34875088fd8af9c97e88446cbbfa11bca24c1b6558cec048ac1152bd5486f4e9",
|
|
11
|
+
"after_sha256": "b29a975245a7194ef2ac4f2a742090d9e0d8f64ba3471bae475a564ee96600c1",
|
|
12
|
+
"before": "toolCallNames=new Map;",
|
|
13
|
+
"after": "toolCallNames=new Map;axomQoderToolOrigins=new Map;"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"file": "bundle/qodercli.js",
|
|
17
|
+
"before_sha256": "b29a975245a7194ef2ac4f2a742090d9e0d8f64ba3471bae475a564ee96600c1",
|
|
18
|
+
"after_sha256": "8d6dac333c191312ffdd5180554279dc168405cffc3720833f21139f9242d5fe",
|
|
19
|
+
"before": "async sendUpdate(A){let e={sessionId:this.id,update:A};await this.connection.sessionUpdate(e)}",
|
|
20
|
+
"after": "axomQoderId(value){return typeof value === \"string\" && value.length > 0 && value.length <= 256 && !/[\\x00-\\x1f\\x7f]/.test(value)}\naxomQoderObserveSdk(message){\n if(message.type !== \"assistant\" || !Array.isArray(message.message?.content)) return;\n const parent=message.parent_tool_use_id;\n if(parent !== null && !this.axomQoderId(parent)) return;\n for(const block of message.message.content){\n if(block?.type !== \"tool_use\" || !this.axomQoderId(block.id) || !this.axomQoderId(block.name)) continue;\n const prior=this.axomQoderToolOrigins.get(block.id);\n if(this.axomQoderToolOrigins.has(block.id)){\n if(prior && (prior.parent !== parent || prior.name !== block.name)) this.axomQoderToolOrigins.set(block.id,null);\n continue;\n }\n if(this.axomQoderToolOrigins.size >= 4096) continue;\n this.axomQoderToolOrigins.set(block.id,{parent,name:block.name});\n }\n}\naxomQoderSdkUpdate(message,update){\n if(this.axomQoderId(message.parent_tool_use_id)) update={...update,_meta:{...update._meta,qoder:{...update._meta?.qoder,version:1,source:\"native-acp-patch\",parentToolUseId:message.parent_tool_use_id,route:\"child\"}}};\n return this.sendUpdate(update);\n}\nasync sendUpdate(A){\n if(A.sessionUpdate === \"tool_call\" || A.sessionUpdate === \"tool_call_update\"){\n const origin=this.axomQoderToolOrigins.get(A.toolCallId);\n if(origin) A={...A,_meta:{...A._meta,qoder:{...A._meta?.qoder,version:1,source:\"native-acp-patch\",toolName:origin.name,...(origin.parent ? {parentToolUseId:origin.parent,route:\"child\"} : {})}}};\n }\n let e={sessionId:this.id,update:A};await this.connection.sessionUpdate(e)\n}"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"file": "bundle/qodercli.js",
|
|
24
|
+
"before_sha256": "8d6dac333c191312ffdd5180554279dc168405cffc3720833f21139f9242d5fe",
|
|
25
|
+
"after_sha256": "c606c209aa5c89afacb411c68acc071817de29dc31fe0978e7c22e713eaba5cd",
|
|
26
|
+
"before": "async dispatchSDKMessage(A){switch(A.type){",
|
|
27
|
+
"after": "async dispatchSDKMessage(A){this.axomQoderObserveSdk(A);switch(A.type){"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"file": "bundle/qodercli.js",
|
|
31
|
+
"before_sha256": "c606c209aa5c89afacb411c68acc071817de29dc31fe0978e7c22e713eaba5cd",
|
|
32
|
+
"after_sha256": "fa8a112848de34c682943d97a6f59c3eb6c882d388c9478c7edf2c7ae6597973",
|
|
33
|
+
"before": "await this.sendUpdate({sessionUpdate:\"agent_message_chunk\",content:{type:\"text\",text:e.delta.text}})",
|
|
34
|
+
"after": "await this.axomQoderSdkUpdate(A,{sessionUpdate:\"agent_message_chunk\",content:{type:\"text\",text:e.delta.text}})"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"file": "bundle/qodercli.js",
|
|
38
|
+
"before_sha256": "fa8a112848de34c682943d97a6f59c3eb6c882d388c9478c7edf2c7ae6597973",
|
|
39
|
+
"after_sha256": "9b0bce311b17ac72f1bcdda18bc587d7cc5383994ca56893085e1568b57f5940",
|
|
40
|
+
"before": "await this.sendUpdate({sessionUpdate:\"agent_thought_chunk\",content:{type:\"text\",text:e.delta.thinking}})",
|
|
41
|
+
"after": "await this.axomQoderSdkUpdate(A,{sessionUpdate:\"agent_thought_chunk\",content:{type:\"text\",text:e.delta.thinking}})"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"file": "bundle/qodercli.js",
|
|
45
|
+
"before_sha256": "9b0bce311b17ac72f1bcdda18bc587d7cc5383994ca56893085e1568b57f5940",
|
|
46
|
+
"after_sha256": "c5af49f3d42a8f525af8813b97b93078fa0bc3433e7331b47b55cd9a13b7b0d9",
|
|
47
|
+
"before": "async streamHistory(A){let e=gnd(A);for(let t of A){",
|
|
48
|
+
"after": "async streamHistory(A){let e=gnd(A);for(let t of A){this.axomQoderObserveSdk(t);"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"file": "bundle/qodercli.js",
|
|
52
|
+
"before_sha256": "c5af49f3d42a8f525af8813b97b93078fa0bc3433e7331b47b55cd9a13b7b0d9",
|
|
53
|
+
"after_sha256": "5a4a47e3812f5cef51847852b400bab9d74acfd4932c890d9072c0ec58a552a9",
|
|
54
|
+
"before": "await this.sendUpdate({sessionUpdate:\"user_message_chunk\",content:{type:\"text\",text:A},messageId:t.uuid})",
|
|
55
|
+
"after": "await this.axomQoderSdkUpdate(t,{sessionUpdate:\"user_message_chunk\",content:{type:\"text\",text:A},messageId:t.uuid})"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"file": "bundle/qodercli.js",
|
|
59
|
+
"before_sha256": "5a4a47e3812f5cef51847852b400bab9d74acfd4932c890d9072c0ec58a552a9",
|
|
60
|
+
"after_sha256": "0041e7a85e0ed7a8a811c7fd5b2cc7f7df710b529e087af319411a8cbd5a481d",
|
|
61
|
+
"before": "await this.sendUpdate({sessionUpdate:\"agent_message_chunk\",content:{type:\"text\",text:A},messageId:t.uuid})",
|
|
62
|
+
"after": "await this.axomQoderSdkUpdate(t,{sessionUpdate:\"agent_message_chunk\",content:{type:\"text\",text:A},messageId:t.uuid})"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"file": "bundle/qodercli.js",
|
|
66
|
+
"before_sha256": "0041e7a85e0ed7a8a811c7fd5b2cc7f7df710b529e087af319411a8cbd5a481d",
|
|
67
|
+
"after_sha256": "88829cdc00f1d435d6b9fb4cd8088d678731a99e8c414cb02159a770ddedc32d",
|
|
68
|
+
"before": "await this.sendUpdate({sessionUpdate:\"agent_thought_chunk\",content:{type:\"text\",text:A.thinking},messageId:t.uuid})",
|
|
69
|
+
"after": "await this.axomQoderSdkUpdate(t,{sessionUpdate:\"agent_thought_chunk\",content:{type:\"text\",text:A.thinking},messageId:t.uuid})"
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"bin": "qodercli"
|
|
73
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# qoder-subagent-origin / qoder-subagent-subwork
|
|
2
|
+
|
|
3
|
+
## 为什么需要
|
|
4
|
+
|
|
5
|
+
Qoder CLI 1.1.61 的内部运行流已经带 `parent_tool_use_id`,但它自己的 ACP
|
|
6
|
+
`dispatchSDKMessage` / `streamHistory` 在生成文字、思考和工具事件时丢掉了这个字段。
|
|
7
|
+
因此原生 `qodercli --acp` 的子任务 Read / Bash 出现在主会话。ACP 上层无法从时间、
|
|
8
|
+
标题或返回顺序补出可靠关系,尤其不能拆解并发任务。
|
|
9
|
+
|
|
10
|
+
此前只在 Axom 的 SDK adapter 里加 `_meta.qoder`,没有覆盖用户正在用的原生入口。
|
|
11
|
+
那个实验能证明 SDK 归属信息存在,但不能证明原生入口已经修好。
|
|
12
|
+
|
|
13
|
+
## 补丁的位置与行为
|
|
14
|
+
|
|
15
|
+
1. `qoder-subagent-origin.json` 对官方 npm `@qoder-ai/qodercli@1.1.61` 的
|
|
16
|
+
`bundle/qodercli.js` 做精确版本、原文件及每一步产物 SHA-256 校验。
|
|
17
|
+
在 Qoder 原生 ACP 转换层保留每个工具的父 ID,在文字/思考及历史事件上写
|
|
18
|
+
`_meta.qoder={version:1,source:"native-acp-patch",parentToolUseId,route:"child"}`。
|
|
19
|
+
根工具保留工具名和补丁版本,但不伪造父 ID。冲突和容量不足不猜归属。
|
|
20
|
+
2. `qoderAdapter/subwork.ts` 消费该元数据,生成已有的 ACP
|
|
21
|
+
`subagent_spawned` / `subagent_state_update`,并给 child item 填确定性地址:
|
|
22
|
+
`qoder-agent:<root native sessionId>:<Agent toolCallId>`。
|
|
23
|
+
解析器仍在根进程;任务正文、执行工具、结果和带身份的文字/思考落在 subwork。
|
|
24
|
+
3. Agent 工具调用被归一为同一个 subwork 派发与结果,不再额外产生委派摘要卡。
|
|
25
|
+
后台 `async_launched` 只是启动回执,不能据此结束子工作;已存在的后台真实终态修补
|
|
26
|
+
走同一归一入口。权限回调保持原生根会话的请求/回答路径,不启用独立子任务控制。
|
|
27
|
+
|
|
28
|
+
服务端、数据库、公共工作模型及 App 不新增 Qoder 判断;此次新增的核心 Qoder
|
|
29
|
+
元数据分支已经撤回。通用 ACP 会话只接线到 Qoder 自己的边界。
|
|
30
|
+
|
|
31
|
+
## 分发和版本门槛
|
|
32
|
+
|
|
33
|
+
`runtime.json` 引用补丁配方。`managedPatches.ts` 在 Install/Update/首次 managed
|
|
34
|
+
launch 时复制完整 npm 包及依赖,校验并写收据,启动不可变副本。npm 原缓存和用户
|
|
35
|
+
原有 Qoder 二进制保持原样。Qoder 包同时发布 `qodercli` 和 dispatcher 两个 bin,
|
|
36
|
+
配方显式选择 `bin:"qodercli"`;通用补丁加载器只增加可信配方的 bin 选择能力。
|
|
37
|
+
没有显式 bin 的其他补丁仍执行原来的单入口检查。
|
|
38
|
+
|
|
39
|
+
- 只认证原生 Qoder CLI 1.1.61 的这份发布包,不把 1.1.64 当作兼容版本。
|
|
40
|
+
- CLI 版本 bump 到 0.3.7,补丁跟随正常 Client release 分发。
|
|
41
|
+
- 显式自定义 command 按用户配置运行,不会偷偷替换用户二进制。要启用原生补丁,
|
|
42
|
+
工作站 Qoder 项使用 catalog 管理的原生 npm ACP 入口(清除旧二进制 command/args)。
|
|
43
|
+
- 继续走 Qoder 原生 ACP 的 new/load/resume、模型和权限模式;不把原生会话切换到
|
|
44
|
+
不支持恢复的 SDK adapter。已有历史不追溯猜分或改写;修复后的新事件才按证据分流。
|
|
45
|
+
- SDK adapter 的既有实验同样可经过本边界,但不是原生入口验收的替代品。
|
|
46
|
+
|
|
47
|
+
## 什么时候可以移除
|
|
48
|
+
|
|
49
|
+
当无补丁的 Qoder ACP 能发送稳定的派生关系、每帧子任务归属、真实终态以及可回放
|
|
50
|
+
的同一关系,并通过并发乱序、失败/取消、后台迟到、load/resume/重连验收后:删除
|
|
51
|
+
配方、runtime 引用、Qoder subwork 归一器和接线,台账标 retired。继续保留通用
|
|
52
|
+
ACP/Claude/Codex 基线。不以升级版本号或主 Agent 返回成功作为移除依据。
|
|
53
|
+
|
|
54
|
+
## 验证
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
cd axom-cli
|
|
58
|
+
npm test
|
|
59
|
+
cd ..
|
|
60
|
+
node axom-patch/cli/probes/qoder-subagent-origin.mjs /path/to/patched/qoder-package
|
|
61
|
+
AXOM_BASELINE_SQLITE_BIN=/path/to/new-sqlite/bin \
|
|
62
|
+
AXOM_BASELINE_PYTHON_BIN=/path/to/new-python/bin scripts/test-acp-baseline.sh
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
运行时探针执行官方 bundle 里实际的 ACP dispatch 方法,验证并发 child 的工具与
|
|
66
|
+
结果、文字、根输出和冲突边界;不启动模型、不读取凭据。真实功能验收必须另经
|
|
67
|
+
测试工作站、服务端、数据库、REST 和页面,记录具体会话。fixture 通过不等于上线验收。
|
|
68
|
+
|
|
69
|
+
## 原生后台过程补齐
|
|
70
|
+
|
|
71
|
+
Qoder 1.1.61 不向主 ACP 流转发后台子任务的 SDK 消息。`backgroundProcess.ts` 只读轮询经过原生启动回执确认的 `agent-<agentId>.jsonl`;每行必须同时匹配 native session、cwd、agentId、parent_tool_use_id、isSidechain 与版本。只发出实际记录的工具调用、结果、思考和回复,经 `_meta.qoder` 进入同一 subwork 边界。父会话空闲后仍可接收这些项;完成状态继续采用原生 task-notification,不从最后一条文本推断完成。
|
|
72
|
+
|
|
73
|
+
解析有单行、单轮字节与行数上限,拒绝符号链接、未知工具结果与不完整行,并按原生 uuid 去重。这一补齐针对本次已观察的后台调用;历史未观察任务不会被猜测迁移。上游转发后台消息后应移除 transcript 轮询,并保留并行归属和晚到事件验收。
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"overrides": [
|
|
4
|
+
{
|
|
5
|
+
"id": "claude-async-task-preview",
|
|
6
|
+
"agent": "claude-acp",
|
|
7
|
+
"distribution": {
|
|
8
|
+
"version": "0.86.1-preview.2",
|
|
9
|
+
"npx": {
|
|
10
|
+
"package": "@agentclientprotocol/claude-agent-acp@0.86.1-preview.2"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"when_registry_version": [
|
|
14
|
+
"0.86.0"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "claude-plan-tools",
|
|
19
|
+
"agent": "claude-acp",
|
|
20
|
+
"env": {
|
|
21
|
+
"CLAUDE_CODE_ENABLE_TODO_TOOLS": "1"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "codex-plan-tools",
|
|
26
|
+
"agent": "codex-acp",
|
|
27
|
+
"env": {
|
|
28
|
+
"CODEX_CONFIG": "{\"tools\":{\"update_plan\":{\"enabled\":true}}}"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"package_patches": [
|
|
33
|
+
"pi-steering.json",
|
|
34
|
+
"qoder-subagent-origin.json",
|
|
35
|
+
"qoder-steering.json"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
--- a/dist/acp-agent.js
|
|
2
|
+
+++ b/dist/acp-agent.js
|
|
3
|
+
@@ -180,12 +180,29 @@
|
|
4
|
+
return { sessionId, asyncTaskId };
|
|
5
|
+
}
|
|
6
|
+
/** How urgently the SDK delivers a steered message relative to the running
|
|
7
|
+
- * turn — an internal Claude implementation detail, not part of the wire
|
|
8
|
+
- * contract. `now` pre-empts the current generation, while `later` waits for a
|
|
9
|
+
- * pending permission/elicitation callback to settle instead of cancelling its
|
|
10
|
+
- * ACP request and hiding the client's user-input card (IJAI-1191). */
|
|
11
|
+
+ * turn. `now` pre-empts the current generation, `next` waits for the next
|
|
12
|
+
+ * natural boundary without aborting, and `later` waits for a pending
|
|
13
|
+
+ * permission/elicitation callback to settle instead of cancelling its ACP
|
|
14
|
+
+ * request and hiding the client's user-input card (IJAI-1191).
|
|
15
|
+
+ *
|
|
16
|
+
+ * This is both the agent's own default choice and — since the
|
|
17
|
+
+ * `_session/steering` response is identical whichever timing was used, so a
|
|
18
|
+
+ * Host cannot discover the difference by trying — the vocabulary a Host may
|
|
19
|
+
+ * name explicitly through `_meta.steering.priority`. The set is advertised on
|
|
20
|
+
+ * `InitializeResponse._meta.steering.timings` so the capability is declared
|
|
21
|
+
+ * rather than probed. */
|
|
22
|
+
const STEER_PRIORITY_NOW = "now";
|
|
23
|
+
+const STEER_PRIORITY_NEXT = "next";
|
|
24
|
+
const STEER_PRIORITY_LATER = "later";
|
|
25
|
+
+/** The delivery timings this agent accepts on `_meta.steering.priority`, and the
|
|
26
|
+
+ * value advertised as `InitializeResponse._meta.steering.timings`. Both reads
|
|
27
|
+
+ * come from this one array so the accepted set and the advertised set cannot
|
|
28
|
+
+ * drift apart. */
|
|
29
|
+
+const STEER_TIMINGS = [
|
|
30
|
+
+ STEER_PRIORITY_NOW,
|
|
31
|
+
+ STEER_PRIORITY_NEXT,
|
|
32
|
+
+ STEER_PRIORITY_LATER,
|
|
33
|
+
+];
|
|
34
|
+
/** Validate raw JSON-RPC params into a {@link SteerRequest}. Kept minimal — the
|
|
35
|
+
* content blocks are handed to `promptToClaude`, which tolerates unknown block
|
|
36
|
+
* types — but `sessionId` and a non-empty `prompt` array are required. */
|
|
37
|
+
@@ -206,6 +223,16 @@
|
|
38
|
+
: undefined;
|
|
39
|
+
if (idleBehavior !== undefined && idleBehavior !== "promptRequired") {
|
|
40
|
+
throw RequestError.invalidParams(undefined, "unsupported steering idleBehavior");
|
|
41
|
+
+ }
|
|
42
|
+
+ const priority = steering && typeof steering === "object"
|
|
43
|
+
+ ? steering.priority
|
|
44
|
+
+ : undefined;
|
|
45
|
+
+ // Rejected rather than ignored: a silently dropped priority is
|
|
46
|
+
+ // indistinguishable from an honoured one on the response, so a Host that
|
|
47
|
+
+ // asked for `next` and got `now` would only find out by losing the running
|
|
48
|
+
+ // turn's remaining work.
|
|
49
|
+
+ if (priority !== undefined && !STEER_TIMINGS.includes(priority)) {
|
|
50
|
+
+ throw RequestError.invalidParams(undefined, "unsupported steering priority");
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
sessionId,
|
|
54
|
+
@@ -947,6 +974,10 @@
|
|
55
|
+
...airSessionFailureCapabilityMeta(AGENT_FILE_CHANGE_REPORT_CAPABILITY, AIR_NATIVE_SUBAGENT_SESSIONS_CAPABILITY, AIR_ASYNC_TASKS_CAPABILITY, AIR_RECOMMENDED_CONFIG_VALUE_CAPABILITY),
|
|
56
|
+
steering: {
|
|
57
|
+
supported: true,
|
|
58
|
+
+ // The timings a Host may name on `_meta.steering.priority`
|
|
59
|
+
+ // (see STEER_TIMINGS). Declared, not probed: the response to
|
|
60
|
+
+ // `_session/steering` is the same whichever timing was used.
|
|
61
|
+
+ timings: [...STEER_TIMINGS],
|
|
62
|
+
},
|
|
63
|
+
goal: {
|
|
64
|
+
version: GOAL_EXTENSION_VERSION,
|
|
65
|
+
@@ -1758,9 +1789,22 @@
|
|
66
|
+
const steeredUuid = randomUUID();
|
|
67
|
+
userMessage.uuid = steeredUuid;
|
|
68
|
+
// Deliver into the running turn rather than queuing behind it as a fresh
|
|
69
|
+
- // prompt would.
|
|
70
|
+
+ // prompt would. With no priority in `_meta` this is byte-for-byte the
|
|
71
|
+
+ // established behavior: `now`, held back to `later` only while a
|
|
72
|
+
+ // permission/elicitation callback is awaiting input.
|
|
73
|
+
+ const defaultPriority = (session.pendingUserInputCount ?? 0) > 0
|
|
74
|
+
+ ? STEER_PRIORITY_LATER
|
|
75
|
+
+ : STEER_PRIORITY_NOW;
|
|
76
|
+
+ // A Host that named a timing gets it, with one exception: an explicit
|
|
77
|
+
+ // `now` is still held back while a callback is awaiting input, because
|
|
78
|
+
+ // pre-empting ABORTS the cycle, which cancels that ACP request and can
|
|
79
|
+
+ // strand the prompt (IJAI-1191). `next` and `later` never pre-empt, so
|
|
80
|
+
+ // they carry no such hazard and are honoured verbatim.
|
|
81
|
+
+ const requestedPriority = params._meta?.steering?.priority;
|
|
82
|
+
userMessage.priority =
|
|
83
|
+
- (session.pendingUserInputCount ?? 0) > 0 ? STEER_PRIORITY_LATER : STEER_PRIORITY_NOW;
|
|
84
|
+
+ requestedPriority === undefined || requestedPriority === STEER_PRIORITY_NOW
|
|
85
|
+
+ ? defaultPriority
|
|
86
|
+
+ : requestedPriority;
|
|
87
|
+
// Mark before the push and in the same synchronous section as the in-flight
|
|
88
|
+
// check: the interrupt can have the CLI finalizing the aborted cycle by the
|
|
89
|
+
// time the consumer next runs, and an unmarked result would settle the turn
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
--- a/dist/acp-agent.d.ts
|
|
2
|
+
+++ b/dist/acp-agent.d.ts
|
|
3
|
+
@@ -47,17 +47,22 @@
|
|
4
|
+
stopped: boolean;
|
|
5
|
+
};
|
|
6
|
+
/** Request-level steering options. `promptRequired` is opt-in so existing Hosts
|
|
7
|
+
- * keep the established idle fallback behavior. */
|
|
8
|
+
+ * keep the established idle fallback behavior, and `priority` is optional so a
|
|
9
|
+
+ * Host that names none keeps the agent's established default. */
|
|
10
|
+
type SteerMeta = {
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
steering?: {
|
|
13
|
+
idleBehavior?: "promptRequired";
|
|
14
|
+
+ priority?: SteerTiming;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
+/** A delivery timing a Host may name on {@link SteerMeta}, and a member of the
|
|
18
|
+
+ * set advertised as `InitializeResponse._meta.steering.timings`. */
|
|
19
|
+
+export type SteerTiming = "now" | "next" | "later";
|
|
20
|
+
/** Params of a {@link STEER_METHOD} request. Shaped like the relevant subset of
|
|
21
|
+
* a `PromptRequest` so the same `promptToClaude` conversion applies. Delivery
|
|
22
|
+
- * priority is deliberately NOT exposed here — it's an internal detail the agent
|
|
23
|
+
- * chooses (see {@link STEER_PRIORITY}). */
|
|
24
|
+
+ * priority is the agent's own choice (see {@link STEER_TIMINGS}) unless the
|
|
25
|
+
+ * Host names one it advertised. */
|
|
26
|
+
export type SteerRequest = {
|
|
27
|
+
sessionId: string;
|
|
28
|
+
prompt: PromptRequest["prompt"];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
--- a/dist/index.js
|
|
2
|
+
+++ b/dist/index.js
|
|
3
|
+
@@ -31723,6 +31723,20 @@
|
|
4
|
+
// src/AcpExtensions.ts
|
|
5
|
+
var LEGACY_SET_SESSION_MODEL_METHOD = "session/set_model";
|
|
6
|
+
var SESSION_STEERING_METHOD = "_session/steering";
|
|
7
|
+
+/**
|
|
8
|
+
+ * The delivery timings this agent accepts on a `_session/steering` request's
|
|
9
|
+
+ * `_meta.steering.priority`, and the value advertised as
|
|
10
|
+
+ * `InitializeResponse._meta.steering.timings`. Both reads come from this one
|
|
11
|
+
+ * array so the accepted set and the advertised set cannot drift apart.
|
|
12
|
+
+ *
|
|
13
|
+
+ * `now` is the only entry because injecting into the live turn is the only
|
|
14
|
+
+ * thing this adapter can ask the app-server for: `turn/steer` carries no timing
|
|
15
|
+
+ * field. A Host that needs `next` (deliver at a boundary without discarding the
|
|
16
|
+
+ * running turn's remaining work) must hold the message itself; declaring the
|
|
17
|
+
+ * set is what lets it know that without having to try and lose work finding
|
|
18
|
+
+ * out.
|
|
19
|
+
+ */
|
|
20
|
+
+var SESSION_STEERING_TIMINGS = ["now"];
|
|
21
|
+
function isExtMethodRequest(request) {
|
|
22
|
+
return request.method === "authentication/status" || request.method === "authentication/logout" || request.method === LEGACY_SET_SESSION_MODEL_METHOD || request.method === GOAL_CONTROL_METHOD || request.method === LEGACY_GOAL_CONTROL_METHOD || request.method === SESSION_STEERING_METHOD || request.method === ASYNC_TASK_STOP_METHOD;
|
|
23
|
+
}
|
|
24
|
+
@@ -32334,7 +32348,11 @@
|
|
25
|
+
authMethods: getCodexAuthMethods(_params.clientCapabilities),
|
|
26
|
+
_meta: {
|
|
27
|
+
steering: {
|
|
28
|
+
- supported: true
|
|
29
|
+
+ supported: true,
|
|
30
|
+
+ // Declared, not probed: `_session/steering` answers the same
|
|
31
|
+
+ // `{outcome}` whichever timing was used, so a Host cannot discover
|
|
32
|
+
+ // this by trying. See SESSION_STEERING_TIMINGS.
|
|
33
|
+
+ timings: [...SESSION_STEERING_TIMINGS]
|
|
34
|
+
},
|
|
35
|
+
goal: {
|
|
36
|
+
version: GOAL_EXTENSION_VERSION,
|
|
37
|
+
@@ -33502,6 +33520,20 @@
|
|
38
|
+
const prompt = params["prompt"];
|
|
39
|
+
if (typeof sessionId !== "string" || !Array.isArray(prompt)) {
|
|
40
|
+
throw RequestError.invalidParams();
|
|
41
|
+
+ }
|
|
42
|
+
+ // `_meta` reaches us because sessionSteerParamsParser passes unknown keys
|
|
43
|
+
+ // through. A priority outside the advertised set is REJECTED rather than
|
|
44
|
+
+ // ignored: the `{outcome}` this method answers is identical either way, so
|
|
45
|
+
+ // a Host that asked for a timing we cannot honour would otherwise learn it
|
|
46
|
+
+ // only by losing the running turn's remaining work.
|
|
47
|
+
+ const meta = params["_meta"];
|
|
48
|
+
+ const steering = meta && typeof meta === "object" ? meta["steering"] : void 0;
|
|
49
|
+
+ const priority = steering && typeof steering === "object" ? steering["priority"] : void 0;
|
|
50
|
+
+ if (priority !== void 0 && !SESSION_STEERING_TIMINGS.includes(priority)) {
|
|
51
|
+
+ throw RequestError.invalidParams(
|
|
52
|
+
+ void 0,
|
|
53
|
+
+ `Unsupported steering priority; this agent accepts ${SESSION_STEERING_TIMINGS.join(", ")}`
|
|
54
|
+
+ );
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
sessionId,
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Injected into pi-acp 0.0.34. Uses its existing RPC process and ACP prompt ownership.
|
|
2
|
+
// Pi 0.87.1 accepts prompt(streamingBehavior=steer) before streaming events finish.
|
|
3
|
+
// Holding the ACP prompt open also tracks a native continuation admitted at the idle boundary.
|
|
4
|
+
class AxomPiSteering {
|
|
5
|
+
constructor(session) {
|
|
6
|
+
this.session = session;
|
|
7
|
+
this.tail = Promise.resolve();
|
|
8
|
+
this.pending = 0;
|
|
9
|
+
this.requested = false;
|
|
10
|
+
this.finishing = false;
|
|
11
|
+
this.settling = null;
|
|
12
|
+
this.revision = 0;
|
|
13
|
+
}
|
|
14
|
+
steer(message, images) {
|
|
15
|
+
const session = this.session;
|
|
16
|
+
if (!session.pendingTurn || session.cancelRequested || this.finishing) {
|
|
17
|
+
return Promise.resolve({ outcome: "promptRequired" });
|
|
18
|
+
}
|
|
19
|
+
const turn = session.pendingTurn;
|
|
20
|
+
this.pending++;
|
|
21
|
+
const operation = this.tail.then(async () => {
|
|
22
|
+
if (session.pendingTurn !== turn || session.cancelRequested) return { outcome: "promptRequired" };
|
|
23
|
+
const state = await session.proc.getState();
|
|
24
|
+
if (state?.isStreaming !== true || state?.isCompacting === true) return { outcome: "promptRequired" };
|
|
25
|
+
// No await between checking ACP ownership and starting the native request.
|
|
26
|
+
if (session.pendingTurn !== turn || session.cancelRequested) return { outcome: "promptRequired" };
|
|
27
|
+
const result = await session.proc.request({ type: "prompt", message, images, streamingBehavior: "steer" });
|
|
28
|
+
if (!result.success) return { outcome: "promptRequired" };
|
|
29
|
+
return { outcome: "injected" };
|
|
30
|
+
});
|
|
31
|
+
this.tail = operation.catch(() => {});
|
|
32
|
+
return operation.finally(() => {
|
|
33
|
+
this.pending--;
|
|
34
|
+
if (!this.pending && this.requested) this.settle();
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
settle() {
|
|
38
|
+
this.requested = true;
|
|
39
|
+
this.revision++;
|
|
40
|
+
if (this.pending || this.settling || this.finishing) return this.settling;
|
|
41
|
+
const session = this.session;
|
|
42
|
+
const turn = session.pendingTurn;
|
|
43
|
+
if (!turn) return;
|
|
44
|
+
const revision = this.revision;
|
|
45
|
+
this.settling = (async () => {
|
|
46
|
+
const state = await session.proc.getState();
|
|
47
|
+
// An old agent_settled notification may arrive during admission of a new native loop.
|
|
48
|
+
if (this.pending || session.pendingTurn !== turn || state?.isStreaming === true || state?.isCompacting === true) return;
|
|
49
|
+
this.finishing = true;
|
|
50
|
+
this.requested = false;
|
|
51
|
+
try { await session.axomFinishTurn(); }
|
|
52
|
+
finally { this.finishing = false; }
|
|
53
|
+
})().catch(error => {
|
|
54
|
+
if (session.pendingTurn === turn) {
|
|
55
|
+
session.pendingTurn = null;
|
|
56
|
+
turn.reject(error);
|
|
57
|
+
}
|
|
58
|
+
}).finally(() => {
|
|
59
|
+
this.settling = null;
|
|
60
|
+
if (!this.pending && this.requested && this.revision !== revision) this.settle();
|
|
61
|
+
});
|
|
62
|
+
return this.settling;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function axomPiSupportsSteering() {
|
|
67
|
+
const command = getPiCommand(process.env.PI_ACP_PI_COMMAND);
|
|
68
|
+
const launch = shouldUseShellForPiCommand(command) ? crossSpawn : spawn;
|
|
69
|
+
return new Promise(resolve => {
|
|
70
|
+
let output = "";
|
|
71
|
+
let child;
|
|
72
|
+
try { child = launch(command, ["--version"], { stdio: ["ignore", "pipe", "ignore"], env: process.env }); }
|
|
73
|
+
catch { resolve(false); return; }
|
|
74
|
+
const timeout = setTimeout(() => { child.kill(); resolve(false); }, 5000);
|
|
75
|
+
child.stdout.on("data", data => { output += data; });
|
|
76
|
+
child.on("error", () => { clearTimeout(timeout); resolve(false); });
|
|
77
|
+
child.on("close", code => { clearTimeout(timeout); resolve(code === 0 && output.trim() === "0.87.1"); });
|
|
78
|
+
});
|
|
79
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -25,7 +25,8 @@ export function buildProgram() {
|
|
|
25
25
|
.command('auth')
|
|
26
26
|
.description('Authorize axom-cli with an Axomwork server')
|
|
27
27
|
.option('--server <url>', 'Axomwork server URL')
|
|
28
|
-
.
|
|
28
|
+
.option('--cowork', 'Request delegated cowork session access')
|
|
29
|
+
.action((options) => runCommand(() => authAction({ server: options.server ?? serverOption(), cowork: options.cowork })));
|
|
29
30
|
program
|
|
30
31
|
.command('whoami')
|
|
31
32
|
.description('Print the authenticated Axomwork user')
|
|
@@ -38,6 +39,13 @@ export function buildProgram() {
|
|
|
38
39
|
program
|
|
39
40
|
.command('__credential-broker', { hidden: true })
|
|
40
41
|
.action(() => runCredentialBroker());
|
|
42
|
+
program.command('qoder-acp')
|
|
43
|
+
.description('Run the Qoder SDK ACP adapter over stdio')
|
|
44
|
+
.requiredOption('--qodercli <path>', 'Explicit Qoder CLI executable')
|
|
45
|
+
.action(async (options) => {
|
|
46
|
+
const { runQoderAdapter } = await import('./workstation/qoderAdapter/main.js');
|
|
47
|
+
await runQoderAdapter(options.qodercli);
|
|
48
|
+
});
|
|
41
49
|
registerStructCommands(program);
|
|
42
50
|
registerRecordCommands(program);
|
|
43
51
|
registerExecuteCommand(program);
|
package/dist/commands/auth.js
CHANGED
|
@@ -2,13 +2,14 @@ import { hostname } from 'node:os';
|
|
|
2
2
|
import { loadConfig, resolveServer, saveConfig } from '../config.js';
|
|
3
3
|
import { callAxomTool } from '../mcp.js';
|
|
4
4
|
import { authorizeDevice } from '../workstation/oauth/deviceAuthorization.js';
|
|
5
|
-
import { revokeAndClearTokens, saveTokens } from '../credentials.js';
|
|
5
|
+
import { revokeAndClearTokens, revokeRefreshToken, saveTokens } from '../credentials.js';
|
|
6
|
+
import { cliRequestedScopes } from '../authScopes.js';
|
|
6
7
|
export const DEFAULT_SERVER_URL = 'http://localhost:8080';
|
|
7
8
|
export async function authAction(options, deps = {}) {
|
|
8
9
|
const config = await loadConfig();
|
|
9
10
|
const server = resolveServer(config, options.server ?? config.defaultServer ?? DEFAULT_SERVER_URL);
|
|
10
11
|
const host = hostname();
|
|
11
|
-
const { accessToken, refreshToken, expiresInSeconds } = await authorizeDevice(server, `Axomwork CLI (${host})`, host, deps);
|
|
12
|
+
const { accessToken, refreshToken, expiresInSeconds, scopes } = await authorizeDevice(server, `Axomwork CLI (${host})`, host, deps, cliRequestedScopes(options.cowork));
|
|
12
13
|
const updated = await loadConfig();
|
|
13
14
|
try {
|
|
14
15
|
await saveTokens(server, { accessToken, refreshToken, expiresAt: new Date(Date.now() + expiresInSeconds * 1000).toISOString() });
|
|
@@ -22,6 +23,7 @@ export async function authAction(options, deps = {}) {
|
|
|
22
23
|
updated.defaultServer = server;
|
|
23
24
|
}
|
|
24
25
|
await saveConfig(updated);
|
|
26
|
+
console.log(`Authorized scopes: ${scopes.join(', ')}`);
|
|
25
27
|
const outcome = await callAxomTool(server, 'axom__system__whoami', {});
|
|
26
28
|
if (outcome.isError) {
|
|
27
29
|
throw new Error(outcome.text);
|
|
@@ -39,14 +41,3 @@ export async function logoutAction(options) {
|
|
|
39
41
|
await saveConfig(config);
|
|
40
42
|
console.log(`Logged out from ${server}`);
|
|
41
43
|
}
|
|
42
|
-
async function revokeRefreshToken(server, refreshToken) {
|
|
43
|
-
await fetch(`${server}/oauth/revoke`, {
|
|
44
|
-
method: 'POST',
|
|
45
|
-
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
46
|
-
body: new URLSearchParams({
|
|
47
|
-
token: refreshToken,
|
|
48
|
-
token_type_hint: 'refresh_token',
|
|
49
|
-
client_id: 'axom-cli',
|
|
50
|
-
}),
|
|
51
|
-
}).catch(() => undefined);
|
|
52
|
-
}
|
package/dist/commands/execute.js
CHANGED
|
@@ -20,9 +20,9 @@ export async function executeAction(options) {
|
|
|
20
20
|
if (parts.length === 3) {
|
|
21
21
|
const [applicationName, modelName, operationName] = parts;
|
|
22
22
|
printOutcome(
|
|
23
|
-
// 同步是
|
|
23
|
+
// 同步是 axom__execute__run_* 的固有语义;awaitResult 参数已随 InvocationMode 重构移除,
|
|
24
24
|
// 继续传会被工具的封闭 inputSchema 直接拒掉。
|
|
25
|
-
await callAxomTool(server, '
|
|
25
|
+
await callAxomTool(server, 'axom__execute__run_operation', {
|
|
26
26
|
applicationName,
|
|
27
27
|
modelName,
|
|
28
28
|
operationName,
|
|
@@ -32,9 +32,9 @@ export async function executeAction(options) {
|
|
|
32
32
|
}
|
|
33
33
|
if (parts.length === 2) {
|
|
34
34
|
const [applicationName, serviceName] = parts;
|
|
35
|
-
printOutcome(await callAxomTool(server, '
|
|
35
|
+
printOutcome(await callAxomTool(server, 'axom__execute__run_service', { applicationName, serviceName, input }));
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
const [serviceName] = parts;
|
|
39
|
-
printOutcome(await callAxomTool(server, '
|
|
39
|
+
printOutcome(await callAxomTool(server, 'axom__execute__run_service', { serviceName, input }));
|
|
40
40
|
}
|
package/dist/commands/record.js
CHANGED
|
@@ -45,24 +45,24 @@ export function registerRecordCommands(program) {
|
|
|
45
45
|
export async function recordGetAction(options) {
|
|
46
46
|
const server = await resolveActionServer(options.server);
|
|
47
47
|
const [applicationName, modelName] = splitPath(options.path, 2, '<app>/<model>');
|
|
48
|
-
printOutcome(await callAxomTool(server, '
|
|
48
|
+
printOutcome(await callAxomTool(server, 'axom__record_query__get_record', { applicationName, modelName, id: options.id }));
|
|
49
49
|
}
|
|
50
50
|
export async function recordCreateAction(options) {
|
|
51
51
|
const server = await resolveActionServer(options.server);
|
|
52
52
|
const [applicationName, modelName] = splitPath(options.path, 2, '<app>/<model>');
|
|
53
53
|
const record = parseJsonArg(options.json, 'record', recordExample);
|
|
54
|
-
printOutcome(await callAxomTool(server, '
|
|
54
|
+
printOutcome(await callAxomTool(server, 'axom__record_write__create_record', { applicationName, modelName, record }));
|
|
55
55
|
}
|
|
56
56
|
export async function recordUpdateAction(options) {
|
|
57
57
|
const server = await resolveActionServer(options.server);
|
|
58
58
|
const [applicationName, modelName] = splitPath(options.path, 2, '<app>/<model>');
|
|
59
59
|
const changes = parseJsonArg(options.json, 'record update changes', recordExample);
|
|
60
|
-
printOutcome(await callAxomTool(server, '
|
|
60
|
+
printOutcome(await callAxomTool(server, 'axom__record_write__update_record', { applicationName, modelName, id: options.id, changes }));
|
|
61
61
|
}
|
|
62
62
|
export async function recordUpsertAction(options) {
|
|
63
63
|
const server = await resolveActionServer(options.server);
|
|
64
64
|
const record = parseJsonArg(options.record, 'record', recordExample);
|
|
65
|
-
printOutcome(await callAxomTool(server, '
|
|
65
|
+
printOutcome(await callAxomTool(server, 'axom__record_write__upsert_record', {
|
|
66
66
|
applicationName: options.applicationName,
|
|
67
67
|
modelName: options.modelName,
|
|
68
68
|
identityField: options.identityField,
|
|
@@ -72,7 +72,7 @@ export async function recordUpsertAction(options) {
|
|
|
72
72
|
export async function recordDeleteAction(options) {
|
|
73
73
|
const server = await resolveActionServer(options.server);
|
|
74
74
|
const [applicationName, modelName] = splitPath(options.path, 2, '<app>/<model>');
|
|
75
|
-
printOutcome(await callAxomTool(server, '
|
|
75
|
+
printOutcome(await callAxomTool(server, 'axom__record_write__delete_record', { applicationName, modelName, id: options.id }));
|
|
76
76
|
}
|
|
77
77
|
export async function recordQueryAction(options) {
|
|
78
78
|
const server = await resolveActionServer(options.server);
|
|
@@ -92,7 +92,7 @@ export async function recordQueryAction(options) {
|
|
|
92
92
|
args.criteria = queryCriteria;
|
|
93
93
|
if ('page' in criteria)
|
|
94
94
|
args.page = criteria.page;
|
|
95
|
-
printOutcome(await callAxomTool(server, '
|
|
95
|
+
printOutcome(await callAxomTool(server, 'axom__record_query__query_records', args));
|
|
96
96
|
}
|
|
97
97
|
async function resolveActionServer(server) {
|
|
98
98
|
return resolveServer(await loadConfig(), server);
|
package/dist/commands/struct.js
CHANGED
|
@@ -23,22 +23,22 @@ export async function structListAction(options) {
|
|
|
23
23
|
if (options.target !== undefined) {
|
|
24
24
|
throw new UsageError('Expected axom struct list app with no target.');
|
|
25
25
|
}
|
|
26
|
-
printOutcome(await callAxomTool(server, '
|
|
26
|
+
printOutcome(await callAxomTool(server, 'axom__app_struct__list_applications', {}));
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
const [applicationName] = splitPath(options.target ?? '', 1, '<applicationName>');
|
|
30
|
-
printOutcome(await callAxomTool(server, '
|
|
30
|
+
printOutcome(await callAxomTool(server, 'axom__app_struct__list_models', { applicationName }));
|
|
31
31
|
}
|
|
32
32
|
export async function structGetAction(options) {
|
|
33
33
|
const server = await resolveActionServer(options.server);
|
|
34
34
|
const kind = requireStructKind(options.kind);
|
|
35
35
|
if (kind === 'app') {
|
|
36
36
|
const [applicationName] = splitPath(options.target ?? '', 1, '<applicationName>');
|
|
37
|
-
printOutcome(await callAxomTool(server, '
|
|
37
|
+
printOutcome(await callAxomTool(server, 'axom__app_struct__get_application', { applicationName }));
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
40
|
const [applicationName, modelName] = splitPath(options.target ?? '', 2, '<applicationName>/<modelName>');
|
|
41
|
-
printOutcome(await callAxomTool(server, '
|
|
41
|
+
printOutcome(await callAxomTool(server, 'axom__app_struct__get_model', { applicationName, modelName }));
|
|
42
42
|
}
|
|
43
43
|
async function resolveActionServer(server) {
|
|
44
44
|
return resolveServer(await loadConfig(), server);
|