@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.
Files changed (165) hide show
  1. package/dist/base-command.d.ts +35 -0
  2. package/dist/base-command.js +107 -0
  3. package/dist/commands/agenda/trigger/list.d.ts +2 -1
  4. package/dist/commands/agenda/trigger/list.js +55 -6
  5. package/dist/commands/agents/chat.js +7 -0
  6. package/dist/commands/agents/create.js +3 -1
  7. package/dist/commands/browser/persistent-profile.d.ts +22 -0
  8. package/dist/commands/browser/persistent-profile.js +46 -0
  9. package/dist/commands/commitments/action-history.js +1 -1
  10. package/dist/commands/commitments/cases.js +3 -3
  11. package/dist/commands/commitments/check-now.d.ts +10 -2
  12. package/dist/commands/commitments/check-now.js +53 -3
  13. package/dist/commands/commitments/create.d.ts +6 -14
  14. package/dist/commands/commitments/create.js +64 -7
  15. package/dist/commands/commitments/doctor.js +3 -1
  16. package/dist/commands/commitments/effective-policy.d.ts +11 -1
  17. package/dist/commands/commitments/effective-policy.js +90 -4
  18. package/dist/commands/commitments/explain.js +10 -1
  19. package/dist/commands/commitments/hypotheses.js +12 -12
  20. package/dist/commands/commitments/next-tick.js +5 -0
  21. package/dist/commands/commitments/observations.js +18 -17
  22. package/dist/commands/commitments/pack/list.js +2 -1
  23. package/dist/commands/commitments/pack/plan.d.ts +6 -0
  24. package/dist/commands/commitments/pack/plan.js +19 -0
  25. package/dist/commands/commitments/plan.d.ts +14 -0
  26. package/dist/commands/commitments/plan.js +32 -0
  27. package/dist/commands/commitments/preflight.d.ts +20 -1
  28. package/dist/commands/commitments/preflight.js +118 -12
  29. package/dist/commands/commitments/show.d.ts +9 -0
  30. package/dist/commands/commitments/show.js +14 -1
  31. package/dist/commands/commitments/trigger-status.js +8 -0
  32. package/dist/commands/commitments/update.d.ts +1 -0
  33. package/dist/commands/commitments/update.js +45 -4
  34. package/dist/commands/commitments/wake-capabilities.js +13 -0
  35. package/dist/commands/compass/archive.js +4 -0
  36. package/dist/commands/compass/commitments.js +15 -1
  37. package/dist/commands/compass/create.js +11 -3
  38. package/dist/commands/compass/effective-policy.d.ts +1 -0
  39. package/dist/commands/compass/effective-policy.js +8 -7
  40. package/dist/commands/compass/revert.d.ts +8 -0
  41. package/dist/commands/compass/revert.js +25 -1
  42. package/dist/commands/compass/revisions.d.ts +6 -0
  43. package/dist/commands/compass/revisions.js +26 -2
  44. package/dist/commands/compass/tactic.d.ts +10 -3
  45. package/dist/commands/compass/tactic.js +22 -7
  46. package/dist/commands/compass/update.js +19 -3
  47. package/dist/commands/followups/act.js +1 -1
  48. package/dist/commands/followups/cancel.js +13 -0
  49. package/dist/commands/followups/observability.js +20 -1
  50. package/dist/commands/followups/plans/create.js +12 -1
  51. package/dist/commands/followups/show.js +13 -0
  52. package/dist/commands/followups/watch.js +1 -1
  53. package/dist/commands/goals/planner-config.d.ts +11 -0
  54. package/dist/commands/goals/planner-config.js +16 -0
  55. package/dist/commands/harnesses/list.js +1 -1
  56. package/dist/commands/machines/update.d.ts +5 -3
  57. package/dist/commands/machines/update.js +70 -9
  58. package/dist/commands/northstars/create.js +3 -1
  59. package/dist/commands/northstars/governance/configure.d.ts +4 -0
  60. package/dist/commands/northstars/governance/configure.js +76 -10
  61. package/dist/commands/northstars/intents/decide.d.ts +6 -0
  62. package/dist/commands/northstars/intents/decide.js +68 -15
  63. package/dist/commands/northstars/intents/list.d.ts +2 -1
  64. package/dist/commands/northstars/intents/list.js +15 -5
  65. package/dist/commands/northstars/intents.d.ts +26 -0
  66. package/dist/commands/northstars/intents.js +49 -0
  67. package/dist/commands/northstars/list.d.ts +1 -0
  68. package/dist/commands/northstars/list.js +24 -3
  69. package/dist/commands/northstars/recommendations/list.d.ts +1 -1
  70. package/dist/commands/northstars/recommendations/list.js +3 -3
  71. package/dist/commands/northstars/recommendations.d.ts +19 -0
  72. package/dist/commands/northstars/recommendations.js +42 -0
  73. package/dist/commands/northstars/review-now.d.ts +1 -0
  74. package/dist/commands/northstars/review-now.js +15 -4
  75. package/dist/commands/northstars/reviews.d.ts +1 -0
  76. package/dist/commands/northstars/reviews.js +34 -6
  77. package/dist/commands/northstars/update.js +8 -1
  78. package/dist/commands/proposals/list.js +11 -2
  79. package/dist/commands/proposals/show.js +9 -1
  80. package/dist/commands/spaces/auto-executor/preview.d.ts +14 -1
  81. package/dist/commands/spaces/auto-executor/preview.js +35 -1
  82. package/dist/commands/spaces/auto-executor/run.d.ts +17 -0
  83. package/dist/commands/spaces/auto-executor/run.js +60 -2
  84. package/dist/commands/spaces/auto-executor/runs.d.ts +9 -1
  85. package/dist/commands/spaces/auto-executor/runs.js +18 -1
  86. package/dist/commands/spaces/files/upload.js +1 -2
  87. package/dist/commands/spaces/heartbeats/create.js +7 -5
  88. package/dist/commands/spaces/heartbeats/update.js +5 -3
  89. package/dist/commands/spaces/index.js +23 -0
  90. package/dist/commands/store/artifacts/releases.d.ts +20 -0
  91. package/dist/commands/store/artifacts/releases.js +85 -0
  92. package/dist/commands/store/library.d.ts +14 -0
  93. package/dist/commands/store/library.js +71 -0
  94. package/dist/commands/tasks/list.d.ts +48 -0
  95. package/dist/commands/tasks/list.js +141 -9
  96. package/dist/commands/tasks/remind.js +23 -11
  97. package/dist/commands/tasks/retry-schedule.js +6 -3
  98. package/dist/commands/tasks/schedule.js +29 -7
  99. package/dist/commands/tasks/show.js +4 -0
  100. package/dist/generated/agent-guides.json +69 -69
  101. package/dist/lib/agent-trigger-listing.d.ts +26 -0
  102. package/dist/lib/agent-trigger-listing.js +63 -0
  103. package/dist/lib/agentic-stream.d.ts +9 -0
  104. package/dist/lib/agentic-stream.js +152 -41
  105. package/dist/lib/command-miss.js +11 -2
  106. package/dist/lib/commitment-attention-copy.d.ts +96 -0
  107. package/dist/lib/commitment-attention-copy.js +209 -0
  108. package/dist/lib/commitment-ledgers.js +3 -1
  109. package/dist/lib/commitment-loop-status.d.ts +6 -0
  110. package/dist/lib/commitment-loop-status.js +16 -6
  111. package/dist/lib/commitments.d.ts +112 -0
  112. package/dist/lib/commitments.js +250 -2
  113. package/dist/lib/compass-body-help.d.ts +20 -0
  114. package/dist/lib/compass-body-help.js +61 -0
  115. package/dist/lib/compass-refusals.d.ts +35 -0
  116. package/dist/lib/compass-refusals.js +50 -0
  117. package/dist/lib/compasses.d.ts +82 -4
  118. package/dist/lib/compasses.js +232 -12
  119. package/dist/lib/followups.d.ts +22 -1
  120. package/dist/lib/followups.js +21 -1
  121. package/dist/lib/format.d.ts +11 -0
  122. package/dist/lib/format.js +29 -0
  123. package/dist/lib/initiatives.d.ts +9 -2
  124. package/dist/lib/initiatives.js +13 -2
  125. package/dist/lib/iso-instant.d.ts +52 -0
  126. package/dist/lib/iso-instant.js +162 -0
  127. package/dist/lib/machines.d.ts +14 -1
  128. package/dist/lib/machines.js +24 -0
  129. package/dist/lib/northstars.d.ts +201 -24
  130. package/dist/lib/northstars.js +655 -27
  131. package/dist/lib/proposal-decision-command.js +21 -1
  132. package/dist/lib/proposals.d.ts +26 -1
  133. package/dist/lib/proposals.js +167 -0
  134. package/dist/lib/rate-limit-retry.d.ts +5 -0
  135. package/dist/lib/rate-limit-retry.js +19 -0
  136. package/dist/lib/roles.d.ts +1 -1
  137. package/dist/lib/space-charter.js +9 -0
  138. package/dist/lib/store-artifact-releases.d.ts +39 -0
  139. package/dist/lib/store-artifact-releases.js +12 -0
  140. package/dist/lib/store-library.d.ts +37 -0
  141. package/dist/lib/store-library.js +12 -0
  142. package/dist/lib/task-asset-upload.js +1 -2
  143. package/dist/lib/task-calendar.d.ts +19 -0
  144. package/dist/lib/task-calendar.js +72 -0
  145. package/dist/lib/task-recurrence-outcome.js +3 -1
  146. package/dist/lib/task-recurrence-summary.d.ts +15 -0
  147. package/dist/lib/task-recurrence-summary.js +228 -0
  148. package/dist/lib/task-reminder.d.ts +28 -0
  149. package/dist/lib/task-reminder.js +50 -0
  150. package/dist/lib/triggers.d.ts +13 -2
  151. package/dist/lib/triggers.js +31 -13
  152. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.js +11 -1
  153. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.d.ts +123 -0
  154. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.js +160 -0
  155. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -0
  156. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +17 -0
  157. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.js +11 -1
  158. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.d.ts +123 -0
  159. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.js +173 -0
  160. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -0
  161. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -0
  162. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  163. package/dist/node_modules/@skrr-ai/data-provider/index.js +6922 -6828
  164. package/oclif.manifest.json +612 -62
  165. package/package.json +4 -4
@@ -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
- const glyph = CYCLE_GLYPH[cycle.outcome] || '?';
1717
- lines.push(`${cycleTime(cycle.startedAt)} ${glyph} ${String(cycle.outcome).padEnd(9)} ${cycleWake(cycle).padEnd(18)} ${cycleSummary(cycle)}`);
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
+ }