@skrr-ai/cli 0.1.127 → 0.1.129
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base-command.d.ts +35 -0
- package/dist/base-command.js +107 -0
- package/dist/commands/agenda/trigger/list.d.ts +2 -1
- package/dist/commands/agenda/trigger/list.js +55 -6
- package/dist/commands/agents/chat.js +7 -0
- package/dist/commands/agents/create.js +3 -1
- package/dist/commands/browser/persistent-profile.d.ts +22 -0
- package/dist/commands/browser/persistent-profile.js +46 -0
- package/dist/commands/commitments/action-history.js +1 -1
- package/dist/commands/commitments/cases.js +3 -3
- package/dist/commands/commitments/check-now.d.ts +10 -2
- package/dist/commands/commitments/check-now.js +53 -3
- package/dist/commands/commitments/create.d.ts +6 -14
- package/dist/commands/commitments/create.js +64 -7
- package/dist/commands/commitments/doctor.js +3 -1
- package/dist/commands/commitments/effective-policy.d.ts +11 -1
- package/dist/commands/commitments/effective-policy.js +90 -4
- package/dist/commands/commitments/explain.js +10 -1
- package/dist/commands/commitments/hypotheses.js +12 -12
- package/dist/commands/commitments/next-tick.js +5 -0
- package/dist/commands/commitments/observations.js +18 -17
- package/dist/commands/commitments/pack/list.js +2 -1
- package/dist/commands/commitments/pack/plan.d.ts +6 -0
- package/dist/commands/commitments/pack/plan.js +19 -0
- package/dist/commands/commitments/plan.d.ts +14 -0
- package/dist/commands/commitments/plan.js +32 -0
- package/dist/commands/commitments/preflight.d.ts +20 -1
- package/dist/commands/commitments/preflight.js +118 -12
- package/dist/commands/commitments/show.d.ts +9 -0
- package/dist/commands/commitments/show.js +14 -1
- package/dist/commands/commitments/trigger-status.js +8 -0
- package/dist/commands/commitments/update.d.ts +1 -0
- package/dist/commands/commitments/update.js +45 -4
- package/dist/commands/commitments/wake-capabilities.js +13 -0
- package/dist/commands/compass/archive.js +4 -0
- package/dist/commands/compass/commitments.js +15 -1
- package/dist/commands/compass/create.js +11 -3
- package/dist/commands/compass/effective-policy.d.ts +1 -0
- package/dist/commands/compass/effective-policy.js +8 -7
- package/dist/commands/compass/revert.d.ts +8 -0
- package/dist/commands/compass/revert.js +25 -1
- package/dist/commands/compass/revisions.d.ts +6 -0
- package/dist/commands/compass/revisions.js +26 -2
- package/dist/commands/compass/tactic.d.ts +10 -3
- package/dist/commands/compass/tactic.js +22 -7
- package/dist/commands/compass/update.js +19 -3
- package/dist/commands/followups/act.js +1 -1
- package/dist/commands/followups/cancel.js +13 -0
- package/dist/commands/followups/observability.js +20 -1
- package/dist/commands/followups/plans/create.js +12 -1
- package/dist/commands/followups/show.js +13 -0
- package/dist/commands/followups/watch.js +1 -1
- package/dist/commands/goals/planner-config.d.ts +11 -0
- package/dist/commands/goals/planner-config.js +16 -0
- package/dist/commands/harnesses/list.js +1 -1
- package/dist/commands/machines/update.d.ts +5 -3
- package/dist/commands/machines/update.js +70 -9
- package/dist/commands/northstars/create.js +3 -1
- package/dist/commands/northstars/governance/configure.d.ts +4 -0
- package/dist/commands/northstars/governance/configure.js +76 -10
- package/dist/commands/northstars/intents/decide.d.ts +6 -0
- package/dist/commands/northstars/intents/decide.js +68 -15
- package/dist/commands/northstars/intents/list.d.ts +2 -1
- package/dist/commands/northstars/intents/list.js +15 -5
- package/dist/commands/northstars/intents.d.ts +26 -0
- package/dist/commands/northstars/intents.js +49 -0
- package/dist/commands/northstars/list.d.ts +1 -0
- package/dist/commands/northstars/list.js +24 -3
- package/dist/commands/northstars/recommendations/list.d.ts +1 -1
- package/dist/commands/northstars/recommendations/list.js +3 -3
- package/dist/commands/northstars/recommendations.d.ts +19 -0
- package/dist/commands/northstars/recommendations.js +42 -0
- package/dist/commands/northstars/review-now.d.ts +1 -0
- package/dist/commands/northstars/review-now.js +15 -4
- package/dist/commands/northstars/reviews.d.ts +1 -0
- package/dist/commands/northstars/reviews.js +34 -6
- package/dist/commands/northstars/update.js +8 -1
- package/dist/commands/proposals/list.js +11 -2
- package/dist/commands/proposals/show.js +9 -1
- package/dist/commands/spaces/auto-executor/preview.d.ts +14 -1
- package/dist/commands/spaces/auto-executor/preview.js +35 -1
- package/dist/commands/spaces/auto-executor/run.d.ts +17 -0
- package/dist/commands/spaces/auto-executor/run.js +60 -2
- package/dist/commands/spaces/auto-executor/runs.d.ts +9 -1
- package/dist/commands/spaces/auto-executor/runs.js +18 -1
- package/dist/commands/spaces/files/upload.js +1 -2
- package/dist/commands/spaces/heartbeats/create.js +7 -5
- package/dist/commands/spaces/heartbeats/update.js +5 -3
- package/dist/commands/spaces/index.js +23 -0
- package/dist/commands/store/artifacts/releases.d.ts +20 -0
- package/dist/commands/store/artifacts/releases.js +85 -0
- package/dist/commands/store/library.d.ts +14 -0
- package/dist/commands/store/library.js +71 -0
- package/dist/commands/tasks/list.d.ts +48 -0
- package/dist/commands/tasks/list.js +141 -9
- package/dist/commands/tasks/remind.js +23 -11
- package/dist/commands/tasks/retry-schedule.js +6 -3
- package/dist/commands/tasks/schedule.js +29 -7
- package/dist/commands/tasks/show.js +4 -0
- package/dist/generated/agent-guides.json +69 -69
- package/dist/lib/agent-trigger-listing.d.ts +26 -0
- package/dist/lib/agent-trigger-listing.js +63 -0
- package/dist/lib/agentic-stream.d.ts +9 -0
- package/dist/lib/agentic-stream.js +152 -41
- package/dist/lib/command-miss.js +11 -2
- package/dist/lib/commitment-attention-copy.d.ts +96 -0
- package/dist/lib/commitment-attention-copy.js +209 -0
- package/dist/lib/commitment-ledgers.js +3 -1
- package/dist/lib/commitment-loop-status.d.ts +6 -0
- package/dist/lib/commitment-loop-status.js +16 -6
- package/dist/lib/commitments.d.ts +112 -0
- package/dist/lib/commitments.js +250 -2
- package/dist/lib/compass-body-help.d.ts +20 -0
- package/dist/lib/compass-body-help.js +61 -0
- package/dist/lib/compass-refusals.d.ts +35 -0
- package/dist/lib/compass-refusals.js +50 -0
- package/dist/lib/compasses.d.ts +82 -4
- package/dist/lib/compasses.js +232 -12
- package/dist/lib/followups.d.ts +22 -1
- package/dist/lib/followups.js +21 -1
- package/dist/lib/format.d.ts +11 -0
- package/dist/lib/format.js +29 -0
- package/dist/lib/initiatives.d.ts +9 -2
- package/dist/lib/initiatives.js +13 -2
- package/dist/lib/iso-instant.d.ts +52 -0
- package/dist/lib/iso-instant.js +162 -0
- package/dist/lib/machines.d.ts +14 -1
- package/dist/lib/machines.js +24 -0
- package/dist/lib/northstars.d.ts +201 -24
- package/dist/lib/northstars.js +655 -27
- package/dist/lib/proposal-decision-command.js +21 -1
- package/dist/lib/proposals.d.ts +26 -1
- package/dist/lib/proposals.js +167 -0
- package/dist/lib/rate-limit-retry.d.ts +5 -0
- package/dist/lib/rate-limit-retry.js +19 -0
- package/dist/lib/roles.d.ts +1 -1
- package/dist/lib/space-charter.js +9 -0
- package/dist/lib/store-artifact-releases.d.ts +39 -0
- package/dist/lib/store-artifact-releases.js +12 -0
- package/dist/lib/store-library.d.ts +37 -0
- package/dist/lib/store-library.js +12 -0
- package/dist/lib/task-asset-upload.js +1 -2
- package/dist/lib/task-calendar.d.ts +19 -0
- package/dist/lib/task-calendar.js +72 -0
- package/dist/lib/task-recurrence-outcome.js +3 -1
- package/dist/lib/task-recurrence-summary.d.ts +15 -0
- package/dist/lib/task-recurrence-summary.js +228 -0
- package/dist/lib/task-reminder.d.ts +28 -0
- package/dist/lib/task-reminder.js +50 -0
- package/dist/lib/triggers.d.ts +13 -2
- package/dist/lib/triggers.js +31 -13
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.js +11 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.d.ts +123 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.js +160 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +17 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.js +11 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.d.ts +123 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.js +173 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +6922 -6828
- package/oclif.manifest.json +612 -62
- package/package.json +4 -4
package/dist/lib/commitments.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.COMMITMENT_CLI_EVALUATORS = exports.COMMITMENT_CREATE_KEYS = exports.COMMITMENT_REMEDIATION_ACTIONS = exports.COMMITMENT_FEEDBACK_KINDS = exports.commitmentApi = exports.commitmentPackApi = exports.MAX_COMMITMENT_INTERVAL_MS = exports.MIN_COMMITMENT_INTERVAL_MS = exports.COMMITMENT_EXECUTION_ISOLATION_MODES = exports.COMMITMENT_AUTHORABLE_CADENCE_MODES = exports.COMMITMENT_KIND_VALUES = exports.COMMITMENT_STATUSES = exports.COMMITMENT_CADENCE_MAX_TIMES = exports.COMMITMENT_CADENCE_TIME_PATTERN = exports.COMMITMENT_CADENCE_MODES = exports.COMMITMENT_TEMPLATE_IDS = exports.COMMITMENT_WATCHED_SOURCES = void 0;
|
|
4
|
+
exports.activationRefusalLines = activationRefusalLines;
|
|
5
|
+
exports.gateRefusesActivation = gateRefusesActivation;
|
|
4
6
|
exports.permissionLines = permissionLines;
|
|
5
7
|
exports.scheduleIssueLines = scheduleIssueLines;
|
|
6
8
|
exports.retiredFieldsLine = retiredFieldsLine;
|
|
7
9
|
exports.readCommitmentAgentDirective = readCommitmentAgentDirective;
|
|
10
|
+
exports.unrecognizedCreateKeys = unrecognizedCreateKeys;
|
|
11
|
+
exports.ignoredCreateKeys = ignoredCreateKeys;
|
|
12
|
+
exports.ignoredCreateKeysWarning = ignoredCreateKeysWarning;
|
|
8
13
|
exports.normalizeCreateBody = normalizeCreateBody;
|
|
9
14
|
exports.parseCommitmentConcurrencyLimit = parseCommitmentConcurrencyLimit;
|
|
10
15
|
exports.commitmentConcurrencyEnvelopePatch = commitmentConcurrencyEnvelopePatch;
|
|
@@ -29,6 +34,9 @@ exports.withLiveAssessment = withLiveAssessment;
|
|
|
29
34
|
exports.commitmentWriteWarnings = commitmentWriteWarnings;
|
|
30
35
|
exports.renderCommitmentWriteWarnings = renderCommitmentWriteWarnings;
|
|
31
36
|
exports.describeCommitmentRevision = describeCommitmentRevision;
|
|
37
|
+
exports.describeCommitmentPriority = describeCommitmentPriority;
|
|
38
|
+
exports.describeBoundCompass = describeBoundCompass;
|
|
39
|
+
exports.explainCompassLines = explainCompassLines;
|
|
32
40
|
exports.renderCommitmentSummary = renderCommitmentSummary;
|
|
33
41
|
exports.describeWakeDecision = describeWakeDecision;
|
|
34
42
|
exports.renderCheckList = renderCheckList;
|
|
@@ -37,6 +45,7 @@ exports.renderCommitmentTrace = renderCommitmentTrace;
|
|
|
37
45
|
exports.renderProactivenessScorecard = renderProactivenessScorecard;
|
|
38
46
|
exports.formatCommitmentCycles = formatCommitmentCycles;
|
|
39
47
|
exports.hypothesisRefusalLines = hypothesisRefusalLines;
|
|
48
|
+
exports.wakeOutcomeLines = wakeOutcomeLines;
|
|
40
49
|
exports.formatCommitmentExplanation = formatCommitmentExplanation;
|
|
41
50
|
exports.renderListPageHint = renderListPageHint;
|
|
42
51
|
exports.describeObservationArtifacts = describeObservationArtifacts;
|
|
@@ -80,6 +89,7 @@ Object.defineProperty(exports, "COMMITMENT_EXECUTION_ISOLATION_MODES", { enumera
|
|
|
80
89
|
Object.defineProperty(exports, "COMMITMENT_STATUSES", { enumerable: true, get: function () { return data_provider_2.COMMITMENT_STATUSES; } });
|
|
81
90
|
Object.defineProperty(exports, "COMMITMENT_KIND_VALUES", { enumerable: true, get: function () { return data_provider_2.COMMITMENT_KIND_VALUES; } });
|
|
82
91
|
const commitment_product_1 = require("./commitment-product");
|
|
92
|
+
const commitment_attention_copy_1 = require("./commitment-attention-copy");
|
|
83
93
|
const instruction_input_1 = require("./instruction-input");
|
|
84
94
|
const format_1 = require("./format");
|
|
85
95
|
const triggers_1 = require("./triggers");
|
|
@@ -95,6 +105,41 @@ exports.COMMITMENT_AUTHORABLE_CADENCE_MODES = data_provider_2.COMMITMENT_CADENCE
|
|
|
95
105
|
*/
|
|
96
106
|
exports.MIN_COMMITMENT_INTERVAL_MS = 60_000;
|
|
97
107
|
exports.MAX_COMMITMENT_INTERVAL_MS = 365 * 24 * 60 * 60 * 1000;
|
|
108
|
+
/**
|
|
109
|
+
* The lines preflight prints when the server says activation would be refused (OSK-21258). The gate
|
|
110
|
+
* list marks an advisory gate `info (advisory: does not stop a run)`, which is true of a run and false
|
|
111
|
+
* of activation: `resume` refused the same gate with a 409 while preflight read as if nothing stopped
|
|
112
|
+
* it. The server owns which gates refuse; this lays out its answer and never re-derives it. Nothing
|
|
113
|
+
* for an allowed activation or an older server that does not send the block.
|
|
114
|
+
*/
|
|
115
|
+
function activationRefusalLines(activation) {
|
|
116
|
+
if (!activation || activation.canActivate !== false)
|
|
117
|
+
return [];
|
|
118
|
+
const blockers = activation.blockers ?? [];
|
|
119
|
+
if (!blockers.length)
|
|
120
|
+
return ['Activation: would be refused (the server named no gate)'];
|
|
121
|
+
const lines = ['Activation: would be refused'];
|
|
122
|
+
for (const blocker of blockers) {
|
|
123
|
+
lines.push(` - ${blocker.label || blocker.gate}${blocker.reason ? ` (${blocker.reason})` : ''}`);
|
|
124
|
+
if (blocker.hint)
|
|
125
|
+
lines.push(` ${blocker.hint}`);
|
|
126
|
+
}
|
|
127
|
+
return lines;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Whether the server's activation answer names this gate as one that refuses activation (OSK-21258).
|
|
131
|
+
* A gate can be advisory for a run (`admission: 'advisory'`) and still be what `resume` refuses with a
|
|
132
|
+
* 409; the gate list printed it `info (advisory: does not stop a run)` right under an "Activation:
|
|
133
|
+
* would be refused" section naming the same gate. Matches on the gate id, and on the reason too when
|
|
134
|
+
* both sides carry one, so a gate advisory for one reason is not promoted by another. An older server
|
|
135
|
+
* that sends no answer promotes nothing.
|
|
136
|
+
*/
|
|
137
|
+
function gateRefusesActivation(activation, gate) {
|
|
138
|
+
if (!activation || activation.canActivate !== false || !gate?.id)
|
|
139
|
+
return false;
|
|
140
|
+
return (activation.blockers ?? []).some((blocker) => blocker.gate === gate.id &&
|
|
141
|
+
(!blocker.reason || !gate.reason || blocker.reason === gate.reason));
|
|
142
|
+
}
|
|
98
143
|
/**
|
|
99
144
|
* The lines every Commitment read surface prints for "whose permissions does a
|
|
100
145
|
* run use?" — `show`, `effective-policy` and `preflight` share it so the three
|
|
@@ -414,6 +459,87 @@ async function readCommitmentAgentDirective({ directive, file, }) {
|
|
|
414
459
|
}
|
|
415
460
|
return (0, instruction_input_1.readInstructionBody)({ body: directive, file });
|
|
416
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* What a contract dumped from `show`/`list --json` carries that is the server's, not the author's. These are
|
|
464
|
+
* dropped on purpose and never reported.
|
|
465
|
+
*/
|
|
466
|
+
const SERVER_OWNED_CONTRACT_KEYS = new Set([
|
|
467
|
+
'id',
|
|
468
|
+
'ownerUserId',
|
|
469
|
+
'workspaceId',
|
|
470
|
+
'version',
|
|
471
|
+
'createdAt',
|
|
472
|
+
'updatedAt',
|
|
473
|
+
'createdBy',
|
|
474
|
+
'updatedBy',
|
|
475
|
+
'state',
|
|
476
|
+
'firstActivatedAt',
|
|
477
|
+
'executionEpoch',
|
|
478
|
+
'alwaysOnGeneration',
|
|
479
|
+
'requiresAlwaysOn',
|
|
480
|
+
'assessment',
|
|
481
|
+
'abilities',
|
|
482
|
+
'url',
|
|
483
|
+
'latestCheck',
|
|
484
|
+
'operatingState',
|
|
485
|
+
'triggerPlan',
|
|
486
|
+
'executorHandovers',
|
|
487
|
+
'priority',
|
|
488
|
+
'proposal',
|
|
489
|
+
'rationale',
|
|
490
|
+
'droppedFields',
|
|
491
|
+
'warnings',
|
|
492
|
+
]);
|
|
493
|
+
function editDistance(a, b) {
|
|
494
|
+
const row = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
495
|
+
for (let i = 1; i <= a.length; i += 1) {
|
|
496
|
+
let diagonal = row[0];
|
|
497
|
+
row[0] = i;
|
|
498
|
+
for (let j = 1; j <= b.length; j += 1) {
|
|
499
|
+
const above = row[j];
|
|
500
|
+
row[j] = Math.min(row[j] + 1, row[j - 1] + 1, diagonal + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
501
|
+
diagonal = above;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return row[b.length];
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* The top-level keys of a `--from-json` body that `create`/`preflight` will not send. A key within two edits
|
|
508
|
+
* of a real one is a `typo`; the rest are `ignored`. A server-owned dump field is neither.
|
|
509
|
+
*/
|
|
510
|
+
function unrecognizedCreateKeys(src) {
|
|
511
|
+
const known = exports.COMMITMENT_CREATE_KEYS;
|
|
512
|
+
const typos = [];
|
|
513
|
+
const ignored = [];
|
|
514
|
+
for (const key of Object.keys(src || {})) {
|
|
515
|
+
if (known.includes(key) || SERVER_OWNED_CONTRACT_KEYS.has(key))
|
|
516
|
+
continue;
|
|
517
|
+
const near = key.length >= 4
|
|
518
|
+
? known.find((candidate) => candidate.length >= 4 &&
|
|
519
|
+
editDistance(key.toLowerCase(), candidate.toLowerCase()) <= 2)
|
|
520
|
+
: undefined;
|
|
521
|
+
if (near)
|
|
522
|
+
typos.push({ key, suggestion: near });
|
|
523
|
+
else
|
|
524
|
+
ignored.push(key);
|
|
525
|
+
}
|
|
526
|
+
return { typos, ignored };
|
|
527
|
+
}
|
|
528
|
+
/** The keys of a `--from-json` body that are neither sent nor server-owned and not a typo: to be warned about. */
|
|
529
|
+
function ignoredCreateKeys(input) {
|
|
530
|
+
const envelope = input;
|
|
531
|
+
const src = envelope && typeof envelope.proposal === 'object' && envelope.proposal !== null
|
|
532
|
+
? envelope.proposal
|
|
533
|
+
: input || {};
|
|
534
|
+
return unrecognizedCreateKeys(src).ignored;
|
|
535
|
+
}
|
|
536
|
+
/** The one sentence `create` and `preflight` print for them. */
|
|
537
|
+
function ignoredCreateKeysWarning(keys) {
|
|
538
|
+
if (keys.length === 0)
|
|
539
|
+
return null;
|
|
540
|
+
return (`--from-json: ${keys.map((key) => `"${key}"`).join(', ')} ${keys.length === 1 ? 'is' : 'are'} not sent ` +
|
|
541
|
+
'(the CLI does not forward it), so the Commitment is built without it.');
|
|
542
|
+
}
|
|
417
543
|
/**
|
|
418
544
|
* Normalize a `--from-json` body into something the create endpoint accepts.
|
|
419
545
|
*
|
|
@@ -433,6 +559,16 @@ function normalizeCreateBody(input) {
|
|
|
433
559
|
const src = envelope && typeof envelope.proposal === 'object' && envelope.proposal !== null
|
|
434
560
|
? envelope.proposal
|
|
435
561
|
: input || {};
|
|
562
|
+
// Dropping a key the body does not declare is deliberate for what a dumped contract carries (id, version,
|
|
563
|
+
// state, ...). It is not for a typo of a real field: `cadance` was dropped and the Commitment created with
|
|
564
|
+
// the default manual cadence, exit 0, while the same body over REST is a 400 (dogfood
|
|
565
|
+
// df-261031-commitment-authoring, OSK-21246).
|
|
566
|
+
const { typos } = unrecognizedCreateKeys(src);
|
|
567
|
+
if (typos.length > 0) {
|
|
568
|
+
throw new Error(`--from-json has ${typos.length === 1 ? 'a field' : 'fields'} the API does not know: ` +
|
|
569
|
+
`${typos.map((t) => `"${t.key}" (did you mean "${t.suggestion}"?)`).join(', ')}. ` +
|
|
570
|
+
'Nothing was sent: the API refuses unknown fields, and dropping them here would create the Commitment without them.');
|
|
571
|
+
}
|
|
436
572
|
const out = {};
|
|
437
573
|
for (const key of exports.COMMITMENT_CREATE_KEYS) {
|
|
438
574
|
if (src[key] !== undefined)
|
|
@@ -976,6 +1112,12 @@ function describeExecutorBlocked(commitment) {
|
|
|
976
1112
|
* operation and reason is printed as it always was.
|
|
977
1113
|
*/
|
|
978
1114
|
function describeOperation(operation, reason) {
|
|
1115
|
+
// "Cannot tell" travels as `blocked` + this reason (the server's `storedOperation`: no status
|
|
1116
|
+
// recorded yet for this version of the contract, or the recorded one expired). A Commitment that
|
|
1117
|
+
// was turned on a moment ago is in exactly that state, and `blocked` read as a refused activation
|
|
1118
|
+
// while `show` said `ready` seconds later (OSK-21105).
|
|
1119
|
+
if (reason === 'operation_read_unavailable')
|
|
1120
|
+
return 'not read yet — no status is recorded for the current contract, which is not a failure; `skrr commitments show` reads it live';
|
|
979
1121
|
const lifecycle = typeof reason === 'string' ? /^lifecycle_([a-z_]+)$/.exec(reason) : null;
|
|
980
1122
|
if (!lifecycle)
|
|
981
1123
|
return `${operation ?? 'blocked'}${reason ? ` — ${reason}` : ''}`;
|
|
@@ -1135,6 +1277,56 @@ function describeCommitmentRevision(revision) {
|
|
|
1135
1277
|
}
|
|
1136
1278
|
return `Updated commitment (version ${revision.previousVersion} -> ${revision.version}):`;
|
|
1137
1279
|
}
|
|
1280
|
+
/**
|
|
1281
|
+
* A commitment's priority, as one line: `high · weight 70 · from northstar`.
|
|
1282
|
+
*
|
|
1283
|
+
* Linking a commitment to a northstar rewrites its priority (`source: northstar`) and a governor
|
|
1284
|
+
* reprioritization changes it again, so the place a person looks to confirm either is `show`, which
|
|
1285
|
+
* printed everything but this and sent them to `--json`. An unset priority says so rather than
|
|
1286
|
+
* printing nothing.
|
|
1287
|
+
*/
|
|
1288
|
+
function describeCommitmentPriority(priority) {
|
|
1289
|
+
const parts = [];
|
|
1290
|
+
if (priority?.tier)
|
|
1291
|
+
parts.push(priority.tier);
|
|
1292
|
+
if (typeof priority?.weight === 'number')
|
|
1293
|
+
parts.push(`weight ${priority.weight}`);
|
|
1294
|
+
if (priority?.source === 'northstar')
|
|
1295
|
+
parts.push('from northstar');
|
|
1296
|
+
else if (priority?.source === 'manual')
|
|
1297
|
+
parts.push('set manually');
|
|
1298
|
+
return parts.length ? parts.join(' · ') : 'not set';
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* The `Compass:` line of a bound commitment. A commitment names its compass (`compassId`) but the
|
|
1302
|
+
* read does not carry that compass's STATUS, and an archived one governs nothing (the commitment
|
|
1303
|
+
* runs on defaults), so the id alone could be read as "governed by it". Only what is known is
|
|
1304
|
+
* stated: the id, and the command that says whether it is active (OSK-21242).
|
|
1305
|
+
*/
|
|
1306
|
+
function describeBoundCompass(commitment) {
|
|
1307
|
+
const id = commitment.compassId ?? '-';
|
|
1308
|
+
const agent = commitment.agentId ?? '<agent-id>';
|
|
1309
|
+
return `Compass: ${id} — status not shown here; an archived compass governs nothing: \`skrr compass show ${id} --agent ${agent}\``;
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* The bound Compass, as `explain` prints it (OSK-21332). `explain` is where a person asks "why does
|
|
1313
|
+
* this Commitment behave this way", and a bound Compass (or an archived one, which runs the
|
|
1314
|
+
* Commitment on defaults) is part of the answer. The explain payload names neither the Compass nor
|
|
1315
|
+
* its status, so the caller reads the Commitment itself, the same read `show` renders, and hands the
|
|
1316
|
+
* result here: the line is `describeBoundCompass`, the one `show` prints, not a second wording.
|
|
1317
|
+
*
|
|
1318
|
+
* `null` means that read did not come back. It is said, not skipped: a silent skip is
|
|
1319
|
+
* indistinguishable from "no Compass is bound". A Commitment bound to none prints nothing, as in
|
|
1320
|
+
* `show`.
|
|
1321
|
+
*/
|
|
1322
|
+
function explainCompassLines(commitmentId, commitment) {
|
|
1323
|
+
if (!commitment) {
|
|
1324
|
+
return [
|
|
1325
|
+
`Compass: not shown — the commitment could not be read just now; \`skrr commitments show ${commitmentId}\` prints it`,
|
|
1326
|
+
];
|
|
1327
|
+
}
|
|
1328
|
+
return commitment.compassId ? [describeBoundCompass(commitment)] : [];
|
|
1329
|
+
}
|
|
1138
1330
|
function renderCommitmentSummary(commitment, log,
|
|
1139
1331
|
/**
|
|
1140
1332
|
* The most recent check, when the caller has one. Optional because pause /
|
|
@@ -1174,6 +1366,9 @@ scheduleIssues) {
|
|
|
1174
1366
|
log(`Goal: ${commitment.goalId}`);
|
|
1175
1367
|
if (commitment.northstarId)
|
|
1176
1368
|
log(`Northstar: ${commitment.northstarId}`);
|
|
1369
|
+
if (commitment.compassId)
|
|
1370
|
+
log(describeBoundCompass(commitment));
|
|
1371
|
+
log(`Priority: ${describeCommitmentPriority(commitment.priority)}`);
|
|
1177
1372
|
if (commitment.target?.outcome)
|
|
1178
1373
|
log(`Outcome: ${commitment.target.outcome}`);
|
|
1179
1374
|
if (commitment.target?.deadlineAt)
|
|
@@ -1184,6 +1379,13 @@ scheduleIssues) {
|
|
|
1184
1379
|
log(`Delivery: ${(0, commitment_product_1.deliveryLabel)(commitment.delivery?.mode)}${commitment.delivery?.repo ? ` · ${commitment.delivery.repo}` : ''}${commitment.delivery?.baseBranch ? ` → ${commitment.delivery.baseBranch}` : ''}`);
|
|
1185
1380
|
log(`Concurrency: ${describeCommitmentConcurrency(commitment)}`);
|
|
1186
1381
|
log(`Evidence gate: ${describeEvidenceGate(commitment)}`);
|
|
1382
|
+
// How much it may interrupt the owner (OSK-21120). A server that sent no policy prints
|
|
1383
|
+
// nothing, rather than a guess that reads as "unlimited".
|
|
1384
|
+
if (commitment.policy) {
|
|
1385
|
+
for (const line of (0, commitment_attention_copy_1.nudgeSettingLines)((0, commitment_attention_copy_1.nudgeSettingsFromPolicy)(commitment.policy)))
|
|
1386
|
+
log(line);
|
|
1387
|
+
log(`Quiet hours: ${(0, commitment_attention_copy_1.describeQuietHours)(commitment.policy.quietHours)}`);
|
|
1388
|
+
}
|
|
1187
1389
|
const criteria = commitment.target?.successCriteria || [];
|
|
1188
1390
|
const evidenceHealth = latestCheck?.inputs?.evidenceHealth;
|
|
1189
1391
|
const evidenceLine = describeEvidenceHealth(evidenceHealth, criteria.length);
|
|
@@ -1643,6 +1845,9 @@ const CYCLE_GLYPH = {
|
|
|
1643
1845
|
stopped: '●',
|
|
1644
1846
|
quiet: '○',
|
|
1645
1847
|
in_flight: '◌',
|
|
1848
|
+
// An applied result whose agent said work is warranted and left nothing the platform can see
|
|
1849
|
+
// (OSK-21608): not a tick, because the work is still owed, and not a stop, because it applied.
|
|
1850
|
+
owed: '◐',
|
|
1646
1851
|
};
|
|
1647
1852
|
/** `MM-DD HH:MM` in the reader's local time; `-` when the time is unknown. */
|
|
1648
1853
|
function cycleTime(value) {
|
|
@@ -1672,6 +1877,11 @@ function cycleSummary(cycle) {
|
|
|
1672
1877
|
return `${question} ${reason || gate} — ${fix || detail || 'stopped'}${moved}`;
|
|
1673
1878
|
}
|
|
1674
1879
|
if (cycle.outcome === 'advanced') {
|
|
1880
|
+
if (cycle.owed) {
|
|
1881
|
+
return cycle.advancementKinds?.length
|
|
1882
|
+
? `${cycle.advancementKinds.join(', ')} — ${data_provider_2.COMMITMENT_CYCLE_OWED_SENTENCE}`
|
|
1883
|
+
: data_provider_2.COMMITMENT_CYCLE_OWED_SENTENCE;
|
|
1884
|
+
}
|
|
1675
1885
|
return cycle.advancementKinds?.length
|
|
1676
1886
|
? cycle.advancementKinds.join(', ')
|
|
1677
1887
|
: 'applied an agent result';
|
|
@@ -1682,6 +1892,13 @@ function cycleSummary(cycle) {
|
|
|
1682
1892
|
}
|
|
1683
1893
|
return cycle.note || cycle.decision?.summary || cycle.decision?.posture || 'nothing to act on';
|
|
1684
1894
|
}
|
|
1895
|
+
/** A record-only follow-through says what it is, and what it noted, instead of claiming progress. */
|
|
1896
|
+
function recordOnlyEchoSummary(cycle) {
|
|
1897
|
+
const noted = cycle.advancementKinds?.length
|
|
1898
|
+
? ` (noted: ${cycle.advancementKinds.join(', ')})`
|
|
1899
|
+
: '';
|
|
1900
|
+
return `records the earlier run's outcome; no work of its own${noted}`;
|
|
1901
|
+
}
|
|
1685
1902
|
/** Content-free rows admitted by the native sensor loader; licenses stay unknown. */
|
|
1686
1903
|
function platformFetchLines(cycle) {
|
|
1687
1904
|
const lines = [];
|
|
@@ -1713,8 +1930,17 @@ function formatCommitmentCycles(page) {
|
|
|
1713
1930
|
return ['No cycles recorded yet.'];
|
|
1714
1931
|
const lines = [];
|
|
1715
1932
|
for (const cycle of cycles) {
|
|
1716
|
-
|
|
1717
|
-
|
|
1933
|
+
// A follow-through Check that only records the Run before it is not what the loop did, and
|
|
1934
|
+
// `✓ advanced` above a stopped Run reads as if the work had moved (OSK-21240).
|
|
1935
|
+
const echo = (0, data_provider_2.isRecordOnlyEchoCycle)(cycle);
|
|
1936
|
+
const owed = !echo && cycle.outcome === 'advanced' && cycle.owed === true;
|
|
1937
|
+
const glyph = echo
|
|
1938
|
+
? CYCLE_GLYPH.quiet
|
|
1939
|
+
: owed
|
|
1940
|
+
? CYCLE_GLYPH.owed
|
|
1941
|
+
: CYCLE_GLYPH[cycle.outcome] || '?';
|
|
1942
|
+
const word = echo ? 'recorded' : owed ? 'owed' : String(cycle.outcome);
|
|
1943
|
+
lines.push(`${cycleTime(cycle.startedAt)} ${glyph} ${word.padEnd(9)} ${cycleWake(cycle).padEnd(18)} ${echo ? recordOnlyEchoSummary(cycle) : cycleSummary(cycle)}`);
|
|
1718
1944
|
lines.push(...platformFetchLines(cycle));
|
|
1719
1945
|
lines.push(...formatCycleLatency(cycle));
|
|
1720
1946
|
for (const task of cycle.tasks || []) {
|
|
@@ -1730,6 +1956,8 @@ function formatCommitmentCycles(page) {
|
|
|
1730
1956
|
lines.push(` run ${run.id} report: ${run.reportPayload.status === 'rejected' ? 'structured report rejected; plain summary used' : 'structured report validated (delivery tracked separately)'}`);
|
|
1731
1957
|
for (const line of hypothesisRefusalLines(run))
|
|
1732
1958
|
lines.push(` ${line}`);
|
|
1959
|
+
for (const line of wakeOutcomeLines(run))
|
|
1960
|
+
lines.push(` ${line}`);
|
|
1733
1961
|
if (!['machine', 'contract', 'work'].includes(run.failureClass))
|
|
1734
1962
|
continue;
|
|
1735
1963
|
const owner = run.failureOwner === 'model' ? 'model' : run.failureOwner || 'work';
|
|
@@ -1784,6 +2012,20 @@ const HYPOTHESIS_REFUSAL_REASON = {
|
|
|
1784
2012
|
function hypothesisRefusalLines(run) {
|
|
1785
2013
|
return (run.hypothesisRefusals || []).map((refusal) => `${refusal.count} ${refusal.count === 1 ? 'hypothesis' : 'hypotheses'} not recorded: ${HYPOTHESIS_REFUSAL_REASON[refusal.reason] || refusal.reason} (${refusal.reason})`);
|
|
1786
2014
|
}
|
|
2015
|
+
/**
|
|
2016
|
+
* A wake the Agent asked for and the platform did not arm, in the server's words.
|
|
2017
|
+
* The only record used to be `ledger --json`; the cycle read `advanced` (OSK-21132).
|
|
2018
|
+
*/
|
|
2019
|
+
function wakeOutcomeLines(run) {
|
|
2020
|
+
const wake = run.wake;
|
|
2021
|
+
if (!wake?.detail)
|
|
2022
|
+
return [];
|
|
2023
|
+
const label = wake.status === 'awaiting_approval' ? 'wake request waiting' : 'wake not armed';
|
|
2024
|
+
return [
|
|
2025
|
+
`${label}: ${wake.detail}${wake.reason ? ` (${wake.reason})` : ''}`,
|
|
2026
|
+
...(wake.fix ? [` Fix: ${wake.fix}`] : []),
|
|
2027
|
+
];
|
|
2028
|
+
}
|
|
1787
2029
|
function formatCommitmentExplanation(explanation) {
|
|
1788
2030
|
const cycle = explanation.cycle;
|
|
1789
2031
|
const lines = [
|
|
@@ -1819,6 +2061,8 @@ function formatCommitmentExplanation(explanation) {
|
|
|
1819
2061
|
lines.push(` run ${run.id} report: ${run.reportPayload.status === 'rejected' ? 'structured report rejected; plain summary used' : 'structured report validated (delivery tracked separately)'}`);
|
|
1820
2062
|
for (const line of hypothesisRefusalLines(run))
|
|
1821
2063
|
lines.push(` ${line}`);
|
|
2064
|
+
for (const line of wakeOutcomeLines(run))
|
|
2065
|
+
lines.push(` ${line}`);
|
|
1822
2066
|
}
|
|
1823
2067
|
}
|
|
1824
2068
|
lines.push(...permissionLines(explanation.permissions));
|
|
@@ -1827,6 +2071,10 @@ function formatCommitmentExplanation(explanation) {
|
|
|
1827
2071
|
/**
|
|
1828
2072
|
* Print the continuation hint for a paged `object:'list'` response — the line
|
|
1829
2073
|
* that makes history beyond the newest page reachable instead of invisible.
|
|
2074
|
+
*
|
|
2075
|
+
* Text mode ONLY. Under `--json` stdout must be one JSON document, and the same
|
|
2076
|
+
* facts are already in it as `has_more` / `next_cursor`: a caller that prints
|
|
2077
|
+
* this after the JSON makes `| json.load` fail (OSK-21118).
|
|
1830
2078
|
*/
|
|
1831
2079
|
function renderListPageHint(page, log) {
|
|
1832
2080
|
if (page?.has_more === true && page.next_cursor) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `--json-body` takes on `skrr compass create` and `skrr compass update` (OSK-21154).
|
|
3
|
+
*
|
|
4
|
+
* The flag's help said only "a JSON file with the full body", so the field names, the
|
|
5
|
+
* invariant-target limit and the quiet-hours rules were found by guessing and by being refused. One
|
|
6
|
+
* declaration, read by both commands' help so they cannot drift apart. The server owns every rule
|
|
7
|
+
* stated here (`api/server/services/AgentCompass/CompassPolicyContract.js` and the route schemas); the
|
|
8
|
+
* limits are written out because a help screen is read before the first request is sent, and
|
|
9
|
+
* `docs/cli/SKRR_COMPASS.md` ("Body shape") carries the same table.
|
|
10
|
+
*
|
|
11
|
+
* ONE SHORT LINE PER FIELD, each beginning with its full path. oclif runs a description through
|
|
12
|
+
* `wrap-ansi` (hard wrap at the terminal width minus 2, 80 when not a terminal) which TRIMS every
|
|
13
|
+
* line's leading spaces, so the indentation this list used to carry collapsed (`id` and
|
|
14
|
+
* `description` read as top-level fields) and its long lines broke mid-sentence. A path prefix is
|
|
15
|
+
* not whitespace, so the nesting survives, and no line is longer than 77 characters, so none wraps
|
|
16
|
+
* (`help.spec.ts` runs the real wrap over it) (OSK-21243).
|
|
17
|
+
*/
|
|
18
|
+
export declare const COMPASS_BODY_HELP: string;
|
|
19
|
+
/** An example body: two targets (one domain-scoped, one general) and a quiet-hours window. */
|
|
20
|
+
export declare const COMPASS_BODY_EXAMPLE = "# compass.json\n{\n \"title\": \"Production reliability\",\n \"invariantTargets\": [\n { \"id\": \"api-latency\", \"domainKind\": \"reliability\", \"description\": \"p99 API latency stays under 300 ms\" },\n { \"id\": \"general\", \"description\": \"Nothing the owner has not seen ships on a Friday\" }\n ],\n \"autonomyDefaults\": {\n \"mode\": \"ask_first\",\n \"quietHours\": { \"enabled\": true, \"start\": \"22:00\", \"end\": \"07:00\", \"timezone\": \"America/New_York\" }\n }\n}";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.COMPASS_BODY_EXAMPLE = exports.COMPASS_BODY_HELP = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* What `--json-body` takes on `skrr compass create` and `skrr compass update` (OSK-21154).
|
|
6
|
+
*
|
|
7
|
+
* The flag's help said only "a JSON file with the full body", so the field names, the
|
|
8
|
+
* invariant-target limit and the quiet-hours rules were found by guessing and by being refused. One
|
|
9
|
+
* declaration, read by both commands' help so they cannot drift apart. The server owns every rule
|
|
10
|
+
* stated here (`api/server/services/AgentCompass/CompassPolicyContract.js` and the route schemas); the
|
|
11
|
+
* limits are written out because a help screen is read before the first request is sent, and
|
|
12
|
+
* `docs/cli/SKRR_COMPASS.md` ("Body shape") carries the same table.
|
|
13
|
+
*
|
|
14
|
+
* ONE SHORT LINE PER FIELD, each beginning with its full path. oclif runs a description through
|
|
15
|
+
* `wrap-ansi` (hard wrap at the terminal width minus 2, 80 when not a terminal) which TRIMS every
|
|
16
|
+
* line's leading spaces, so the indentation this list used to carry collapsed (`id` and
|
|
17
|
+
* `description` read as top-level fields) and its long lines broke mid-sentence. A path prefix is
|
|
18
|
+
* not whitespace, so the nesting survives, and no line is longer than 77 characters, so none wraps
|
|
19
|
+
* (`help.spec.ts` runs the real wrap over it) (OSK-21243).
|
|
20
|
+
*/
|
|
21
|
+
exports.COMPASS_BODY_HELP = [
|
|
22
|
+
'--json-body takes the API body as a JSON file; the flags are merged over it.',
|
|
23
|
+
'Each line below names one field by its full path:',
|
|
24
|
+
'title, domain, reason: strings (reason is what the revision ledger shows)',
|
|
25
|
+
'invariantTargets[]: what the agent keeps true',
|
|
26
|
+
'invariantTargets[]: AT MOST 25: more is refused with the count sent',
|
|
27
|
+
'invariantTargets[].id: optional, unique in the list (a repeat is refused)',
|
|
28
|
+
'invariantTargets[].id: default invariant_<position>',
|
|
29
|
+
'invariantTargets[].description: required on create',
|
|
30
|
+
'invariantTargets[].domainKind: optional; leave it off ONE target',
|
|
31
|
+
'invariantTargets[].domainKind: the target without one is the general fallback',
|
|
32
|
+
'invariantTargets[].maintainedState[]: list of strings',
|
|
33
|
+
'invariantTargets[].successMetrics[]: list of strings',
|
|
34
|
+
'invariantTargets[].boundaries[]: list of strings',
|
|
35
|
+
'invariantTargets[].cadence, .escalation, .stateMonitor: advanced',
|
|
36
|
+
'invariantTargets[].learnedTactics[]: advanced; see docs/cli/SKRR_COMPASS.md',
|
|
37
|
+
'autonomyDefaults.mode: off | suggestions_only | ask_first | auto_run_limited',
|
|
38
|
+
'autonomyDefaults.mode: auto_run (short forms: suggest, auto)',
|
|
39
|
+
'autonomyDefaults.quietHours = {"enabled":true,"start":"22:00","end":"07:00"}',
|
|
40
|
+
'autonomyDefaults.quietHours.start, .end: HH:MM, 00:00 to 23:59',
|
|
41
|
+
'autonomyDefaults.quietHours: start must differ from end; refused otherwise',
|
|
42
|
+
'autonomyDefaults.quietHours.timezone: an IANA zone, e.g. America/New_York',
|
|
43
|
+
'communicationDefaults: mode, destination, fallbackDestination, quietHours',
|
|
44
|
+
'communicationDefaults.allowedDestinations[]: list of strings',
|
|
45
|
+
'communicationDefaults.requireApprovalRiskLevels[]: list of strings',
|
|
46
|
+
'communicationDefaults: any other key is stored as a note and never read',
|
|
47
|
+
'rules[]: owner-enforced, Agent owner only; see docs/cli/SKRR_COMPASS.md',
|
|
48
|
+
].join('\n');
|
|
49
|
+
/** An example body: two targets (one domain-scoped, one general) and a quiet-hours window. */
|
|
50
|
+
exports.COMPASS_BODY_EXAMPLE = `# compass.json
|
|
51
|
+
{
|
|
52
|
+
"title": "Production reliability",
|
|
53
|
+
"invariantTargets": [
|
|
54
|
+
{ "id": "api-latency", "domainKind": "reliability", "description": "p99 API latency stays under 300 ms" },
|
|
55
|
+
{ "id": "general", "description": "Nothing the owner has not seen ships on a Friday" }
|
|
56
|
+
],
|
|
57
|
+
"autonomyDefaults": {
|
|
58
|
+
"mode": "ask_first",
|
|
59
|
+
"quietHours": { "enabled": true, "start": "22:00", "end": "07:00", "timezone": "America/New_York" }
|
|
60
|
+
}
|
|
61
|
+
}`;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* compass-refusals.ts — the words for the two Compass refusals a person acts on.
|
|
3
|
+
*
|
|
4
|
+
* `COMPASS_VERSION_CONFLICT` (409) and `COMPASS_REVISION_NOT_FOUND` (404) used to reach the
|
|
5
|
+
* terminal as `HTTP_409` and `NOT_FOUND`, with the one fact that makes each actionable dropped:
|
|
6
|
+
* where the Compass is now, and which version was missing (OSK-21162, OSK-21152).
|
|
7
|
+
*
|
|
8
|
+
* The route sends the code in upper-case `error` (and now in `code` too). `refusalCodeOf` does
|
|
9
|
+
* not read the first as a code, and widening it for every route is not this module's call, so
|
|
10
|
+
* `compassRefusalCode` reads both spellings here, for these two codes only. No imports: this is
|
|
11
|
+
* pure, and `base-command` loads it.
|
|
12
|
+
*/
|
|
13
|
+
export declare const COMPASS_VERSION_CONFLICT = "COMPASS_VERSION_CONFLICT";
|
|
14
|
+
export declare const COMPASS_REVISION_NOT_FOUND = "COMPASS_REVISION_NOT_FOUND";
|
|
15
|
+
export type CompassRefusalCode = typeof COMPASS_VERSION_CONFLICT | typeof COMPASS_REVISION_NOT_FOUND;
|
|
16
|
+
/**
|
|
17
|
+
* What the failing request was about, for a refusal whose remedy is a command that names it. The
|
|
18
|
+
* command sets this before it sends, as it sets `requestFieldFlags`. The server's own body wins
|
|
19
|
+
* where it carries the same fact; these cover a server that does not send it yet.
|
|
20
|
+
*/
|
|
21
|
+
export interface CompassRefusalContext {
|
|
22
|
+
compassId?: string;
|
|
23
|
+
agentId?: string;
|
|
24
|
+
/** The version the caller based the change on. */
|
|
25
|
+
expectedVersion?: number;
|
|
26
|
+
/** The version a revert asked for. */
|
|
27
|
+
toVersion?: number;
|
|
28
|
+
}
|
|
29
|
+
/** The Compass refusal an API error body carries, under `code` or the legacy `error`. */
|
|
30
|
+
export declare function compassRefusalCode(body: Record<string, unknown> | null | undefined): CompassRefusalCode | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* The refusal as a sentence, then the command to run next on its own line (the shape
|
|
33
|
+
* `COMMITMENT_ACTIVATION_BLOCKED` uses: `→`).
|
|
34
|
+
*/
|
|
35
|
+
export declare function describeCompassRefusal(code: CompassRefusalCode, body: Record<string, unknown> | null | undefined, context: CompassRefusalContext, bin: string): string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* compass-refusals.ts — the words for the two Compass refusals a person acts on.
|
|
4
|
+
*
|
|
5
|
+
* `COMPASS_VERSION_CONFLICT` (409) and `COMPASS_REVISION_NOT_FOUND` (404) used to reach the
|
|
6
|
+
* terminal as `HTTP_409` and `NOT_FOUND`, with the one fact that makes each actionable dropped:
|
|
7
|
+
* where the Compass is now, and which version was missing (OSK-21162, OSK-21152).
|
|
8
|
+
*
|
|
9
|
+
* The route sends the code in upper-case `error` (and now in `code` too). `refusalCodeOf` does
|
|
10
|
+
* not read the first as a code, and widening it for every route is not this module's call, so
|
|
11
|
+
* `compassRefusalCode` reads both spellings here, for these two codes only. No imports: this is
|
|
12
|
+
* pure, and `base-command` loads it.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.COMPASS_REVISION_NOT_FOUND = exports.COMPASS_VERSION_CONFLICT = void 0;
|
|
16
|
+
exports.compassRefusalCode = compassRefusalCode;
|
|
17
|
+
exports.describeCompassRefusal = describeCompassRefusal;
|
|
18
|
+
exports.COMPASS_VERSION_CONFLICT = 'COMPASS_VERSION_CONFLICT';
|
|
19
|
+
exports.COMPASS_REVISION_NOT_FOUND = 'COMPASS_REVISION_NOT_FOUND';
|
|
20
|
+
/** The Compass refusal an API error body carries, under `code` or the legacy `error`. */
|
|
21
|
+
function compassRefusalCode(body) {
|
|
22
|
+
for (const key of ['code', 'error']) {
|
|
23
|
+
const value = body?.[key];
|
|
24
|
+
if (value === exports.COMPASS_VERSION_CONFLICT || value === exports.COMPASS_REVISION_NOT_FOUND)
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
function versionOf(value) {
|
|
30
|
+
return typeof value === 'number' && Number.isInteger(value) ? value : undefined;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The refusal as a sentence, then the command to run next on its own line (the shape
|
|
34
|
+
* `COMMITMENT_ACTIVATION_BLOCKED` uses: `→`).
|
|
35
|
+
*/
|
|
36
|
+
function describeCompassRefusal(code, body, context, bin) {
|
|
37
|
+
const compassId = context.compassId ?? '<compass-id>';
|
|
38
|
+
const agentId = context.agentId ?? '<agent-id>';
|
|
39
|
+
const current = versionOf(body?.currentVersion);
|
|
40
|
+
if (code === exports.COMPASS_VERSION_CONFLICT) {
|
|
41
|
+
const sent = versionOf(body?.expectedVersion) ?? context.expectedVersion;
|
|
42
|
+
const where = current !== undefined ? `it is at v${current} now` : 'it changed while this was being saved';
|
|
43
|
+
return (`Compass version conflict: ${where}${sent !== undefined ? `, and this change was based on v${sent}` : ''}.\n` +
|
|
44
|
+
` → Re-read it with \`${bin} compass show ${compassId} --agent ${agentId}\`, review what changed, and retry.`);
|
|
45
|
+
}
|
|
46
|
+
const asked = versionOf(body?.toVersion) ?? context.toVersion;
|
|
47
|
+
return (`Compass revision ${asked !== undefined ? `v${asked} ` : ''}not found` +
|
|
48
|
+
`${current !== undefined ? `: the Compass is at v${current}` : ''}.\n` +
|
|
49
|
+
` → List its versions with \`${bin} compass revisions ${compassId} --agent ${agentId}\`, then pass one as --to-version.`);
|
|
50
|
+
}
|