@skrr-ai/cli 0.1.48 → 0.1.50
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 +16 -4
- package/dist/commands/agent-worker.d.ts +12 -0
- package/dist/commands/agent-worker.js +140 -0
- package/dist/commands/agents/create.js +14 -7
- package/dist/commands/agents/update.js +11 -5
- 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/effective-policy.js +26 -1
- package/dist/commands/commitments/explain.d.ts +17 -0
- package/dist/commands/commitments/explain.js +40 -0
- package/dist/commands/goals/create.d.ts +1 -0
- package/dist/commands/goals/create.js +22 -0
- 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/tasks/create.js +1 -0
- package/dist/commands/tasks/list.js +1 -0
- package/dist/commands/tasks/update.js +1 -0
- package/dist/lib/agent-config.d.ts +2 -0
- package/dist/lib/agent-config.js +3 -1
- package/dist/lib/api-fetch.js +19 -0
- package/dist/lib/auth-storage.d.ts +14 -0
- package/dist/lib/auth-storage.js +14 -0
- package/dist/lib/commitments.d.ts +17 -2
- package/dist/lib/commitments.js +114 -0
- package/dist/lib/daemon-installer.d.ts +6 -5
- package/dist/lib/daemon-installer.js +4 -17
- package/dist/lib/daemonBroker.d.ts +120 -31
- package/dist/lib/daemonBroker.js +313 -20
- 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/first-party-harness-broker.d.ts +10 -0
- package/dist/lib/first-party-harness-broker.js +9 -0
- 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/hosted-machines.d.ts +10 -1
- package/dist/lib/hosted-machines.js +36 -2
- package/dist/lib/login.js +16 -0
- package/dist/lib/machine-spend-cap.d.ts +23 -0
- package/dist/lib/machine-spend-cap.js +68 -0
- package/dist/lib/node-adapter.js +15 -3
- 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/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 +109 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.js +171 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarness.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +4 -2
- 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.js +8 -9
- 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/releaseManifest.d.ts +38 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseManifest.js +66 -1
- 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/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/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 +109 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.js +164 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarness.js +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -1
- 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.js +8 -9
- 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/releaseManifest.d.ts +38 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseManifest.js +64 -0
- 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/types.d.ts +6 -1
- package/dist/node_modules/@skrr-ai/auth-core/package.json +41 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +3413 -3343
- package/oclif.manifest.json +8930 -8466
- package/package.json +4 -1
package/dist/lib/api-fetch.js
CHANGED
|
@@ -42,6 +42,7 @@ const idempotency_scope_1 = require("./idempotency-scope");
|
|
|
42
42
|
const node_adapter_1 = require("./node-adapter");
|
|
43
43
|
const refresh_1 = require("./refresh");
|
|
44
44
|
const delegated_cli_1 = require("./delegated-cli");
|
|
45
|
+
const daemonBroker_1 = require("./daemonBroker");
|
|
45
46
|
const workspace_header_1 = require("./workspace-header");
|
|
46
47
|
const non_json_response_1 = require("./non-json-response");
|
|
47
48
|
class ApiFetchError extends Error {
|
|
@@ -191,6 +192,24 @@ async function apiFetch(pathOrUrl, opts = {}) {
|
|
|
191
192
|
res = await fetchWithCredential(cred);
|
|
192
193
|
}
|
|
193
194
|
}
|
|
195
|
+
else if (res.status === 401 &&
|
|
196
|
+
(0, daemonBroker_1.isBrokeredHandoffToken)(cred.token) &&
|
|
197
|
+
!isAuthEndpoint(pathOrUrl)) {
|
|
198
|
+
// Broker-mode hand-off credential: nothing was persisted, so there is no
|
|
199
|
+
// stored family for `ensureFreshCliCredential` to rotate. Re-redeem over
|
|
200
|
+
// loopback once (forceRefresh bypasses the daemon's cached token) and
|
|
201
|
+
// retry once — the same recovery contract the delegated path has.
|
|
202
|
+
const fresh = await (0, daemonBroker_1.redeemBrokeredHandoffToken)(true);
|
|
203
|
+
if (fresh?.accessToken) {
|
|
204
|
+
cred = {
|
|
205
|
+
token: fresh.accessToken,
|
|
206
|
+
source: 'env-token',
|
|
207
|
+
kind: (0, credential_resolver_1.kindOf)(fresh.accessToken),
|
|
208
|
+
};
|
|
209
|
+
(0, node_adapter_1.setAdapterCredentialOverride)(cred);
|
|
210
|
+
res = await fetchWithCredential(cred);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
194
213
|
else if (res.status === 401 && !autonomousCredential && !isAuthEndpoint(pathOrUrl)) {
|
|
195
214
|
const fresh = await (0, refresh_1.ensureFreshCliCredential)({ credential: cred, force: true });
|
|
196
215
|
if (fresh.refreshed && fresh.credential.token) {
|
|
@@ -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 } 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, };
|
|
@@ -351,6 +351,13 @@ export declare const commitmentApi: {
|
|
|
351
351
|
limit?: number;
|
|
352
352
|
cursor?: string;
|
|
353
353
|
}) => Promise<Record<string, unknown>>;
|
|
354
|
+
/** One Cycle per Check, newest first — the unit a person reads (D8). */
|
|
355
|
+
cycles: (id: string, query?: {
|
|
356
|
+
limit?: number;
|
|
357
|
+
cursor?: string;
|
|
358
|
+
}) => Promise<CommitmentCyclesResponse>;
|
|
359
|
+
/** The latest Cycle walked as six questions; the first "no" is where it stopped. */
|
|
360
|
+
explain: (id: string) => Promise<CommitmentExplanationResponse>;
|
|
354
361
|
ledger: (id: string, query?: Record<string, string | number | undefined>) => Promise<Record<string, unknown>>;
|
|
355
362
|
wakeCapabilities: (id: string) => Promise<CommitmentWakeCapabilities>;
|
|
356
363
|
dailyMetrics: (id: string, query?: {
|
|
@@ -759,8 +766,16 @@ export declare function renderCheckList(checks: CommitmentCheckView[], log: (lin
|
|
|
759
766
|
type ReadModelRecord = Record<string, unknown>;
|
|
760
767
|
/** Human view for `commitments ledger`; JSON remains the automation surface. */
|
|
761
768
|
export declare function renderCommitmentLedger(ledger: ReadModelRecord, log: (line: string) => void): void;
|
|
762
|
-
/** Human view for the ordered commitment trace. */
|
|
763
769
|
export declare function renderCommitmentTrace(trace: ReadModelRecord, log: (line: string) => void): void;
|
|
770
|
+
/**
|
|
771
|
+
* One line per Cycle:
|
|
772
|
+
* `09-22 12:04 ● stopped act commitment_execution_budget_exhausted — Raise maxRunsPerDay…`
|
|
773
|
+
* A run that failed is named under its Cycle with who has to move (machine
|
|
774
|
+
* or model), because that is the next question every reader asks.
|
|
775
|
+
*/
|
|
776
|
+
export declare function formatCommitmentCycles(page: Partial<CommitmentCyclesResponse>): string[];
|
|
777
|
+
/** The six questions for the latest Cycle, the first ✗ carrying its fix. */
|
|
778
|
+
export declare function formatCommitmentExplanation(explanation: Partial<CommitmentExplanationResponse>): string[];
|
|
764
779
|
/**
|
|
765
780
|
* Print the continuation hint for a paged `object:'list'` response — the line
|
|
766
781
|
* that makes history beyond the newest page reachable instead of invisible.
|
package/dist/lib/commitments.js
CHANGED
|
@@ -26,6 +26,8 @@ exports.describeWakeDecision = describeWakeDecision;
|
|
|
26
26
|
exports.renderCheckList = renderCheckList;
|
|
27
27
|
exports.renderCommitmentLedger = renderCommitmentLedger;
|
|
28
28
|
exports.renderCommitmentTrace = renderCommitmentTrace;
|
|
29
|
+
exports.formatCommitmentCycles = formatCommitmentCycles;
|
|
30
|
+
exports.formatCommitmentExplanation = formatCommitmentExplanation;
|
|
29
31
|
exports.renderListPageHint = renderListPageHint;
|
|
30
32
|
exports.renderCommitmentObservations = renderCommitmentObservations;
|
|
31
33
|
exports.renderCommitmentHypotheses = renderCommitmentHypotheses;
|
|
@@ -236,6 +238,10 @@ exports.commitmentApi = {
|
|
|
236
238
|
/** Un-delete. Returns the Commitment PAUSED, never active. */
|
|
237
239
|
restore: (id) => data_provider_1.request.post(`${base(id)}/restore`, {}),
|
|
238
240
|
trace: (id, query = {}) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/trace`, query)),
|
|
241
|
+
/** One Cycle per Check, newest first — the unit a person reads (D8). */
|
|
242
|
+
cycles: (id, query = {}) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/cycles`, query)),
|
|
243
|
+
/** The latest Cycle walked as six questions; the first "no" is where it stopped. */
|
|
244
|
+
explain: (id) => data_provider_1.request.get(`${base(id)}/explain`),
|
|
239
245
|
ledger: (id, query = {}) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/ledger`, query)),
|
|
240
246
|
wakeCapabilities: (id) => data_provider_1.request.get(`${base(id)}/wake-capabilities`),
|
|
241
247
|
dailyMetrics: (id, query = {}) => data_provider_1.request.get((0, triggers_1.withQuery)(`${base(id)}/daily-metrics`, query)),
|
|
@@ -1160,23 +1166,131 @@ function renderCommitmentLedger(ledger, log) {
|
|
|
1160
1166
|
}
|
|
1161
1167
|
}
|
|
1162
1168
|
/** Human view for the ordered commitment trace. */
|
|
1169
|
+
/**
|
|
1170
|
+
* `question:reason` for a trace event's server-derived stop — which of the six
|
|
1171
|
+
* questions (wake, fresh, turn, think, act, reach) the wake stopped at. `none`
|
|
1172
|
+
* means an Agent turn was dispatched. Blank when the event carries no stop.
|
|
1173
|
+
*/
|
|
1174
|
+
function stopCell(item) {
|
|
1175
|
+
const detail = item.detail;
|
|
1176
|
+
const stop = detail && typeof detail === 'object' ? detail.stop : undefined;
|
|
1177
|
+
if (!stop || typeof stop !== 'object')
|
|
1178
|
+
return '';
|
|
1179
|
+
const { question, gate, reason } = stop;
|
|
1180
|
+
if (typeof question !== 'string')
|
|
1181
|
+
return '';
|
|
1182
|
+
let why = '';
|
|
1183
|
+
if (typeof reason === 'string' && reason)
|
|
1184
|
+
why = reason;
|
|
1185
|
+
else if (typeof gate === 'string')
|
|
1186
|
+
why = gate;
|
|
1187
|
+
return why ? `${question}: ${why}` : question;
|
|
1188
|
+
}
|
|
1163
1189
|
function renderCommitmentTrace(trace, log) {
|
|
1164
1190
|
const events = records(trace.events);
|
|
1165
1191
|
renderRows(events.map((item) => ({
|
|
1166
1192
|
at: text(firstValue(item, ['occurredAt', 'createdAt', 'startedAt'])),
|
|
1167
1193
|
type: text(firstValue(item, ['type', 'kind'])),
|
|
1168
1194
|
status: text(item.status),
|
|
1195
|
+
stop: stopCell(item),
|
|
1169
1196
|
summary: text(firstValue(item, ['summary', 'reason', 'title']), ''),
|
|
1170
1197
|
})), [
|
|
1171
1198
|
{ key: 'at', header: 'AT', maxWidth: 24 },
|
|
1172
1199
|
{ key: 'type', header: 'TYPE', maxWidth: 28 },
|
|
1173
1200
|
{ key: 'status', header: 'STATUS', maxWidth: 28 },
|
|
1201
|
+
{ key: 'stop', header: 'STOPPED AT', maxWidth: 48 },
|
|
1174
1202
|
{ key: 'summary', header: 'SUMMARY', maxWidth: 72 },
|
|
1175
1203
|
], 'No trace events recorded.', log);
|
|
1176
1204
|
if (trace.has_more === true && trace.next_cursor) {
|
|
1177
1205
|
log(`More events are available; continue with --cursor ${text(trace.next_cursor)}.`);
|
|
1178
1206
|
}
|
|
1179
1207
|
}
|
|
1208
|
+
const CYCLE_GLYPH = {
|
|
1209
|
+
advanced: '✓',
|
|
1210
|
+
stopped: '●',
|
|
1211
|
+
quiet: '○',
|
|
1212
|
+
in_flight: '◌',
|
|
1213
|
+
};
|
|
1214
|
+
/** `MM-DD HH:MM` in the reader's local time; `-` when the time is unknown. */
|
|
1215
|
+
function cycleTime(value) {
|
|
1216
|
+
if (typeof value !== 'string')
|
|
1217
|
+
return '-';
|
|
1218
|
+
const date = new Date(value);
|
|
1219
|
+
if (Number.isNaN(date.getTime()))
|
|
1220
|
+
return '-';
|
|
1221
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
1222
|
+
return `${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
1223
|
+
}
|
|
1224
|
+
function cycleWake(cycle) {
|
|
1225
|
+
const wake = cycle.wake || {};
|
|
1226
|
+
if (wake.kind === 'fire')
|
|
1227
|
+
return `${wake.source || 'trigger'} wake`;
|
|
1228
|
+
return wake.source ? `${wake.kind} (${wake.source})` : String(wake.kind || '-');
|
|
1229
|
+
}
|
|
1230
|
+
/** What one Cycle came to, in a single line. */
|
|
1231
|
+
function cycleSummary(cycle) {
|
|
1232
|
+
if (cycle.outcome === 'stopped' && cycle.stop) {
|
|
1233
|
+
const { question, gate, reason, fix, detail } = cycle.stop;
|
|
1234
|
+
return `${question} ${reason || gate} — ${fix || detail || 'stopped'}`;
|
|
1235
|
+
}
|
|
1236
|
+
if (cycle.outcome === 'advanced') {
|
|
1237
|
+
return cycle.advancementKinds?.length
|
|
1238
|
+
? cycle.advancementKinds.join(', ')
|
|
1239
|
+
: 'applied an agent result';
|
|
1240
|
+
}
|
|
1241
|
+
if (cycle.outcome === 'in_flight') {
|
|
1242
|
+
const runs = cycle.runs?.length || 0;
|
|
1243
|
+
return runs ? `${runs} run(s) still going` : 'check still running';
|
|
1244
|
+
}
|
|
1245
|
+
return cycle.note || cycle.decision?.summary || cycle.decision?.posture || 'nothing to act on';
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* One line per Cycle:
|
|
1249
|
+
* `09-22 12:04 ● stopped act commitment_execution_budget_exhausted — Raise maxRunsPerDay…`
|
|
1250
|
+
* A run that failed is named under its Cycle with who has to move (machine
|
|
1251
|
+
* or model), because that is the next question every reader asks.
|
|
1252
|
+
*/
|
|
1253
|
+
function formatCommitmentCycles(page) {
|
|
1254
|
+
const cycles = Array.isArray(page.cycles) ? page.cycles : [];
|
|
1255
|
+
if (!cycles.length)
|
|
1256
|
+
return ['No cycles recorded yet.'];
|
|
1257
|
+
const lines = [];
|
|
1258
|
+
for (const cycle of cycles) {
|
|
1259
|
+
const glyph = CYCLE_GLYPH[cycle.outcome] || '?';
|
|
1260
|
+
lines.push(`${cycleTime(cycle.startedAt)} ${glyph} ${String(cycle.outcome).padEnd(9)} ${cycleWake(cycle).padEnd(18)} ${cycleSummary(cycle)}`);
|
|
1261
|
+
for (const run of cycle.runs || []) {
|
|
1262
|
+
if (!['machine', 'contract', 'work'].includes(run.failureClass))
|
|
1263
|
+
continue;
|
|
1264
|
+
const owner = run.failureOwner === 'model' ? 'model' : run.failureOwner || 'work';
|
|
1265
|
+
lines.push(` run ${run.id} ${run.status} — ${owner}: ${run.failureCode || '-'}`);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
if (page.has_more && page.next_cursor) {
|
|
1269
|
+
lines.push(`More cycles are available; continue with --cursor ${page.next_cursor}.`);
|
|
1270
|
+
}
|
|
1271
|
+
return lines;
|
|
1272
|
+
}
|
|
1273
|
+
const ANSWER_GLYPH = { yes: '✓', no: '✗', 'n/a': '–' };
|
|
1274
|
+
/** The six questions for the latest Cycle, the first ✗ carrying its fix. */
|
|
1275
|
+
function formatCommitmentExplanation(explanation) {
|
|
1276
|
+
const cycle = explanation.cycle;
|
|
1277
|
+
const lines = [
|
|
1278
|
+
cycle
|
|
1279
|
+
? `Latest cycle: ${cycleTime(cycle.startedAt)} ${cycle.outcome} (${cycle.id})`
|
|
1280
|
+
: `No cycle yet (status: ${explanation.status || '-'})`,
|
|
1281
|
+
];
|
|
1282
|
+
for (const answer of explanation.answers || []) {
|
|
1283
|
+
lines.push(` ${ANSWER_GLYPH[answer.answer] || '?'} ${answer.question} ${answer.because}`);
|
|
1284
|
+
if (answer.fix)
|
|
1285
|
+
lines.push(` Fix: ${answer.fix}`);
|
|
1286
|
+
}
|
|
1287
|
+
lines.push(!explanation.stoppedAt
|
|
1288
|
+
? 'Nothing stopped this cycle.'
|
|
1289
|
+
: explanation.verdict === 'quiet'
|
|
1290
|
+
? `Chose to stay quiet at: ${explanation.stoppedAt}`
|
|
1291
|
+
: `Stopped at: ${explanation.stoppedAt}`);
|
|
1292
|
+
return lines;
|
|
1293
|
+
}
|
|
1180
1294
|
/**
|
|
1181
1295
|
* Print the continuation hint for a paged `object:'list'` response — the line
|
|
1182
1296
|
* that makes history beyond the newest page reachable instead of invisible.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type DaemonVersionManifest, type ReleaseKey } from '@skrr-ai/auth-core';
|
|
1
|
+
import { isTrustedArtifactOrigin, type DaemonVersionManifest, type ReleaseKey } from '@skrr-ai/auth-core';
|
|
2
2
|
/** Public CloudFront feed. Mirrors the daemon's own `CLOUDFRONT_FEED_BASE`. */
|
|
3
|
-
export declare const DEFAULT_DAEMON_FEED_BASE = "https://updates.
|
|
3
|
+
export declare const DEFAULT_DAEMON_FEED_BASE = "https://updates.skrr.ai/daemon";
|
|
4
4
|
/** Same override the daemon honours, so one env var steers both. */
|
|
5
5
|
export declare const DAEMON_FEED_BASE_ENV = "OVERSKY_DAEMON_UPDATE_FEED_BASE";
|
|
6
6
|
export type DaemonInstallFailureCode = 'unsupported_platform' | 'manifest_unreachable' | 'manifest_malformed' | 'manifest_unsigned' | 'platform_missing' | 'untrusted_artifact_origin' | 'download_failed' | 'checksum_mismatch' | 'artifact_unsigned' | 'write_failed';
|
|
@@ -44,10 +44,11 @@ export declare function daemonBinaryPath(env?: NodeJS.ProcessEnv): string;
|
|
|
44
44
|
export declare function daemonPlatformKey(platform?: string, arch?: string): string | null;
|
|
45
45
|
/**
|
|
46
46
|
* True when `candidate` may serve an artifact for a feed rooted at `feedBase`.
|
|
47
|
-
*
|
|
48
|
-
*
|
|
47
|
+
* The predicate is shared with the daemon's self-updater via
|
|
48
|
+
* `@skrr-ai/auth-core` — during the host transition a signed manifest may
|
|
49
|
+
* legitimately point at either update origin (see TRUSTED_FEED_ORIGINS there).
|
|
49
50
|
*/
|
|
50
|
-
export
|
|
51
|
+
export { isTrustedArtifactOrigin };
|
|
51
52
|
/** Fetch `<feedBase>/latest/daemon-version.json` and verify its signature. */
|
|
52
53
|
export declare function fetchVerifiedDaemonManifest(opts?: DaemonInstallOptions): Promise<{
|
|
53
54
|
ok: true;
|
|
@@ -3,11 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.DAEMON_FEED_BASE_ENV = exports.DEFAULT_DAEMON_FEED_BASE = void 0;
|
|
6
|
+
exports.isTrustedArtifactOrigin = exports.DAEMON_FEED_BASE_ENV = exports.DEFAULT_DAEMON_FEED_BASE = void 0;
|
|
7
7
|
exports.daemonFeedBase = daemonFeedBase;
|
|
8
8
|
exports.daemonBinaryPath = daemonBinaryPath;
|
|
9
9
|
exports.daemonPlatformKey = daemonPlatformKey;
|
|
10
|
-
exports.isTrustedArtifactOrigin = isTrustedArtifactOrigin;
|
|
11
10
|
exports.fetchVerifiedDaemonManifest = fetchVerifiedDaemonManifest;
|
|
12
11
|
exports.installDaemon = installDaemon;
|
|
13
12
|
/**
|
|
@@ -63,8 +62,9 @@ const node_fs_1 = require("node:fs");
|
|
|
63
62
|
const node_os_1 = __importDefault(require("node:os"));
|
|
64
63
|
const node_path_1 = __importDefault(require("node:path"));
|
|
65
64
|
const auth_core_1 = require("@skrr-ai/auth-core");
|
|
65
|
+
Object.defineProperty(exports, "isTrustedArtifactOrigin", { enumerable: true, get: function () { return auth_core_1.isTrustedArtifactOrigin; } });
|
|
66
66
|
/** Public CloudFront feed. Mirrors the daemon's own `CLOUDFRONT_FEED_BASE`. */
|
|
67
|
-
exports.DEFAULT_DAEMON_FEED_BASE = 'https://updates.
|
|
67
|
+
exports.DEFAULT_DAEMON_FEED_BASE = 'https://updates.skrr.ai/daemon';
|
|
68
68
|
/** Same override the daemon honours, so one env var steers both. */
|
|
69
69
|
exports.DAEMON_FEED_BASE_ENV = 'OVERSKY_DAEMON_UPDATE_FEED_BASE';
|
|
70
70
|
/** Refuse a manifest larger than this. It is a small JSON document. */
|
|
@@ -102,19 +102,6 @@ function daemonPlatformKey(platform = process.platform, arch = process.arch) {
|
|
|
102
102
|
const key = `${platform}-${arch}`;
|
|
103
103
|
return supported.has(key) ? key : null;
|
|
104
104
|
}
|
|
105
|
-
/**
|
|
106
|
-
* True when `candidate` may serve an artifact for a feed rooted at `feedBase`.
|
|
107
|
-
* Same rule as the daemon's `isTrustedArtifactOrigin`: a signed manifest still
|
|
108
|
-
* does not get to point the download at another origin.
|
|
109
|
-
*/
|
|
110
|
-
function isTrustedArtifactOrigin(candidate, feedBase) {
|
|
111
|
-
try {
|
|
112
|
-
return new URL(candidate).origin === new URL(feedBase).origin;
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
105
|
function fail(code, error) {
|
|
119
106
|
return { ok: false, code, error };
|
|
120
107
|
}
|
|
@@ -193,7 +180,7 @@ async function installDaemon(opts = {}) {
|
|
|
193
180
|
if (!artifact?.url || !artifact.sha256) {
|
|
194
181
|
return fail('platform_missing', `release ${manifest.version} publishes no artifact for ${platformKey}`);
|
|
195
182
|
}
|
|
196
|
-
if (!isTrustedArtifactOrigin(artifact.url, feedBase)) {
|
|
183
|
+
if (!(0, auth_core_1.isTrustedArtifactOrigin)(artifact.url, feedBase)) {
|
|
197
184
|
return fail('untrusted_artifact_origin', `manifest points ${platformKey} at ${artifact.url}, which is not on the feed's origin`);
|
|
198
185
|
}
|
|
199
186
|
const artifactVerdict = (0, auth_core_1.verifyArtifact)(platformKey, manifest.version, artifact, keys);
|
|
@@ -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;
|
|
@@ -120,7 +141,7 @@ export interface DaemonBrokerFailure {
|
|
|
120
141
|
}
|
|
121
142
|
export type DaemonBrokerOutcome = (DaemonBrokerResult & {
|
|
122
143
|
ok: true;
|
|
123
|
-
}) | DaemonBrokerFailure;
|
|
144
|
+
}) | DaemonBrokeredOutcome | DaemonBrokerFailure;
|
|
124
145
|
export interface DaemonBrokerOptions {
|
|
125
146
|
/** Stable per-machine cliId the CLI wants the new refresh row bound to. */
|
|
126
147
|
cliId: string;
|
|
@@ -151,6 +172,22 @@ export interface DaemonBrokerOptions {
|
|
|
151
172
|
candidatePathsOverride?: readonly string[];
|
|
152
173
|
/** Override total request timeout. Tests use a short value. */
|
|
153
174
|
timeoutMs?: number;
|
|
175
|
+
/**
|
|
176
|
+
* Which advertised mode to prefer when a descriptor offers both
|
|
177
|
+
* (`handoffModes: ['access_token', 'refresh_family']`, the laptop island
|
|
178
|
+
* shape during transition):
|
|
179
|
+
*
|
|
180
|
+
* - `'access_token'` — broker mode: redeem a short-lived access token
|
|
181
|
+
* and hold it in memory only. Used by `maybeAutoBroker`: nothing
|
|
182
|
+
* credential-shaped lands on disk and each `skrr` process re-redeems
|
|
183
|
+
* over loopback.
|
|
184
|
+
* - `'refresh_family'` (default) — the legacy durable mint. Used by
|
|
185
|
+
* explicit `skrr login`: a human login still writes a real,
|
|
186
|
+
* user-owned refresh family. A descriptor that advertises ONLY
|
|
187
|
+
* `access_token` (the Dedicated guest shape) redeems brokered
|
|
188
|
+
* regardless — its secret cannot mint a family at all.
|
|
189
|
+
*/
|
|
190
|
+
preferHandoffMode?: 'access_token' | 'refresh_family';
|
|
154
191
|
}
|
|
155
192
|
/**
|
|
156
193
|
* Compute the bootstrap file path. Exported for tests so they can assert
|
|
@@ -214,10 +251,60 @@ export declare function readBootstrap(filePath: string): LocalBootstrap | null;
|
|
|
214
251
|
*/
|
|
215
252
|
export declare function attemptDaemonBrokerLogin(opts: DaemonBrokerOptions): Promise<DaemonBrokerOutcome>;
|
|
216
253
|
/**
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
254
|
+
* True when `token` is the access token this process redeemed through the
|
|
255
|
+
* daemon's broker-mode hand-off. `api-fetch` uses this to pick the re-redeem
|
|
256
|
+
* recovery branch instead of the stored-family refresh (which would have
|
|
257
|
+
* nothing to rotate — brokered credentials are never persisted).
|
|
258
|
+
*/
|
|
259
|
+
export declare function isBrokeredHandoffToken(token: string | null | undefined): boolean;
|
|
260
|
+
/**
|
|
261
|
+
* Re-redeem the brokered hand-off token — the 401-recovery path. The
|
|
262
|
+
* descriptor is re-read from disk when its source path is known, so a secret
|
|
263
|
+
* rotated by a daemon restart resolves to the fresh one. Returns null when
|
|
264
|
+
* this process holds no brokered credential or the redeem fails (the caller
|
|
265
|
+
* then surfaces the original 401).
|
|
266
|
+
*/
|
|
267
|
+
export declare function redeemBrokeredHandoffToken(forceRefresh?: boolean): Promise<CliHandoffTokenResponse | null>;
|
|
268
|
+
/** @internal test seam — clears the module-scoped brokered credential. */
|
|
269
|
+
export declare function __resetBrokeredHandoffForTest(): void;
|
|
270
|
+
/**
|
|
271
|
+
* True when a live local descriptor advertises broker-mode access — i.e.
|
|
272
|
+
* this machine's CLI authority is platform-managed and `skrr logout` has no
|
|
273
|
+
* local credential to clear. Read-only: parses candidates, never redeems.
|
|
274
|
+
*/
|
|
275
|
+
export declare function findBrokeredHandoffDescriptor(profile?: string): LocalBootstrap | null;
|
|
276
|
+
/**
|
|
277
|
+
* Migration cleanup: retire the refresh family a pre-broker-mode CLI
|
|
278
|
+
* generation persisted, now that this machine redeems access tokens from
|
|
279
|
+
* the daemon's in-memory broker.
|
|
280
|
+
*
|
|
281
|
+
* Provenance guard — locally we cannot tell a hand-off-minted family from a
|
|
282
|
+
* user's explicit `skrr login` family by shape (the distinguishing
|
|
283
|
+
* `daemonRefOverride` lives server-side). The safe rule, applied here:
|
|
284
|
+
* revoke + delete ONLY when all of these hold —
|
|
285
|
+
*
|
|
286
|
+
* 1. the descriptor that just redeemed IS the Dedicated Runtime guest
|
|
287
|
+
* hand-off file (`/run/skrr-dedicated-runtime/...`),
|
|
288
|
+
* 2. `~/.skrr/cli-auth.json` reads cleanly and carries a refresh token,
|
|
289
|
+
* 3. its stored `serverOrigin` matches the descriptor's `serverUrl`.
|
|
290
|
+
*
|
|
291
|
+
* When provenance can't be proven the file is KEPT: an explicit `skrr login`
|
|
292
|
+
* on a guest is rare but real, and a stale extra family is bounded by the
|
|
293
|
+
* server's session cap and expires on its own. Best-effort throughout — a
|
|
294
|
+
* failed revoke still deletes the file (the whole point is that nothing
|
|
295
|
+
* credential-shaped should remain), and any failure leaves the working
|
|
296
|
+
* brokered credential untouched.
|
|
297
|
+
*/
|
|
298
|
+
export declare function maybeRetireStoredCliAuthFile(opts: {
|
|
299
|
+
descriptorPath?: string;
|
|
300
|
+
descriptorServerUrl?: string;
|
|
301
|
+
}): Promise<void>;
|
|
302
|
+
/**
|
|
303
|
+
* Convenience wrapper: run the broker call and, on a durable-mint success,
|
|
304
|
+
* persist the returned bundle through the canonical Sky CLI auth backend
|
|
305
|
+
* (Keychain on macOS, `cli-auth.json` elsewhere). A `brokered` outcome is
|
|
306
|
+
* returned WITHOUT persisting — that is the entire point of broker mode.
|
|
307
|
+
* Returns the same outcome shape so the caller can branch on `ok`/`brokered`.
|
|
221
308
|
*/
|
|
222
309
|
export declare function attemptDaemonBrokerLoginAndPersist(opts: DaemonBrokerOptions): Promise<DaemonBrokerOutcome>;
|
|
223
310
|
export interface MaybeAutoBrokerOptions {
|
|
@@ -275,10 +362,12 @@ export interface MaybeAutoBrokerResult {
|
|
|
275
362
|
* - `commandId` is in `AUTH_SELF_MANAGED_COMMANDS`
|
|
276
363
|
*
|
|
277
364
|
* Side effects:
|
|
278
|
-
* - Calls `attemptDaemonBrokerLoginAndPersist`
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
365
|
+
* - Calls `attemptDaemonBrokerLoginAndPersist` with `preferHandoffMode:
|
|
366
|
+
* 'access_token'`. On a descriptor that advertises broker mode the
|
|
367
|
+
* outcome is `brokered` — an in-memory access token, nothing written;
|
|
368
|
+
* the caller holds it for this process and the next `skrr` re-redeems.
|
|
369
|
+
* On a legacy/v1 descriptor the durable mint is persisted to the
|
|
370
|
+
* keychain / cli-auth.json exactly as before.
|
|
282
371
|
* - May generate a new `cliId` if the config doesn't have one. The
|
|
283
372
|
* caller MUST persist `updatedConfig` so the next invocation
|
|
284
373
|
* presents the same id to the server's refresh rotator.
|