@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
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
"id": "zcode-subagent-subwork",
|
|
3
3
|
"package": "zcode-acp-server",
|
|
4
4
|
"versions": [
|
|
5
|
-
"0.
|
|
6
|
-
"0.69.4"
|
|
5
|
+
"0.76.3"
|
|
7
6
|
],
|
|
8
7
|
"edits": [
|
|
9
8
|
{
|
|
@@ -29,15 +28,15 @@
|
|
|
29
28
|
},
|
|
30
29
|
{
|
|
31
30
|
"file": "dist/server.js",
|
|
32
|
-
"before_sha256": "
|
|
33
|
-
"after_sha256": "
|
|
31
|
+
"before_sha256": "40a55e7b7fc6662a664f9d462dd4c8774e2e73d222669cb3902448c026b6b6a2",
|
|
32
|
+
"after_sha256": "95e940c79d16571c1c125d4536c88c94136ddc09713dee65e003cce3ac2a4a8e",
|
|
34
33
|
"before": "export class ZcodeAcpServer {",
|
|
35
34
|
"after": "/** Axom patch `zcode-subagent-subwork`: normalize ZCode sub-agents and background\n * tasks into the draft ACP subagent variants (RFD #1992) and the AIR async-task\n * extension — the same contracts claude-agent-acp ships. The backend already emits\n * first-class lifecycle events on `session.updated` (agentId/childSessionId for\n * sub-agents, taskId for background tasks); this listener forwards them so hosts\n * can project subworks, and dispatch.js re-scopes a foreground sub-agent's internal\n * `tool_subagent_*` tool calls onto its child session. */\nclass AxomZcodeSubagents {\n constructor(server, zcodeSid) {\n this.server = server;\n this.sid = zcodeSid;\n /** agentId → { agentId, child, background, terminal, pendingState, pendingP, resultSeen, preview } */\n this.agents = new Map();\n /** parentToolCallId → agent record (foreground result flush). */\n this.parents = new Map();\n /** taskId → { terminal } (bash/exec background tasks only). */\n this.tasks = new Map();\n }\n /** Draft RFD #1992 negotiated — the axom daemon always declares this. */\n nativeOk() {\n const caps = this.server.clientCapabilities;\n return !!(caps && caps.subagents);\n }\n /** AIR async-task capability declared (`_meta.jetbrains.air.capabilities`). */\n asyncOk() {\n const air = this.server.clientCapabilities?._meta?.jetbrains?.air;\n return !!(air && Array.isArray(air.capabilities) && air.capabilities.includes(\"asyncTasks\"));\n }\n handleEvent(ev) {\n try {\n void this.onEvent(ev);\n }\n catch {\n // Never crash the bridge from a normalization observer.\n }\n }\n async onEvent(ev) {\n if (!ev || ev.type !== \"session.updated\") {\n this.onToolEvent(ev);\n return;\n }\n const p = ev.payload ?? {};\n if (typeof p.agentId === \"string\" && p.agentId && typeof p.childSessionId === \"string\" && p.childSessionId) {\n this.onAgent(p);\n return;\n }\n // Sub-agent background tasks also carry taskId with taskKind \"subagent\" —\n // the agentId path above owns those. Workflow runs have their own poller.\n if (typeof p.taskId === \"string\" && p.taskId && p.taskKind !== \"subagent\" && p.taskKind !== \"workflow\") {\n this.onTask(p);\n }\n }\n onAgent(p) {\n if (!this.nativeOk())\n return;\n const agentId = p.agentId;\n const child = p.childSessionId;\n const status = typeof p.status === \"string\" ? p.status : \"running\";\n let rec = this.agents.get(agentId);\n if (!rec) {\n rec = { agentId, child, background: p.background === true, terminal: false, pendingState: null, pendingP: null, resultSeen: false, preview: null };\n this.agents.set(agentId, rec);\n if (typeof p.parentToolCallId === \"string\" && p.parentToolCallId)\n this.parents.set(p.parentToolCallId, rec);\n // First sighting already terminal (adapter restart): adopt — emit the\n // spawn so the host can still link the child, then the state below.\n if (status !== \"running\")\n rec.resultSeen = true;\n this.emit({\n sessionUpdate: \"subagent_spawned\",\n subagentSessionId: child,\n name: (typeof p.description === \"string\" && p.description) || (typeof p.agentType === \"string\" && p.agentType) || \"Subagent\",\n task: typeof p.prompt === \"string\" ? p.prompt : (p.description ?? \"\"),\n capabilities: {},\n _meta: { zcode: { agentId, parentToolCallId: p.parentToolCallId, background: rec.background, adopted: status !== \"running\" } },\n });\n }\n if (rec.child !== child)\n return;\n const mapped = status === \"completed\" ? \"completed\"\n : status === \"failed\" || status === \"error\" ? \"failed\"\n : status === \"cancelled\" || status === \"stopped\" ? \"cancelled\"\n : status === \"disconnected\" ? \"disconnected\" : null;\n if (!mapped || rec.terminal)\n return;\n if (rec.background || rec.resultSeen || mapped !== \"completed\") {\n this.finishAgent(rec, mapped, p);\n return;\n }\n // Foreground completion: hold the state until the parent Agent tool's own\n // result event arrives (one event later, measured) so the child-scoped\n // preview precedes the terminal state on the wire.\n rec.pendingState = mapped;\n rec.pendingP = p;\n }\n finishAgent(rec, state, p) {\n rec.terminal = true;\n if (rec.preview) {\n this.emitChild(rec.child, { sessionUpdate: \"agent_message_chunk\", content: { type: \"text\", text: rec.preview } });\n rec.preview = null;\n }\n const meta = { zcode: { agentId: rec.agentId } };\n if (p) {\n for (const key of [\"parentToolCallId\", \"outputFile\"])\n if (typeof p[key] === \"string\")\n meta.zcode[key] = p[key];\n if (typeof p.totalTokens === \"number\")\n meta.zcode.totalTokens = p.totalTokens;\n if (typeof p.totalDurationMs === \"number\")\n meta.zcode.totalDurationMs = p.totalDurationMs;\n }\n this.emit({ sessionUpdate: \"subagent_state_update\", subagentSessionId: rec.child, state, _meta: meta });\n }\n onToolEvent(ev) {\n if (!ev || ev.type !== \"tool.updated\")\n return;\n const p = ev.payload ?? {};\n if (p.kind !== \"result\" || typeof p.toolCallId !== \"string\")\n return;\n const rec = this.parents.get(p.toolCallId);\n if (!rec || rec.terminal || rec.background)\n return;\n rec.resultSeen = true;\n const text = axomSubagentResultPreview(p.result);\n if (text)\n rec.preview = text;\n if (rec.pendingState)\n this.finishAgent(rec, rec.pendingState, rec.pendingP);\n }\n onTask(p) {\n if (!this.asyncOk())\n return;\n const taskId = p.taskId;\n let task = this.tasks.get(taskId);\n const status = typeof p.status === \"string\" ? p.status : \"running\";\n if (!task) {\n task = { terminal: false };\n this.tasks.set(taskId, task);\n this.emit({\n sessionUpdate: \"async_task_spawned\",\n asyncTaskId: taskId,\n name: (typeof p.description === \"string\" && p.description) || (typeof p.command === \"string\" && p.command) || \"background task\",\n taskType: typeof p.taskKind === \"string\" ? p.taskKind : \"shell\",\n description: typeof p.description === \"string\" ? p.description : \"\",\n showInTranscript: false,\n canStop: p.cancellable === true,\n ...(typeof p.outputPath === \"string\" ? { outputFilePath: p.outputPath } : {}),\n ...(typeof p.toolCallId === \"string\" ? { toolCallId: p.toolCallId } : {}),\n _meta: { zcode: { taskKind: p.taskKind, command: p.command } },\n });\n }\n const mapped = status === \"completed\" ? \"completed\"\n : status === \"failed\" || status === \"error\" ? \"failed\"\n : status === \"cancelled\" ? \"stopped\" : null;\n if (!mapped || task.terminal)\n return;\n task.terminal = true;\n this.emit({\n sessionUpdate: \"async_task_state_update\",\n asyncTaskId: taskId,\n state: mapped,\n ...(typeof p.toolCallId === \"string\" ? { toolCallId: p.toolCallId } : {}),\n });\n }\n emit(update) {\n void this.server.notifyByZcodeSid(this.sid, update);\n }\n emitChild(childId, update) {\n const server = this.server;\n if (!server.clients || server.clients.size === 0)\n return;\n void enqueueSessionSend(childId, () => server.clients.broadcast().notify(\"session/update\", { sessionId: childId, update }));\n }\n}\n/** The parent Agent tool's result carries the sub-agent's final message plus an\n * `agentId:` line and a `<usage>` block that belong to the envelope, not the\n * answer. The backend delivers the payload as a JSON string or as an already\n * parsed object (both measured) — accept either. */\nfunction axomSubagentResultPreview(result) {\n let content = null;\n if (typeof result === \"string\") {\n try {\n const parsed = JSON.parse(result);\n if (parsed && typeof parsed.content === \"string\")\n content = parsed.content;\n }\n catch {\n content = result;\n }\n }\n else if (result && typeof result === \"object\" && typeof result.content === \"string\") {\n content = result.content;\n }\n if (typeof content !== \"string\" || !content.trim())\n return null;\n const stripped = content\n .replace(/<usage>[\\s\\S]*?<\\/usage>/g, \"\")\n .split(\"\\n\")\n .filter((line) => !/^agentId:\\s*\\S+/.test(line))\n .join(\"\\n\")\n .trim();\n return stripped ? stripped.slice(0, 2000) : null;\n}\nexport { AxomZcodeSubagents };\nexport class ZcodeAcpServer {"
|
|
36
35
|
},
|
|
37
36
|
{
|
|
38
37
|
"file": "dist/server.js",
|
|
39
|
-
"before_sha256": "
|
|
40
|
-
"after_sha256": "
|
|
38
|
+
"before_sha256": "95e940c79d16571c1c125d4536c88c94136ddc09713dee65e003cce3ac2a4a8e",
|
|
39
|
+
"after_sha256": "240a49618e47792dfbaa5f713dca8072bd1e0c56f726e177a1936e071c69df42",
|
|
41
40
|
"before": " backend.registerEventListener(zcodeSid, new SessionTitleListener(this, zcodeSid));\n this.backgroundListenerBackend.set(zcodeSid, backend);",
|
|
42
41
|
"after": " backend.registerEventListener(zcodeSid, new SessionTitleListener(this, zcodeSid));\n backend.registerEventListener(zcodeSid, new AxomZcodeSubagents(this, zcodeSid));\n this.backgroundListenerBackend.set(zcodeSid, backend);"
|
|
43
42
|
},
|
|
@@ -57,15 +56,15 @@
|
|
|
57
56
|
},
|
|
58
57
|
{
|
|
59
58
|
"file": "dist/handlers/session.js",
|
|
60
|
-
"before_sha256": "
|
|
61
|
-
"after_sha256": "
|
|
59
|
+
"before_sha256": "770b8094520487b3eefbea3b47edfad82895bb2658b38dd8c70b201f29ac07be",
|
|
60
|
+
"after_sha256": "86877e687c74d97e581a0991e549842130567e2041cf4caa10b8ae910a0f2a77",
|
|
62
61
|
"before": "async function adoptStoredTitle(server, acpSid, zcodeSid) {\n if (server.sessionTitles.has(acpSid))\n return;",
|
|
63
62
|
"after": "async function adoptStoredTitle(server, acpSid, zcodeSid) {\n // Axom patch `zcode-subagent-subwork`: the in-memory title is usually the first\n // prompt's echo; the backend's stored generated title is the real answer, and the\n // live titleUpdated push is routinely lost at a backend respawn boundary — this\n // load-time read is then the only surviving copy. A user-pinned rename still wins.\n if (server.sessionTitles.has(acpSid) && server.titleUserSetBy.has(acpSid))\n return;"
|
|
64
63
|
},
|
|
65
64
|
{
|
|
66
65
|
"file": "dist/handlers/session.js",
|
|
67
|
-
"before_sha256": "
|
|
68
|
-
"after_sha256": "
|
|
66
|
+
"before_sha256": "86877e687c74d97e581a0991e549842130567e2041cf4caa10b8ae910a0f2a77",
|
|
67
|
+
"after_sha256": "ba1d5ba52957793c9f392ee6ab425a13eb912e1a5544b485d548d11e25f95a95",
|
|
69
68
|
"before": " if (hit?.title) {\n server.sessionTitles.set(acpSid, hit.title);\n server.touchSessionSummary(acpSid, hit.title);\n refreshTerminalTabTitle(server, acpSid);\n log(`adopted stored title for ${acpSid.slice(0, 8)}: ${hit.title}`);\n }",
|
|
70
69
|
"after": " if (hit?.title && server.sessionTitles.get(acpSid) !== hit.title) {\n server.sessionTitles.set(acpSid, hit.title);\n server.touchSessionSummary(acpSid, hit.title);\n refreshTerminalTabTitle(server, acpSid);\n // Axom patch `zcode-subagent-subwork`: broadcast so hosts sync the stored\n // generated title on (re-)attach — the live push was lost at a respawn.\n void sendSessionUpdate(server.clients.broadcast(), acpSid, {\n sessionUpdate: \"session_info_update\",\n title: hit.title,\n updatedAt: new Date().toISOString(),\n }).catch(() => { });\n log(`adopted stored title for ${acpSid.slice(0, 8)}: ${hit.title}`);\n }"
|
|
71
70
|
}
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { realpathSync } from 'node:fs';
|
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
5
5
|
import { authAction, logoutAction } from './commands/auth.js';
|
|
6
6
|
import { registerExecuteCommand } from './commands/execute.js';
|
|
7
|
-
import {
|
|
7
|
+
import { registerKnowledgeCommands } from './commands/knowledge.js';
|
|
8
8
|
import { registerRecordCommands } from './commands/record.js';
|
|
9
9
|
import { registerSkillsCommands } from './commands/skills.js';
|
|
10
10
|
import { registerStructCommands } from './commands/struct.js';
|
|
@@ -39,50 +39,18 @@ export function buildProgram() {
|
|
|
39
39
|
program
|
|
40
40
|
.command('__credential-broker', { hidden: true })
|
|
41
41
|
.action(() => runCredentialBroker());
|
|
42
|
-
const qoderCommand = program.command('qoder-acp')
|
|
43
|
-
.description('Prepare or run the Qoder SDK ACP adapter')
|
|
44
|
-
.option('--qodercli <path>', 'Explicit Qoder CLI executable')
|
|
45
|
-
.option('--prepare-sdk', 'Install the separate SDK runtime, then exit');
|
|
46
|
-
qoderCommand.action(async (options) => {
|
|
47
|
-
if (Boolean(options.qodercli) === Boolean(options.prepareSdk))
|
|
48
|
-
qoderCommand.error('Choose exactly one of --prepare-sdk or --qodercli <path>');
|
|
49
|
-
try {
|
|
50
|
-
if (options.prepareSdk) {
|
|
51
|
-
const { prepareSdkRuntime } = await import('./workstation/qoderAdapter/sdkRuntimeInstall.js');
|
|
52
|
-
const controller = new AbortController();
|
|
53
|
-
const cancel = () => controller.abort();
|
|
54
|
-
process.once('SIGINT', cancel);
|
|
55
|
-
process.once('SIGTERM', cancel);
|
|
56
|
-
try {
|
|
57
|
-
console.error('Preparing Qoder SDK…');
|
|
58
|
-
const result = await prepareSdkRuntime({ signal: controller.signal });
|
|
59
|
-
console.error(`Qoder SDK ready${result.alreadyInstalled ? ' (already prepared)' : ''}: ${result.instance}`);
|
|
60
|
-
}
|
|
61
|
-
finally {
|
|
62
|
-
process.removeListener('SIGINT', cancel);
|
|
63
|
-
process.removeListener('SIGTERM', cancel);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
const { runQoderAdapter } = await import('./workstation/qoderAdapter/main.js');
|
|
68
|
-
await runQoderAdapter(options.qodercli);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
73
|
-
process.exitCode = 1;
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
42
|
registerStructCommands(program);
|
|
77
43
|
registerRecordCommands(program);
|
|
78
44
|
registerExecuteCommand(program);
|
|
79
|
-
|
|
45
|
+
registerKnowledgeCommands(program);
|
|
80
46
|
registerSkillsCommands(program);
|
|
81
47
|
registerUpdateCommand(program);
|
|
82
48
|
registerWorkstationCommands(program, {
|
|
83
49
|
start, stop, restart, install, uninstall, runDaemon, registerWorkstation,
|
|
84
50
|
status: async () => {
|
|
85
51
|
const current = await status();
|
|
52
|
+
if (current.uncertain)
|
|
53
|
+
return 'workstation state is unknown; run `axom workstation inspect --json` to verify it';
|
|
86
54
|
return current.running
|
|
87
55
|
? `running connected to ${current.server ?? 'unknown server'} as ${current.workstationId ?? 'unknown workstation'}`
|
|
88
56
|
: 'stopped';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { loadConfig, resolveServer, UsageError } from '../config.js';
|
|
2
|
+
import { callAxomTool } from '../mcp.js';
|
|
3
|
+
import { printOutcome, runCommand } from '../output.js';
|
|
4
|
+
export const GUIDE_RENAMED_MESSAGE = 'axom guide was renamed: use axom knowledge get|search';
|
|
5
|
+
export function registerKnowledgeCommands(program) {
|
|
6
|
+
const knowledge = program.command('knowledge').description('Read and search the Axomwork manual');
|
|
7
|
+
const serverOption = () => program.opts().server;
|
|
8
|
+
knowledge
|
|
9
|
+
.command('get')
|
|
10
|
+
.description('Get a manual page, or the table of contents when no path is given')
|
|
11
|
+
.argument('[path]', 'manual page path, e.g. script-language/sdk/records.md')
|
|
12
|
+
.option('--locale <locale>', 'manual locale (en|zh)')
|
|
13
|
+
.action((path, options) => runCommand(() => knowledgeGetAction({ path, locale: options.locale, server: serverOption() })));
|
|
14
|
+
knowledge
|
|
15
|
+
.command('search')
|
|
16
|
+
.description('Search the manual with keywords or a question')
|
|
17
|
+
.argument('<query>')
|
|
18
|
+
.option('--locale <locale>', 'manual locale (en|zh)')
|
|
19
|
+
.option('--limit <n>', 'maximum hits')
|
|
20
|
+
.action((query, options) => runCommand(() => knowledgeSearchAction({ query, locale: options.locale, limit: options.limit, server: serverOption() })));
|
|
21
|
+
// Deliberately not an alias: old scripts must fail loudly and learn the new name.
|
|
22
|
+
program
|
|
23
|
+
.command('guide', { hidden: true })
|
|
24
|
+
.allowUnknownOption()
|
|
25
|
+
.allowExcessArguments()
|
|
26
|
+
.argument('[args...]')
|
|
27
|
+
.helpOption(false)
|
|
28
|
+
.action(() => runCommand(async () => { throw new UsageError(GUIDE_RENAMED_MESSAGE); }));
|
|
29
|
+
}
|
|
30
|
+
export async function knowledgeGetAction(options) {
|
|
31
|
+
const server = resolveServer(await loadConfig(), options.server);
|
|
32
|
+
const args = {};
|
|
33
|
+
if (options.path !== undefined)
|
|
34
|
+
args.path = options.path;
|
|
35
|
+
if (options.locale !== undefined)
|
|
36
|
+
args.locale = options.locale;
|
|
37
|
+
printOutcome(await callAxomTool(server, 'axom__knowledge__get', args));
|
|
38
|
+
}
|
|
39
|
+
export async function knowledgeSearchAction(options) {
|
|
40
|
+
const server = resolveServer(await loadConfig(), options.server);
|
|
41
|
+
const args = { query: options.query };
|
|
42
|
+
if (options.locale !== undefined)
|
|
43
|
+
args.locale = options.locale;
|
|
44
|
+
if (options.limit !== undefined)
|
|
45
|
+
args.limit = Number(options.limit);
|
|
46
|
+
printOutcome(await callAxomTool(server, 'axom__knowledge__search', args));
|
|
47
|
+
}
|
package/dist/commands/update.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { inspectWorkstation } from '../workstation/control/inspect.js';
|
|
3
|
+
import { requestRuntimeUpdate } from '../workstation/control/runtimeClient.js';
|
|
4
|
+
import { withWorkstationLock } from '../workstation/control/locks.js';
|
|
5
|
+
import { bindingGuardSchema, LocalControlError } from '../workstation/control/protocol.js';
|
|
6
|
+
import { enrollmentFailure } from '../workstation/control/enrollment.js';
|
|
7
|
+
import { readLocalRequest } from '../workstation/control/commands.js';
|
|
8
|
+
import { deploymentDownloadURL, normalizeWorkstationServer, workstationEndpoint } from '../workstation/control/serverIdentity.js';
|
|
1
9
|
import { randomUUID } from 'node:crypto';
|
|
2
10
|
import { UsageError, loadConfig, resolveServer } from '../config.js';
|
|
3
11
|
import { runCommand } from '../output.js';
|
|
@@ -13,8 +21,8 @@ function isManifest(value) {
|
|
|
13
21
|
}
|
|
14
22
|
/** Fetches the release the server currently publishes for this exact deployment. */
|
|
15
23
|
async function fetchManifest(server, fetchImpl) {
|
|
16
|
-
const url =
|
|
17
|
-
const response = await fetchImpl(url);
|
|
24
|
+
const url = workstationEndpoint(server, '/download/client/manifest.json').toString();
|
|
25
|
+
const response = await fetchImpl(url, { redirect: 'error', signal: AbortSignal.timeout(30_000) });
|
|
18
26
|
if (!response.ok) {
|
|
19
27
|
throw new Error(`Fetching the release manifest failed with HTTP ${response.status}`);
|
|
20
28
|
}
|
|
@@ -55,6 +63,15 @@ export async function updateAction(options, deps = {}) {
|
|
|
55
63
|
version: manifest.version, url: manifest.url, size: manifest.size, sha512: manifest.sha512,
|
|
56
64
|
};
|
|
57
65
|
const dir = deps.dir ?? clientDir();
|
|
66
|
+
if (!deps.createCoordinator) {
|
|
67
|
+
const current = await inspectWorkstation(dir);
|
|
68
|
+
const result = await updateLocalCli({ operationId: `manual-${randomUUID()}`, server, guard: { revision: current.revision, runtimeGeneration: current.runtime.generation }, expectedRelease: { version: release.version, sha512: release.sha512 } }, dir, fetchImpl);
|
|
69
|
+
if (result.status === 'succeeded' || result.status === 'pending') {
|
|
70
|
+
(deps.log ?? console.log)(result.status === 'pending' ? 'Update requested. Check workstation status for progress.' : `Installed ${release.version}.`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
throw new Error(result.error?.message ?? 'The workstation is busy; try again when its work finishes.');
|
|
74
|
+
}
|
|
58
75
|
const coordinator = deps.createCoordinator ? deps.createCoordinator({ dir, server }) : defaultCoordinator(dir, server);
|
|
59
76
|
const command = { commandId: `manual-${randomUUID()}`, release, force: false };
|
|
60
77
|
const status = await coordinator.handle(command);
|
|
@@ -78,11 +95,56 @@ export async function updateAction(options, deps = {}) {
|
|
|
78
95
|
throw new Error(status.error ?? `Update did not complete (phase: ${status.phase}).`);
|
|
79
96
|
}
|
|
80
97
|
}
|
|
98
|
+
const updateRequestSchema = z.object({ operationId: z.string().min(1).max(128), server: z.string(), guard: bindingGuardSchema, expectedRelease: z.object({ version: z.string(), sha512: z.string().regex(/^[a-f0-9]{128}$/i) }).strict() }).strict();
|
|
99
|
+
export async function updateLocalCli(raw, directory, fetchImpl = globalThis.fetch) {
|
|
100
|
+
try {
|
|
101
|
+
const request = updateRequestSchema.parse(raw);
|
|
102
|
+
const server = normalizeWorkstationServer(request.server);
|
|
103
|
+
const manifest = await fetchManifest(server, fetchImpl);
|
|
104
|
+
if (manifest.version !== request.expectedRelease.version || manifest.sha512 !== request.expectedRelease.sha512)
|
|
105
|
+
throw new LocalControlError('BINDING_CONFLICT', 'The published release changed; review it again');
|
|
106
|
+
manifest.url = deploymentDownloadURL(server, manifest.url);
|
|
107
|
+
return await withWorkstationLock(directory, 'installation', () => withWorkstationLock(directory, 'operation', async () => {
|
|
108
|
+
const current = await inspectWorkstation(directory);
|
|
109
|
+
if (current.revision !== request.guard.revision || current.runtime.generation !== request.guard.runtimeGeneration)
|
|
110
|
+
throw new LocalControlError('BINDING_CONFLICT', 'Workstation changed; check it again');
|
|
111
|
+
if (current.runtime.state === 'unknown')
|
|
112
|
+
throw new LocalControlError('OUTCOME_UNKNOWN', 'Stop and verify the existing daemon before updating');
|
|
113
|
+
if (current.runtime.state === 'running' && current.runtime.binding?.server !== server)
|
|
114
|
+
throw new LocalControlError('INSTANCE_OCCUPIED', 'Another server owns the running daemon');
|
|
115
|
+
const status = current.runtime.state === 'running'
|
|
116
|
+
? await requestRuntimeUpdate(directory, manifest, request.operationId)
|
|
117
|
+
: await createUpdateCoordinator({ dir: directory, server, cliPath: CLI_PATH, serviceLifecycle: 'none', installationLockHeld: true }).handle({ commandId: request.operationId, release: manifest, force: false });
|
|
118
|
+
return { status: ['BUSY', 'UPDATE_IN_PROGRESS'].includes(status.phase) ? 'busy' : status.phase === 'SUCCEEDED' ? 'succeeded' : status.phase === 'FAILED' || status.phase === 'ROLLED_BACK' ? 'failed' : 'pending', inspection: await inspectWorkstation(directory) };
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
return enrollmentFailure(error, directory);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
81
125
|
export function registerUpdateCommand(program) {
|
|
82
126
|
const serverOption = () => program.opts().server;
|
|
83
127
|
program
|
|
84
128
|
.command('update')
|
|
85
129
|
.description('Update axom-cli to the release the configured server currently publishes')
|
|
130
|
+
.option('--json', 'Emit local management protocol JSON')
|
|
131
|
+
.option('--input-stdin', 'Read the guarded update request from stdin')
|
|
86
132
|
.option('--version <version>', 'Fail unless the server-published release matches this exact version')
|
|
87
|
-
.action((options) => runCommand(() =>
|
|
133
|
+
.action((options) => runCommand(async () => {
|
|
134
|
+
if (!options.json)
|
|
135
|
+
return updateAction({ server: serverOption(), version: options.version });
|
|
136
|
+
if (!options.inputStdin)
|
|
137
|
+
throw new UsageError('--json requires --input-stdin');
|
|
138
|
+
let request;
|
|
139
|
+
let result;
|
|
140
|
+
try {
|
|
141
|
+
request = await readLocalRequest(process.stdin);
|
|
142
|
+
result = await updateLocalCli(request, clientDir());
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
result = await enrollmentFailure(error, clientDir());
|
|
146
|
+
}
|
|
147
|
+
const id = updateRequestSchema.safeParse(request);
|
|
148
|
+
process.stdout.write(JSON.stringify({ schemaVersion: 1, kind: 'result', operationId: id.success ? id.data.operationId : randomUUID(), result }) + '\n');
|
|
149
|
+
}));
|
|
88
150
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { assertIdentityCanStart, recoverStoppedIdentity } from '../workstation/control/daemonIdentity.js';
|
|
2
|
+
import { withWorkstationLock } from '../workstation/control/locks.js';
|
|
3
|
+
import { inspectWorkstation } from '../workstation/control/inspect.js';
|
|
4
|
+
import { runLocalJsonCommand } from '../workstation/control/commands.js';
|
|
1
5
|
import { hostname } from 'node:os';
|
|
2
6
|
import { basename } from 'node:path';
|
|
3
7
|
import { loadConfig, resolveServer, UsageError } from '../config.js';
|
|
@@ -6,6 +10,8 @@ import { ensureFreshToken } from '../mcp.js';
|
|
|
6
10
|
import { runCommand } from '../output.js';
|
|
7
11
|
import { clientDir, loadClientConfig } from '../workstation/config.js';
|
|
8
12
|
import { resolveWorkstationName, sanitizeName } from '../workstation/names.js';
|
|
13
|
+
import { configureRd, rdStatus } from '../workstation/rd/control.js';
|
|
14
|
+
import { runManagedDesktop } from '../workstation/rd/sessions.js';
|
|
9
15
|
/**
|
|
10
16
|
* Registers this workstation with the server if it has no credential yet, then leaves it alone.
|
|
11
17
|
* Returns whether it just registered (`false` when an existing credential meant there was nothing
|
|
@@ -89,6 +95,7 @@ function dropAccessTokenFromEnvironment() {
|
|
|
89
95
|
* top-level argument (see service/launchd.ts and service/systemd.ts).
|
|
90
96
|
*/
|
|
91
97
|
export function registerWorkstationCommands(program, deps) {
|
|
98
|
+
const localJson = deps.localJson ?? runLocalJsonCommand;
|
|
92
99
|
const workstation = program.command('workstation').description('Manage the local Axomwork workstation daemon');
|
|
93
100
|
// Same idiom as `registerUpdateCommand`: the global `--server` is read at action time, not at
|
|
94
101
|
// registration time, so `axom --server <url> workstation start` works. `axom auth` only writes
|
|
@@ -106,12 +113,29 @@ export function registerWorkstationCommands(program, deps) {
|
|
|
106
113
|
// own `options.name` the dead one instead. `start`'s action below reads the whole fallback chain
|
|
107
114
|
// so it doesn't matter which link is live for a given flag.
|
|
108
115
|
const workstationOption = () => workstation.opts();
|
|
116
|
+
const applyRd = deps.configureRd ?? configureRd;
|
|
109
117
|
workstation
|
|
110
118
|
.command('start')
|
|
119
|
+
.option('--json', 'Emit local management protocol JSON')
|
|
120
|
+
.option('--input-stdin', 'Read the guarded request from stdin')
|
|
111
121
|
.option('--server <url>', 'Axomwork server URL to register this workstation against')
|
|
112
122
|
.option('--name <name>', 'Workstation name (default: AXOM_WORKSTATION_NAME, then the hostname)')
|
|
123
|
+
.option('--enable-rd', 'Install and enable Linux remote desktop')
|
|
124
|
+
.option('--disable-rd', 'Disable remote desktop without changing workstation registration')
|
|
125
|
+
.option('--rd-session <mode>', 'Desktop selection: auto, existing, or virtual')
|
|
126
|
+
.option('--rd-display <display>', 'Choose an existing local X11 display, such as :10')
|
|
113
127
|
.description('Start the workstation user service')
|
|
114
128
|
.action((options) => runCommand(async () => {
|
|
129
|
+
const rd = { ...workstationOption(), ...options, server: options.server ?? workstationOption().server ?? serverOption() };
|
|
130
|
+
if (options.json && (rd.enableRd || rd.disableRd || rd.rdSession || rd.rdDisplay))
|
|
131
|
+
throw new UsageError('RD flags cannot be combined with the JSON management protocol');
|
|
132
|
+
if (options.json) {
|
|
133
|
+
if (!options.inputStdin)
|
|
134
|
+
throw new UsageError('--json requires --input-stdin');
|
|
135
|
+
await localJson('start');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
await applyRd(clientDir(), rd);
|
|
115
139
|
// `install()` runs only when this call just registered the workstation, not on every
|
|
116
140
|
// `start` — it's not the free idempotent no-op it looks like. On macOS it's bootout, write
|
|
117
141
|
// plist, bootstrap, and the `deps.start()` right after it is `kickstart -k`: on an
|
|
@@ -122,40 +146,82 @@ export function registerWorkstationCommands(program, deps) {
|
|
|
122
146
|
// by a removed nvm version only if that's a *good* node; run from an ad-hoc one and it
|
|
123
147
|
// manufactures the exact stranding it's meant to cure. That repair belongs to the explicit
|
|
124
148
|
// verb that already exists for it, `axom workstation install`, not as a side effect here.
|
|
149
|
+
await withWorkstationLock(clientDir(), 'operation', async () => { await recoverStoppedIdentity(clientDir()); await assertIdentityCanStart(clientDir()); });
|
|
125
150
|
const justRegistered = await ensureRegistered(deps, options.server ?? workstationOption().server ?? serverOption(), options.name ?? workstationOption().name);
|
|
126
|
-
if (justRegistered)
|
|
127
|
-
await deps.install();
|
|
128
|
-
await deps.start();
|
|
151
|
+
await withWorkstationLock(clientDir(), 'operation', async () => { await assertIdentityCanStart(clientDir()); if (justRegistered)
|
|
152
|
+
await deps.install(); await deps.start(); });
|
|
129
153
|
}));
|
|
130
154
|
workstation
|
|
131
155
|
.command('stop')
|
|
156
|
+
.option('--json', 'Emit local management protocol JSON')
|
|
157
|
+
.option('--input-stdin', 'Read the guarded request from stdin')
|
|
132
158
|
.description('Stop the workstation user service')
|
|
133
|
-
.action(() => runCommand(async () => {
|
|
159
|
+
.action((options) => runCommand(async () => { if (options.json) {
|
|
160
|
+
if (!options.inputStdin)
|
|
161
|
+
throw new UsageError('--json requires --input-stdin');
|
|
162
|
+
await localJson('stop');
|
|
163
|
+
}
|
|
164
|
+
else
|
|
165
|
+
await withWorkstationLock(clientDir(), 'operation', () => deps.stop()); }));
|
|
134
166
|
workstation
|
|
135
167
|
.command('restart')
|
|
168
|
+
.option('--json', 'Emit local management protocol JSON')
|
|
169
|
+
.option('--input-stdin', 'Read the guarded request from stdin')
|
|
136
170
|
.description('Restart the workstation user service')
|
|
137
|
-
.action(() => runCommand(async () => {
|
|
171
|
+
.action((options) => runCommand(async () => { if (options.json) {
|
|
172
|
+
if (!options.inputStdin)
|
|
173
|
+
throw new UsageError('--json requires --input-stdin');
|
|
174
|
+
await localJson('restart');
|
|
175
|
+
}
|
|
176
|
+
else
|
|
177
|
+
await withWorkstationLock(clientDir(), 'operation', async () => { await recoverStoppedIdentity(clientDir()); await assertIdentityCanStart(clientDir()); await deps.restart(); }); }));
|
|
138
178
|
workstation
|
|
139
179
|
.command('status')
|
|
140
180
|
.description('Report whether the workstation daemon is running')
|
|
141
181
|
.action(() => runCommand(async () => { deps.log(await deps.status()); }));
|
|
142
182
|
workstation
|
|
143
183
|
.command('install')
|
|
184
|
+
.option('--json', 'Emit local management protocol JSON')
|
|
185
|
+
.option('--input-stdin', 'Read the guarded request from stdin')
|
|
144
186
|
.description('Install and enable the operating-system service')
|
|
145
|
-
.action(() => runCommand(async () => {
|
|
187
|
+
.action((options) => runCommand(async () => { if (options.json) {
|
|
188
|
+
if (!options.inputStdin)
|
|
189
|
+
throw new UsageError('--json requires --input-stdin');
|
|
190
|
+
await localJson('install');
|
|
191
|
+
}
|
|
192
|
+
else
|
|
193
|
+
await withWorkstationLock(clientDir(), 'operation', async () => { await recoverStoppedIdentity(clientDir()); await assertIdentityCanStart(clientDir()); await deps.install(); }); }));
|
|
146
194
|
workstation
|
|
147
195
|
.command('uninstall')
|
|
148
196
|
.description('Disable and remove the operating-system service')
|
|
149
|
-
.action(() => runCommand(async () => { await deps.uninstall(); }));
|
|
197
|
+
.action(() => runCommand(async () => { await withWorkstationLock(clientDir(), 'operation', () => deps.uninstall()); }));
|
|
198
|
+
workstation.command('inspect').requiredOption('--json', 'Emit local management protocol JSON')
|
|
199
|
+
.action(() => runCommand(async () => { process.stdout.write(JSON.stringify(await inspectWorkstation(clientDir())) + '\n'); }));
|
|
200
|
+
workstation.command('set-enabled').description('Persistently enable or disable this workstation service')
|
|
201
|
+
.requiredOption('--json').requiredOption('--input-stdin').action(() => localJson('set-enabled'));
|
|
202
|
+
for (const verb of ['register', 'forget', 'begin-remove', 'adopt-owner', 'recover']) {
|
|
203
|
+
workstation.command(verb, { hidden: verb === 'forget' }).requiredOption('--json', 'Emit local management protocol JSON')
|
|
204
|
+
.requiredOption('--input-stdin', 'Read the guarded request from stdin').action(() => localJson(verb));
|
|
205
|
+
}
|
|
206
|
+
const rd = workstation.command('rd').description('Manage Linux remote desktop independently of the workstation service');
|
|
207
|
+
rd.command('status').action(() => runCommand(async () => { deps.log(JSON.stringify(await rdStatus(clientDir()), null, 2)); }));
|
|
208
|
+
rd.command('disable').action(() => runCommand(async () => { await applyRd(clientDir(), { disableRd: true }); }));
|
|
150
209
|
workstation
|
|
151
210
|
.option('--server <url>', 'Axomwork server URL to register against (default: AXOM_SERVER, then the stored default)')
|
|
152
211
|
.option('--name <name>', 'Workstation name (default: AXOM_WORKSTATION_NAME, then the hostname)')
|
|
212
|
+
.option('--enable-rd', 'Install and enable Linux remote desktop')
|
|
213
|
+
.option('--disable-rd', 'Disable remote desktop without changing workstation registration')
|
|
214
|
+
.option('--rd-session <mode>', 'Desktop selection: auto, existing, or virtual')
|
|
215
|
+
.option('--rd-display <display>', 'Choose an existing local X11 display, such as :10')
|
|
153
216
|
.description('Run the workstation daemon in the foreground (Docker ENTRYPOINT / debugging); subcommands manage the OS service')
|
|
154
217
|
.action((options) => runCommand(async () => {
|
|
218
|
+
await applyRd(clientDir(), { ...options, server: options.server ?? serverOption() });
|
|
155
219
|
await ensureRegistered(deps, options.server ?? serverOption(), options.name);
|
|
156
220
|
dropAccessTokenFromEnvironment();
|
|
157
221
|
await deps.runDaemon({ supervision: deps.detectSupervision() });
|
|
158
222
|
}));
|
|
223
|
+
program.command('__rd-desktop', { hidden: true }).requiredOption('--directory <path>')
|
|
224
|
+
.action((options) => runCommand(async () => { dropAccessTokenFromEnvironment(); await runManagedDesktop(options.directory); }));
|
|
159
225
|
program.command('__daemon', { hidden: true }).action(() => runCommand(async () => {
|
|
160
226
|
// The literal exec target launchd/systemd start: the one call site allowed to opt into
|
|
161
227
|
// OS-service treatment. See RunDaemonOptions in daemon.ts for why this must be an explicit
|
|
@@ -12,7 +12,7 @@ Workflow:
|
|
|
12
12
|
2. \`axom__app_struct__list_models\` / \`axom__app_struct__get_model\` for a model's attributes, operations, and display metadata.
|
|
13
13
|
3. Prefer read-only struct tools here; do not mutate anything from this command.
|
|
14
14
|
|
|
15
|
-
For the underlying concepts (applications, models, attributes, references),
|
|
15
|
+
For the underlying concepts (applications, models, attributes, references), see knowledge page \`concepts/data-model/index.md\` (\`axom__knowledge__get\`).
|
|
16
16
|
`,
|
|
17
17
|
record: `---
|
|
18
18
|
description: Query, create, update, upsert, or delete Axomwork records
|
|
@@ -24,11 +24,11 @@ $ARGUMENTS
|
|
|
24
24
|
|
|
25
25
|
Workflow:
|
|
26
26
|
1. Discover structure first when unsure: \`axom__app_struct__get_model\` for attribute names and types.
|
|
27
|
-
2. Query with \`axom__record_query__query_records\` (filters/sorts/page criteria — for criteria syntax,
|
|
27
|
+
2. Query with \`axom__record_query__query_records\` (filters/sorts/page criteria — for criteria syntax, see knowledge page \`agent-integration/mcp/record-query-criteria.md\`).
|
|
28
28
|
3. Mutate with \`axom__record_write__create_record\` / \`axom__record_write__update_record\` / \`axom__record_write__upsert_record\` / \`axom__record_write__delete_record\`. Read the record first before updating; confirm with the user before deleting.
|
|
29
29
|
4. \`axom__record_write__upsert_record\` needs \`identityField\` and the identity value inside \`record\`.
|
|
30
30
|
|
|
31
|
-
For safe mutation patterns,
|
|
31
|
+
For safe mutation patterns, see knowledge page \`agent-integration/operating-patterns/safe-record-mutations.md\`.
|
|
32
32
|
`,
|
|
33
33
|
execute: `---
|
|
34
34
|
description: Execute Axomwork operations and services, following async runs to completion
|
|
@@ -44,7 +44,7 @@ Workflow:
|
|
|
44
44
|
3. Interpret the ExecuteResult payload: \`status\` (success/failure/running), \`message\`, \`text\`, \`returnValue\`, \`runId\`/\`runType\`, \`errors[]\` ({target,code,message}).
|
|
45
45
|
4. When \`status\` is \`running\`, follow \`runId\` (see \`runType\`) until a terminal state before reporting the outcome.
|
|
46
46
|
|
|
47
|
-
For sync-vs-job semantics
|
|
47
|
+
For sync-vs-job semantics see knowledge page \`concepts/execution/synchronous-and-task-execution.md\`; for run following see knowledge page \`agent-integration/operating-patterns/following-runs.md\`.
|
|
48
48
|
`,
|
|
49
49
|
definition: `---
|
|
50
50
|
description: Develop Axomwork definitions — apps, models, attributes, operations, workflows (requires app_studio scope and an admin account)
|
|
@@ -56,8 +56,8 @@ $ARGUMENTS
|
|
|
56
56
|
|
|
57
57
|
Rules:
|
|
58
58
|
1. ETag workflow: read the resource first, send its \`etag\` back as \`expectedEtag\` (bodies use \`expectedBodyEtag\`). On conflict, re-read and merge intentionally.
|
|
59
|
-
2. Before authoring \`.axom.kts\` script bodies,
|
|
60
|
-
3. For definition semantics (apps, models, attributes, operations, workflows),
|
|
59
|
+
2. Before authoring \`.axom.kts\` script bodies, see knowledge page \`script-language/sdk/index.md\`; workflow DSL: \`script-language/workflows/index.md\`; sync/job/streaming patterns: \`script-language/patterns/index.md\`.
|
|
60
|
+
3. For definition semantics (apps, models, attributes, operations, workflows), see knowledge page \`application-development/index.md\`.
|
|
61
61
|
4. Confirm destructive definition deletes with the user first.
|
|
62
62
|
`,
|
|
63
63
|
platform: `---
|
|
@@ -70,20 +70,20 @@ $ARGUMENTS
|
|
|
70
70
|
|
|
71
71
|
Rules:
|
|
72
72
|
1. Read current configuration before editing; respect ETag guards where tools expose them.
|
|
73
|
-
2. For configuration semantics (AI providers and profiles, cowork agents, datasources, platform skills and settings),
|
|
73
|
+
2. For configuration semantics (AI providers and profiles, cowork agents, datasources, platform skills and settings), see knowledge page \`platform-operations/index.md\` first.
|
|
74
74
|
3. Confirm with the user before changes that can interrupt running workflows or agent sessions.
|
|
75
75
|
`,
|
|
76
|
-
|
|
77
|
-
description: Look something up in the Axomwork
|
|
76
|
+
knowledge: `---
|
|
77
|
+
description: Look something up in the Axomwork manual
|
|
78
78
|
---
|
|
79
79
|
|
|
80
|
-
Answer using the Axomwork
|
|
80
|
+
Answer using the Axomwork manual:
|
|
81
81
|
|
|
82
82
|
$ARGUMENTS
|
|
83
83
|
|
|
84
84
|
Workflow:
|
|
85
|
-
1. \`
|
|
86
|
-
2. \`
|
|
87
|
-
3. Answer from
|
|
85
|
+
1. \`axom__knowledge__search\` with keywords or the question itself; read the ranked snippets.
|
|
86
|
+
2. \`axom__knowledge__get\` a hit's \`path\` for the full page (omit \`path\` for the table of contents).
|
|
87
|
+
3. Answer from the manual and cite the knowledge page paths you used. If the manual has no answer, say so and fall back to tool discovery (\`tools/list\`).
|
|
88
88
|
`,
|
|
89
89
|
};
|
package/dist/mcp.js
CHANGED
|
@@ -98,7 +98,7 @@ export function isInsufficientScope(error) {
|
|
|
98
98
|
return /\b403\b/.test(message);
|
|
99
99
|
}
|
|
100
100
|
/** Abilities every credential has (Ability registry: BASELINE with the MCP surface). */
|
|
101
|
-
const BASELINE_TOOL_SCOPES = new Set(['system', '
|
|
101
|
+
const BASELINE_TOOL_SCOPES = new Set(['system', 'knowledge', 'app_struct']);
|
|
102
102
|
const TOOL_SCOPE = /^axom__([a-z][a-z0-9]*(?:_[a-z0-9]+)*)__[a-z]/;
|
|
103
103
|
const ADMIN_NOTE = ' Scopes marked "Requires an administrator account" on the consent page also need an administrator user.';
|
|
104
104
|
/** An external tool's middle segment IS the OAuth scope that grants it (spec 2026-09-26 §3.5). */
|
|
Binary file
|