@skrr-ai/cli 0.1.104 → 0.1.105

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 (110) hide show
  1. package/dist/base-command.js +6 -2
  2. package/dist/commands/agenda/trigger/list.js +2 -0
  3. package/dist/commands/agents/chat.js +4 -1
  4. package/dist/commands/agents/operating-plan.js +5 -2
  5. package/dist/commands/agents/triggers/create.js +3 -1
  6. package/dist/commands/agents/triggers/fire.js +2 -0
  7. package/dist/commands/agents/triggers/replay.js +2 -0
  8. package/dist/commands/agents/triggers/update.js +12 -4
  9. package/dist/commands/commitments/action-history.js +7 -2
  10. package/dist/commands/commitments/cadence-decisions.js +6 -1
  11. package/dist/commands/commitments/cadence-requests/decide.d.ts +1 -1
  12. package/dist/commands/commitments/cadence-requests/decide.js +1 -1
  13. package/dist/commands/commitments/doctor.js +7 -1
  14. package/dist/commands/commitments/observations.js +7 -1
  15. package/dist/commands/commitments/operating-review.d.ts +15 -0
  16. package/dist/commands/commitments/operating-review.js +23 -2
  17. package/dist/commands/commitments/preflight.d.ts +12 -0
  18. package/dist/commands/commitments/preflight.js +23 -9
  19. package/dist/commands/commitments/reflection.js +6 -1
  20. package/dist/commands/commitments/show.js +3 -1
  21. package/dist/commands/commitments/trigger-status.js +2 -22
  22. package/dist/commands/commitments/wake-capabilities.d.ts +13 -0
  23. package/dist/commands/commitments/wake-capabilities.js +39 -3
  24. package/dist/commands/daemon/logs.d.ts +41 -3
  25. package/dist/commands/daemon/logs.js +202 -17
  26. package/dist/commands/followups/act.js +13 -1
  27. package/dist/commands/followups/checkin.js +11 -2
  28. package/dist/commands/followups/reschedule.js +13 -1
  29. package/dist/commands/proposals/discard.d.ts +1 -1
  30. package/dist/commands/proposals/keep.d.ts +1 -1
  31. package/dist/commands/proposals/list.d.ts +7 -0
  32. package/dist/commands/proposals/list.js +31 -5
  33. package/dist/commands/proposals/show.d.ts +2 -1
  34. package/dist/commands/proposals/show.js +31 -4
  35. package/dist/commands/proposals/snooze.d.ts +1 -1
  36. package/dist/commands/requests/create.js +8 -3
  37. package/dist/commands/spaces/workflows/create.js +3 -3
  38. package/dist/commands/tasks/complete.js +4 -0
  39. package/dist/commands/tasks/create.d.ts +2 -0
  40. package/dist/commands/tasks/create.js +17 -3
  41. package/dist/commands/tasks/deliverable/add.d.ts +2 -0
  42. package/dist/commands/tasks/deliverable/add.js +22 -7
  43. package/dist/commands/tasks/deliverable/list.d.ts +13 -0
  44. package/dist/commands/tasks/deliverable/list.js +34 -1
  45. package/dist/commands/tasks/economics-compare.js +7 -1
  46. package/dist/commands/tasks/expectations.d.ts +10 -0
  47. package/dist/commands/tasks/expectations.js +31 -3
  48. package/dist/commands/tasks/list.d.ts +9 -0
  49. package/dist/commands/tasks/list.js +40 -5
  50. package/dist/commands/tasks/report.js +1 -1
  51. package/dist/commands/tasks/result/show.d.ts +7 -0
  52. package/dist/commands/tasks/result/show.js +32 -1
  53. package/dist/commands/tasks/result/submit.js +1 -1
  54. package/dist/commands/tasks/show.d.ts +6 -0
  55. package/dist/commands/tasks/show.js +23 -0
  56. package/dist/commands/tasks/update.d.ts +3 -0
  57. package/dist/commands/tasks/update.js +23 -3
  58. package/dist/commands/triggers/audit.js +6 -2
  59. package/dist/commands/triggers/create.js +3 -1
  60. package/dist/commands/triggers/fire.d.ts +1 -0
  61. package/dist/commands/triggers/fire.js +16 -1
  62. package/dist/commands/triggers/preflight.js +6 -5
  63. package/dist/commands/triggers/replay.js +2 -0
  64. package/dist/commands/triggers/update.js +12 -4
  65. package/dist/commands/workspaces/stewardship.js +5 -1
  66. package/dist/lib/agentic-stream.d.ts +9 -0
  67. package/dist/lib/agentic-stream.js +38 -18
  68. package/dist/lib/commitment-event-wakes.d.ts +8 -0
  69. package/dist/lib/commitment-event-wakes.js +39 -0
  70. package/dist/lib/commitment-ledgers.d.ts +9 -0
  71. package/dist/lib/commitment-ledgers.js +126 -0
  72. package/dist/lib/commitments.d.ts +102 -2
  73. package/dist/lib/commitments.js +208 -8
  74. package/dist/lib/delegated-cli.js +13 -2
  75. package/dist/lib/followups.d.ts +6 -0
  76. package/dist/lib/followups.js +12 -0
  77. package/dist/lib/message-content.d.ts +6 -0
  78. package/dist/lib/message-content.js +24 -0
  79. package/dist/lib/operating-plan-loops.d.ts +8 -0
  80. package/dist/lib/operating-plan-loops.js +32 -0
  81. package/dist/lib/preflight-copy.d.ts +27 -0
  82. package/dist/lib/preflight-copy.js +89 -0
  83. package/dist/lib/proposal-decision-command.d.ts +1 -1
  84. package/dist/lib/proposal-decision-command.js +27 -3
  85. package/dist/lib/proposals.d.ts +17 -0
  86. package/dist/lib/proposals.js +41 -0
  87. package/dist/lib/stewardship-output.js +57 -12
  88. package/dist/lib/task-economics-line.d.ts +30 -0
  89. package/dist/lib/task-economics-line.js +49 -0
  90. package/dist/lib/task-economics.d.ts +15 -0
  91. package/dist/lib/task-economics.js +73 -8
  92. package/dist/lib/task-recurrence-outcome.d.ts +19 -0
  93. package/dist/lib/task-recurrence-outcome.js +30 -0
  94. package/dist/lib/triggers.d.ts +42 -0
  95. package/dist/lib/triggers.js +136 -2
  96. package/dist/lib/widgetTerminalText.d.ts +8 -0
  97. package/dist/lib/widgetTerminalText.js +116 -0
  98. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.d.ts +33 -0
  99. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.js +27 -0
  100. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.d.ts +28 -5
  101. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.js +50 -5
  102. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.d.ts +33 -0
  103. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.js +26 -0
  104. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.d.ts +28 -5
  105. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.js +50 -5
  106. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  107. package/dist/node_modules/@skrr-ai/data-provider/index.js +7261 -7056
  108. package/docs/v1/operations.md +1 -1
  109. package/oclif.manifest.json +116 -72
  110. package/package.json +1 -1
