@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
@@ -0,0 +1,52 @@
1
+ /**
2
+ * One reading of "an ISO-8601 UTC instant" for every CLI flag that takes one.
3
+ *
4
+ * `tasks remind --at` and `tasks schedule --at` each had their own: remind ran
5
+ * `new Date(value)` behind a `/^\d{4}-\d{2}-\d{2}T/` check, and schedule forwarded
6
+ * the string and printed the server's zod issue. `new Date()` is the wrong tool
7
+ * for an instant, in two ways that both stored a different time than the one
8
+ * typed and said nothing (OSK-21504, OSK-21506):
9
+ *
10
+ * - a time with no zone is read in the zone of the MACHINE running the CLI, so
11
+ * the same command stored different instants on different laptops;
12
+ * - a day that does not exist overflows into the next month
13
+ * (`2027-02-30` is `2027-03-02`).
14
+ *
15
+ * The rule here is the one `tasks schedule --help` already states and the server's
16
+ * `z.string().datetime()` enforces: a calendar-real date, a time with seconds, and
17
+ * a literal `Z`. A numeric offset is refused too, even though it names an instant:
18
+ * the two commands must agree, and the server's schedule door does not take one.
19
+ *
20
+ * Never reads the machine's zone. Pure.
21
+ */
22
+ export type InstantProblem = 'not_a_date' | 'date_only' | 'no_zone' | 'numeric_offset' | 'not_a_real_date' | 'not_a_real_time';
23
+ export type InstantParse = {
24
+ ok: true;
25
+ date: Date;
26
+ iso: string;
27
+ } | {
28
+ ok: false;
29
+ problem: InstantProblem;
30
+ message: string;
31
+ };
32
+ /**
33
+ * Parse a flag value as a UTC instant, or say precisely what is wrong with it.
34
+ *
35
+ * `label` is what the user typed (`--at`, `scheduledFor`), so the message names
36
+ * their input rather than a REST field they never saw.
37
+ */
38
+ export declare function parseUtcInstant(raw: string, label?: string): InstantParse;
39
+ /** `2027-02-02T09:00:00Z` - the instant in UTC, whole seconds when there are no milliseconds. */
40
+ export declare function formatUtcInstant(date: Date): string;
41
+ /**
42
+ * `2027-02-02 01:00:00 PST` - the same instant on this machine's wall clock, with the
43
+ * zone NAMED. `toLocaleString()` printed neither the zone nor anything that mapped back
44
+ * to the instant that was typed (OSK-21505). `timeZone` is for tests and defaults to
45
+ * the machine's own.
46
+ */
47
+ export declare function formatLocalInstant(date: Date, timeZone?: string): string;
48
+ /**
49
+ * The instant for a person: UTC first (it is what was typed and what is stored), then the
50
+ * local reading with its zone name. A machine already on UTC gets the UTC form alone.
51
+ */
52
+ export declare function describeInstant(date: Date, timeZone?: string): string;
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ /**
3
+ * One reading of "an ISO-8601 UTC instant" for every CLI flag that takes one.
4
+ *
5
+ * `tasks remind --at` and `tasks schedule --at` each had their own: remind ran
6
+ * `new Date(value)` behind a `/^\d{4}-\d{2}-\d{2}T/` check, and schedule forwarded
7
+ * the string and printed the server's zod issue. `new Date()` is the wrong tool
8
+ * for an instant, in two ways that both stored a different time than the one
9
+ * typed and said nothing (OSK-21504, OSK-21506):
10
+ *
11
+ * - a time with no zone is read in the zone of the MACHINE running the CLI, so
12
+ * the same command stored different instants on different laptops;
13
+ * - a day that does not exist overflows into the next month
14
+ * (`2027-02-30` is `2027-03-02`).
15
+ *
16
+ * The rule here is the one `tasks schedule --help` already states and the server's
17
+ * `z.string().datetime()` enforces: a calendar-real date, a time with seconds, and
18
+ * a literal `Z`. A numeric offset is refused too, even though it names an instant:
19
+ * the two commands must agree, and the server's schedule door does not take one.
20
+ *
21
+ * Never reads the machine's zone. Pure.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.parseUtcInstant = parseUtcInstant;
25
+ exports.formatUtcInstant = formatUtcInstant;
26
+ exports.formatLocalInstant = formatLocalInstant;
27
+ exports.describeInstant = describeInstant;
28
+ const EXAMPLE = '2026-12-01T09:00:00Z';
29
+ const UTC_INSTANT = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?Z$/;
30
+ const ZONELESS = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(\.\d+)?)?$/;
31
+ const OFFSET = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(\.\d+)?)?([+-])(\d{2}):?(\d{2})$/;
32
+ const DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
33
+ const MONTH_NAMES = [
34
+ 'January',
35
+ 'February',
36
+ 'March',
37
+ 'April',
38
+ 'May',
39
+ 'June',
40
+ 'July',
41
+ 'August',
42
+ 'September',
43
+ 'October',
44
+ 'November',
45
+ 'December',
46
+ ];
47
+ function daysInMonth(year, month) {
48
+ return new Date(Date.UTC(year, month, 0)).getUTCDate();
49
+ }
50
+ /**
51
+ * What is wrong with the calendar part, or `null` when the date exists.
52
+ * Checked by construction rather than by `new Date()`, which accepts the overflow.
53
+ */
54
+ function calendarProblem(year, month, day) {
55
+ if (month < 1 || month > 12)
56
+ return `month ${String(month).padStart(2, '0')} does not exist`;
57
+ const last = daysInMonth(year, month);
58
+ if (day < 1 || day > last) {
59
+ return `${MONTH_NAMES[month - 1]} ${year} has ${last} days, so day ${String(day).padStart(2, '0')} does not exist`;
60
+ }
61
+ return null;
62
+ }
63
+ function clockProblem(hour, minute, second) {
64
+ if (hour > 23 || minute > 59 || second > 59) {
65
+ return `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}:${String(second).padStart(2, '0')} is not a time of day`;
66
+ }
67
+ return null;
68
+ }
69
+ function rule(label) {
70
+ return `${label} must be an ISO-8601 UTC time ending in Z, for example ${EXAMPLE}`;
71
+ }
72
+ /**
73
+ * Parse a flag value as a UTC instant, or say precisely what is wrong with it.
74
+ *
75
+ * `label` is what the user typed (`--at`, `scheduledFor`), so the message names
76
+ * their input rather than a REST field they never saw.
77
+ */
78
+ function parseUtcInstant(raw, label = '--at') {
79
+ const value = String(raw ?? '').trim();
80
+ const fail = (problem, reason) => ({
81
+ ok: false,
82
+ problem,
83
+ message: `${rule(label)}. ${reason}`,
84
+ });
85
+ const utc = UTC_INSTANT.exec(value);
86
+ if (utc) {
87
+ const [year, month, day, hour, minute, second] = utc.slice(1, 7).map(Number);
88
+ const calendar = calendarProblem(year, month, day);
89
+ if (calendar)
90
+ return fail('not_a_real_date', `"${value}" is not a real date: ${calendar}.`);
91
+ const clock = clockProblem(hour, minute, second);
92
+ if (clock)
93
+ return fail('not_a_real_time', `"${value}" is not a real time: ${clock}.`);
94
+ const date = new Date(value);
95
+ if (Number.isNaN(date.getTime())) {
96
+ return fail('not_a_date', `"${value}" is not a date.`);
97
+ }
98
+ return { ok: true, date, iso: date.toISOString() };
99
+ }
100
+ const zoneless = ZONELESS.exec(value);
101
+ if (zoneless) {
102
+ return fail('no_zone', `"${value}" has no time zone, so it could mean a different moment on each machine. ` +
103
+ `Add Z if it is UTC, or convert it to UTC first.`);
104
+ }
105
+ const offset = OFFSET.exec(value);
106
+ if (offset) {
107
+ const [year, month, day, hour, minute] = offset.slice(1, 6).map(Number);
108
+ const second = Number(offset[6] ?? 0);
109
+ const sign = offset[8] === '-' ? -1 : 1;
110
+ const shiftMinutes = sign * (Number(offset[9]) * 60 + Number(offset[10]));
111
+ let converted = '';
112
+ if (!calendarProblem(year, month, day) && !clockProblem(hour, minute, second)) {
113
+ const at = new Date(Date.UTC(year, month - 1, day, hour, minute, second) - shiftMinutes * 60_000);
114
+ converted = ` (${value} is ${at.toISOString().replace(/\.000Z$/, 'Z')})`;
115
+ }
116
+ return fail('numeric_offset', `Numeric offsets such as ${offset[8]}${offset[9]}:${offset[10]} are not accepted; convert the time to UTC and end it with Z${converted}.`);
117
+ }
118
+ const dateOnly = DATE_ONLY.exec(value);
119
+ if (dateOnly) {
120
+ const calendar = calendarProblem(Number(dateOnly[1]), Number(dateOnly[2]), Number(dateOnly[3]));
121
+ return fail(calendar ? 'not_a_real_date' : 'date_only', calendar
122
+ ? `"${value}" is not a real date: ${calendar}.`
123
+ : `"${value}" is a date without a time; add a time of day, e.g. ${value}T09:00:00Z.`);
124
+ }
125
+ return fail('not_a_date', `"${value}" is not an ISO-8601 date and time.`);
126
+ }
127
+ /** `2027-02-02T09:00:00Z` - the instant in UTC, whole seconds when there are no milliseconds. */
128
+ function formatUtcInstant(date) {
129
+ return date.toISOString().replace(/\.000Z$/, 'Z');
130
+ }
131
+ /**
132
+ * `2027-02-02 01:00:00 PST` - the same instant on this machine's wall clock, with the
133
+ * zone NAMED. `toLocaleString()` printed neither the zone nor anything that mapped back
134
+ * to the instant that was typed (OSK-21505). `timeZone` is for tests and defaults to
135
+ * the machine's own.
136
+ */
137
+ function formatLocalInstant(date, timeZone) {
138
+ const parts = new Intl.DateTimeFormat('en-CA', {
139
+ ...(timeZone ? { timeZone } : {}),
140
+ year: 'numeric',
141
+ month: '2-digit',
142
+ day: '2-digit',
143
+ hour: '2-digit',
144
+ minute: '2-digit',
145
+ second: '2-digit',
146
+ hourCycle: 'h23',
147
+ timeZoneName: 'short',
148
+ }).formatToParts(date);
149
+ const get = (type) => parts.find((p) => p.type === type)?.value ?? '';
150
+ return `${get('year')}-${get('month')}-${get('day')} ${get('hour')}:${get('minute')}:${get('second')} ${get('timeZoneName')}`;
151
+ }
152
+ /**
153
+ * The instant for a person: UTC first (it is what was typed and what is stored), then the
154
+ * local reading with its zone name. A machine already on UTC gets the UTC form alone.
155
+ */
156
+ function describeInstant(date, timeZone) {
157
+ const utc = formatUtcInstant(date);
158
+ const local = formatLocalInstant(date, timeZone);
159
+ if (/ (UTC|GMT)$/.test(local))
160
+ return utc;
161
+ return `${utc} (${local})`;
162
+ }
@@ -1,4 +1,4 @@
1
- import type { DaemonContactState, DaemonMaintenanceSummary } from '@skrr-ai/data-provider';
1
+ import type { DaemonContactState, DaemonMaintenanceSummary, MachineIcon, MachineIconPatch } from '@skrr-ai/data-provider';
2
2
  /**
3
3
  * machines.ts — request client for `/api/machines`.
4
4
  *
@@ -134,6 +134,7 @@ export interface Machine {
134
134
  name?: string;
135
135
  description?: string;
136
136
  tags?: string[];
137
+ icon?: MachineIcon;
137
138
  };
138
139
  lease: Record<string, unknown> | null;
139
140
  controls: {
@@ -271,7 +272,19 @@ export interface MachinePreferencesPatch {
271
272
  name?: string;
272
273
  description?: string;
273
274
  tags?: string[];
275
+ /** A preset, or null for the default. An uploaded image is not set by a patch. */
276
+ icon?: MachineIconPatch;
274
277
  }
