@skrr-ai/cli 0.1.94 → 0.1.96
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 +175 -165
- package/bin/run.js +32 -0
- package/bin/update-npm-runner.cjs +33 -0
- package/bin/update-session.cjs +194 -0
- package/bin/update-worker.cjs +208 -0
- package/dist/base-command.js +0 -15
- package/dist/commands/agent/message/send.d.ts +2 -0
- package/dist/commands/agent/message/send.js +75 -5
- package/dist/commands/agents/chat.js +1 -1
- package/dist/commands/agents/create.d.ts +0 -3
- package/dist/commands/agents/create.js +0 -26
- package/dist/commands/agents/egress.d.ts +17 -0
- package/dist/commands/agents/egress.js +84 -0
- package/dist/commands/agents/mailbox/messages.d.ts +14 -0
- package/dist/commands/agents/mailbox/messages.js +52 -0
- package/dist/commands/agents/mailbox/show.d.ts +13 -0
- package/dist/commands/agents/mailbox/show.js +52 -0
- package/dist/commands/agents/operating-plan.js +8 -0
- package/dist/commands/agents/roles/capture.d.ts +16 -0
- package/dist/commands/agents/roles/capture.js +53 -0
- package/dist/commands/agents/roles/install.d.ts +1 -0
- package/dist/commands/agents/roles/install.js +8 -1
- package/dist/commands/agents/roles/preview.d.ts +2 -0
- package/dist/commands/agents/roles/preview.js +27 -3
- package/dist/commands/agents/update.d.ts +0 -3
- package/dist/commands/agents/update.js +1 -31
- package/dist/commands/agents/usage-cap.d.ts +4 -1
- package/dist/commands/agents/usage-cap.js +49 -10
- package/dist/commands/code/doctor.d.ts +1 -0
- package/dist/commands/code/doctor.js +6 -0
- package/dist/commands/code/index.js +4 -0
- package/dist/commands/code/install.d.ts +5 -62
- package/dist/commands/code/install.js +86 -279
- package/dist/commands/code/jobs/show.js +12 -0
- package/dist/commands/code/rollback.d.ts +8 -0
- package/dist/commands/code/rollback.js +20 -0
- package/dist/commands/code/update.d.ts +8 -37
- package/dist/commands/code/update.js +134 -213
- package/dist/commands/commitments/action-proposals/decide.d.ts +2 -0
- package/dist/commands/commitments/action-proposals/decide.js +12 -0
- package/dist/commands/commitments/action-proposals.js +7 -0
- package/dist/commands/commitments/create.d.ts +1 -0
- package/dist/commands/commitments/create.js +17 -1
- package/dist/commands/commitments/delivery.d.ts +1 -0
- package/dist/commands/commitments/delivery.js +11 -1
- package/dist/commands/commitments/doctor.js +4 -0
- package/dist/commands/commitments/effective-policy.js +26 -0
- package/dist/commands/commitments/endpoints/create.js +5 -2
- package/dist/commands/commitments/observations.d.ts +10 -0
- package/dist/commands/commitments/observations.js +88 -0
- package/dist/commands/commitments/pause.d.ts +1 -1
- package/dist/commands/commitments/pause.js +4 -3
- package/dist/commands/commitments/preflight.js +2 -1
- package/dist/commands/commitments/reports.d.ts +2 -0
- package/dist/commands/commitments/reports.js +22 -4
- package/dist/commands/commitments/update.d.ts +1 -0
- package/dist/commands/commitments/update.js +35 -5
- package/dist/commands/daemon/install.js +4 -0
- package/dist/commands/generate-recovery-code.d.ts +13 -1
- package/dist/commands/generate-recovery-code.js +146 -13
- package/dist/commands/grants/create.d.ts +1 -0
- package/dist/commands/grants/create.js +8 -0
- package/dist/commands/grants/rotate.d.ts +5 -0
- package/dist/commands/grants/rotate.js +13 -1
- package/dist/commands/grants/update.d.ts +12 -0
- package/dist/commands/grants/update.js +27 -0
- package/dist/commands/instructions/guide.d.ts +20 -0
- package/dist/commands/instructions/guide.js +84 -0
- package/dist/commands/instructions/install.js +57 -33
- package/dist/commands/instructions/setup.d.ts +14 -0
- package/dist/commands/instructions/setup.js +72 -0
- package/dist/commands/integrations/execute.js +1 -1
- package/dist/commands/login.d.ts +5 -6
- package/dist/commands/login.js +27 -11
- package/dist/commands/logout.js +7 -7
- package/dist/commands/machines/hosted/start.js +7 -1
- package/dist/commands/machines/list.js +4 -4
- package/dist/commands/measures/confirm.d.ts +1 -7
- package/dist/commands/measures/confirm.js +15 -14
- package/dist/commands/measures/list.d.ts +1 -7
- package/dist/commands/measures/list.js +1 -7
- package/dist/commands/measures/record.js +4 -4
- package/dist/commands/measures/show.d.ts +11 -0
- package/dist/commands/measures/show.js +26 -0
- package/dist/commands/northstars/governance/configure.d.ts +1 -0
- package/dist/commands/northstars/governance/configure.js +8 -1
- package/dist/commands/proposals/discard.d.ts +5 -0
- package/dist/commands/proposals/discard.js +8 -0
- package/dist/commands/proposals/keep.d.ts +5 -0
- package/dist/commands/proposals/keep.js +8 -0
- package/dist/commands/proposals/list.d.ts +15 -0
- package/dist/commands/proposals/list.js +74 -0
- package/dist/commands/proposals/show.d.ts +12 -0
- package/dist/commands/proposals/show.js +27 -0
- package/dist/commands/proposals/snooze.d.ts +5 -0
- package/dist/commands/proposals/snooze.js +8 -0
- package/dist/commands/security/overview.d.ts +11 -0
- package/dist/commands/security/overview.js +158 -0
- package/dist/commands/signals/monitors/create.d.ts +9 -0
- package/dist/commands/signals/monitors/create.js +29 -0
- package/dist/commands/signals/monitors/list.d.ts +8 -0
- package/dist/commands/signals/monitors/list.js +16 -0
- package/dist/commands/signals/monitors/pause.d.ts +11 -0
- package/dist/commands/signals/monitors/pause.js +17 -0
- package/dist/commands/signals/monitors/resume.d.ts +11 -0
- package/dist/commands/signals/monitors/resume.js +17 -0
- package/dist/commands/signals/monitors/revise.d.ts +12 -0
- package/dist/commands/signals/monitors/revise.js +25 -0
- package/dist/commands/signals/monitors/show.d.ts +11 -0
- package/dist/commands/signals/monitors/show.js +17 -0
- package/dist/commands/signals/monitors/test.d.ts +12 -0
- package/dist/commands/signals/monitors/test.js +25 -0
- package/dist/commands/signals/monitors/transitions.d.ts +11 -0
- package/dist/commands/signals/monitors/transitions.js +17 -0
- package/dist/commands/signals/monitors/validate.d.ts +9 -0
- package/dist/commands/signals/monitors/validate.js +24 -0
- package/dist/commands/signals/schemas/list.d.ts +8 -0
- package/dist/commands/signals/schemas/list.js +16 -0
- package/dist/commands/signals/schemas/show.d.ts +11 -0
- package/dist/commands/signals/schemas/show.js +17 -0
- package/dist/commands/signals/sources/list.d.ts +8 -0
- package/dist/commands/signals/sources/list.js +16 -0
- package/dist/commands/signals/sources/receipts.d.ts +11 -0
- package/dist/commands/signals/sources/receipts.js +17 -0
- package/dist/commands/signals/sources/show.d.ts +11 -0
- package/dist/commands/signals/sources/show.js +17 -0
- package/dist/commands/spaces/claim.d.ts +12 -0
- package/dist/commands/spaces/claim.js +42 -0
- package/dist/commands/spaces/ownership.d.ts +12 -0
- package/dist/commands/spaces/ownership.js +46 -0
- package/dist/commands/spaces/usage.d.ts +12 -0
- package/dist/commands/spaces/usage.js +28 -0
- package/dist/commands/spaces/workflows/run.js +3 -0
- package/dist/commands/spaces/workflows/runs.js +2 -1
- package/dist/commands/spaces/workflows/update.d.ts +6 -1
- package/dist/commands/spaces/workflows/update.js +34 -2
- package/dist/commands/tasks/cancel-cascade.js +1 -1
- package/dist/commands/tasks/cascade-status.d.ts +2 -0
- package/dist/commands/tasks/cascade-status.js +27 -1
- package/dist/commands/tasks/create-tree.d.ts +5 -1
- package/dist/commands/tasks/create-tree.js +35 -7
- package/dist/commands/tasks/create.d.ts +4 -0
- package/dist/commands/tasks/create.js +16 -0
- package/dist/commands/tasks/deliverable/add.js +12 -3
- package/dist/commands/tasks/economics-compare.d.ts +15 -0
- package/dist/commands/tasks/economics-compare.js +60 -0
- package/dist/commands/tasks/expectations/evaluate.d.ts +13 -0
- package/dist/commands/tasks/expectations/evaluate.js +43 -0
- package/dist/commands/tasks/interrupt.js +2 -2
- package/dist/commands/tasks/list.d.ts +1 -0
- package/dist/commands/tasks/list.js +44 -1
- package/dist/commands/tasks/pause-schedule.js +1 -1
- package/dist/commands/tasks/show.d.ts +5 -0
- package/dist/commands/tasks/show.js +17 -0
- package/dist/commands/tasks/update.d.ts +4 -0
- package/dist/commands/tasks/update.js +9 -0
- package/dist/commands/tasks/workflow-findings.js +2 -2
- package/dist/commands/token/list.d.ts +3 -5
- package/dist/commands/token/list.js +99 -57
- package/dist/commands/triggers/create.d.ts +2 -0
- package/dist/commands/triggers/create.js +15 -0
- package/dist/commands/update.d.ts +14 -0
- package/dist/commands/update.js +61 -0
- package/dist/commands/workspaces/grants.d.ts +12 -0
- package/dist/commands/workspaces/grants.js +31 -0
- package/dist/commands/workspaces/stewardship.d.ts +13 -0
- package/dist/commands/workspaces/stewardship.js +34 -0
- package/dist/generated/managed-instruction-guides.json +9 -0
- package/dist/hooks/init.d.ts +5 -0
- package/dist/hooks/init.js +27 -0
- package/dist/lib/agent-config.d.ts +0 -12
- package/dist/lib/agent-config.js +1 -27
- package/dist/lib/agent-mailbox.d.ts +35 -0
- package/dist/lib/agent-mailbox.js +55 -0
- package/dist/lib/commitment-endpoints.d.ts +2 -1
- package/dist/lib/commitment-endpoints.js +2 -5
- package/dist/lib/commitment-product.d.ts +3 -1
- package/dist/lib/commitment-product.js +10 -0
- package/dist/lib/commitment-terms.js +1 -1
- package/dist/lib/commitments.d.ts +17 -15
- package/dist/lib/commitments.js +173 -137
- package/dist/lib/compasses.d.ts +14 -0
- package/dist/lib/compasses.js +25 -11
- package/dist/lib/daemon-installer.d.ts +2 -0
- package/dist/lib/daemon-installer.js +100 -24
- package/dist/lib/first-party-harness-doctor.js +31 -1
- package/dist/lib/first-party-harness-remote-install.d.ts +71 -0
- package/dist/lib/first-party-harness-remote-install.js +310 -0
- package/dist/lib/first-party-harness-remote-update.d.ts +46 -0
- package/dist/lib/first-party-harness-remote-update.js +242 -0
- package/dist/lib/first-party-harness-startup-update.d.ts +26 -0
- package/dist/lib/first-party-harness-startup-update.js +166 -0
- package/dist/lib/first-party-harness-update.d.ts +46 -0
- package/dist/lib/first-party-harness-update.js +289 -0
- package/dist/lib/first-party-harness.js +7 -4
- package/dist/lib/grants.d.ts +5 -1
- package/dist/lib/grants.js +9 -1
- package/dist/lib/hosted-machines.d.ts +7 -0
- package/dist/lib/mailbox-human-command.d.ts +11 -0
- package/dist/lib/mailbox-human-command.js +41 -0
- package/dist/lib/managed-instruction-local.d.ts +12 -0
- package/dist/lib/managed-instruction-local.js +58 -0
- package/dist/lib/managed-instruction-setup.d.ts +35 -0
- package/dist/lib/managed-instruction-setup.js +306 -0
- package/dist/lib/measures.d.ts +28 -2
- package/dist/lib/measures.js +38 -14
- package/dist/lib/memory-sync.d.ts +1 -0
- package/dist/lib/memory-sync.js +279 -68
- package/dist/lib/message-intent.d.ts +6 -2
- package/dist/lib/message-intent.js +1 -0
- package/dist/lib/northstars.js +2 -1
- package/dist/lib/platform-update-local.d.ts +2 -0
- package/dist/lib/platform-update-local.js +113 -0
- package/dist/lib/platform-update.d.ts +39 -0
- package/dist/lib/platform-update.js +84 -0
- package/dist/lib/profile-machine-identity-guard.d.ts +2 -0
- package/dist/lib/profile-machine-identity-guard.js +13 -0
- package/dist/lib/prompt.d.ts +1 -0
- package/dist/lib/prompt.js +4 -3
- package/dist/lib/proposal-decision-command.d.ts +19 -0
- package/dist/lib/proposal-decision-command.js +64 -0
- package/dist/lib/proposals.d.ts +8 -0
- package/dist/lib/proposals.js +22 -0
- package/dist/lib/roles.d.ts +141 -6
- package/dist/lib/roles.js +8 -2
- package/dist/lib/signals.d.ts +20 -0
- package/dist/lib/signals.js +24 -0
- package/dist/lib/space-usage.d.ts +3 -0
- package/dist/lib/space-usage.js +17 -0
- package/dist/lib/stewardship-output.d.ts +4 -0
- package/dist/lib/stewardship-output.js +82 -0
- package/dist/lib/task-asset-upload.d.ts +3 -1
- package/dist/lib/task-asset-upload.js +1 -0
- package/dist/lib/task-batch.d.ts +9 -0
- package/dist/lib/task-batch.js +94 -17
- package/dist/lib/task-economics.d.ts +16 -0
- package/dist/lib/task-economics.js +22 -0
- package/dist/lib/task-instruction-offer.d.ts +1 -4
- package/dist/lib/task-instruction-offer.js +3 -129
- package/dist/lib/triggers.d.ts +11 -3
- package/dist/lib/triggers.js +58 -1
- package/dist/lib/update-check.d.ts +61 -53
- package/dist/lib/update-check.js +453 -314
- package/dist/lib/usage-discovery.d.ts +10 -0
- package/dist/lib/usage-discovery.js +24 -3
- package/dist/lib/workflow-run-budget.d.ts +12 -0
- package/dist/lib/workflow-run-budget.js +37 -0
- package/dist/lib/workspaces.d.ts +48 -0
- package/dist/lib/workspaces.js +8 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.d.ts +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.js +14 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.d.ts +3 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessChannels.js +3 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessReleaseKeys.d.ts +82 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessReleaseKeys.js +105 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessUpdater.d.ts +110 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/firstPartyHarnessUpdater.js +945 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/githubPushRefusal.d.ts +9 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/githubPushRefusal.js +49 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.d.ts +32 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessPermissionControls.js +62 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +4 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +35 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releasePolicy.d.ts +63 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releasePolicy.js +169 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseVersions.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/releaseVersions.js +44 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.d.ts +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.js +12 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.d.ts +3 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessChannels.js +3 -4
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessReleaseKeys.d.ts +82 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessReleaseKeys.js +102 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessUpdater.d.ts +110 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/firstPartyHarnessUpdater.js +923 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/githubPushRefusal.d.ts +9 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/githubPushRefusal.js +44 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.d.ts +32 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessPermissionControls.js +59 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +35 -5
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releasePolicy.d.ts +63 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releasePolicy.js +163 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseVersions.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/releaseVersions.js +41 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +41 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +8069 -7121
- package/docs/v1/README.md +28 -0
- package/docs/v1/api.md +55 -0
- package/docs/v1/changelog.md +16 -0
- package/docs/v1/check-examples.mjs +178 -0
- package/docs/v1/examples/api-readonly.mjs +144 -0
- package/docs/v1/operations.md +87 -0
- package/docs/v1/quickstart.md +71 -0
- package/oclif.manifest.json +49424 -46174
- package/package.json +34 -11
|
@@ -1,8 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseObservationWindow = parseObservationWindow;
|
|
4
|
+
exports.renderObservationWindow = renderObservationWindow;
|
|
3
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
4
7
|
const base_command_1 = require("../../base-command");
|
|
5
8
|
const commitments_1 = require("../../lib/commitments");
|
|
9
|
+
/** Explicit ISO FROM/TO intervals avoid local-time or rolling-window ambiguity. */
|
|
10
|
+
function parseObservationWindow(value) {
|
|
11
|
+
const parts = value.split('/');
|
|
12
|
+
const timestamp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
13
|
+
const [from, to] = parts.map((entry) => new Date(entry).getTime());
|
|
14
|
+
const realCalendarDay = (part) => {
|
|
15
|
+
const day = part.slice(0, 10);
|
|
16
|
+
const parsed = new Date(`${day}T00:00:00Z`);
|
|
17
|
+
return Number.isFinite(parsed.getTime()) && parsed.toISOString().slice(0, 10) === day;
|
|
18
|
+
};
|
|
19
|
+
if (parts.length !== 2 ||
|
|
20
|
+
!parts.every((part) => timestamp.test(part) && realCalendarDay(part)) ||
|
|
21
|
+
!Number.isFinite(from) ||
|
|
22
|
+
!Number.isFinite(to) ||
|
|
23
|
+
to <= from ||
|
|
24
|
+
to - from > data_provider_1.OBSERVATION_WINDOW_MAX_MS)
|
|
25
|
+
throw new Error('Window requires ISO FROM/TO with an explicit timezone and a positive span of at most 90 days');
|
|
26
|
+
return { from: new Date(from).toISOString(), to: new Date(to).toISOString() };
|
|
27
|
+
}
|
|
28
|
+
function renderObservationWindow(response, log) {
|
|
29
|
+
// Always announce partial data before showing figures, including baseline truncation.
|
|
30
|
+
if (response.truncated)
|
|
31
|
+
log('TRUNCATED: bounded sample only; figures are incomplete.');
|
|
32
|
+
log('Agent-reported samples; as-of interval coverage is not independent verification.');
|
|
33
|
+
const display = (label, value) => {
|
|
34
|
+
const window = value;
|
|
35
|
+
log(`${label}: [${window.from}, ${window.to})`);
|
|
36
|
+
log(`Samples: ${window.count}; numeric: ${window.numericCount}; unreadable: ${window.gapCount}; uncovered ms: ${window.gapMs}`);
|
|
37
|
+
log(`Mean: ${window.mean ?? 'unknown'}; sum: ${window.sum ?? 'unknown'}; first: ${window.first ?? 'unknown'}; last: ${window.last ?? 'unknown'}`);
|
|
38
|
+
};
|
|
39
|
+
if (response.baseline) {
|
|
40
|
+
display('Baseline', response.baseline);
|
|
41
|
+
display('After', response.after);
|
|
42
|
+
log(`Comparison: ${response.sufficient ? `delta=${response.delta}; ratio=${response.ratio}` : `unavailable (${response.reason})`}`);
|
|
43
|
+
}
|
|
44
|
+
else
|
|
45
|
+
display('Window', response.summary);
|
|
46
|
+
}
|
|
6
47
|
/**
|
|
7
48
|
* `skrr commitments observations <id>` — what this commitment's runs saw.
|
|
8
49
|
*
|
|
@@ -30,6 +71,18 @@ class CommitmentsObservations extends base_command_1.BaseCommand {
|
|
|
30
71
|
};
|
|
31
72
|
static flags = {
|
|
32
73
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
74
|
+
latest: core_1.Flags.boolean({
|
|
75
|
+
description: 'Latest recorded attempt per current declared key (not history)',
|
|
76
|
+
}),
|
|
77
|
+
key: core_1.Flags.string({ description: 'Observation key for --window' }),
|
|
78
|
+
window: core_1.Flags.string({
|
|
79
|
+
description: 'Half-open ISO FROM/TO interval, at most 90 days',
|
|
80
|
+
dependsOn: ['key'],
|
|
81
|
+
}),
|
|
82
|
+
'compare-to': core_1.Flags.string({
|
|
83
|
+
description: 'Baseline ISO FROM/TO interval',
|
|
84
|
+
dependsOn: ['window'],
|
|
85
|
+
}),
|
|
33
86
|
limit: core_1.Flags.integer({ description: 'Rows to include', min: 1, max: 200 }),
|
|
34
87
|
'declared-only': core_1.Flags.boolean({
|
|
35
88
|
description: 'Only keys the operator declared — the rows that can move the loop',
|
|
@@ -45,10 +98,42 @@ class CommitmentsObservations extends base_command_1.BaseCommand {
|
|
|
45
98
|
async run() {
|
|
46
99
|
this.requireAuth();
|
|
47
100
|
const { args, flags } = await this.parse(CommitmentsObservations);
|
|
101
|
+
if (flags.latest && (flags.window || flags.cursor || flags['changed-only'] || flags.since))
|
|
102
|
+
this.error('--latest cannot be combined with --window, --cursor, --changed-only, or --since');
|
|
48
103
|
let response;
|
|
104
|
+
if (flags.window) {
|
|
105
|
+
try {
|
|
106
|
+
if (flags['declared-only'] || flags['changed-only'] || flags.since || flags.cursor)
|
|
107
|
+
this.error('--window cannot be combined with list filters');
|
|
108
|
+
const query = {
|
|
109
|
+
key: flags.key,
|
|
110
|
+
...parseObservationWindow(flags.window),
|
|
111
|
+
limit: flags.limit,
|
|
112
|
+
};
|
|
113
|
+
const baseline = flags['compare-to'] ? parseObservationWindow(flags['compare-to']) : null;
|
|
114
|
+
response = baseline
|
|
115
|
+
? await commitments_1.commitmentApi.observationCompare(args.commitmentId, {
|
|
116
|
+
...query,
|
|
117
|
+
baselineFrom: baseline.from,
|
|
118
|
+
baselineTo: baseline.to,
|
|
119
|
+
})
|
|
120
|
+
: await commitments_1.commitmentApi.observationSeries(args.commitmentId, query);
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
this.handleApiError(err);
|
|
124
|
+
}
|
|
125
|
+
if (flags.json)
|
|
126
|
+
this.log(JSON.stringify(response, null, 2));
|
|
127
|
+
else
|
|
128
|
+
renderObservationWindow(response, (line) => this.log(line));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (flags.key)
|
|
132
|
+
this.error('--key requires --window');
|
|
49
133
|
try {
|
|
50
134
|
response = await commitments_1.commitmentApi.observations(args.commitmentId, {
|
|
51
135
|
limit: flags.limit,
|
|
136
|
+
latest: flags.latest || undefined,
|
|
52
137
|
declaredOnly: flags['declared-only'] || undefined,
|
|
53
138
|
changedOnly: flags['changed-only'] || undefined,
|
|
54
139
|
since: flags.since,
|
|
@@ -66,6 +151,7 @@ class CommitmentsObservations extends base_command_1.BaseCommand {
|
|
|
66
151
|
// facts; a filter that empties the list must not claim the first
|
|
67
152
|
// (OSK-10953).
|
|
68
153
|
const filters = [
|
|
154
|
+
flags.latest ? '--latest' : null,
|
|
69
155
|
flags['declared-only'] ? '--declared-only' : null,
|
|
70
156
|
flags['changed-only'] ? '--changed-only' : null,
|
|
71
157
|
flags.since ? `--since ${flags.since}` : null,
|
|
@@ -73,6 +159,8 @@ class CommitmentsObservations extends base_command_1.BaseCommand {
|
|
|
73
159
|
const emptyMessage = filters.length
|
|
74
160
|
? `No observations match ${filters.join(' ')}.`
|
|
75
161
|
: 'No observations recorded.';
|
|
162
|
+
if (response?.truncated)
|
|
163
|
+
this.log(`TRUNCATED: ${response.omitted} current keys omitted; increase --limit (max 200).`);
|
|
76
164
|
(0, commitments_1.renderCommitmentObservations)(response, (line) => this.log(line), { emptyMessage });
|
|
77
165
|
}
|
|
78
166
|
(0, commitments_1.renderListPageHint)(response, (line) => this.log(line));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
2
|
/**
|
|
3
3
|
* `skrr commitments pause <id>` — stop the control loop without losing the
|
|
4
|
-
* contract or its history.
|
|
4
|
+
* contract or its history. An already executing turn may continue.
|
|
5
5
|
*/
|
|
6
6
|
export default class CommitmentsPause extends BaseCommand {
|
|
7
7
|
static description: string;
|
|
@@ -6,10 +6,10 @@ const web_url_1 = require("../../lib/web-url");
|
|
|
6
6
|
const commitments_1 = require("../../lib/commitments");
|
|
7
7
|
/**
|
|
8
8
|
* `skrr commitments pause <id>` — stop the control loop without losing the
|
|
9
|
-
* contract or its history.
|
|
9
|
+
* contract or its history. An already executing turn may continue.
|
|
10
10
|
*/
|
|
11
11
|
class CommitmentsPause extends base_command_1.BaseCommand {
|
|
12
|
-
static description = 'Pause a commitment —
|
|
12
|
+
static description = 'Pause a commitment — stops new work; a turn already running may continue until it finishes or reaches its deadline';
|
|
13
13
|
static examples = ['<%= config.bin %> commitments pause <commitment-id>'];
|
|
14
14
|
static args = {
|
|
15
15
|
id: core_1.Args.string({ description: 'Commitment ID', required: true, ignoreStdin: true }),
|
|
@@ -30,6 +30,7 @@ class CommitmentsPause extends base_command_1.BaseCommand {
|
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
this.log(`Paused commitment ${args.id}.`);
|
|
33
|
+
this.log('Stops new work. A turn already running may continue until it finishes or reaches its deadline.');
|
|
33
34
|
// The status write is the fence and it has landed. The teardown of the
|
|
34
35
|
// wake tree behind it is best-effort, and used to be silent — so a pause
|
|
35
36
|
// that left triggers live looked exactly like one that did not. Say which
|
|
@@ -39,7 +40,7 @@ class CommitmentsPause extends base_command_1.BaseCommand {
|
|
|
39
40
|
.teardown;
|
|
40
41
|
if (teardown?.status === 'degraded') {
|
|
41
42
|
this.warn('The control loop is stopped, but some scheduled wakes may not have been retired yet. ' +
|
|
42
|
-
'They cannot
|
|
43
|
+
'They cannot start new work — every wake is refused while this Commitment is paused — ' +
|
|
43
44
|
`and the reconciler retries automatically. Check with: skrr commitments trigger-status ${args.id}`);
|
|
44
45
|
}
|
|
45
46
|
(0, commitments_1.renderCommitmentSummary)(commitment, (line) => this.log(line));
|
|
@@ -153,7 +153,8 @@ class CommitmentsPreflight extends base_command_1.BaseCommand {
|
|
|
153
153
|
for (const endpoint of report.endpoints || []) {
|
|
154
154
|
this.log(` ${endpoint.available ? 'ok ' : 'BLOCK'} ${endpoint.label || endpoint.destination}` +
|
|
155
155
|
` — ${(endpoint.capabilities || []).join(', ') || 'no capabilities'}` +
|
|
156
|
-
(endpoint.reason ? ` (${endpoint.reason})` : '')
|
|
156
|
+
(endpoint.reason ? ` (${endpoint.reason})` : '') +
|
|
157
|
+
(!endpoint.available && endpoint.detail ? ` — ${endpoint.detail}` : ''));
|
|
157
158
|
}
|
|
158
159
|
this.log(`\nAttention: ${report.attention?.allowed ? 'delivery allowed now' : `suppressed by ${report.attention?.suppressedBy || 'policy'}`}`);
|
|
159
160
|
if (report.verdict === 'blocked')
|
|
@@ -19,7 +19,9 @@ export default class CommitmentsReports extends BaseCommand {
|
|
|
19
19
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
20
20
|
add: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
21
21
|
target: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
22
|
+
review: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
22
23
|
on: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
24
|
+
format: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
23
25
|
remove: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
24
26
|
};
|
|
25
27
|
run(): Promise<void>;
|
|
@@ -6,16 +6,18 @@ const base_command_1 = require("../../base-command");
|
|
|
6
6
|
const commitments_1 = require("../../lib/commitments");
|
|
7
7
|
const commitment_terms_1 = require("../../lib/commitment-terms");
|
|
8
8
|
/** Destinations that address one specific place and therefore need a target. */
|
|
9
|
-
const DESTINATIONS_NEEDING_TARGET = new Set(
|
|
9
|
+
const DESTINATIONS_NEEDING_TARGET = new Set(Object.values(data_provider_1.COMMITMENT_DESTINATION_REGISTRY)
|
|
10
|
+
.filter((destination) => destination.requiresTarget)
|
|
11
|
+
.map((destination) => destination.key));
|
|
10
12
|
/**
|
|
11
13
|
* Keep the CLI safe across a rolling data-provider build. Older installed
|
|
12
14
|
* packages expose the compatibility destination list but not the narrowed
|
|
13
15
|
* authoring list; derive the same restriction instead of crashing command
|
|
14
|
-
* discovery
|
|
16
|
+
* discovery.
|
|
15
17
|
*/
|
|
16
18
|
const AUTHORABLE_REPORT_DESTINATIONS = Array.isArray(data_provider_1.COMMITMENT_AUTHORABLE_REPORT_DESTINATIONS)
|
|
17
19
|
? data_provider_1.COMMITMENT_AUTHORABLE_REPORT_DESTINATIONS
|
|
18
|
-
: data_provider_1.COMMITMENT_REPORT_DESTINATIONS
|
|
20
|
+
: data_provider_1.COMMITMENT_REPORT_DESTINATIONS;
|
|
19
21
|
/**
|
|
20
22
|
* Identity of a report target = destination + its target id. The same channel
|
|
21
23
|
* may legitimately appear twice with different `on` conditions (a digest on
|
|
@@ -41,6 +43,7 @@ class CommitmentsReports extends base_command_1.BaseCommand {
|
|
|
41
43
|
'<%= config.bin %> commitments reports <commitment-id>',
|
|
42
44
|
'<%= config.bin %> commitments reports <commitment-id> --add slack_channel --target C0123456 --on material_change',
|
|
43
45
|
'<%= config.bin %> commitments reports <commitment-id> --add main --on completion',
|
|
46
|
+
'<%= config.bin %> commitments reports <commitment-id> --add user_notify --target <user-id> --review owner',
|
|
44
47
|
'<%= config.bin %> commitments reports <commitment-id> --remove slack_channel:C0123456',
|
|
45
48
|
];
|
|
46
49
|
static args = {
|
|
@@ -53,12 +56,20 @@ class CommitmentsReports extends base_command_1.BaseCommand {
|
|
|
53
56
|
options: [...AUTHORABLE_REPORT_DESTINATIONS],
|
|
54
57
|
}),
|
|
55
58
|
target: core_1.Flags.string({
|
|
56
|
-
description: 'Channel id for slack_channel. App
|
|
59
|
+
description: 'Channel id for slack_channel, or the user id for user_notify. App, owner-DM and email destinations need no target (email goes to your verified account address).',
|
|
60
|
+
}),
|
|
61
|
+
review: core_1.Flags.string({
|
|
62
|
+
description: 'Hold the exact text for approver approval before it is sent to this target (owner)',
|
|
63
|
+
options: [...data_provider_1.COMMITMENT_REPORT_REVIEW_MODES],
|
|
57
64
|
}),
|
|
58
65
|
on: core_1.Flags.string({
|
|
59
66
|
description: 'When to report (default: material_change)',
|
|
60
67
|
options: [...data_provider_1.COMMITMENT_REPORT_TRIGGERS],
|
|
61
68
|
}),
|
|
69
|
+
format: core_1.Flags.string({
|
|
70
|
+
description: 'Optional report format (absent: text)',
|
|
71
|
+
options: ['text', 'report_v1'],
|
|
72
|
+
}),
|
|
62
73
|
remove: core_1.Flags.string({
|
|
63
74
|
description: 'Report target to remove: "<destination>" or "<destination>:<target>"',
|
|
64
75
|
}),
|
|
@@ -66,6 +77,8 @@ class CommitmentsReports extends base_command_1.BaseCommand {
|
|
|
66
77
|
async run() {
|
|
67
78
|
this.requireAuth();
|
|
68
79
|
const { args, flags } = await this.parse(CommitmentsReports);
|
|
80
|
+
if (flags.format && !flags.add)
|
|
81
|
+
this.error('--format requires --add.', { exit: 1 });
|
|
69
82
|
if (flags.add && flags.remove) {
|
|
70
83
|
this.error('Pass --add or --remove, not both.', { exit: 1 });
|
|
71
84
|
}
|
|
@@ -89,6 +102,9 @@ class CommitmentsReports extends base_command_1.BaseCommand {
|
|
|
89
102
|
try {
|
|
90
103
|
const current = await (0, commitment_terms_1.loadCommitment)(args.id);
|
|
91
104
|
const reports = current.reports ?? [];
|
|
105
|
+
if (flags.review && !flags.add) {
|
|
106
|
+
throw new Error('--review applies to a report being added (--add).');
|
|
107
|
+
}
|
|
92
108
|
if (flags.add) {
|
|
93
109
|
const destination = flags.add;
|
|
94
110
|
if (DESTINATIONS_NEEDING_TARGET.has(destination) && !flags.target) {
|
|
@@ -102,8 +118,10 @@ class CommitmentsReports extends base_command_1.BaseCommand {
|
|
|
102
118
|
const next = {
|
|
103
119
|
destination,
|
|
104
120
|
...(flags.target ? { destinationTarget: flags.target } : {}),
|
|
121
|
+
...(flags.review ? { review: flags.review } : {}),
|
|
105
122
|
on: flags.on ?? 'material_change',
|
|
106
123
|
enabled: true,
|
|
124
|
+
...(flags.format ? { format: flags.format } : {}),
|
|
107
125
|
};
|
|
108
126
|
payload = { reports: (0, commitment_terms_1.appendUnique)(reports, next, reportKey, 'Report target') };
|
|
109
127
|
}
|
|
@@ -30,6 +30,7 @@ export default class CommitmentsUpdate extends BaseCommand {
|
|
|
30
30
|
yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
31
31
|
'from-json': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
32
32
|
'if-version': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
33
|
+
'task-review-policy': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
33
34
|
title: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
34
35
|
description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
35
36
|
'agent-directive': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const core_1 = require("@oclif/core");
|
|
4
3
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
4
|
+
const core_1 = require("@oclif/core");
|
|
5
|
+
const commitment_product_1 = require("../../lib/commitment-product");
|
|
6
|
+
const data_provider_2 = require("@skrr-ai/data-provider");
|
|
5
7
|
const base_command_1 = require("../../base-command");
|
|
6
8
|
const prompt_1 = require("../../lib/prompt");
|
|
7
9
|
const web_url_1 = require("../../lib/web-url");
|
|
@@ -52,6 +54,10 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
52
54
|
'if-version': core_1.Flags.integer({
|
|
53
55
|
description: 'Only update this observed contract version; returns a conflict if it changed',
|
|
54
56
|
}),
|
|
57
|
+
'task-review-policy': core_1.Flags.string({
|
|
58
|
+
options: [...data_provider_1.TASK_REVIEW_POLICIES],
|
|
59
|
+
description: 'Owner choice for generated Tasks; required records a blocker but does not stop the owner close.',
|
|
60
|
+
}),
|
|
55
61
|
title: core_1.Flags.string({ description: 'New title' }),
|
|
56
62
|
description: core_1.Flags.string({ description: 'New description' }),
|
|
57
63
|
'agent-directive': core_1.Flags.string({
|
|
@@ -133,9 +139,22 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
133
139
|
const wantsCadence = flags.cadence !== undefined ||
|
|
134
140
|
flags['cadence-mode'] !== undefined ||
|
|
135
141
|
flags.timezone !== undefined;
|
|
142
|
+
let payload;
|
|
143
|
+
try {
|
|
144
|
+
payload = await (0, prompt_2.readJsonBody)(flags['from-json']);
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
this.error(err.message, { exit: 1 });
|
|
148
|
+
}
|
|
149
|
+
const authoredDelivery = payload.delivery && typeof payload.delivery === 'object' && !Array.isArray(payload.delivery)
|
|
150
|
+
? payload.delivery
|
|
151
|
+
: undefined;
|
|
136
152
|
// Read-modify-write: only pay the extra round-trip when we must merge.
|
|
137
153
|
let current;
|
|
138
|
-
if (wantsTarget ||
|
|
154
|
+
if (wantsTarget ||
|
|
155
|
+
wantsCadence ||
|
|
156
|
+
authoredDelivery ||
|
|
157
|
+
flags['task-review-policy'] !== undefined) {
|
|
139
158
|
try {
|
|
140
159
|
const res = await commitments_1.commitmentApi.get(args.id);
|
|
141
160
|
current = res?.commitment;
|
|
@@ -147,11 +166,22 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
147
166
|
this.error(`Commitment ${args.id} not found.`, { exit: 4 });
|
|
148
167
|
}
|
|
149
168
|
}
|
|
150
|
-
let payload;
|
|
151
169
|
try {
|
|
152
|
-
payload = await (0, prompt_2.readJsonBody)(flags['from-json']);
|
|
153
170
|
if (flags['if-version'] !== undefined)
|
|
154
171
|
payload.expectedVersion = flags['if-version'];
|
|
172
|
+
if (authoredDelivery || flags['task-review-policy'] !== undefined) {
|
|
173
|
+
payload.delivery = {
|
|
174
|
+
...(current?.delivery || { version: 1, mode: 'report_only' }),
|
|
175
|
+
...authoredDelivery,
|
|
176
|
+
...(flags['task-review-policy'] !== undefined
|
|
177
|
+
? { reviewPolicy: (0, commitment_product_1.normalizeTaskReviewPolicy)(flags['task-review-policy']) }
|
|
178
|
+
: {}),
|
|
179
|
+
};
|
|
180
|
+
payload.expectedVersion ??= current?.version;
|
|
181
|
+
}
|
|
182
|
+
const declaredDelivery = payload.delivery;
|
|
183
|
+
if (declaredDelivery?.reviewPolicy !== undefined)
|
|
184
|
+
(0, commitment_product_1.normalizeTaskReviewPolicy)(declaredDelivery.reviewPolicy);
|
|
155
185
|
if (flags.title)
|
|
156
186
|
payload.title = flags.title;
|
|
157
187
|
if (flags.description !== undefined)
|
|
@@ -168,7 +198,7 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
168
198
|
// generic PATCH with no ceremony at all, while `commitments delete` —
|
|
169
199
|
// whose data is all still on disk, and which is now restorable —
|
|
170
200
|
// prompts. Ceremony should track how hard something is to undo.
|
|
171
|
-
if ((0,
|
|
201
|
+
if ((0, data_provider_2.isTerminalCommitmentStatus)(flags.status)) {
|
|
172
202
|
let confirmed;
|
|
173
203
|
try {
|
|
174
204
|
confirmed = await (0, prompt_1.confirmDestructive)(`Set ${args.id} to ${flags.status}? This ends the Commitment — making it active again means archiving it first, then resuming.`, flags.yes);
|
|
@@ -84,6 +84,10 @@ class DaemonInstall extends core_1.Command {
|
|
|
84
84
|
// is how a CLI and its daemon end up on different deployments
|
|
85
85
|
// (OSK-279) without anyone doing anything wrong.
|
|
86
86
|
const code = await (0, exec_runtime_binary_1.execRuntimeBinary)(['install', ...(0, daemon_binding_1.bindToCliSession)(argv)]);
|
|
87
|
+
if (code === 0 &&
|
|
88
|
+
!argv.some((arg) => ['--json', '--help', '-h'].includes(arg))) {
|
|
89
|
+
this.log('Coding-agent instructions: sign in with `skrr login`, or review installation choices with `skrr instructions setup`.');
|
|
90
|
+
}
|
|
87
91
|
this.exit(code);
|
|
88
92
|
}
|
|
89
93
|
catch (err) {
|
|
@@ -6,7 +6,9 @@ import { BaseCommand } from '../base-command';
|
|
|
6
6
|
* POST /api/auth/recovery/generate. The formatted code is printed
|
|
7
7
|
* exactly once to STDOUT; a warning goes to STDERR.
|
|
8
8
|
*
|
|
9
|
-
* Requires
|
|
9
|
+
* Requires a user sign-in session (NOT a CI token or PAT). When the server
|
|
10
|
+
* requests a fresh proof, this command verifies it for recovery_code_generate
|
|
11
|
+
* on the same session before retrying the generation exactly once.
|
|
10
12
|
* On success: any previously-active recovery code is revoked server-side
|
|
11
13
|
* and the new one is returned.
|
|
12
14
|
*
|
|
@@ -19,6 +21,16 @@ export default class GenerateRecoveryCode extends BaseCommand {
|
|
|
19
21
|
static examples: string[];
|
|
20
22
|
static flags: {
|
|
21
23
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
24
|
+
otp: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
25
|
+
'backup-code': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
26
|
+
'email-code': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
22
27
|
};
|
|
23
28
|
run(): Promise<void>;
|
|
29
|
+
private generate;
|
|
30
|
+
private proofFor;
|
|
31
|
+
private nonemptyCode;
|
|
32
|
+
private refuseUnavailableMethod;
|
|
33
|
+
private refusePasskeyOnly;
|
|
34
|
+
private refuseStepUp;
|
|
35
|
+
private handleGenerationError;
|
|
24
36
|
}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
4
5
|
const base_command_1 = require("../base-command");
|
|
5
6
|
const api_fetch_1 = require("../lib/api-fetch");
|
|
7
|
+
const prompt_1 = require("../lib/prompt");
|
|
8
|
+
// Include passkey even though this terminal cannot run a WebAuthn ceremony.
|
|
9
|
+
// The server uses this header when choosing the account's strongest proof:
|
|
10
|
+
// omitting passkey would make a passkey-only account fall back to email.
|
|
11
|
+
// A passkey-only challenge is refused below with a first-party web handoff.
|
|
12
|
+
const STEP_UP_HEADERS = { 'X-Step-Up-Methods': 'passkey,totp,backup_code,email_code' };
|
|
13
|
+
const PURPOSE = data_provider_1.RECOVERY_CODE_GENERATE_STEP_UP_PURPOSE;
|
|
6
14
|
/**
|
|
7
15
|
* `skrr generate-recovery-code`
|
|
8
16
|
*
|
|
@@ -10,7 +18,9 @@ const api_fetch_1 = require("../lib/api-fetch");
|
|
|
10
18
|
* POST /api/auth/recovery/generate. The formatted code is printed
|
|
11
19
|
* exactly once to STDOUT; a warning goes to STDERR.
|
|
12
20
|
*
|
|
13
|
-
* Requires
|
|
21
|
+
* Requires a user sign-in session (NOT a CI token or PAT). When the server
|
|
22
|
+
* requests a fresh proof, this command verifies it for recovery_code_generate
|
|
23
|
+
* on the same session before retrying the generation exactly once.
|
|
14
24
|
* On success: any previously-active recovery code is revoked server-side
|
|
15
25
|
* and the new one is returned.
|
|
16
26
|
*
|
|
@@ -22,6 +32,8 @@ class GenerateRecoveryCode extends base_command_1.BaseCommand {
|
|
|
22
32
|
static description = 'Generate a printable account-recovery code. Shown once — store it safely. Recovery codes use letters A-Z and digits 2-7.';
|
|
23
33
|
static examples = [
|
|
24
34
|
'<%= config.bin %> generate-recovery-code',
|
|
35
|
+
'<%= config.bin %> generate-recovery-code --otp 123456',
|
|
36
|
+
'<%= config.bin %> generate-recovery-code --backup-code <unused-code>',
|
|
25
37
|
'<%= config.bin %> generate-recovery-code --json',
|
|
26
38
|
];
|
|
27
39
|
static flags = {
|
|
@@ -29,28 +41,60 @@ class GenerateRecoveryCode extends base_command_1.BaseCommand {
|
|
|
29
41
|
description: 'Output as JSON (for scripting). Code still printed only once.',
|
|
30
42
|
default: false,
|
|
31
43
|
}),
|
|
44
|
+
otp: core_1.Flags.string({
|
|
45
|
+
description: 'Current code from your authenticator app when a fresh proof is required',
|
|
46
|
+
exclusive: ['backup-code', 'email-code'],
|
|
47
|
+
}),
|
|
48
|
+
'backup-code': core_1.Flags.string({
|
|
49
|
+
description: 'Unused two-factor backup code when a fresh proof is required (it is spent)',
|
|
50
|
+
exclusive: ['otp', 'email-code'],
|
|
51
|
+
}),
|
|
52
|
+
'email-code': core_1.Flags.string({
|
|
53
|
+
description: 'Previously requested one-time email code when a fresh proof is required',
|
|
54
|
+
exclusive: ['otp', 'backup-code'],
|
|
55
|
+
}),
|
|
32
56
|
};
|
|
33
57
|
async run() {
|
|
34
58
|
this.requireAuth();
|
|
35
59
|
const { flags } = await this.parse(GenerateRecoveryCode);
|
|
36
|
-
//
|
|
37
|
-
if (this.resolvedCredential.kind === 'ci') {
|
|
38
|
-
this.error('CI tokens cannot generate recovery codes.
|
|
60
|
+
// Static credentials cannot mint account recovery credentials.
|
|
61
|
+
if (this.resolvedCredential.kind === 'ci' || this.resolvedCredential.kind === 'pat') {
|
|
62
|
+
this.error('CI and personal access tokens cannot generate recovery codes. Sign in with `skrr login` first.', { exit: 2 });
|
|
39
63
|
}
|
|
40
64
|
let result;
|
|
41
65
|
try {
|
|
42
|
-
result = await (
|
|
43
|
-
method: 'POST',
|
|
44
|
-
credential: this.resolvedCredential,
|
|
45
|
-
});
|
|
66
|
+
result = await this.generate();
|
|
46
67
|
}
|
|
47
68
|
catch (err) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
69
|
+
const challenge = err instanceof api_fetch_1.ApiFetchError && err.status === 403 ? (0, data_provider_1.stepUpChallengeFromError)(err) : null;
|
|
70
|
+
if (!challenge)
|
|
71
|
+
this.handleGenerationError(err);
|
|
72
|
+
if (challenge.purpose !== PURPOSE) {
|
|
73
|
+
this.error('The server asked for verification of a different action. Nothing changed.', {
|
|
74
|
+
code: 'STEP_UP_PURPOSE_MISMATCH',
|
|
75
|
+
exit: 2,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (challenge.reason !== 'no_recent_step_up')
|
|
79
|
+
this.refuseStepUp(challenge);
|
|
80
|
+
const proof = await this.proofFor(challenge, flags);
|
|
81
|
+
try {
|
|
82
|
+
await (0, api_fetch_1.apiFetch)('/api/auth/step-up', {
|
|
83
|
+
method: 'POST',
|
|
84
|
+
credential: this.resolvedCredential,
|
|
85
|
+
headers: STEP_UP_HEADERS,
|
|
86
|
+
body: { purpose: PURPOSE, ...proof },
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (verifyError) {
|
|
90
|
+
this.handleApiError(verifyError);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
result = await this.generate();
|
|
94
|
+
}
|
|
95
|
+
catch (retryError) {
|
|
96
|
+
this.handleGenerationError(retryError);
|
|
52
97
|
}
|
|
53
|
-
this.handleApiError(err);
|
|
54
98
|
}
|
|
55
99
|
if (flags.json) {
|
|
56
100
|
// JSON mode: print structured output to stdout for scripting.
|
|
@@ -75,5 +119,94 @@ class GenerateRecoveryCode extends base_command_1.BaseCommand {
|
|
|
75
119
|
process.stderr.write(` Generated at: ${new Date(result.createdAt).toISOString()}\n`);
|
|
76
120
|
process.stderr.write('\n');
|
|
77
121
|
}
|
|
122
|
+
generate() {
|
|
123
|
+
return (0, api_fetch_1.apiFetch)('/api/auth/recovery/generate', {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
credential: this.resolvedCredential,
|
|
126
|
+
headers: STEP_UP_HEADERS,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async proofFor(challenge, flags) {
|
|
130
|
+
if (challenge.methods.includes('passkey') &&
|
|
131
|
+
!challenge.methods.includes('totp') &&
|
|
132
|
+
!challenge.methods.includes('backup_code')) {
|
|
133
|
+
this.refusePasskeyOnly();
|
|
134
|
+
}
|
|
135
|
+
if (flags.otp !== undefined) {
|
|
136
|
+
if (!challenge.methods.includes('totp'))
|
|
137
|
+
this.refuseUnavailableMethod();
|
|
138
|
+
return { token: this.nonemptyCode(flags.otp) };
|
|
139
|
+
}
|
|
140
|
+
if (flags['backup-code'] !== undefined) {
|
|
141
|
+
if (!challenge.methods.includes('backup_code'))
|
|
142
|
+
this.refuseUnavailableMethod();
|
|
143
|
+
return { backupCode: this.nonemptyCode(flags['backup-code']) };
|
|
144
|
+
}
|
|
145
|
+
if (flags['email-code'] !== undefined) {
|
|
146
|
+
if (!challenge.methods.includes('email_code'))
|
|
147
|
+
this.refuseUnavailableMethod();
|
|
148
|
+
return { emailCode: this.nonemptyCode(flags['email-code']) };
|
|
149
|
+
}
|
|
150
|
+
if (!process.stdin.isTTY) {
|
|
151
|
+
this.error('A fresh identity check is required. Run this command at a terminal, or pass --otp, --backup-code, or a previously requested --email-code. Nothing changed.', { code: 'STEP_UP_PROOF_REQUIRED', exit: 2 });
|
|
152
|
+
}
|
|
153
|
+
if (challenge.methods.includes('totp')) {
|
|
154
|
+
const entered = await (0, prompt_1.prompt)('Authenticator code: ', {
|
|
155
|
+
hidden: true,
|
|
156
|
+
output: process.stderr,
|
|
157
|
+
});
|
|
158
|
+
return { token: this.nonemptyCode(entered) };
|
|
159
|
+
}
|
|
160
|
+
if (challenge.methods.includes('backup_code')) {
|
|
161
|
+
const entered = await (0, prompt_1.prompt)('Unused two-factor backup code: ', {
|
|
162
|
+
hidden: true,
|
|
163
|
+
output: process.stderr,
|
|
164
|
+
});
|
|
165
|
+
return { backupCode: this.nonemptyCode(entered) };
|
|
166
|
+
}
|
|
167
|
+
if (challenge.methods.includes('email_code')) {
|
|
168
|
+
try {
|
|
169
|
+
await (0, api_fetch_1.apiFetch)('/api/auth/step-up/email-code', {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
credential: this.resolvedCredential,
|
|
172
|
+
headers: STEP_UP_HEADERS,
|
|
173
|
+
body: { purpose: PURPOSE },
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
catch (requestError) {
|
|
177
|
+
this.handleApiError(requestError);
|
|
178
|
+
}
|
|
179
|
+
process.stderr.write('A one-time code was sent to your account email.\n');
|
|
180
|
+
const entered = await (0, prompt_1.prompt)('Email code: ', { hidden: true, output: process.stderr });
|
|
181
|
+
return { emailCode: this.nonemptyCode(entered) };
|
|
182
|
+
}
|
|
183
|
+
this.refuseUnavailableMethod();
|
|
184
|
+
}
|
|
185
|
+
nonemptyCode(value) {
|
|
186
|
+
const code = value.trim();
|
|
187
|
+
if (!code)
|
|
188
|
+
this.error('A verification code cannot be empty. Nothing changed.', { exit: 2 });
|
|
189
|
+
return code;
|
|
190
|
+
}
|
|
191
|
+
refuseUnavailableMethod() {
|
|
192
|
+
this.error('This login has no identity-check method the CLI can complete. Use Settings → Account in the web app, or enroll an authenticator and try again. Nothing changed.', { code: 'STEP_UP_METHOD_UNAVAILABLE', exit: 2 });
|
|
193
|
+
}
|
|
194
|
+
refusePasskeyOnly() {
|
|
195
|
+
this.error('This account requires a passkey for this identity check. Open Settings → Account in the web app to generate a recovery code. Nothing changed.', { code: 'STEP_UP_PASSKEY_REQUIRED', exit: 2 });
|
|
196
|
+
}
|
|
197
|
+
refuseStepUp(challenge) {
|
|
198
|
+
if (challenge.reason === 'credential_not_session_bound') {
|
|
199
|
+
this.error('This credential has no sign-in session for an identity check. Run `skrr login` and try again. Nothing changed.', { code: 'STEP_UP_SESSION_UNBOUND', exit: 2 });
|
|
200
|
+
}
|
|
201
|
+
this.refuseUnavailableMethod();
|
|
202
|
+
}
|
|
203
|
+
handleGenerationError(err) {
|
|
204
|
+
if (err instanceof api_fetch_1.ApiFetchError && (err.status === 401 || err.status === 403)) {
|
|
205
|
+
this.error('Not authorized to generate a recovery code. Sign in with a user-scope session.', {
|
|
206
|
+
exit: 1,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
this.handleApiError(err);
|
|
210
|
+
}
|
|
78
211
|
}
|
|
79
212
|
exports.default = GenerateRecoveryCode;
|
|
@@ -20,6 +20,7 @@ export default class GrantsCreate extends BaseCommand {
|
|
|
20
20
|
commitment: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
21
21
|
provider: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
22
22
|
label: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
23
|
+
access: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
23
24
|
description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
24
25
|
env: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
25
26
|
daemon: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|