@skrr-ai/cli 0.1.126 → 0.1.128
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base-command.d.ts +23 -0
- package/dist/base-command.js +72 -0
- package/dist/commands/agents/chat.js +7 -0
- package/dist/commands/agents/goals/list.d.ts +2 -2
- package/dist/commands/agents/goals/list.js +2 -2
- package/dist/commands/commitments/action-history.js +1 -1
- package/dist/commands/commitments/cases.js +3 -3
- package/dist/commands/commitments/check-now.d.ts +10 -2
- package/dist/commands/commitments/check-now.js +53 -3
- package/dist/commands/commitments/create.d.ts +6 -14
- package/dist/commands/commitments/create.js +61 -6
- package/dist/commands/commitments/doctor.js +3 -1
- package/dist/commands/commitments/effective-policy.d.ts +11 -1
- package/dist/commands/commitments/effective-policy.js +84 -4
- package/dist/commands/commitments/hypotheses.js +12 -12
- package/dist/commands/commitments/next-tick.js +5 -0
- package/dist/commands/commitments/observations.js +18 -17
- package/dist/commands/commitments/pack/list.js +2 -1
- package/dist/commands/commitments/pack/plan.d.ts +6 -0
- package/dist/commands/commitments/pack/plan.js +19 -0
- package/dist/commands/commitments/preflight.d.ts +19 -0
- package/dist/commands/commitments/preflight.js +108 -10
- package/dist/commands/commitments/trigger-status.js +8 -0
- package/dist/commands/commitments/update.d.ts +1 -0
- package/dist/commands/commitments/update.js +45 -4
- package/dist/commands/commitments/wake-capabilities.js +13 -0
- package/dist/commands/compass/archive.js +4 -0
- package/dist/commands/compass/commitments.js +15 -1
- package/dist/commands/compass/create.js +11 -3
- package/dist/commands/compass/effective-policy.d.ts +1 -0
- package/dist/commands/compass/effective-policy.js +8 -7
- package/dist/commands/compass/revert.d.ts +8 -0
- package/dist/commands/compass/revert.js +25 -1
- package/dist/commands/compass/revisions.d.ts +2 -0
- package/dist/commands/compass/revisions.js +18 -2
- package/dist/commands/compass/tactic.d.ts +5 -3
- package/dist/commands/compass/tactic.js +8 -7
- package/dist/commands/compass/update.js +19 -3
- package/dist/commands/followups/act.js +1 -1
- package/dist/commands/followups/cancel.js +13 -0
- package/dist/commands/followups/observability.js +20 -1
- package/dist/commands/followups/plans/create.js +12 -1
- package/dist/commands/followups/show.js +13 -0
- package/dist/commands/followups/watch.js +1 -1
- package/dist/commands/goals/create.d.ts +1 -0
- package/dist/commands/goals/create.js +4 -1
- package/dist/commands/goals/planner-config.d.ts +11 -0
- package/dist/commands/goals/planner-config.js +16 -0
- package/dist/commands/goals/revisions.js +3 -19
- package/dist/commands/machines/update.d.ts +5 -3
- package/dist/commands/machines/update.js +70 -9
- package/dist/commands/northstars/create.js +3 -1
- package/dist/commands/northstars/governance/configure.d.ts +4 -0
- package/dist/commands/northstars/governance/configure.js +75 -9
- package/dist/commands/northstars/intents/decide.d.ts +6 -0
- package/dist/commands/northstars/intents/decide.js +69 -15
- package/dist/commands/northstars/intents/list.d.ts +2 -1
- package/dist/commands/northstars/intents/list.js +15 -5
- package/dist/commands/northstars/intents.d.ts +26 -0
- package/dist/commands/northstars/intents.js +49 -0
- package/dist/commands/northstars/list.d.ts +1 -0
- package/dist/commands/northstars/list.js +24 -3
- package/dist/commands/northstars/recommendations/list.d.ts +1 -1
- package/dist/commands/northstars/recommendations/list.js +3 -3
- package/dist/commands/northstars/recommendations.d.ts +19 -0
- package/dist/commands/northstars/recommendations.js +42 -0
- package/dist/commands/northstars/review-now.d.ts +1 -0
- package/dist/commands/northstars/review-now.js +10 -4
- package/dist/commands/northstars/reviews.d.ts +1 -0
- package/dist/commands/northstars/reviews.js +19 -3
- package/dist/commands/northstars/update.js +8 -1
- package/dist/commands/proposals/list.js +11 -2
- package/dist/commands/proposals/show.js +9 -1
- package/dist/commands/spaces/auto-executor/preview.d.ts +14 -1
- package/dist/commands/spaces/auto-executor/preview.js +35 -1
- package/dist/commands/spaces/auto-executor/run.d.ts +17 -0
- package/dist/commands/spaces/auto-executor/run.js +60 -2
- package/dist/commands/spaces/files/upload.js +1 -2
- package/dist/commands/spaces/index.js +23 -0
- package/dist/commands/spaces/revisions.js +3 -2
- package/dist/commands/tasks/revisions.js +3 -2
- package/dist/commands/triggers/fire-detail.js +2 -0
- package/dist/generated/agent-guides.json +69 -69
- package/dist/lib/agentic-stream.d.ts +9 -0
- package/dist/lib/agentic-stream.js +14 -0
- package/dist/lib/command-miss.js +11 -2
- package/dist/lib/commitment-attention-copy.d.ts +96 -0
- package/dist/lib/commitment-attention-copy.js +209 -0
- package/dist/lib/commitment-loop-status.d.ts +6 -0
- package/dist/lib/commitment-loop-status.js +16 -6
- package/dist/lib/commitments.d.ts +88 -0
- package/dist/lib/commitments.js +188 -0
- package/dist/lib/compass-body-help.d.ts +20 -0
- package/dist/lib/compass-body-help.js +61 -0
- package/dist/lib/compass-refusals.d.ts +35 -0
- package/dist/lib/compass-refusals.js +50 -0
- package/dist/lib/compasses.d.ts +80 -4
- package/dist/lib/compasses.js +232 -12
- package/dist/lib/followups.d.ts +22 -1
- package/dist/lib/followups.js +21 -1
- package/dist/lib/format.d.ts +11 -0
- package/dist/lib/format.js +29 -0
- package/dist/lib/initiatives.d.ts +9 -2
- package/dist/lib/initiatives.js +13 -2
- package/dist/lib/machines.d.ts +14 -1
- package/dist/lib/machines.js +24 -0
- package/dist/lib/northstars.d.ts +158 -24
- package/dist/lib/northstars.js +538 -26
- package/dist/lib/proposal-decision-command.js +21 -1
- package/dist/lib/proposals.d.ts +26 -1
- package/dist/lib/proposals.js +163 -0
- package/dist/lib/rate-limit-retry.d.ts +5 -0
- package/dist/lib/rate-limit-retry.js +19 -0
- package/dist/lib/revision-actor.d.ts +2 -0
- package/dist/lib/revision-actor.js +16 -0
- package/dist/lib/roles.d.ts +1 -1
- package/dist/lib/space-charter.js +9 -0
- package/dist/lib/task-asset-upload.js +1 -2
- package/dist/lib/triggers.d.ts +33 -1
- package/dist/lib/triggers.js +77 -3
- package/dist/node_modules/@skrr-ai/data-provider/index.js +7537 -7474
- package/oclif.manifest.json +357 -34
- package/package.json +4 -4
package/dist/lib/compasses.js
CHANGED
|
@@ -2,9 +2,17 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.compassApi = exports.COMPASS_STATUSES = void 0;
|
|
4
4
|
exports.renderCompassList = renderCompassList;
|
|
5
|
+
exports.describeSettings = describeSettings;
|
|
6
|
+
exports.describeQuietHours = describeQuietHours;
|
|
7
|
+
exports.describeMode = describeMode;
|
|
5
8
|
exports.renderCompass = renderCompass;
|
|
9
|
+
exports.describeBoundCommitments = describeBoundCommitments;
|
|
10
|
+
exports.renderTacticResult = renderTacticResult;
|
|
11
|
+
exports.renderEffectivePolicy = renderEffectivePolicy;
|
|
6
12
|
exports.renderRevisionList = renderRevisionList;
|
|
7
13
|
exports.renderCompassTrace = renderCompassTrace;
|
|
14
|
+
exports.revisionTypeLabel = revisionTypeLabel;
|
|
15
|
+
exports.renderRevertResult = renderRevertResult;
|
|
8
16
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
9
17
|
/**
|
|
10
18
|
* compasses.ts — request-based client for `/api/compasses`.
|
|
@@ -79,6 +87,76 @@ function renderCompassList(rows, log) {
|
|
|
79
87
|
{ key: 'updated', header: 'UPDATED' },
|
|
80
88
|
], log);
|
|
81
89
|
}
|
|
90
|
+
function scalar(value) {
|
|
91
|
+
if (value === null || value === undefined)
|
|
92
|
+
return 'none';
|
|
93
|
+
return typeof value === 'object' ? JSON.stringify(value) : String(value);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* One setting per line (`key: value`, nested objects as dotted keys, lists joined with `;`), so a
|
|
97
|
+
* settings object reads as labelled lines rather than one JSON blob (OSK-21150).
|
|
98
|
+
*/
|
|
99
|
+
function describeSettings(value, prefix = '') {
|
|
100
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
101
|
+
return [];
|
|
102
|
+
const lines = [];
|
|
103
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
104
|
+
if (entry && typeof entry === 'object' && !Array.isArray(entry)) {
|
|
105
|
+
lines.push(...describeSettings(entry, `${prefix}${key}.`));
|
|
106
|
+
}
|
|
107
|
+
else if (Array.isArray(entry)) {
|
|
108
|
+
lines.push(`${prefix}${key}: ${entry.map(scalar).join('; ') || 'none'}`);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
lines.push(`${prefix}${key}: ${scalar(entry)}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return lines;
|
|
115
|
+
}
|
|
116
|
+
/** A quiet-hours window in words: the hours and the zone, `off`, or `not set`. */
|
|
117
|
+
function describeQuietHours(window) {
|
|
118
|
+
if (!window || typeof window !== 'object' || Array.isArray(window))
|
|
119
|
+
return 'not set';
|
|
120
|
+
const w = window;
|
|
121
|
+
if (w.enabled !== true)
|
|
122
|
+
return 'off';
|
|
123
|
+
const zone = typeof w.timezone === 'string' && w.timezone.trim() ? w.timezone.trim() : 'UTC (no zone set)';
|
|
124
|
+
return `${scalar(w.start ?? '?')} to ${scalar(w.end ?? '?')} ${zone}`;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The mode, and the word the author wrote when it differs from it. The server stores `auto` as
|
|
128
|
+
* `auto_run_limited`; saying so beats showing a value nobody typed as if they had (OSK-21150).
|
|
129
|
+
*/
|
|
130
|
+
function describeMode(mode, authoredMode) {
|
|
131
|
+
const normalized = typeof mode === 'string' && mode ? mode : null;
|
|
132
|
+
const authored = typeof authoredMode === 'string' && authoredMode ? authoredMode : null;
|
|
133
|
+
if (!normalized) {
|
|
134
|
+
return authored
|
|
135
|
+
? `not set (${JSON.stringify(authored)} is not a mode the platform knows)`
|
|
136
|
+
: 'not set (the platform default applies)';
|
|
137
|
+
}
|
|
138
|
+
return authored && authored !== normalized
|
|
139
|
+
? `${normalized} (normalized; you wrote ${JSON.stringify(authored)})`
|
|
140
|
+
: normalized;
|
|
141
|
+
}
|
|
142
|
+
const SOURCE_WORDS = {
|
|
143
|
+
authored: 'the author',
|
|
144
|
+
derived: 'nobody (a default the platform derived)',
|
|
145
|
+
};
|
|
146
|
+
function labelled(label, lines, log, width = 12) {
|
|
147
|
+
lines.forEach((line, index) => log(`${index === 0 ? label.padEnd(width) : ' '.repeat(width)}${line}`));
|
|
148
|
+
}
|
|
149
|
+
/** The stored autonomy defaults, as the lines `show` prints (no JSON). */
|
|
150
|
+
function autonomyLines(autonomy) {
|
|
151
|
+
const { mode, authoredMode, modeSource, quietHours, ...rest } = autonomy;
|
|
152
|
+
const source = typeof modeSource === 'string' ? (SOURCE_WORDS[modeSource] ?? modeSource) : undefined;
|
|
153
|
+
const out = [];
|
|
154
|
+
const modeLine = `${describeMode(mode, authoredMode)}${source ? `; set by ${source}` : ''}`;
|
|
155
|
+
out.push(['Autonomy', [modeLine, ...describeSettings(rest)]]);
|
|
156
|
+
if (quietHours !== undefined)
|
|
157
|
+
out.push(['Quiet hours', [describeQuietHours(quietHours)]]);
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
82
160
|
function renderCompass(compass, log) {
|
|
83
161
|
log(`${compass.title ?? '(untitled compass)'} (${compass.id})`);
|
|
84
162
|
log(`Agent ${compass.agentId}`);
|
|
@@ -86,12 +164,13 @@ function renderCompass(compass, log) {
|
|
|
86
164
|
if (compass.domain)
|
|
87
165
|
log(`Domain ${compass.domain}`);
|
|
88
166
|
if (compass.scope)
|
|
89
|
-
|
|
167
|
+
labelled('Scope', describeSettings(compass.scope), log);
|
|
90
168
|
if (compass.autonomyDefaults) {
|
|
91
|
-
|
|
169
|
+
for (const [label, lines] of autonomyLines(compass.autonomyDefaults))
|
|
170
|
+
labelled(label, lines, log);
|
|
92
171
|
}
|
|
93
172
|
if (compass.communicationDefaults) {
|
|
94
|
-
|
|
173
|
+
labelled('Comms', describeSettings(compass.communicationDefaults), log);
|
|
95
174
|
}
|
|
96
175
|
const rules = compass.rules ?? [];
|
|
97
176
|
if (rules.length) {
|
|
@@ -126,6 +205,13 @@ function renderCompass(compass, log) {
|
|
|
126
205
|
if (target.successMetrics?.length) {
|
|
127
206
|
log(` measured by: ${target.successMetrics.join('; ')}`);
|
|
128
207
|
}
|
|
208
|
+
// Tactics live on a target, not on the compass; they used to be printed nowhere.
|
|
209
|
+
if (target.learnedTactics?.length) {
|
|
210
|
+
log(` learned tactics (${target.learnedTactics.length}):`);
|
|
211
|
+
for (const tactic of target.learnedTactics) {
|
|
212
|
+
log(` • ${tactic.id ?? '—'}: ${tactic.description ?? '—'}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
129
215
|
// The agent's prompt carries a bounded number of each list. Say which
|
|
130
216
|
// were cut, so the list above is not read as what the agent sees.
|
|
131
217
|
for (const overflow of (0, data_provider_1.describeCompassOverflow)(target)) {
|
|
@@ -133,17 +219,103 @@ function renderCompass(compass, log) {
|
|
|
133
219
|
}
|
|
134
220
|
}
|
|
135
221
|
}
|
|
136
|
-
const tactics = compass.learnedTactics ?? [];
|
|
137
|
-
if (tactics.length) {
|
|
138
|
-
log('');
|
|
139
|
-
log(`Learned tactics (${tactics.length}):`);
|
|
140
|
-
for (const tactic of tactics)
|
|
141
|
-
log(` • ${tactic.description ?? '—'}`);
|
|
142
|
-
}
|
|
143
222
|
const commitments = compass.commitments ?? [];
|
|
144
223
|
if (commitments.length) {
|
|
145
224
|
log('');
|
|
146
|
-
log(
|
|
225
|
+
log(describeBoundCommitments(commitments.length, compass.status));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* How many Commitments are bound to a Compass, and whether it governs them. A Commitment stays
|
|
230
|
+
* bound to an archived Compass but runs on defaults: the platform reads only an ACTIVE Compass's
|
|
231
|
+
* direction. "Governed by this compass: 1" printed the same words for both, on the Compass side,
|
|
232
|
+
* while the Commitment's own preflight said it was running on defaults (OSK-21242).
|
|
233
|
+
*/
|
|
234
|
+
function describeBoundCommitments(count, status) {
|
|
235
|
+
return status === 'archived'
|
|
236
|
+
? `Commitments bound to this compass: ${count} (not governed while the compass is archived)`
|
|
237
|
+
: `Commitments governed by this compass: ${count}`;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* What `compass tactic` says back. Three outcomes, each in its own words: it used to print
|
|
241
|
+
* "Appended" for all of them, with a count that was always 0, and name nothing that rolled off.
|
|
242
|
+
* A server that does not report `tactic` is not guessed at.
|
|
243
|
+
*/
|
|
244
|
+
function renderTacticResult(compass, log) {
|
|
245
|
+
const tactic = compass.tactic;
|
|
246
|
+
if (!tactic) {
|
|
247
|
+
log(`Recorded. ${compass.id} is now v${compass.version}. This server did not report what changed; ` +
|
|
248
|
+
'run `compass show` to see the learned tactics.');
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const where = tactic.targetInvariantId ? `invariant ${tactic.targetInvariantId}` : 'its target';
|
|
252
|
+
const carries = `${compass.id} now carries ${tactic.count} learned tactic(s) on ${where}`;
|
|
253
|
+
if (tactic.outcome === 'unchanged') {
|
|
254
|
+
log(`No change — tactic already recorded. ${tactic.id} already reads that way on ${where}; ` +
|
|
255
|
+
`${compass.id} stays at v${compass.version}.`);
|
|
256
|
+
}
|
|
257
|
+
else if (tactic.outcome === 'updated') {
|
|
258
|
+
log(`Updated. ${tactic.id} on ${where} has the new text. ${carries} (v${compass.version}).`);
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
log(`Appended. ${tactic.id} filed under ${where}. ${carries} (v${compass.version}).`);
|
|
262
|
+
}
|
|
263
|
+
for (const dropped of tactic.dropped ?? []) {
|
|
264
|
+
log(`Rolled off to stay within the cap: ${dropped.id} — "${dropped.description}"`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const record = (value) => value && typeof value === 'object' && !Array.isArray(value)
|
|
268
|
+
? value
|
|
269
|
+
: {};
|
|
270
|
+
/**
|
|
271
|
+
* `compass effective-policy` in words (OSK-21150): the mode beside what was written when they
|
|
272
|
+
* differ, who chose it, the quiet hours that apply (or why none do), the communication defaults, and
|
|
273
|
+
* where each field came from. It used to print each of those as one JSON line, with a null mode and
|
|
274
|
+
* "derived" unexplained. `--json` is unchanged.
|
|
275
|
+
*/
|
|
276
|
+
function renderEffectivePolicy(policy, log) {
|
|
277
|
+
log(`Compass ${scalar(policy.compassId)}, revision ${scalar(policy.compassVersion)}: ${scalar(policy.status)}`);
|
|
278
|
+
log(`Applies to runtime: ${policy.appliesToRuntime === true ? 'yes' : 'no'}`);
|
|
279
|
+
const autonomy = record(policy.autonomy);
|
|
280
|
+
log('Autonomy');
|
|
281
|
+
const source = typeof autonomy.modeSource === 'string' ? autonomy.modeSource : undefined;
|
|
282
|
+
labelled(' Mode', [describeMode(autonomy.mode, autonomy.authoredMode)], log, 16);
|
|
283
|
+
if (source)
|
|
284
|
+
labelled(' Mode set by', [SOURCE_WORDS[source] ?? source], log, 16);
|
|
285
|
+
const applied = autonomy.quietHours;
|
|
286
|
+
const configured = autonomy.configuredQuietHours;
|
|
287
|
+
const issues = Array.isArray(autonomy.quietHoursIssues) ? autonomy.quietHoursIssues : [];
|
|
288
|
+
labelled(' Quiet hours', [
|
|
289
|
+
applied
|
|
290
|
+
? describeQuietHours(applied)
|
|
291
|
+
: configured
|
|
292
|
+
? `not applied (stored: ${describeQuietHours(configured)})`
|
|
293
|
+
: 'not set',
|
|
294
|
+
], log, 16);
|
|
295
|
+
for (const issue of issues) {
|
|
296
|
+
const message = record(issue).message;
|
|
297
|
+
if (typeof message === 'string')
|
|
298
|
+
log(` ! ${message} Quiet hours do not apply until this is fixed.`);
|
|
299
|
+
}
|
|
300
|
+
const communication = describeSettings(policy.communication);
|
|
301
|
+
log('Communication');
|
|
302
|
+
if (communication.length === 0)
|
|
303
|
+
log(' nothing set');
|
|
304
|
+
for (const line of communication)
|
|
305
|
+
log(` ${line}`);
|
|
306
|
+
log(`Authority: ${scalar(policy.authority ?? 'unknown')}`);
|
|
307
|
+
const bySource = new Map();
|
|
308
|
+
for (const [path, entry] of Object.entries(record(policy.fieldProvenance))) {
|
|
309
|
+
const from = scalar(record(entry).source ?? 'unknown');
|
|
310
|
+
bySource.set(from, [...(bySource.get(from) ?? []), path]);
|
|
311
|
+
}
|
|
312
|
+
if (bySource.size === 0) {
|
|
313
|
+
log('Field provenance: none (no defaults are set)');
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
log('Field provenance:');
|
|
317
|
+
for (const [from, paths] of bySource)
|
|
318
|
+
log(` ${from}: ${paths.join(', ')}`);
|
|
147
319
|
}
|
|
148
320
|
}
|
|
149
321
|
function renderRevisionList(rows, log) {
|
|
@@ -153,7 +325,7 @@ function renderRevisionList(rows, log) {
|
|
|
153
325
|
}
|
|
154
326
|
(0, format_1.renderTable)(rows.map((row) => ({
|
|
155
327
|
revision: `v${row.revision}`,
|
|
156
|
-
type: row
|
|
328
|
+
type: revisionTypeLabel(row),
|
|
157
329
|
when: shortDate(row.createdAt),
|
|
158
330
|
actor: row.actorUserId ?? '—',
|
|
159
331
|
reason: row.reason ?? '—',
|
|
@@ -194,3 +366,51 @@ function renderCompassTrace(trace, log) {
|
|
|
194
366
|
if (trace.has_more)
|
|
195
367
|
log('More events exist; request a larger --limit (up to 500).');
|
|
196
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* The ledger's name for a row. A revert is stored as `auto_revert`, which reads as something the
|
|
371
|
+
* platform did on its own, so a person's `compass revert` is shown as `revert`, with the versions
|
|
372
|
+
* it moved between: `from v6 → v2` is the version it was at and the version whose content it took.
|
|
373
|
+
* Display only: the stored enum is unchanged.
|
|
374
|
+
*/
|
|
375
|
+
function revisionTypeLabel(row) {
|
|
376
|
+
// Reviving an archived compass has no ledger type of its own (the stored enum has no member for it),
|
|
377
|
+
// so it was recorded and shown as a plain `update`, indistinguishable from an edit. Each revision
|
|
378
|
+
// carries the status before and after (`status` is one of the captured config fields), so the
|
|
379
|
+
// lifecycle act is read from that; display only, the stored type is unchanged (OSK-21244).
|
|
380
|
+
if (row.revisionType === 'update' &&
|
|
381
|
+
row.previousConfig?.status === 'archived' &&
|
|
382
|
+
row.nextConfig?.status === 'active') {
|
|
383
|
+
return 'reactivate';
|
|
384
|
+
}
|
|
385
|
+
if (row.revisionType !== 'auto_revert')
|
|
386
|
+
return row.revisionType ?? '—';
|
|
387
|
+
const { fromVersion, toVersion } = row.metadata?.autoRevert ?? {};
|
|
388
|
+
return fromVersion !== undefined && toVersion !== undefined
|
|
389
|
+
? `revert from v${fromVersion} → v${toVersion}`
|
|
390
|
+
: 'revert';
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* What `compass revert` says after it ran. Three things the old one-liner left out: whether
|
|
394
|
+
* anything was written, that the status is whatever it was (a revert never changes lifecycle), and
|
|
395
|
+
* which enforced rules the restored version no longer carries.
|
|
396
|
+
*/
|
|
397
|
+
function renderRevertResult(compass, toVersion, agentId, log) {
|
|
398
|
+
if (compass.unchanged) {
|
|
399
|
+
log(`Already at v${toVersion}'s content — nothing written. ${compass.id} stays at v${compass.version}.`);
|
|
400
|
+
log(`Status stays ${compass.status}.`);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
log(`Restored v${toVersion} as v${compass.version} — the intermediate versions stay in the ledger.`);
|
|
404
|
+
log(compass.status === 'archived'
|
|
405
|
+
? `Status stays archived: a revert restores the configuration, never the lifecycle. ` +
|
|
406
|
+
`Reactivate it with \`compass update ${compass.id} --agent ${agentId} --status active\`.`
|
|
407
|
+
: `Status stays ${compass.status}.`);
|
|
408
|
+
const changed = compass.rulesChanged;
|
|
409
|
+
if (changed && (changed.to < changed.from || (changed.removed ?? []).length > 0)) {
|
|
410
|
+
const removed = changed.removed ?? [];
|
|
411
|
+
log(`Warning: rules went from ${changed.from} to ${changed.to}` +
|
|
412
|
+
`${removed.length ? ` (removed: ${removed.join(', ')})` : ''}. ` +
|
|
413
|
+
`A removed active rule is no longer enforced; ` +
|
|
414
|
+
`\`compass revert --to-version ${compass.version - 1}\` brings it back.`);
|
|
415
|
+
}
|
|
416
|
+
}
|
package/dist/lib/followups.d.ts
CHANGED
|
@@ -69,10 +69,18 @@ export interface FollowUpRow {
|
|
|
69
69
|
/** Who settled it: `trigger_fire` for the runtime, otherwise the actor. */
|
|
70
70
|
terminalBy?: string | null;
|
|
71
71
|
escalatedInitiativeId?: string | null;
|
|
72
|
-
/** The gate the fire passes: exempt_silent, exempt_user_directed, exempt_system, user_directed_guarded, autonomy_ladder, approval_ladder. */
|
|
72
|
+
/** The gate the fire passes: exempt_silent, exempt_user_directed, exempt_system, exempt_notification (a passive reminder), user_directed_guarded, autonomy_ladder, approval_ladder. */
|
|
73
73
|
gate?: string | null;
|
|
74
74
|
/** Set while its fire waits on an offline machine; it escalates after 60 minutes. */
|
|
75
75
|
parkedAt?: string | null;
|
|
76
|
+
/** The SLA backstop of a paired event/poll watch: it escalates the watch when the wait outlives its deadline. */
|
|
77
|
+
slaFallback?: boolean;
|
|
78
|
+
/** Set while a fire was moved (quiet hours, working hours, an unavailable machine) instead of run. */
|
|
79
|
+
held?: {
|
|
80
|
+
until: string;
|
|
81
|
+
reason?: string | null;
|
|
82
|
+
note?: string | null;
|
|
83
|
+
} | null;
|
|
76
84
|
capsule?: unknown;
|
|
77
85
|
nextRunAt?: string | null;
|
|
78
86
|
deadlineAt?: string | null;
|
|
@@ -100,6 +108,15 @@ export interface FollowUpCreateResponse {
|
|
|
100
108
|
}
|
|
101
109
|
/** One line telling a person the follow-up was recorded with weaker provenance than claimed. */
|
|
102
110
|
export declare function producerDowngradeNotice(response: FollowUpCreateResponse): string | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* What a reused answer means for the person who asked, for the kinds whose lane a repeat
|
|
113
|
+
* declaration cannot move (an act, a watch): it armed nothing and changed neither the note nor
|
|
114
|
+
* the time they typed, and the row that holds the lane keeps ITS time, which may be weeks away.
|
|
115
|
+
* `Already armed … was not duplicated` alone let `act --in 5m` read as scheduled for five minutes
|
|
116
|
+
* while the existing act waited thirty days. Say what is armed and how to move it, as the
|
|
117
|
+
* check-in answer does (OSK-15411).
|
|
118
|
+
*/
|
|
119
|
+
export declare function reusedWithoutChangeMessage(row: FollowUpCreateResponse['followup'], what: string): string;
|
|
103
120
|
export interface FollowUpObservability {
|
|
104
121
|
generatedAt?: string;
|
|
105
122
|
agents?: Array<{
|
|
@@ -123,6 +140,10 @@ export interface FollowUpObservability {
|
|
|
123
140
|
pool: string | null;
|
|
124
141
|
used: number;
|
|
125
142
|
limit: number | null;
|
|
143
|
+
/** Creations the platform dropped on purpose today (an Agent's own check-in); null when unreadable. */
|
|
144
|
+
droppedToday?: number | null;
|
|
145
|
+
/** Creations refused with FOLLOWUP_BUDGET_EXCEEDED today; null when unreadable. */
|
|
146
|
+
refusedToday?: number | null;
|
|
126
147
|
} | null;
|
|
127
148
|
silenceRate: number | null;
|
|
128
149
|
silentFires: number | null;
|
package/dist/lib/followups.js
CHANGED
|
@@ -5,6 +5,7 @@ exports.whenFlagProblem = whenFlagProblem;
|
|
|
5
5
|
exports.settledLine = settledLine;
|
|
6
6
|
exports.recipeWatchBoundsRefusal = recipeWatchBoundsRefusal;
|
|
7
7
|
exports.producerDowngradeNotice = producerDowngradeNotice;
|
|
8
|
+
exports.reusedWithoutChangeMessage = reusedWithoutChangeMessage;
|
|
8
9
|
exports.resolveFollowUpAgent = resolveFollowUpAgent;
|
|
9
10
|
exports.parseSubjectRef = parseSubjectRef;
|
|
10
11
|
exports.followupSummaryLine = followupSummaryLine;
|
|
@@ -135,6 +136,25 @@ function producerDowngradeNotice(response) {
|
|
|
135
136
|
return undefined;
|
|
136
137
|
return `Note: recorded as ${downgraded.recorded}, not ${downgraded.requested}. ${downgraded.note}`;
|
|
137
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* What a reused answer means for the person who asked, for the kinds whose lane a repeat
|
|
141
|
+
* declaration cannot move (an act, a watch): it armed nothing and changed neither the note nor
|
|
142
|
+
* the time they typed, and the row that holds the lane keeps ITS time, which may be weeks away.
|
|
143
|
+
* `Already armed … was not duplicated` alone let `act --in 5m` read as scheduled for five minutes
|
|
144
|
+
* while the existing act waited thirty days. Say what is armed and how to move it, as the
|
|
145
|
+
* check-in answer does (OSK-15411).
|
|
146
|
+
*/
|
|
147
|
+
function reusedWithoutChangeMessage(row, what) {
|
|
148
|
+
const lines = [
|
|
149
|
+
`Already armed: ${row?.id} — ${what} exists and was not duplicated.`,
|
|
150
|
+
'Nothing in this request was applied: it did not change the note or the time you gave.',
|
|
151
|
+
];
|
|
152
|
+
if (row) {
|
|
153
|
+
lines.push(`Armed: ${row.why ? `"${row.why}"` : '(no note)'}, ${row.nextRunAt ? `next ${row.nextRunAt}` : 'waiting on its trigger'}.`);
|
|
154
|
+
}
|
|
155
|
+
lines.push(`To change the time: skrr followups reschedule ${row?.id ?? '<id>'} --at <instant> or --in <offset>.`);
|
|
156
|
+
return lines.join('\n');
|
|
157
|
+
}
|
|
138
158
|
/**
|
|
139
159
|
* A trigger subject becomes a durable concurrency key, so it cannot be prose.
|
|
140
160
|
* Keep this grammar aligned with TriggerEngine's subject validation and the
|
|
@@ -213,5 +233,5 @@ function followupSummaryLine(row) {
|
|
|
213
233
|
const subject = row.subject ? `${row.subject.type}:${row.subject.externalKey}` : '—';
|
|
214
234
|
const kindForm = row.form ? `${row.kind}/${row.form}` : (row.kind ?? '—');
|
|
215
235
|
const when = row.state === 'settled' ? `settled:${row.terminal ?? '?'}` : `next:${fmtWhen(row.nextRunAt)}`;
|
|
216
|
-
return `${row.id} [${row.state ?? '?'}] ${kindForm} ${subject} ${when}`;
|
|
236
|
+
return `${row.id} [${row.state ?? '?'}] ${kindForm}${row.slaFallback ? ' (SLA fallback)' : ''} ${subject} ${when}`;
|
|
217
237
|
}
|
package/dist/lib/format.d.ts
CHANGED
|
@@ -22,6 +22,17 @@ export declare function pad(s: string, width: number): string;
|
|
|
22
22
|
* surrogate pair is never split down the middle into two replacement glyphs.
|
|
23
23
|
*/
|
|
24
24
|
export declare function truncate(s: string, max: number): string;
|
|
25
|
+
/**
|
|
26
|
+
* `truncate`, but never in the middle of a word.
|
|
27
|
+
*
|
|
28
|
+
* For a prose cell (a reason, a title), where `truncate` cuts a sentence at the
|
|
29
|
+
* column and leaves a half word that reads as a typo. The cut moves back to the
|
|
30
|
+
* last word boundary that fits, and loose punctuation is dropped before the
|
|
31
|
+
* ellipsis. A single token longer than the budget has no boundary to move to, so
|
|
32
|
+
* it is cut hard: a clipped word is better than an empty cell. A boundary so
|
|
33
|
+
* early it would throw away most of the budget is not taken for the same reason.
|
|
34
|
+
*/
|
|
35
|
+
export declare function truncateAtWord(s: string, max: number): string;
|
|
25
36
|
/**
|
|
26
37
|
* Render an arbitrary API value as a single table cell.
|
|
27
38
|
*
|
package/dist/lib/format.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.displayWidth = displayWidth;
|
|
4
4
|
exports.pad = pad;
|
|
5
5
|
exports.truncate = truncate;
|
|
6
|
+
exports.truncateAtWord = truncateAtWord;
|
|
6
7
|
exports.formatCell = formatCell;
|
|
7
8
|
exports.collapseWhitespace = collapseWhitespace;
|
|
8
9
|
exports.renderTable = renderTable;
|
|
@@ -105,6 +106,34 @@ function truncate(s, max) {
|
|
|
105
106
|
}
|
|
106
107
|
return `${out}…`;
|
|
107
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* `truncate`, but never in the middle of a word.
|
|
111
|
+
*
|
|
112
|
+
* For a prose cell (a reason, a title), where `truncate` cuts a sentence at the
|
|
113
|
+
* column and leaves a half word that reads as a typo. The cut moves back to the
|
|
114
|
+
* last word boundary that fits, and loose punctuation is dropped before the
|
|
115
|
+
* ellipsis. A single token longer than the budget has no boundary to move to, so
|
|
116
|
+
* it is cut hard: a clipped word is better than an empty cell. A boundary so
|
|
117
|
+
* early it would throw away most of the budget is not taken for the same reason.
|
|
118
|
+
*/
|
|
119
|
+
function truncateAtWord(s, max) {
|
|
120
|
+
if (displayWidth(s) <= max)
|
|
121
|
+
return s;
|
|
122
|
+
if (max <= 1)
|
|
123
|
+
return '…';
|
|
124
|
+
const hard = truncate(s, max);
|
|
125
|
+
const kept = hard.slice(0, -1); // the longest prefix that leaves room for the ellipsis
|
|
126
|
+
const rest = s.slice(kept.length);
|
|
127
|
+
const trim = (value) => value.replace(/[\s,;:(\-—]+$/u, '');
|
|
128
|
+
// The cut already fell on a word boundary.
|
|
129
|
+
if (/^\s/u.test(rest))
|
|
130
|
+
return `${trim(kept)}…`;
|
|
131
|
+
const boundary = kept.search(/\s\S*$/u);
|
|
132
|
+
if (boundary > 0 && displayWidth(kept.slice(0, boundary)) >= max * 0.4) {
|
|
133
|
+
return `${trim(kept.slice(0, boundary))}…`;
|
|
134
|
+
}
|
|
135
|
+
return hard;
|
|
136
|
+
}
|
|
108
137
|
/**
|
|
109
138
|
* Render an arbitrary API value as a single table cell.
|
|
110
139
|
*
|
|
@@ -2,8 +2,15 @@ import { withQuery } from './triggers';
|
|
|
2
2
|
/** The decisions `PATCH /api/initiatives/:id/action` accepts. */
|
|
3
3
|
export declare const INITIATIVE_ACTIONS: readonly ["approve", "edit_then_approve", "always_allow_similar", "dismiss", "never_suggest_again", "mute_source", "not_now", "snooze", "reopen", "resolve", "wait", "follow_up", "undo", "grant_autonomy", "only_when_urgent"];
|
|
4
4
|
export type InitiativeAction = (typeof INITIATIVE_ACTIONS)[number];
|
|
5
|
-
/**
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* States an Initiative moves through before and after a decision: exactly the stored
|
|
7
|
+
* vocabulary (`AGENT_INITIATIVE_STATES`, `@skrr-ai/data-schemas`; a spec holds the two
|
|
8
|
+
* equal). This list used to say `completed`, a state nothing stores and the server refuses
|
|
9
|
+
* (`unsupported initiative state(s): completed`), and omitted `resolved`, so a person could
|
|
10
|
+
* not list the cards that had been approved and finished, nor the snoozed, expired,
|
|
11
|
+
* reopened or followed-up ones.
|
|
12
|
+
*/
|
|
13
|
+
export declare const INITIATIVE_STATES: readonly ["detected", "proposed", "approved", "executing", "waiting", "followed_up", "reopened", "resolved", "dismissed", "snoozed", "expired", "failed"];
|
|
7
14
|
export type InitiativeView = {
|
|
8
15
|
id?: string;
|
|
9
16
|
title?: string;
|
package/dist/lib/initiatives.js
CHANGED
|
@@ -39,15 +39,26 @@ exports.INITIATIVE_ACTIONS = [
|
|
|
39
39
|
'grant_autonomy',
|
|
40
40
|
'only_when_urgent',
|
|
41
41
|
];
|
|
42
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* States an Initiative moves through before and after a decision: exactly the stored
|
|
44
|
+
* vocabulary (`AGENT_INITIATIVE_STATES`, `@skrr-ai/data-schemas`; a spec holds the two
|
|
45
|
+
* equal). This list used to say `completed`, a state nothing stores and the server refuses
|
|
46
|
+
* (`unsupported initiative state(s): completed`), and omitted `resolved`, so a person could
|
|
47
|
+
* not list the cards that had been approved and finished, nor the snoozed, expired,
|
|
48
|
+
* reopened or followed-up ones.
|
|
49
|
+
*/
|
|
43
50
|
exports.INITIATIVE_STATES = [
|
|
44
51
|
'detected',
|
|
45
52
|
'proposed',
|
|
46
53
|
'approved',
|
|
47
54
|
'executing',
|
|
48
55
|
'waiting',
|
|
49
|
-
'
|
|
56
|
+
'followed_up',
|
|
57
|
+
'reopened',
|
|
58
|
+
'resolved',
|
|
50
59
|
'dismissed',
|
|
60
|
+
'snoozed',
|
|
61
|
+
'expired',
|
|
51
62
|
'failed',
|
|
52
63
|
];
|
|
53
64
|
exports.initiativeApi = {
|
package/dist/lib/machines.d.ts
CHANGED
|
@@ -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
|
*
|
package/dist/lib/machines.js
CHANGED
|
@@ -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
|
*
|