278
+ /**
279
+ * The value of `--icon`: a preset's id, or `none` (also `default`) to go back to
280
+ * the default. Throws a sentence that names the valid ids, because the only other
281
+ * way to learn them would be to send a wrong one and read the server's refusal.
282
+ * An uploaded image is a different flag (`--icon-file`): a name that is not a
283
+ * preset is never guessed to be a path.
284
+ */
285
+ export declare function parseMachineIconFlag(value: string): MachineIconPatch;
286
+ /** What `machines show`/`update` print for an icon: the preset's id, or what kind of image. */
287
+ export declare function describeMachineIcon(icon: MachineIcon | undefined): string;
275
288
  /**
276
289
  * How many of a machine's harnesses still represent a capability it has.
277
290
  *
@@ -10,6 +10,8 @@ exports.harnessStateLabel = harnessStateLabel;
10
10
  exports.summarizeDaemons = summarizeDaemons;
11
11
  exports.isThisComputer = isThisComputer;
12
12
  exports.machineListView = machineListView;
13
+ exports.parseMachineIconFlag = parseMachineIconFlag;
14
+ exports.describeMachineIcon = describeMachineIcon;
13
15
  exports.liveHarnessCount = liveHarnessCount;
14
16
  exports.listMachines = listMachines;
15
17
  exports.getMachine = getMachine;
@@ -229,6 +231,28 @@ function machineListView(machine, options) {
229
231
  ...(hidden > 0 ? { hiddenHarnessCount: hidden } : {}),
230
232
  };
231
233
  }
234
+ /**
235
+ * The value of `--icon`: a preset's id, or `none` (also `default`) to go back to
236
+ * the default. Throws a sentence that names the valid ids, because the only other
237
+ * way to learn them would be to send a wrong one and read the server's refusal.
238
+ * An uploaded image is a different flag (`--icon-file`): a name that is not a
239
+ * preset is never guessed to be a path.
240
+ */
241
+ function parseMachineIconFlag(value) {
242
+ const id = value.trim().toLowerCase();
243
+ if (id === 'none' || id === 'default')
244
+ return null;
245
+ if ((0, data_provider_1.isMachineIconPresetId)(id))
246
+ return { kind: 'preset', id };
247
+ throw new Error(`--icon: "${value}" is not an icon. Choose one of ${data_provider_1.MACHINE_ICON_PRESET_IDS.join(', ')}, ` +
248
+ 'or "none" to go back to the default. To use your own image, pass --icon-file <path>.');
249
+ }
250
+ /** What `machines show`/`update` print for an icon: the preset's id, or what kind of image. */
251
+ function describeMachineIcon(icon) {
252
+ if (!icon)
253
+ return 'default';
254
+ return icon.kind === 'preset' ? icon.id : 'uploaded image';
255
+ }
232
256
  /**
233
257
  * How many of a machine's harnesses still represent a capability it has.
234
258
  *
@@ -1,25 +1,3 @@
1
- /**
2
- * northstars.ts — request-based client for the Northstar portfolio layer
3
- * (`/api/northstars/*`) and its Portfolio Governor.
4
- *
5
- * A **Northstar** groups and prioritizes many Commitments without owning their
6
- * loop. The **Governor** is a MODE of its periodic review, not a separate
7
- * entity: a review rolls portfolio health up, allocates each Commitment a
8
- * cadence band and run budget, and emits TYPED management intents that a single
9
- * router turns into `CommitmentControl` mutations — advisory, awaiting a human,
10
- * or (narrowly) automatic.
11
- *
12
- * Two dials, deliberately separate:
13
- * - `analysisMode` — does an Agent get to think about this portfolio?
14
- * - `executionMode` — how much write authority does the outcome carry?
15
- *
16
- * Both default to the safe end (`deterministic` / `advisory`), which is exactly
17
- * what a Northstar did before the Governor existed.
18
- *
19
- * Every vocabulary below is RE-EXPORTED from `@skrr-ai/data-provider`, never
20
- * re-declared. The API validates against those exact strings; a second copy here
21
- * is how the CLI silently drifts from the server that rejects it.
22
- */
23
1
  import { NORTHSTAR_ANALYSIS_MODES, NORTHSTAR_APPROVAL_TRIGGERS, NORTHSTAR_EXECUTION_MODES, NORTHSTAR_INTENT_VERDICTS, NORTHSTAR_MANAGEMENT_INTENT_KINDS, NORTHSTAR_REVIEW_STATUSES } from '@skrr-ai/data-provider';
