@skrr-ai/cli 0.1.103 → 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 (111) 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/create.js +2 -0
  14. package/dist/commands/commitments/doctor.js +7 -1
  15. package/dist/commands/commitments/observations.js +7 -1
  16. package/dist/commands/commitments/operating-review.d.ts +15 -0
  17. package/dist/commands/commitments/operating-review.js +23 -2
  18. package/dist/commands/commitments/preflight.d.ts +12 -0
  19. package/dist/commands/commitments/preflight.js +23 -9
  20. package/dist/commands/commitments/reflection.js +6 -1
  21. package/dist/commands/commitments/show.js +3 -1
  22. package/dist/commands/commitments/trigger-status.js +2 -22
  23. package/dist/commands/commitments/wake-capabilities.d.ts +13 -0
  24. package/dist/commands/commitments/wake-capabilities.js +39 -3
  25. package/dist/commands/daemon/logs.d.ts +109 -4
  26. package/dist/commands/daemon/logs.js +397 -43
  27. package/dist/commands/followups/act.js +13 -1
  28. package/dist/commands/followups/checkin.js +11 -2
  29. package/dist/commands/followups/reschedule.js +13 -1
  30. package/dist/commands/proposals/discard.d.ts +1 -1
  31. package/dist/commands/proposals/keep.d.ts +1 -1
  32. package/dist/commands/proposals/list.d.ts +7 -0
  33. package/dist/commands/proposals/list.js +31 -5
  34. package/dist/commands/proposals/show.d.ts +2 -1
  35. package/dist/commands/proposals/show.js +31 -4
  36. package/dist/commands/proposals/snooze.d.ts +1 -1
  37. package/dist/commands/requests/create.js +8 -3
  38. package/dist/commands/spaces/workflows/create.js +3 -3
  39. package/dist/commands/tasks/complete.js +4 -0
  40. package/dist/commands/tasks/create.d.ts +2 -0
  41. package/dist/commands/tasks/create.js +17 -3
  42. package/dist/commands/tasks/deliverable/add.d.ts +2 -0
  43. package/dist/commands/tasks/deliverable/add.js +22 -7
  44. package/dist/commands/tasks/deliverable/list.d.ts +13 -0
  45. package/dist/commands/tasks/deliverable/list.js +34 -1
  46. package/dist/commands/tasks/economics-compare.js +7 -1
  47. package/dist/commands/tasks/expectations.d.ts +10 -0
  48. package/dist/commands/tasks/expectations.js +31 -3
  49. package/dist/commands/tasks/list.d.ts +9 -0
  50. package/dist/commands/tasks/list.js +40 -5
  51. package/dist/commands/tasks/report.js +1 -1
  52. package/dist/commands/tasks/result/show.d.ts +7 -0
  53. package/dist/commands/tasks/result/show.js +32 -1
  54. package/dist/commands/tasks/result/submit.js +1 -1
  55. package/dist/commands/tasks/show.d.ts +6 -0
  56. package/dist/commands/tasks/show.js +23 -0
  57. package/dist/commands/tasks/update.d.ts +3 -0
  58. package/dist/commands/tasks/update.js +23 -3
  59. package/dist/commands/triggers/audit.js +6 -2
  60. package/dist/commands/triggers/create.js +3 -1
  61. package/dist/commands/triggers/fire.d.ts +1 -0
  62. package/dist/commands/triggers/fire.js +16 -1
  63. package/dist/commands/triggers/preflight.js +6 -5
  64. package/dist/commands/triggers/replay.js +2 -0
  65. package/dist/commands/triggers/update.js +12 -4
  66. package/dist/commands/workspaces/stewardship.js +5 -1
  67. package/dist/lib/agentic-stream.d.ts +9 -0
  68. package/dist/lib/agentic-stream.js +38 -18
  69. package/dist/lib/commitment-event-wakes.d.ts +8 -0
  70. package/dist/lib/commitment-event-wakes.js +39 -0
  71. package/dist/lib/commitment-ledgers.d.ts +9 -0
  72. package/dist/lib/commitment-ledgers.js +126 -0
  73. package/dist/lib/commitments.d.ts +102 -2
  74. package/dist/lib/commitments.js +208 -8
  75. package/dist/lib/delegated-cli.js +13 -2
  76. package/dist/lib/followups.d.ts +6 -0
  77. package/dist/lib/followups.js +12 -0
  78. package/dist/lib/message-content.d.ts +6 -0
  79. package/dist/lib/message-content.js +24 -0
  80. package/dist/lib/operating-plan-loops.d.ts +8 -0
  81. package/dist/lib/operating-plan-loops.js +32 -0
  82. package/dist/lib/preflight-copy.d.ts +27 -0
  83. package/dist/lib/preflight-copy.js +89 -0
  84. package/dist/lib/proposal-decision-command.d.ts +1 -1
  85. package/dist/lib/proposal-decision-command.js +27 -3
  86. package/dist/lib/proposals.d.ts +17 -0
  87. package/dist/lib/proposals.js +41 -0
  88. package/dist/lib/stewardship-output.js +57 -12
  89. package/dist/lib/task-economics-line.d.ts +30 -0
  90. package/dist/lib/task-economics-line.js +49 -0
  91. package/dist/lib/task-economics.d.ts +15 -0
  92. package/dist/lib/task-economics.js +73 -8
  93. package/dist/lib/task-recurrence-outcome.d.ts +19 -0
  94. package/dist/lib/task-recurrence-outcome.js +30 -0
  95. package/dist/lib/triggers.d.ts +42 -0
  96. package/dist/lib/triggers.js +136 -2
  97. package/dist/lib/widgetTerminalText.d.ts +8 -0
  98. package/dist/lib/widgetTerminalText.js +116 -0
  99. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.d.ts +33 -0
  100. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.js +27 -0
  101. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.d.ts +84 -0
  102. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.js +222 -0
  103. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.d.ts +33 -0
  104. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.js +26 -0
  105. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.d.ts +84 -0
  106. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.js +216 -0
  107. package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
  108. package/dist/node_modules/@skrr-ai/data-provider/index.js +7628 -7414
  109. package/docs/v1/operations.md +1 -1
  110. package/oclif.manifest.json +117 -73
  111. package/package.json +1 -1
