@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.
- package/dist/base-command.d.ts +12 -0
- package/dist/base-command.js +65 -0
- package/dist/commands/agenda/trigger/create.js +9 -1
- package/dist/commands/agenda/trigger/list.d.ts +2 -1
- package/dist/commands/agenda/trigger/list.js +55 -6
- package/dist/commands/agents/create.js +3 -1
- package/dist/commands/agents/reflect.d.ts +6 -0
- package/dist/commands/agents/reflect.js +45 -6
- package/dist/commands/agents/schedule-overview.d.ts +17 -0
- package/dist/commands/agents/schedule-overview.js +33 -9
- package/dist/commands/agents/triggers/policy.js +3 -1
- package/dist/commands/browser/persistent-profile.d.ts +22 -0
- package/dist/commands/browser/persistent-profile.js +46 -0
- package/dist/commands/commitments/create.js +3 -1
- package/dist/commands/commitments/effective-policy.js +6 -0
- package/dist/commands/commitments/explain.js +10 -1
- package/dist/commands/commitments/plan.d.ts +14 -0
- package/dist/commands/commitments/plan.js +32 -0
- package/dist/commands/commitments/preflight.d.ts +1 -1
- package/dist/commands/commitments/preflight.js +12 -4
- package/dist/commands/commitments/show.d.ts +9 -0
- package/dist/commands/commitments/show.js +14 -1
- package/dist/commands/compass/revisions.d.ts +6 -2
- package/dist/commands/compass/revisions.js +13 -5
- package/dist/commands/compass/tactic.d.ts +5 -0
- package/dist/commands/compass/tactic.js +14 -0
- package/dist/commands/followups/plans/create.js +1 -1
- package/dist/commands/harnesses/list.js +1 -1
- package/dist/commands/northstars/create.js +6 -1
- package/dist/commands/northstars/governance/configure.js +1 -1
- package/dist/commands/northstars/intents/decide.js +2 -3
- package/dist/commands/northstars/list.js +1 -1
- package/dist/commands/northstars/review-now.js +5 -0
- package/dist/commands/northstars/reviews.js +15 -3
- package/dist/commands/northstars/show.js +1 -1
- package/dist/commands/spaces/auto-executor/runs.d.ts +9 -1
- package/dist/commands/spaces/auto-executor/runs.js +18 -1
- package/dist/commands/spaces/heartbeats/create.js +7 -5
- package/dist/commands/spaces/heartbeats/status.js +10 -0
- package/dist/commands/spaces/heartbeats/update.js +5 -3
- package/dist/commands/store/artifacts/releases.d.ts +20 -0
- package/dist/commands/store/artifacts/releases.js +85 -0
- package/dist/commands/store/library.d.ts +14 -0
- package/dist/commands/store/library.js +71 -0
- package/dist/commands/tasks/archive.js +6 -0
- package/dist/commands/tasks/list.d.ts +48 -0
- package/dist/commands/tasks/list.js +141 -9
- package/dist/commands/tasks/pause-schedule.js +1 -1
- package/dist/commands/tasks/remind.js +23 -11
- package/dist/commands/tasks/resume-schedule.js +4 -1
- package/dist/commands/tasks/retry-schedule.js +6 -3
- package/dist/commands/tasks/schedule.js +35 -8
- package/dist/commands/tasks/self-schedule.d.ts +56 -0
- package/dist/commands/tasks/self-schedule.js +179 -21
- package/dist/commands/tasks/show.js +4 -0
- package/dist/lib/agent-trigger-listing.d.ts +26 -0
- package/dist/lib/agent-trigger-listing.js +63 -0
- package/dist/lib/agentic-stream.js +138 -41
- package/dist/lib/commitment-ledgers.js +3 -1
- package/dist/lib/commitments.d.ts +24 -0
- package/dist/lib/commitments.js +64 -4
- package/dist/lib/compasses.d.ts +2 -0
- package/dist/lib/iso-instant.d.ts +52 -0
- package/dist/lib/iso-instant.js +162 -0
- package/dist/lib/northstars.d.ts +87 -4
- package/dist/lib/northstars.js +226 -94
- package/dist/lib/proposals.js +6 -2
- package/dist/lib/reflection.d.ts +58 -0
- package/dist/lib/reflection.js +115 -6
- package/dist/lib/store-artifact-releases.d.ts +39 -0
- package/dist/lib/store-artifact-releases.js +12 -0
- package/dist/lib/store-library.d.ts +37 -0
- package/dist/lib/store-library.js +12 -0
- package/dist/lib/task-calendar.d.ts +19 -0
- package/dist/lib/task-calendar.js +72 -0
- package/dist/lib/task-operations.js +2 -0
- package/dist/lib/task-recurrence-outcome.js +3 -1
- package/dist/lib/task-recurrence-summary.d.ts +15 -0
- package/dist/lib/task-recurrence-summary.js +228 -0
- package/dist/lib/task-reminder.d.ts +28 -0
- package/dist/lib/task-reminder.js +50 -0
- package/dist/lib/task-schedule-notes.d.ts +46 -0
- package/dist/lib/task-schedule-notes.js +71 -0
- package/dist/lib/triggers.d.ts +31 -2
- package/dist/lib/triggers.js +38 -18
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.js +11 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.d.ts +9 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +22 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.d.ts +123 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.js +160 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +19 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.js +11 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.d.ts +9 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +28 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.d.ts +123 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.js +173 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +6772 -6675
- package/oclif.manifest.json +282 -40
- 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
|
-
|
|
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 {};
|