24
2
  import type { Northstar, NorthstarAnalysisMode, NorthstarExecutionMode, NorthstarGovernance, NorthstarGovernanceStatus, NorthstarGovernanceUpdateParams, NorthstarListResponse, NorthstarManagementIntent, NorthstarManagementIntentKind, NorthstarRecommendation, NorthstarReviewRecord, NorthstarStatusResponse } from '@skrr-ai/data-provider';
25
3
  import { withQuery } from './triggers';
@@ -33,6 +11,20 @@ export type { Northstar, NorthstarAnalysisMode, NorthstarExecutionMode, Northsta
33
11
  export declare const NORTHSTAR_STATUSES: readonly ["active", "paused", "achieved", "archived"];
34
12
  export declare const NORTHSTAR_PRIORITY_TIERS: readonly ["critical", "high", "medium", "low"];
35
13
  export declare const NORTHSTAR_RECOMMENDATION_STATUSES: readonly ["open", "applied", "dismissed"];
14
+ export declare function intentRisk(intent: {
15
+ riskLevel?: string | null;
16
+ } | null | undefined): string;
17
+ export declare function shortReviewId(id: string): string;
18
+ /**
19
+ * What a configure that changed the allocation inputs (the run budget, the critical reserve, the
20
+ * cadence band) says it did to the linked commitments. Additive on the server: absent from an
21
+ * older server, `allocationsPending` only when non-zero, `allocationsRefreshFailed` only on failure.
22
+ */
23
+ export type AllocationRefreshFields = {
24
+ allocationsRefreshed?: number;
25
+ allocationsPending?: number;
26
+ allocationsRefreshFailed?: boolean;
27
+ };
36
28
  export declare const northstarApi: {
37
29
  list: (query?: Parameters<typeof withQuery>[1]) => Promise<NorthstarListResponse>;
38
30
  create: (body: Record<string, unknown>) => Promise<Northstar>;
@@ -51,23 +43,208 @@ export declare const northstarApi: {
51
43
  northstarId: string;
52
44
  northstarVersion: number;
53
45
  governance: NorthstarGovernance;
54
- }>;
46
+ } & AllocationRefreshFields>;
55
47
  reviews: (id: string, query?: Parameters<typeof withQuery>[1]) => Promise<{
56
48
  data: NorthstarReviewRecord[];
49
+ has_more?: boolean;
57
50
  }>;
58
51
  review: (id: string, reviewId: string) => Promise<NorthstarReviewRecord>;
59
52
  reviewNow: (id: string) => Promise<Record<string, unknown>>;
60
53
  intents: (id: string, query?: Parameters<typeof withQuery>[1]) => Promise<{
61
54
  data: NorthstarManagementIntent[];
55
+ has_more?: boolean;
62
56
  }>;
63
57
  decideIntent: (id: string, intentId: string, body: Record<string, unknown>) => Promise<Record<string, unknown>>;
64
58
  };