@@ -0,0 +1,9 @@
1
+ export declare function renderActionHistory(page: {
2
+ data?: unknown[];
3
+ has_more?: boolean;
4
+ next_cursor?: string | null;
5
+ } | undefined, log: (line: string) => void): void;
6
+ export declare function renderReflection(review: Record<string, unknown> | undefined, log: (line: string) => void): void;
7
+ export declare function renderCadenceDecisions(list: {
8
+ data?: unknown[];
9
+ } | undefined, log: (line: string) => void): void;
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderActionHistory = renderActionHistory;
4
+ exports.renderReflection = renderReflection;
5
+ exports.renderCadenceDecisions = renderCadenceDecisions;
6
+ /**
7
+ * Human views for three Commitment read commands that printed raw JSON without `--json`
8
+ * (OSK-15435): `action-history`, `reflection` and `cadence-decisions`. `--json` is unchanged; these
9
+ * only replace the default. An empty ledger is a sentence, not `"data": []`.
10
+ */
11
+ const format_1 = require("./format");
12
+ const commitments_1 = require("./commitments");
13
+ const text = (value, fallback = '-') => typeof value === 'string' && value.trim()
14
+ ? value
15
+ : typeof value === 'number'
16
+ ? String(value)
17
+ : fallback;
18
+ /** First sentence-ish chunk of a message, bounded, so a table row stays a row. */
19
+ function brief(value, max = 80) {
20
+ const raw = text(value, '');
21
+ if (!raw)
22
+ return '';
23
+ const firstLine = raw.split('\n')[0];
24
+ return firstLine.length > max ? `${firstLine.slice(0, max - 1)}…` : firstLine;
25
+ }
26
+ function minutes(ms) {
27
+ if (typeof ms !== 'number' || !Number.isFinite(ms))
28
+ return '-';
29
+ const m = Math.round(ms / 60000);
30
+ if (m >= 1440 && m % 1440 === 0)
31
+ return `${m / 1440}d`;
32
+ if (m >= 60 && m % 60 === 0)
33
+ return `${m / 60}h`;
34
+ return `${m}m`;
35
+ }
36
+ function renderActionHistory(page, log) {
37
+ const rows = (Array.isArray(page?.data) ? page.data : []);
38
+ if (rows.length === 0) {
39
+ log('No actions recorded.');
40
+ }
41
+ else {
42
+ (0, format_1.renderTable)(rows.map((row) => ({
43
+ when: text(row.occurredAt),
44
+ type: text(row.type),
45
+ status: text(row.status),
46
+ check: text(row.checkId),
47
+ // A failed or refused action's reason is the point of reading history.
48
+ why: [text(row.errorCode, ''), brief(row.errorMessage ?? row.reason)]
49
+ .filter(Boolean)
50
+ .join(' · '),
51
+ })), [
52
+ { key: 'when', header: 'WHEN' },
53
+ { key: 'type', header: 'ACTION' },
54
+ { key: 'status', header: 'STATUS' },
55
+ { key: 'check', header: 'CHECK' },
56
+ { key: 'why', header: 'WHY', maxWidth: 100 },
57
+ ], log);
58
+ }
59
+ (0, commitments_1.renderListPageHint)(page, log);
60
+ }
61
+ function renderReflection(review, log) {
62
+ const metrics = (review?.metrics ?? {});
63
+ const proposals = Array.isArray(review?.proposals) ? review.proposals : [];
64
+ if (proposals.length === 0) {
65
+ log('No reflection proposals recorded.');
66
+ }
67
+ else {
68
+ log(`Reflection proposals: ${text(metrics.total, String(proposals.length))} total · ` +
69
+ `${text(metrics.awaitingApproval, '0')} awaiting approval · ${text(metrics.applied, '0')} applied · ` +
70
+ `${text(metrics.rejected, '0')} rejected · ${text(metrics.failed, '0')} failed`);
71
+ }
72
+ if (review?.lastReflectionAt)
73
+ log(`Last reflection: ${text(review.lastReflectionAt)}`);
74
+ const held = Array.isArray(review?.activeProposalKeys)
75
+ ? review.activeProposalKeys
76
+ : [];
77
+ if (held.length > 0)
78
+ log(`Held proposal keys: ${held.map((key) => text(key)).join(', ')}`);
79
+ if (proposals.length === 0)
80
+ return;
81
+ (0, format_1.renderTable)(proposals.map((row) => {
82
+ const proposal = (row.proposal ?? {});
83
+ const decision = (row.decision ?? {});
84
+ return {
85
+ when: text(row.occurredAt),
86
+ status: text(row.status),
87
+ type: text(proposal.type),
88
+ subject: brief(proposal.subject, 60),
89
+ decision: [text(decision.decision, ''), brief(decision.reason, 50)]
90
+ .filter(Boolean)
91
+ .join(' · '),
92
+ check: text(row.checkId),
93
+ };
94
+ }), [
95
+ { key: 'when', header: 'WHEN' },
96
+ { key: 'status', header: 'STATUS' },
97
+ { key: 'type', header: 'TYPE' },
98
+ { key: 'subject', header: 'SUBJECT', maxWidth: 60 },
99
+ { key: 'decision', header: 'DECISION', maxWidth: 70 },
100
+ { key: 'check', header: 'CHECK' },
101
+ ], log);
102
+ }
103
+ function renderCadenceDecisions(list, log) {
104
+ const rows = (Array.isArray(list?.data) ? list.data : []);
105
+ if (rows.length === 0) {
106
+ log('No cadence decisions recorded.');
107
+ return;
108
+ }
109
+ (0, format_1.renderTable)(rows.map((row) => ({
110
+ when: text(row.decidedAt),
111
+ mode: text(row.mode),
112
+ disposition: text(row.disposition),
113
+ direction: text(row.direction),
114
+ interval: `${minutes(row.currentIntervalMs)} → ${minutes(row.candidateIntervalMs)}`,
115
+ confidence: typeof row.confidence === 'number' ? row.confidence.toFixed(2) : '-',
116
+ reason: brief(row.reason, 70),
117
+ })), [
118
+ { key: 'when', header: 'DECIDED' },
119
+ { key: 'mode', header: 'MODE' },
120
+ { key: 'disposition', header: 'DISPOSITION' },
121
+ { key: 'direction', header: 'DIRECTION' },
122
+ { key: 'interval', header: 'INTERVAL' },
123
+ { key: 'confidence', header: 'CONFIDENCE' },
124
+ { key: 'reason', header: 'REASON', maxWidth: 70 },
125
+ ], log);
126
+ }
@@ -18,7 +18,7 @@ import { type CommitmentObservationsQuery, type CommitmentObservationsResponse }
18
18
  * "hold this state", derived from a Compass invariant — not authored here).
