@skrr-ai/cli 0.1.128 → 0.1.130

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.
Files changed (103) hide show
  1. package/dist/base-command.d.ts +12 -0
  2. package/dist/base-command.js +65 -0
  3. package/dist/commands/agenda/trigger/create.js +9 -1
  4. package/dist/commands/agenda/trigger/list.d.ts +2 -1
  5. package/dist/commands/agenda/trigger/list.js +55 -6
  6. package/dist/commands/agents/create.js +3 -1
  7. package/dist/commands/agents/reflect.d.ts +6 -0
  8. package/dist/commands/agents/reflect.js +45 -6
  9. package/dist/commands/agents/schedule-overview.d.ts +17 -0
  10. package/dist/commands/agents/schedule-overview.js +33 -9
  11. package/dist/commands/agents/triggers/policy.js +3 -1
  12. package/dist/commands/browser/persistent-profile.d.ts +22 -0
  13. package/dist/commands/browser/persistent-profile.js +46 -0
  14. package/dist/commands/commitments/create.js +3 -1
  15. package/dist/commands/commitments/effective-policy.js +6 -0
  16. package/dist/commands/commitments/explain.js +10 -1
  17. package/dist/commands/commitments/plan.d.ts +14 -0
  18. package/dist/commands/commitments/plan.js +32 -0
  19. package/dist/commands/commitments/preflight.d.ts +1 -1
  20. package/dist/commands/commitments/preflight.js +12 -4
  21. package/dist/commands/commitments/show.d.ts +9 -0
  22. package/dist/commands/commitments/show.js +14 -1
  23. package/dist/commands/compass/revisions.d.ts +6 -2
  24. package/dist/commands/compass/revisions.js +13 -5
  25. package/dist/commands/compass/tactic.d.ts +5 -0
  26. package/dist/commands/compass/tactic.js +14 -0
  27. package/dist/commands/followups/plans/create.js +1 -1
  28. package/dist/commands/harnesses/list.js +1 -1
  29. package/dist/commands/northstars/create.js +6 -1
  30. package/dist/commands/northstars/governance/configure.js +1 -1
  31. package/dist/commands/northstars/intents/decide.js +2 -3
  32. package/dist/commands/northstars/list.js +1 -1
  33. package/dist/commands/northstars/review-now.js +5 -0
  34. package/dist/commands/northstars/reviews.js +15 -3
  35. package/dist/commands/northstars/show.js +1 -1
  36. package/dist/commands/spaces/auto-executor/runs.d.ts +9 -1
  37. package/dist/commands/spaces/auto-executor/runs.js +18 -1
  38. package/dist/commands/spaces/heartbeats/create.js +7 -5
  39. package/dist/commands/spaces/heartbeats/status.js +10 -0
  40. package/dist/commands/spaces/heartbeats/update.js +5 -3
  41. package/dist/commands/store/artifacts/releases.d.ts +20 -0
  42. package/dist/commands/store/artifacts/releases.js +85 -0
  43. package/dist/commands/store/library.d.ts +14 -0
  44. package/dist/commands/store/library.js +71 -0
  45. package/dist/commands/tasks/archive.js +6 -0
  46. package/dist/commands/tasks/list.d.ts +48 -0
  47. package/dist/commands/tasks/list.js +141 -9
  48. package/dist/commands/tasks/pause-schedule.js +1 -1
  49. package/dist/commands/tasks/remind.js +23 -11
  50. package/dist/commands/tasks/resume-schedule.js +4 -1
  51. package/dist/commands/tasks/retry-schedule.js +6 -3
  52. package/dist/commands/tasks/schedule.js +35 -8
  53. package/dist/commands/tasks/self-schedule.d.ts +56 -0
  54. package/dist/commands/tasks/self-schedule.js +179 -21
  55. package/dist/commands/tasks/show.js +4 -0
  56. package/dist/lib/agent-trigger-listing.d.ts +26 -0
  57. package/dist/lib/agent-trigger-listing.js +63 -0
  58. package/dist/lib/agentic-stream.js +138 -41
  59. package/dist/lib/commitment-ledgers.js +3 -1
  60. package/dist/lib/commitments.d.ts +24 -0
  61. package/dist/lib/commitments.js +64 -4
  62. package/dist/lib/compasses.d.ts +2 -0
  63. package/dist/lib/iso-instant.d.ts +52 -0
  64. package/dist/lib/iso-instant.js +162 -0
  65. package/dist/lib/northstars.d.ts +87 -4
  66. package/dist/lib/northstars.js +226 -94
  67. package/dist/lib/proposals.js +6 -2
  68. package/dist/lib/reflection.d.ts +58 -0
  69. package/dist/lib/reflection.js +115 -6
  70. package/dist/lib/store-artifact-releases.d.ts +39 -0
  71. package/dist/lib/store-artifact-releases.js +12 -0
  72. package/dist/lib/store-library.d.ts +37 -0
  73. package/dist/lib/store-library.js +12 -0
  74. package/dist/lib/task-calendar.d.ts +19 -0
  75. package/dist/lib/task-calendar.js +72 -0
  76. package/dist/lib/task-operations.js +2 -0
  77. package/dist/lib/task-recurrence-outcome.js +3 -1
  78. package/dist/lib/task-recurrence-summary.d.ts +15 -0
  79. package/dist/lib/task-recurrence-summary.js +228 -0
  80. package/dist/lib/task-reminder.d.ts +28 -0
  81. package/dist/lib/task-reminder.js +50 -0
  82. package/dist/lib/task-schedule-notes.d.ts +46 -0
  83. package/dist/lib/task-schedule-notes.js +71 -0
  84. package/dist/lib/triggers.d.ts +31 -2
  85. package/dist/lib/triggers.js +38 -18
  86. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.js +11 -1
  87. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.d.ts +9 -0
  88. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +22 -0
  89. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.d.ts +123 -0
  90. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.js +160 -0
  91. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -1
  92. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +19 -0
  93. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.js +11 -1
  94. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.d.ts +9 -0
  95. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +28 -0
  96. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.d.ts +123 -0
  97. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.js +173 -0
  98. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -1
  99. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +3 -1
  100. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  101. package/dist/node_modules/@skrr-ai/data-provider/index.js +6772 -6675
  102. package/oclif.manifest.json +282 -40
  103. package/package.json +1 -1
