@platless/axom-cli 0.1.0 → 0.5.9
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 +132 -0
- package/dist/axom-patch/cli/account-limits/README.md +27 -0
- package/dist/axom-patch/cli/account-limits/antigravity-proxy.mjs +47 -0
- package/dist/axom-patch/cli/account-limits/antigravity-read.mjs +90 -0
- package/dist/axom-patch/cli/account-limits/antigravity.mjs +46 -0
- package/dist/axom-patch/cli/account-limits/generate.py +120 -0
- package/dist/axom-patch/cli/account-limits/kimi-proxy.mjs +64 -0
- package/dist/axom-patch/cli/account-limits/normalize.mjs +151 -0
- package/dist/axom-patch/cli/claude-account-limits.json +37 -0
- package/dist/axom-patch/cli/codex-account-limits.json +37 -0
- package/dist/axom-patch/cli/commandcode-account-limits.json +30 -0
- package/dist/axom-patch/cli/nightly-task.md +152 -0
- package/dist/axom-patch/cli/pi-steering.json +37 -0
- package/dist/axom-patch/cli/pi-subagent-subwork.json +23 -0
- package/dist/axom-patch/cli/probes/claude-late-async-terminal.mjs +38 -0
- package/dist/axom-patch/cli/probes/pi-steering.mjs +80 -0
- package/dist/axom-patch/cli/probes/pi-subagent-subwork.mjs +211 -0
- package/dist/axom-patch/cli/probes/qoder-steering.mjs +89 -0
- package/dist/axom-patch/cli/probes/qoder-subagent-origin.mjs +61 -0
- package/dist/axom-patch/cli/probes/zcode-subagent-subwork.mjs +257 -0
- package/dist/axom-patch/cli/qoder-background-terminal.md +82 -0
- package/dist/axom-patch/cli/qoder-foreground-output.md +42 -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 +63 -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/axom-patch/cli/zcode-account-limits.json +31 -0
- package/dist/axom-patch/cli/zcode-models.json +38 -0
- package/dist/axom-patch/cli/zcode-subagent-subwork.json +73 -0
- package/dist/cli.js +36 -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/keepers/acp/keeper.mjs +3083 -0
- package/dist/keepers/acp/manifest.json +9 -0
- package/dist/keepers/terminal/keeper.mjs +8469 -0
- package/dist/keepers/terminal/manifest.json +9 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/conpty_console_list_agent.js +25 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/eventEmitter2.js +47 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/index.js +52 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/interfaces.js +7 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/shared/conout.js +10 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/terminal.js +190 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/types.js +7 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/unixTerminal.js +351 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/utils.js +38 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsConoutConnection.js +131 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsPtyAgent.js +344 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsTerminal.js +209 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/dist/keepers/terminal/node_modules/node-pty/package.json +66 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-x64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/linux-arm64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/linux-x64/pty.node +0 -0
- package/dist/mcp.js +32 -14
- package/dist/runtime-deps/qoder-sdk/package-lock.json +1189 -0
- package/dist/runtime-deps/qoder-sdk/package.json +8 -0
- package/dist/test/keeperKit.js +67 -0
- package/dist/workstation/acp/acpAgents.js +2514 -681
- package/dist/workstation/acp/acpClient.js +95 -318
- package/dist/workstation/acp/activityBusy.js +43 -0
- package/dist/workstation/acp/activityReporting.js +54 -0
- package/dist/workstation/acp/adoption.js +28 -356
- package/dist/workstation/acp/authUrlSniffer.js +36 -0
- package/dist/workstation/acp/binaryInstall.js +100 -27
- package/dist/workstation/acp/builds/gc.js +245 -0
- package/dist/workstation/acp/builds/install/binary.js +28 -0
- package/dist/workstation/acp/builds/install/npm.js +235 -0
- package/dist/workstation/acp/builds/install/uv.js +254 -0
- package/dist/workstation/acp/builds/migrate.js +195 -0
- package/dist/workstation/acp/builds/model.js +128 -0
- package/dist/workstation/acp/builds/nodeGate.js +100 -0
- package/dist/workstation/acp/builds/store.js +352 -0
- package/dist/workstation/acp/commandTableProbe.js +68 -0
- package/dist/workstation/acp/configOptions.js +103 -1
- package/dist/workstation/acp/delegationMcp.js +24 -0
- package/dist/workstation/acp/envSecrets.js +27 -0
- package/dist/workstation/acp/initializeResponse.js +285 -0
- package/dist/workstation/acp/installErrors.js +12 -2
- package/dist/workstation/acp/installProbe.js +1 -1
- package/dist/workstation/acp/managedPatches.js +144 -0
- package/dist/workstation/acp/outbox.js +330 -0
- package/dist/workstation/acp/patchAssets.js +80 -0
- package/dist/workstation/acp/permission.js +335 -37
- package/dist/workstation/acp/processor/checkpoint.js +87 -0
- package/dist/workstation/acp/processor/commands.js +35 -0
- package/dist/workstation/acp/processor/control.js +355 -0
- package/dist/workstation/acp/processor/emit.js +26 -0
- package/dist/workstation/acp/processor/jsonrpc.js +172 -0
- package/dist/workstation/acp/processor/memoryLog.js +49 -0
- package/dist/workstation/acp/processor/origins.js +48 -0
- package/dist/workstation/acp/processor/output.js +67 -0
- package/dist/workstation/acp/processor/projection.js +42 -0
- package/dist/workstation/acp/processor/record.js +128 -0
- package/dist/workstation/acp/processor/runtime.js +181 -0
- package/dist/workstation/acp/processor/sdkSchemas.js +61 -0
- package/dist/workstation/acp/processor/session.js +525 -0
- package/dist/workstation/acp/processor/sideChannel.js +80 -0
- package/dist/workstation/acp/processor/state.js +74 -0
- package/dist/workstation/acp/processor/step.js +459 -0
- package/dist/workstation/acp/processor/test/fixtureLog.js +65 -0
- package/dist/workstation/acp/processor/test/harness.js +120 -0
- package/dist/workstation/acp/processor/test/largeIdEcho.js +50 -0
- package/dist/workstation/acp/processor/test/rawAgent.js +70 -0
- package/dist/workstation/acp/processor/transport/generations.js +76 -0
- package/dist/workstation/acp/processor/transport/keeper.js +130 -0
- package/dist/workstation/acp/processor/transport/local.js +269 -0
- package/dist/workstation/acp/processor/transport/types.js +78 -0
- package/dist/workstation/acp/processor/updates.js +364 -0
- package/dist/workstation/acp/processorSession.js +1512 -0
- package/dist/workstation/acp/qoderStartup.js +45 -0
- package/dist/workstation/acp/registry/catalog.js +385 -4
- package/dist/workstation/acp/registry/detect.js +55 -0
- package/dist/workstation/acp/registry/launch.js +61 -119
- package/dist/workstation/acp/sessionUpdateMapper.js +56 -27
- package/dist/workstation/acp/steering.js +58 -0
- package/dist/workstation/acp/switching.js +114 -0
- package/dist/workstation/acp/terminalLogin.js +171 -0
- package/dist/workstation/acp/terminalLoginSpec.js +41 -0
- package/dist/workstation/acp/test/adapterFixtures.js +256 -0
- package/dist/workstation/acp/test/daemonLife.js +106 -0
- package/dist/workstation/acp/test/fakeAgent.js +185 -9
- package/dist/workstation/acp/test/keeperWorld.js +267 -0
- package/dist/workstation/acp/test/memoryOutbox.js +55 -0
- package/dist/workstation/acp/test/raw/fixtures.js +196 -0
- package/dist/workstation/acp/test/raw/qoderCaptures.js +125 -0
- package/dist/workstation/acp/test/raw/sanitize.js +344 -0
- package/dist/workstation/acp/test/raw/sources.js +249 -0
- package/dist/workstation/acp/test/realAdapter.js +377 -0
- package/dist/workstation/acp/test/scriptAgent.js +206 -0
- package/dist/workstation/acp/test/sessionFrames.js +42 -0
- package/dist/workstation/acp/timedCommand.js +4 -2
- package/dist/workstation/acp/uvxInstall.js +72 -122
- package/dist/workstation/acp/validate.js +33 -5
- package/dist/workstation/agentFlow.js +103 -0
- package/dist/workstation/agentSessions.js +1686 -348
- package/dist/workstation/channels/agent.js +14 -6
- package/dist/workstation/channels/computer.js +203 -7
- package/dist/workstation/channels/computerExecs.js +200 -0
- package/dist/workstation/channels/management.js +86 -6
- package/dist/workstation/config.js +3 -1
- package/dist/workstation/connection/encryptedChannel.js +88 -21
- package/dist/workstation/daemon.js +309 -6
- package/dist/workstation/daemonctl.js +28 -2
- 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/exec/attach.js +126 -0
- package/dist/workstation/exec/command.js +40 -0
- package/dist/workstation/exec/durable.js +517 -0
- package/dist/workstation/exec/fallback.js +106 -0
- package/dist/workstation/exec/policy.js +837 -0
- package/dist/workstation/exec/shaping.js +211 -0
- package/dist/workstation/exec.js +3 -112
- package/dist/workstation/files/adapters/computerFileFrames.js +51 -0
- package/dist/workstation/files/adapters/toolRequests.js +121 -0
- package/dist/workstation/files/client.js +455 -0
- package/dist/workstation/files/errors.js +28 -0
- package/dist/workstation/files/fence.js +350 -0
- package/dist/workstation/files/find/fileIndex.js +153 -0
- package/dist/workstation/files/find/fuzzy.js +155 -0
- package/dist/workstation/files/host.js +122 -0
- package/dist/workstation/files/hostProtocol.js +2 -0
- package/dist/workstation/files/media/cache.js +620 -0
- package/dist/workstation/files/media/encoding.js +308 -0
- package/dist/workstation/files/media/estimator.js +100 -0
- package/dist/workstation/files/media/media.js +325 -0
- package/dist/workstation/files/media/packedAudio.js +23 -0
- package/dist/workstation/files/media/scheduler.js +551 -0
- package/dist/workstation/files/media/types.js +5 -0
- package/dist/workstation/files/scope.js +45 -0
- package/dist/workstation/files/structured.js +284 -0
- package/dist/workstation/files/text.js +356 -0
- package/dist/workstation/files/uploads.js +351 -0
- package/dist/workstation/journal.js +65 -236
- package/dist/workstation/keepers/acp/client.js +101 -0
- package/dist/workstation/keepers/acp/envelope.js +62 -0
- package/dist/workstation/keepers/acp/host.js +419 -0
- package/dist/workstation/keepers/acp/main.js +18 -0
- package/dist/workstation/keepers/acp/memoryStream.js +121 -0
- package/dist/workstation/keepers/acp/params.js +137 -0
- package/dist/workstation/keepers/acp/protocol.js +66 -0
- package/dist/workstation/keepers/acp/recover.js +120 -0
- package/dist/workstation/keepers/acp/session.js +584 -0
- package/dist/workstation/keepers/acp/stderr.js +154 -0
- package/dist/workstation/keepers/kit/activity.js +103 -0
- package/dist/workstation/keepers/kit/bootstrap.js +164 -0
- package/dist/workstation/keepers/kit/buildVersion.js +51 -0
- package/dist/workstation/keepers/kit/bundle.js +120 -0
- package/dist/workstation/keepers/kit/client.js +432 -0
- package/dist/workstation/keepers/kit/identity.js +21 -0
- package/dist/workstation/keepers/kit/ipc.js +112 -0
- package/dist/workstation/keepers/kit/launchConfig.js +8 -0
- package/dist/workstation/keepers/kit/launcher.js +249 -0
- package/dist/workstation/keepers/kit/lock.js +123 -0
- package/dist/workstation/keepers/kit/orphanSweep.js +86 -0
- package/dist/workstation/keepers/kit/paths.js +75 -0
- package/dist/workstation/keepers/kit/protocol.js +43 -0
- package/dist/workstation/keepers/kit/server.js +518 -0
- package/dist/workstation/keepers/kit/streamLog.js +697 -0
- package/dist/workstation/keepers/legacy.js +296 -0
- package/dist/workstation/keepers/policy.js +576 -0
- package/dist/workstation/keepers/stop.js +34 -0
- package/dist/workstation/keepers/terminal/client.js +213 -0
- package/dist/workstation/keepers/terminal/exec.js +981 -0
- package/dist/workstation/keepers/terminal/generations.js +129 -0
- package/dist/workstation/keepers/terminal/keeper.js +62 -0
- package/dist/workstation/keepers/terminal/main.js +43 -0
- package/dist/workstation/keepers/terminal/orphanSweep.js +3 -0
- package/dist/workstation/keepers/terminal/params.js +27 -0
- package/dist/workstation/keepers/terminal/protocol.js +56 -0
- package/dist/workstation/keepers/terminal/pty.js +330 -0
- package/dist/workstation/oauth/deviceAuthorization.js +21 -12
- package/dist/workstation/protocol/accountLimits.js +47 -0
- package/dist/workstation/protocol/agent.js +201 -8
- package/dist/workstation/protocol/common.js +36 -0
- package/dist/workstation/protocol/computer.js +107 -7
- package/dist/workstation/protocol/management.js +50 -2
- package/dist/workstation/qoderAdapter/backgroundProcess.js +118 -0
- package/dist/workstation/qoderAdapter/backgroundTerminal.js +193 -0
- package/dist/workstation/qoderAdapter/backgroundTerminalFold.js +372 -0
- package/dist/workstation/qoderAdapter/callbackContext.js +76 -0
- package/dist/workstation/qoderAdapter/completedContinuation.js +139 -0
- package/dist/workstation/qoderAdapter/contract.js +78 -0
- package/dist/workstation/qoderAdapter/foregroundOutput.js +36 -0
- package/dist/workstation/qoderAdapter/history.js +85 -0
- package/dist/workstation/qoderAdapter/identityIndex.js +191 -0
- package/dist/workstation/qoderAdapter/inputQueue.js +42 -0
- package/dist/workstation/qoderAdapter/main.js +95 -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 +48 -0
- package/dist/workstation/qoderAdapter/sdkRuntime.js +93 -0
- package/dist/workstation/qoderAdapter/sdkRuntimeInstall.js +145 -0
- package/dist/workstation/qoderAdapter/session.js +319 -0
- package/dist/workstation/qoderAdapter/subagentMeta.js +28 -0
- package/dist/workstation/qoderAdapter/subwork.js +85 -0
- package/dist/workstation/qoderAdapter/taskControl.js +38 -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/systemMetrics.js +110 -1
- package/dist/workstation/tools/browser.js +394 -0
- package/dist/workstation/tools/client.js +277 -0
- package/dist/workstation/tools/info.js +50 -0
- package/dist/workstation/tools/keeperProcess.js +124 -0
- package/dist/workstation/tools/router.js +55 -0
- package/dist/workstation/tools/terminalRouter.js +222 -0
- package/dist/workstation/tools/validation.js +86 -0
- package/dist/workstation/update/coordinator.js +32 -0
- package/dist/workstation/update/npmInstaller.js +2 -0
- package/dist/workstation/update/ptyPreflight.js +45 -0
- package/dist/workstation/update/taskRegistry.js +141 -23
- package/dist/workstation/update/watchdog.js +66 -0
- package/package.json +20 -7
- package/skills/axom/SKILL.md +55 -17
- package/skills/axom-definition/SKILL.md +32 -32
- package/skills/axom-platform/SKILL.md +39 -39
- package/dist/workstation/acp/acpSession.js +0 -1047
- package/dist/workstation/acp/contract.js +0 -494
- package/dist/workstation/acp/draftInterceptor.js +0 -154
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const object = (v) => v && typeof v === 'object' && !Array.isArray(v) ? v : {};
|
|
2
|
+
const id = (v) => typeof v === 'string' && v.length > 0 && v.length <= 256 && !/[\x00-\x1f\x7f]/.test(v);
|
|
3
|
+
export function newSubworkData() {
|
|
4
|
+
return { calls: {}, count: 0 };
|
|
5
|
+
}
|
|
6
|
+
export function supportsSubworkMeta(info) {
|
|
7
|
+
return (info?.name === 'qoder-cli' && info.version === '1.1.61') ||
|
|
8
|
+
(info?.name === 'axom-qoder-sdk' && info.version === '1.0.50');
|
|
9
|
+
}
|
|
10
|
+
function resultText(value) {
|
|
11
|
+
if (typeof value === 'string')
|
|
12
|
+
return value;
|
|
13
|
+
if (Array.isArray(value)) {
|
|
14
|
+
const texts = value.filter(v => object(v).type === 'text').map(v => object(v).text).filter(v => typeof v === 'string');
|
|
15
|
+
return texts.length ? texts.join('\n') : undefined;
|
|
16
|
+
}
|
|
17
|
+
const v = object(value);
|
|
18
|
+
if (v.kind === 'agent-result')
|
|
19
|
+
return resultText(v.content ?? v.result);
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
export class SubworkBoundary {
|
|
23
|
+
root;
|
|
24
|
+
data;
|
|
25
|
+
constructor(root, data = newSubworkData()) {
|
|
26
|
+
this.root = root;
|
|
27
|
+
this.data = data;
|
|
28
|
+
}
|
|
29
|
+
get(toolId) { return Object.hasOwn(this.data.calls, toolId) ? this.data.calls[toolId] : undefined; }
|
|
30
|
+
child(toolId) { return `qoder-agent:${this.root}:${toolId}`; }
|
|
31
|
+
map(event) {
|
|
32
|
+
if (event.acpSessionId && event.acpSessionId !== this.root)
|
|
33
|
+
return [event];
|
|
34
|
+
const p = event.payload, q = object(object(p._meta).qoder), input = object(p.rawInput);
|
|
35
|
+
const marked = q.version === 1 && ['native-acp-patch', 'sdk', 'correction'].includes(String(q.source));
|
|
36
|
+
const toolId = p.toolCallId;
|
|
37
|
+
let call = id(toolId) ? this.get(toolId) : undefined;
|
|
38
|
+
const parent = marked && q.route !== 'unknown' && id(q.parentToolUseId) ? q.parentToolUseId : undefined;
|
|
39
|
+
const events = [];
|
|
40
|
+
if (!call && marked && p.kind === 'think' && q.toolName === 'Agent' && id(toolId) &&
|
|
41
|
+
typeof input.prompt === 'string' && (input.subagent_type == null || typeof input.subagent_type === 'string') &&
|
|
42
|
+
(input.run_in_background === undefined || typeof input.run_in_background === 'boolean') &&
|
|
43
|
+
['tool_call', 'tool_call_update'].includes(event.eventName) && this.data.count < 4096) {
|
|
44
|
+
call = { child: this.child(toolId), ...(parent ? { parent: this.child(parent) } : {}),
|
|
45
|
+
background: input.run_in_background === true, ended: false, streamedText: '' };
|
|
46
|
+
Object.defineProperty(this.data.calls, toolId, { value: call, enumerable: true, writable: true, configurable: true });
|
|
47
|
+
this.data.count += 1;
|
|
48
|
+
events.push({ eventName: 'subagent_spawned', payload: { subagentSessionId: call.child,
|
|
49
|
+
name: typeof input.description === 'string' && input.description.trim() ? input.description : input.subagent_type ?? 'Agent',
|
|
50
|
+
task: input.prompt, capabilities: {} }, ...(call.parent ? { acpSessionId: call.parent } : {}) });
|
|
51
|
+
events.push({ eventName: 'user_message_chunk', payload: { content: { type: 'text', text: input.prompt } }, acpSessionId: call.child });
|
|
52
|
+
}
|
|
53
|
+
if (call && ['tool_call', 'tool_call_update'].includes(event.eventName)) {
|
|
54
|
+
if (call.ended)
|
|
55
|
+
return events;
|
|
56
|
+
const output = object(p.rawOutput);
|
|
57
|
+
const state = output.kind === 'agent-result' ? output.state : undefined;
|
|
58
|
+
const terminal = state === 'completed' ? 'completed' : ['error', 'failed'].includes(String(state)) ? 'failed' :
|
|
59
|
+
state === 'cancelled' ? 'cancelled' : ['failed', 'cancelled'].includes(String(p.status)) ? p.status :
|
|
60
|
+
!call.background && p.status === 'completed' ? 'completed' : undefined;
|
|
61
|
+
if (terminal) {
|
|
62
|
+
const text = resultText(p.rawOutput);
|
|
63
|
+
if (text !== undefined && !call.streamedText.endsWith(text))
|
|
64
|
+
events.push({ eventName: 'agent_message_chunk',
|
|
65
|
+
payload: { content: { type: 'text', text } }, acpSessionId: call.child });
|
|
66
|
+
events.push({ eventName: 'subagent_state_update', payload: { subagentSessionId: call.child, state: terminal },
|
|
67
|
+
...(call.parent ? { acpSessionId: call.parent } : {}) });
|
|
68
|
+
call.ended = true;
|
|
69
|
+
// Read only by the check above, once: an ended call keeps no stream (checkpointed state).
|
|
70
|
+
call.streamedText = '';
|
|
71
|
+
}
|
|
72
|
+
// The Agent invocation becomes a dispatch/result in subwork. Keeping the vendor tool here
|
|
73
|
+
// would also create the old delegation card for the very same task.
|
|
74
|
+
return events;
|
|
75
|
+
}
|
|
76
|
+
if (parent) {
|
|
77
|
+
const owner = this.get(parent), content = object(p.content);
|
|
78
|
+
if (owner && !owner.ended && event.eventName === 'agent_message_chunk' && content.type === 'text' && typeof content.text === 'string') {
|
|
79
|
+
owner.streamedText += content.text;
|
|
80
|
+
}
|
|
81
|
+
return [{ ...event, acpSessionId: this.child(parent) }];
|
|
82
|
+
}
|
|
83
|
+
return [event];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { capabilitiesFor } from './profile.js';
|
|
2
|
+
const validId = (value) => value.length > 0 && Buffer.byteLength(value, 'utf8') <= 256 &&
|
|
3
|
+
!/[\x00-\x1f\x7f]/.test(value);
|
|
4
|
+
export class TaskControl {
|
|
5
|
+
ledger;
|
|
6
|
+
profile;
|
|
7
|
+
query;
|
|
8
|
+
certifications;
|
|
9
|
+
binding;
|
|
10
|
+
requests = new Map();
|
|
11
|
+
constructor(ledger, profile, query, certifications, binding) {
|
|
12
|
+
this.ledger = ledger;
|
|
13
|
+
this.profile = profile;
|
|
14
|
+
this.query = query;
|
|
15
|
+
this.certifications = certifications;
|
|
16
|
+
this.binding = binding;
|
|
17
|
+
}
|
|
18
|
+
async stop(request) {
|
|
19
|
+
if (![request.sessionId, request.taskId, request.requestId].every(validId))
|
|
20
|
+
throw new Error('Invalid task stop identity');
|
|
21
|
+
const previous = this.requests.get(request.requestId);
|
|
22
|
+
if (previous) {
|
|
23
|
+
if (previous.sessionId !== request.sessionId || previous.taskId !== request.taskId)
|
|
24
|
+
throw new Error('Task stop request identity conflict');
|
|
25
|
+
return previous.receipt;
|
|
26
|
+
}
|
|
27
|
+
const profile = this.profile(), task = this.ledger.get(request.taskId);
|
|
28
|
+
if (!profile || !task || request.sessionId !== profile.rootSessionId ||
|
|
29
|
+
!task.origin.agentId || !task.origin.launchingToolUseId || task.taskType !== 'local_agent' ||
|
|
30
|
+
task.background !== true || !capabilitiesFor(profile, task, this.certifications, this.binding).stopActiveRun)
|
|
31
|
+
throw new Error('Task stop unavailable');
|
|
32
|
+
if (this.requests.size >= 4096)
|
|
33
|
+
throw new Error('Task stop receipt capacity exceeded');
|
|
34
|
+
const receipt = this.query.stopTask(request.taskId).then(() => ({ requestId: request.requestId, state: 'accepted' }), () => ({ requestId: request.requestId, state: 'unknown' }));
|
|
35
|
+
this.requests.set(request.requestId, { sessionId: request.sessionId, taskId: request.taskId, receipt });
|
|
36
|
+
return receipt;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
const identifier = (value) => typeof value === 'string' && value.length > 0 &&
|
|
2
|
+
Buffer.byteLength(value, 'utf8') <= 256 && !/[\x00-\x1f\x7f]/.test(value);
|
|
3
|
+
const terminal = (state) => state === 'completed' || state === 'failed' || state === 'stopped';
|
|
4
|
+
const defaultMaxTasks = 4096;
|
|
5
|
+
const sameTask = (a, b) => a.state === b.state && a.live === b.live && a.stale === b.stale && a.taskType === b.taskType &&
|
|
6
|
+
a.background === b.background && JSON.stringify(a.origin) === JSON.stringify(b.origin);
|
|
7
|
+
export class TaskLedger {
|
|
8
|
+
rootSessionId;
|
|
9
|
+
runtimeGeneration;
|
|
10
|
+
maxTasks;
|
|
11
|
+
tasks = new Map();
|
|
12
|
+
seen = new Set();
|
|
13
|
+
actors = new Map();
|
|
14
|
+
launchTasks = new Map();
|
|
15
|
+
conflicts = new Set();
|
|
16
|
+
notified = new Set();
|
|
17
|
+
failed = false;
|
|
18
|
+
constructor(rootSessionId, runtimeGeneration, maxTasks = defaultMaxTasks) {
|
|
19
|
+
this.rootSessionId = rootSessionId;
|
|
20
|
+
this.runtimeGeneration = runtimeGeneration;
|
|
21
|
+
this.maxTasks = maxTasks;
|
|
22
|
+
if (!identifier(rootSessionId) || !identifier(runtimeGeneration))
|
|
23
|
+
throw new Error('Invalid task ledger binding');
|
|
24
|
+
if (!Number.isInteger(maxTasks) || maxTasks < 1 || maxTasks > defaultMaxTasks)
|
|
25
|
+
throw new Error('Invalid task ledger capacity');
|
|
26
|
+
}
|
|
27
|
+
get(taskId) {
|
|
28
|
+
const task = this.tasks.get(taskId);
|
|
29
|
+
return task && { ...task, origin: { ...task.origin } };
|
|
30
|
+
}
|
|
31
|
+
all() { return [...this.tasks.keys()].map((id) => this.get(id)); }
|
|
32
|
+
get launchObservationCount() { return this.actors.size; }
|
|
33
|
+
get degraded() { return this.failed; }
|
|
34
|
+
markStale() {
|
|
35
|
+
for (const [id, task] of this.tasks)
|
|
36
|
+
this.tasks.set(id, { ...task, live: false, stale: true });
|
|
37
|
+
return this.all();
|
|
38
|
+
}
|
|
39
|
+
degrade() {
|
|
40
|
+
this.failed = true;
|
|
41
|
+
return this.markStale();
|
|
42
|
+
}
|
|
43
|
+
observeLaunch(toolUseId, agentId) {
|
|
44
|
+
if (this.failed || !identifier(toolUseId) || !identifier(agentId))
|
|
45
|
+
return [];
|
|
46
|
+
const prior = this.actors.get(toolUseId);
|
|
47
|
+
if (prior !== undefined && prior !== agentId)
|
|
48
|
+
this.actors.set(toolUseId, null);
|
|
49
|
+
else if (prior === undefined && this.actors.size < this.maxTasks)
|
|
50
|
+
this.actors.set(toolUseId, agentId);
|
|
51
|
+
const changed = [];
|
|
52
|
+
for (const [id, task] of this.tasks) {
|
|
53
|
+
if (task.origin.launchingToolUseId !== toolUseId)
|
|
54
|
+
continue;
|
|
55
|
+
const actor = this.actors.get(toolUseId);
|
|
56
|
+
const next = { ...task, origin: { ...task.origin,
|
|
57
|
+
agentId: this.conflicts.has(id) ? undefined : actor ?? undefined },
|
|
58
|
+
stale: actor === null || this.conflicts.has(id) || task.stale };
|
|
59
|
+
this.tasks.set(id, next);
|
|
60
|
+
changed.push(next);
|
|
61
|
+
}
|
|
62
|
+
return changed;
|
|
63
|
+
}
|
|
64
|
+
ensure(taskId) {
|
|
65
|
+
if (!identifier(taskId))
|
|
66
|
+
return undefined;
|
|
67
|
+
const existing = this.tasks.get(taskId);
|
|
68
|
+
if (existing)
|
|
69
|
+
return existing;
|
|
70
|
+
if (this.tasks.size >= this.maxTasks) {
|
|
71
|
+
this.degrade();
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
const task = { origin: { rootSessionId: this.rootSessionId, runtimeGeneration: this.runtimeGeneration,
|
|
75
|
+
taskId }, state: 'unknown', live: false, stale: false };
|
|
76
|
+
this.tasks.set(taskId, task);
|
|
77
|
+
return task;
|
|
78
|
+
}
|
|
79
|
+
apply(message) {
|
|
80
|
+
if (this.failed || message.type !== 'system' || message.session_id !== this.rootSessionId ||
|
|
81
|
+
!identifier(message.uuid) || this.seen.has(message.uuid))
|
|
82
|
+
return [];
|
|
83
|
+
if (this.seen.size >= this.maxTasks * 4)
|
|
84
|
+
return this.degrade();
|
|
85
|
+
if (message.subtype === 'background_tasks_changed' && message.tasks.length > this.maxTasks)
|
|
86
|
+
return this.degrade();
|
|
87
|
+
if (message.subtype === 'background_tasks_changed') {
|
|
88
|
+
const added = new Set();
|
|
89
|
+
for (const entry of message.tasks) {
|
|
90
|
+
if (identifier(entry.task_id) && !this.tasks.has(entry.task_id))
|
|
91
|
+
added.add(entry.task_id);
|
|
92
|
+
if (this.tasks.size + added.size > this.maxTasks)
|
|
93
|
+
return this.degrade();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const previous = new Map(this.tasks);
|
|
97
|
+
this.seen.add(message.uuid);
|
|
98
|
+
if (message.subtype === 'background_tasks_changed') {
|
|
99
|
+
const current = new Map(message.tasks.filter((entry) => identifier(entry.task_id))
|
|
100
|
+
.map((entry) => [entry.task_id, entry]));
|
|
101
|
+
for (const [id, task] of this.tasks) {
|
|
102
|
+
if (!terminal(task.state) && task.background) {
|
|
103
|
+
const next = { ...task, live: current.has(id),
|
|
104
|
+
stale: current.has(id) ? this.conflicts.has(id) : task.stale };
|
|
105
|
+
if (!sameTask(task, next))
|
|
106
|
+
this.tasks.set(id, next);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
for (const [id, entry] of current) {
|
|
110
|
+
const task = this.ensure(id);
|
|
111
|
+
if (task && !terminal(task.state)) {
|
|
112
|
+
const next = { ...task, state: 'running', live: true,
|
|
113
|
+
stale: this.conflicts.has(id), taskType: entry.task_type, background: true };
|
|
114
|
+
if (!sameTask(task, next))
|
|
115
|
+
this.tasks.set(id, next);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (message.subtype === 'task_started' || message.subtype === 'task_progress') {
|
|
120
|
+
const task = this.ensure(message.task_id);
|
|
121
|
+
if (task && !terminal(task.state)) {
|
|
122
|
+
const toolId = identifier(message.tool_use_id) ? message.tool_use_id : task.origin.launchingToolUseId;
|
|
123
|
+
if (toolId && !this.launchTasks.has(toolId) && this.launchTasks.size < this.maxTasks)
|
|
124
|
+
this.launchTasks.set(toolId, message.task_id);
|
|
125
|
+
else if (toolId && this.launchTasks.get(toolId) !== message.task_id) {
|
|
126
|
+
this.conflicts.add(message.task_id);
|
|
127
|
+
const other = this.launchTasks.get(toolId);
|
|
128
|
+
if (other) {
|
|
129
|
+
this.conflicts.add(other);
|
|
130
|
+
const previous = this.tasks.get(other);
|
|
131
|
+
if (previous)
|
|
132
|
+
this.tasks.set(other, { ...previous, stale: true,
|
|
133
|
+
origin: { ...previous.origin, agentId: undefined } });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const actor = toolId && this.actors.get(toolId);
|
|
137
|
+
this.tasks.set(message.task_id, { ...task, state: 'running', stale: this.conflicts.has(message.task_id),
|
|
138
|
+
taskType: 'task_type' in message ? message.task_type : task.taskType,
|
|
139
|
+
origin: { ...task.origin, launchingToolUseId: toolId,
|
|
140
|
+
agentId: this.conflicts.has(message.task_id) ? undefined : actor ?? task.origin.agentId } });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else if (message.subtype === 'task_updated') {
|
|
144
|
+
const task = this.ensure(message.task_id);
|
|
145
|
+
if (task && !terminal(task.state)) {
|
|
146
|
+
const status = message.patch.status;
|
|
147
|
+
const state = status === 'killed' ? 'stopped' : status ?? task.state;
|
|
148
|
+
this.tasks.set(message.task_id, { ...task, state, live: terminal(state) ? false : task.live,
|
|
149
|
+
stale: this.conflicts.has(message.task_id), background: message.patch.is_backgrounded ?? task.background });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (message.subtype === 'task_notification') {
|
|
153
|
+
const task = this.ensure(message.task_id);
|
|
154
|
+
if (task && (!this.notified.has(message.task_id) ||
|
|
155
|
+
(task.state === 'stopped' && message.status === 'completed'))) {
|
|
156
|
+
this.notified.add(message.task_id);
|
|
157
|
+
this.tasks.set(message.task_id, { ...task, state: message.status,
|
|
158
|
+
live: false, stale: this.conflicts.has(message.task_id) });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return [...this.tasks].filter(([id, task]) => task !== previous.get(id)).map(([id]) => this.get(id));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const QODER_CREDITS_LABEL = 'Qoder Credits(厂商报告)';
|
|
2
|
+
const validCredits = (value) => typeof value === 'number' &&
|
|
3
|
+
Number.isFinite(value) && value >= 0;
|
|
4
|
+
/** Qoder's report is cumulative. A missing/invalid report never erases a prior valid value. */
|
|
5
|
+
export function applyCredits(previous, reported) {
|
|
6
|
+
if (validCredits(reported))
|
|
7
|
+
return reported;
|
|
8
|
+
return validCredits(previous) ? previous : undefined;
|
|
9
|
+
}
|
|
10
|
+
function reportedCredits(value) {
|
|
11
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
12
|
+
return undefined;
|
|
13
|
+
const input = value;
|
|
14
|
+
for (const key of ['total_credits', 'totalCredits', 'credits'])
|
|
15
|
+
if (validCredits(input[key]))
|
|
16
|
+
return input[key];
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Keeps vendor credits separate from ACP token/USD counters. Qoder's SDK does not
|
|
21
|
+
* provide equivalent token or USD values, so zero placeholders are intentionally omitted.
|
|
22
|
+
*/
|
|
23
|
+
export function normalizeQoderUsage(value, previousCredits) {
|
|
24
|
+
const input = value && typeof value === 'object' && !Array.isArray(value)
|
|
25
|
+
? value : {};
|
|
26
|
+
const scope = input.cumulativeScope === 'unknown' ? 'unknown' : 'session';
|
|
27
|
+
const reported = reportedCredits(value);
|
|
28
|
+
if (scope === 'unknown') {
|
|
29
|
+
return { credits: undefined, creditsLabel: QODER_CREDITS_LABEL, creditsScope: scope,
|
|
30
|
+
inputTokens: undefined, outputTokens: undefined, costUsd: undefined,
|
|
31
|
+
...(validCredits(previousCredits) ? { previousCredits } : {}) };
|
|
32
|
+
}
|
|
33
|
+
const credits = applyCredits(previousCredits, reported);
|
|
34
|
+
return { credits, creditsLabel: QODER_CREDITS_LABEL, creditsScope: scope,
|
|
35
|
+
inputTokens: undefined, outputTokens: undefined, costUsd: undefined,
|
|
36
|
+
...(validCredits(previousCredits) ? { previousCredits } : {}) };
|
|
37
|
+
}
|
|
@@ -32,6 +32,10 @@ export async function registerWorkstation(server, clientName, token, ws) {
|
|
|
32
32
|
+ `when the same machine re-registers after an axom-cli upgrade. Delete it under Settings → `
|
|
33
33
|
+ 'Workstations, then run `axom workstation start` again.');
|
|
34
34
|
}
|
|
35
|
+
if (res.status === 403) {
|
|
36
|
+
throw new UsageError('This credential is not authorized to register a workstation. '
|
|
37
|
+
+ 'Run `axom auth` and select workstation, then try again.');
|
|
38
|
+
}
|
|
35
39
|
throw new Error(`Registration failed: ${res.status} ${await res.text()}`);
|
|
36
40
|
}
|
|
37
41
|
const data = (await res.json());
|
|
@@ -100,6 +100,97 @@ async function defaultDarwinMemoryPressure() {
|
|
|
100
100
|
return null;
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Parses `ioreg -r -d 1 -w 0 -c AGXAccelerator` output. Apple Silicon publishes live GPU
|
|
105
|
+
* utilization (`Device Utilization %`, a driver-side running average) and GPU-resident unified
|
|
106
|
+
* memory (`In use system memory`) in each accelerator's `PerformanceStatistics`, without any
|
|
107
|
+
* privileges. Intel Macs expose no `AGXAccelerator` class, so they parse to null.
|
|
108
|
+
*/
|
|
109
|
+
export function parseAppleAgxStats(output) {
|
|
110
|
+
const gpus = output.split('+-o ').slice(1).map((block, index) => {
|
|
111
|
+
const stats = /"PerformanceStatistics"\s*=\s*\{([^}]*)\}/.exec(block)?.[1];
|
|
112
|
+
if (stats === undefined)
|
|
113
|
+
return null;
|
|
114
|
+
const utilizationPercent = Number(/"Device Utilization %"\s*=\s*(\d+(?:\.\d+)?)/.exec(stats)?.[1]);
|
|
115
|
+
const memoryUsedBytes = Number(/"In use system memory"\s*=\s*(\d+)/.exec(stats)?.[1]);
|
|
116
|
+
return {
|
|
117
|
+
id: `apple:agx-${index}`,
|
|
118
|
+
name: /"model"\s*=\s*"([^"]+)"/.exec(block)?.[1] ?? 'Apple GPU',
|
|
119
|
+
utilization: Number.isFinite(utilizationPercent)
|
|
120
|
+
? Math.max(0, Math.min(1, utilizationPercent / 100))
|
|
121
|
+
: null,
|
|
122
|
+
memoryTotalBytes: null,
|
|
123
|
+
memoryUsedBytes: Number.isFinite(memoryUsedBytes) && memoryUsedBytes >= 0 ? memoryUsedBytes : null,
|
|
124
|
+
coreCount: (() => {
|
|
125
|
+
const cores = Number(/"gpu-core-count"\s*=\s*(\d+)/.exec(block)?.[1]);
|
|
126
|
+
return Number.isFinite(cores) && cores > 0 ? cores : null;
|
|
127
|
+
})(),
|
|
128
|
+
};
|
|
129
|
+
}).filter((gpu) => gpu !== null);
|
|
130
|
+
return gpus.length > 0 ? gpus : null;
|
|
131
|
+
}
|
|
132
|
+
async function appleAgxGpuProbe() {
|
|
133
|
+
try {
|
|
134
|
+
const { stdout } = await execFileAsync('/usr/sbin/ioreg', ['-r', '-d', '1', '-w', '0', '-c', 'AGXAccelerator'], {
|
|
135
|
+
timeout: 2_000,
|
|
136
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
137
|
+
});
|
|
138
|
+
return parseAppleAgxStats(stdout);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** Parses `nvidia-smi --query-gpu=... --format=csv,noheader,nounits` output; `[N/A]` reads as null. */
|
|
145
|
+
export function parseNvidiaSmiGpus(output) {
|
|
146
|
+
const mib = (field) => {
|
|
147
|
+
if (field === undefined)
|
|
148
|
+
return null;
|
|
149
|
+
const value = Number(field);
|
|
150
|
+
return Number.isFinite(value) && value >= 0 ? Math.round(value * 1024 * 1024) : null;
|
|
151
|
+
};
|
|
152
|
+
const gpus = output.split(/\r?\n/).map((line) => {
|
|
153
|
+
const fields = line.split(',').map((field) => field.trim());
|
|
154
|
+
if (fields.length < 6)
|
|
155
|
+
return null;
|
|
156
|
+
const [, uuid, name, utilizationField, totalField, usedField] = fields;
|
|
157
|
+
if (!/^GPU-/.test(uuid) || name.length === 0)
|
|
158
|
+
return null;
|
|
159
|
+
const utilizationPercent = Number(utilizationField);
|
|
160
|
+
return {
|
|
161
|
+
id: `nvidia:${uuid}`,
|
|
162
|
+
name,
|
|
163
|
+
utilization: Number.isFinite(utilizationPercent)
|
|
164
|
+
? Math.max(0, Math.min(1, utilizationPercent / 100))
|
|
165
|
+
: null,
|
|
166
|
+
memoryTotalBytes: mib(totalField),
|
|
167
|
+
memoryUsedBytes: mib(usedField),
|
|
168
|
+
coreCount: null,
|
|
169
|
+
};
|
|
170
|
+
}).filter((gpu) => gpu !== null);
|
|
171
|
+
return gpus.length > 0 ? gpus : null;
|
|
172
|
+
}
|
|
173
|
+
async function nvidiaSmiGpuProbe() {
|
|
174
|
+
try {
|
|
175
|
+
const { stdout } = await execFileAsync('nvidia-smi', [
|
|
176
|
+
'--query-gpu=index,uuid,name,utilization.gpu,memory.total,memory.used',
|
|
177
|
+
'--format=csv,noheader,nounits',
|
|
178
|
+
], { timeout: 3_000 });
|
|
179
|
+
return parseNvidiaSmiGpus(stdout);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Absent binary, driver hiccup, or unsupported GPU -- all read as "no reading", never as failure.
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async function defaultProbeGpus(platform) {
|
|
187
|
+
const [apple, nvidia] = await Promise.all([
|
|
188
|
+
platform === 'darwin' ? appleAgxGpuProbe() : Promise.resolve(null),
|
|
189
|
+
nvidiaSmiGpuProbe(),
|
|
190
|
+
]);
|
|
191
|
+
const gpus = [...(apple ?? []), ...(nvidia ?? [])];
|
|
192
|
+
return gpus.length > 0 ? gpus : null;
|
|
193
|
+
}
|
|
103
194
|
/**
|
|
104
195
|
* Low-overhead host sampler. CPU and memory are read only while a heartbeat is being built; storage
|
|
105
196
|
* topology is discovered out of band and capacity reads use the cached representative paths.
|
|
@@ -114,6 +205,8 @@ export class SystemMetricsSampler {
|
|
|
114
205
|
darwinMemoryRefreshInFlight = null;
|
|
115
206
|
darwinMemoryAvailable = null;
|
|
116
207
|
darwinMemoryPressure = null;
|
|
208
|
+
gpuRefreshInFlight = null;
|
|
209
|
+
gpus = null;
|
|
117
210
|
constructor(workspaces, deps = {
|
|
118
211
|
platform: process.platform,
|
|
119
212
|
cpus: os.cpus,
|
|
@@ -126,12 +219,13 @@ export class SystemMetricsSampler {
|
|
|
126
219
|
identifyStorage: (cwd, device) => defaultIdentifyStorage(process.platform, cwd, device),
|
|
127
220
|
darwinAvailableMemory: defaultDarwinAvailableMemory,
|
|
128
221
|
darwinMemoryPressure: defaultDarwinMemoryPressure,
|
|
222
|
+
probeGpus: () => defaultProbeGpus(process.platform),
|
|
129
223
|
}) {
|
|
130
224
|
this.workspaces = workspaces;
|
|
131
225
|
this.deps = deps;
|
|
132
226
|
}
|
|
133
227
|
async start() {
|
|
134
|
-
await Promise.all([this.refreshTopology(), this.refreshDarwinMemory()]);
|
|
228
|
+
await Promise.all([this.refreshTopology(), this.refreshDarwinMemory(), this.refreshGpus()]);
|
|
135
229
|
this.refreshTimer = setInterval(() => this.refreshTopologyInBackground(), STORAGE_TOPOLOGY_REFRESH_MS);
|
|
136
230
|
this.refreshTimer.unref();
|
|
137
231
|
}
|
|
@@ -143,6 +237,7 @@ export class SystemMetricsSampler {
|
|
|
143
237
|
snapshot() {
|
|
144
238
|
try {
|
|
145
239
|
this.refreshDarwinMemoryInBackground();
|
|
240
|
+
this.refreshGpusInBackground();
|
|
146
241
|
const cpus = this.deps.cpus();
|
|
147
242
|
const currentCpu = cpuTotals(cpus);
|
|
148
243
|
const previousCpu = this.previousCpu;
|
|
@@ -192,6 +287,7 @@ export class SystemMetricsSampler {
|
|
|
192
287
|
memoryTotalBytes,
|
|
193
288
|
memoryAvailableBytes,
|
|
194
289
|
storagePools: [...pools.values()],
|
|
290
|
+
gpus: this.gpus,
|
|
195
291
|
};
|
|
196
292
|
}
|
|
197
293
|
catch {
|
|
@@ -218,6 +314,19 @@ export class SystemMetricsSampler {
|
|
|
218
314
|
this.darwinMemoryRefreshInFlight = null;
|
|
219
315
|
});
|
|
220
316
|
}
|
|
317
|
+
refreshGpusInBackground() {
|
|
318
|
+
if (this.gpuRefreshInFlight)
|
|
319
|
+
return;
|
|
320
|
+
const refresh = this.refreshGpus();
|
|
321
|
+
this.gpuRefreshInFlight = refresh;
|
|
322
|
+
void refresh.finally(() => {
|
|
323
|
+
if (this.gpuRefreshInFlight === refresh)
|
|
324
|
+
this.gpuRefreshInFlight = null;
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
async refreshGpus() {
|
|
328
|
+
this.gpus = await this.deps.probeGpus().catch(() => null);
|
|
329
|
+
}
|
|
221
330
|
async refreshDarwinMemory() {
|
|
222
331
|
if (this.deps.platform !== 'darwin')
|
|
223
332
|
return;
|