19
19
  */
20
20
  import { COMMITMENT_WATCHED_SOURCES, COMMITMENT_TEMPLATE_IDS, COMMITMENT_CADENCE_MODES, COMMITMENT_CADENCE_TIME_PATTERN, COMMITMENT_CADENCE_MAX_TIMES, COMMITMENT_EXECUTION_ISOLATION_MODES, COMMITMENT_STATUSES, COMMITMENT_KIND_VALUES } from '@skrr-ai/data-provider';
21
- import type { CommitmentCheck, CommitmentChecksResponse, Commitment, CommitmentActionProposal, CommitmentListResponse, CommitmentPlanResponse, CommitmentStatusResponse, CommitmentWorkLink, CommitmentExecutionReceiptListResponse, CommitmentExecutionReceiptQuarterlyMetricsResponse, CommitmentCapabilitySource, CommitmentDeliveryPatchResponse, CommitmentDeliveryBundleResponse, CommitmentCyclesResponse, CommitmentExplanationResponse, CommitmentRunPermissions, CommitmentLoopStatus, CommitmentRoster } from '@skrr-ai/data-provider';
21
+ import type { CommitmentCheck, CommitmentChecksResponse, Commitment, CommitmentActionProposal, CommitmentListResponse, CommitmentPlanResponse, CommitmentScheduleIssue, CommitmentStatusResponse, CommitmentWorkLink, CommitmentExecutionReceiptListResponse, CommitmentExecutionReceiptQuarterlyMetricsResponse, CommitmentCapabilitySource, CommitmentDeliveryPatchResponse, CommitmentDeliveryBundleResponse, CommitmentCyclesResponse, CommitmentExplanationResponse, CommitmentRunPermissions, CommitmentLoopStatus, CommitmentRoster } from '@skrr-ai/data-provider';
22
22
  import { withQuery } from './triggers';
23
23
  export { COMMITMENT_WATCHED_SOURCES, COMMITMENT_TEMPLATE_IDS, COMMITMENT_CADENCE_MODES, COMMITMENT_CADENCE_TIME_PATTERN, COMMITMENT_CADENCE_MAX_TIMES, COMMITMENT_STATUSES, COMMITMENT_KIND_VALUES, };
24
24
  export type { CommitmentCheck, CommitmentChecksResponse, Commitment, CommitmentActionProposal, CommitmentListResponse, CommitmentPlanResponse, CommitmentStatusResponse, CommitmentWorkLink, };
@@ -105,6 +105,13 @@ export type CommitmentPreflightReport = {
105
105
  * report it) prints nothing rather than a guess.
106
106
  */
107
107
  export declare function permissionLines(permissions: CommitmentRunPermissions | null | undefined): string[];
108
+ /**
109
+ * The lines `show` prints for a stored schedule setting the engine cannot honour
110
+ * (OSK-15452): the cadence line above them reads as honoured while the daily times
111
+ * run on UTC. The sentence and the remedy are the server's; this only lays them out.
112
+ * An older server reports none, which prints nothing rather than a guess.
113
+ */
114
+ export declare function scheduleIssueLines(issues: CommitmentScheduleIssue[] | null | undefined): string[];
108
115
  /**
109
116
  * One line naming fields that are still in the JSON but decide nothing any
110
117
  * more. Deprecation, not removal: `--json` keeps them for scripts.
@@ -568,6 +575,36 @@ export interface CommitmentCostWindow {
568
575
  unavailableRunCount?: number;
569
576
  costStatus?: 'reported' | 'partial' | 'unavailable' | 'not_applicable';
570
577
  }
578
+ /**
579
+ * The event-wake block of a Commitment's trigger status (`eventCapabilities`), as the server sends
580
+ * it. Rendered by `eventWakeLines` for both `trigger-status` and `wake-capabilities`.
581
+ */
582
+ export type EventWakeCapabilities = {
583
+ requested?: boolean;
584
+ configuredSources?: string[];
585
+ eligibleSources?: string[];
586
+ materializedSources?: string[];
587
+ dormantSources?: string[];
588
+ unroutableSources?: {
589
+ source?: string;
590
+ reason?: string;
591
+ }[];
592
+ /** Sources whose upstream producer was positively verified to route events here. */
593
+ verifiedSources?: string[];
594
+ /** Sources whose upstream could not be read: "cannot see", never "fine" (OSK-16209). */
595
+ unverifiedSources?: {
596
+ source?: string;
597
+ reason?: string;
598
+ }[];
599
+ permissionGaps?: {
600
+ source?: string;
601
+ permission?: string;
602
+ capability?: string;
603
+ events?: string[];
604
+ impact?: string;
605
+ }[];
606
+ degradedReason?: string;
607
+ };
571
608
  /** Shape of `GET /:id/wake-capabilities`. */
