@skrr-ai/cli 0.1.49 → 0.1.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/base-command.js +75 -6
- package/dist/commands/agents/chat.d.ts +14 -0
- package/dist/commands/agents/chat.js +37 -1
- package/dist/commands/agents/create.js +14 -7
- package/dist/commands/agents/show.d.ts +9 -0
- package/dist/commands/agents/show.js +53 -0
- package/dist/commands/agents/update.d.ts +9 -0
- package/dist/commands/agents/update.js +38 -5
- package/dist/commands/balance/show.d.ts +34 -0
- package/dist/commands/balance/show.js +92 -2
- package/dist/commands/code/index.d.ts +1 -0
- package/dist/commands/code/index.js +49 -5
- package/dist/commands/code/run.js +5 -1
- package/dist/commands/commitments/cycles.d.ts +19 -0
- package/dist/commands/commitments/cycles.js +46 -0
- package/dist/commands/commitments/doctor.d.ts +1 -0
- package/dist/commands/commitments/doctor.js +19 -4
- package/dist/commands/commitments/effective-policy.js +40 -1
- package/dist/commands/commitments/explain.d.ts +17 -0
- package/dist/commands/commitments/explain.js +40 -0
- package/dist/commands/commitments/next-tick.js +3 -1
- package/dist/commands/commitments/preflight.js +10 -0
- package/dist/commands/commitments/show.js +11 -1
- package/dist/commands/daemon/config.d.ts +15 -0
- package/dist/commands/daemon/config.js +38 -0
- package/dist/commands/daemon/index.js +1 -0
- package/dist/commands/daemon/status.js +15 -1
- package/dist/commands/goals/create.d.ts +1 -0
- package/dist/commands/goals/create.js +22 -0
- package/dist/commands/harnesses/models.d.ts +54 -0
- package/dist/commands/harnesses/models.js +100 -7
- package/dist/commands/harnesses/show.d.ts +11 -0
- package/dist/commands/harnesses/show.js +35 -0
- package/dist/commands/harnesses/update.d.ts +28 -1
- package/dist/commands/harnesses/update.js +73 -10
- package/dist/commands/logout.js +12 -1
- package/dist/commands/machines/dedicated/index.js +1 -1
- package/dist/commands/machines/dedicated/sign-in.js +4 -1
- package/dist/commands/machines/dedicated/terminal/kill.d.ts +21 -0
- package/dist/commands/machines/dedicated/terminal/kill.js +55 -0
- package/dist/commands/machines/dedicated/terminal/ls.d.ts +22 -0
- package/dist/commands/machines/dedicated/terminal/ls.js +70 -0
- package/dist/commands/machines/dedicated/terminal/rename.d.ts +23 -0
- package/dist/commands/machines/dedicated/terminal/rename.js +64 -0
- package/dist/commands/machines/dedicated/terminal.d.ts +9 -0
- package/dist/commands/machines/dedicated/terminal.js +27 -2
- package/dist/commands/machines/hosted/connect.js +2 -2
- package/dist/commands/machines/hosted/destroy.js +1 -1
- package/dist/commands/machines/hosted/exec.js +1 -1
- package/dist/commands/machines/hosted/list.js +1 -1
- package/dist/commands/machines/hosted/pause.js +1 -1
- package/dist/commands/machines/hosted/pull.js +1 -1
- package/dist/commands/machines/hosted/resume.js +1 -1
- package/dist/commands/machines/hosted/start.js +2 -2
- package/dist/commands/machines/hosted/status.js +2 -1
- package/dist/commands/outbox/list.d.ts +12 -1
- package/dist/commands/outbox/list.js +31 -2
- package/dist/commands/revoke-daemon.js +9 -0
- package/dist/commands/spaces/create.d.ts +1 -0
- package/dist/commands/spaces/create.js +17 -0
- package/dist/commands/spaces/show.js +5 -0
- package/dist/commands/spaces/update.d.ts +1 -0
- package/dist/commands/spaces/update.js +16 -0
- package/dist/commands/tasks/create.d.ts +1 -0
- package/dist/commands/tasks/create.js +6 -0
- package/dist/commands/tasks/list.js +1 -0
- package/dist/commands/tasks/show.js +45 -0
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +22 -0
- package/dist/commands/tasks/upsert.d.ts +1 -0
- package/dist/commands/tasks/upsert.js +16 -0
- package/dist/lib/agent-config.d.ts +2 -0
- package/dist/lib/agent-config.js +3 -1
- package/dist/lib/agentic-stream.d.ts +68 -1
- package/dist/lib/agentic-stream.js +294 -7
- package/dist/lib/api-fetch.js +19 -0
- package/dist/lib/auth-core-init.d.ts +2 -10
- package/dist/lib/auth-core-init.js +20 -67
- package/dist/lib/auth-failure.d.ts +33 -0
- package/dist/lib/auth-failure.js +65 -0
- package/dist/lib/auth-storage.d.ts +14 -0
- package/dist/lib/auth-storage.js +14 -0
- package/dist/lib/commitments.d.ts +37 -2
- package/dist/lib/commitments.js +148 -0
- package/dist/lib/daemonBroker.d.ts +134 -31
- package/dist/lib/daemonBroker.js +376 -31
- package/dist/lib/dedicated-lease-command.d.ts +14 -0
- package/dist/lib/dedicated-lease-command.js +30 -1
- package/dist/lib/dedicated-machines.js +8 -25
- package/dist/lib/dedicated-service-command.d.ts +11 -3
- package/dist/lib/dedicated-service-command.js +20 -3
- package/dist/lib/dedicated-service.d.ts +46 -0
- package/dist/lib/dedicated-service.js +85 -7
- package/dist/lib/dedicated-terminal.d.ts +21 -0
- package/dist/lib/dedicated-terminal.js +104 -9
- package/dist/lib/delegated-cli.js +4 -1
- package/dist/lib/exec-runtime-binary.d.ts +3 -1
- package/dist/lib/exec-runtime-binary.js +4 -2
- package/dist/lib/first-party-harness-broker.d.ts +10 -0
- package/dist/lib/first-party-harness-broker.js +13 -1
- package/dist/lib/first-party-harness-doctor.js +41 -1
- package/dist/lib/first-party-harness-managed.d.ts +4 -3
- package/dist/lib/first-party-harness-project-trust.d.ts +125 -0
- package/dist/lib/first-party-harness-project-trust.js +364 -0
- package/dist/lib/first-party-harness.d.ts +9 -2
- package/dist/lib/first-party-harness.js +6 -5
- package/dist/lib/harnesses.d.ts +10 -0
- package/dist/lib/hosted-machines.d.ts +10 -1
- package/dist/lib/hosted-machines.js +36 -2
- package/dist/lib/live-runtime-binary.d.ts +40 -0
- package/dist/lib/live-runtime-binary.js +193 -0
- package/dist/lib/login.d.ts +23 -0
- package/dist/lib/login.js +60 -10
- package/dist/lib/machine-spend-cap.d.ts +23 -0
- package/dist/lib/machine-spend-cap.js +68 -0
- package/dist/lib/message-intent.js +3 -1
- package/dist/lib/node-adapter.js +15 -3
- package/dist/lib/tasks.d.ts +20 -0
- package/dist/lib/tasks.js +54 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.d.ts +90 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.js +113 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.js +26 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialSession.d.ts +47 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialSession.js +69 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.d.ts +133 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.js +189 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +41 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +25 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/loopbackHttp.d.ts +32 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/loopbackHttp.js +268 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineId.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineId.js +11 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.d.ts +36 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +156 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.d.ts +8 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.js +9 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.d.ts +8 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.js +16 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refreshClassification.d.ts +6 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refreshClassification.js +32 -9
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/sessionPermissionAuthority.d.ts +81 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/sessionPermissionAuthority.js +87 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.d.ts +22 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/spawnEnv.js +61 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/types.d.ts +6 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.d.ts +90 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.js +105 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.js +25 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialSession.d.ts +47 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialSession.js +66 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.d.ts +133 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.js +182 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +41 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +10 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/loopbackHttp.d.ts +32 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/loopbackHttp.js +257 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineId.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineId.js +11 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.d.ts +36 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +147 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.d.ts +8 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.js +9 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.d.ts +8 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.js +16 -10
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refreshClassification.d.ts +6 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refreshClassification.js +31 -9
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/sessionPermissionAuthority.d.ts +81 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/sessionPermissionAuthority.js +80 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.d.ts +22 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/spawnEnv.js +58 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/types.d.ts +6 -1
- package/dist/node_modules/@skrr-ai/auth-core/package.json +61 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +3418 -3344
- package/oclif.manifest.json +24813 -24242
- package/package.json +4 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* auth-failure.ts — say WHY a request was refused on authentication (OSK-12116).
|
|
4
|
+
*
|
|
5
|
+
* A 401 reaches the CLI after its own renewal has already failed: the access
|
|
6
|
+
* token expired, the refresh was refused, and the retry went out with the dead
|
|
7
|
+
* token. The server's answer to that retry is `TOKEN_EXPIRED`, which is true and
|
|
8
|
+
* useless — the expiry is routine, the refusal to RENEW is the fault, and it was
|
|
9
|
+
* visible only as an `[auth-core warn]` line on stderr.
|
|
10
|
+
*
|
|
11
|
+
* auth-core latches every permanent refresh refusal (`needs-reauth.json`, the
|
|
12
|
+
* same record `skrr whoami` prints as "Refresh state"). This module reads that
|
|
13
|
+
* latch and turns it into the sentence the error should have carried.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.describeRefreshRefusal = describeRefreshRefusal;
|
|
17
|
+
/**
|
|
18
|
+
* Explain one refresh refusal in terms of what the reader can do about it.
|
|
19
|
+
* Returns null when there is no latched refusal, so the caller keeps its
|
|
20
|
+
* generic wording rather than inventing a cause.
|
|
21
|
+
*/
|
|
22
|
+
function describeRefreshRefusal(refusal, opts) {
|
|
23
|
+
if (!refusal?.reason)
|
|
24
|
+
return null;
|
|
25
|
+
const { bin } = opts;
|
|
26
|
+
const code = refusal.reason;
|
|
27
|
+
const said = refusal.message ? ` (${code}: ${refusal.message})` : ` (${code})`;
|
|
28
|
+
const relogin = `Run \`${bin} login\` to sign in again.`;
|
|
29
|
+
const message = refusal.message ?? '';
|
|
30
|
+
// The row the stored refresh token belongs to was minted for a different CLI
|
|
31
|
+
// identity than the one this config presents. The keychain slot is keyed by
|
|
32
|
+
// profile, while the CLI ID lives in the config directory — so a second skrr
|
|
33
|
+
// configuration on this machine (a different HOME or config dir sharing the
|
|
34
|
+
// same login Keychain) can write this profile's credential under its own ID.
|
|
35
|
+
// Observed: a token minted for `cli_devin_dogfood` sitting in the default
|
|
36
|
+
// profile's slot.
|
|
37
|
+
if (/bound to a different daemon/i.test(message)) {
|
|
38
|
+
return {
|
|
39
|
+
code,
|
|
40
|
+
message: `This profile's stored sign-in could not be renewed${said}. The credential in its ` +
|
|
41
|
+
`Keychain slot was issued to a different CLI identity than this one` +
|
|
42
|
+
`${opts.cliId ? ` (${opts.cliId})` : ''} — usually another skrr configuration on this ` +
|
|
43
|
+
`machine (a different HOME or config directory) signed in and wrote over it. ${relogin}`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (code === 'SESSION_REVOKED') {
|
|
47
|
+
return {
|
|
48
|
+
code,
|
|
49
|
+
message: `This sign-in was revoked${said}. Signing out elsewhere revokes it, and so does ` +
|
|
50
|
+
`revoking a daemon that brokered it (\`${bin} login\` without a browser signs in ` +
|
|
51
|
+
`through this machine's daemon). ${relogin}`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (code === 'REFRESH_REUSED') {
|
|
55
|
+
return {
|
|
56
|
+
code,
|
|
57
|
+
message: `This sign-in was ended because its refresh token was presented twice${said}; the ` +
|
|
58
|
+
`server treats that as possible theft and revokes the whole family. ${relogin}`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
code,
|
|
63
|
+
message: `This sign-in could not be renewed${said}. ${relogin}`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -21,6 +21,20 @@ export interface WriteOptions {
|
|
|
21
21
|
/** Clear a stale needs-reauth latch after a server has issued fresh credentials. */
|
|
22
22
|
clearReauth?: boolean;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* File-backend-only read. Exported for the brokered-hand-off migration
|
|
26
|
+
* cleanup (`daemonBroker.maybeRetireStoredCliAuthFile`), which must inspect
|
|
27
|
+
* `~/.skrr/cli-auth.json` specifically — not the keychain-preferred
|
|
28
|
+
* `readFromBackend()` — to prove the stored family's provenance before
|
|
29
|
+
* retiring it. Everything else should keep using `readFromBackend()`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function readFromFile(): AuthBundle | null;
|
|
32
|
+
/**
|
|
33
|
+
* Delete `~/.skrr/cli-auth.json` only (the keychain is untouched). Exported
|
|
34
|
+
* for the brokered-hand-off migration cleanup; `skrr logout` continues to
|
|
35
|
+
* use `clearAllBackends()`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function deleteFileBackend(): void;
|
|
24
38
|
/**
|
|
25
39
|
* Read the CLI's auth bundle from the preferred backend.
|
|
26
40
|
*
|
package/dist/lib/auth-storage.js
CHANGED
|
@@ -34,6 +34,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.backends = void 0;
|
|
37
|
+
exports.readFromFile = readFromFile;
|
|
38
|
+
exports.deleteFileBackend = deleteFileBackend;
|
|
37
39
|
exports.readFromBackend = readFromBackend;
|
|
38
40
|
exports.writeToBackend = writeToBackend;
|
|
39
41
|
exports.clearAllBackends = clearAllBackends;
|
|
@@ -96,6 +98,13 @@ function authFilePath() {
|
|
|
96
98
|
// ---------------------------------------------------------------------
|
|
97
99
|
// File backend
|
|
98
100
|
// ---------------------------------------------------------------------
|
|
101
|
+
/**
|
|
102
|
+
* File-backend-only read. Exported for the brokered-hand-off migration
|
|
103
|
+
* cleanup (`daemonBroker.maybeRetireStoredCliAuthFile`), which must inspect
|
|
104
|
+
* `~/.skrr/cli-auth.json` specifically — not the keychain-preferred
|
|
105
|
+
* `readFromBackend()` — to prove the stored family's provenance before
|
|
106
|
+
* retiring it. Everything else should keep using `readFromBackend()`.
|
|
107
|
+
*/
|
|
99
108
|
function readFromFile() {
|
|
100
109
|
const p = authFilePath();
|
|
101
110
|
if (!fs.existsSync(p))
|
|
@@ -235,6 +244,11 @@ function writeToFile(bundle) {
|
|
|
235
244
|
throw err;
|
|
236
245
|
}
|
|
237
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* Delete `~/.skrr/cli-auth.json` only (the keychain is untouched). Exported
|
|
249
|
+
* for the brokered-hand-off migration cleanup; `skrr logout` continues to
|
|
250
|
+
* use `clearAllBackends()`.
|
|
251
|
+
*/
|
|
238
252
|
function deleteFileBackend() {
|
|
239
253
|
const p = authFilePath();
|
|
240
254
|
try {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* "hold this state", derived from a Compass invariant — not authored here).
|
|
18
18
|
*/
|
|
19
19
|
import { COMMITMENT_WATCHED_SOURCES, COMMITMENT_TEMPLATE_IDS, COMMITMENT_CADENCE_MODES, COMMITMENT_CADENCE_TIME_PATTERN, COMMITMENT_CADENCE_MAX_TIMES, COMMITMENT_AUTONOMY_MODES, COMMITMENT_EXECUTION_ISOLATION_MODES, COMMITMENT_STATUSES, COMMITMENT_KIND_VALUES } from '@skrr-ai/data-provider';
|
|
20
|
-
import type { CommitmentCheck, CommitmentChecksResponse, Commitment, CommitmentActionProposal, CommitmentListResponse, CommitmentPlanResponse, CommitmentStatusResponse, CommitmentWorkLink, CommitmentExecutionReceiptListResponse, CommitmentExecutionReceiptQuarterlyMetricsResponse, CommitmentCapabilitySource, CommitmentDeliveryPatchResponse, CommitmentDeliveryBundleResponse } from '@skrr-ai/data-provider';
|
|
20
|
+
import type { CommitmentCheck, CommitmentChecksResponse, Commitment, CommitmentActionProposal, CommitmentListResponse, CommitmentPlanResponse, CommitmentStatusResponse, CommitmentWorkLink, CommitmentExecutionReceiptListResponse, CommitmentExecutionReceiptQuarterlyMetricsResponse, CommitmentCapabilitySource, CommitmentDeliveryPatchResponse, CommitmentDeliveryBundleResponse, CommitmentCyclesResponse, CommitmentExplanationResponse, CommitmentRunPermissions } from '@skrr-ai/data-provider';
|
|
21
21
|
import { withQuery } from './triggers';
|
|
22
22
|
export { COMMITMENT_WATCHED_SOURCES, COMMITMENT_TEMPLATE_IDS, COMMITMENT_CADENCE_MODES, COMMITMENT_CADENCE_TIME_PATTERN, COMMITMENT_CADENCE_MAX_TIMES, COMMITMENT_STATUSES, COMMITMENT_KIND_VALUES, };
|
|
23
23
|
export type { CommitmentCheck, CommitmentChecksResponse, Commitment, CommitmentActionProposal, CommitmentListResponse, CommitmentPlanResponse, CommitmentStatusResponse, CommitmentWorkLink, };
|
|
@@ -99,7 +99,27 @@ export type CommitmentPreflightReport = {
|
|
|
99
99
|
suppressedBy?: string | null;
|
|
100
100
|
[key: string]: unknown;
|
|
101
101
|
};
|
|
102
|
+
/** Whose permissions a run uses (OSK-11975). Absent from older servers. */
|
|
103
|
+
permissions?: CommitmentRunPermissions | null;
|
|
104
|
+
/** `retired` names the fence fields OSK-11975 made inert (OSK-12065). */
|
|
105
|
+
execution?: {
|
|
106
|
+
retired?: string[];
|
|
107
|
+
retiredReason?: string;
|
|
108
|
+
} & Record<string, unknown>;
|
|
102
109
|
};
|
|
110
|
+
/**
|
|
111
|
+
* The lines every Commitment read surface prints for "whose permissions does a
|
|
112
|
+
* run use?" — `show`, `effective-policy` and `preflight` share it so the three
|
|
113
|
+
* cannot phrase it three ways (OSK-12065). The sentence and the warnings are
|
|
114
|
+
* the server's; this only lays them out. `null` (an older server that does not
|
|
115
|
+
* report it) prints nothing rather than a guess.
|
|
116
|
+
*/
|
|
117
|
+
export declare function permissionLines(permissions: CommitmentRunPermissions | null | undefined): string[];
|
|
118
|
+
/**
|
|
119
|
+
* One line naming fields that are still in the JSON but decide nothing any
|
|
120
|
+
* more. Deprecation, not removal: `--json` keeps them for scripts.
|
|
121
|
+
*/
|
|
122
|
+
export declare function retiredFieldsLine(retired: string[] | undefined, reason: string | undefined): string | null;
|
|
103
123
|
/**
|
|
104
124
|
* A Commitment Pack's readiness receipt.
|
|
105
125
|
*
|
|
@@ -351,6 +371,13 @@ export declare const commitmentApi: {
|
|
|
351
371
|
limit?: number;
|
|
352
372
|
cursor?: string;
|
|
353
373
|
}) => Promise<Record<string, unknown>>;
|
|
374
|
+
/** One Cycle per Check, newest first — the unit a person reads (D8). */
|
|
375
|
+
cycles: (id: string, query?: {
|
|
376
|
+
limit?: number;
|
|
377
|
+
cursor?: string;
|
|
378
|
+
}) => Promise<CommitmentCyclesResponse>;
|
|
379
|
+
/** The latest Cycle walked as six questions; the first "no" is where it stopped. */
|
|
380
|
+
explain: (id: string) => Promise<CommitmentExplanationResponse>;
|
|
354
381
|
ledger: (id: string, query?: Record<string, string | number | undefined>) => Promise<Record<string, unknown>>;
|
|
355
382
|
wakeCapabilities: (id: string) => Promise<CommitmentWakeCapabilities>;
|
|
356
383
|
dailyMetrics: (id: string, query?: {
|
|
@@ -759,8 +786,16 @@ export declare function renderCheckList(checks: CommitmentCheckView[], log: (lin
|
|
|
759
786
|
type ReadModelRecord = Record<string, unknown>;
|
|
760
787
|
/** Human view for `commitments ledger`; JSON remains the automation surface. */
|
|
761
788
|
export declare function renderCommitmentLedger(ledger: ReadModelRecord, log: (line: string) => void): void;
|
|
762
|
-
/** Human view for the ordered commitment trace. */
|
|
763
789
|
export declare function renderCommitmentTrace(trace: ReadModelRecord, log: (line: string) => void): void;
|
|
790
|
+
/**
|
|
791
|
+
* One line per Cycle:
|
|
792
|
+
* `09-22 12:04 ● stopped act commitment_execution_budget_exhausted — Raise maxRunsPerDay…`
|
|
793
|
+
* A run that failed is named under its Cycle with who has to move (machine
|
|
794
|
+
* or model), because that is the next question every reader asks.
|
|
795
|
+
*/
|
|
796
|
+
export declare function formatCommitmentCycles(page: Partial<CommitmentCyclesResponse>): string[];
|
|
797
|
+
/** The six questions for the latest Cycle, the first ✗ carrying its fix. */
|
|
798
|
+
export declare function formatCommitmentExplanation(explanation: Partial<CommitmentExplanationResponse>): string[];
|
|
764
799
|
/**
|
|
765
800
|
* Print the continuation hint for a paged `object:'list'` response — the line
|
|
766
801
|
* that makes history beyond the newest page reachable instead of invisible.
|
package/dist/lib/commitments.js
CHANGED
|
@@ -4,6 +4,8 @@ exports.COMMITMENT_CLI_EVALUATORS = exports.COMMITMENT_CREATE_KEYS = exports.COM
|
|
|
4
4
|
exports.storedAutonomyModeForAuthoring = storedAutonomyModeForAuthoring;
|
|
5
5
|
exports.authoringAutonomyModeForStored = authoringAutonomyModeForStored;
|
|
6
6
|
exports.commitmentAutonomyLabel = commitmentAutonomyLabel;
|
|
7
|
+
exports.permissionLines = permissionLines;
|
|
8
|
+
exports.retiredFieldsLine = retiredFieldsLine;
|
|
7
9
|
exports.readCommitmentAgentDirective = readCommitmentAgentDirective;
|
|
8
10
|
exports.normalizeCreateBody = normalizeCreateBody;
|
|
9
11
|
exports.parseCommitmentConcurrencyLimit = parseCommitmentConcurrencyLimit;
|
|
@@ -26,6 +28,8 @@ exports.describeWakeDecision = describeWakeDecision;
|
|
|
26
28
|
exports.renderCheckList = renderCheckList;
|
|
27
29
|
exports.renderCommitmentLedger = renderCommitmentLedger;
|
|
28
30
|
exports.renderCommitmentTrace = renderCommitmentTrace;
|
|
31
|
+
exports.formatCommitmentCycles = formatCommitmentCycles;
|
|
32
|
+
exports.formatCommitmentExplanation = formatCommitmentExplanation;
|
|
29
33
|
exports.renderListPageHint = renderListPageHint;
|
|
30
34
|
exports.renderCommitmentObservations = renderCommitmentObservations;
|
|
31
35
|
exports.renderCommitmentHypotheses = renderCommitmentHypotheses;
|
|
@@ -107,6 +111,33 @@ function commitmentAutonomyLabel(mode) {
|
|
|
107
111
|
*/
|
|
108
112
|
exports.MIN_COMMITMENT_INTERVAL_MS = 60_000;
|
|
109
113
|
exports.MAX_COMMITMENT_INTERVAL_MS = 365 * 24 * 60 * 60 * 1000;
|
|
114
|
+
/**
|
|
115
|
+
* The lines every Commitment read surface prints for "whose permissions does a
|
|
116
|
+
* run use?" — `show`, `effective-policy` and `preflight` share it so the three
|
|
117
|
+
* cannot phrase it three ways (OSK-12065). The sentence and the warnings are
|
|
118
|
+
* the server's; this only lays them out. `null` (an older server that does not
|
|
119
|
+
* report it) prints nothing rather than a guess.
|
|
120
|
+
*/
|
|
121
|
+
function permissionLines(permissions) {
|
|
122
|
+
if (!permissions?.summary)
|
|
123
|
+
return [];
|
|
124
|
+
const lines = [`Permissions: ${permissions.summary}`];
|
|
125
|
+
for (const warning of permissions.warnings || []) {
|
|
126
|
+
lines.push(`Warning: ${warning.message}`);
|
|
127
|
+
if (warning.fix)
|
|
128
|
+
lines.push(` Fix: ${warning.fix}`);
|
|
129
|
+
}
|
|
130
|
+
return lines;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* One line naming fields that are still in the JSON but decide nothing any
|
|
134
|
+
* more. Deprecation, not removal: `--json` keeps them for scripts.
|
|
135
|
+
*/
|
|
136
|
+
function retiredFieldsLine(retired, reason) {
|
|
137
|
+
if (!Array.isArray(retired) || !retired.length)
|
|
138
|
+
return null;
|
|
139
|
+
return `Retired fields (no effect): ${retired.join(', ')}${reason ? ` — ${reason}` : ''}`;
|
|
140
|
+
}
|
|
110
141
|
function base(id) {
|
|
111
142
|
return `/api/commitments/${encodeURIComponent(id)}`;
|
|
112
143
|
}
|
|
@@ -236,6 +267,10 @@ exports.commitmentApi = {
|
|
|
236
267
|
/** Un-delete. Returns the Commitment PAUSED, never active. */
|
|
237
268
|
restore: (id) => data_provider_1.request.post(`${base(id)}/restore`, {}),
|
|
238
269
|
trace: (id, query = {}) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/trace`, query)),
|
|
270
|
+
/** One Cycle per Check, newest first — the unit a person reads (D8). */
|
|
271
|
+
cycles: (id, query = {}) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/cycles`, query)),
|
|
272
|
+
/** The latest Cycle walked as six questions; the first "no" is where it stopped. */
|
|
273
|
+
explain: (id) => data_provider_1.request.get(`${base(id)}/explain`),
|
|
239
274
|
ledger: (id, query = {}) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/ledger`, query)),
|
|
240
275
|
wakeCapabilities: (id) => data_provider_1.request.get(`${base(id)}/wake-capabilities`),
|
|
241
276
|
dailyMetrics: (id, query = {}) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/daily-metrics`, query)),
|
|
@@ -1007,6 +1042,11 @@ function describeWakeDecision(check) {
|
|
|
1007
1042
|
if (verdict === 'skipped') {
|
|
1008
1043
|
const reason = typeof entry.reason === 'string' ? entry.reason : '';
|
|
1009
1044
|
if (reason === 'posture_does_not_admit_agent_run') {
|
|
1045
|
+
// The server names the commonest cause on the check's `stop`: nothing
|
|
1046
|
+
// was open to act on. "record_only" alone read as a setting to change
|
|
1047
|
+
// when the remedy was to give the Commitment some work (OSK-12090).
|
|
1048
|
+
if (check.stop?.reason === 'no_open_loop')
|
|
1049
|
+
return 'no — nothing open';
|
|
1010
1050
|
const posture = typeof entry.posture === 'string' ? entry.posture : '';
|
|
1011
1051
|
return posture ? `no — ${posture}` : 'no — posture';
|
|
1012
1052
|
}
|
|
@@ -1160,23 +1200,131 @@ function renderCommitmentLedger(ledger, log) {
|
|
|
1160
1200
|
}
|
|
1161
1201
|
}
|
|
1162
1202
|
/** Human view for the ordered commitment trace. */
|
|
1203
|
+
/**
|
|
1204
|
+
* `question:reason` for a trace event's server-derived stop — which of the six
|
|
1205
|
+
* questions (wake, fresh, turn, think, act, reach) the wake stopped at. `none`
|
|
1206
|
+
* means an Agent turn was dispatched. Blank when the event carries no stop.
|
|
1207
|
+
*/
|
|
1208
|
+
function stopCell(item) {
|
|
1209
|
+
const detail = item.detail;
|
|
1210
|
+
const stop = detail && typeof detail === 'object' ? detail.stop : undefined;
|
|
1211
|
+
if (!stop || typeof stop !== 'object')
|
|
1212
|
+
return '';
|
|
1213
|
+
const { question, gate, reason } = stop;
|
|
1214
|
+
if (typeof question !== 'string')
|
|
1215
|
+
return '';
|
|
1216
|
+
let why = '';
|
|
1217
|
+
if (typeof reason === 'string' && reason)
|
|
1218
|
+
why = reason;
|
|
1219
|
+
else if (typeof gate === 'string')
|
|
1220
|
+
why = gate;
|
|
1221
|
+
return why ? `${question}: ${why}` : question;
|
|
1222
|
+
}
|
|
1163
1223
|
function renderCommitmentTrace(trace, log) {
|
|
1164
1224
|
const events = records(trace.events);
|
|
1165
1225
|
renderRows(events.map((item) => ({
|
|
1166
1226
|
at: text(firstValue(item, ['occurredAt', 'createdAt', 'startedAt'])),
|
|
1167
1227
|
type: text(firstValue(item, ['type', 'kind'])),
|
|
1168
1228
|
status: text(item.status),
|
|
1229
|
+
stop: stopCell(item),
|
|
1169
1230
|
summary: text(firstValue(item, ['summary', 'reason', 'title']), ''),
|
|
1170
1231
|
})), [
|
|
1171
1232
|
{ key: 'at', header: 'AT', maxWidth: 24 },
|
|
1172
1233
|
{ key: 'type', header: 'TYPE', maxWidth: 28 },
|
|
1173
1234
|
{ key: 'status', header: 'STATUS', maxWidth: 28 },
|
|
1235
|
+
{ key: 'stop', header: 'STOPPED AT', maxWidth: 48 },
|
|
1174
1236
|
{ key: 'summary', header: 'SUMMARY', maxWidth: 72 },
|
|
1175
1237
|
], 'No trace events recorded.', log);
|
|
1176
1238
|
if (trace.has_more === true && trace.next_cursor) {
|
|
1177
1239
|
log(`More events are available; continue with --cursor ${text(trace.next_cursor)}.`);
|
|
1178
1240
|
}
|
|
1179
1241
|
}
|
|
1242
|
+
const CYCLE_GLYPH = {
|
|
1243
|
+
advanced: '✓',
|
|
1244
|
+
stopped: '●',
|
|
1245
|
+
quiet: '○',
|
|
1246
|
+
in_flight: '◌',
|
|
1247
|
+
};
|
|
1248
|
+
/** `MM-DD HH:MM` in the reader's local time; `-` when the time is unknown. */
|
|
1249
|
+
function cycleTime(value) {
|
|
1250
|
+
if (typeof value !== 'string')
|
|
1251
|
+
return '-';
|
|
1252
|
+
const date = new Date(value);
|
|
1253
|
+
if (Number.isNaN(date.getTime()))
|
|
1254
|
+
return '-';
|
|
1255
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
1256
|
+
return `${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
1257
|
+
}
|
|
1258
|
+
function cycleWake(cycle) {
|
|
1259
|
+
const wake = cycle.wake || {};
|
|
1260
|
+
if (wake.kind === 'fire')
|
|
1261
|
+
return `${wake.source || 'trigger'} wake`;
|
|
1262
|
+
return wake.source ? `${wake.kind} (${wake.source})` : String(wake.kind || '-');
|
|
1263
|
+
}
|
|
1264
|
+
/** What one Cycle came to, in a single line. */
|
|
1265
|
+
function cycleSummary(cycle) {
|
|
1266
|
+
if (cycle.outcome === 'stopped' && cycle.stop) {
|
|
1267
|
+
const { question, gate, reason, fix, detail } = cycle.stop;
|
|
1268
|
+
return `${question} ${reason || gate} — ${fix || detail || 'stopped'}`;
|
|
1269
|
+
}
|
|
1270
|
+
if (cycle.outcome === 'advanced') {
|
|
1271
|
+
return cycle.advancementKinds?.length
|
|
1272
|
+
? cycle.advancementKinds.join(', ')
|
|
1273
|
+
: 'applied an agent result';
|
|
1274
|
+
}
|
|
1275
|
+
if (cycle.outcome === 'in_flight') {
|
|
1276
|
+
const runs = cycle.runs?.length || 0;
|
|
1277
|
+
return runs ? `${runs} run(s) still going` : 'check still running';
|
|
1278
|
+
}
|
|
1279
|
+
return cycle.note || cycle.decision?.summary || cycle.decision?.posture || 'nothing to act on';
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* One line per Cycle:
|
|
1283
|
+
* `09-22 12:04 ● stopped act commitment_execution_budget_exhausted — Raise maxRunsPerDay…`
|
|
1284
|
+
* A run that failed is named under its Cycle with who has to move (machine
|
|
1285
|
+
* or model), because that is the next question every reader asks.
|
|
1286
|
+
*/
|
|
1287
|
+
function formatCommitmentCycles(page) {
|
|
1288
|
+
const cycles = Array.isArray(page.cycles) ? page.cycles : [];
|
|
1289
|
+
if (!cycles.length)
|
|
1290
|
+
return ['No cycles recorded yet.'];
|
|
1291
|
+
const lines = [];
|
|
1292
|
+
for (const cycle of cycles) {
|
|
1293
|
+
const glyph = CYCLE_GLYPH[cycle.outcome] || '?';
|
|
1294
|
+
lines.push(`${cycleTime(cycle.startedAt)} ${glyph} ${String(cycle.outcome).padEnd(9)} ${cycleWake(cycle).padEnd(18)} ${cycleSummary(cycle)}`);
|
|
1295
|
+
for (const run of cycle.runs || []) {
|
|
1296
|
+
if (!['machine', 'contract', 'work'].includes(run.failureClass))
|
|
1297
|
+
continue;
|
|
1298
|
+
const owner = run.failureOwner === 'model' ? 'model' : run.failureOwner || 'work';
|
|
1299
|
+
lines.push(` run ${run.id} ${run.status} — ${owner}: ${run.failureCode || '-'}`);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
if (page.has_more && page.next_cursor) {
|
|
1303
|
+
lines.push(`More cycles are available; continue with --cursor ${page.next_cursor}.`);
|
|
1304
|
+
}
|
|
1305
|
+
return lines;
|
|
1306
|
+
}
|
|
1307
|
+
const ANSWER_GLYPH = { yes: '✓', no: '✗', 'n/a': '–' };
|
|
1308
|
+
/** The six questions for the latest Cycle, the first ✗ carrying its fix. */
|
|
1309
|
+
function formatCommitmentExplanation(explanation) {
|
|
1310
|
+
const cycle = explanation.cycle;
|
|
1311
|
+
const lines = [
|
|
1312
|
+
cycle
|
|
1313
|
+
? `Latest cycle: ${cycleTime(cycle.startedAt)} ${cycle.outcome} (${cycle.id})`
|
|
1314
|
+
: `No cycle yet (status: ${explanation.status || '-'})`,
|
|
1315
|
+
];
|
|
1316
|
+
for (const answer of explanation.answers || []) {
|
|
1317
|
+
lines.push(` ${ANSWER_GLYPH[answer.answer] || '?'} ${answer.question} ${answer.because}`);
|
|
1318
|
+
if (answer.fix)
|
|
1319
|
+
lines.push(` Fix: ${answer.fix}`);
|
|
1320
|
+
}
|
|
1321
|
+
lines.push(!explanation.stoppedAt
|
|
1322
|
+
? 'Nothing stopped this cycle.'
|
|
1323
|
+
: explanation.verdict === 'quiet'
|
|
1324
|
+
? `Chose to stay quiet at: ${explanation.stoppedAt}`
|
|
1325
|
+
: `Stopped at: ${explanation.stoppedAt}`);
|
|
1326
|
+
return lines;
|
|
1327
|
+
}
|
|
1180
1328
|
/**
|
|
1181
1329
|
* Print the continuation hint for a paged `object:'list'` response — the line
|
|
1182
1330
|
* that makes history beyond the newest page reachable instead of invisible.
|
|
@@ -36,31 +36,25 @@
|
|
|
36
36
|
* liveness with `process.kill(pid, 0)` to filter stale files left behind
|
|
37
37
|
* by a force-killed daemon.
|
|
38
38
|
*/
|
|
39
|
+
import { type CliHandoffDescriptor, type CliHandoffTokenResponse } from '@skrr-ai/auth-core/cli-handoff-wire';
|
|
39
40
|
import { type AuthBackend } from './auth-storage';
|
|
40
41
|
import { type CliConfig } from './config';
|
|
41
42
|
/**
|
|
42
|
-
* Wire-shape of the bootstrap file
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* Wire-shape of the bootstrap file — the shared declaration in
|
|
44
|
+
* `@skrr-ai/auth-core/cli-handoff-wire` (`CliHandoffDescriptor`), which the
|
|
45
|
+
* daemon's writers and this reader both parse against so the format cannot
|
|
46
|
+
* drift between two mirrored type declarations. `LocalBootstrap` stays the
|
|
47
|
+
* exported name so existing callers (`daemon-target`, `message-intent`,
|
|
48
|
+
* `dedicated-lease-command`) don't churn.
|
|
49
|
+
*
|
|
50
|
+
* Fields the CLI doesn't use are ignored by the parser, and a future
|
|
51
|
+
* addition (e.g. version bump, new metadata) doesn't break this reader.
|
|
52
|
+
* `handoffModes` (descriptor v2) advertises what the secret can redeem:
|
|
53
|
+
* absent reads as `['refresh_family']` — today's durable mint; a guest
|
|
54
|
+
* descriptor advertising `['access_token']` can only redeem short-lived
|
|
55
|
+
* access tokens from the daemon's in-memory broker.
|
|
46
56
|
*/
|
|
47
|
-
export
|
|
48
|
-
version?: number;
|
|
49
|
-
pid?: number;
|
|
50
|
-
daemonId?: string;
|
|
51
|
-
host?: string;
|
|
52
|
-
port?: number;
|
|
53
|
-
/** Base64 32-byte handshake secret. */
|
|
54
|
-
secret?: string;
|
|
55
|
-
/**
|
|
56
|
-
* Server URL the daemon is authenticated against (e.g.
|
|
57
|
-
* `https://oversky.ai` or `http://localhost:3080`). Daemons that
|
|
58
|
-
* pre-date the baseURL-match check do not write this field — the
|
|
59
|
-
* broker pre-flight then refuses to call so we never mint against
|
|
60
|
-
* an unknown server.
|
|
61
|
-
*/
|
|
62
|
-
serverUrl?: string;
|
|
63
|
-
}
|
|
57
|
+
export type LocalBootstrap = CliHandoffDescriptor;
|
|
64
58
|
/**
|
|
65
59
|
* Normalize a base URL for equality comparison. Mirrors the daemon-side
|
|
66
60
|
* `normalizeBaseUrl` in `daemon/src/auth/cliHandoff.ts` so both ends
|
|
@@ -94,6 +88,33 @@ export interface DaemonBrokerResult {
|
|
|
94
88
|
* the file.
|
|
95
89
|
*/
|
|
96
90
|
storedIn?: Exclude<AuthBackend, 'none'>;
|
|
91
|
+
/**
|
|
92
|
+
* False on the legacy durable-mint shape so `outcome.brokered === true`
|
|
93
|
+
* narrows the outcome union. A durable mint is never brokered.
|
|
94
|
+
*/
|
|
95
|
+
brokered?: false;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Broker-mode success: the descriptor advertised `access_token` and the
|
|
99
|
+
* daemon's loopback token route (`POST /v1/auth/cli-handoff-token`) answered
|
|
100
|
+
* a short-lived cli-scope access token minted from a refresh family the
|
|
101
|
+
* DAEMON holds in memory.
|
|
102
|
+
*
|
|
103
|
+
* This outcome carries no `refreshToken`, no `cliId`, no `userId` — nothing
|
|
104
|
+
* credential-shaped may be persisted for it. `brokered: true` is the tag the
|
|
105
|
+
* persist path keys on to skip `writeToBackend` entirely; the token is used
|
|
106
|
+
* in-memory for this process only, and the next `skrr` invocation re-redeems
|
|
107
|
+
* over loopback.
|
|
108
|
+
*/
|
|
109
|
+
export interface DaemonBrokeredOutcome {
|
|
110
|
+
ok: true;
|
|
111
|
+
brokered: true;
|
|
112
|
+
accessToken: string;
|
|
113
|
+
/** Absolute expiry in epoch ms, when the daemon reports it. */
|
|
114
|
+
accessExpiresAt?: number;
|
|
115
|
+
/** Server the minted credential belongs to (daemon-reported, else the
|
|
116
|
+
* descriptor's own `serverUrl`). */
|
|
117
|
+
serverUrl?: string;
|
|
97
118
|
}
|
|
98
119
|
/**
|
|
99
120
|
* Explicit reasons the broker path could fail. These exist to keep the
|
|
@@ -101,7 +122,7 @@ export interface DaemonBrokerResult {
|
|
|
101
122
|
* fall through to PKCE; `ci_token_refused` is the one we surface
|
|
102
123
|
* because re-driving it via PKCE would not change the outcome.
|
|
103
124
|
*/
|
|
104
|
-
export type DaemonBrokerErrorReason = 'no_bootstrap' | 'stale_bootstrap' | 'bootstrap_parse' | 'base_url_mismatch' | 'daemon_not_authed' | 'ci_token_refused' | 'rate_limited' | 'server_error' | 'network' | 'timeout' | 'unknown';
|
|
125
|
+
export type DaemonBrokerErrorReason = 'no_bootstrap' | 'stale_bootstrap' | 'bootstrap_parse' | 'base_url_mismatch' | 'daemon_not_authed' | 'ci_token_refused' | 'handoff_broker_only' | 'rate_limited' | 'server_error' | 'network' | 'timeout' | 'unknown';
|
|
105
126
|
export interface DaemonBrokerFailure {
|
|
106
127
|
ok: false;
|
|
107
128
|
reason: DaemonBrokerErrorReason;
|
|
@@ -117,10 +138,16 @@ export interface DaemonBrokerFailure {
|
|
|
117
138
|
* the daemon".
|
|
118
139
|
*/
|
|
119
140
|
daemonServerUrl?: string;
|
|
141
|
+
/**
|
|
142
|
+
* For `base_url_mismatch` found locally: the descriptor file that named
|
|
143
|
+
* `daemonServerUrl`, so a message can say what was read rather than assert
|
|
144
|
+
* where "the" daemon is logged in (OSK-12117).
|
|
145
|
+
*/
|
|
146
|
+
descriptorPath?: string;
|
|
120
147
|
}
|
|
121
148
|
export type DaemonBrokerOutcome = (DaemonBrokerResult & {
|
|
122
149
|
ok: true;
|
|
123
|
-
}) | DaemonBrokerFailure;
|
|
150
|
+
}) | DaemonBrokeredOutcome | DaemonBrokerFailure;
|
|
124
151
|
export interface DaemonBrokerOptions {
|
|
125
152
|
/** Stable per-machine cliId the CLI wants the new refresh row bound to. */
|
|
126
153
|
cliId: string;
|
|
@@ -151,6 +178,22 @@ export interface DaemonBrokerOptions {
|
|
|
151
178
|
candidatePathsOverride?: readonly string[];
|
|
152
179
|
/** Override total request timeout. Tests use a short value. */
|
|
153
180
|
timeoutMs?: number;
|
|
181
|
+
/**
|
|
182
|
+
* Which advertised mode to prefer when a descriptor offers both
|
|
183
|
+
* (`handoffModes: ['access_token', 'refresh_family']`, the laptop island
|
|
184
|
+
* shape during transition):
|
|
185
|
+
*
|
|
186
|
+
* - `'access_token'` — broker mode: redeem a short-lived access token
|
|
187
|
+
* and hold it in memory only. Used by `maybeAutoBroker`: nothing
|
|
188
|
+
* credential-shaped lands on disk and each `skrr` process re-redeems
|
|
189
|
+
* over loopback.
|
|
190
|
+
* - `'refresh_family'` (default) — the legacy durable mint. Used by
|
|
191
|
+
* explicit `skrr login`: a human login still writes a real,
|
|
192
|
+
* user-owned refresh family. A descriptor that advertises ONLY
|
|
193
|
+
* `access_token` (the Dedicated guest shape) redeems brokered
|
|
194
|
+
* regardless — its secret cannot mint a family at all.
|
|
195
|
+
*/
|
|
196
|
+
preferHandoffMode?: 'access_token' | 'refresh_family';
|
|
154
197
|
}
|
|
155
198
|
/**
|
|
156
199
|
* Compute the bootstrap file path. Exported for tests so they can assert
|
|
@@ -187,6 +230,14 @@ export declare function resolveBootstrapCandidatePaths(profile?: string): string
|
|
|
187
230
|
export declare const DEDICATED_RUNTIME_CLI_HANDOFF_DESCRIPTOR = "/run/skrr-dedicated-runtime/cli-handoff/descriptor.json";
|
|
188
231
|
/** Where the cli-handoff broker looks, in order. */
|
|
189
232
|
export declare function resolveCliHandoffCandidatePaths(profile?: string): string[];
|
|
233
|
+
/**
|
|
234
|
+
* The island files that belong to exactly `profile` — its canonical path and
|
|
235
|
+
* the pre-rename darwin location — and never another profile's. The broker's
|
|
236
|
+
* candidate list for `default` deliberately falls through to any running
|
|
237
|
+
* profile, which is right for borrowing a credential and wrong for naming
|
|
238
|
+
* which daemon a profile's status describes (OSK-12102).
|
|
239
|
+
*/
|
|
240
|
+
export declare function resolveExactProfileBootstrapPaths(profile?: string): string[];
|
|
190
241
|
/**
|
|
191
242
|
* Resolve the first live daemon bootstrap for a profile. Message-intent
|
|
192
243
|
* submission reuses the same authenticated loopback discovery as the login
|
|
@@ -214,10 +265,60 @@ export declare function readBootstrap(filePath: string): LocalBootstrap | null;
|
|
|
214
265
|
*/
|
|
215
266
|
export declare function attemptDaemonBrokerLogin(opts: DaemonBrokerOptions): Promise<DaemonBrokerOutcome>;
|
|
216
267
|
/**
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
268
|
+
* True when `token` is the access token this process redeemed through the
|
|
269
|
+
* daemon's broker-mode hand-off. `api-fetch` uses this to pick the re-redeem
|
|
270
|
+
* recovery branch instead of the stored-family refresh (which would have
|
|
271
|
+
* nothing to rotate — brokered credentials are never persisted).
|
|
272
|
+
*/
|
|
273
|
+
export declare function isBrokeredHandoffToken(token: string | null | undefined): boolean;
|
|
274
|
+
/**
|
|
275
|
+
* Re-redeem the brokered hand-off token — the 401-recovery path. The
|
|
276
|
+
* descriptor is re-read from disk when its source path is known, so a secret
|
|
277
|
+
* rotated by a daemon restart resolves to the fresh one. Returns null when
|
|
278
|
+
* this process holds no brokered credential or the redeem fails (the caller
|
|
279
|
+
* then surfaces the original 401).
|
|
280
|
+
*/
|
|
281
|
+
export declare function redeemBrokeredHandoffToken(forceRefresh?: boolean): Promise<CliHandoffTokenResponse | null>;
|
|
282
|
+
/** @internal test seam — clears the module-scoped brokered credential. */
|
|
283
|
+
export declare function __resetBrokeredHandoffForTest(): void;
|
|
284
|
+
/**
|
|
285
|
+
* True when a live local descriptor advertises broker-mode access — i.e.
|
|
286
|
+
* this machine's CLI authority is platform-managed and `skrr logout` has no
|
|
287
|
+
* local credential to clear. Read-only: parses candidates, never redeems.
|
|
288
|
+
*/
|
|
289
|
+
export declare function findBrokeredHandoffDescriptor(profile?: string): LocalBootstrap | null;
|
|
290
|
+
/**
|
|
291
|
+
* Migration cleanup: retire the refresh family a pre-broker-mode CLI
|
|
292
|
+
* generation persisted, now that this machine redeems access tokens from
|
|
293
|
+
* the daemon's in-memory broker.
|
|
294
|
+
*
|
|
295
|
+
* Provenance guard — locally we cannot tell a hand-off-minted family from a
|
|
296
|
+
* user's explicit `skrr login` family by shape (the distinguishing
|
|
297
|
+
* `daemonRefOverride` lives server-side). The safe rule, applied here:
|
|
298
|
+
* revoke + delete ONLY when all of these hold —
|
|
299
|
+
*
|
|
300
|
+
* 1. the descriptor that just redeemed IS the Dedicated Runtime guest
|
|
301
|
+
* hand-off file (`/run/skrr-dedicated-runtime/...`),
|
|
302
|
+
* 2. `~/.skrr/cli-auth.json` reads cleanly and carries a refresh token,
|
|
303
|
+
* 3. its stored `serverOrigin` matches the descriptor's `serverUrl`.
|
|
304
|
+
*
|
|
305
|
+
* When provenance can't be proven the file is KEPT: an explicit `skrr login`
|
|
306
|
+
* on a guest is rare but real, and a stale extra family is bounded by the
|
|
307
|
+
* server's session cap and expires on its own. Best-effort throughout — a
|
|
308
|
+
* failed revoke still deletes the file (the whole point is that nothing
|
|
309
|
+
* credential-shaped should remain), and any failure leaves the working
|
|
310
|
+
* brokered credential untouched.
|
|
311
|
+
*/
|
|
312
|
+
export declare function maybeRetireStoredCliAuthFile(opts: {
|
|
313
|
+
descriptorPath?: string;
|
|
314
|
+
descriptorServerUrl?: string;
|
|
315
|
+
}): Promise<void>;
|
|
316
|
+
/**
|
|
317
|
+
* Convenience wrapper: run the broker call and, on a durable-mint success,
|
|
318
|
+
* persist the returned bundle through the canonical Sky CLI auth backend
|
|
319
|
+
* (Keychain on macOS, `cli-auth.json` elsewhere). A `brokered` outcome is
|
|
320
|
+
* returned WITHOUT persisting — that is the entire point of broker mode.
|
|
321
|
+
* Returns the same outcome shape so the caller can branch on `ok`/`brokered`.
|
|
221
322
|
*/
|
|
222
323
|
export declare function attemptDaemonBrokerLoginAndPersist(opts: DaemonBrokerOptions): Promise<DaemonBrokerOutcome>;
|
|
223
324
|
export interface MaybeAutoBrokerOptions {
|
|
@@ -275,10 +376,12 @@ export interface MaybeAutoBrokerResult {
|
|
|
275
376
|
* - `commandId` is in `AUTH_SELF_MANAGED_COMMANDS`
|
|
276
377
|
*
|
|
277
378
|
* Side effects:
|
|
278
|
-
* - Calls `attemptDaemonBrokerLoginAndPersist`
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
379
|
+
* - Calls `attemptDaemonBrokerLoginAndPersist` with `preferHandoffMode:
|
|
380
|
+
* 'access_token'`. On a descriptor that advertises broker mode the
|
|
381
|
+
* outcome is `brokered` — an in-memory access token, nothing written;
|
|
382
|
+
* the caller holds it for this process and the next `skrr` re-redeems.
|
|
383
|
+
* On a legacy/v1 descriptor the durable mint is persisted to the
|
|
384
|
+
* keychain / cli-auth.json exactly as before.
|
|
282
385
|
* - May generate a new `cliId` if the config doesn't have one. The
|
|
283
386
|
* caller MUST persist `updatedConfig` so the next invocation
|
|
284
387
|
* presents the same id to the server's refresh rotator.
|