59
+ /**
60
+ * One review, from the id a person typed. The full id is asked for first, exactly as before. Only when
61
+ * the server has no review of that exact id is the typed text read as the start of one, among the
62
+ * northstar's newest 100 reviews: that is what the REVIEW column of `intents list` prints
63
+ * (`shortReviewId`), so the table's own output can be pasted back. A prefix of several reviews is
64
+ * reported, not guessed; one of none, or of a review older than the newest 100, raises the server's
65
+ * original "not found". Both ids are in `--json`.
66
+ */
67
+ export declare function lookupReview(northstarId: string, typed: string): Promise<{
68
+ review: NorthstarReviewRecord;
69
+ } | {
70
+ ambiguous: string[];
71
+ }>;
65
72
  /** ms → a short human duration, for a table cell that must stay narrow. */
66
73
  export declare function humanMs(ms?: number): string;
67
74
  export declare function shortDate(value?: string): string;
75
+ export declare const NORTHSTAR_REASON_WORDS: Readonly<Record<string, string>>;
76
+ /** A code in words; an unknown code comes back unchanged, an absent one says so. */
77
+ export declare function describeNorthstarReason(code: string | null | undefined): string;
78
+ export type NorthstarDecisionContext = {
79
+ northstarId: string;
80
+ intentId: string;
81
+ decision: 'approve' | 'reject';
82
+ /** The CLI binary name, for the command a sentence tells the reader to run. */
83
+ bin?: string;
84
+ };
85
+ /**
86
+ * A refused decision, as one sentence with its next step.
87
+ *
88
+ * `body` is the server's refusal (`reason`, plus the context it adds: the two
89
+ * northstar versions, or when and by whom the intent was already decided).
90
+ */
91
+ export declare function describeDecisionRefusal(body: Record<string, unknown>, ctx: NorthstarDecisionContext): {
92
+ code: string;
93
+ text: string;
94
+ };
95
+ export type NorthstarDecisionOutcome = {
96
+ /** The arrow line (`nsi_x → applied`), printed before any explanation. */
97
+ headline: string;
98
+ /** 0 only when the thing asked for now holds. */
99
+ exitCode: 0 | 1;
100
+ /** What to say after the headline. */
101
+ text?: string;
102
+ /** The raw code behind a non-zero exit, for `--json` and `Code:`. */
103
+ code?: string;
104
+ };
105
+ /**
106
+ * What a decision that the server ACCEPTED (HTTP 200) actually did.
107
+ *
108
+ * One exit rule: an approval exits 0 only when the intent is `applied`, and a
109
+ * rejection only when it is `rejected`. An approval the version fence
110
+ * invalidated, or one whose change has not landed, used to print a line shaped
111
+ * like success and exit 0, so a script could not tell it from one that worked.
112
+ */
113
+ export declare function describeDecisionOutcome(result: Record<string, unknown>, ctx: NorthstarDecisionContext): NorthstarDecisionOutcome;
114
+ /** What the server returned before `--limit` existed; sent explicitly so a page is never silently smaller. */
115
+ export declare const NORTHSTAR_LIST_DEFAULT_LIMIT = 50;
116
+ /**
117
+ * The footer under a list that was cut short. `has_more: false` used to be
118
+ * unconditional on these lists, so a page of `--limit` rows read as the whole
119
+ * answer; the server now says when there is more and this says what to do.
120
+ * Empty when the page is complete.
121
+ *
122
+ * `cursor` is true only for a list that can be paged (`northstars list`); the
123
+ * reviews and intents lists have no cursor, so their way on is a larger
124
+ * `--limit`, or a narrower `--status` once `--limit` is at its ceiling.
125
+ */
126
+ export declare function listFooter(input: {
127
+ shown: number;
128
+ hasMore: boolean;
129
+ limit: number;
130
+ max: number;
131
+ nextCursor?: string | null;
132
+ cursor?: boolean;
133
+ }): string;
68
134
  export declare function renderNorthstarList(rows: Northstar[], log: (line: string) => void): void;