@@ -1298,7 +1298,6 @@ class BaseCommand extends core_1.Command {
1298
1298
  // CI scripts key off 75 to distinguish "re-authenticate" from
1299
1299
  // "bad command" (exit 2); without this carve-out they had to
1300
1300
  // string-match the stderr message, which was fragile.
1301
- const exitCode = this.bareMode ? 75 : 2;
1302
1301
  // An `osk_ci_*` token is a DAEMON BOOTSTRAP credential — only
1303
1302
  // `POST /api/daemons/token` accepts it. Telling its holder to run
1304
1303
  // `login` sends a CI job to do the one thing it cannot, and hides the
@@ -1308,6 +1307,11 @@ class BaseCommand extends core_1.Command {
1308
1307
  // and no daemon to ask: the server's own reason (expired, revoked) IS
1309
1308
  // the answer, and the repair is a new token, not `login`.
1310
1309
  const presentedPat = Boolean(this.resolvedCredential?.token?.startsWith('osk_pat_'));
1310
+ // A token nothing can renew is refused for good: a new token is the only repair, so a retry
1311
+ // loop is exactly the wrong response to it (OSK-15360). 77 (EX_NOPERM) rather than 75
1312
+ // (EX_TEMPFAIL), as the delegated-credential refusal that only a new sign-in repairs does.
1313
+ const unrenewable = presentedCiToken || presentedPat;
1314
+ const exitCode = this.bareMode ? (unrenewable ? 77 : 75) : 2;
1311
1315
  // OSK-12116 — the 401 is usually the SECOND failure: the token expired
1312
1316
  // (routine) and renewing it was refused (the fault). The server's code
1313
1317
  // for the retry is `TOKEN_EXPIRED`, which names the routine half; the
@@ -1361,7 +1365,7 @@ class BaseCommand extends core_1.Command {
1361
1365
  code: refreshRefusal?.code || bodyCode || 'AUTHENTICATION_FAILED',
1362
1366
  status: e.status,
1363
1367
  exit: exitCode,
1364
- retryable: true,
1368
+ retryable: !unrenewable,
1365
1369
  ...(Object.keys(details).length > 0 ? { details } : {}),
1366
1370
  });
1367
1371
  }
@@ -5,6 +5,7 @@ const core_1 = require("@oclif/core");
5
5
  const data_provider_1 = require("@skrr-ai/data-provider");
6
6
  const base_command_1 = require("../../../base-command");
7
7
  const format_1 = require("../../../lib/format");