@@ -0,0 +1,160 @@
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 executorStopReceipt_exports = {};
20
+ __export(executorStopReceipt_exports, {
21
+ EXECUTOR_STOP_RECEIPT_DEFAULT_MAX_AGE_SECONDS: () => EXECUTOR_STOP_RECEIPT_DEFAULT_MAX_AGE_SECONDS,
22
+ EXECUTOR_STOP_RECEIPT_ERASURE_SCOPES: () => EXECUTOR_STOP_RECEIPT_ERASURE_SCOPES,
23
+ EXECUTOR_STOP_RECEIPT_TYP: () => EXECUTOR_STOP_RECEIPT_TYP,
24
+ canonicalReceiptJson: () => canonicalReceiptJson,
25
+ executorStopReceiptHtu: () => executorStopReceiptHtu,
26
+ parseExecutorStopReceiptBody: () => parseExecutorStopReceiptBody,
27
+ signExecutorStopReceipt: () => signExecutorStopReceipt,
28
+ verifyExecutorStopReceipt: () => verifyExecutorStopReceipt
29
+ });
30
+ module.exports = __toCommonJS(executorStopReceipt_exports);
31
+ var import_deviceKey = require("./deviceKey.js");
32
+ const EXECUTOR_STOP_RECEIPT_TYP = "skrr-executor-stop-receipt+jwt";
33
+ const EXECUTOR_STOP_RECEIPT_ERASURE_SCOPES = ["session_temp"];
34
+ const EXECUTOR_STOP_RECEIPT_DEFAULT_MAX_AGE_SECONDS = 24 * 60 * 60;
35
+ const MAX_ID_LENGTH = 160;
36
+ const BODY_KEYS = [
37
+ "version",
38
+ "daemonId",
39
+ "sourceId",
40
+ "sessionId",
41
+ "requestId",
42
+ "dispatchId",
43
+ "status",
44
+ "stoppedAt",
45
+ "descendants",
46
+ "erasure"
47
+ ];
48
+ const BINDING_KEYS = ["daemonId", "sourceId", "sessionId", "requestId", "dispatchId"];
49
+ const isPlainObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
50
+ const hasExactKeys = (value, keys) => Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
51
+ const isId = (value) => typeof value === "string" && value.length > 0 && value.length <= MAX_ID_LENGTH;
52
+ const isCount = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
53
+ function canonicalReceiptJson(value) {
54
+ if (value === null || typeof value !== "object")
55
+ return JSON.stringify(value);
56
+ if (Array.isArray(value))
57
+ return `[${value.map(canonicalReceiptJson).join(",")}]`;
58
+ const record = value;
59
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonicalReceiptJson(record[key])}`).join(",")}}`;
60
+ }
61
+ function executorStopReceiptHtu(dispatchId) {
62
+ return `https://executor-stop-receipt.skrr.invalid/v1/${encodeURIComponent(dispatchId)}`;
63
+ }
64
+ function parseExecutorStopReceiptBody(value) {
65
+ if (!isPlainObject(value) || !hasExactKeys(value, BODY_KEYS) || value.version !== 1)
66
+ return null;
67
+ if (!BINDING_KEYS.every((key) => isId(value[key])))
68
+ return null;
69
+ if (value.status !== "completed" && value.status !== "failed" && value.status !== "cancelled")
70
+ return null;
71
+ if (typeof value.stoppedAt !== "string" || Number.isNaN(Date.parse(value.stoppedAt)))
72
+ return null;
73
+ const d = value.descendants;
74
+ if (!isPlainObject(d) || !hasExactKeys(d, ["observed", "stopped", "survivors"]))
75
+ return null;
76
+ if (!isCount(d.observed) || !isCount(d.stopped) || !isCount(d.survivors))
77
+ return null;
78
+ if (d.observed !== d.stopped + d.survivors)
79
+ return null;
80
+ const e = value.erasure;
81
+ if (!isPlainObject(e))
82
+ return null;
83
+ if (e.performed === false) {
84
+ if (!hasExactKeys(e, ["performed"]))
85
+ return null;
86
+ } else if (e.performed === true) {
87
+ if (!hasExactKeys(e, ["performed", "scope", "artifacts", "bytes"]))
88
+ return null;
89
+ if (!EXECUTOR_STOP_RECEIPT_ERASURE_SCOPES.includes(e.scope))
90
+ return null;
91
+ if (!isCount(e.artifacts) || !isCount(e.bytes))
92
+ return null;
93
+ } else {
94
+ return null;
95
+ }
96
+ return value;
97
+ }
98
+ async function signExecutorStopReceipt(signer, body, options = {}) {
99
+ const parsed = parseExecutorStopReceiptBody(body);
100
+ if (!parsed)
101
+ throw new Error("signExecutorStopReceipt: body is not a v1 executor stop receipt body");
102
+ const proof = await (0, import_deviceKey.signProofWith)(signer, {
103
+ method: "POST",
104
+ url: executorStopReceiptHtu(parsed.dispatchId),
105
+ // `accessToken` is hashed inline into the `ath` claim: the commitment to the body.
106
+ accessToken: canonicalReceiptJson(parsed),
107
+ ...options.iat !== void 0 ? { iat: options.iat } : {},
108
+ ...options.jti !== void 0 ? { jti: options.jti } : {}
109
+ }, EXECUTOR_STOP_RECEIPT_TYP);
110
+ return { body: parsed, proof };
111
+ }
112
+ function verifyExecutorStopReceipt(receipt, options) {
113
+ if (!isPlainObject(receipt) || !hasExactKeys(receipt, ["body", "proof"])) {
114
+ return { valid: false, reason: "bad_receipt" };
115
+ }
116
+ const body = parseExecutorStopReceiptBody(receipt.body);
117
+ if (!body || typeof receipt.proof !== "string")
118
+ return { valid: false, reason: "bad_receipt" };
119
+ const pin = options.pinnedPublicJwk;
120
+ if (!pin || !(0, import_deviceKey.isDevicePublicJwk)(pin))
121
+ return { valid: false, reason: "no_pin" };
122
+ const result = (0, import_deviceKey.verifyDevicePublicKeyProof)(receipt.proof, {
123
+ expectedHtm: "POST",
124
+ expectedHtu: executorStopReceiptHtu(body.dispatchId),
125
+ expectedAth: (0, import_deviceKey.tokenHash)(canonicalReceiptJson(body)),
126
+ pinnedPublicJwk: pin,
127
+ // The algorithm of the PIN, never a list: a receipt cannot pick a weaker one.
128
+ allowedAlgs: [(0, import_deviceKey.algForJwk)(pin)],
129
+ maxAgeSeconds: options.maxAgeSeconds ?? EXECUTOR_STOP_RECEIPT_DEFAULT_MAX_AGE_SECONDS,
130
+ ...options.clockSkewSeconds !== void 0 ? { clockSkewSeconds: options.clockSkewSeconds } : {},
131
+ ...options.now !== void 0 ? { now: options.now } : {}
132
+ }, EXECUTOR_STOP_RECEIPT_TYP);
133
+ if (!result.valid)
134
+ return { valid: false, reason: result.reason };
135
+ for (const key of BINDING_KEYS) {
136
+ const want = options.expected?.[key];
137
+ if (want !== void 0 && body[key] !== want)
138
+ return { valid: false, reason: "binding_mismatch" };
139
+ }
140
+ if (body.descendants.survivors > 0)
141
+ return { valid: false, reason: "not_quiescent" };
142
+ return {
143
+ valid: true,
144
+ body,
145
+ alg: result.alg,
146
+ thumbprint: (0, import_deviceKey.jwkThumbprint)(result.publicJwk),
147
+ signedAtSeconds: result.claims.iat
148
+ };
149
+ }
150
+ // Annotate the CommonJS export names for ESM import in node:
151
+ 0 && (module.exports = {
152
+ EXECUTOR_STOP_RECEIPT_DEFAULT_MAX_AGE_SECONDS,
153
+ EXECUTOR_STOP_RECEIPT_ERASURE_SCOPES,
154
+ EXECUTOR_STOP_RECEIPT_TYP,
155
+ canonicalReceiptJson,
156
+ executorStopReceiptHtu,
157
+ parseExecutorStopReceiptBody,
158
+ signExecutorStopReceipt,
159
+ verifyExecutorStopReceipt
160
+ });
@@ -28,12 +28,13 @@ export { buildCredentialAad, decrypt as credEnvelopeDecrypt, deserialize as cred
28
28
  export { __setKekStrategyForTest, getKekStrategy, InMemoryKek, UnavailableKek, KekUnavailableError, classifyDaemonKeychainService, isMasterKekKeychainService, isSessionKeychainService, isUserOwnedSecretKeychainService, LinuxKek, MacosKek, MASTER_KEK_KEYCHAIN_ACCOUNT, MASTER_KEK_KEYCHAIN_SERVICE, registerZeroizeHook, WindowsKek, zeroizeKekCaches, type DaemonKeychainServiceClass, type KekStrategy, } from './kek/index.js';
29
29
  export { ALLOW_LIVE_STATE_ENV, __setAccountHomeForTest, DAEMON_BYOK_KEYCHAIN_SERVICE_BASE, DAEMON_KEYCHAIN_SERVICE_BASE, HERMETIC_HOME_ENV, LEGACY_DAEMON_KEYCHAIN_SERVICE, LIVE_DEFAULT_PROFILE, LIVE_STATE_REFUSED_CODE, LiveStateRefusedError, accountHomeDir, assertMayMutateLiveKeychain, assertMayMutateLiveState, isLiveKeychainService, isLiveStateRefusal, isTestProcess, keychainSuffixForDir, liveKeychainServices, liveStateRoot, refusesLiveKeychainMutation, refusesLiveStateInTest, rethrowIfLiveStateRefusal, testProcessSignal, type LiveKeychainProbe, type LiveStateProbe, } from './liveState.js';
30
30
  export { algForJwk, buildProof as buildDeviceProof, DEVICE_KEY_ALGS, generateDeviceKeyPair, isDevicePublicJwk, jwkThumbprint, normalizeHtu, p256PublicJwkFromRaw, proofSigningInput, publicJwkFromX, signProofWith, tokenHash, verifyProof as verifyDeviceProof, type DeviceKeyAlg, type DeviceKeyPair, type DeviceKeySigner, type DevicePublicJwk, type DeviceProofClaims, type DeviceProofHeader, type Ed25519PrivateJwk, type Ed25519PublicJwk, type P256PublicJwk, type VerifyFailureReason as DeviceProofVerifyFailureReason, type VerifyFailure as DeviceProofVerifyFailure, type VerifyOptions as DeviceProofVerifyOptions, type VerifySuccess as DeviceProofVerifySuccess, } from './deviceKey.js';
31
+ export { canonicalReceiptJson, EXECUTOR_STOP_RECEIPT_DEFAULT_MAX_AGE_SECONDS, EXECUTOR_STOP_RECEIPT_ERASURE_SCOPES, EXECUTOR_STOP_RECEIPT_TYP, executorStopReceiptHtu, parseExecutorStopReceiptBody, signExecutorStopReceipt, verifyExecutorStopReceipt, type ExecutorStopReceipt, type ExecutorStopReceiptBody, type ExecutorStopReceiptErasureScope, type ExecutorStopReceiptFailureReason, type ExecutorStopReceiptStatus, type SignExecutorStopReceiptOptions, type VerifyExecutorStopReceiptOptions, type VerifyExecutorStopReceiptResult, } from './executorStopReceipt.js';
31
32
  export { softwareEd25519Handle, type DeviceKeyCustody, type DeviceKeyHandle } from './deviceKeyHandle.js';
32
33
  export { AUTH_SERVER_METADATA_PATH, readServerDeviceKeyAlgs, SERVER_DEVICE_KEY_ALGS_FIELD, } from './deviceKeyServerSupport.js';
33
34
  export { configureHardwareDeviceKeyHelper, HARDWARE_KEY_HELPER_NAME, HardwareDeviceKeyError, probeHardwareDeviceKey, resolveHardwareDeviceKeyHelper, type HardwareDeviceKeyErrorCode, type HardwareKeyCapability, } from './deviceKeyHardware.js';
34
35
  export { DPOP_HEADER, DPOP_MAX_AGE_SECONDS, DPOP_PROOF_INVALID, DPOP_PROOF_REQUIRED, DPOP_PROOF_TYP, DPOP_PROOF_VERIFY_UNAVAILABLE, accessTokenHash, createDpopKey, isAth, isJwkThumbprint, normalizeDpopHtu, verifyDpopProof, type DpopKey, type DpopProofClaims, type DpopProofRequest, type DpopVerifyFailureReason, type DpopVerifyOptions, type DpopVerifyResult, } from './dpop.js';
35
36
  export { initCredEnvelope, initExistingCredEnvelope, initNewIndependentCredEnvelope, resetCredEnvelope, shutdownCredEnvelope, isCredEnvelopeActive, hasCredEnvelopePathConflict, describeCredEnvelopeState, splitKeyConvergencePolicy, maybeEncryptForWrite, maybeDecryptOnRead, DEFAULT_UNREADABLE_CREDENTIAL_HINT, type DecryptOnReadOptions, __wrappedDekFilePathForTest, __setStateForTest as __setCredEnvelopeStateForTest, __getStateForTest as __getCredEnvelopeStateForTest, __resetShutdownGuardForTest, type ReadTransformResult, } from './credentialEnvelopeBridge.js';
36
- export { initDeviceIdentity, resetDeviceIdentity, signServerRequest, prepareHardwareKeyCandidate, commitDeviceKeyCandidate, signWithCandidate, persistPendingHardwareKey, commitPendingHardwareKey, discardPendingHardwareKey, PENDING_HARDWARE_KEY_MAX_AGE_MS, type DeviceKeyCandidate, type DeviceKeyCandidateResult, type PendingHardwareKeyOutcome, enrollWithServer, clearEnrollmentMarker, isDeviceIdentityActive, getDevicePublicKey, describeDeviceIdentityState, describeDeviceKeySplit, describeStoredDeviceKey, DEVICE_KEY_UNREADABLE_CREDENTIAL_HINT, type StoredDeviceKeyDescription, __publicKeyPathForTest, __privateKeyPathForTest, __enrollmentMarkerPathForTest, __enrollmentBackoffPathForTest, __setUnreadableReloadIntervalForTest, __setStateForTest as __setDeviceIdentityStateForTest, __getStateForTest as __getDeviceIdentityStateForTest, type EnrollmentResult, } from './deviceIdentityBridge.js';
37
+ export { initDeviceIdentity, resetDeviceIdentity, signServerRequest, signExecutorStopReceiptWithDeviceKey, prepareHardwareKeyCandidate, commitDeviceKeyCandidate, signWithCandidate, persistPendingHardwareKey, commitPendingHardwareKey, discardPendingHardwareKey, PENDING_HARDWARE_KEY_MAX_AGE_MS, type DeviceKeyCandidate, type DeviceKeyCandidateResult, type PendingHardwareKeyOutcome, enrollWithServer, clearEnrollmentMarker, isDeviceIdentityActive, getDevicePublicKey, describeDeviceIdentityState, describeDeviceKeySplit, describeStoredDeviceKey, DEVICE_KEY_UNREADABLE_CREDENTIAL_HINT, type StoredDeviceKeyDescription, __publicKeyPathForTest, __privateKeyPathForTest, __enrollmentMarkerPathForTest, __enrollmentBackoffPathForTest, __setUnreadableReloadIntervalForTest, __setStateForTest as __setDeviceIdentityStateForTest, __getStateForTest as __getDeviceIdentityStateForTest, type EnrollmentResult, } from './deviceIdentityBridge.js';
37
38
  export { getMachineUuid, getMachineUuidForProfile, describeMachineIdentity, type MachineIdentityDescription, type MachineIdentityReason, getHardwareMachineUuid, setMachineUuidProfile, getMachineUuidProfile, qualifyMachineUuid, MACHINE_IDENTITY_FILENAME, hostedRuntimeIdOverride, HOSTED_RUNTIME_MACHINE_SOURCES, __resetMachineUuidCacheForTest, } from './machineUuid.js';
38
39
  export { ensureMachineDaemonId, legacyDaemonUuids, __resetCachedDaemonIdForTest, } from './machineId.js';
39
40
  export { PAIR_AAD_PREFIX, PAIR_AAD_MAX_LEN, PAIR_BUNDLE_MAX_BASE64_LEN, PAIR_NONCE_LEN, PAIR_PUBKEY_LEN, PAIR_SECRET_LEN, PairBundleError, assemblePairBundleBase64, base64ToUint8Array as pairBase64ToUint8Array, base64UrlToUint8Array as pairBase64UrlToUint8Array, buildPairAad, buildPairUrl, generatePairKeyPair, openPairBundleBase64, parsePairBundle, parsePairPlaintext, parsePairUrl, uint8ArrayToBase64 as pairUint8ArrayToBase64, uint8ArrayToBase64Url as pairUint8ArrayToBase64Url, type AssembleBundleOptions as PairAssembleBundleOptions, type OpenBundleOptions as PairOpenBundleOptions, type PairBundle, type PairBundleErrorCode, type PairKeyPair, type PairPlaintextV1, type PairUrlFields, } from './daemonPair.js';
@@ -46,6 +46,9 @@ __export(index_exports, {
46
46
  DPOP_PROOF_REQUIRED: () => import_dpop.DPOP_PROOF_REQUIRED,
47
47
  DPOP_PROOF_TYP: () => import_dpop.DPOP_PROOF_TYP,
48
48
  DPOP_PROOF_VERIFY_UNAVAILABLE: () => import_dpop.DPOP_PROOF_VERIFY_UNAVAILABLE,
49
+ EXECUTOR_STOP_RECEIPT_DEFAULT_MAX_AGE_SECONDS: () => import_executorStopReceipt.EXECUTOR_STOP_RECEIPT_DEFAULT_MAX_AGE_SECONDS,
50
+ EXECUTOR_STOP_RECEIPT_ERASURE_SCOPES: () => import_executorStopReceipt.EXECUTOR_STOP_RECEIPT_ERASURE_SCOPES,
51
+ EXECUTOR_STOP_RECEIPT_TYP: () => import_executorStopReceipt.EXECUTOR_STOP_RECEIPT_TYP,
49
52
  EXIT_NEEDS_REAUTH: () => import_messages.EXIT_NEEDS_REAUTH,
50
53
  FIRST_PARTY_HARNESS_CHANNELS: () => import_firstPartyHarnessChannels.FIRST_PARTY_HARNESS_CHANNELS,
51
54
  FIRST_PARTY_HARNESS_PREVIOUS_SUFFIX: () => import_firstPartyHarnessHome.FIRST_PARTY_HARNESS_PREVIOUS_SUFFIX,
@@ -148,6 +151,7 @@ __export(index_exports, {
148
151
  buildManifestMessage: () => import_releaseManifest.buildManifestMessage,
149
152
  buildPairAad: () => import_daemonPair.buildPairAad,
150
153
  buildPairUrl: () => import_daemonPair.buildPairUrl,
154
+ canonicalReceiptJson: () => import_executorStopReceipt.canonicalReceiptJson,
151
155
  challenge: () => import_pkce.challenge,
152
156
  classifyDaemonKeychainService: () => import_kek.classifyDaemonKeychainService,
153
157
  classifyRefreshResponse: () => import_refreshClassification.classifyRefreshResponse,
@@ -186,6 +190,7 @@ __export(index_exports, {
186
190
  enrollWithServer: () => import_deviceIdentityBridge.enrollWithServer,
187
191
  ensureMachineDaemonId: () => import_machineId.ensureMachineDaemonId,
188
192
  envHasProxy: () => import_spawnEnv.envHasProxy,
193
+ executorStopReceiptHtu: () => import_executorStopReceipt.executorStopReceiptHtu,
189
194
  findLegacyLocalState: () => import_legacyStatePreflight.findLegacyLocalState,
190
195
  firstPartyHarnessBinDir: () => import_firstPartyHarnessHome.firstPartyHarnessBinDir,
191
196
  firstPartyHarnessChannelPrefix: () => import_firstPartyHarnessChannels.firstPartyHarnessChannelPrefix,
@@ -270,6 +275,7 @@ __export(index_exports, {
270
275
  pairBase64UrlToUint8Array: () => import_daemonPair.base64UrlToUint8Array,
271
276
  pairUint8ArrayToBase64: () => import_daemonPair.uint8ArrayToBase64,
272
277
  pairUint8ArrayToBase64Url: () => import_daemonPair.uint8ArrayToBase64Url,
278
+ parseExecutorStopReceiptBody: () => import_executorStopReceipt.parseExecutorStopReceiptBody,
273
279
  parsePairBundle: () => import_daemonPair.parsePairBundle,
274
280
  parsePairPlaintext: () => import_daemonPair.parsePairPlaintext,
275
281
  parsePairUrl: () => import_daemonPair.parsePairUrl,
@@ -309,6 +315,8 @@ __export(index_exports, {
309
315
  sanitizeSpawnEnv: () => import_spawnEnv.sanitizeSpawnEnv,
310
316
  setMachineUuidProfile: () => import_machineUuid.setMachineUuidProfile,
311
317
  shutdownCredEnvelope: () => import_credentialEnvelopeBridge.shutdownCredEnvelope,
318
+ signExecutorStopReceipt: () => import_executorStopReceipt.signExecutorStopReceipt,
319
+ signExecutorStopReceiptWithDeviceKey: () => import_deviceIdentityBridge.signExecutorStopReceiptWithDeviceKey,
312
320
  signProofWith: () => import_deviceKey.signProofWith,
313
321
  signServerRequest: () => import_deviceIdentityBridge.signServerRequest,
314
322
  signWithCandidate: () => import_deviceIdentityBridge.signWithCandidate,
@@ -322,6 +330,7 @@ __export(index_exports, {
322
330
  verifyChallenge: () => import_pkce.verifyChallenge,
323
331
  verifyDeviceProof: () => import_deviceKey.verifyProof,
324
332
  verifyDpopProof: () => import_dpop.verifyDpopProof,
333
+ verifyExecutorStopReceipt: () => import_executorStopReceipt.verifyExecutorStopReceipt,
325
334
  verifyIndependentMachineReservation: () => import_independentMachineReservation.verifyIndependentMachineReservation,
326
335
  verifyManifest: () => import_releaseManifest.verifyManifest,
327
336
  withAuthLock: () => import_refresh.withAuthLock,
@@ -351,6 +360,7 @@ var import_credentialEnvelope = require("./credentialEnvelope.js");
351
360
  var import_kek = require("./kek/index.js");
352
361
  var import_liveState = require("./liveState.js");
353
362
  var import_deviceKey = require("./deviceKey.js");
363
+ var import_executorStopReceipt = require("./executorStopReceipt.js");
354
364
  var import_deviceKeyHandle = require("./deviceKeyHandle.js");
355
365
  var import_deviceKeyServerSupport = require("./deviceKeyServerSupport.js");
356
366
  var import_deviceKeyHardware = require("./deviceKeyHardware.js");
@@ -407,6 +417,9 @@ var import_independentMachineReservation = require("./independentMachineReservat
407
417
  DPOP_PROOF_REQUIRED,
408
418
  DPOP_PROOF_TYP,
409
419
  DPOP_PROOF_VERIFY_UNAVAILABLE,
420
+ EXECUTOR_STOP_RECEIPT_DEFAULT_MAX_AGE_SECONDS,
421
+ EXECUTOR_STOP_RECEIPT_ERASURE_SCOPES,
422
+ EXECUTOR_STOP_RECEIPT_TYP,
410
423
  EXIT_NEEDS_REAUTH,
411
424
  FIRST_PARTY_HARNESS_CHANNELS,
412
425
  FIRST_PARTY_HARNESS_PREVIOUS_SUFFIX,
@@ -509,6 +522,7 @@ var import_independentMachineReservation = require("./independentMachineReservat
509
522
  buildManifestMessage,
510
523
  buildPairAad,
511
524
  buildPairUrl,
525
+ canonicalReceiptJson,
512
526
  challenge,
513
527
  classifyDaemonKeychainService,
514
528
  classifyRefreshResponse,
@@ -547,6 +561,7 @@ var import_independentMachineReservation = require("./independentMachineReservat
547
561
  enrollWithServer,
548
562
  ensureMachineDaemonId,
549
563
  envHasProxy,
564
+ executorStopReceiptHtu,
550
565
  findLegacyLocalState,
551
566
  firstPartyHarnessBinDir,
552
567
  firstPartyHarnessChannelPrefix,
@@ -631,6 +646,7 @@ var import_independentMachineReservation = require("./independentMachineReservat
631
646
  pairBase64UrlToUint8Array,
632
647
  pairUint8ArrayToBase64,
633
648
  pairUint8ArrayToBase64Url,
649
+ parseExecutorStopReceiptBody,
634
650
  parsePairBundle,
635
651
  parsePairPlaintext,
636
652
  parsePairUrl,
@@ -670,6 +686,8 @@ var import_independentMachineReservation = require("./independentMachineReservat
670
686
  sanitizeSpawnEnv,
671
687
  setMachineUuidProfile,
672
688
  shutdownCredEnvelope,
689
+ signExecutorStopReceipt,
690
+ signExecutorStopReceiptWithDeviceKey,
673
691
  signProofWith,
674
692
  signServerRequest,
675
693
  signWithCandidate,
@@ -683,6 +701,7 @@ var import_independentMachineReservation = require("./independentMachineReservat
683
701
  verifyChallenge,
684
702
  verifyDeviceProof,
685
703
  verifyDpopProof,
704
+ verifyExecutorStopReceipt,
686
705
  verifyIndependentMachineReservation,
687
706
  verifyManifest,
688
707
  withAuthLock,
@@ -101,6 +101,7 @@ const SESSION_TURN_DIFF_LIVE = 'session_turn_diff_live_v1';
101
101
  const WORKSPACE_ISOLATION_PROBE = 'workspace_isolation_probe_v1';
102
102
  const TOOL_RESPONSE_OUTBOX = 'tool_response_outbox_v1';
103
103
  const SESSION_STEER = 'session_steer_v1';
104
+ const QUESTION_ACK = 'question_ack_v1';
104
105
  // ---------------------------------------------------------------------------
105
106
  // Connection, identity, liveness
106
107
  // ---------------------------------------------------------------------------
@@ -267,7 +268,16 @@ const SESSIONS = [
267
268
  delivery: 'acked',
268
269
  answeredBy: 'daemon:claude:question:response',
269
270
  }),
270
- toDaemon('daemon:claude:question:response', "A person's answer to a question."),
271
+ // A daemon that announces `question_ack_v1` says whether it TOOK the answer: the
272
+ // question was still pending and the harness has it ('delivered'), or the daemon had
273
+ // already timed out or been cancelled ('not_pending'). Without the capability the
274
+ // worker settles an answer at the relay handoff, as it always did.
275
+ toDaemon('daemon:claude:question:response', "A person's answer to a question.", {
276
+ delivery: 'acked',
277
+ answeredBy: 'daemon:claude:question:ack',
278
+ capability: QUESTION_ACK,
279
+ }),
280
+ toServer('daemon:claude:question:ack', "Whether this daemon took a person's answer to a question, or had already stopped waiting.", { capability: QUESTION_ACK, payload: { kind: 'zod', schema: 'daemonQuestionAckSchema' } }),
271
281
  ];
272
282
  // ---------------------------------------------------------------------------
273
283
  // Tools (the cloud agent's tool calls, proxied to the machine)
@@ -1,5 +1,6 @@
1
1
  import { type DeviceKeyAlg, type DevicePublicJwk } from './deviceKey.js';
2
2
  import { type DeviceKeyCustody, type DeviceKeyHandle } from './deviceKeyHandle.js';
3
+ import { type ExecutorStopReceipt, type ExecutorStopReceiptBody } from './executorStopReceipt.js';
3
4
  import { type HardwareKeyCapability, type HardwareKeyRecord } from './deviceKeyHardware.js';
4
5
  /**
5
6
  * The `cred_envelope.read.decrypt_failed` hint for the device PRIVATE key
@@ -235,6 +236,14 @@ export declare function signServerRequest(opts: {
235
236
  refreshToken?: string;
236
237
  accessToken?: string;
237
238
  }): Promise<string | null>;
239
+ /**
240
+ * Sign an executor stop receipt (OSK-20777 Gate 1) with the device key: the signed proof that a
241
+ * scheduled session stopped, which the server verifies against the key pinned on this machine's row.
242
+ * Returns null when device identity is not active or the key cannot sign right now. NEVER throws: a
243
+ * failed sign emits a telemetry event and the caller sends the response without a receipt, which the
244
+ * server treats as an unproven stop rather than as a failure of the session.
245
+ */
246
+ export declare function signExecutorStopReceiptWithDeviceKey(body: ExecutorStopReceiptBody): Promise<ExecutorStopReceipt | null>;
238
247
  /** @internal Test seams — file path resolvers. */
239
248
  export declare function __publicKeyPathForTest(profile: string): string;
240
249
  export declare function __privateKeyPathForTest(profile: string): string;
@@ -34,6 +34,7 @@ import path from 'node:path';
34
34
  import lockfile from 'proper-lockfile';
35
35
  import { generateDeviceKeyPair, isDevicePublicJwk, jwkThumbprint, signProofWith, } from './deviceKey.js';
36
36
  import { softwareEd25519Handle } from './deviceKeyHandle.js';
37
+ import { signExecutorStopReceipt, } from './executorStopReceipt.js';
37
38
  import { createHardwareDeviceKey, hardwareDeviceKeyHandle, parseHardwareKeyRecord, probeHardwareDeviceKey, resolveHardwareDeviceKeyHelper, serializeHardwareKeyRecord, HardwareDeviceKeyError, } from './deviceKeyHardware.js';
38
39
  import { hasCredEnvelopePathConflict, isCredEnvelopeActive, maybeDecryptOnRead, splitKeyConvergencePolicy, wrapIfActiveOrPassthrough, } from './credentialEnvelopeBridge.js';
39
40
  import { consolidateProfileState, profileStateFilePathsToClear, profileStateDir, resolveProfileStateDir, RETIRED_COPY_SUFFIX, } from './profileStateDir.js';
@@ -1133,6 +1134,33 @@ export async function signServerRequest(opts) {
1133
1134
  return null;
1134
1135
  }
1135
1136
  }
1137
+ /**
1138
+ * Sign an executor stop receipt (OSK-20777 Gate 1) with the device key: the signed proof that a
1139
+ * scheduled session stopped, which the server verifies against the key pinned on this machine's row.
1140
+ * Returns null when device identity is not active or the key cannot sign right now. NEVER throws: a
1141
+ * failed sign emits a telemetry event and the caller sends the response without a receipt, which the
1142
+ * server treats as an unproven stop rather than as a failure of the session.
1143
+ */
1144
+ export async function signExecutorStopReceiptWithDeviceKey(body) {
1145
+ reloadIfRecovered();
1146
+ const state = _state;
1147
+ if (state.kind !== 'active')
1148
+ return null;
1149
+ try {
1150
+ return await signExecutorStopReceipt(state.key, body);
1151
+ }
1152
+ catch (err) {
1153
+ emit('sign_failed', false, {
1154
+ profile: state.profile,
1155
+ thumbprint: state.key.thumbprint,
1156
+ custody: state.key.custody,
1157
+ method: 'executor_stop_receipt',
1158
+ ...(err instanceof HardwareDeviceKeyError ? { hardwareFailure: err.code } : {}),
1159
+ message: err?.message ?? 'unknown',
1160
+ });
1161
+ return null;
1162
+ }
1163
+ }
1136
1164
  /** @internal Test seams — file path resolvers. */
1137
1165
  export function __publicKeyPathForTest(profile) {
1138
1166
  return publicKeyPath(profile);
@@ -0,0 +1,123 @@
1
+ /**
2
+ * executorStopReceipt.ts — a daemon-signed proof that a scheduled session stopped.
3
+ *
4
+ * OSK-20777, Gate 1 (docs/architecture/scheduled-publication-custody-enrollment-2026-11-01.md).
5
+ * Today the executor's terminal proof is the daemon reporting about itself over its own socket: the
6
+ * dispatch tuple is checked for consistency but nothing is signed, nothing covers descendant
7
+ * processes, and nothing says what was erased. A receipt is that report, signed with the device key
8
+ * the server already pins on the daemon's row, so a settlement that depends on it depends on the
9
+ * machine and not on whoever reached the socket.
10
+ *
11
+ * No new cryptography. A receipt is a DPoP-shaped device proof (`deviceKey.ts`) under its OWN header
12
+ * `typ`, so the two can never stand in for each other: a request proof fails here with `bad_typ`, and a
13
+ * receipt fails the request verifier the same way. The proof's `ath` commits to the SHA-256 of the
14
+ * canonical receipt body, its `htu` names the dispatch, and the pin decides which key may sign it.
15
+ *
16
+ * Verification is deliberately strict and returns a reason, never a boolean:
17
+ * - a pin is REQUIRED (a receipt with no key to compare against has no authority);
18
+ * - the algorithm admitted is the algorithm of the pin, never a list, so a receipt cannot choose a
19
+ * weaker algorithm than the device enrolled with;
20
+ * - the body is a closed shape with bounded fields;
21
+ * - every field the caller expects (the dispatch the server issued) must match exactly;
22
+ * - a descendant that survived is `not_quiescent`, not a valid receipt with a footnote;
23
+ * - erasure is claimed only for the one scope the owner allowed, `session_temp`.
24
+ *
25
+ * Freshness is the caller's decision (`maxAgeSeconds`). A receipt can legitimately arrive hours after it
26
+ * was signed, replayed from the daemon's response WAL after a reconnect, so it has no short window of its
27
+ * own. Replay protection is the dispatch binding: the server accepts one receipt per `dispatchId`.
28
+ */
29
+ import { type DeviceKeyAlg, type DeviceKeySigner, type DevicePublicJwk, type VerifyFailureReason } from './deviceKey.js';
30
+ /** Header `typ` of an executor stop receipt. Distinct from `DEVICE_PROOF_TYP` on purpose. */
31
+ export declare const EXECUTOR_STOP_RECEIPT_TYP = "skrr-executor-stop-receipt+jwt";
32
+ /** What the daemon may claim to have erased. One scope, decided by the owner (2026-11-01). */
33
+ export declare const EXECUTOR_STOP_RECEIPT_ERASURE_SCOPES: readonly ["session_temp"];
34
+ export type ExecutorStopReceiptErasureScope = (typeof EXECUTOR_STOP_RECEIPT_ERASURE_SCOPES)[number];
35
+ /** Default ceiling on a receipt's age, for a caller that does not decide: one day. */
36
+ export declare const EXECUTOR_STOP_RECEIPT_DEFAULT_MAX_AGE_SECONDS: number;
37
+ export type ExecutorStopReceiptStatus = 'completed' | 'failed' | 'cancelled';
38
+ export interface ExecutorStopReceiptBody {
39
+ version: 1;
40
+ daemonId: string;
41
+ /** The scheduled Run (or Source) the dispatch belongs to. */
42
+ sourceId: string;
43
+ sessionId: string;
44
+ requestId: string;
45
+ dispatchId: string;
46
+ status: ExecutorStopReceiptStatus;
47
+ /** ISO-8601, when the session's process tree was last observed stopped. */
48
+ stoppedAt: string;
49
+ /** Counted after the stop, not assumed. `observed === stopped + survivors`. */
50
+ descendants: {
51
+ observed: number;
52
+ stopped: number;
53
+ survivors: number;
54
+ };
55
+ /** `performed: false` carries no scope: nothing was erased and nothing is claimed. */
56
+ erasure: {
57
+ performed: false;
58
+ } | {
59
+ performed: true;
60
+ scope: ExecutorStopReceiptErasureScope;
61
+ artifacts: number;
62
+ bytes: number;
63
+ };
64
+ }
65
+ export interface ExecutorStopReceipt {
66
+ body: ExecutorStopReceiptBody;
67
+ /** The device-key proof (JWS compact) that commits to `body`. */
68
+ proof: string;
69
+ }
70
+ export type ExecutorStopReceiptFailureReason = VerifyFailureReason | 'bad_receipt' | 'no_pin' | 'binding_mismatch' | 'not_quiescent';
71
+ export type VerifyExecutorStopReceiptResult = {
72
+ valid: true;
73
+ body: ExecutorStopReceiptBody;
74
+ alg: DeviceKeyAlg;
75
+ thumbprint: string;
76
+ signedAtSeconds: number;
77
+ } | {
78
+ valid: false;
79
+ reason: ExecutorStopReceiptFailureReason;
80
+ };
81
+ declare const BINDING_KEYS: readonly ["daemonId", "sourceId", "sessionId", "requestId", "dispatchId"];
82
+ /**
83
+ * Stable JSON: object keys sorted at every level, no whitespace. The signer and the verifier must
84
+ * produce the same bytes from the same body, whatever order a transport reordered its keys into.
85
+ */
86
+ export declare function canonicalReceiptJson(value: unknown): string;
87
+ /** The URI a receipt's proof names. Reserved `.invalid` host: it can never be a real request target. */
88
+ export declare function executorStopReceiptHtu(dispatchId: string): string;
89
+ /** Shape check only. Returns the body as typed, or null when it is not exactly a v1 receipt body. */
90
+ export declare function parseExecutorStopReceiptBody(value: unknown): ExecutorStopReceiptBody | null;
91
+ export interface SignExecutorStopReceiptOptions {
92
+ /** Test hooks; production leaves both unset. */
93
+ iat?: number;
94
+ jti?: string;
95
+ }
96
+ /**
97
+ * Sign a receipt with any `DeviceKeySigner` (a software key, or a hardware handle). Throws on a body
98
+ * that is not exactly a v1 receipt body, so a daemon bug cannot produce a signed receipt the server
99
+ * would only reject later.
100
+ */
101
+ export declare function signExecutorStopReceipt(signer: DeviceKeySigner, body: ExecutorStopReceiptBody, options?: SignExecutorStopReceiptOptions): Promise<ExecutorStopReceipt>;
102
+ export interface VerifyExecutorStopReceiptOptions {
103
+ /** The key pinned on the daemon's row. REQUIRED: without it nothing authorizes the signature. */
104
+ pinnedPublicJwk: DevicePublicJwk | undefined;
105
+ /**
106
+ * What the server issued for this dispatch. Every key given must equal the receipt's, so a receipt for
107
+ * another daemon, Run, session, request or dispatch is `binding_mismatch`.
108
+ */
109
+ expected?: Partial<Pick<ExecutorStopReceiptBody, (typeof BINDING_KEYS)[number]>>;
110
+ /** Ceiling on the receipt's age in seconds. Defaults to one day. */
111
+ maxAgeSeconds?: number;
112
+ /** Tolerated clock skew in seconds. Defaults to the proof verifier's. */
113
+ clockSkewSeconds?: number;
114
+ /** Testing hook. */
115
+ now?: number;
116
+ }
117
+ /**
118
+ * Verify a receipt against the pinned key. Order matters: shape, then signature and pin, then the
119
+ * binding to the dispatch, then what the body claims. A forged receipt is reported as the forgery it
120
+ * is (`sig_invalid`, `pin_mismatch`, `ath_mismatch`), not as a quiescence failure.
121
+ */
122
+ export declare function verifyExecutorStopReceipt(receipt: unknown, options: VerifyExecutorStopReceiptOptions): VerifyExecutorStopReceiptResult;
123
+ export {};