135
+ /**
136
+ * The active-commitment cap, in words. `0` is accepted and stored, and a review
137
+ * treats it as "no cap" (it does not flag every commitment over a cap of zero),
138
+ * so the screen says that rather than letting `0` read as a limit.
139
+ */
140
+ export declare function describeMaxActive(value: number | undefined): string;
69
141
  export declare function renderNorthstar(status: NorthstarStatusResponse, log: (line: string) => void): void;
70
142
  export declare function renderRecommendationList(rows: NorthstarRecommendation[], log: (line: string) => void): void;
143
+ /**
144
+ * No reviewer configured, a ready one, and an unreachable one are three
145
+ * different answers — and the third is the one an operator needs spelled out,
146
+ * because a scheduled review trigger says nothing about whether the agent that
147
+ * would run it is online.
148
+ */
149
+ export declare function reviewerReadiness(reviewer: NorthstarGovernanceStatus['reviewer']): string;
150
+ /** The `governance configure` flags that move what a commitment's allocation is computed from. */
151
+ export declare const ALLOCATION_INPUT_FLAGS: readonly ["max-runs-per-day", "clear-max-runs-per-day", "critical-reserve", "min-interval-hours", "max-interval-hours", "max-relative-change"];
152
+ export type AllocationRefresh = {
153
+ refreshed: number;
154
+ pending: number;
155
+ failed: boolean;
156
+ };
157
+ /** The refresh summary a configure response carries, or undefined from a server that sends none. */
158
+ export declare function readAllocationRefresh(response: AllocationRefreshFields | undefined): AllocationRefresh | undefined;
159
+ /**
160
+ * What `governance configure` says about the linked commitments. The server re-applies a changed
161
+ * budget or cadence band to every linked active commitment at once and answers how many it wrote,
162
+ * how many it could not, and whether the refresh itself failed; the command discarded all of it and
163
+ * re-read the status, so "nothing happened" and "applied to three" looked the same (OSK-21245).
164
+ *
165
+ * `inputsSent` is whether this call touched an allocation input: only then is "already up to date" a
166
+ * true statement, since a zero is also what an unrelated change (the analysis mode) answers.
167
+ */
168
+ export declare function describeAllocationRefresh(refresh: AllocationRefresh | undefined, options: {
169
+ northstarId: string;
170
+ inputsSent: boolean;
171
+ bin?: string;
172
+ }): {
173
+ lines: string[];
174
+ warnings: string[];
175
+ };
176
+ /**
177
+ * The `Allocations` line of `review-now`. The count is of commitments WRITTEN, so `0` does not say
178
+ * "nothing happened": it is what a review prints when a configure already applied the budget, or
179
+ * when no active commitment is linked, or when no review row could be opened to write under.
180
+ */
181
+ export declare function describeReviewAllocations(result: {
182
+ review?: unknown;
183
+ allocations?: unknown;
184
+ attention?: unknown;
185
+ }): string;
186
+ /**
187
+ * The sentence for a portfolio run budget smaller than the number of linked active commitments
188
+ * (OSK-21334): each still gets the floor of 1 run/day, so the ceilings add up to more than the
189
+ * budget. The server derives it once (`portfolioRunBudgetFloor.js`) and carries it, when it
190
+ * applies, on the `governance show` read, the `review-now` result and the effective policy's
191
+ * `portfolio`; every one of those three prints THIS sentence, so none composes its own and they
192
+ * cannot disagree. Absent from an older server, and from a budget that covers every commitment:
193
+ * no line, never a guess.
194
+ *
195
+ * Takes the carried field as it arrives (`unknown`), because two of the three callers read it off
196
+ * an untyped body.
197
+ */
198
+ export declare function runBudgetFloorNote(value: unknown): string | undefined;
199
+ /**
200
+ * What `critical_commitment` on the always-ask list does and does not do (OSK-21333).
201
+ *
202
+ * The list governs PROMOTION to critical (`critical_promotion`): remove the class and a bounded_auto
203
+ * review applies a small promotion itself. It does not govern the way back: a demotion away from
204
+ * critical is held for a person in `bounded_auto` whatever the list says (`critical_demotion`,
205
+ * `NorthstarGovernancePolicy.classifyIntent`: the demotion rule never reads the list). The behaviour
206
+ * is pinned by `NorthstarGovernancePolicy.spec.js` ("critical_commitment off the approval list"),
207
+ * the words by `cli/src/commands/northstars/__tests__/critical-approval-help.spec.ts`. The flag help
208
+ * and the `Approval for` line of `governance show` both read this one sentence, so neither can
209
+ * drift from the other.
210
+ */
211
+ export declare const CRITICAL_COMMITMENT_APPROVAL_NOTE = "critical_commitment governs promotion to critical only; demotion away from critical (critical_demotion) is always held for a person, whatever this list says";
71
212
  export declare function renderGovernance(status: NorthstarGovernanceStatus, log: (line: string) => void): void;
