@platless/axom-cli 0.5.9 → 0.6.52
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 +25 -6
- package/dist/axom-patch/cli/README.md +129 -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/claude-replay-lifecycle.json +16 -0
- 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/claude-replay-lifecycle.mjs +31 -0
- 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/zcode-env-account.mjs +81 -0
- package/dist/axom-patch/cli/probes/zcode-subagent-subwork.mjs +7 -0
- package/dist/axom-patch/cli/qoder/dist/axom-acp-compat.mjs +1687 -0
- package/dist/axom-patch/cli/qoder/releases/1.1.75.json +277 -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 +19 -19
- package/dist/axom-patch/cli/zcode/env-account.mjs +13 -0
- package/dist/axom-patch/cli/zcode/generate-env-account.py +52 -0
- package/dist/axom-patch/cli/zcode-account-limits.json +10 -11
- package/dist/axom-patch/cli/zcode-env-account.json +58 -0
- package/dist/axom-patch/cli/zcode-models.json +9 -10
- package/dist/axom-patch/cli/zcode-subagent-subwork.json +10 -11
- package/dist/cli.js +11 -45
- package/dist/commands/auth.js +4 -1
- package/dist/commands/knowledge.js +47 -0
- package/dist/commands/update.js +126 -3
- package/dist/commands/workstation.js +101 -164
- package/dist/commands/workstationRegistrations.js +116 -0
- package/dist/credentialBroker.js +13 -2
- package/dist/credentials.js +16 -0
- package/dist/install/claude/commands.js +15 -15
- package/dist/keepers/terminal/keeper.mjs +1089 -673
- package/dist/keepers/terminal/manifest.json +4 -4
- package/dist/mcp.js +1 -1
- package/dist/native/darwin-x64/axom-quic +0 -0
- package/dist/workstation/acp/acpAgents.js +113 -102
- 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/outbox.js +12 -5
- package/dist/workstation/acp/patchAssets.js +40 -0
- package/dist/workstation/acp/permission.js +2 -2
- package/dist/workstation/acp/processor/checkpoint.js +26 -34
- package/dist/workstation/acp/processor/control.js +7 -80
- package/dist/workstation/acp/processor/jsonrpc.js +8 -0
- package/dist/workstation/acp/processor/runtime.js +5 -81
- package/dist/workstation/acp/processor/session.js +54 -82
- package/dist/workstation/acp/processor/state.js +7 -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/transport/local.js +19 -3
- package/dist/workstation/acp/processor/updates.js +156 -105
- package/dist/workstation/acp/processorSession.js +20 -173
- 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 +32 -3
- 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 +114 -166
- package/dist/workstation/channels/agent.js +9 -1
- package/dist/workstation/channels/computer.js +27 -4
- package/dist/workstation/channels/management.js +130 -15
- package/dist/workstation/channels/url.js +1 -1
- package/dist/workstation/config.js +33 -9
- package/dist/workstation/connection/encryptedChannel.js +4 -1
- package/dist/workstation/control/bindingStore.js +204 -0
- package/dist/workstation/control/commands.js +125 -0
- package/dist/workstation/control/daemonIdentity.js +143 -0
- package/dist/workstation/control/deviceCommands.js +191 -0
- package/dist/workstation/control/deviceProtocol.js +68 -0
- package/dist/workstation/control/enrollment.js +106 -0
- package/dist/workstation/control/inspect.js +71 -0
- package/dist/workstation/control/locks.js +110 -0
- package/dist/workstation/control/protocol.js +40 -0
- package/dist/workstation/control/restartGuard.js +46 -0
- package/dist/workstation/control/rootFormat.js +16 -0
- package/dist/workstation/control/runtimeClient.js +152 -0
- package/dist/workstation/control/runtimeHost.js +235 -0
- package/dist/workstation/control/serverIdentity.js +35 -0
- package/dist/workstation/control/updateTransition.js +91 -0
- package/dist/workstation/daemon.js +266 -264
- package/dist/workstation/daemonctl.js +226 -25
- package/dist/workstation/desktopControl/audio.js +99 -0
- package/dist/workstation/desktopControl/automationDevice.js +219 -0
- package/dist/workstation/desktopControl/automationJson.js +74 -0
- package/dist/workstation/desktopControl/automationLocalState.js +23 -0
- package/dist/workstation/desktopControl/automationProtocol.js +253 -0
- package/dist/workstation/desktopControl/automationSchema.generated.js +1 -0
- package/dist/workstation/desktopControl/automationSession.js +81 -0
- package/dist/workstation/desktopControl/automationTransport.js +138 -0
- package/dist/workstation/desktopControl/capabilities.js +93 -0
- package/dist/workstation/desktopControl/captureModes.js +9 -0
- package/dist/workstation/desktopControl/captureTargetLabel.js +9 -0
- package/dist/workstation/desktopControl/deviceAdmission.js +229 -0
- package/dist/workstation/desktopControl/deviceOwnership.js +130 -0
- package/dist/workstation/desktopControl/deviceSockets.js +246 -0
- package/dist/workstation/desktopControl/helperProcess.js +602 -0
- package/dist/workstation/desktopControl/hostGrant.js +65 -0
- package/dist/workstation/desktopControl/lobby.js +131 -0
- package/dist/workstation/desktopControl/macProvider.js +156 -0
- package/dist/workstation/desktopControl/media.js +331 -0
- package/dist/workstation/desktopControl/nativeDeviceAdmission.js +207 -0
- package/dist/workstation/desktopControl/nativeProvider.js +1044 -0
- package/dist/workstation/desktopControl/networkEvidence.js +43 -0
- package/dist/workstation/desktopControl/overview.js +58 -0
- package/dist/workstation/desktopControl/ownershipProtocol.js +31 -0
- package/dist/workstation/desktopControl/protocol.js +311 -0
- package/dist/workstation/desktopControl/provider.js +1 -0
- package/dist/workstation/desktopControl/quicMedia.js +240 -0
- package/dist/workstation/desktopControl/rateController.js +226 -0
- package/dist/workstation/desktopControl/supervisor.js +1774 -0
- package/dist/workstation/desktopControl/transport.js +27 -0
- package/dist/workstation/desktopControl/wallpaper.js +98 -0
- package/dist/workstation/exec/policy.js +5 -0
- package/dist/workstation/files/client.js +10 -1
- package/dist/workstation/files/credentials.js +142 -0
- package/dist/workstation/files/host.js +9 -2
- package/dist/workstation/files/text.js +42 -8
- package/dist/workstation/journal.js +5 -2
- package/dist/workstation/keepers/acp/client.js +38 -2
- package/dist/workstation/keepers/kit/buildVersion.js +35 -11
- package/dist/workstation/keepers/kit/bundle.js +21 -17
- package/dist/workstation/keepers/kit/client.js +2 -2
- package/dist/workstation/keepers/kit/launcher.js +123 -7
- package/dist/workstation/keepers/kit/paths.js +2 -1
- package/dist/workstation/keepers/legacy.js +16 -2
- package/dist/workstation/keepers/policy.js +5 -34
- package/dist/workstation/keepers/terminal/client.js +115 -23
- package/dist/workstation/keepers/terminal/exec.js +6 -3
- package/dist/workstation/keepers/terminal/frames.js +73 -0
- package/dist/workstation/keepers/terminal/generations.js +5 -8
- package/dist/workstation/keepers/terminal/gridProtocol.js +16 -0
- package/dist/workstation/keepers/terminal/input.js +146 -0
- package/dist/workstation/keepers/terminal/keeper.js +22 -8
- package/dist/workstation/keepers/terminal/main.js +1 -1
- package/dist/workstation/keepers/terminal/metadata.js +138 -0
- package/dist/workstation/keepers/terminal/protocol.js +4 -28
- package/dist/workstation/keepers/terminal/pty.js +1 -330
- package/dist/workstation/keepers/terminal/screen.js +246 -0
- package/dist/workstation/keepers/terminal/sessions.js +526 -0
- package/dist/workstation/managedInstall.js +57 -0
- package/dist/workstation/oauth/deviceAuthorization.js +31 -17
- package/dist/workstation/protocol/agent.js +2 -15
- package/dist/workstation/protocol/management.js +113 -5
- package/dist/workstation/protocol/runtimeDiagnostics.js +15 -0
- package/dist/workstation/rd/artifact.js +120 -0
- package/dist/workstation/rd/control.js +117 -0
- package/dist/workstation/rd/display.js +29 -0
- package/dist/workstation/rd/host.js +213 -0
- package/dist/workstation/rd/migrationReadiness.js +46 -0
- package/dist/workstation/rd/provider.js +256 -0
- package/dist/workstation/rd/sessions.js +391 -0
- package/dist/workstation/rd/state.js +57 -0
- package/dist/workstation/rd/update.js +168 -0
- package/dist/workstation/rd/upkeep.js +80 -0
- package/dist/workstation/register.js +27 -37
- package/dist/workstation/registrations/enrollment.js +250 -0
- package/dist/workstation/registrations/enrollmentPending.js +361 -0
- package/dist/workstation/registrations/migration.js +356 -0
- package/dist/workstation/registrations/model.js +34 -0
- package/dist/workstation/registrations/removal.js +222 -0
- package/dist/workstation/registrations/store.js +737 -0
- package/dist/workstation/runtime/desktopBinding.js +20 -0
- package/dist/workstation/runtime/deviceDesktop.js +193 -0
- package/dist/workstation/runtime/deviceRuntime.js +568 -0
- package/dist/workstation/runtime/deviceServices.js +117 -0
- package/dist/workstation/runtime/events.js +20 -0
- package/dist/workstation/runtime/ownership.js +100 -0
- package/dist/workstation/runtime/registrationRuntime.js +575 -0
- package/dist/workstation/runtime/remoteDesktopAdapter.js +186 -0
- package/dist/workstation/runtime/removalActivity.js +184 -0
- package/dist/workstation/service/installer.js +197 -14
- package/dist/workstation/service/launchd.js +2 -0
- package/dist/workstation/service/systemd.js +1 -0
- package/dist/workstation/storageMetrics.js +118 -0
- package/dist/workstation/systemMetrics.js +47 -92
- package/dist/workstation/toolchain.js +94 -0
- package/dist/workstation/tools/browser.js +28 -4
- package/dist/workstation/tools/client.js +8 -27
- package/dist/workstation/tools/info.js +6 -13
- package/dist/workstation/tools/terminalRouter.js +17 -172
- package/dist/workstation/tools/validation.js +55 -1
- package/dist/workstation/update/archiveEvidence.js +206 -0
- package/dist/workstation/update/artifact.js +2 -1
- package/dist/workstation/update/coordinator.js +34 -13
- package/dist/workstation/update/deviceCompatibility.js +119 -0
- package/dist/workstation/update/deviceCoordinator.js +369 -0
- package/dist/workstation/update/deviceHealth.js +104 -0
- package/dist/workstation/update/deviceHealthProtocol.js +26 -0
- package/dist/workstation/update/deviceRecoveryLifecycle.js +46 -0
- package/dist/workstation/update/deviceRollback.js +78 -0
- package/dist/workstation/update/globalInstall.js +186 -0
- package/dist/workstation/update/legacyBridge.js +414 -0
- package/dist/workstation/update/legacyOwner.js +39 -0
- package/dist/workstation/update/npmInstaller.js +51 -25
- package/dist/workstation/update/privateDurability.js +61 -0
- package/dist/workstation/update/rdRollback.js +145 -0
- package/dist/workstation/update/recoveryPlan.js +124 -0
- package/dist/workstation/update/runUpdate.js +10 -3
- package/dist/workstation/update/taskRegistry.js +161 -3
- package/dist/workstation/update/watchdog.js +29806 -333
- package/dist/workstation/update/watchdogProcess.js +72 -0
- package/package.json +11 -7
- 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/automationPreparation.js} +0 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { updateServiceContext } from '../config.js';
|
|
2
|
+
import { SystemMetricsSampler } from '../systemMetrics.js';
|
|
3
|
+
import { ToolchainProbe } from '../toolchain.js';
|
|
4
|
+
import { terminalEnv, terminalShell } from '../tools/terminalRouter.js';
|
|
5
|
+
import { preflightOptionalPty } from '../update/ptyPreflight.js';
|
|
6
|
+
import { DeviceEventRouter } from './events.js';
|
|
7
|
+
import { DeviceOwnership } from '../desktopControl/deviceOwnership.js';
|
|
8
|
+
import { DeviceDesktopRuntime } from './deviceDesktop.js';
|
|
9
|
+
import { DeviceUpdateCoordinator } from '../update/deviceCoordinator.js';
|
|
10
|
+
export class DeviceUpdateService {
|
|
11
|
+
generations = new Map();
|
|
12
|
+
releases = new Map();
|
|
13
|
+
coordinator;
|
|
14
|
+
constructor(options) { if (options)
|
|
15
|
+
this.configure(options); }
|
|
16
|
+
configure(options) {
|
|
17
|
+
if (this.coordinator)
|
|
18
|
+
throw new Error('Device update coordinator is already configured');
|
|
19
|
+
this.coordinator = new DeviceUpdateCoordinator({ ...options, management: id => { const origin = this.generations.get(id); return origin ? { origin, release: this.releases.get(id) } : undefined; } });
|
|
20
|
+
}
|
|
21
|
+
ready(origin, release) {
|
|
22
|
+
this.generations.set(origin.registrationId, Object.freeze({ ...origin }));
|
|
23
|
+
if (release)
|
|
24
|
+
this.releases.set(origin.registrationId, { ...release });
|
|
25
|
+
else
|
|
26
|
+
this.releases.delete(origin.registrationId);
|
|
27
|
+
return Promise.resolve();
|
|
28
|
+
}
|
|
29
|
+
closed(origin) {
|
|
30
|
+
if (this.generations.get(origin.registrationId)?.managementGeneration === origin.managementGeneration) {
|
|
31
|
+
this.generations.delete(origin.registrationId);
|
|
32
|
+
this.releases.delete(origin.registrationId);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async handle(origin, command) {
|
|
36
|
+
const current = this.generations.get(origin.registrationId);
|
|
37
|
+
const valid = current?.managementGeneration === origin.managementGeneration && current.server === origin.server;
|
|
38
|
+
if (valid && this.coordinator)
|
|
39
|
+
return this.coordinator.request(Object.freeze({ ...origin }), command);
|
|
40
|
+
return { phase: 'FAILED', commandId: command.commandId, version: command.release.version, error: valid ? 'Device updates require the device activity and source compatibility policy; update is unavailable until that policy is integrated' : 'The originating management connection is no longer current' };
|
|
41
|
+
}
|
|
42
|
+
async local(operationId, release, source) {
|
|
43
|
+
if (this.coordinator && release && source)
|
|
44
|
+
return this.coordinator.local(operationId, release, source);
|
|
45
|
+
return { phase: 'FAILED', commandId: operationId, error: 'Device update source and activity policy is not yet integrated' };
|
|
46
|
+
}
|
|
47
|
+
async health(request, generation) {
|
|
48
|
+
if (!this.coordinator)
|
|
49
|
+
throw new Error('Device successor health is not configured');
|
|
50
|
+
return this.coordinator.health(request, generation);
|
|
51
|
+
}
|
|
52
|
+
async snapshot(registrationId) {
|
|
53
|
+
if (!this.coordinator)
|
|
54
|
+
return;
|
|
55
|
+
const origin = this.generations.get(registrationId);
|
|
56
|
+
return origin ? this.coordinator.snapshot(origin) : { phase: 'SUCCEEDED', remoteForcePolicy: 'drain-only' };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export function createDeviceServices(options) {
|
|
60
|
+
const desktopOwnership = new DeviceOwnership();
|
|
61
|
+
const workspaces = [];
|
|
62
|
+
const configurations = new Map();
|
|
63
|
+
const factRecipients = new Set();
|
|
64
|
+
const facts = new Map();
|
|
65
|
+
const events = new DeviceEventRouter((registrationId, event) => facts.get(registrationId)?.(event), factRecipients);
|
|
66
|
+
const desktop = new DeviceDesktopRuntime(options.root, desktopOwnership, options.resolveDesktopProvider);
|
|
67
|
+
const metrics = new SystemMetricsSampler(workspaces, options.metricsDependencies);
|
|
68
|
+
const toolchain = new ToolchainProbe(() => terminalShell(), () => terminalEnv());
|
|
69
|
+
let maintenance = Promise.resolve();
|
|
70
|
+
let started;
|
|
71
|
+
let stopped = false;
|
|
72
|
+
const refresh = () => {
|
|
73
|
+
workspaces.splice(0, workspaces.length, ...[...configurations].flatMap(([id, configuration]) => (configuration.workspaces ?? []).map((workspace, index) => ({ name: `${id}:${index}`, cwd: workspace.cwd }))));
|
|
74
|
+
metrics.refreshWorkspaces();
|
|
75
|
+
};
|
|
76
|
+
return {
|
|
77
|
+
desktopOwnership,
|
|
78
|
+
get desktopProvider() { return options.desktopProvider ?? desktop.provider; },
|
|
79
|
+
desktopFacts: () => desktop.facts(),
|
|
80
|
+
desktopActivity: () => desktop.activity(),
|
|
81
|
+
watchDesktop: (id, consumer) => desktop.watch(id, consumer),
|
|
82
|
+
watchFacts(registrationId, receive) {
|
|
83
|
+
facts.set(registrationId, receive);
|
|
84
|
+
factRecipients.add(registrationId);
|
|
85
|
+
return () => { if (facts.get(registrationId) === receive) {
|
|
86
|
+
facts.delete(registrationId);
|
|
87
|
+
factRecipients.delete(registrationId);
|
|
88
|
+
} };
|
|
89
|
+
},
|
|
90
|
+
publishToolState() { events.publish({ scope: 'device', kind: 'tool-state', payload: { changed: true } }); },
|
|
91
|
+
updates: new DeviceUpdateService(),
|
|
92
|
+
start() {
|
|
93
|
+
started ??= (async () => { await (options.preflight ?? (() => preflightOptionalPty(updateServiceContext(options.root))))(); await desktop.start(); await metrics.start(); if (stopped)
|
|
94
|
+
metrics.stop();
|
|
95
|
+
else
|
|
96
|
+
toolchain.start(); })();
|
|
97
|
+
return started;
|
|
98
|
+
},
|
|
99
|
+
async stop() { stopped = true; await started?.catch(() => { }); await maintenance; await desktop.stop(); metrics.stop(); toolchain.stop(); },
|
|
100
|
+
register(id, configuration) { configurations.set(id, configuration); refresh(); },
|
|
101
|
+
unregister(id) { configurations.delete(id); facts.delete(id); factRecipients.delete(id); refresh(); },
|
|
102
|
+
metrics(id) {
|
|
103
|
+
const snapshot = metrics.snapshot();
|
|
104
|
+
if (!snapshot)
|
|
105
|
+
return null;
|
|
106
|
+
const owned = configurations.get(id)?.workspaces ?? [];
|
|
107
|
+
return { ...snapshot, storagePools: snapshot.storagePools.flatMap(pool => {
|
|
108
|
+
const names = pool.workspaces.flatMap(name => { const index = owned.findIndex((_workspace, position) => name === `${id}:${position}`); return index < 0 ? [] : [owned[index].name]; });
|
|
109
|
+
return names.length ? [{ ...pool, label: 'Storage', workspaces: names }] : [];
|
|
110
|
+
}) };
|
|
111
|
+
},
|
|
112
|
+
toolchain: () => toolchain.current(),
|
|
113
|
+
rdSource: () => { const sources = new Set([...configurations.values()].map(configuration => configuration.server)); return sources.size === 1 ? sources.values().next().value : undefined; },
|
|
114
|
+
maintainAdapters(operation) { const result = maintenance.then(async () => { if (!stopped)
|
|
115
|
+
await operation(); }); maintenance = result.catch(() => { }); return result; },
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class DeviceEventRouter {
|
|
2
|
+
send;
|
|
3
|
+
registrations;
|
|
4
|
+
constructor(send, registrations) {
|
|
5
|
+
this.send = send;
|
|
6
|
+
this.registrations = registrations;
|
|
7
|
+
}
|
|
8
|
+
publish(event) {
|
|
9
|
+
if (event.scope === 'registration') {
|
|
10
|
+
if (this.registrations.has(event.registrationId))
|
|
11
|
+
this.send(event.registrationId, event);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const payload = event.payload;
|
|
15
|
+
if (!['metrics', 'desktop-capability', 'tool-state'].includes(event.kind) || !payload || typeof payload !== 'object' || Array.isArray(payload) || Object.keys(payload).length !== 1 || payload.changed !== true)
|
|
16
|
+
throw new Error('Device fact must contain only a change notification');
|
|
17
|
+
for (const registrationId of [...this.registrations])
|
|
18
|
+
this.send(registrationId, { ...event, payload: { changed: true } });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { constants, closeSync, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { readLegacyRegistrationSources } from '../registrations/migration.js';
|
|
4
|
+
import { RegistrationStore } from '../registrations/store.js';
|
|
5
|
+
const verifiedLegacySources = new WeakMap();
|
|
6
|
+
export class RegistrationOwnershipError extends Error {
|
|
7
|
+
code = 'REGISTRATION_OWNERSHIP';
|
|
8
|
+
constructor(message, cause) { super(message, { cause }); this.name = 'RegistrationOwnershipError'; }
|
|
9
|
+
}
|
|
10
|
+
export function legacySourcesOf(ownership) {
|
|
11
|
+
return ownership ? verifiedLegacySources.get(ownership) : undefined;
|
|
12
|
+
}
|
|
13
|
+
export async function resolveRegistrationOwnership(registration, sources) {
|
|
14
|
+
if (!sources)
|
|
15
|
+
return Object.freeze({ registrationId: registration.id });
|
|
16
|
+
const verified = await readLegacyRegistrationSources(sources.adapterCacheDirectory, registration.id);
|
|
17
|
+
if (!verified || JSON.stringify(verified) !== JSON.stringify(sources) || registration.keeperConfigDirectory !== sources.adapterCacheDirectory)
|
|
18
|
+
throw new RegistrationOwnershipError('Legacy registration ownership needs verification');
|
|
19
|
+
const current = (await new RegistrationStore(sources.adapterCacheDirectory).read(registration.id)).registration;
|
|
20
|
+
if (current.server !== registration.server || current.ownerUserId !== registration.ownerUserId || current.workstationId !== registration.workstationId || current.keeperConfigDirectory !== registration.keeperConfigDirectory)
|
|
21
|
+
throw new RegistrationOwnershipError('Legacy registration ownership changed');
|
|
22
|
+
const ownership = Object.freeze({ registrationId: registration.id, legacySources: Object.freeze({ ...verified }) });
|
|
23
|
+
verifiedLegacySources.set(ownership, ownership.legacySources);
|
|
24
|
+
return ownership;
|
|
25
|
+
}
|
|
26
|
+
export function legacyOwnershipAllowed(ownership, directory, kind) {
|
|
27
|
+
const sources = legacySourcesOf(ownership);
|
|
28
|
+
if (!sources)
|
|
29
|
+
return false;
|
|
30
|
+
const resolved = path.resolve(directory);
|
|
31
|
+
if (kind === 'journal')
|
|
32
|
+
return resolved === path.resolve(sources.journalDirectory);
|
|
33
|
+
if (kind === 'local-outbox')
|
|
34
|
+
return path.dirname(resolved) === path.resolve(sources.localOutboxDirectory);
|
|
35
|
+
const root = path.join(sources.adapterCacheDirectory, 'keepers', kind);
|
|
36
|
+
return resolved === root || path.dirname(resolved) === root;
|
|
37
|
+
}
|
|
38
|
+
export function assertRegistrationOwner(value, ownership, legacy) {
|
|
39
|
+
if (!ownership)
|
|
40
|
+
return;
|
|
41
|
+
if (value && typeof value === 'object' && (value.registrationId === ownership.registrationId || (value.registrationId === undefined && legacy && legacyOwnershipAllowed(ownership, legacy.directory, legacy.kind))))
|
|
42
|
+
return;
|
|
43
|
+
throw new RegistrationOwnershipError('Registration owner is unknown or mismatched; state quarantined');
|
|
44
|
+
}
|
|
45
|
+
export function readOwnerFile(file) {
|
|
46
|
+
let descriptor;
|
|
47
|
+
try {
|
|
48
|
+
descriptor = openSync(file, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
49
|
+
const stat = fstatSync(descriptor);
|
|
50
|
+
if (!stat.isFile() || stat.nlink !== 1 || stat.size > 4096 || (stat.mode & 0o077) || (process.getuid && stat.uid !== process.getuid()))
|
|
51
|
+
throw new RegistrationOwnershipError('Unsafe registration owner metadata');
|
|
52
|
+
const value = JSON.parse(readFileSync(descriptor, 'utf8'));
|
|
53
|
+
if (value?.schemaVersion !== 1 || typeof value.registrationId !== 'string' || !value.registrationId)
|
|
54
|
+
throw new RegistrationOwnershipError('Invalid registration owner metadata');
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (error.code === 'ENOENT' || error instanceof RegistrationOwnershipError)
|
|
59
|
+
throw error;
|
|
60
|
+
throw new RegistrationOwnershipError('Registration owner metadata could not be verified; state quarantined', error);
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
if (descriptor !== undefined)
|
|
64
|
+
closeSync(descriptor);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function assertOwnedDirectory(directory, ownership, kind) {
|
|
68
|
+
if (!ownership)
|
|
69
|
+
return;
|
|
70
|
+
try {
|
|
71
|
+
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
72
|
+
const stat = lstatSync(directory);
|
|
73
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || (process.getuid && stat.uid !== process.getuid()))
|
|
74
|
+
throw new RegistrationOwnershipError('Unsafe registration owner directory');
|
|
75
|
+
const file = path.join(directory, 'registration-owner.json');
|
|
76
|
+
try {
|
|
77
|
+
assertRegistrationOwner(readOwnerFile(file), ownership);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error.code !== 'ENOENT')
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
if (readdirSync(directory).length && !(kind && legacyOwnershipAllowed(ownership, directory, kind)))
|
|
85
|
+
throw new RegistrationOwnershipError('Registration owner is unknown; state quarantined');
|
|
86
|
+
try {
|
|
87
|
+
writeFileSync(file, JSON.stringify({ schemaVersion: 1, registrationId: ownership.registrationId }), { mode: 0o600, flag: 'wx' });
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (error.code !== 'EEXIST')
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
assertRegistrationOwner(readOwnerFile(file), ownership);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (error instanceof RegistrationOwnershipError)
|
|
97
|
+
throw error;
|
|
98
|
+
throw new RegistrationOwnershipError('Registration owner directory could not be verified; state quarantined', error);
|
|
99
|
+
}
|
|
100
|
+
}
|