8
+ const triggers_1 = require("../../../lib/triggers");
8
9
  /**
9
10
  * A schedule persisted while handling a conversation turn, for which no explicit
10
11
  * confirmation was recorded.
@@ -69,6 +70,7 @@ class AgendaTriggerList extends base_command_1.BaseCommand {
69
70
  const rows = items.map((t) => {
70
71
  const next = t.schedule?.nextRunAt ??
71
72
  t.selfScheduled?.nextRunAt ??
73
+ (0, triggers_1.onceDueAt)(t) ??
72
74
  '-';
73
75
  const fires = t.audit?.fireCount ?? 0;
74
76
  return {
@@ -366,7 +366,10 @@ class AgentsChat extends base_command_1.BaseCommand {
366
366
  'Assistant text arrives as `text.delta` whose `text` is the CUMULATIVE answer so far, ' +
367
367
  'not a delta — take the last one, or `run.result` at the end. The same text is ' +
368
368
  'mirrored inside `session.output` envelopes for consumers that want the raw stream, ' +
369
- 'so folding both doubles the answer: pick ONE lane. Inside a `session.output`, ' +
369
+ 'so folding both doubles the answer: pick ONE lane. A widget the agent wrote ' +
370
+ '(a block of CSS, HTML and JavaScript the apps draw) is its text description in ' +
371
+ '`text.delta` and `run.result`; the `session.output` lane carries the block itself. ' +
372
+ 'Inside a `session.output`, ' +
370
373
  '`envelopes[].__seq` is the dedupe key and the ordering key — the same envelope is ' +
371
374
  'delivered by more than one room, and a re-delivery repeats its `__seq`. A ' +
372
375
  '`stream.gap` event means envelopes in that seq range never arrived and replay from ' +
@@ -4,6 +4,8 @@ const data_provider_1 = require("@skrr-ai/data-provider");
4
4
  const core_1 = require("@oclif/core");
5
5
  const base_command_1 = require("../../base-command");
6
6
  const roles_1 = require("../../lib/roles");
7
+ const operating_plan_loops_1 = require("../../lib/operating-plan-loops");
8
+ const preflight_copy_1 = require("../../lib/preflight-copy");
7
9
  class AgentOperatingPlan extends base_command_1.BaseCommand {
8
10
  static description = 'Read responsibilities, evidence, inquiries, work, delayed evaluation and existing planning loops without scheduling work';
9
11
  static args = {
@@ -25,7 +27,7 @@ class AgentOperatingPlan extends base_command_1.BaseCommand {
25
27
  for (const r of plan.responsibilities) {
26
28
  this.log(`\n${r.title} · ${r.status} · ${r.kind} v${r.version}`);
27
29
  this.log(` Responsibility: ${r.purpose}`);
28
- this.log(` Evidence: ${r.evidence.status}${r.evidence.issues?.length ? ` (${r.evidence.issues.join(', ')})` : ''}`);
30
+ this.log(` Evidence: ${r.evidence.status}${r.evidence.issues?.length ? ` (${r.evidence.issues.map(preflight_copy_1.sourceRefusalWords).join('; ')})` : ''}`);
29
31
  this.log(" Execution authority: tools, sandbox and approvals use the Agent's runtime permissions.");
30
32
  for (const observation of r.evidenceAuthority?.observations || []) {
31
33
  const comparison = (0, data_provider_1.describeObservationChange)({
@@ -44,7 +46,8 @@ class AgentOperatingPlan extends base_command_1.BaseCommand {
44
46
  if (r.blocker)
45
47
  this.log(` Blocker: ${r.blocker.code} — ${r.blocker.remediation || ''}`);
46
48
  }
47
- this.log(`\n${plan.planning.loops.length} existing planning/reflection loops; ${plan.planning.todos.length} scheduled work blocks.`);
49
+ for (const line of (0, operating_plan_loops_1.planningLoopLines)(plan.planning.loops, plan.planning.todos.length))
50
+ this.log(line);
48
51
  if (plan.learning?.skillValidation)
49
52
  this.log(`Skill validation: ${plan.learning.skillValidation.enabled ? 'enabled' : 'disabled'} (${plan.learning.skillValidation.scope}); external effects validated: ${plan.learning.skillValidation.externalEffectsValidated}.`);
50
53
  if (!plan.coverage.complete) {
@@ -75,7 +75,9 @@ class AgentsTriggersCreate extends base_command_1.BaseCommand {
75
75
  'end-at': core_1.Flags.string({
76
76
  description: 'ISO-8601 datetime after which a schedule stops firing (--kind schedule)',
77
77
  }),
78
- 'stale-catchup-ms': core_1.Flags.integer({ description: 'Schedule stale catch-up window in ms' }),
78
+ 'stale-catchup-ms': core_1.Flags.integer({
79
+ description: 'How late a missed occurrence may still run, in ms (a positive number). After downtime, an occurrence more than this overdue is skipped rather than run late, and the schedule moves to its next future slot. Unset: 3600000 (1 hour).',
80
+ }),
79
81
  // once
80
82
  at: core_1.Flags.string({
81
83
  description: 'ISO-8601 datetime to fire once (--kind once). Must be ≥5s in the future.',
@@ -51,6 +51,8 @@ class AgentsTriggersFire extends base_command_1.BaseCommand {
51
51
  return;
52
52
  }
53
53
  this.log(`Fire requested: outcome=${String(result.outcome ?? '-')} reason=${String(result.reason ?? '-')}`);
54
+ for (const line of (0, triggers_1.describeFireDetail)(result))
55
+ this.log(line);
54
56
  }
55
57
  }
56
58
  exports.default = AgentsTriggersFire;
@@ -50,6 +50,8 @@ class AgentsTriggersReplay extends base_command_1.BaseCommand {
50
50
  return;
51
51
  }
52
52
  this.log(`Replay requested: ok=${String(result.ok ?? '-')} outcome=${String(result.outcome ?? '-')} reason=${String(result.reason ?? '-')}`);
53
+ for (const line of (0, triggers_1.describeFireDetail)(result))
54
+ this.log(line);
53
55
  }
54
56
  }
55
57
  exports.default = AgentsTriggersReplay;
@@ -62,9 +62,13 @@ class AgentsTriggersUpdate extends base_command_1.BaseCommand {
62
62
  'end-at': core_1.Flags.string({
63
63
  description: 'ISO-8601 datetime after which a schedule stops firing',
64
64
  }),
65
- 'stale-catchup-ms': core_1.Flags.integer({ description: 'Schedule stale catch-up window in ms' }),
65
+ 'stale-catchup-ms': core_1.Flags.integer({
66
+ description: 'How late a missed occurrence may still run, in ms (a positive number). After downtime, an occurrence more than this overdue is skipped rather than run late, and the schedule moves to its next future slot. Unset: 3600000 (1 hour).',
67
+ }),
66
68
  at: core_1.Flags.string({ description: 'ISO-8601 datetime for once triggers' }),
67
- entity: core_1.Flags.string({ description: 'Event entity type for event triggers' }),
69
+ entity: core_1.Flags.string({
70
+ description: 'Event entity type for event triggers (create only; refused on update)',
71
+ }),
68
72
  event: core_1.Flags.string({ description: 'Event type for event triggers' }),
69
73
  'filter-mode': core_1.Flags.string({
70
74
  description: 'Event filter mode',
@@ -79,8 +83,12 @@ class AgentsTriggersUpdate extends base_command_1.BaseCommand {
79
83
  'max-per-hour': core_1.Flags.integer({ description: 'Event hourly cap' }),
80
84
  probability: core_1.Flags.string({ description: 'Stochastic probability from 0 to 1' }),
81
85
  'jitter-ms': core_1.Flags.integer({ description: 'Stochastic jitter in ms' }),
82
- 'eval-interval-minutes': core_1.Flags.integer({ description: 'Stochastic eval interval in minutes' }),
83
- 'next-run-at': core_1.Flags.string({ description: 'ISO datetime for self_scheduled triggers' }),
86
+ 'eval-interval-minutes': core_1.Flags.integer({
87
+ description: 'Stochastic eval interval in minutes (create only; refused on update)',
88
+ }),
89
+ 'next-run-at': core_1.Flags.string({
90
+ description: 'ISO datetime: alias of --at for once triggers; for self_scheduled triggers it is set at create and refused on update',
91
+ }),
84
92
  'form-title': core_1.Flags.string({ description: 'Form heading for form triggers' }),
85
93
  'form-subtitle': core_1.Flags.string({ description: 'Form subtitle for form triggers' }),
86
94
  'form-fields': core_1.Flags.string({ description: 'Form fields JSON array for form triggers' }),
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const base_command_1 = require("../../base-command");
5
5
  const commitments_1 = require("../../lib/commitments");
6
+ const commitment_ledgers_1 = require("../../lib/commitment-ledgers");
6
7
  /**
7
8
  * `skrr commitments action-history <id>` — what the commitment DID, as opposed to
8
9
  * what it decided.
@@ -40,8 +41,12 @@ class CommitmentsActionHistory extends base_command_1.BaseCommand {
40
41
  catch (err) {
41
42
  this.handleApiError(err);
42
43
  }
43
- this.log(JSON.stringify(response, null, 2));
44
- (0, commitments_1.renderListPageHint)(response, (line) => this.log(line));
44
+ if (flags.json) {
45
+ this.log(JSON.stringify(response, null, 2));
46
+ (0, commitments_1.renderListPageHint)(response, (line) => this.log(line));
47
+ return;
48
+ }
49
+ (0, commitment_ledgers_1.renderActionHistory)(response, (line) => this.log(line));
45
50
  }
46
51
  }
47
52
  exports.default = CommitmentsActionHistory;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const base_command_1 = require("../../base-command");
5
5
  const commitments_1 = require("../../lib/commitments");
6
+ const commitment_ledgers_1 = require("../../lib/commitment-ledgers");
6
7
  /**
7
8
  * `skrr commitments cadence-decisions <id>` — the adaptive controller's
8
9
  * append-only decision ledger, including shadow recommendations.
@@ -30,7 +31,11 @@ class CommitmentsCadenceDecisions extends base_command_1.BaseCommand {
30
31
  catch (error) {
31
32
  this.handleApiError(error);
32
33
  }
33
- this.log(JSON.stringify(response, null, 2));
34
+ if (flags.json) {
35
+ this.log(JSON.stringify(response, null, 2));
36
+ return;
37
+ }
38
+ (0, commitment_ledgers_1.renderCadenceDecisions)(response, (line) => this.log(line));
34
39
  }
35
40
  }
36
41
  exports.default = CommitmentsCadenceDecisions;
@@ -6,7 +6,7 @@ import { BaseCommand } from '../../../base-command';
6
6
  * Approval changes only the check schedule; it grants no execution permissions.
7
7
  * Rejection records the decision and leaves the schedule unchanged.
8
8
  *
9
- * List the pending ones with `skrr commitments show <id>`.
9
+ * List the pending ones with `skrr commitments show <id>` (it prints each request id).
10
10
  */