572
609
  export interface CommitmentWakeCapabilities {
573
610
  eligibleCapabilities: Array<{
@@ -580,6 +617,17 @@ export interface CommitmentWakeCapabilities {
580
617
  kind?: string;
581
618
  source?: string;
582
619
  }>;
620
+ /**
621
+ * The event-wake facts `trigger-status` reports, verbatim, plus the Agent's own enabled event
622
+ * waits. Absent from a server that predates it, or when the status could not be read: "no
623
+ * statement", never "nothing is bound".
624
+ */
625
+ standingEventWakes?: {
626
+ commitmentStatus: string;
627
+ cadenceMode?: string;
628
+ eventCapabilities: EventWakeCapabilities;
629
+ agentChosenEventWaits: number;
630
+ } | null;
583
631
  }
584
632
  /** One-tap check feedback. `handled` means "I dealt with it", not "good nudge". */
585
633
  export declare const COMMITMENT_FEEDBACK_KINDS: readonly ["useful", "noisy", "wrong", "handled"];
@@ -624,6 +672,12 @@ export declare function commitmentConcurrencyEnvelopePatch({ rawValue, reason, a
624
672
  reason?: string;
625
673
  autonomous?: boolean;
626
674
  }): Record<string, unknown> | undefined;
675
+ /**
676
+ * What `policy.evidenceGate.requireMaterialEvidenceForAutonomousRun` does to this Commitment's
677
+ * scheduled runs, in a line `show` can print (OSK-15417). It existed only in `show --json`: nothing
678
+ * in help, docs or any text view said whether a run on an unchanged day would be held back.
679
+ */
680
+ export declare function describeEvidenceGate(commitment: CommitmentView): string;
627
681
  export declare function describeCommitmentConcurrency(commitment: CommitmentView): string;
628
682
  export declare function parseIntervalToMs(input: string): number;
629
683
  /**
@@ -699,6 +753,11 @@ export declare function buildSuccessCriteria(labels: string[], opts?: {
699
753
  measureId?: string;
700
754
  source?: string;
701
755
  }): SuccessCriterionInput[];
756
+ /**
757
+ * The cadence changes an Agent has proposed and nobody has decided. `cadence-requests decide` needs a request
758
+ * id, and `show` listed none, so a person could not find the id to pass (OSK-15422).
759
+ */
760
+ export declare function pendingCadenceRequestLines(commitment: unknown): string[];
702
761
  export declare function cadenceLabel(commitment: CommitmentView): string;
703
762
  export declare function renderCommitmentList(commitments: CommitmentView[], log: (line: string) => void): void;
704
763
  /**
@@ -741,6 +800,31 @@ export declare function extractStandstillFromCheck(check?: {
741
800
  * null rather than printing a guess.
742
801
  */
743
802
  export declare function describeExecutorBlocked(commitment: CommitmentView): string | null;
803
+ /**
804
+ * The Operation line's wording for a Commitment that is not running because of its lifecycle.
805
+ *
806
+ * The assessment reports `waiting` with reason `lifecycle_<status>` for a Commitment a person
807
+ * paused, and `show` printed that verbatim ("waiting — lifecycle_paused"): the word "waiting" and a
808
+ * raw code, indistinguishable from one waiting on a machine or an approval (OSK-15423). Any other
809
+ * operation and reason is printed as it always was.
810
+ */
811
+ export declare function describeOperation(operation: string | null | undefined, reason: string | null | undefined): string;
812
+ /**
813
+ * What to do about an operation that is not running, from the operating state's
814
+ * first actionable blocker (`withLiveAssessment` carries it onto the view).
815
+ *
816
+ * `show` printed `Operation: blocked — typed_external_blocker` and nothing else,
817
+ * so the one line a reader acts on was a code; the remediation the server
818
+ * already composed sat only in `--json` and `doctor` (OSK-16212). Nothing is
819
+ * printed while the operation is ready or working, where a fix would contradict
820
+ * the line above it.
821
+ */
822
+ export declare function describeOperationFix(commitment: CommitmentView, operation: string | null | undefined): string | null;
823
+ /**
824
+ * Who stopped a Commitment, and when and why, in one line. The server stores it as `stoppedBy`;
825
+ * `show` printed neither (OSK-15423), so a Commitment you paused did not say you had.
826
+ */
827
+ export declare function describeStoppedBy(commitment: CommitmentView): string | null;
744
828
  /**
745
829
  * The commitment `show` should render: its stored contract, with the
746
830
  * assessment replaced by the one the operating state recomputed for this read
@@ -751,6 +835,8 @@ export declare function describeExecutorBlocked(commitment: CommitmentView): str
751
835
  */
752
836
  export declare function withLiveAssessment(commitment: CommitmentView, operatingState?: {
753
837
  assessment?: unknown;
838
+ executorBlocked?: unknown;
839
+ firstActionableBlocker?: unknown;
754
840
  } | null): CommitmentView;
755
841
  export declare function renderCommitmentSummary(commitment: CommitmentView, log: (line: string) => void,
756
842
  /**
@@ -765,7 +851,13 @@ latestCheck?: {
765
851
  decision?: {
766
852
  policyTrace?: Array<Record<string, unknown>>;
767
853
  } | null;
768
- } | null): void;
854
+ } | null,
855
+ /**
856
+ * Stored schedule settings the engine cannot honour (OSK-15452), printed directly under the
857
+ * cadence they affect rather than after the free-text summary at the bottom. Optional for the
858
+ * same reason as `latestCheck`: only `show` reads them from the server.
859
+ */
860
+ scheduleIssues?: CommitmentScheduleIssue[] | null): void;
769
861
  /**
770
862
  * Whether a check woke the agent, in plain words (OSK-4884).
771
863
  *
@@ -820,6 +912,14 @@ export declare function renderListPageHint(page: {
820
912
  * `other`. `--json` carries each artifact's `ref`, `locator` and `originalRef`.
821
913
  */
822
914
  export declare function describeObservationArtifacts(artifacts: unknown): string;
915
+ /**
916
+ * What the observations table's terse columns mean, for the rows actually on screen (OSK-15432).
917
+ *
918
+ * The table shortens VALUE to fit with `…`, so a reading cut by the screen looked the same as one
919
+ * the platform truncated; `undeclared` / `DECLARED no` and CLAMPED were defined nowhere. Only the
920
+ * terms present in THESE rows are explained, so an ordinary table adds nothing.
921
+ */
922
+ export declare function observationLegend(data: ReadModelRecord[]): string[];
823
923
  export declare function renderCommitmentObservations(response: ReadModelRecord, log: (line: string) => void, options?: {
824
924
  emptyMessage?: string;
825
925
  }): void;
@@ -2,11 +2,13 @@
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
4
  exports.permissionLines = permissionLines;
5
+ exports.scheduleIssueLines = scheduleIssueLines;
5
6
  exports.retiredFieldsLine = retiredFieldsLine;
6
7
  exports.readCommitmentAgentDirective = readCommitmentAgentDirective;
7
8
  exports.normalizeCreateBody = normalizeCreateBody;
8
9
  exports.parseCommitmentConcurrencyLimit = parseCommitmentConcurrencyLimit;
9
10
  exports.commitmentConcurrencyEnvelopePatch = commitmentConcurrencyEnvelopePatch;
11
+ exports.describeEvidenceGate = describeEvidenceGate;
10
12
  exports.describeCommitmentConcurrency = describeCommitmentConcurrency;
11
13
  exports.parseIntervalToMs = parseIntervalToMs;
12
14
  exports.normalizeWatchedSourceDeclarations = normalizeWatchedSourceDeclarations;
@@ -14,10 +16,14 @@ exports.buildWatchedSources = buildWatchedSources;
14
16
  exports.describeEvidenceHealth = describeEvidenceHealth;
15
17
  exports.describeIntervalMs = describeIntervalMs;
16
18
  exports.buildSuccessCriteria = buildSuccessCriteria;
19
+ exports.pendingCadenceRequestLines = pendingCadenceRequestLines;
17
20
  exports.cadenceLabel = cadenceLabel;
18
21
  exports.renderCommitmentList = renderCommitmentList;
19
22
  exports.extractStandstillFromCheck = extractStandstillFromCheck;
20
23
  exports.describeExecutorBlocked = describeExecutorBlocked;
24
+ exports.describeOperation = describeOperation;
25
+ exports.describeOperationFix = describeOperationFix;
26
+ exports.describeStoppedBy = describeStoppedBy;
21
27
  exports.withLiveAssessment = withLiveAssessment;
22
28
  exports.renderCommitmentSummary = renderCommitmentSummary;
23
29
  exports.describeWakeDecision = describeWakeDecision;
@@ -29,6 +35,7 @@ exports.formatCommitmentCycles = formatCommitmentCycles;
29
35
  exports.formatCommitmentExplanation = formatCommitmentExplanation;
30
36
  exports.renderListPageHint = renderListPageHint;
31
37
  exports.describeObservationArtifacts = describeObservationArtifacts;
38
+ exports.observationLegend = observationLegend;
32
39
  exports.renderCommitmentObservations = renderCommitmentObservations;
33
40
  exports.renderCommitmentHypotheses = renderCommitmentHypotheses;
34
41
  exports.renderCommitmentLineage = renderCommitmentLineage;
@@ -100,6 +107,21 @@ function permissionLines(permissions) {
100
107
  }
101
108
  return lines;
102
109
  }
