@skrr-ai/cli 0.1.119 → 0.1.120
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/dist/base-command.d.ts +31 -0
- package/dist/base-command.js +106 -4
- package/dist/commands/commands.js +11 -0
- package/dist/commands/commitments/action-proposal.d.ts +13 -0
- package/dist/commands/commitments/action-proposal.js +39 -0
- package/dist/commands/commitments/action-proposals/decide.js +8 -1
- package/dist/commands/commitments/action-proposals/execute.js +11 -1
- package/dist/commands/commitments/create.js +2 -2
- package/dist/commands/commitments/doctor.d.ts +8 -0
- package/dist/commands/commitments/doctor.js +22 -0
- package/dist/commands/commitments/execute-remediation.js +12 -1
- package/dist/commands/commitments/observations.js +2 -2
- package/dist/commands/commitments/pack/bind.d.ts +18 -1
- package/dist/commands/commitments/pack/bind.js +66 -8
- package/dist/commands/commitments/pack/plan.d.ts +4 -1
- package/dist/commands/commitments/pack/plan.js +30 -2
- package/dist/commands/commitments/update.js +8 -2
- package/dist/commands/completion/index.js +1 -1
- package/dist/commands/completion/values.js +1 -1
- package/dist/commands/computer-use/audio.d.ts +1 -0
- package/dist/commands/computer-use/audio.js +1 -0
- package/dist/commands/computer-use/browser.d.ts +1 -0
- package/dist/commands/computer-use/browser.js +1 -0
- package/dist/commands/computer-use/disable.d.ts +1 -0
- package/dist/commands/computer-use/disable.js +1 -0
- package/dist/commands/computer-use/enable.d.ts +1 -0
- package/dist/commands/computer-use/enable.js +1 -0
- package/dist/commands/computer-use/index.d.ts +1 -0
- package/dist/commands/computer-use/index.js +1 -0
- package/dist/commands/computer-use/install.d.ts +1 -0
- package/dist/commands/computer-use/install.js +1 -0
- package/dist/commands/computer-use/recover.d.ts +1 -0
- package/dist/commands/computer-use/recover.js +1 -0
- package/dist/commands/computer-use/status.d.ts +1 -0
- package/dist/commands/computer-use/status.js +1 -0
- package/dist/commands/computer-use/stop.d.ts +1 -0
- package/dist/commands/computer-use/stop.js +1 -0
- package/dist/commands/context.js +16 -11
- package/dist/commands/convos/recovery.js +1 -1
- package/dist/commands/daemon/diagnostics.d.ts +9 -0
- package/dist/commands/daemon/diagnostics.js +53 -0
- package/dist/commands/daemon/index.js +2 -0
- package/dist/commands/daemon/maintenance/attest.d.ts +15 -0
- package/dist/commands/daemon/maintenance/attest.js +52 -0
- package/dist/commands/daemon/maintenance/hold.d.ts +17 -0
- package/dist/commands/daemon/maintenance/hold.js +70 -0
- package/dist/commands/daemon/maintenance/index.d.ts +12 -0
- package/dist/commands/daemon/maintenance/index.js +30 -0
- package/dist/commands/daemon/maintenance/resume.d.ts +13 -0
- package/dist/commands/daemon/maintenance/resume.js +36 -0
- package/dist/commands/daemon/maintenance/status.d.ts +13 -0
- package/dist/commands/daemon/maintenance/status.js +36 -0
- package/dist/commands/doctor.d.ts +4 -1
- package/dist/commands/doctor.js +50 -6
- package/dist/commands/followups/plans/cancel-batch.js +6 -3
- package/dist/commands/followups/plans/capacity.js +7 -3
- package/dist/commands/followups/plans/observability.js +11 -3
- package/dist/commands/followups/plans/preferences/set.js +26 -8
- package/dist/commands/followups/plans/preferences.js +1 -1
- package/dist/commands/followups/plans/show.js +1 -1
- package/dist/commands/goals/key-results/assess.d.ts +36 -0
- package/dist/commands/goals/key-results/assess.js +110 -0
- package/dist/commands/goals/key-results/history.d.ts +30 -0
- package/dist/commands/goals/key-results/history.js +104 -0
- package/dist/commands/goals/key-results/list.d.ts +5 -4
- package/dist/commands/goals/key-results/list.js +12 -6
- package/dist/commands/goals/key-results/show.d.ts +4 -2
- package/dist/commands/goals/key-results/show.js +25 -4
- package/dist/commands/goals/key-results/update.d.ts +4 -0
- package/dist/commands/goals/key-results/update.js +18 -24
- package/dist/commands/goals/plan-now.js +12 -1
- package/dist/commands/goals/planner-compare.d.ts +30 -0
- package/dist/commands/goals/planner-compare.js +136 -0
- package/dist/commands/machines/dedicated/service/exec.d.ts +3 -0
- package/dist/commands/machines/dedicated/service/exec.js +70 -11
- package/dist/commands/machines/hosted/destroy.d.ts +1 -0
- package/dist/commands/machines/hosted/destroy.js +11 -1
- package/dist/commands/machines/hosted/exec.d.ts +1 -0
- package/dist/commands/machines/hosted/exec.js +12 -1
- package/dist/commands/machines/hosted/index.js +1 -0
- package/dist/commands/machines/hosted/operation.d.ts +14 -0
- package/dist/commands/machines/hosted/operation.js +51 -0
- package/dist/commands/machines/hosted/pull.js +1 -1
- package/dist/commands/machines/hosted/start.js +6 -2
- package/dist/commands/spaces/auto-executor/compare.d.ts +18 -0
- package/dist/commands/spaces/auto-executor/compare.js +139 -0
- package/dist/commands/spaces/auto-executor/runs.d.ts +3 -0
- package/dist/commands/spaces/auto-executor/runs.js +13 -1
- package/dist/commands/spaces/charter/create-from-description.d.ts +21 -0
- package/dist/commands/spaces/charter/create-from-description.js +77 -0
- package/dist/commands/spaces/charter/show.d.ts +22 -0
- package/dist/commands/spaces/charter/show.js +61 -0
- package/dist/commands/spaces/heartbeats/list.d.ts +1 -16
- package/dist/commands/spaces/heartbeats/list.js +13 -0
- package/dist/commands/spaces/install-template.js +3 -0
- package/dist/commands/spaces/loops/migrate.d.ts +32 -0
- package/dist/commands/spaces/loops/migrate.js +103 -0
- package/dist/commands/spaces/loops/release.d.ts +14 -0
- package/dist/commands/spaces/loops/release.js +59 -0
- package/dist/commands/spaces/notebook.d.ts +25 -0
- package/dist/commands/spaces/notebook.js +75 -0
- package/dist/commands/spaces/proposals/discard.d.ts +17 -0
- package/dist/commands/spaces/proposals/discard.js +17 -0
- package/dist/commands/spaces/proposals/keep.d.ts +17 -0
- package/dist/commands/spaces/proposals/keep.js +17 -0
- package/dist/commands/spaces/proposals/list.d.ts +24 -0
- package/dist/commands/spaces/proposals/list.js +89 -0
- package/dist/commands/spaces/skills/propose.d.ts +29 -0
- package/dist/commands/spaces/skills/propose.js +82 -0
- package/dist/commands/spaces/templates/fork.js +3 -0
- package/dist/commands/spaces/triggers/show.js +6 -0
- package/dist/commands/spaces/workflows/retry.d.ts +1 -0
- package/dist/commands/spaces/workflows/retry.js +8 -1
- package/dist/commands/spaces/workflows/triggers/create.js +3 -2
- package/dist/commands/spaces/workflows/triggers/fire.js +4 -0
- package/dist/commands/spaces/workflows/triggers/update.js +2 -1
- package/dist/commands/spaces/write-policy/set.d.ts +22 -0
- package/dist/commands/spaces/write-policy/set.js +82 -0
- package/dist/commands/spaces/write-policy/show.d.ts +19 -0
- package/dist/commands/spaces/write-policy/show.js +49 -0
- package/dist/commands/store/artifacts/receipt.d.ts +14 -0
- package/dist/commands/store/artifacts/receipt.js +34 -0
- package/dist/commands/store/artifacts/release.d.ts +2 -0
- package/dist/commands/store/artifacts/release.js +11 -0
- package/dist/commands/store/governance/publish-release.d.ts +2 -0
- package/dist/commands/store/governance/publish-release.js +30 -1
- package/dist/commands/store/governance/release-receipt.d.ts +12 -0
- package/dist/commands/store/governance/release-receipt.js +32 -0
- package/dist/commands/tasks/approvals/list.d.ts +11 -5
- package/dist/commands/tasks/approvals/list.js +13 -6
- package/dist/commands/tasks/attachments/facts.d.ts +12 -0
- package/dist/commands/tasks/attachments/facts.js +29 -0
- package/dist/commands/tasks/attachments/upload.d.ts +1 -0
- package/dist/commands/tasks/attachments/upload.js +16 -0
- package/dist/commands/tasks/bulk-update.js +35 -1
- package/dist/commands/tasks/context.d.ts +15 -0
- package/dist/commands/tasks/context.js +69 -0
- package/dist/commands/tasks/copy.d.ts +18 -0
- package/dist/commands/tasks/copy.js +85 -0
- package/dist/commands/tasks/create-tree.js +97 -23
- package/dist/commands/tasks/create.js +9 -1
- package/dist/commands/tasks/deliverable/add.js +20 -10
- package/dist/commands/tasks/move.js +8 -1
- package/dist/commands/tasks/operations/show.d.ts +16 -0
- package/dist/commands/tasks/operations/show.js +98 -0
- package/dist/commands/tasks/operations/wait.d.ts +22 -0
- package/dist/commands/tasks/operations/wait.js +114 -0
- package/dist/commands/tasks/preflight.d.ts +1 -0
- package/dist/commands/tasks/preflight.js +11 -1
- package/dist/commands/tasks/rearm-recurrence.js +4 -0
- package/dist/commands/tasks/result/show.js +22 -0
- package/dist/commands/tasks/result/submit.d.ts +1 -0
- package/dist/commands/tasks/result/submit.js +3 -0
- package/dist/commands/tasks/retry-receipt.d.ts +15 -0
- package/dist/commands/tasks/retry-receipt.js +89 -0
- package/dist/commands/tasks/retry-review.d.ts +16 -0
- package/dist/commands/tasks/retry-review.js +66 -0
- package/dist/commands/tasks/retry.d.ts +4 -8
- package/dist/commands/tasks/retry.js +34 -68
- package/dist/commands/tasks/runs.d.ts +21 -0
- package/dist/commands/tasks/runs.js +95 -0
- package/dist/commands/tasks/show.d.ts +2 -0
- package/dist/commands/tasks/show.js +15 -1
- package/dist/commands/tasks/start-receipt.d.ts +15 -0
- package/dist/commands/tasks/start-receipt.js +95 -0
- package/dist/commands/tasks/start.d.ts +4 -0
- package/dist/commands/tasks/start.js +49 -3
- package/dist/commands/tasks/update.js +3 -0
- package/dist/commands/tasks/upsert.js +17 -3
- package/dist/commands/tasks/watch.d.ts +3 -0
- package/dist/commands/tasks/watch.js +85 -20
- package/dist/commands/wiki/history.d.ts +33 -0
- package/dist/commands/wiki/history.js +134 -0
- package/dist/commands/wiki/ls.d.ts +2 -0
- package/dist/commands/wiki/ls.js +8 -0
- package/dist/commands/wiki/update.d.ts +3 -1
- package/dist/commands/wiki/update.js +24 -2
- package/dist/commands/wiki/write.d.ts +22 -0
- package/dist/commands/wiki/write.js +144 -6
- package/dist/generated/agent-guides.json +81 -81
- package/dist/generated/managed-instruction-guides.json +1 -1
- package/dist/lib/agent-guides.d.ts +9 -0
- package/dist/lib/agent-guides.js +23 -1
- package/dist/lib/agentic-stream.d.ts +5 -0
- package/dist/lib/agentic-stream.js +122 -3
- package/dist/lib/auth-diagnostics.d.ts +39 -0
- package/dist/lib/auth-diagnostics.js +71 -0
- package/dist/lib/cli-client-identity.d.ts +6 -0
- package/dist/lib/cli-client-identity.js +16 -0
- package/dist/lib/cli-installation-diagnostics.d.ts +52 -0
- package/dist/lib/cli-installation-diagnostics.js +254 -0
- package/dist/lib/command-hygiene.d.ts +45 -0
- package/dist/lib/command-hygiene.js +413 -0
- package/dist/lib/commitments.d.ts +64 -3
- package/dist/lib/commitments.js +34 -6
- package/dist/lib/completion-index.d.ts +16 -4
- package/dist/lib/completion-index.js +50 -14
- package/dist/lib/config.js +7 -1
- package/dist/lib/daemon-maintenance-command.d.ts +22 -0
- package/dist/lib/daemon-maintenance-command.js +39 -0
- package/dist/lib/daemon-maintenance.d.ts +275 -0
- package/dist/lib/daemon-maintenance.js +1035 -0
- package/dist/lib/dedicated-service.d.ts +3 -2
- package/dist/lib/dedicated-service.js +11 -3
- package/dist/lib/governed-store.d.ts +8 -0
- package/dist/lib/governed-store.js +5 -0
- package/dist/lib/hosted-machines.d.ts +33 -2
- package/dist/lib/hosted-machines.js +19 -1
- package/dist/lib/json-output.d.ts +1 -1
- package/dist/lib/machines.d.ts +9 -1
- package/dist/lib/machines.js +15 -1
- package/dist/lib/node-adapter.js +13 -0
- package/dist/lib/record-output.d.ts +22 -0
- package/dist/lib/record-output.js +78 -0
- package/dist/lib/roles.d.ts +3 -3
- package/dist/lib/scoped-memory-command.d.ts +18 -0
- package/dist/lib/scoped-memory-command.js +53 -2
- package/dist/lib/space-charter.d.ts +49 -0
- package/dist/lib/space-charter.js +78 -0
- package/dist/lib/space-loop-migration.d.ts +18 -0
- package/dist/lib/space-loop-migration.js +128 -0
- package/dist/lib/space-notebook.d.ts +22 -0
- package/dist/lib/space-notebook.js +140 -0
- package/dist/lib/space-proposal-decision-command.d.ts +36 -0
- package/dist/lib/space-proposal-decision-command.js +108 -0
- package/dist/lib/space-proposals.d.ts +44 -0
- package/dist/lib/space-proposals.js +186 -0
- package/dist/lib/space-templates.d.ts +8 -0
- package/dist/lib/space-templates.js +17 -0
- package/dist/lib/space-write-policy.d.ts +24 -0
- package/dist/lib/space-write-policy.js +103 -0
- package/dist/lib/task-agent-context-capabilities.d.ts +10 -0
- package/dist/lib/task-agent-context-capabilities.js +22 -0
- package/dist/lib/task-agent-context-compatibility.d.ts +9 -0
- package/dist/lib/task-agent-context-compatibility.js +30 -0
- package/dist/lib/task-asset-upload.d.ts +22 -0
- package/dist/lib/task-asset-upload.js +257 -29
- package/dist/lib/task-batch.d.ts +15 -1
- package/dist/lib/task-batch.js +35 -2
- package/dist/lib/task-operation-watch.d.ts +66 -0
- package/dist/lib/task-operation-watch.js +159 -0
- package/dist/lib/task-resolver.d.ts +1 -1
- package/dist/lib/task-resolver.js +4 -3
- package/dist/lib/task-work.d.ts +1 -1
- package/dist/lib/task-work.js +35 -1
- package/dist/lib/task-write-attribution.d.ts +14 -0
- package/dist/lib/task-write-attribution.js +35 -2
- package/dist/lib/triggers.d.ts +11 -0
- package/dist/lib/triggers.js +7 -0
- package/dist/lib/wiki-update.d.ts +1 -0
- package/dist/lib/wiki-update.js +10 -1
- package/dist/lib/wiki.js +4 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.d.ts +9 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.js +31 -15
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.js +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.js +13 -7
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/guidedUpdate.d.ts +370 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/guidedUpdate.js +315 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/maintenanceReportWire.d.ts +178 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/maintenanceReportWire.js +262 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/toolApprovalSignature.d.ts +51 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/toolApprovalSignature.js +106 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.d.ts +9 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.js +32 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.js +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.js +33 -14
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/guidedUpdate.d.ts +370 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/guidedUpdate.js +404 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/maintenanceReportWire.d.ts +178 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/maintenanceReportWire.js +342 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/toolApprovalSignature.d.ts +51 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/toolApprovalSignature.js +138 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +20 -0
- package/dist/node_modules/@skrr-ai/data-provider/index.js +27085 -20250
- package/oclif.manifest.json +10566 -7247
- package/package.json +20 -2
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The maintenance report wire contract (Machine Maintenance, OSK-19107, task M24;
|
|
3
|
+
* `docs/architecture/machine-maintenance/implementation-plan-2026-10-24.md` §3.5,
|
|
4
|
+
* `phase0/m04-quiescence-evidence.md` §2.5 and §2.6).
|
|
5
|
+
*
|
|
6
|
+
* Declared ONCE, here. The daemon is published and cannot import the API, so the
|
|
7
|
+
* capability name, the payload shape and its bounds live in this package, which
|
|
8
|
+
* every end can import (`@skrr-ai/auth-core/maintenance-report-wire`).
|
|
9
|
+
* `maintenanceReportWire.test.ts` fails on a second spelling of the capability
|
|
10
|
+
* anywhere else in the repo. The shape follows `dedicatedRuntimeBusyWire.ts`, the
|
|
11
|
+
* precedent for a positively announced, fail-closed report, and differs from it
|
|
12
|
+
* only where the owner's pause needs more.
|
|
13
|
+
*
|
|
14
|
+
* WHAT THE REPORT SAYS
|
|
15
|
+
* ---------------------------------------------------------------------------
|
|
16
|
+
* "What does this daemon process hold right now that an update would take from
|
|
17
|
+
* the owner, and has anything been admitted since the last time you asked?" It is
|
|
18
|
+
* a LOCAL read summarised into counts, the handoff's own restart blockers, and
|
|
19
|
+
* the daemon's own update handoff phase.
|
|
20
|
+
*
|
|
21
|
+
* It is EVIDENCE, never authority. The fence does not depend on it: a daemon that
|
|
22
|
+
* lies, or one that sends nothing, cannot make a held machine accept work. Only
|
|
23
|
+
* this report can grant `ready` (a server-side source can only veto it), and a
|
|
24
|
+
* daemon that never announces the capability can only reach `ready` by the
|
|
25
|
+
* owner's attestation.
|
|
26
|
+
*
|
|
27
|
+
* FAIL CLOSED, in three places
|
|
28
|
+
* ---------------------------------------------------------------------------
|
|
29
|
+
* 1. A count is `0` only when the daemon positively counted. A source that could
|
|
30
|
+
* not be read is `complete: 'unknown'`; a daemon that is leaving is
|
|
31
|
+
* `complete: false`. A reader MUST treat both as busy, whatever the counts
|
|
32
|
+
* say (`maintenanceReportIsQuiet` is the one place that says so).
|
|
33
|
+
* 2. A report that is malformed in ANY field is `null` from
|
|
34
|
+
* `parseMaintenanceReport`, and the caller treats the machine as not quiet.
|
|
35
|
+
* A count that is missing, negative, fractional or not a safe integer is not
|
|
36
|
+
* "zero": it is a different, broken report. A version this parser does not
|
|
37
|
+
* know is `null` too: a newer shape needs its own announced capability.
|
|
38
|
+
* 3. Bounds. The blocker list and every string are clamped, so one report can
|
|
39
|
+
* never be large enough to matter, and a field that is NOT in the contract is
|
|
40
|
+
* never copied into what the parser returns (the result is built from a
|
|
41
|
+
* fresh object, so `__proto__` and its kin cannot ride along).
|
|
42
|
+
*
|
|
43
|
+
* `admittedTotal`
|
|
44
|
+
* ---------------------------------------------------------------------------
|
|
45
|
+
* A MONOTONIC counter of admissions since this process started. The server proves
|
|
46
|
+
* "nothing was admitted between two reports" by comparing two values, without
|
|
47
|
+
* trusting the daemon's clock. It counts at every place the daemon admits work
|
|
48
|
+
* and OVER-counts on purpose (one admission may be noted at the gate and again
|
|
49
|
+
* where the work registers): a second increment can only make the proof harder,
|
|
50
|
+
* never easier. A path that the daemon cannot count must say so in
|
|
51
|
+
* `daemon/src/maintenance-report.ts`, not hide in a zero.
|
|
52
|
+
*/
|
|
53
|
+
export declare const MAINTENANCE_REPORT_CAPABILITY = "maintenance_report_v1";
|
|
54
|
+
/** The heartbeat (and register) key the report rides under. Sent only by a daemon that announced the capability. */
|
|
55
|
+
export declare const MAINTENANCE_REPORT_HEARTBEAT_KEY = "maintenanceReport";
|
|
56
|
+
export declare const MAINTENANCE_REPORT_VERSION = 1;
|
|
57
|
+
/**
|
|
58
|
+
* The daemon's own update handoff phases (`daemon/src/update/handoff.ts`), and the
|
|
59
|
+
* members of `DaemonMaintenanceHandoff.phase` in `@skrr-ai/data-provider`. A phase
|
|
60
|
+
* outside this list is a newer protocol and makes the whole report `null`.
|
|
61
|
+
*/
|
|
62
|
+
export declare const MAINTENANCE_REPORT_HANDOFF_PHASES: readonly ["ready", "deferred", "reconnecting", "verified", "failed", "rolled-back"];
|
|
63
|
+
export type MaintenanceReportHandoffPhase = (typeof MAINTENANCE_REPORT_HANDOFF_PHASES)[number];
|
|
64
|
+
export declare const MAINTENANCE_REPORT_LIMITS: {
|
|
65
|
+
/** The handoff's blockers carried for the "waiting on" text; the counts, not this list, decide busy. */
|
|
66
|
+
readonly maxBlockers: 32;
|
|
67
|
+
readonly maxKindLength: 32;
|
|
68
|
+
readonly maxIdLength: 128;
|
|
69
|
+
readonly maxReasonLength: 240;
|
|
70
|
+
readonly maxHandoffIdLength: 64;
|
|
71
|
+
readonly maxHandoffReasonLength: 64;
|
|
72
|
+
readonly maxProcessStartIdLength: 64;
|
|
73
|
+
/** Hard ceiling on the serialized report. The clamps above keep a valid one well under it. */
|
|
74
|
+
readonly maxSerializedBytes: 20000;
|
|
75
|
+
};
|
|
76
|
+
/** What `complete` can be. Anything but `true` means the counts prove nothing. */
|
|
77
|
+
export type MaintenanceReportComplete = boolean | 'unknown';
|
|
78
|
+
/** The handoff's own `RestartBlocker` shape (`daemon/src/update/handoff.ts`). Reason text is the handoff's, never re-spelled. */
|
|
79
|
+
export interface MaintenanceReportBlocker {
|
|
80
|
+
kind: string;
|
|
81
|
+
id?: string;
|
|
82
|
+
reason: string;
|
|
83
|
+
}
|
|
84
|
+
export interface MaintenanceReportInflight {
|
|
85
|
+
/** Provider sessions and their wrapper processes: in-process turns, preparing dispatches, live wrappers. */
|
|
86
|
+
sessions: number;
|
|
87
|
+
/** Tool calls running, plus background commands still running. */
|
|
88
|
+
tools: number;
|
|
89
|
+
/** Terminals the daemon holds, preservable or not. A person's open shell is work an update would interrupt. */
|
|
90
|
+
terminals: number;
|
|
91
|
+
/** Provider turns that still depend on credentials, permissions, a browser or a model connection the service owns. */
|
|
92
|
+
providerDependencies: number;
|
|
93
|
+
/** Write-ahead entries whose durability the daemon has not confirmed. */
|
|
94
|
+
walUnconfirmed: number;
|
|
95
|
+
}
|
|
96
|
+
export interface MaintenanceReportHandoff {
|
|
97
|
+
phase: MaintenanceReportHandoffPhase;
|
|
98
|
+
handoffId: string;
|
|
99
|
+
reason?: string;
|
|
100
|
+
/** ISO time the daemon's lease on this phase ends. */
|
|
101
|
+
expiresAt?: string;
|
|
102
|
+
}
|
|
103
|
+
export interface MaintenanceReport {
|
|
104
|
+
version: typeof MAINTENANCE_REPORT_VERSION;
|
|
105
|
+
/** The daemon process that read this. The server drops a report that is not its registered process's. */
|
|
106
|
+
processStartId: string;
|
|
107
|
+
/** ISO time of the daemon's own read. Informational: freshness is the server's receipt time. */
|
|
108
|
+
readAt: string;
|
|
109
|
+
/** `true`: every source was read. `'unknown'`: one could not be. `false`: the process is leaving. */
|
|
110
|
+
complete: MaintenanceReportComplete;
|
|
111
|
+
/** Monotonic count of admissions since this process started. */
|
|
112
|
+
admittedTotal: number;
|
|
113
|
+
inflight: MaintenanceReportInflight;
|
|
114
|
+
blockers: MaintenanceReportBlocker[];
|
|
115
|
+
/** True when the daemon had more blockers than it sent. */
|
|
116
|
+
blockersTruncated: boolean;
|
|
117
|
+
/** The daemon's own update handoff, only while it is live or unresolved; otherwise `null`. */
|
|
118
|
+
handoff: MaintenanceReportHandoff | null;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The reader's view of a daemon's heartbeat section. Anything malformed, from a
|
|
122
|
+
* daemon that did not announce the capability, an unknown version, or oversized
|
|
123
|
+
* is `null`, and the caller must then treat the machine as NOT quiet. Never
|
|
124
|
+
* trusts a field it did not validate and never copies one it does not know.
|
|
125
|
+
*/
|
|
126
|
+
export declare function parseMaintenanceReport(raw: unknown): MaintenanceReport | null;
|
|
127
|
+
/**
|
|
128
|
+
* A report as it was stored (JSON text on the presence row). Anything that does
|
|
129
|
+
* not parse, or does not validate, is `null`: a stored value is an input like any
|
|
130
|
+
* other and is read with the same suspicion.
|
|
131
|
+
*/
|
|
132
|
+
export declare function parseStoredMaintenanceReport(stored: unknown): MaintenanceReport | null;
|
|
133
|
+
/**
|
|
134
|
+
* The one definition of a POSITIVE ZERO: the daemon read every source and found
|
|
135
|
+
* nothing. `complete: 'unknown'` and `complete: false` are never zero whatever
|
|
136
|
+
* the counts say, because the counts were not (all) read.
|
|
137
|
+
*
|
|
138
|
+
* A blocker that is not work (a missing restart owner, say) does not make a
|
|
139
|
+
* report non-quiet; readiness is "nothing is running", not "the daemon can
|
|
140
|
+
* restart itself".
|
|
141
|
+
*/
|
|
142
|
+
export declare function maintenanceReportIsQuiet(report: MaintenanceReport | null): boolean;
|
|
143
|
+
export interface BuildMaintenanceReportInput {
|
|
144
|
+
processStartId: string;
|
|
145
|
+
/** Epoch ms of the daemon's own read. */
|
|
146
|
+
readAtMs: number;
|
|
147
|
+
complete: MaintenanceReportComplete;
|
|
148
|
+
admittedTotal: number;
|
|
149
|
+
inflight: MaintenanceReportInflight;
|
|
150
|
+
blockers: ReadonlyArray<{
|
|
151
|
+
kind: string;
|
|
152
|
+
id?: string;
|
|
153
|
+
reason: string;
|
|
154
|
+
}>;
|
|
155
|
+
/** `expiresAtMs` is epoch ms; the wire carries ISO. */
|
|
156
|
+
handoff: {
|
|
157
|
+
phase: MaintenanceReportHandoffPhase;
|
|
158
|
+
handoffId: string;
|
|
159
|
+
reason?: string;
|
|
160
|
+
expiresAtMs?: number;
|
|
161
|
+
} | null;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* A report that says nothing was counted. The shape the daemon sends when it
|
|
165
|
+
* could not read an inventory source at all, and the shape `buildMaintenanceReport`
|
|
166
|
+
* falls back to when it was handed something the contract cannot carry.
|
|
167
|
+
*/
|
|
168
|
+
export declare function unknownMaintenanceReport(processStartId: string, readAtMs: number, admittedTotal?: number): MaintenanceReport;
|
|
169
|
+
/**
|
|
170
|
+
* Build the wire report from what the daemon read. Input the contract cannot
|
|
171
|
+
* carry (a negative count, a blocker with no kind, a time that is not a time)
|
|
172
|
+
* becomes an `unknown` report rather than a throw or a report that parses to
|
|
173
|
+
* something else, so the result parses whenever `processStartId` is a real id (the
|
|
174
|
+
* daemon's always is). A builder that threw would turn a bad read into silence,
|
|
175
|
+
* and silence is the absence of a report, which the server reads the same way,
|
|
176
|
+
* but later.
|
|
177
|
+
*/
|
|
178
|
+
export declare function buildMaintenanceReport(input: BuildMaintenanceReportInput): MaintenanceReport;
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var maintenanceReportWire_exports = {};
|
|
20
|
+
__export(maintenanceReportWire_exports, {
|
|
21
|
+
MAINTENANCE_REPORT_CAPABILITY: () => MAINTENANCE_REPORT_CAPABILITY,
|
|
22
|
+
MAINTENANCE_REPORT_HANDOFF_PHASES: () => MAINTENANCE_REPORT_HANDOFF_PHASES,
|
|
23
|
+
MAINTENANCE_REPORT_HEARTBEAT_KEY: () => MAINTENANCE_REPORT_HEARTBEAT_KEY,
|
|
24
|
+
MAINTENANCE_REPORT_LIMITS: () => MAINTENANCE_REPORT_LIMITS,
|
|
25
|
+
MAINTENANCE_REPORT_VERSION: () => MAINTENANCE_REPORT_VERSION,
|
|
26
|
+
buildMaintenanceReport: () => buildMaintenanceReport,
|
|
27
|
+
maintenanceReportIsQuiet: () => maintenanceReportIsQuiet,
|
|
28
|
+
parseMaintenanceReport: () => parseMaintenanceReport,
|
|
29
|
+
parseStoredMaintenanceReport: () => parseStoredMaintenanceReport,
|
|
30
|
+
unknownMaintenanceReport: () => unknownMaintenanceReport
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(maintenanceReportWire_exports);
|
|
33
|
+
const MAINTENANCE_REPORT_CAPABILITY = "maintenance_report_v1";
|
|
34
|
+
const MAINTENANCE_REPORT_HEARTBEAT_KEY = "maintenanceReport";
|
|
35
|
+
const MAINTENANCE_REPORT_VERSION = 1;
|
|
36
|
+
const MAINTENANCE_REPORT_HANDOFF_PHASES = [
|
|
37
|
+
"ready",
|
|
38
|
+
"deferred",
|
|
39
|
+
"reconnecting",
|
|
40
|
+
"verified",
|
|
41
|
+
"failed",
|
|
42
|
+
"rolled-back"
|
|
43
|
+
];
|
|
44
|
+
const MAINTENANCE_REPORT_LIMITS = {
|
|
45
|
+
/** The handoff's blockers carried for the "waiting on" text; the counts, not this list, decide busy. */
|
|
46
|
+
maxBlockers: 32,
|
|
47
|
+
maxKindLength: 32,
|
|
48
|
+
maxIdLength: 128,
|
|
49
|
+
maxReasonLength: 240,
|
|
50
|
+
maxHandoffIdLength: 64,
|
|
51
|
+
maxHandoffReasonLength: 64,
|
|
52
|
+
maxProcessStartIdLength: 64,
|
|
53
|
+
/** Hard ceiling on the serialized report. The clamps above keep a valid one well under it. */
|
|
54
|
+
maxSerializedBytes: 2e4
|
|
55
|
+
};
|
|
56
|
+
const PROCESS_START_ID_PATTERN = /^[A-Za-z0-9_.:-]+$/;
|
|
57
|
+
const CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/g;
|
|
58
|
+
function isRecord(value) {
|
|
59
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
60
|
+
}
|
|
61
|
+
function field(record, key) {
|
|
62
|
+
return Object.prototype.hasOwnProperty.call(record, key) ? record[key] : void 0;
|
|
63
|
+
}
|
|
64
|
+
function isoFromMs(ms) {
|
|
65
|
+
if (typeof ms !== "number" || !Number.isFinite(ms))
|
|
66
|
+
return "";
|
|
67
|
+
const date = new Date(ms);
|
|
68
|
+
return Number.isNaN(date.getTime()) ? "" : date.toISOString();
|
|
69
|
+
}
|
|
70
|
+
function count(value) {
|
|
71
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
72
|
+
}
|
|
73
|
+
function clampText(value, max) {
|
|
74
|
+
if (typeof value !== "string")
|
|
75
|
+
return null;
|
|
76
|
+
const clean = value.replace(CONTROL_CHARACTERS, " ");
|
|
77
|
+
return clean.length > max ? clean.slice(0, max) : clean;
|
|
78
|
+
}
|
|
79
|
+
function isoOf(value) {
|
|
80
|
+
if (typeof value !== "string")
|
|
81
|
+
return null;
|
|
82
|
+
const ms = Date.parse(value);
|
|
83
|
+
if (!Number.isFinite(ms))
|
|
84
|
+
return null;
|
|
85
|
+
try {
|
|
86
|
+
return new Date(ms).toISOString();
|
|
87
|
+
} catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function completeOf(value) {
|
|
92
|
+
return value === true || value === false || value === "unknown" ? value : void 0;
|
|
93
|
+
}
|
|
94
|
+
function parseMaintenanceReport(raw) {
|
|
95
|
+
if (!isRecord(raw))
|
|
96
|
+
return null;
|
|
97
|
+
if (field(raw, "version") !== MAINTENANCE_REPORT_VERSION)
|
|
98
|
+
return null;
|
|
99
|
+
const processStartId = field(raw, "processStartId");
|
|
100
|
+
if (typeof processStartId !== "string" || processStartId.length < 1 || processStartId.length > MAINTENANCE_REPORT_LIMITS.maxProcessStartIdLength || !PROCESS_START_ID_PATTERN.test(processStartId)) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const readAt = isoOf(field(raw, "readAt"));
|
|
104
|
+
if (readAt === null)
|
|
105
|
+
return null;
|
|
106
|
+
const complete = completeOf(field(raw, "complete"));
|
|
107
|
+
if (complete === void 0)
|
|
108
|
+
return null;
|
|
109
|
+
const admittedTotal = count(field(raw, "admittedTotal"));
|
|
110
|
+
if (admittedTotal === null)
|
|
111
|
+
return null;
|
|
112
|
+
const rawInflight = field(raw, "inflight");
|
|
113
|
+
if (!isRecord(rawInflight))
|
|
114
|
+
return null;
|
|
115
|
+
const sessions = count(field(rawInflight, "sessions"));
|
|
116
|
+
const tools = count(field(rawInflight, "tools"));
|
|
117
|
+
const terminals = count(field(rawInflight, "terminals"));
|
|
118
|
+
const providerDependencies = count(field(rawInflight, "providerDependencies"));
|
|
119
|
+
const walUnconfirmed = count(field(rawInflight, "walUnconfirmed"));
|
|
120
|
+
if (sessions === null || tools === null || terminals === null || providerDependencies === null || walUnconfirmed === null) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const rawBlockers = field(raw, "blockers");
|
|
124
|
+
if (!Array.isArray(rawBlockers))
|
|
125
|
+
return null;
|
|
126
|
+
const rawTruncated = field(raw, "blockersTruncated");
|
|
127
|
+
if (rawTruncated !== void 0 && typeof rawTruncated !== "boolean")
|
|
128
|
+
return null;
|
|
129
|
+
const limit = MAINTENANCE_REPORT_LIMITS.maxBlockers;
|
|
130
|
+
const blockers = [];
|
|
131
|
+
for (let index = 0; index < rawBlockers.length && blockers.length < limit; index += 1) {
|
|
132
|
+
const element = rawBlockers[index];
|
|
133
|
+
if (!isRecord(element))
|
|
134
|
+
return null;
|
|
135
|
+
const kind = clampText(field(element, "kind"), MAINTENANCE_REPORT_LIMITS.maxKindLength);
|
|
136
|
+
const reason = clampText(field(element, "reason"), MAINTENANCE_REPORT_LIMITS.maxReasonLength);
|
|
137
|
+
if (kind === null || kind === "" || reason === null)
|
|
138
|
+
return null;
|
|
139
|
+
const blocker = { kind, reason };
|
|
140
|
+
const rawId = field(element, "id");
|
|
141
|
+
if (rawId !== void 0) {
|
|
142
|
+
const id = clampText(rawId, MAINTENANCE_REPORT_LIMITS.maxIdLength);
|
|
143
|
+
if (id === null)
|
|
144
|
+
return null;
|
|
145
|
+
blocker.id = id;
|
|
146
|
+
}
|
|
147
|
+
blockers.push(blocker);
|
|
148
|
+
}
|
|
149
|
+
const blockersTruncated = rawBlockers.length > limit || rawTruncated === true;
|
|
150
|
+
const rawHandoff = field(raw, "handoff");
|
|
151
|
+
if (rawHandoff === void 0)
|
|
152
|
+
return null;
|
|
153
|
+
let handoff = null;
|
|
154
|
+
if (rawHandoff !== null) {
|
|
155
|
+
if (!isRecord(rawHandoff))
|
|
156
|
+
return null;
|
|
157
|
+
const phase = field(rawHandoff, "phase");
|
|
158
|
+
if (!MAINTENANCE_REPORT_HANDOFF_PHASES.includes(phase))
|
|
159
|
+
return null;
|
|
160
|
+
const handoffId = clampText(field(rawHandoff, "handoffId"), MAINTENANCE_REPORT_LIMITS.maxHandoffIdLength);
|
|
161
|
+
if (handoffId === null || handoffId === "")
|
|
162
|
+
return null;
|
|
163
|
+
handoff = { phase, handoffId };
|
|
164
|
+
const rawReason = field(rawHandoff, "reason");
|
|
165
|
+
if (rawReason !== void 0) {
|
|
166
|
+
const reason = clampText(rawReason, MAINTENANCE_REPORT_LIMITS.maxHandoffReasonLength);
|
|
167
|
+
if (reason === null)
|
|
168
|
+
return null;
|
|
169
|
+
handoff.reason = reason;
|
|
170
|
+
}
|
|
171
|
+
const rawExpiresAt = field(rawHandoff, "expiresAt");
|
|
172
|
+
if (rawExpiresAt !== void 0) {
|
|
173
|
+
const expiresAt = isoOf(rawExpiresAt);
|
|
174
|
+
if (expiresAt === null)
|
|
175
|
+
return null;
|
|
176
|
+
handoff.expiresAt = expiresAt;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const report = {
|
|
180
|
+
version: MAINTENANCE_REPORT_VERSION,
|
|
181
|
+
processStartId,
|
|
182
|
+
readAt,
|
|
183
|
+
complete,
|
|
184
|
+
admittedTotal,
|
|
185
|
+
inflight: { sessions, tools, terminals, providerDependencies, walUnconfirmed },
|
|
186
|
+
blockers,
|
|
187
|
+
blockersTruncated,
|
|
188
|
+
handoff
|
|
189
|
+
};
|
|
190
|
+
if (JSON.stringify(report).length > MAINTENANCE_REPORT_LIMITS.maxSerializedBytes)
|
|
191
|
+
return null;
|
|
192
|
+
return report;
|
|
193
|
+
}
|
|
194
|
+
function parseStoredMaintenanceReport(stored) {
|
|
195
|
+
if (typeof stored !== "string" || stored === "")
|
|
196
|
+
return null;
|
|
197
|
+
if (stored.length > MAINTENANCE_REPORT_LIMITS.maxSerializedBytes)
|
|
198
|
+
return null;
|
|
199
|
+
try {
|
|
200
|
+
return parseMaintenanceReport(JSON.parse(stored));
|
|
201
|
+
} catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function maintenanceReportIsQuiet(report) {
|
|
206
|
+
if (!report)
|
|
207
|
+
return false;
|
|
208
|
+
if (report.complete !== true)
|
|
209
|
+
return false;
|
|
210
|
+
const { sessions, tools, terminals, providerDependencies, walUnconfirmed } = report.inflight;
|
|
211
|
+
return sessions === 0 && tools === 0 && terminals === 0 && providerDependencies === 0 && walUnconfirmed === 0;
|
|
212
|
+
}
|
|
213
|
+
function unknownMaintenanceReport(processStartId, readAtMs, admittedTotal = 0) {
|
|
214
|
+
return {
|
|
215
|
+
version: MAINTENANCE_REPORT_VERSION,
|
|
216
|
+
processStartId,
|
|
217
|
+
readAt: isoFromMs(readAtMs) || (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
218
|
+
complete: "unknown",
|
|
219
|
+
admittedTotal: count(admittedTotal) ?? 0,
|
|
220
|
+
inflight: { sessions: 0, tools: 0, terminals: 0, providerDependencies: 0, walUnconfirmed: 0 },
|
|
221
|
+
blockers: [],
|
|
222
|
+
blockersTruncated: false,
|
|
223
|
+
handoff: null
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function buildMaintenanceReport(input) {
|
|
227
|
+
const blockers = input.blockers.slice(0, MAINTENANCE_REPORT_LIMITS.maxBlockers).map((blocker) => ({
|
|
228
|
+
kind: blocker.kind,
|
|
229
|
+
...blocker.id !== void 0 ? { id: blocker.id } : {},
|
|
230
|
+
reason: blocker.reason
|
|
231
|
+
}));
|
|
232
|
+
const candidate = {
|
|
233
|
+
version: MAINTENANCE_REPORT_VERSION,
|
|
234
|
+
processStartId: input.processStartId,
|
|
235
|
+
readAt: isoFromMs(input.readAtMs),
|
|
236
|
+
complete: input.complete,
|
|
237
|
+
admittedTotal: input.admittedTotal,
|
|
238
|
+
inflight: { ...input.inflight },
|
|
239
|
+
blockers,
|
|
240
|
+
blockersTruncated: input.blockers.length > MAINTENANCE_REPORT_LIMITS.maxBlockers,
|
|
241
|
+
handoff: input.handoff ? {
|
|
242
|
+
phase: input.handoff.phase,
|
|
243
|
+
handoffId: input.handoff.handoffId,
|
|
244
|
+
...input.handoff.reason !== void 0 ? { reason: input.handoff.reason } : {},
|
|
245
|
+
...input.handoff.expiresAtMs !== void 0 ? { expiresAt: isoFromMs(input.handoff.expiresAtMs) } : {}
|
|
246
|
+
} : null
|
|
247
|
+
};
|
|
248
|
+
return parseMaintenanceReport(candidate) ?? unknownMaintenanceReport(input.processStartId, input.readAtMs, input.admittedTotal);
|
|
249
|
+
}
|
|
250
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
251
|
+
0 && (module.exports = {
|
|
252
|
+
MAINTENANCE_REPORT_CAPABILITY,
|
|
253
|
+
MAINTENANCE_REPORT_HANDOFF_PHASES,
|
|
254
|
+
MAINTENANCE_REPORT_HEARTBEAT_KEY,
|
|
255
|
+
MAINTENANCE_REPORT_LIMITS,
|
|
256
|
+
MAINTENANCE_REPORT_VERSION,
|
|
257
|
+
buildMaintenanceReport,
|
|
258
|
+
maintenanceReportIsQuiet,
|
|
259
|
+
parseMaintenanceReport,
|
|
260
|
+
parseStoredMaintenanceReport,
|
|
261
|
+
unknownMaintenanceReport
|
|
262
|
+
});
|
|
@@ -177,6 +177,57 @@ export declare function signToolApproval(args: {
|
|
|
177
177
|
now?: number;
|
|
178
178
|
ttlMs?: number;
|
|
179
179
|
}): SignedToolApproval;
|
|
180
|
+
/** A short-lived platform-signed assertion for exactly one local executor. */
|
|
181
|
+
export interface PersonalDataExecutorLeasePayload {
|
|
182
|
+
v: 1;
|
|
183
|
+
leaseId: string;
|
|
184
|
+
/** The daemon identity registered for this machine. */
|
|
185
|
+
daemonId: string;
|
|
186
|
+
/** Fresh random daemon-start nonce; restart invalidates every prior lease. */
|
|
187
|
+
daemonInstanceId: string;
|
|
188
|
+
/** Account whose interactive session requested this local executor. */
|
|
189
|
+
ownerUserId: string;
|
|
190
|
+
/** Fixed, sorted set of operations this executor may make available. */
|
|
191
|
+
capabilities: string[];
|
|
192
|
+
issuedAt: number;
|
|
193
|
+
expiresAt: number;
|
|
194
|
+
}
|
|
195
|
+
export interface SignedPersonalDataExecutorLease {
|
|
196
|
+
v: 1;
|
|
197
|
+
payload: string;
|
|
198
|
+
kid: string;
|
|
199
|
+
sig: string;
|
|
200
|
+
}
|
|
201
|
+
export type PersonalDataExecutorLeaseVerdict = {
|
|
202
|
+
ok: true;
|
|
203
|
+
leaseId: string;
|
|
204
|
+
ownerUserId: string;
|
|
205
|
+
expiresAt: number;
|
|
206
|
+
} | {
|
|
207
|
+
ok: false;
|
|
208
|
+
reason: 'absent' | 'malformed' | 'unknown_key' | 'signature' | 'daemon_binding' | 'capabilities' | 'expired' | 'window';
|
|
209
|
+
};
|
|
210
|
+
/** Server-side mint. The caller must authorize the requesting user separately. */
|
|
211
|
+
export declare function signPersonalDataExecutorLease(args: {
|
|
212
|
+
leaseId: string;
|
|
213
|
+
daemonId: string;
|
|
214
|
+
daemonInstanceId: string;
|
|
215
|
+
ownerUserId: string;
|
|
216
|
+
capabilities: readonly string[];
|
|
217
|
+
signer: ApprovalSigner;
|
|
218
|
+
now?: number;
|
|
219
|
+
ttlMs?: number;
|
|
220
|
+
}): SignedPersonalDataExecutorLease | null;
|
|
221
|
+
/**
|
|
222
|
+
* Daemon-side verifier. It trusts the same independently pinned platform
|
|
223
|
+
* keyset as v2 tool approvals, but a separate signature domain and schema.
|
|
224
|
+
*/
|
|
225
|
+
export declare function verifyPersonalDataExecutorLease(lease: unknown, expected: {
|
|
226
|
+
daemonId: string;
|
|
227
|
+
daemonInstanceId: string;
|
|
228
|
+
capabilities: readonly string[];
|
|
229
|
+
now?: number;
|
|
230
|
+
}, keyset: ApprovalKeyset): PersonalDataExecutorLeaseVerdict;
|
|
180
231
|
export interface SignedToolApprovalCall {
|
|
181
232
|
toolUseId: string;
|
|
182
233
|
toolName: string;
|
|
@@ -24,8 +24,10 @@ __export(toolApprovalSignature_exports, {
|
|
|
24
24
|
canonicalApprovalKeysetText: () => canonicalApprovalKeysetText,
|
|
25
25
|
endorseApprovalKeysetText: () => endorseApprovalKeysetText,
|
|
26
26
|
parseApprovalKeysetText: () => parseApprovalKeysetText,
|
|
27
|
+
signPersonalDataExecutorLease: () => signPersonalDataExecutorLease,
|
|
27
28
|
signToolApproval: () => signToolApproval,
|
|
28
29
|
verifyApprovalKeysetDocument: () => verifyApprovalKeysetDocument,
|
|
30
|
+
verifyPersonalDataExecutorLease: () => verifyPersonalDataExecutorLease,
|
|
29
31
|
verifySignedToolApproval: () => verifySignedToolApproval,
|
|
30
32
|
verifyToolApprovalAttestation: () => verifyToolApprovalAttestation
|
|
31
33
|
});
|
|
@@ -35,11 +37,17 @@ var import_daemonToolApproval = require("./daemonToolApproval.js");
|
|
|
35
37
|
const TOOL_APPROVAL_SIGNED_CAPABILITY = "tool_approval_signed_v1";
|
|
36
38
|
const ATTESTATION_SIGNING_DOMAIN = "skrr-tool-approval-v2\n";
|
|
37
39
|
const KEYSET_SIGNING_DOMAIN = "skrr-tool-approval-keyset-v1\n";
|
|
40
|
+
const PERSONAL_DATA_EXECUTOR_LEASE_SIGNING_DOMAIN = "skrr-personal-data-executor-lease-v1\n";
|
|
38
41
|
const KID_PATTERN = /^[A-Za-z0-9._-]{1,64}$/;
|
|
39
42
|
const MAX_PAYLOAD_BYTES = 4096;
|
|
40
43
|
const MAX_KEYSET_BYTES = 16 * 1024;
|
|
41
44
|
const MAX_KEYSET_KEYS = 16;
|
|
42
45
|
const MAX_KEYSET_SIGNATURES = 16;
|
|
46
|
+
const MAX_EXECUTOR_LEASE_CAPABILITIES = 8;
|
|
47
|
+
const MAX_EXECUTOR_LEASE_TTL_MS = 5 * 60 * 1e3;
|
|
48
|
+
const EXECUTOR_LEASE_CLOCK_SKEW_MS = 3e4;
|
|
49
|
+
const EXECUTOR_LEASE_ID_PATTERN = /^[A-Za-z0-9_-]{16,128}$/;
|
|
50
|
+
const EXECUTOR_CAPABILITY_PATTERN = /^[a-z0-9_.:-]{1,128}$/;
|
|
43
51
|
function approvalPublicKeyFromKeyObject(kid, key) {
|
|
44
52
|
const publicKey = key.type === "private" ? (0, import_node_crypto.createPublicKey)(key) : key;
|
|
45
53
|
const der = publicKey.export({ format: "der", type: "spki" });
|
|
@@ -70,6 +78,24 @@ function verifySignature(domain, message, sigB64, key) {
|
|
|
70
78
|
function signMessage(domain, message, privateKey) {
|
|
71
79
|
return (0, import_node_crypto.sign)(null, Buffer.from(domain + message, "utf8"), privateKey).toString("base64");
|
|
72
80
|
}
|
|
81
|
+
function isExecutorLeaseId(value) {
|
|
82
|
+
return typeof value === "string" && EXECUTOR_LEASE_ID_PATTERN.test(value);
|
|
83
|
+
}
|
|
84
|
+
function isExecutorLeaseText(value, max = 128) {
|
|
85
|
+
return typeof value === "string" && value.length > 0 && value.length <= max && !/[\u0000-\u001f]/.test(value);
|
|
86
|
+
}
|
|
87
|
+
function canonicalExecutorCapabilities(value) {
|
|
88
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > MAX_EXECUTOR_LEASE_CAPABILITIES) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const capabilities = value.map((entry) => typeof entry === "string" ? entry : "");
|
|
92
|
+
if (capabilities.some((entry) => !EXECUTOR_CAPABILITY_PATTERN.test(entry)))
|
|
93
|
+
return null;
|
|
94
|
+
const sorted = [...capabilities].sort();
|
|
95
|
+
if (new Set(sorted).size !== sorted.length)
|
|
96
|
+
return null;
|
|
97
|
+
return sorted;
|
|
98
|
+
}
|
|
73
99
|
function compareKid(a, b) {
|
|
74
100
|
if (a === b)
|
|
75
101
|
return 0;
|
|
@@ -199,6 +225,84 @@ function signToolApproval(args) {
|
|
|
199
225
|
sig: signMessage(ATTESTATION_SIGNING_DOMAIN, text, args.signer.privateKey)
|
|
200
226
|
};
|
|
201
227
|
}
|
|
228
|
+
function signPersonalDataExecutorLease(args) {
|
|
229
|
+
const capabilities = canonicalExecutorCapabilities(args.capabilities);
|
|
230
|
+
const ttlMs = args.ttlMs ?? MAX_EXECUTOR_LEASE_TTL_MS;
|
|
231
|
+
const now = args.now ?? Date.now();
|
|
232
|
+
if (!isExecutorLeaseId(args.leaseId) || !isExecutorLeaseText(args.daemonId) || !isExecutorLeaseId(args.daemonInstanceId) || !isExecutorLeaseText(args.ownerUserId) || !capabilities || !Number.isSafeInteger(now) || !Number.isSafeInteger(ttlMs) || ttlMs <= 0 || ttlMs > MAX_EXECUTOR_LEASE_TTL_MS) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
const payload = {
|
|
236
|
+
v: 1,
|
|
237
|
+
leaseId: args.leaseId,
|
|
238
|
+
daemonId: args.daemonId,
|
|
239
|
+
daemonInstanceId: args.daemonInstanceId,
|
|
240
|
+
ownerUserId: args.ownerUserId,
|
|
241
|
+
capabilities,
|
|
242
|
+
issuedAt: now,
|
|
243
|
+
expiresAt: now + ttlMs
|
|
244
|
+
};
|
|
245
|
+
const text = (0, import_daemonToolApproval.canonicalApprovalJson)(payload);
|
|
246
|
+
return {
|
|
247
|
+
v: 1,
|
|
248
|
+
payload: text,
|
|
249
|
+
kid: args.signer.kid,
|
|
250
|
+
sig: signMessage(PERSONAL_DATA_EXECUTOR_LEASE_SIGNING_DOMAIN, text, args.signer.privateKey)
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function verifyPersonalDataExecutorLease(lease, expected, keyset) {
|
|
254
|
+
if (lease === void 0 || lease === null)
|
|
255
|
+
return { ok: false, reason: "absent" };
|
|
256
|
+
if (!lease || typeof lease !== "object" || Array.isArray(lease)) {
|
|
257
|
+
return { ok: false, reason: "malformed" };
|
|
258
|
+
}
|
|
259
|
+
const wire = lease;
|
|
260
|
+
if (wire.v !== 1 || typeof wire.payload !== "string" || wire.payload.length === 0 || wire.payload.length > MAX_PAYLOAD_BYTES || typeof wire.kid !== "string" || typeof wire.sig !== "string") {
|
|
261
|
+
return { ok: false, reason: "malformed" };
|
|
262
|
+
}
|
|
263
|
+
const pinnedKey = keyset.keys.find((key2) => key2.kid === wire.kid);
|
|
264
|
+
const key = pinnedKey ? ed25519PublicKey(pinnedKey.publicKeySpkiB64) : null;
|
|
265
|
+
if (!key)
|
|
266
|
+
return { ok: false, reason: "unknown_key" };
|
|
267
|
+
if (!verifySignature(PERSONAL_DATA_EXECUTOR_LEASE_SIGNING_DOMAIN, wire.payload, wire.sig, key)) {
|
|
268
|
+
return { ok: false, reason: "signature" };
|
|
269
|
+
}
|
|
270
|
+
let parsed;
|
|
271
|
+
try {
|
|
272
|
+
parsed = JSON.parse(wire.payload);
|
|
273
|
+
} catch {
|
|
274
|
+
return { ok: false, reason: "malformed" };
|
|
275
|
+
}
|
|
276
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
277
|
+
return { ok: false, reason: "malformed" };
|
|
278
|
+
}
|
|
279
|
+
const payload = parsed;
|
|
280
|
+
const issuedAt = payload.issuedAt;
|
|
281
|
+
const expiresAt = payload.expiresAt;
|
|
282
|
+
const capabilities = canonicalExecutorCapabilities(payload.capabilities);
|
|
283
|
+
if (payload.v !== 1 || !isExecutorLeaseId(payload.leaseId) || !isExecutorLeaseText(payload.daemonId) || !isExecutorLeaseId(payload.daemonInstanceId) || !isExecutorLeaseText(payload.ownerUserId) || !capabilities || typeof issuedAt !== "number" || typeof expiresAt !== "number" || !Number.isSafeInteger(issuedAt) || !Number.isSafeInteger(expiresAt)) {
|
|
284
|
+
return { ok: false, reason: "malformed" };
|
|
285
|
+
}
|
|
286
|
+
const expectedCapabilities = canonicalExecutorCapabilities(expected.capabilities);
|
|
287
|
+
if (!expectedCapabilities || capabilities.join("\0") !== expectedCapabilities.join("\0")) {
|
|
288
|
+
return { ok: false, reason: "capabilities" };
|
|
289
|
+
}
|
|
290
|
+
if (payload.daemonId !== expected.daemonId || payload.daemonInstanceId !== expected.daemonInstanceId) {
|
|
291
|
+
return { ok: false, reason: "daemon_binding" };
|
|
292
|
+
}
|
|
293
|
+
const now = expected.now ?? Date.now();
|
|
294
|
+
if (expiresAt <= issuedAt || expiresAt - issuedAt > MAX_EXECUTOR_LEASE_TTL_MS || issuedAt > now + EXECUTOR_LEASE_CLOCK_SKEW_MS) {
|
|
295
|
+
return { ok: false, reason: "window" };
|
|
296
|
+
}
|
|
297
|
+
if (expiresAt <= now)
|
|
298
|
+
return { ok: false, reason: "expired" };
|
|
299
|
+
return {
|
|
300
|
+
ok: true,
|
|
301
|
+
leaseId: payload.leaseId,
|
|
302
|
+
ownerUserId: payload.ownerUserId,
|
|
303
|
+
expiresAt
|
|
304
|
+
};
|
|
305
|
+
}
|
|
202
306
|
function verifySignedToolApproval(approval, call, keyset) {
|
|
203
307
|
if (approval === void 0 || approval === null)
|
|
204
308
|
return { ok: false, reason: "absent" };
|
|
@@ -271,8 +375,10 @@ function verifyToolApprovalAttestation(approval, call, pin) {
|
|
|
271
375
|
canonicalApprovalKeysetText,
|
|
272
376
|
endorseApprovalKeysetText,
|
|
273
377
|
parseApprovalKeysetText,
|
|
378
|
+
signPersonalDataExecutorLease,
|
|
274
379
|
signToolApproval,
|
|
275
380
|
verifyApprovalKeysetDocument,
|
|
381
|
+
verifyPersonalDataExecutorLease,
|
|
276
382
|
verifySignedToolApproval,
|
|
277
383
|
verifyToolApprovalAttestation
|
|
278
384
|
});
|
|
@@ -185,6 +185,14 @@ export type DaemonComputerEventKey = keyof typeof DAEMON_COMPUTER_EVENTS;
|
|
|
185
185
|
export type DaemonComputerEventName = (typeof DAEMON_COMPUTER_EVENTS)[DaemonComputerEventKey];
|
|
186
186
|
export declare const COMPUTER_EVENT_NAMES: readonly ComputerEventName[];
|
|
187
187
|
export declare const DAEMON_COMPUTER_EVENT_NAMES: readonly DaemonComputerEventName[];
|
|
188
|
+
/**
|
|
189
|
+
* API → daemon: an authorized person observes, configures, stops or recovers
|
|
190
|
+
* the machine's Computer Use provider. Answered with `daemon:computer:ack`. It
|
|
191
|
+
* is deliberately outside `DAEMON_COMPUTER_EVENTS`, which lists the events the
|
|
192
|
+
* attachment protocol itself speaks, so the registry parity over that table
|
|
193
|
+
* does not move.
|
|
194
|
+
*/
|
|
195
|
+
export declare const DAEMON_COMPUTER_USE_CONTROL_EVENT: "daemon:computer:use-control";
|
|
188
196
|
/** The daemon → API events; every other `daemon:computer:*` event flows API → daemon. */
|
|
189
197
|
export declare const DAEMON_COMPUTER_REPORT_EVENT_KEYS: readonly ["ack", "manifest", "data", "activity", "detached", "filesChanged", "diagnostics"];
|
|
190
198
|
/** The API → client events; every other `computer:*` event flows client → API. */
|
|
@@ -362,7 +370,7 @@ export declare const COMPUTER_CAPABILITY_VALUES: [ComputerCapability, ...Compute
|
|
|
362
370
|
* Every refusal and limit the computer protocol can answer with. Callers branch
|
|
363
371
|
* on the code; a message beside it is free text and may change.
|
|
364
372
|
*/
|
|
365
|
-
export declare const COMPUTER_REFUSAL_CODES: readonly ["human_control", "stale_epoch", "stale_generation", "file_changed", "capability_missing", "unauthorized", "control_denied", "not_holder", "attachment_limit", "observer_limit", "watch_limit", "grant_limit", "browser_limit", "rate_limited", "not_found", "surface_ended", "machine_unavailable", "daemon_unreachable", "relay_error", "timeout", "invalid_request", "consent_missing", "path_withheld", "too_large", "service_limit"];
|
|
373
|
+
export declare const COMPUTER_REFUSAL_CODES: readonly ["human_control", "stale_epoch", "stale_generation", "file_changed", "capability_missing", "unauthorized", "control_denied", "not_holder", "attachment_limit", "observer_limit", "watch_limit", "grant_limit", "browser_limit", "rate_limited", "not_found", "surface_ended", "machine_unavailable", "daemon_unreachable", "relay_error", "timeout", "invalid_request", "consent_missing", "path_withheld", "too_large", "service_limit", "maintenance_hold"];
|
|
366
374
|
export type ComputerRefusalCode = (typeof COMPUTER_REFUSAL_CODES)[number];
|
|
367
375
|
/**
|
|
368
376
|
* The code when it is a computer refusal, else `null`. There is one spelling
|