213
+ /**
214
+ * The automatic-change budget line.
215
+ *
216
+ * `0/day` is a MODE (automatic changes off, everything waits for approval), and `used` can
217
+ * legitimately exceed any cap, because the changes were made before the owner lowered it. A bare
218
+ * `2/0 used today · 0 left` collapses both into a ratio over 100% that says neither (OSK-21233).
219
+ */
220
+ export declare function describeAutoBudget(budget: NorthstarGovernanceStatus['mutationBudget']): string;
221
+ /** One cell of words for what a review did beyond "it ran"; empty when there is nothing to add. */
222
+ export declare function reviewNote(review: NorthstarReviewRecord): string;
223
+ /** `Reason` line of one review: the words, with the raw code kept beside them for grep. */
224
+ export declare function describeReviewReason(reason: string): string;
72
225
  export declare function renderReviewList(reviews: NorthstarReviewRecord[], log: (line: string) => void): void;
73
- export declare function renderIntentList(intents: NorthstarManagementIntent[], log: (line: string) => void): void;
226
+ /** `--wide` on every command that prints the intents table. */
227
+ export declare const northstarWideFlag: import("@oclif/core/interfaces").BooleanFlag<boolean>;
228
+ export type IntentTableOptions = {
229
+ /** Never clip the reason, and keep the machine code beside it as `[code]`. */
230
+ wide?: boolean;
231
+ /** Terminal width to fit the table to; defaults to the real terminal, else 250. */
232
+ columns?: number;
233
+ };
234
+ /**
235
+ * The intents table.
236
+ *
237
+ * WHY is the HUMAN reason the governor wrote (`reason`), not the machine code in
238
+ * `verdictReason`, which says why an intent needed approval (`execution_mode_approval`)
239
+ * and is no reason for the change itself. The code stays in `--json`, and beside
240
+ * the sentence as `[code]` under `--wide`. By default the sentence is cut at a
241
+ * word boundary to what the terminal leaves after the other columns.
242
+ */
243
+ export declare function renderIntentList(intents: NorthstarManagementIntent[], log: (line: string) => void, options?: IntentTableOptions): void;
244
+ /**
245
+ * The line that says a review's intent budget cut something off. A cap of 0
246
+ * records nothing at all, which a screen reading "No management intents." made
247
+ * indistinguishable from a review with nothing to say; the count was only in
248
+ * `--json` (`deterministicSnapshot.truncatedIntents`).
249
+ */
250
+ export declare function intentBudgetNote(truncated: unknown, cap?: unknown): string;