110
+ /**
111
+ * The lines `show` prints for a stored schedule setting the engine cannot honour
112
+ * (OSK-15452): the cadence line above them reads as honoured while the daily times
113
+ * run on UTC. The sentence and the remedy are the server's; this only lays them out.
114
+ * An older server reports none, which prints nothing rather than a guess.
115
+ */
116
+ function scheduleIssueLines(issues) {
117
+ const lines = [];
118
+ for (const issue of issues ?? []) {
119
+ lines.push(`Warning: ${issue.message}`);
120
+ if (issue.fix)
121
+ lines.push(` Fix: ${issue.fix}`);
122
+ }
123
+ return lines;
124
+ }
103
125
  /**
104
126
  * One line naming fields that are still in the JSON but decide nothing any
105
127
  * more. Deprecation, not removal: `--json` keeps them for scripts.
@@ -449,6 +471,17 @@ function commitmentConcurrencyEnvelopePatch({ rawValue, reason, autonomous = pro
449
471
  ...(normalizedReason ? { maxConcurrentRunsReason: normalizedReason } : {}),
450
472
  };
451
473
  }
474
+ /**
475
+ * What `policy.evidenceGate.requireMaterialEvidenceForAutonomousRun` does to this Commitment's
476
+ * scheduled runs, in a line `show` can print (OSK-15417). It existed only in `show --json`: nothing
477
+ * in help, docs or any text view said whether a run on an unchanged day would be held back.
478
+ */
479
+ function describeEvidenceGate(commitment) {
480
+ const gate = commitment.policy?.evidenceGate;
481
+ return gate?.requireMaterialEvidenceForAutonomousRun === true
482
+ ? 'an autonomous run is held back unless the check found material evidence (a scheduled run on an unchanged day does not start)'
483
+ : 'off — an autonomous run is not held back for lack of material evidence';
484
+ }
452
485
  function describeCommitmentConcurrency(commitment) {
453
486
  const envelope = commitment.policy?.executionBudget;
454
487
  const limit = envelope?.maxConcurrentRuns;
@@ -657,6 +690,12 @@ function describeEvidenceHealth(health, criteriaCount) {
657
690
  if (state === 'degraded_observability') {
658
691
  return `degraded_observability${detail} — ${describeDegradedObservability(reasons)}`;
659
692
  }
693
+ if (state === 'awaiting_first_evidence') {
694
+ // Not stale and not degraded: nothing has been reported yet. The server
695
+ // only says this while the first run has neither reported nor finished;
696
+ // after that, seeing nothing is `degraded_observability` again (OSK-16211).
697
+ return `awaiting_first_evidence${detail} — no evidence yet: the first run is still collecting it`;
698
+ }
660
699
  return `${state}${detail}`;
661
700
  }
662
701
  /**
@@ -680,6 +719,9 @@ function describeDegradedObservability(reasons) {
680
719
  if (has('evidence_stale')) {
681
720
  return "the freshest evidence is older than this commitment's freshness expectation";
682
721
  }
722
+ if (has('evidence_awaiting_first_report')) {
723
+ return 'no evidence yet: the first run has not reported';
724
+ }
683
725
  return 'the last check could not see everything it needs to judge this commitment';
684
726
  }
685
727
  /** Render an interval back as a compact human string. */
@@ -745,6 +787,29 @@ function buildSuccessCriteria(labels, opts = {}) {
745
787
  ...(evaluator === 'source_state' && source ? { config: { source } } : {}),
746
788
  }));