11
11
  export default class CommitmentsCadenceRequestsDecide extends BaseCommand {
12
12
  static description: string;
@@ -10,7 +10,7 @@ const commitments_1 = require("../../../lib/commitments");
10
10
  * Approval changes only the check schedule; it grants no execution permissions.
11
11
  * Rejection records the decision and leaves the schedule unchanged.
12
12
  *
13
- * List the pending ones with `skrr commitments show <id>`.
13
+ * List the pending ones with `skrr commitments show <id>` (it prints each request id).
14
14
  */
15
15
  class CommitmentsCadenceRequestsDecide extends base_command_1.BaseCommand {
16
16
  static description = 'Approve or reject an agent-proposed commitment cadence change';
@@ -11,7 +11,13 @@ function doctorVerdict(input) {
11
11
  const operatingState = input.operatingState || {};
12
12
  const blocker = operatingState.firstActionableBlocker;
13
13
  if (blocker?.code) {
14
- return { verdict: 'blocked', next: String(blocker.remediation || 'Inspect the Commitment') };
14
+ // A lifecycle stop is a state, not a fault: a Commitment its owner paused is `paused`, with the
15
+ // way back as its next step, not `blocked` (OSK-15423).
16
+ const lifecycle = /^status_([a-z_]+)$/.exec(String(blocker.code));
17
+ return {
18
+ verdict: lifecycle ? lifecycle[1] : blocker.code === 'deleted' ? 'deleted' : 'blocked',
19
+ next: String(blocker.remediation || 'Inspect the Commitment'),
20
+ };
15
21
  }
16
22
  if (operatingState.status === 'waiting_approval') {
17
23
  return { verdict: 'waiting_approval', next: 'Open the pending prepared action for review' };
@@ -60,7 +60,13 @@ function renderObservationWindow(response, log) {
60
60
  * actually move the loop.
61
61
  */
62
62
  class CommitmentsObservations extends base_command_1.BaseCommand {
63
- static description = "Show what the commitment's runs reported observing";
63
+ static description = "Show what the commitment's runs reported observing.\n\n" +
64
+ 'Columns: VALUE is shortened to fit the table (--json has the stored value). DECLARED no / ' +
65
+ "REASON undeclared means the key is not declared on the Commitment's agent_run source: the " +
66
+ 'reading is recorded but can never open a loop. CLAMPED yes means the observed time the run ' +
67
+ 'claimed was moved into the accepted window (CLAIMED is what it said). CHANGED is the ' +
68
+ "server's verdict against the previous reading of the same key, never the run's. CONF is a " +
69
+ 'cap on how much an Agent-reported reading is worth, not a measurement.';
64
70
  static examples = [
65
71
  '<%= config.bin %> commitments observations obj_abc123',
66
72
  '<%= config.bin %> commitments observations obj_abc123 --declared-only --changed-only',
@@ -1,4 +1,18 @@
1
1
  import { BaseCommand } from '../../base-command';
2
+ type SystemCommitmentRow = {
3
+ systemRole?: string;
4
+ status?: string;
5
+ lastCheckedAt?: string;
6
+ lastMaterialChangeAt?: string;
7
+ lastUserNudgedAt?: string;
8
+ maxUserNudgesPerDay?: number;
9
+ };
10
+ /**
11
+ * What "no open questions" means, said only as far as it is true. "It has not told you anything is
12
+ * missing" read as reassurance under an Always-On-OFF header and loops that had never checked
13
+ * (OSK-15438): an Agent that cannot run cannot have asked.
14
+ */
15
+ export declare function noQuestionsSentence(alwaysOn: boolean, roles: SystemCommitmentRow[]): string;
2
16
  export default class CommitmentsOperatingReview extends BaseCommand {
3
17
  static description: string;
4
18
  static args: {
@@ -9,3 +23,4 @@ export default class CommitmentsOperatingReview extends BaseCommand {
9
23
  };
10
24
  run(): Promise<void>;
11
25
  }
26
+ export {};
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noQuestionsSentence = noQuestionsSentence;
3
4
  const core_1 = require("@oclif/core");
4
5
  const base_command_1 = require("../../base-command");
5
6
  const commitments_1 = require("../../lib/commitments");
@@ -24,6 +25,20 @@ function ago(value) {
24
25
  return `${Math.round(mins / 60)}h ago`;
25
26
  return `${Math.round(mins / (60 * 24))}d ago`;
26
27
  }
28
+ /**
29
+ * What "no open questions" means, said only as far as it is true. "It has not told you anything is
30
+ * missing" read as reassurance under an Always-On-OFF header and loops that had never checked
31
+ * (OSK-15438): an Agent that cannot run cannot have asked.
32
+ */
33
+ function noQuestionsSentence(alwaysOn, roles) {
34
+ if (!alwaysOn) {
35
+ return 'None recorded. Its background loops are not running (Always-On is off), so it has had no chance to ask.';
36
+ }
37
+ const checked = roles.some((role) => role.status === 'active' && role.lastCheckedAt);
38
+ return checked
39
+ ? 'None. It has not told you anything is missing.'
40
+ : 'None recorded yet. None of its loops has checked, so this says nothing about whether anything is missing.';
41
+ }
27
42
  class CommitmentsOperatingReview extends base_command_1.BaseCommand {
28
43
  static description = 'Read an agent’s system-managed commitment operating review';
29
44
  static args = {
@@ -33,6 +48,11 @@ class CommitmentsOperatingReview extends base_command_1.BaseCommand {
33
48
  async run() {
34
49
  this.requireAuth();
35
50
  const { args, flags } = await this.parse(CommitmentsOperatingReview);
51
+ // A Commitment id here answered "Agent not found" without saying an Agent id was wanted.
52
+ if (/^obj_/.test(args.agentId)) {
53
+ this.error(`${args.agentId} is a Commitment id; operating-review takes an Agent id. ` +
54
+ `Use \`skrr commitments status ${args.agentId}\` for one Commitment.`, { exit: 1 });
55
+ }
36
56
  let result;
37
57
  try {
38
58
  result = await commitments_1.commitmentApi.operatingReview(args.agentId);
@@ -84,7 +104,7 @@ class CommitmentsOperatingReview extends base_command_1.BaseCommand {
84
104
  this.log('');
85
105
  this.log(`Open questions from this agent (${questions.length})`);
86
106
  if (questions.length === 0) {
87
- this.log(' None. It has not told you anything is missing.');
107
+ this.log(` ${noQuestionsSentence(alwaysOn, roles)}`);
88
108
  }
89
109
  for (const q of questions) {
90
110
  this.log(` • ${q.question}`);
@@ -93,7 +113,8 @@ class CommitmentsOperatingReview extends base_command_1.BaseCommand {
93
113
  this.log(` asked ${ago(q.askedAt)}`);
94
114
  }
95
115
  this.log('');
96
- this.log(`Business commitments: ${portfolio.activeCommitmentCount ?? 0} active, ${portfolio.pausedCommitmentCount ?? 0} paused`);
116
+ const drafts = portfolio.draftCommitmentCount ?? 0;
117
+ this.log(`Business commitments: ${portfolio.activeCommitmentCount ?? 0} active, ${portfolio.pausedCommitmentCount ?? 0} paused${drafts > 0 ? `, ${drafts} draft` : ''}`);
97
118
  }
98
119
  }
99
120
  exports.default = CommitmentsOperatingReview;
@@ -23,6 +23,18 @@ type PreflightGate = CommitmentPreflightReport['gates'][number];
23
23
  * The note gets its own indented line. It is prose, and hanging it off the same
24
24
  * dash as a short code puts two different kinds of thing in one slot.
25
25
  */
26
+ /**
27
+ * The upcoming runs, said honestly under the verdict above them (OSK-15440).
28
+ *
29
+ * The cadence projection does not know whether the Commitment can run, so a paused one, or one
30
+ * with Always-On off, still listed three timestamps beneath "Run is blocked" and answered "when
31
+ * next?" opposite to `show` ("no wake observed yet"). While the run is blocked they are what the
32
+ * cadence WOULD do, so they are labelled that way instead of reading as a promise.
33
+ */
34
+ export declare function nextRunsLines(report: {
35
+ verdict?: string;
36
+ nextRuns?: string[];
37
+ }): string[];
26
38
  export declare function preflightGateLines(gate: PreflightGate, verbose?: boolean): string[];
27
39
  export default class CommitmentsPreflight extends BaseCommand {
28
40
  static description: string;
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nextRunsLines = nextRunsLines;
3
4
  exports.preflightGateLines = preflightGateLines;
4
5
  const core_1 = require("@oclif/core");
5
6
  const data_provider_1 = require("@skrr-ai/data-provider");
6
7
  const base_command_1 = require("../../base-command");
7
8
  const commitments_1 = require("../../lib/commitments");
8
9
  const prompt_1 = require("../../lib/prompt");
10
+ const preflight_copy_1 = require("../../lib/preflight-copy");
9
11
  /**
10
12
  * The lines one preflight gate contributes.
11
13
  *
@@ -23,6 +25,22 @@ const prompt_1 = require("../../lib/prompt");
23
25
  * The note gets its own indented line. It is prose, and hanging it off the same
24
26
  * dash as a short code puts two different kinds of thing in one slot.
25
27
  */
28
+ /**
29
+ * The upcoming runs, said honestly under the verdict above them (OSK-15440).
30
+ *
31
+ * The cadence projection does not know whether the Commitment can run, so a paused one, or one
32
+ * with Always-On off, still listed three timestamps beneath "Run is blocked" and answered "when
33
+ * next?" opposite to `show` ("no wake observed yet"). While the run is blocked they are what the
34
+ * cadence WOULD do, so they are labelled that way instead of reading as a promise.
35
+ */
36
+ function nextRunsLines(report) {
37
+ if (!report.nextRuns?.length)
38
+ return ['', 'Next runs: none scheduled'];
39
+ const header = report.verdict === 'blocked'
40
+ ? 'Next runs (the cadence\u2019s times; none will fire while the run is blocked above):'
41
+ : 'Next runs:';
42
+ return ['', header, ...report.nextRuns.map((run) => ` ${run}`)];
43
+ }
26
44
  function preflightGateLines(gate, verbose = false) {
27
45
  // "Could it contact you now?" is not a Run gate. It answers whether a message
28
46
  // would reach the owner, and a limit the owner set themselves (zero nudges a day,
@@ -90,6 +108,8 @@ function preflightGateLines(gate, verbose = false) {
90
108
  if (typeof hint === 'string' && hint.trim()) {
91
109
  lines.push(` ${hint.trim()}`);
92
110
  }
111
+ for (const sentence of (0, preflight_copy_1.gateExplanationLines)(gate))
112
+ lines.push(` ${sentence}`);
93
113
  return lines;
94
114
  }
95
115
  class CommitmentsPreflight extends base_command_1.BaseCommand {
@@ -171,21 +191,15 @@ class CommitmentsPreflight extends base_command_1.BaseCommand {
171
191
  cloud_runtime: 'Runtime-scoped access',
172
192
  };
173
193
  for (const capability of report.capabilities) {
174
- this.log(` ${sourceLabels[capability.source]} · ${capability.provider} · ${capability.capability}${capability.scope ? ` · ${capability.scope}` : ''}: ${capability.status}`);
194
+ this.log(` ${sourceLabels[capability.source]} · ${capability.provider} · ${capability.capability}${capability.scope ? ` · ${capability.scope}` : ''}: ${(0, preflight_copy_1.capabilityStatusLabel)(capability)}`);
175
195
  if (capability.testedAt)
176
196
  this.log(` Tested: ${capability.testedAt}${capability.expiresAt ? ` · expires ${capability.expiresAt}` : ''}`);
177
197
  if (capability.attestation === 'machine')
178
198
  this.log(' Machine-attested; not platform-attested.');
179
199
  }
180
200
  }
181
- if (report.nextRuns?.length) {
182
- this.log('\nNext runs:');
183
- for (const run of report.nextRuns)
184
- this.log(` ${run}`);
185
- }
186
- else {
187
- this.log('\nNext runs: none scheduled');
188
- }
201
+ for (const line of nextRunsLines(report))
202
+ this.log(line);
189
203
  this.log('\nEndpoints:');
190
204
  for (const endpoint of report.endpoints || []) {
191
205
  this.log(` ${endpoint.available ? 'ok ' : 'BLOCK'} ${endpoint.label || endpoint.destination}` +
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const base_command_1 = require("../../base-command");
5
5
  const commitments_1 = require("../../lib/commitments");
6
+ const commitment_ledgers_1 = require("../../lib/commitment-ledgers");
6
7
  class CommitmentsReflection extends base_command_1.BaseCommand {
7
8
  static description = 'Read pending and decided reflection proposals for a commitment';
8
9
  static args = {
@@ -19,7 +20,11 @@ class CommitmentsReflection extends base_command_1.BaseCommand {
19
20
  catch (error) {
20
21
  this.handleApiError(error);
21
22
  }
22
- this.log(flags.json ? JSON.stringify(result, null, 2) : JSON.stringify(result, null, 2));
23
+ if (flags.json) {
24
+ this.log(JSON.stringify(result, null, 2));
25
+ return;
26
+ }
27
+ (0, commitment_ledgers_1.renderReflection)(result, (line) => this.log(line));
23
28
  }
24
29
  }
25
30
  exports.default = CommitmentsReflection;
@@ -49,7 +49,9 @@ class CommitmentsShow extends base_command_1.BaseCommand {
49
49
  this.log(`Commitment ${args.id} not found.`);
50
50
  return;
51
51
  }
52
- (0, commitments_1.renderCommitmentSummary)((0, commitments_1.withLiveAssessment)(response.commitment, response.operatingState), (line) => this.log(line), response.latestCheck);
52
+ (0, commitments_1.renderCommitmentSummary)((0, commitments_1.withLiveAssessment)(response.commitment, response.operatingState), (line) => this.log(line), response.latestCheck, response.scheduleIssues);
53
+ for (const line of (0, commitments_1.pendingCadenceRequestLines)(response.commitment))
54
+ this.log(line);
53
55
  // Whose permissions a run uses (OSK-11975) — read from the operating state,
54
56
  // which carries the same projection preflight reports (OSK-12065).
55
57
  const autonomy = response.operatingState?.execution;
@@ -4,6 +4,7 @@ exports.formatTriggerStatus = formatTriggerStatus;
4
4
  const core_1 = require("@oclif/core");
5
5
  const base_command_1 = require("../../base-command");
6
6
  const commitments_1 = require("../../lib/commitments");
7
+ const commitment_event_wakes_1 = require("../../lib/commitment-event-wakes");
7
8
  /**
8
9
  * `skrr commitments trigger-status <id>` — what the SCHEDULER actually has.
9
10
  *
@@ -103,29 +104,8 @@ function formatTriggerStatus(status) {
103
104
  }
104
105
  }
105
106
  }
106
- const caps = (status.eventCapabilities ?? {});
107
107
  lines.push('');
108
- lines.push('Event wakes:');
109
- lines.push(` requested: ${caps.requested ? 'yes' : 'no'}`);
110
- lines.push(` configured sources: ${(caps.configuredSources ?? []).join(', ') || 'none'}`);
111
- lines.push(` eligible sources: ${(caps.eligibleSources ?? []).join(', ') || 'none'}`);
112
- lines.push(` materialized sources: ${(caps.materializedSources ?? []).join(', ') || 'none'}`);
113
- if ((caps.dormantSources ?? []).length) {
114
- lines.push(` dormant sources: ${caps.dormantSources.join(', ')} (configured but the cadence never requests them)`);
115
- }
116
- if ((caps.unroutableSources ?? []).length) {
117
- lines.push(` unroutable sources: ${caps
118
- .unroutableSources.map((item) => `${item.source} (${item.reason})`)
119
- .join(', ')} — materialized but no upstream producer can deliver events`);
120
- }
121
- if ((caps.permissionGaps ?? []).length) {
122
- lines.push(` permission gaps: ${caps
123
- .permissionGaps.map((gap) => `${gap.source} ${gap.capability ?? gap.permission}` +
124
- ` (${gap.impact === 'evidence_read' ? 'needed by' : 'blocks'} ${(gap.events ?? []).join(', ')})`)
125
- .join('; ')} — the routing GitHub installation does not hold the permission`);
126
- }
127
- if (caps.degradedReason)
128
- lines.push(` degraded: ${caps.degradedReason}`);
108
+ lines.push(...(0, commitment_event_wakes_1.eventWakeLines)((status.eventCapabilities ?? {})));
129
109
  const recent = (status.recent ?? {});
130
110
  const fires = recent.fires ?? [];
131
111
  lines.push('');
@@ -1,5 +1,18 @@
1
1
  import { BaseCommand } from '../../base-command';
2
+ import { type CommitmentWakeCapabilities } from '../../lib/commitments';
3
+ /**
4
+ * The headline used to stop at "configured sources may wake the Agent within lifecycle and execution
5
+ * budgets", over a column marked ACTIVE, which read as bound while `trigger-status` said no event
6
+ * wake would fire (OSK-15428, OSK-15419). It still says what a source does, conditionally.
7
+ */
2
8
  export declare function wakePolicyHeadline(_result?: unknown): string;
9
+ /**
10
+ * The lines above the table. The table is what the Agent may PICK; what is bound is the server's
11
+ * `trigger-status` event-wake block, printed by the same function in the same words, so the two
12
+ * commands cannot disagree. No sentence here concludes "armed" or "none will fire": that depends
13
+ * on Always-On, the upstream installation and leftover rows, which only the facts carry.
14
+ */
15
+ export declare function wakePolicyLines(result?: CommitmentWakeCapabilities): string[];
3
16
  /**
4
17
  * `skrr commitments wake-capabilities <id>` — which wakes an Agent may pick.
5
18
  *
@@ -1,12 +1,47 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.wakePolicyHeadline = wakePolicyHeadline;
4
+ exports.wakePolicyLines = wakePolicyLines;
4
5
  const core_1 = require("@oclif/core");
5
6
  const base_command_1 = require("../../base-command");
6
7
  const commitments_1 = require("../../lib/commitments");
7
8
  const format_1 = require("../../lib/format");
9
+ const commitment_event_wakes_1 = require("../../lib/commitment-event-wakes");
10
+ /**
11
+ * The headline used to stop at "configured sources may wake the Agent within lifecycle and execution
12
+ * budgets", over a column marked ACTIVE, which read as bound while `trigger-status` said no event
13
+ * wake would fire (OSK-15428, OSK-15419). It still says what a source does, conditionally.
14
+ */
8
15
  function wakePolicyHeadline(_result) {
9
- return 'Wake behavior: configured sources may wake the Agent within lifecycle and execution budgets.';
16
+ return 'Wake behavior: configured sources may wake the Agent within lifecycle and execution budgets, once an event wake is bound to them.';
17
+ }
18
+ /**
19
+ * The lines above the table. The table is what the Agent may PICK; what is bound is the server's
20
+ * `trigger-status` event-wake block, printed by the same function in the same words, so the two
21
+ * commands cannot disagree. No sentence here concludes "armed" or "none will fire": that depends
22
+ * on Always-On, the upstream installation and leftover rows, which only the facts carry.
23
+ */
24
+ function wakePolicyLines(result) {
25
+ const wakes = result?.standingEventWakes;
26
+ const pickable = 'The table lists wakes the Agent may pick, not what is bound.';
27
+ if (!wakes) {
28
+ return [
29
+ wakePolicyHeadline(),
30
+ `${pickable} \`skrr commitments trigger-status <id>\` shows what is bound.`,
31
+ ];
32
+ }
33
+ const lines = [wakePolicyHeadline(), pickable];
34
+ if (wakes.commitmentStatus !== 'active') {
35
+ lines.push(`The Commitment's status is ${wakes.commitmentStatus}, so none of this wakes it.`);
36
+ }
37
+ lines.push(`Cadence mode: ${wakes.cadenceMode ?? 'unknown'}`);
38
+ lines.push(...(0, commitment_event_wakes_1.eventWakeLines)(wakes.eventCapabilities));
39
+ lines.push('`materialized` means a trigger exists, not that it is enabled or can fire (Always-On, the upstream ' +
40
+ 'installation): `skrr commitments trigger-status <id>` lists each binding with its state.');
41
+ if (wakes.commitmentStatus === 'active' && wakes.agentChosenEventWaits > 0) {
42
+ lines.push(`The Agent has ${wakes.agentChosenEventWaits} event wait(s) of its own set (enabled trigger rows); the cadence does not gate those.`);
43
+ }
44
+ return lines;
10
45
  }
11
46
  /**
12
47
  * `skrr commitments wake-capabilities <id>` — which wakes an Agent may pick.
@@ -47,7 +82,8 @@ class CommitmentsWakeCapabilities extends base_command_1.BaseCommand {
47
82
  this.log(JSON.stringify(result, null, 2));
48
83
  return;
49
84
  }
50
- this.log(wakePolicyHeadline());
85
+ for (const line of wakePolicyLines(result))
86
+ this.log(line);
51
87
  const visible = new Set(result.visibleCapabilities.map((item) => item.id));
52
88
  (0, format_1.renderTable)(result.eligibleCapabilities.map((item) => ({
53
89
  id: item.id,
@@ -58,7 +94,7 @@ class CommitmentsWakeCapabilities extends base_command_1.BaseCommand {
58
94
  { key: 'id', header: 'CAPABILITY' },
59
95
  { key: 'kind', header: 'KIND' },
60
96
  { key: 'source', header: 'SOURCE' },
61
- { key: 'offered', header: 'ACTIVE' },
97
+ { key: 'offered', header: 'OFFERED' },
62
98
  ], (line) => this.log(line));
63
99
  }
64
100
  }