@platless/axom-cli 0.3.13 → 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 +119 -9
- 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 +123 -0
- package/dist/axom-patch/cli/account-limits/kimi-proxy.mjs +81 -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/codex-terminal-output.json +16 -0
- package/dist/axom-patch/cli/commandcode-account-limits.json +30 -0
- 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 +194 -0
- package/dist/axom-patch/cli/pi-subagent-subwork.json +23 -0
- package/dist/axom-patch/cli/probes/claude-late-async-terminal.mjs +5 -1
- 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/probes/pi-subagent-subwork.mjs +211 -0
- package/dist/axom-patch/cli/probes/zcode-subagent-subwork.mjs +257 -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 -5
- package/dist/axom-patch/cli/qoder-foreground-output.md +14 -7
- 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 +39 -15
- package/dist/axom-patch/cli/zcode-account-limits.json +30 -0
- package/dist/axom-patch/cli/zcode-models.json +37 -0
- package/dist/axom-patch/cli/zcode-subagent-subwork.json +72 -0
- package/dist/cli.js +4 -9
- 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/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 +1 -1
- package/dist/native/darwin-arm64/axom-quic +0 -0
- package/dist/test/keeperKit.js +67 -0
- package/dist/workstation/acp/acpAgents.js +2192 -636
- package/dist/workstation/acp/acpClient.js +84 -495
- package/dist/workstation/acp/adoption.js +10 -396
- 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 +324 -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/envSecrets.js +27 -0
- package/dist/workstation/acp/initializeResponse.js +290 -0
- package/dist/workstation/acp/installErrors.js +12 -2
- package/dist/workstation/acp/installProbe.js +1 -1
- package/dist/workstation/acp/managedPatches.js +239 -159
- package/dist/workstation/acp/managedRuntime.js +314 -0
- package/dist/workstation/acp/outbox.js +330 -0
- package/dist/workstation/acp/patchAssets.js +60 -3
- package/dist/workstation/acp/permission.js +42 -10
- package/dist/workstation/acp/processor/checkpoint.js +78 -0
- package/dist/workstation/acp/processor/commands.js +35 -0
- package/dist/workstation/acp/processor/control.js +282 -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 +105 -0
- package/dist/workstation/acp/processor/sdkSchemas.js +61 -0
- package/dist/workstation/acp/processor/session.js +496 -0
- package/dist/workstation/acp/processor/state.js +67 -0
- package/dist/workstation/acp/processor/step.js +442 -0
- package/dist/workstation/acp/processor/test/fixtureLog.js +58 -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 +390 -0
- package/dist/workstation/acp/processorSession.js +1348 -0
- package/dist/workstation/acp/registry/catalog.js +189 -41
- package/dist/workstation/acp/registry/launch.js +76 -119
- package/dist/workstation/acp/sessionUpdateMapper.js +18 -7
- package/dist/workstation/acp/steering.js +58 -0
- package/dist/workstation/acp/switching.js +111 -0
- package/dist/workstation/acp/terminalLogin.js +16 -42
- 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 +13 -0
- package/dist/workstation/acp/test/keeperWorld.js +295 -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/sanitize.js +344 -0
- package/dist/workstation/acp/test/raw/sources.js +135 -0
- package/dist/workstation/acp/test/realAdapter.js +331 -0
- package/dist/workstation/acp/test/scriptAgent.js +214 -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/agentFlow.js +103 -0
- package/dist/workstation/agentSessions.js +1289 -544
- package/dist/workstation/channels/agent.js +7 -5
- package/dist/workstation/channels/computer.js +69 -21
- package/dist/workstation/channels/computerExecs.js +200 -0
- package/dist/workstation/channels/management.js +172 -8
- 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 +393 -12
- package/dist/workstation/daemonctl.js +103 -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/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/credentials.js +142 -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/{fileOps.js → files/text.js} +152 -39
- 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 +124 -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 +289 -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 +76 -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/managedInstall.js +57 -0
- package/dist/workstation/protocol/accountLimits.js +47 -0
- package/dist/workstation/protocol/agent.js +50 -19
- package/dist/workstation/protocol/common.js +30 -0
- package/dist/workstation/protocol/computer.js +15 -4
- package/dist/workstation/protocol/management.js +141 -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 +154 -93
- package/dist/workstation/toolchain.js +94 -0
- package/dist/workstation/tools/browser.js +28 -4
- package/dist/workstation/tools/client.js +9 -1
- package/dist/workstation/tools/info.js +50 -0
- package/dist/workstation/tools/keeperProcess.js +15 -5
- package/dist/workstation/tools/router.js +55 -0
- package/dist/workstation/tools/terminalRouter.js +222 -0
- package/dist/workstation/tools/validation.js +37 -1
- package/dist/workstation/update/artifact.js +2 -1
- package/dist/workstation/update/coordinator.js +3 -0
- package/dist/workstation/update/globalInstall.js +116 -0
- package/dist/workstation/update/npmInstaller.js +49 -23
- package/dist/workstation/update/ptyPreflight.js +21 -0
- package/dist/workstation/update/rdRollback.js +145 -0
- package/dist/workstation/update/runUpdate.js +3 -2
- package/dist/workstation/update/taskRegistry.js +105 -11
- package/dist/workstation/update/watchdog.js +16790 -334
- package/package.json +11 -8
- 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 -49
- 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/workstation/acp/acpSession.js +0 -1475
- package/dist/workstation/acp/contract.js +0 -499
- package/dist/workstation/acp/delegationMcp.js +0 -24
- package/dist/workstation/acp/draftInterceptor.js +0 -163
- package/dist/workstation/acp/qoderStartup.js +0 -45
- package/dist/workstation/acp/sessionScope.js +0 -19
- package/dist/workstation/filePaths.js +0 -174
- package/dist/workstation/fileWorker.js +0 -81
- package/dist/workstation/fileWorkerClient.js +0 -121
- package/dist/workstation/qoderAdapter/backgroundProcess.js +0 -106
- package/dist/workstation/qoderAdapter/backgroundTerminal.js +0 -262
- package/dist/workstation/qoderAdapter/completedContinuation.js +0 -139
- package/dist/workstation/qoderAdapter/contract.js +0 -78
- package/dist/workstation/qoderAdapter/foregroundOutput.js +0 -30
- package/dist/workstation/qoderAdapter/history.js +0 -87
- package/dist/workstation/qoderAdapter/identityIndex.js +0 -191
- package/dist/workstation/qoderAdapter/inputQueue.js +0 -42
- package/dist/workstation/qoderAdapter/main.js +0 -93
- 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 -49
- package/dist/workstation/qoderAdapter/session.js +0 -319
- package/dist/workstation/qoderAdapter/subagentMeta.js +0 -28
- package/dist/workstation/qoderAdapter/subwork.js +0 -77
- package/dist/workstation/qoderAdapter/taskControl.js +0 -38
- package/dist/workstation/qoderAdapter/taskEvent.js +0 -26
- package/dist/workstation/qoderAdapter/taskLedger.js +0 -163
- package/dist/workstation/qoderAdapter/usage.js +0 -37
- package/dist/workstation/tools/core.js +0 -50
- package/dist/workstation/tools/files.js +0 -525
- package/dist/workstation/tools/terminal.js +0 -214
- /package/dist/workstation/{qoderAdapter/types.js → desktopControl/provider.js} +0 -0
|
@@ -1,46 +1,36 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { clientDir
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { clientDir } from './config.js';
|
|
3
3
|
import { osInfo } from './osinfo.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
os: osInfo(),
|
|
11
|
-
defaultWorkspace: { name: ws.name, cwd: ws.cwd, shell: ws.shell },
|
|
12
|
-
};
|
|
4
|
+
import { workstationEndpoint } from './control/serverIdentity.js';
|
|
5
|
+
import { LocalControlError } from './control/protocol.js';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
export const registerResponseSchema = z.object({ workstationId: z.string().min(1), ownerUserId: z.string().min(1).optional(), clientKey: z.string(), serverPub: z.string() });
|
|
8
|
+
/** No persistence; callers own the operation lock and identity transaction. */
|
|
9
|
+
export async function requestWorkstationRegistration(server, clientName, token, ws, workstationId, shell = ws?.shell ?? '/bin/sh') {
|
|
13
10
|
let res;
|
|
14
11
|
try {
|
|
15
|
-
res = await fetch(
|
|
16
|
-
method: 'POST',
|
|
12
|
+
res = await fetch(workstationEndpoint(server, '/workstation/register'), { method: 'POST', redirect: 'error', signal: AbortSignal.timeout(30_000),
|
|
17
13
|
headers: { 'content-type': 'application/json', authorization: `Bearer ${token}` },
|
|
18
|
-
body: JSON.stringify(
|
|
14
|
+
body: JSON.stringify({ name: clientName, ...(workstationId ? { workstationId } : {}), os: osInfo(), shell, ...(ws ? { defaultWorkspace: ws } : {}) }),
|
|
19
15
|
});
|
|
20
16
|
}
|
|
21
|
-
catch
|
|
22
|
-
throw new
|
|
17
|
+
catch {
|
|
18
|
+
throw new LocalControlError('OUTCOME_UNKNOWN', 'Registration was sent but its outcome could not be confirmed. Check your workstation list before trying again.');
|
|
19
|
+
}
|
|
20
|
+
if (res.status === 409)
|
|
21
|
+
throw new LocalControlError('BINDING_CONFLICT', 'A workstation with this name is already registered. Check Settings → Workstations.');
|
|
22
|
+
if (res.status === 401 || res.status === 403)
|
|
23
|
+
throw new LocalControlError('AUTHORIZATION_REQUIRED', 'Workstation permission is required. Run `axom auth` and select workstation, then try again.');
|
|
24
|
+
if (!res.ok)
|
|
25
|
+
throw new LocalControlError('OUTCOME_UNKNOWN', 'Registration could not be confirmed. Check your workstation list.');
|
|
26
|
+
try {
|
|
27
|
+
return registerResponseSchema.parse(await res.json());
|
|
23
28
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// this same machine registered before an axom-cli upgrade and no longer has a local config at
|
|
27
|
-
// the new config-directory path (see the client's move from ~/.axom-workstation to
|
|
28
|
-
// ~/.axom/workstation). Rebinding the existing row silently would hand this machine's identity
|
|
29
|
-
// to whichever caller re-registers next, so the server refuses instead of upserting.
|
|
30
|
-
if (res.status === 409) {
|
|
31
|
-
throw new UsageError(`A workstation named '${clientName}' is already registered for this account. This is expected `
|
|
32
|
-
+ `when the same machine re-registers after an axom-cli upgrade. Delete it under Settings → `
|
|
33
|
-
+ 'Workstations, then run `axom workstation start` again.');
|
|
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
|
-
}
|
|
39
|
-
throw new Error(`Registration failed: ${res.status} ${await res.text()}`);
|
|
29
|
+
catch {
|
|
30
|
+
throw new LocalControlError('OUTCOME_UNKNOWN', 'Registration response was incomplete. Check your workstation list.');
|
|
40
31
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
await
|
|
45
|
-
await writeKeys(dir, data.clientKey, data.serverPub);
|
|
32
|
+
}
|
|
33
|
+
export async function registerWorkstation(server, clientName, token, ws) {
|
|
34
|
+
const { enrollLegacyWorkstation } = await import('./control/enrollment.js');
|
|
35
|
+
await enrollLegacyWorkstation({ server, name: clientName, accessToken: token, workspace: ws, operationId: randomUUID() }, clientDir());
|
|
46
36
|
}
|
|
@@ -58,6 +58,22 @@ async function assertWritable(directory) {
|
|
|
58
58
|
}
|
|
59
59
|
const defaultDeps = {
|
|
60
60
|
run: runProcess,
|
|
61
|
+
readLaunchAgent: async (file) => {
|
|
62
|
+
const handle = await fs.open(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
63
|
+
try {
|
|
64
|
+
const stat = await handle.stat();
|
|
65
|
+
if (!stat.isFile() || stat.size > 65536)
|
|
66
|
+
throw new Error('Invalid LaunchAgent');
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
await handle.close();
|
|
70
|
+
}
|
|
71
|
+
const result = await runProcess('/usr/bin/plutil', ['-convert', 'json', '-o', '-', file]);
|
|
72
|
+
const value = JSON.parse(result.stdout);
|
|
73
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
74
|
+
throw new Error('Invalid LaunchAgent');
|
|
75
|
+
return value;
|
|
76
|
+
},
|
|
61
77
|
writeTemp,
|
|
62
78
|
assertWritable,
|
|
63
79
|
ensureDirectory: async (directory) => { await fs.mkdir(directory, { recursive: true }); },
|
|
@@ -219,24 +235,38 @@ export function createServiceManager(context, overrides = {}) {
|
|
|
219
235
|
// durable LaunchAgent plist. This keeps explicit stop meaningful across both service managers.
|
|
220
236
|
if (action === 'stop')
|
|
221
237
|
return deps.run('launchctl', ['bootout', launchdDomain]);
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
238
|
+
return launchdStart();
|
|
239
|
+
};
|
|
240
|
+
const enabled = async (plistDisabled = false) => {
|
|
241
|
+
if (context.platform === 'darwin') {
|
|
242
|
+
const result = await deps.run('launchctl', ['print-disabled', `gui/${context.userId}`]);
|
|
243
|
+
if (!result.stdout.includes('{') || !result.stdout.includes('}'))
|
|
244
|
+
throw new Error('Cannot determine launchd enablement');
|
|
245
|
+
const line = result.stdout.split('\n').find(line => line.includes(`"${SERVICE_LABEL}"`));
|
|
246
|
+
if (line) {
|
|
247
|
+
const override = /=>\s*(true|false|enabled|disabled)\b/.exec(line);
|
|
248
|
+
if (!override)
|
|
249
|
+
throw new Error('Cannot determine launchd enablement');
|
|
250
|
+
return override[1] === 'true' || override[1] === 'disabled' ? false : true;
|
|
231
251
|
}
|
|
232
|
-
return
|
|
252
|
+
return !plistDisabled;
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
return (await deps.run('systemctl', ['--user', 'is-enabled', `${SERVICE_LABEL}.service`])).stdout.trim() === 'enabled';
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
if (/disabled|not-found/.test(String(error)))
|
|
259
|
+
return false;
|
|
260
|
+
throw error;
|
|
233
261
|
}
|
|
234
|
-
return launchdStart();
|
|
235
262
|
};
|
|
236
263
|
// Extracted so `start()` can reuse it: reinstalling is the same work whether triggered
|
|
237
264
|
// explicitly (`axom workstation install`) or as `start()`'s self-heal for a missing definition
|
|
238
265
|
// file. Both platform branches leave the service running, so callers need no separate start.
|
|
239
266
|
const performInstall = async (_options = {}) => {
|
|
267
|
+
const present = await deps.pathExists(target);
|
|
268
|
+
const plistDisabled = context.platform === 'darwin' && present && (await deps.readLaunchAgent(target)).Disabled === true;
|
|
269
|
+
const preserveDisabled = (context.platform === 'darwin' || present) && !await enabled(plistDisabled);
|
|
240
270
|
await deps.assertWritable(context.npmPrefix);
|
|
241
271
|
await deps.ensureDirectory(path.dirname(target));
|
|
242
272
|
const temp = await deps.writeTemp(contents);
|
|
@@ -246,7 +276,8 @@ export function createServiceManager(context, overrides = {}) {
|
|
|
246
276
|
await deps.run('mv', [targetTemp, target]);
|
|
247
277
|
if (context.platform === 'linux') {
|
|
248
278
|
await deps.run('systemctl', ['--user', 'daemon-reload']);
|
|
249
|
-
|
|
279
|
+
if (!preserveDisabled)
|
|
280
|
+
await deps.run('systemctl', ['--user', 'enable', '--now', `${SERVICE_LABEL}.service`]);
|
|
250
281
|
}
|
|
251
282
|
else {
|
|
252
283
|
// Reload an existing service before bootstrapping the replacement into the GUI domain.
|
|
@@ -255,7 +286,8 @@ export function createServiceManager(context, overrides = {}) {
|
|
|
255
286
|
// bounded probe/bootstrap path so Bootstrap failed: 5 is confirmed then kickstarted, and
|
|
256
287
|
// so a launchd that never releases the job is reported instead of leaving the machine
|
|
257
288
|
// with the bootout applied and nothing bootstrapped in its place.
|
|
258
|
-
|
|
289
|
+
if (!preserveDisabled)
|
|
290
|
+
await launchdStart();
|
|
259
291
|
}
|
|
260
292
|
}
|
|
261
293
|
finally {
|
|
@@ -303,6 +335,11 @@ export function createServiceManager(context, overrides = {}) {
|
|
|
303
335
|
*/
|
|
304
336
|
async start() {
|
|
305
337
|
await withGuiSessionHint(async () => {
|
|
338
|
+
// An explicit Start is consent to re-enable; install/update alone preserves OFF.
|
|
339
|
+
if (context.platform === 'darwin')
|
|
340
|
+
await deps.run('launchctl', ['enable', launchdDomain]);
|
|
341
|
+
else
|
|
342
|
+
await deps.run('systemctl', ['--user', 'enable', `${SERVICE_LABEL}.service`]);
|
|
306
343
|
if (!(await deps.pathExists(target)))
|
|
307
344
|
await performInstall({});
|
|
308
345
|
await lifecycle('start');
|
|
@@ -310,6 +347,60 @@ export function createServiceManager(context, overrides = {}) {
|
|
|
310
347
|
},
|
|
311
348
|
async stop() { await withGuiSessionHint(() => lifecycle('stop')); },
|
|
312
349
|
async restart() { await withGuiSessionHint(() => lifecycle('restart')); },
|
|
350
|
+
async setEnabled(value) {
|
|
351
|
+
await withGuiSessionHint(async () => {
|
|
352
|
+
if (context.platform === 'darwin') {
|
|
353
|
+
await deps.run('launchctl', [value ? 'enable' : 'disable', launchdDomain]);
|
|
354
|
+
if (value) {
|
|
355
|
+
if (!await deps.pathExists(target))
|
|
356
|
+
await performInstall({});
|
|
357
|
+
await launchdStart();
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
try {
|
|
361
|
+
await lifecycle('stop');
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
if (!launchdAbsent(error))
|
|
365
|
+
throw error;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
else
|
|
370
|
+
await deps.run('systemctl', ['--user', value ? 'enable' : 'disable', '--now', `${SERVICE_LABEL}.service`]);
|
|
371
|
+
});
|
|
372
|
+
},
|
|
373
|
+
async enablement() {
|
|
374
|
+
const installed = await deps.pathExists(target);
|
|
375
|
+
if (!installed)
|
|
376
|
+
return { installed: false, enabled: false, loaded: false, running: false };
|
|
377
|
+
let value;
|
|
378
|
+
try {
|
|
379
|
+
let disabled = false;
|
|
380
|
+
if (context.platform === 'darwin') {
|
|
381
|
+
const plist = await deps.readLaunchAgent(target);
|
|
382
|
+
const args = plist.ProgramArguments;
|
|
383
|
+
const environment = plist.EnvironmentVariables;
|
|
384
|
+
if (plist.Label !== SERVICE_LABEL || !Array.isArray(args) || args.length !== 3 || args[0] !== context.nodePath || args[1] !== context.cliPath || args[2] !== '__daemon' || environment?.AXOM_WORKSTATION_CONFIG_DIR !== context.configDir) {
|
|
385
|
+
return { installed, enabled: null, loaded: false, running: false, reason: 'service_identity_mismatch' };
|
|
386
|
+
}
|
|
387
|
+
disabled = plist.Disabled === true;
|
|
388
|
+
}
|
|
389
|
+
value = await enabled(disabled);
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
return { installed, enabled: null, loaded: false, running: false, reason: 'service_state_unknown' };
|
|
393
|
+
}
|
|
394
|
+
try {
|
|
395
|
+
const result = await lifecycle('status');
|
|
396
|
+
return { installed, enabled: value, loaded: true, running: context.platform === 'darwin' ? launchdIsRunning(result.stdout) : true };
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
if (launchdAbsent(error) || /inactive|not loaded|not-found/.test(String(error)))
|
|
400
|
+
return { installed, enabled: value, loaded: false, running: false };
|
|
401
|
+
return { installed, enabled: value, loaded: false, running: false, reason: 'runtime_state_unknown' };
|
|
402
|
+
}
|
|
403
|
+
},
|
|
313
404
|
async status() {
|
|
314
405
|
try {
|
|
315
406
|
const result = await lifecycle('status');
|
|
@@ -31,6 +31,7 @@ ${keyValue('AXOM_WORKSTATION_CONFIG_DIR', context.configDir)}
|
|
|
31
31
|
${keyValue('AXOM_WORKSTATION_NPM_PATH', context.npmPath)}
|
|
32
32
|
${keyValue('AXOM_WORKSTATION_NPM_PREFIX', context.npmPrefix)}
|
|
33
33
|
${keyValue('PATH', context.pathEnv)}
|
|
34
|
+
${context.npmConfigPrefix ? keyValue('NPM_CONFIG_PREFIX', context.npmConfigPrefix) : ''}
|
|
34
35
|
\t</dict>
|
|
35
36
|
\t<key>StandardOutPath</key>
|
|
36
37
|
\t<string>${xml(`${context.configDir}/daemon.log`)}</string>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { statSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { promisify } from 'node:util';
|
|
5
|
+
const execFileAsync = promisify(execFile);
|
|
6
|
+
const LOCAL_FILESYSTEMS = new Set([
|
|
7
|
+
'ext2', 'ext3', 'ext4', 'xfs', 'btrfs', 'zfs', 'f2fs', 'bcachefs',
|
|
8
|
+
'vfat', 'exfat', 'ntfs', 'ntfs3', 'fuseblk',
|
|
9
|
+
]);
|
|
10
|
+
export function linuxStoragePools(mounts) {
|
|
11
|
+
const pools = new Map();
|
|
12
|
+
for (const mount of mounts) {
|
|
13
|
+
if (!LOCAL_FILESYSTEMS.has(mount.fstype) || mount.options?.split(',').includes('ro'))
|
|
14
|
+
continue;
|
|
15
|
+
if (/^\/(?:boot|efi)(?:\/|$)/.test(mount.target))
|
|
16
|
+
continue;
|
|
17
|
+
const source = mount.source.split('[')[0];
|
|
18
|
+
const key = mount.fstype === 'zfs'
|
|
19
|
+
? `zfs:${source.split('/')[0]}`
|
|
20
|
+
: mount.uuid ? `${mount.fstype}:${mount.uuid}` : `dev:${mount['maj:min']}`;
|
|
21
|
+
const existing = pools.get(key);
|
|
22
|
+
if (existing)
|
|
23
|
+
existing.paths.push(mount.target);
|
|
24
|
+
else
|
|
25
|
+
pools.set(key, { key, label: mount.label || source, paths: [mount.target] });
|
|
26
|
+
}
|
|
27
|
+
if (pools.size === 0) {
|
|
28
|
+
const root = mounts.find((mount) => mount.target === '/' && mount.fstype === 'overlay');
|
|
29
|
+
if (root)
|
|
30
|
+
pools.set('overlay:/', { key: 'overlay:/', label: 'Container storage', paths: ['/'] });
|
|
31
|
+
}
|
|
32
|
+
return [...pools.values()];
|
|
33
|
+
}
|
|
34
|
+
export function darwinStoragePools(disks, physicalDisks, containers) {
|
|
35
|
+
const physical = new Set(physicalDisks.flatMap((disk) => [disk.DeviceIdentifier, ...(disk.Partitions ?? []).map((part) => part.DeviceIdentifier)]));
|
|
36
|
+
const volumes = disks.flatMap((disk) => [disk, ...(disk.Partitions ?? []), ...(disk.APFSVolumes ?? [])]);
|
|
37
|
+
const pools = [];
|
|
38
|
+
for (const container of containers) {
|
|
39
|
+
if (!container.PhysicalStores.some((store) => physical.has(store.DeviceIdentifier)))
|
|
40
|
+
continue;
|
|
41
|
+
const userVolumes = container.Volumes.filter((volume) => volume.Roles.length === 0 || volume.Roles.includes('Data'));
|
|
42
|
+
userVolumes.sort((first, second) => Number(second.Roles.includes('Data')) - Number(first.Roles.includes('Data')));
|
|
43
|
+
const mounted = userVolumes.flatMap((volume) => {
|
|
44
|
+
const disk = volumes.find((candidate) => candidate.DeviceIdentifier === volume.DeviceIdentifier);
|
|
45
|
+
return disk?.MountPoint ? [{ name: volume.Name, mount: disk.MountPoint }] : [];
|
|
46
|
+
});
|
|
47
|
+
if (mounted.length === 0)
|
|
48
|
+
continue;
|
|
49
|
+
const system = container.Volumes.find((volume) => volume.Roles.includes('System'));
|
|
50
|
+
pools.push({
|
|
51
|
+
key: `apfs:${container.APFSContainerUUID}`,
|
|
52
|
+
label: system?.Name || mounted[0].name,
|
|
53
|
+
paths: mounted.map((volume) => volume.mount),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
for (const volume of volumes) {
|
|
57
|
+
if (!physical.has(volume.DeviceIdentifier) || !volume.MountPoint)
|
|
58
|
+
continue;
|
|
59
|
+
if (!['Apple_HFS', 'Microsoft Basic Data', 'Windows_NTFS', 'DOS_FAT_32', 'DOS_FAT_16', 'ExFAT'].includes(volume.Content ?? ''))
|
|
60
|
+
continue;
|
|
61
|
+
pools.push({
|
|
62
|
+
key: `volume:${volume.VolumeUUID || volume.DiskUUID || volume.DeviceIdentifier}`,
|
|
63
|
+
label: volume.VolumeName || volume.MountPoint,
|
|
64
|
+
paths: [volume.MountPoint],
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return pools;
|
|
68
|
+
}
|
|
69
|
+
async function diskutilJson(args) {
|
|
70
|
+
const { stdout } = await execFileAsync('/usr/sbin/diskutil', args, {
|
|
71
|
+
timeout: 5_000, maxBuffer: 4 * 1024 * 1024,
|
|
72
|
+
});
|
|
73
|
+
const json = await new Promise((resolve, reject) => {
|
|
74
|
+
const child = execFile('/usr/bin/plutil', ['-convert', 'json', '-o', '-', '-'], {
|
|
75
|
+
timeout: 2_000, maxBuffer: 4 * 1024 * 1024,
|
|
76
|
+
}, (error, output) => error ? reject(error) : resolve(output));
|
|
77
|
+
child.stdin?.on('error', reject);
|
|
78
|
+
child.stdin?.end(stdout);
|
|
79
|
+
});
|
|
80
|
+
return JSON.parse(json);
|
|
81
|
+
}
|
|
82
|
+
export async function discoverStoragePools(platform, workspaces) {
|
|
83
|
+
if (platform === 'linux') {
|
|
84
|
+
const { stdout } = await execFileAsync('findmnt', [
|
|
85
|
+
'--json', '--list', '--output', 'TARGET,SOURCE,FSTYPE,UUID,LABEL,MAJ:MIN,OPTIONS',
|
|
86
|
+
], { timeout: 5_000, maxBuffer: 4 * 1024 * 1024, env: { ...process.env, LC_ALL: 'C' } });
|
|
87
|
+
const mounts = JSON.parse(stdout).filesystems;
|
|
88
|
+
return linuxStoragePools(mounts.filter((mount) => {
|
|
89
|
+
try {
|
|
90
|
+
return statSync(mount.target).isDirectory();
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
if (platform === 'darwin') {
|
|
98
|
+
const [all, physical, apfs] = await Promise.all([
|
|
99
|
+
diskutilJson(['list', '-plist']),
|
|
100
|
+
diskutilJson(['list', '-plist', 'physical']),
|
|
101
|
+
diskutilJson(['apfs', 'list', '-plist']),
|
|
102
|
+
]);
|
|
103
|
+
return darwinStoragePools(all.AllDisksAndPartitions, physical.AllDisksAndPartitions, apfs.Containers ?? []);
|
|
104
|
+
}
|
|
105
|
+
const pools = new Map();
|
|
106
|
+
for (const { cwd } of workspaces) {
|
|
107
|
+
try {
|
|
108
|
+
const key = `dev:${statSync(cwd).dev}`;
|
|
109
|
+
const existing = pools.get(key);
|
|
110
|
+
if (existing)
|
|
111
|
+
existing.paths.push(cwd);
|
|
112
|
+
else
|
|
113
|
+
pools.set(key, { key, label: path.parse(cwd).root, paths: [cwd] });
|
|
114
|
+
}
|
|
115
|
+
catch { }
|
|
116
|
+
}
|
|
117
|
+
return [...pools.values()];
|
|
118
|
+
}
|