747
789
  }
790
+ /**
791
+ * The cadence changes an Agent has proposed and nobody has decided. `cadence-requests decide` needs a request
792
+ * id, and `show` listed none, so a person could not find the id to pass (OSK-15422).
793
+ */
794
+ function pendingCadenceRequestLines(commitment) {
795
+ const state = commitment?.state;
796
+ const requests = Array.isArray(state?.pendingCadenceRequests) ? state.pendingCadenceRequests : [];
797
+ const pending = requests.filter((item) => !!item &&
798
+ typeof item === 'object' &&
799
+ item.kind === 'cadence_change' &&
800
+ item.status === 'pending');
801
+ if (!pending.length)
802
+ return [];
803
+ return [
804
+ 'Pending cadence requests (decide with `commitments cadence-requests decide <id> <request-id> --approve|--reject`):',
805
+ ...pending.map((item) => {
806
+ const from = item.basis?.intervalMs;
807
+ const to = item.requestedIntervalMs;
808
+ const reason = typeof item.reason === 'string' && item.reason ? ` — ${item.reason}` : '';
809
+ return ` ${String(item.id)} ${describeIntervalMs(from)} → ${describeIntervalMs(to)}${reason}`;
810
+ }),
811
+ ];
812
+ }
748
813
  function cadenceLabel(commitment) {
749
814
  const cadence = commitment.cadence;
750
815
  if (!cadence || !cadence.mode || cadence.mode === 'manual')
@@ -859,6 +924,71 @@ function describeExecutorBlocked(commitment) {
859
924
  : reason || 'blocked';
860
925
  return `${label}${until ? ` until ${until}` : ''}`;
861
926
  }
927
+ /**
928
+ * The Operation line's wording for a Commitment that is not running because of its lifecycle.
929
+ *
930
+ * The assessment reports `waiting` with reason `lifecycle_<status>` for a Commitment a person
931
+ * paused, and `show` printed that verbatim ("waiting — lifecycle_paused"): the word "waiting" and a
932
+ * raw code, indistinguishable from one waiting on a machine or an approval (OSK-15423). Any other
933
+ * operation and reason is printed as it always was.
934
+ */
935
+ function describeOperation(operation, reason) {
936
+ const lifecycle = typeof reason === 'string' ? /^lifecycle_([a-z_]+)$/.exec(reason) : null;
937
+ if (!lifecycle)
938
+ return `${operation ?? 'blocked'}${reason ? ` — ${reason}` : ''}`;
939
+ const status = lifecycle[1];
940
+ const meaning = {
941
+ paused: 'paused, it will not run until it is resumed',
942
+ draft: 'a draft, it will not run until it is activated',
943
+ archived: 'archived, it will not run',
944
+ completed: 'completed, it will not run',
945
+ cancelled: 'cancelled, it will not run',
946
+ };
947
+ return `not running — ${meaning[status] ?? status}`;
948
+ }
949
+ /**
950
+ * What to do about an operation that is not running, from the operating state's
951
+ * first actionable blocker (`withLiveAssessment` carries it onto the view).
952
+ *
953
+ * `show` printed `Operation: blocked — typed_external_blocker` and nothing else,
954
+ * so the one line a reader acts on was a code; the remediation the server
955
+ * already composed sat only in `--json` and `doctor` (OSK-16212). Nothing is
956
+ * printed while the operation is ready or working, where a fix would contradict
957
+ * the line above it.
958
+ */
959
+ function describeOperationFix(commitment, operation) {
960
+ if (operation === 'ready' || operation === 'working')
961
+ return null;
962
+ const blocker = commitment.firstActionableBlocker;
963
+ const remediation = blocker && typeof blocker.remediation === 'string' ? blocker.remediation.trim() : '';
964
+ if (!remediation)
965
+ return null;
966
+ const who = typeof blocker?.ownerLabel === 'string' && blocker.ownerLabel
967
+ ? blocker.ownerLabel
968
+ : typeof blocker?.owner === 'string' && blocker.owner
969
+ ? blocker.owner
970
+ : '';
971
+ return `${remediation}${who ? ` (${who})` : ''}`;
972
+ }
973
+ /**
974
+ * Who stopped a Commitment, and when and why, in one line. The server stores it as `stoppedBy`;
975
+ * `show` printed neither (OSK-15423), so a Commitment you paused did not say you had.
976
+ */
977
+ function describeStoppedBy(commitment) {
978
+ const stoppedBy = commitment.stoppedBy;
979
+ if (!stoppedBy || typeof stoppedBy !== 'object')
980
+ return null;
981
+ const who = stoppedBy.kind === 'user'
982
+ ? 'a person'
983
+ : stoppedBy.kind === 'agent'
984
+ ? 'the Agent'
985
+ : stoppedBy.kind
986
+ ? 'the platform'
987
+ : 'someone';
988
+ const status = stoppedBy.status || commitment.status || 'stopped';
989
+ return (`${status} by ${who}${stoppedBy.at ? ` on ${stoppedBy.at}` : ''}` +
990
+ `${stoppedBy.reason ? `: ${stoppedBy.reason}` : ''}`);
991
+ }
862
992
  /**
863
993
  * The commitment `show` should render: its stored contract, with the
864
994
  * assessment replaced by the one the operating state recomputed for this read
@@ -869,9 +999,30 @@ function describeExecutorBlocked(commitment) {
869
999
  */
870
1000
  function withLiveAssessment(commitment, operatingState) {
871
1001
  const live = operatingState?.assessment;
872
- if (!live || typeof live !== 'object')
873
- return commitment;
874
- return { ...commitment, assessment: live };
1002
+ // The remediation for a blocked operation lives on the operating state's
1003
+ // first actionable blocker; the header printed only the code (OSK-16212).
1004
+ const blocker = operatingState?.firstActionableBlocker &&
1005
+ typeof operatingState.firstActionableBlocker === 'object'
1006
+ ? { firstActionableBlocker: operatingState.firstActionableBlocker }
1007
+ : {};
1008
+ // The operating state also knows the executor's machine is stopped (`waiting_for_machine`),
1009
+ // which the stored contract never carries; `show` printed neither (OSK-15423).
1010
+ const executorBlocked = !commitment.executorBlocked &&
1011
+ operatingState?.executorBlocked &&
1012
+ typeof operatingState.executorBlocked === 'object'
1013
+ ? { executorBlocked: operatingState.executorBlocked }
1014
+ : {};
1015
+ if (!live || typeof live !== 'object') {
1016
+ return Object.keys(executorBlocked).length + Object.keys(blocker).length > 0
1017
+ ? { ...commitment, ...executorBlocked, ...blocker }
1018
+ : commitment;
1019
+ }
1020
+ return {
1021
+ ...commitment,
1022
+ ...executorBlocked,
1023
+ ...blocker,
1024
+ assessment: live,
1025
+ };
875
1026
  }
876
1027
  function renderCommitmentSummary(commitment, log,
877
1028
  /**
@@ -879,19 +1030,34 @@ function renderCommitmentSummary(commitment, log,
879
1030
  * complete / detach / reports render this same summary and hold only the
880
1031
  * contract — they should not be made to fetch a check to print one line.
881
1032
  */
882
- latestCheck) {
1033
+ latestCheck,
1034
+ /**
1035
+ * Stored schedule settings the engine cannot honour (OSK-15452), printed directly under the
1036
+ * cadence they affect rather than after the free-text summary at the bottom. Optional for the
1037
+ * same reason as `latestCheck`: only `show` reads them from the server.
1038
+ */
1039
+ scheduleIssues) {
883
1040
  log(`ID: ${commitment.id ?? '-'}`);
884
1041
  log(`Title: ${commitment.title ?? '-'}`);
885
1042
  log(`Kind: ${commitment.kind ?? 'achieve'}`);
886
1043
  log(`Status: ${commitment.status ?? '-'}`);
1044
+ const stopped = describeStoppedBy(commitment);
1045
+ if (commitment.status !== 'active' && stopped)
1046
+ log(`Stopped: ${stopped}`);
887
1047
  log(`Agent: ${commitment.agentId ?? '-'}`);
888
1048
  // A commitment whose executor cannot run anywhere should say so on the
889
1049
  // header, not as a silent skip series — "executor cannot run until <date> —
890
1050
  // reassign or add a fallback target" (design doc P4).
891
1051
  const executorBlocked = describeExecutorBlocked(commitment);
892
1052
  if (executorBlocked) {
893
- log(`Executor: blocked — ${executorBlocked}`);
894
- log(` Fix: reassign with \`skrr commitments handover ${commitment.id ?? '<id>'} --to <agent>\` or add a fallback target`);
1053
+ // A stopped machine is started for the work: that is waiting, not blocked, and reassigning the
1054
+ // Commitment is not its remedy (OSK-15423).
1055
+ const machineWait = commitment.executorBlocked?.reason ===
1056
+ 'waiting_for_machine';
1057
+ log(`Executor: ${machineWait ? 'waiting' : 'blocked'} — ${executorBlocked}`);
1058
+ if (!machineWait) {
1059
+ log(` Fix: reassign with \`skrr commitments handover ${commitment.id ?? '<id>'} --to <agent>\` or add a fallback target`);
1060
+ }
895
1061
  }
896
1062
  if (commitment.goalId)
897
1063
  log(`Goal: ${commitment.goalId}`);
@@ -902,8 +1068,11 @@ latestCheck) {
902
1068
  if (commitment.target?.deadlineAt)
903
1069
  log(`Deadline: ${commitment.target.deadlineAt}`);
904
1070
  log(`Cadence: ${cadenceLabel(commitment)}`);
1071
+ for (const line of scheduleIssueLines(scheduleIssues))
1072
+ log(line);
905
1073
  log(`Delivery: ${(0, commitment_product_1.deliveryLabel)(commitment.delivery?.mode)}${commitment.delivery?.repo ? ` · ${commitment.delivery.repo}` : ''}${commitment.delivery?.baseBranch ? ` → ${commitment.delivery.baseBranch}` : ''}`);
906
1074
  log(`Concurrency: ${describeCommitmentConcurrency(commitment)}`);
1075
+ log(`Evidence gate: ${describeEvidenceGate(commitment)}`);
907
1076
  const criteria = commitment.target?.successCriteria || [];
908
1077
  const evidenceHealth = latestCheck?.inputs?.evidenceHealth;
909
1078
  const evidenceLine = describeEvidenceHealth(evidenceHealth, criteria.length);
@@ -912,7 +1081,10 @@ latestCheck) {
912
1081
  : undefined;
913
1082
  log(`Assessment: ${assessment?.label ?? 'Unknown'}`);
914
1083
  log(`Evidence: ${assessment?.evidence ?? 'unavailable'}`);
915
- log(`Operation: ${assessment?.operation ?? 'blocked'}${assessment?.operationReason ? ` — ${assessment.operationReason}` : ''}`);
1084
+ log(`Operation: ${describeOperation(assessment?.operation, assessment?.operationReason)}`);
1085
+ const fix = describeOperationFix(commitment, assessment?.operation);
1086
+ if (fix)
1087
+ log(` Fix: ${fix}`);
916
1088
  if (commitment.state?.lastCheckedAt)
917
1089
  log(`Checked: ${commitment.state.lastCheckedAt}`);
918
1090
  if (typeof commitment.state?.consecutiveUnresolvedChecks === 'number') {
@@ -1553,6 +1725,32 @@ function describeObservationArtifacts(artifacts) {
1553
1725
  .map((name) => `${counts.get(name)} ${name}`)
1554
1726
  .join(', ');
1555
1727
  }
1728
+ /** The VALUE column's width in `renderCommitmentObservations`, which `observationLegend` checks against. */
1729
+ const OBSERVATION_VALUE_WIDTH = 38;
1730
+ /**
1731
+ * What the observations table's terse columns mean, for the rows actually on screen (OSK-15432).
1732
+ *
1733
+ * The table shortens VALUE to fit with `…`, so a reading cut by the screen looked the same as one
1734
+ * the platform truncated; `undeclared` / `DECLARED no` and CLAMPED were defined nowhere. Only the
1735
+ * terms present in THESE rows are explained, so an ordinary table adds nothing.
1736
+ */
1737
+ function observationLegend(data) {
1738
+ const lines = [];
1739
+ const shortened = data.some((item) => (0, format_1.formatCell)(firstValue(item, ['value', 'observedValue', 'latestValue'])).length >
1740
+ OBSERVATION_VALUE_WIDTH);
1741
+ if (shortened) {
1742
+ lines.push('VALUE is shortened to fit this table (…); the stored value is complete in --json.');
1743
+ }
1744
+ if (data.some((item) => item.declared === false)) {
1745
+ lines.push('DECLARED no / REASON undeclared: the key is not declared on this Commitment’s agent_run ' +
1746
+ 'source, so the reading is recorded but can never open a loop.');
1747
+ }
1748
+ if (data.some((item) => item.observedAtClamped === true)) {
1749
+ lines.push('CLAMPED yes: the observed time the run claimed was moved into the accepted window; ' +
1750
+ 'CLAIMED shows what it said.');
1751
+ }
1752
+ return lines;
1753
+ }
1556
1754
  function renderCommitmentObservations(response, log, options = {}) {
1557
1755
  const data = records(response.data);
1558
1756
  renderRows(data.map((item) => ({
@@ -1590,7 +1788,7 @@ function renderCommitmentObservations(response, log, options = {}) {
1590
1788
  { key: 'model', header: 'MODEL', maxWidth: 40 },
1591
1789
  { key: 'modelSource', header: 'MODEL SOURCE', maxWidth: 18 },
1592
1790
  { key: 'key', header: 'KEY', maxWidth: 30 },
1593
- { key: 'value', header: 'VALUE', maxWidth: 38 },
1791
+ { key: 'value', header: 'VALUE', maxWidth: OBSERVATION_VALUE_WIDTH },
1594
1792
  { key: 'changed', header: 'CHANGED', maxWidth: 8 },
1595
1793
  { key: 'reason', header: 'REASON', maxWidth: 20 },
1596
1794
  { key: 'reference', header: 'REFERENCE', maxWidth: 80 },
@@ -1599,6 +1797,8 @@ function renderCommitmentObservations(response, log, options = {}) {
1599
1797
  { key: 'confidence', header: 'CONF', maxWidth: 6 },
1600
1798
  { key: 'artifacts', header: 'ARTIFACTS', maxWidth: 36 },
1601
1799
  ], options.emptyMessage || 'No observations recorded.', log);
1800
+ for (const line of observationLegend(data))
1801
+ log(line);
1602
1802
  }
1603
1803
  /** Human view for causal hypotheses. */
1604
1804
  function renderCommitmentHypotheses(response, log, options = {}) {