@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
|
@@ -6,10 +6,24 @@ const commitment_product_1 = require("../../lib/commitment-product");
|
|
|
6
6
|
const data_provider_2 = require("@skrr-ai/data-provider");
|
|
7
7
|
const base_command_1 = require("../../base-command");
|
|
8
8
|
const prompt_1 = require("../../lib/prompt");
|
|
9
|
+
const commitment_attention_copy_1 = require("../../lib/commitment-attention-copy");
|
|
9
10
|
const web_url_1 = require("../../lib/web-url");
|
|
10
11
|
const prompt_2 = require("../../lib/prompt");
|
|
11
12
|
const triggers_1 = require("../../lib/triggers");
|
|
12
13
|
const commitments_1 = require("../../lib/commitments");
|
|
14
|
+
/**
|
|
15
|
+
* Every field a stored cadence can carry. `satisfies` makes a key the type does not know a
|
|
16
|
+
* compile error; `update.cadence-preservation.spec.ts` pins the other direction.
|
|
17
|
+
*/
|
|
18
|
+
const CARRIED_CADENCE_KEYS = [
|
|
19
|
+
'mode',
|
|
20
|
+
'intervalMs',
|
|
21
|
+
'times',
|
|
22
|
+
'jitterRatio',
|
|
23
|
+
'activeHours',
|
|
24
|
+
'daysOfWeek',
|
|
25
|
+
'timezone',
|
|
26
|
+
];
|
|
13
27
|
/**
|
|
14
28
|
* `skrr commitments update <id>` — edit the contract.
|
|
15
29
|
*
|
|
@@ -32,13 +46,15 @@ const commitments_1 = require("../../lib/commitments");
|
|
|
32
46
|
*/
|
|
33
47
|
class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
34
48
|
static description = "Update a commitment's contract (title, target, cadence, sources). A cadence is manual, an interval or daily clock times; " +
|
|
35
|
-
'activeHours and daysOfWeek in --from-json select hours and weekdays. No holiday, business-day or trading-calendar fields'
|
|
49
|
+
'activeHours and daysOfWeek in --from-json select hours and weekdays. No holiday, business-day or trading-calendar fields. ' +
|
|
50
|
+
'The Compass a commitment is bound to ("compassId" in the create body) cannot be changed: create a successor commitment instead';
|
|
36
51
|
static examples = [
|
|
37
52
|
'<%= config.bin %> commitments update <commitment-id> --cadence 12h',
|
|
38
53
|
'<%= config.bin %> commitments update <commitment-id> --title "Ship v2 (Q3)" --outcome "v2 is live for all users"',
|
|
39
54
|
'<%= config.bin %> commitments update <commitment-id> --watch tasks --watch github',
|
|
40
55
|
'<%= config.bin %> commitments update <commitment-id> --criterion "signups confirmed" --evaluator metric --measure <measure-id>',
|
|
41
56
|
'<%= config.bin %> commitments update <commitment-id> --agent-directive-file ./review-policy.md',
|
|
57
|
+
'# Nudges: how many times a day it may interrupt you. 0 mutes it; "unlimited" removes the limit.\n<%= config.bin %> commitments update <commitment-id> --max-nudges 2\n<%= config.bin %> commitments update <commitment-id> --max-nudges unlimited',
|
|
42
58
|
`# Read the current contract and use its version for --if-version.
|
|
43
59
|
<%= config.bin %> commitments show <commitment-id> --json
|
|
44
60
|
cat > commitment-patch.json <<'JSON'
|
|
@@ -48,6 +64,11 @@ cat > commitment-patch.json <<'JSON'
|
|
|
48
64
|
}
|
|
49
65
|
JSON
|
|
50
66
|
<%= config.bin %> commitments update <commitment-id> --from-json commitment-patch.json --if-version <observed-version> --json`,
|
|
67
|
+
`# Quiet hours: no messages to you from 22:00 to 07:00. Times are HH:MM (00:00-23:59); without a timezone UTC is used.
|
|
68
|
+
cat > quiet-hours.json <<'JSON'
|
|
69
|
+
{ "policy": { "quietHours": { "enabled": true, "start": "22:00", "end": "07:00", "timezone": "America/Los_Angeles" } } }
|
|
70
|
+
JSON
|
|
71
|
+
<%= config.bin %> commitments update <commitment-id> --from-json quiet-hours.json`,
|
|
51
72
|
];
|
|
52
73
|
static args = {
|
|
53
74
|
id: core_1.Args.string({ description: 'Commitment ID', required: true, ignoreStdin: true }),
|
|
@@ -59,7 +80,7 @@ JSON
|
|
|
59
80
|
description: 'Skip the confirmation prompt for an irreversible status change',
|
|
60
81
|
}),
|
|
61
82
|
'from-json': core_1.Flags.string({
|
|
62
|
-
description:
|
|
83
|
+
description: `JSON patch file (or "-" for stdin). See examples below. JSON cadence and watchedSources replace those fields; policy is deep-merged. ${commitment_attention_copy_1.QUIET_HOURS_HELP} ${commitment_attention_copy_1.EVENT_SOURCES_HELP}`,
|
|
63
84
|
}),
|
|
64
85
|
'if-version': core_1.Flags.integer({
|
|
65
86
|
description: 'Only update this observed contract version; returns a conflict if it changed',
|
|
@@ -126,6 +147,11 @@ JSON
|
|
|
126
147
|
'to be in a Git repository with an initial commit.',
|
|
127
148
|
options: [...commitments_1.COMMITMENT_EXECUTION_ISOLATION_MODES],
|
|
128
149
|
}),
|
|
150
|
+
'max-nudges': core_1.Flags.string({
|
|
151
|
+
// Sent as a single-key `policy` patch, which the API deep-merges. Before this flag the only
|
|
152
|
+
// way back to unlimited was hand-writing {"policy":{"maxUserNudgesPerDay":null}}.
|
|
153
|
+
description: commitment_attention_copy_1.MAX_NUDGES_FLAG_HELP,
|
|
154
|
+
}),
|
|
129
155
|
'max-concurrent-runs': core_1.Flags.string({
|
|
130
156
|
description: 'Set 1..100, or "unlimited" to remove the owner cap. Finite values require --concurrency-reason.',
|
|
131
157
|
}),
|
|
@@ -301,7 +327,11 @@ JSON
|
|
|
301
327
|
if (wantsCadence) {
|
|
302
328
|
const existing = current?.cadence ?? {};
|
|
303
329
|
const storedCadence = {};
|
|
304
|
-
|
|
330
|
+
// Every authored cadence field. The API replaces `cadence` wholesale, so a field left out
|
|
331
|
+
// of this list is erased from the Commitment by an edit that never mentioned it: omitting
|
|
332
|
+
// `activeHours`/`daysOfWeek` turned "weekdays 09:00-22:00" into "around the clock" on
|
|
333
|
+
// `--cadence 2h` (OSK-18366). Mirrors `cadenceShape` in api/server/routes/commitments.js.
|
|
334
|
+
for (const key of CARRIED_CADENCE_KEYS) {
|
|
305
335
|
if (existing[key] !== undefined)
|
|
306
336
|
storedCadence[key] = existing[key];
|
|
307
337
|
}
|
|
@@ -350,6 +380,11 @@ JSON
|
|
|
350
380
|
delete cadence.jitterRatio;
|
|
351
381
|
}
|
|
352
382
|
}
|
|
383
|
+
// A daily cadence's rhythm is its times, and the API refuses an `intervalMs` beside them.
|
|
384
|
+
// Dropping the inherited one also repairs a row an earlier build let store both.
|
|
385
|
+
if (cadence.mode === 'daily' && !Object.hasOwn(authoredCadence ?? {}, 'intervalMs')) {
|
|
386
|
+
delete cadence.intervalMs;
|
|
387
|
+
}
|
|
353
388
|
if (!['interval', 'daily', 'event_plus_interval'].includes(String(cadence.mode)) &&
|
|
354
389
|
!Object.hasOwn(authoredCadence ?? {}, 'activeHours'))
|
|
355
390
|
delete cadence.activeHours;
|
|
@@ -365,13 +400,16 @@ JSON
|
|
|
365
400
|
rawValue: flags['max-concurrent-runs'],
|
|
366
401
|
reason: flags['concurrency-reason'],
|
|
367
402
|
});
|
|
368
|
-
|
|
403
|
+
const maxNudges = (0, commitment_attention_copy_1.parseMaxNudgesFlag)(flags['max-nudges']);
|
|
404
|
+
if (flags.isolation || concurrencyPatch || maxNudges !== undefined) {
|
|
369
405
|
const existingPolicy = payload.policy && typeof payload.policy === 'object' && !Array.isArray(payload.policy)
|
|
370
406
|
? payload.policy
|
|
371
407
|
: {};
|
|
372
408
|
const nextPolicy = { ...existingPolicy };
|
|
373
409
|
if (flags.isolation)
|
|
374
410
|
nextPolicy.executionIsolation = flags.isolation;
|
|
411
|
+
if (maxNudges !== undefined)
|
|
412
|
+
nextPolicy.maxUserNudgesPerDay = maxNudges;
|
|
375
413
|
if (concurrencyPatch) {
|
|
376
414
|
const existingEnvelope = nextPolicy.executionBudget &&
|
|
377
415
|
typeof nextPolicy.executionBudget === 'object' &&
|
|
@@ -390,6 +428,9 @@ JSON
|
|
|
390
428
|
!Array.isArray(finalPolicy.executionBudget)
|
|
391
429
|
? finalPolicy.executionBudget
|
|
392
430
|
: undefined;
|
|
431
|
+
const quietHoursProblem = (0, commitment_attention_copy_1.quietHoursInputProblem)(finalPolicy);
|
|
432
|
+
if (quietHoursProblem)
|
|
433
|
+
throw new Error(quietHoursProblem);
|
|
393
434
|
if (process.env.OVERSKY_AUTONOMOUS_SESSION === '1' &&
|
|
394
435
|
finalEnvelope &&
|
|
395
436
|
Object.prototype.hasOwnProperty.call(finalEnvelope, 'maxConcurrentRuns')) {
|
|
@@ -7,6 +7,7 @@ const base_command_1 = require("../../base-command");
|
|
|
7
7
|
const commitments_1 = require("../../lib/commitments");
|
|
8
8
|
const format_1 = require("../../lib/format");
|
|
9
9
|
const commitment_event_wakes_1 = require("../../lib/commitment-event-wakes");
|
|
10
|
+
const commitment_attention_copy_1 = require("../../lib/commitment-attention-copy");
|
|
10
11
|
/**
|
|
11
12
|
* The headline used to stop at "configured sources may wake the Agent within lifecycle and execution
|
|
12
13
|
* budgets", over a column marked ACTIVE, which read as bound while `trigger-status` said no event
|
|
@@ -84,6 +85,18 @@ class CommitmentsWakeCapabilities extends base_command_1.BaseCommand {
|
|
|
84
85
|
}
|
|
85
86
|
for (const line of wakePolicyLines(result))
|
|
86
87
|
this.log(line);
|
|
88
|
+
// The owner's allowlist of event sources (OSK-21113): the response does not carry it, and for
|
|
89
|
+
// unset, [], a bogus name and a real source this output was byte-identical. Read from the
|
|
90
|
+
// Commitment's own policy; unread, the line is left out rather than claim "all allowed".
|
|
91
|
+
try {
|
|
92
|
+
const policy = (await commitments_1.commitmentApi.get(args.commitmentId))?.commitment?.policy;
|
|
93
|
+
if (policy) {
|
|
94
|
+
this.log(`Event sources: ${(0, commitment_attention_copy_1.describeEventSources)(policy.executionBudget?.allowedEventSources)}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// The wake table below does not depend on it.
|
|
99
|
+
}
|
|
87
100
|
const visible = new Set(result.visibleCapabilities.map((item) => item.id));
|
|
88
101
|
(0, format_1.renderTable)(result.eligibleCapabilities.map((item) => ({
|
|
89
102
|
id: item.id,
|
|
@@ -58,6 +58,10 @@ class CompassArchive extends base_command_1.BaseCommand {
|
|
|
58
58
|
this.log(JSON.stringify(result, null, 2));
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
|
+
if (result.alreadyArchived) {
|
|
62
|
+
this.log(`Already archived. ${result.id} is unchanged — no new revision was written.`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
61
65
|
this.log(`Archived ${result.id}. Revisions remain readable via \`compass revisions\`.`);
|
|
62
66
|
}
|
|
63
67
|
}
|
|
@@ -38,10 +38,24 @@ class CompassCommitments extends base_command_1.BaseCommand {
|
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
40
|
const rows = response.data ?? [];
|
|
41
|
+
// The list carries no compass status, so one read says whether it governs these at all. Best
|
|
42
|
+
// effort: when it fails the rows still print, with no claim either way about governance.
|
|
43
|
+
let status;
|
|
44
|
+
try {
|
|
45
|
+
status = (await compasses_1.compassApi.get(args.compassId, { agentId: flags.agent })).status;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
status = undefined;
|
|
49
|
+
}
|
|
50
|
+
const archived = status === 'archived';
|
|
41
51
|
if (rows.length === 0) {
|
|
42
|
-
this.log(
|
|
52
|
+
this.log(archived
|
|
53
|
+
? 'No commitments are bound to this compass.'
|
|
54
|
+
: 'No commitments are governed by this compass.');
|
|
43
55
|
return;
|
|
44
56
|
}
|
|
57
|
+
if (archived)
|
|
58
|
+
this.log((0, compasses_1.describeBoundCommitments)(rows.length, status));
|
|
45
59
|
(0, format_1.renderTable)(rows.map((row) => ({
|
|
46
60
|
id: String(row.id ?? ''),
|
|
47
61
|
title: String(row.title ?? ''),
|
|
@@ -5,6 +5,7 @@ const core_1 = require("@oclif/core");
|
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
6
|
const prompt_1 = require("../../lib/prompt");
|
|
7
7
|
const compasses_1 = require("../../lib/compasses");
|
|
8
|
+
const compass_body_help_1 = require("../../lib/compass-body-help");
|
|
8
9
|
const web_url_1 = require("../../lib/web-url");
|
|
9
10
|
/**
|
|
10
11
|
* Stamp the owning agent onto a compass the API returned without one.
|
|
@@ -33,11 +34,17 @@ function withCompassAgentContext(compass, agentId) {
|
|
|
33
34
|
* without turning the CLI into a schema.
|
|
34
35
|
*/
|
|
35
36
|
class CompassCreate extends base_command_1.BaseCommand {
|
|
36
|
-
static description =
|
|
37
|
+
static description = `Create a compass for an agent.
|
|
38
|
+
|
|
39
|
+
${compass_body_help_1.COMPASS_BODY_HELP}
|
|
40
|
+
|
|
41
|
+
To govern a Commitment with this compass, put "compassId" in the Commitment's --from-json create body (see: commitments create --help). The binding is fixed at creation.`;
|
|
37
42
|
static examples = [
|
|
38
43
|
'<%= config.bin %> compass create --agent agent_abc --title "Production reliability" --domain reliability',
|
|
39
44
|
'<%= config.bin %> compass create --agent agent_abc --title "FinOps" --invariant "Cloud spend stays under $10k/mo"',
|
|
40
45
|
'<%= config.bin %> compass create --agent agent_abc --json-body ./compass.json',
|
|
46
|
+
`${compass_body_help_1.COMPASS_BODY_EXAMPLE}
|
|
47
|
+
<%= config.bin %> compass create --agent agent_abc --json-body compass.json`,
|
|
41
48
|
];
|
|
42
49
|
static flags = {
|
|
43
50
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
@@ -45,11 +52,12 @@ class CompassCreate extends base_command_1.BaseCommand {
|
|
|
45
52
|
title: core_1.Flags.string({ description: 'Human-readable direction, e.g. "Production reliability"' }),
|
|
46
53
|
domain: core_1.Flags.string({ description: 'Broad subject area, e.g. "aws" or "finops"' }),
|
|
47
54
|
invariant: core_1.Flags.string({
|
|
48
|
-
description: 'Invariant target description (repeatable). The state the agent keeps true.'
|
|
55
|
+
description: 'Invariant target description (repeatable, at most 25). The state the agent keeps true. ' +
|
|
56
|
+
'Each gets the id invariant_<position> and no domainKind: use --json-body for ids and domains.',
|
|
49
57
|
multiple: true,
|
|
50
58
|
}),
|
|
51
59
|
'json-body': core_1.Flags.string({
|
|
52
|
-
description: 'Path to a JSON file with the full body (merged under the flags)',
|
|
60
|
+
description: 'Path to a JSON file with the full body (merged under the flags). Field names and limits are listed in the description above.',
|
|
53
61
|
}),
|
|
54
62
|
};
|
|
55
63
|
async run() {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
2
|
export default class CompassEffectivePolicy extends BaseCommand {
|
|
3
3
|
static description: string;
|
|
4
|
+
static examples: string[];
|
|
4
5
|
static args: {
|
|
5
6
|
compassId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
7
|
};
|
|
@@ -5,7 +5,13 @@ const base_command_1 = require("../../base-command");
|
|
|
5
5
|
const compasses_1 = require("../../lib/compasses");
|
|
6
6
|
class CompassEffectivePolicy extends base_command_1.BaseCommand {
|
|
7
7
|
static description = 'Read a Compass policy revision, effective defaults and field provenance';
|
|
8
|
-
static
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> compass effective-policy agch_abc123 --agent agent_xyz',
|
|
10
|
+
'<%= config.bin %> compass effective-policy agch_abc123 --agent agent_xyz --json',
|
|
11
|
+
];
|
|
12
|
+
static args = {
|
|
13
|
+
compassId: core_1.Args.string({ description: 'Compass ID', required: true, ignoreStdin: true }),
|
|
14
|
+
};
|
|
9
15
|
static flags = {
|
|
10
16
|
agent: core_1.Flags.string({ description: 'Agent ID that owns the Compass', required: true }),
|
|
11
17
|
json: core_1.Flags.boolean({ description: 'Output the complete policy and provenance as JSON' }),
|
|
@@ -19,12 +25,7 @@ class CompassEffectivePolicy extends base_command_1.BaseCommand {
|
|
|
19
25
|
this.log(JSON.stringify(policy, null, 2));
|
|
20
26
|
return;
|
|
21
27
|
}
|
|
22
|
-
|
|
23
|
-
this.log(`Applies to runtime: ${policy.appliesToRuntime === true ? 'yes' : 'no'}`);
|
|
24
|
-
this.log(`Autonomy defaults: ${JSON.stringify(policy.autonomy ?? {})}`);
|
|
25
|
-
this.log(`Communication defaults: ${JSON.stringify(policy.communication ?? {})}`);
|
|
26
|
-
this.log(`Authority: ${policy.authority ?? 'unknown'}`);
|
|
27
|
-
this.log(`Field provenance: ${JSON.stringify(policy.fieldProvenance ?? {})}`);
|
|
28
|
+
(0, compasses_1.renderEffectivePolicy)(policy, (line) => this.log(line));
|
|
28
29
|
}
|
|
29
30
|
catch (error) {
|
|
30
31
|
this.handleApiError(error);
|
|
@@ -6,6 +6,13 @@ import { BaseCommand } from '../../base-command';
|
|
|
6
6
|
* The ledger therefore records that someone chose to go back, and versions 4–8
|
|
7
7
|
* stay readable instead of vanishing. That is the difference between an audit
|
|
8
8
|
* trail and an undo button.
|
|
9
|
+
*
|
|
10
|
+
* Like `update`, a revert is version-fenced: `--expected-version` pins the
|
|
11
|
+
* version the caller looked at, and without it the current version is read at
|
|
12
|
+
* the start and said so on stderr, so a concurrent edit is a named conflict
|
|
13
|
+
* rather than a surprise. A revert restores the configuration and keeps the
|
|
14
|
+
* compass's current status; it says when it wrote nothing and when it removed
|
|
15
|
+
* enforced rules.
|
|
9
16
|
*/
|
|
10
17
|
export default class CompassRevert extends BaseCommand {
|
|
11
18
|
static description: string;
|
|
@@ -18,6 +25,7 @@ export default class CompassRevert extends BaseCommand {
|
|
|
18
25
|
agent: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
26
|
'to-version': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
27
|
reason: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
28
|
+
'expected-version': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
29
|
};
|
|
22
30
|
run(): Promise<void>;
|
|
23
31
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const base_command_1 = require("../../base-command");
|
|
5
5
|
const compasses_1 = require("../../lib/compasses");
|
|
6
|
+
const update_1 = require("./update");
|
|
6
7
|
/**
|
|
7
8
|
* `skrr compass revert <compass-id> --agent <id> --to-version 3`
|
|
8
9
|
*
|
|
@@ -10,12 +11,20 @@ const compasses_1 = require("../../lib/compasses");
|
|
|
10
11
|
* The ledger therefore records that someone chose to go back, and versions 4–8
|
|
11
12
|
* stay readable instead of vanishing. That is the difference between an audit
|
|
12
13
|
* trail and an undo button.
|
|
14
|
+
*
|
|
15
|
+
* Like `update`, a revert is version-fenced: `--expected-version` pins the
|
|
16
|
+
* version the caller looked at, and without it the current version is read at
|
|
17
|
+
* the start and said so on stderr, so a concurrent edit is a named conflict
|
|
18
|
+
* rather than a surprise. A revert restores the configuration and keeps the
|
|
19
|
+
* compass's current status; it says when it wrote nothing and when it removed
|
|
20
|
+
* enforced rules.
|
|
13
21
|
*/
|
|
14
22
|
class CompassRevert extends base_command_1.BaseCommand {
|
|
15
23
|
static description = 'Restore an earlier compass version (as a NEW forward revision)';
|
|
16
24
|
static examples = [
|
|
17
25
|
'<%= config.bin %> compass revert agch_abc --agent agent_xyz --to-version 3',
|
|
18
26
|
'<%= config.bin %> compass revert agch_abc --agent agent_xyz --to-version 3 --reason "new SLO was wrong"',
|
|
27
|
+
'<%= config.bin %> compass revert agch_abc --agent agent_xyz --to-version 3 --expected-version 9',
|
|
19
28
|
];
|
|
20
29
|
static args = {
|
|
21
30
|
compassId: core_1.Args.string({ ignoreStdin: true, description: 'Compass ID', required: true }),
|
|
@@ -29,15 +38,30 @@ class CompassRevert extends base_command_1.BaseCommand {
|
|
|
29
38
|
min: 1,
|
|
30
39
|
}),
|
|
31
40
|
reason: core_1.Flags.string({ description: 'Why — recorded on the revision ledger' }),
|
|
41
|
+
'expected-version': core_1.Flags.integer({
|
|
42
|
+
min: 1,
|
|
43
|
+
description: 'Compass version this revert is based on; it is refused if the compass moved. ' +
|
|
44
|
+
'Defaults to the version read at the start of this command.',
|
|
45
|
+
}),
|
|
32
46
|
};
|
|
33
47
|
async run() {
|
|
34
48
|
this.requireAuth();
|
|
35
49
|
const { args, flags } = await this.parse(CompassRevert);
|
|
50
|
+
this.compassRef = {
|
|
51
|
+
compassId: args.compassId,
|
|
52
|
+
agentId: flags.agent,
|
|
53
|
+
toVersion: flags['to-version'],
|
|
54
|
+
};
|
|
36
55
|
let compass;
|
|
37
56
|
try {
|
|
57
|
+
const expected = await (0, update_1.resolveExpectedVersion)(flags['expected-version'], {}, async () => (await compasses_1.compassApi.get(args.compassId, { agentId: flags.agent })).version);
|
|
58
|
+
if (expected.source === 'current' && !flags.json) {
|
|
59
|
+
this.logToStderr(`No --expected-version given; reverting from the current version (v${String(expected.version)}).`);
|
|
60
|
+
}
|
|
38
61
|
compass = await compasses_1.compassApi.revert(args.compassId, {
|
|
39
62
|
agentId: flags.agent,
|
|
40
63
|
toVersion: flags['to-version'],
|
|
64
|
+
expectedVersion: expected.version,
|
|
41
65
|
...(flags.reason ? { reason: flags.reason } : {}),
|
|
42
66
|
});
|
|
43
67
|
}
|
|
@@ -48,7 +72,7 @@ class CompassRevert extends base_command_1.BaseCommand {
|
|
|
48
72
|
this.log(JSON.stringify(compass, null, 2));
|
|
49
73
|
return;
|
|
50
74
|
}
|
|
51
|
-
|
|
75
|
+
(0, compasses_1.renderRevertResult)(compass, flags['to-version'], flags.agent, (line) => this.log(line));
|
|
52
76
|
this.log('');
|
|
53
77
|
(0, compasses_1.renderCompass)(compass, (line) => this.log(line));
|
|
54
78
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/** What to say under a list the ledger had more rows for. */
|
|
3
|
+
export declare function revisionsFooter(shown: number): string;
|
|
2
4
|
/**
|
|
3
5
|
* `skrr compass revisions <compass-id> --agent <id>` — the append-only ledger.
|
|
4
6
|
*
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.revisionsFooter = revisionsFooter;
|
|
3
4
|
const core_1 = require("@oclif/core");
|
|
4
5
|
const base_command_1 = require("../../base-command");
|
|
5
6
|
const compasses_1 = require("../../lib/compasses");
|
|
7
|
+
/** What to say under a list the ledger had more rows for. */
|
|
8
|
+
function revisionsFooter(shown) {
|
|
9
|
+
return shown >= 100
|
|
10
|
+
? `Showing ${shown} of at least ${shown + 1} revisions. --limit is capped at 100, so older ones cannot be listed yet.`
|
|
11
|
+
: `Showing ${shown} of at least ${shown + 1} revisions — use --limit (up to 100) to see more.`;
|
|
12
|
+
}
|
|
6
13
|
/**
|
|
7
14
|
* `skrr compass revisions <compass-id> --agent <id>` — the append-only ledger.
|
|
8
15
|
*
|
|
@@ -21,7 +28,11 @@ class CompassRevisions extends base_command_1.BaseCommand {
|
|
|
21
28
|
static flags = {
|
|
22
29
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
23
30
|
agent: core_1.Flags.string({ description: 'Agent ID that owns the compass', required: true }),
|
|
24
|
-
limit: core_1.Flags.integer({
|
|
31
|
+
limit: core_1.Flags.integer({
|
|
32
|
+
description: 'Max revisions (1..100, default 20); newest first',
|
|
33
|
+
min: 1,
|
|
34
|
+
max: 100,
|
|
35
|
+
}),
|
|
25
36
|
};
|
|
26
37
|
async run() {
|
|
27
38
|
this.requireAuth();
|
|
@@ -40,7 +51,12 @@ class CompassRevisions extends base_command_1.BaseCommand {
|
|
|
40
51
|
this.log(JSON.stringify(response, null, 2));
|
|
41
52
|
return;
|
|
42
53
|
}
|
|
43
|
-
|
|
54
|
+
const rows = response.data ?? [];
|
|
55
|
+
(0, compasses_1.renderRevisionList)(rows, (line) => this.log(line));
|
|
56
|
+
// The API reads one row past the page, so `has_more` is true only when older rows exist. A
|
|
57
|
+
// 22-revision ledger used to list 20 rows and stop, with v1 (the create) silently missing.
|
|
58
|
+
if (response.has_more)
|
|
59
|
+
this.log(revisionsFooter(rows.length));
|
|
44
60
|
}
|
|
45
61
|
}
|
|
46
62
|
exports.default = CompassRevisions;
|
|
@@ -2,9 +2,11 @@ import { BaseCommand } from '../../base-command';
|
|
|
2
2
|
/**
|
|
3
3
|
* `skrr compass tactic <compass-id> --agent <id> --description "..."`
|
|
4
4
|
*
|
|
5
|
-
* Appends to the bounded, rolling "what has worked before" list
|
|
6
|
-
* separate verb from `update` on
|
|
7
|
-
* write would let two concurrent
|
|
5
|
+
* Appends to the bounded, rolling "what has worked before" list, or updates the
|
|
6
|
+
* entry that carries the same `--id`. It is a separate verb from `update` on
|
|
7
|
+
* purpose: expressing an append as a full-object write would let two concurrent
|
|
8
|
+
* learners clobber each other's entry. It says which of appended / updated /
|
|
9
|
+
* unchanged happened, and names any tactic that rolled off the end.
|
|
8
10
|
*/
|
|
9
11
|
export default class CompassTactic extends BaseCommand {
|
|
10
12
|
static description: string;
|
|
@@ -6,12 +6,14 @@ const compasses_1 = require("../../lib/compasses");
|
|
|
6
6
|
/**
|
|
7
7
|
* `skrr compass tactic <compass-id> --agent <id> --description "..."`
|
|
8
8
|
*
|
|
9
|
-
* Appends to the bounded, rolling "what has worked before" list
|
|
10
|
-
* separate verb from `update` on
|
|
11
|
-
* write would let two concurrent
|
|
9
|
+
* Appends to the bounded, rolling "what has worked before" list, or updates the
|
|
10
|
+
* entry that carries the same `--id`. It is a separate verb from `update` on
|
|
11
|
+
* purpose: expressing an append as a full-object write would let two concurrent
|
|
12
|
+
* learners clobber each other's entry. It says which of appended / updated /
|
|
13
|
+
* unchanged happened, and names any tactic that rolled off the end.
|
|
12
14
|
*/
|
|
13
15
|
class CompassTactic extends base_command_1.BaseCommand {
|
|
14
|
-
static description = '
|
|
16
|
+
static description = 'Record a learned tactic on a compass (appends, or updates the tactic with the same --id)';
|
|
15
17
|
static examples = [
|
|
16
18
|
'<%= config.bin %> compass tactic agch_abc --agent agent_xyz --description "Roll back before paging on a deploy regression"',
|
|
17
19
|
];
|
|
@@ -23,7 +25,7 @@ class CompassTactic extends base_command_1.BaseCommand {
|
|
|
23
25
|
agent: core_1.Flags.string({ description: 'Agent ID that owns the compass', required: true }),
|
|
24
26
|
description: core_1.Flags.string({ description: 'The tactic, in one sentence', required: true }),
|
|
25
27
|
id: core_1.Flags.string({
|
|
26
|
-
description: 'Stable tactic ID
|
|
28
|
+
description: 'Stable tactic ID. A known ID with a different description updates that entry; with the same description nothing is written.',
|
|
27
29
|
}),
|
|
28
30
|
reason: core_1.Flags.string({ description: 'Why — recorded on the revision ledger' }),
|
|
29
31
|
};
|
|
@@ -46,8 +48,7 @@ class CompassTactic extends base_command_1.BaseCommand {
|
|
|
46
48
|
this.log(JSON.stringify(compass, null, 2));
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
49
|
-
|
|
50
|
-
this.log(`Appended. ${compass.id} now carries ${count} learned tactic(s) (v${compass.version}).`);
|
|
51
|
+
(0, compasses_1.renderTacticResult)(compass, (line) => this.log(line));
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
exports.default = CompassTactic;
|
|
@@ -6,6 +6,7 @@ const base_command_1 = require("../../base-command");
|
|
|
6
6
|
const prompt_1 = require("../../lib/prompt");
|
|
7
7
|
const compasses_1 = require("../../lib/compasses");
|
|
8
8
|
const web_url_1 = require("../../lib/web-url");
|
|
9
|
+
const compass_body_help_1 = require("../../lib/compass-body-help");
|
|
9
10
|
/**
|
|
10
11
|
* The server fences every compass write on the version the caller last saw
|
|
11
12
|
* (`expectedVersion`, required), so a stale writer gets a conflict instead of
|
|
@@ -33,7 +34,11 @@ async function resolveExpectedVersion(explicit, fileBody, fetchCurrentVersion) {
|
|
|
33
34
|
* winning for some domain — replacement makes the new set the whole answer.
|
|
34
35
|
*/
|
|
35
36
|
class CompassUpdate extends base_command_1.BaseCommand {
|
|
36
|
-
static description =
|
|
37
|
+
static description = `Update a compass (bumps the version, writes a revision).
|
|
38
|
+
|
|
39
|
+
${compass_body_help_1.COMPASS_BODY_HELP}
|
|
40
|
+
|
|
41
|
+
On update, invariantTargets (and --invariant) REPLACE the whole list, so send every target you want to keep; identity, scope, autonomyDefaults and communicationDefaults merge field by field onto what is stored; rules replace the list. An archived compass stays archived unless you pass --status active.`;
|
|
37
42
|
static examples = [
|
|
38
43
|
'<%= config.bin %> compass update agch_abc --agent agent_xyz --title "Reliability & cost"',
|
|
39
44
|
'<%= config.bin %> compass update agch_abc --agent agent_xyz --invariant "p99 under 300ms" --reason "new SLO"',
|
|
@@ -50,7 +55,8 @@ class CompassUpdate extends base_command_1.BaseCommand {
|
|
|
50
55
|
domain: core_1.Flags.string({ description: 'New domain' }),
|
|
51
56
|
status: core_1.Flags.string({ description: 'New status', options: [...compasses_1.COMPASS_STATUSES] }),
|
|
52
57
|
invariant: core_1.Flags.string({
|
|
53
|
-
description: 'Invariant target description (repeatable; REPLACES the list)'
|
|
58
|
+
description: 'Invariant target description (repeatable, at most 25; REPLACES the list). ' +
|
|
59
|
+
'Each gets the id invariant_<position> and no domainKind, so it drops the ids and domains of the targets it replaces: use --json-body to keep them.',
|
|
54
60
|
multiple: true,
|
|
55
61
|
}),
|
|
56
62
|
reason: core_1.Flags.string({ description: 'Why — recorded on the revision ledger' }),
|
|
@@ -59,7 +65,9 @@ class CompassUpdate extends base_command_1.BaseCommand {
|
|
|
59
65
|
description: 'Compass version this change is based on; the update is refused if it moved. ' +
|
|
60
66
|
'Defaults to the version read at the start of this command.',
|
|
61
67
|
}),
|
|
62
|
-
'json-body': core_1.Flags.string({
|
|
68
|
+
'json-body': core_1.Flags.string({
|
|
69
|
+
description: 'Path to a JSON file with the body (merged under the flags). Field names and limits are listed in the description above.',
|
|
70
|
+
}),
|
|
63
71
|
};
|
|
64
72
|
async run() {
|
|
65
73
|
this.requireAuth();
|
|
@@ -81,10 +89,14 @@ class CompassUpdate extends base_command_1.BaseCommand {
|
|
|
81
89
|
if (Object.keys(body).length <= 1) {
|
|
82
90
|
this.error('Nothing to update — pass at least one field flag or --json-body.');
|
|
83
91
|
}
|
|
92
|
+
this.compassRef = { compassId: args.compassId, agentId: flags.agent };
|
|
84
93
|
let compass;
|
|
85
94
|
try {
|
|
86
95
|
const expected = await resolveExpectedVersion(flags['expected-version'], fileBody, async () => (await compasses_1.compassApi.get(args.compassId, { agentId: flags.agent })).version);
|
|
87
96
|
body.expectedVersion = expected.version;
|
|
97
|
+
if (typeof expected.version === 'number') {
|
|
98
|
+
this.compassRef = { ...this.compassRef, expectedVersion: expected.version };
|
|
99
|
+
}
|
|
88
100
|
if (expected.source === 'current' && !flags.json) {
|
|
89
101
|
this.logToStderr(`No --expected-version given; updating from the current version (v${String(expected.version)}).`);
|
|
90
102
|
}
|
|
@@ -100,6 +112,10 @@ class CompassUpdate extends base_command_1.BaseCommand {
|
|
|
100
112
|
return;
|
|
101
113
|
}
|
|
102
114
|
this.log(`Updated ${withContext.id} → v${withContext.version}.`);
|
|
115
|
+
// An edit keeps the status (docs: it never resurrects). Say so, or the edit looks live.
|
|
116
|
+
if (withContext.status === 'archived' && body.status !== 'archived') {
|
|
117
|
+
this.log('Compass is archived: this edit has no runtime effect until it is reactivated (`--status active`).');
|
|
118
|
+
}
|
|
103
119
|
if (url)
|
|
104
120
|
this.log(`View it at ${url}`);
|
|
105
121
|
this.log('');
|
|
@@ -105,7 +105,7 @@ class FollowupsAct extends base_command_1.BaseCommand {
|
|
|
105
105
|
this.log(producerNotice);
|
|
106
106
|
const row = response.followup;
|
|
107
107
|
if (response.reused) {
|
|
108
|
-
this.log(
|
|
108
|
+
this.log((0, followups_1.reusedWithoutChangeMessage)(row, 'the same act on this subject'));
|
|
109
109
|
return;
|
|
110
110
|
}
|
|
111
111
|
if (response.dropped) {
|
|
@@ -30,6 +30,16 @@ class FollowupsCancel extends base_command_1.BaseCommand {
|
|
|
30
30
|
async run() {
|
|
31
31
|
this.requireAuth();
|
|
32
32
|
const { args, flags } = await this.parse(FollowupsCancel);
|
|
33
|
+
// Best effort, and only to warn: cancelling the SLA backstop of a paired watch leaves that watch
|
|
34
|
+
// armed with no deadline, and the answer used to be the same bare "cancelled".
|
|
35
|
+
let wasSlaFallback = false;
|
|
36
|
+
try {
|
|
37
|
+
const before = await followups_1.followupsApi.show(args.id);
|
|
38
|
+
wasSlaFallback = Boolean(before?.followup?.slaFallback && !before.followup.terminal);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// The cancel below reports any real problem with the id.
|
|
42
|
+
}
|
|
33
43
|
let result;
|
|
34
44
|
try {
|
|
35
45
|
result = (await followups_1.followupsApi.cancel(args.id, {
|
|
@@ -45,6 +55,9 @@ class FollowupsCancel extends base_command_1.BaseCommand {
|
|
|
45
55
|
return;
|
|
46
56
|
}
|
|
47
57
|
this.log((0, followups_1.settledLine)(args.id, result, 'cancelled'));
|
|
58
|
+
if (wasSlaFallback) {
|
|
59
|
+
this.log('That was the SLA backstop of a paired watch. The watch itself is still armed and now has no deadline: cancel or resolve it too if you meant to end the wait.');
|
|
60
|
+
}
|
|
48
61
|
}
|
|
49
62
|
}
|
|
50
63
|
exports.default = FollowupsCancel;
|
|
@@ -6,6 +6,23 @@ const format_1 = require("../../lib/format");
|
|
|
6
6
|
const followups_1 = require("../../lib/followups");
|
|
7
7
|
const agent_resolver_1 = require("../../lib/agent-resolver");
|
|
8
8
|
const rate = (value) => value === null ? '—' : `${Math.round(value * 100)}%`;
|
|
9
|
+
/**
|
|
10
|
+
* What today's budget turned away. A creation refused or dropped makes no row, so
|
|
11
|
+
* this is the only place it shows (OSK-21209). `—` is "this kind has no budget",
|
|
12
|
+
* `?` is "the counter could not be read", `0` is a real zero.
|
|
13
|
+
*/
|
|
14
|
+
const turnedAway = (budget) => {
|
|
15
|
+
if (!budget)
|
|
16
|
+
return '—';
|
|
17
|
+
const { droppedToday, refusedToday } = budget;
|
|
18
|
+
if (droppedToday == null || refusedToday == null)
|
|
19
|
+
return '?';
|
|
20
|
+
const parts = [
|
|
21
|
+
droppedToday > 0 ? `${droppedToday} dropped` : null,
|
|
22
|
+
refusedToday > 0 ? `${refusedToday} refused` : null,
|
|
23
|
+
].filter(Boolean);
|
|
24
|
+
return parts.length > 0 ? parts.join(' · ') : '0';
|
|
25
|
+
};
|
|
9
26
|
/** `resolved 3 · abandoned 1` — the outcomes that happened, not five zeros. */
|
|
10
27
|
const outcomes = (terminal) => Object.entries(terminal)
|
|
11
28
|
.filter(([, count]) => count > 0)
|
|
@@ -97,6 +114,7 @@ class FollowupsObservability extends base_command_1.BaseCommand {
|
|
|
97
114
|
? `$${kind.spend.today.toFixed(2)} / $${kind.spend.total.toFixed(2)}`
|
|
98
115
|
: '—',
|
|
99
116
|
budget: kind.budget ? `${kind.budget.used}/${kind.budget.limit ?? '∞'}` : '—',
|
|
117
|
+
turnedAway: turnedAway(kind.budget),
|
|
100
118
|
silence: rate(kind.silenceRate),
|
|
101
119
|
})), [
|
|
102
120
|
{ key: 'kind', header: 'KIND' },
|
|
@@ -109,10 +127,11 @@ class FollowupsObservability extends base_command_1.BaseCommand {
|
|
|
109
127
|
{ key: 'fires', header: 'FIRES' },
|
|
110
128
|
{ key: 'spend', header: 'SPENT TODAY/ALL' },
|
|
111
129
|
{ key: 'budget', header: 'TODAY/LIMIT' },
|
|
130
|
+
{ key: 'turnedAway', header: 'TURNED AWAY' },
|
|
112
131
|
{ key: 'silence', header: 'SILENT' },
|
|
113
132
|
], (line) => this.log(line));
|
|
114
133
|
});
|
|
115
|
-
this.log(`\nAs of ${report.generatedAt ?? 'now'}. SPENT is the agent turns these follow-ups woke (USD, today / all time); TODAY/LIMIT is the daily creation budget (reminders are not metered); SILENT is how often a check-in chose to stay quiet.`);
|
|
134
|
+
this.log(`\nAs of ${report.generatedAt ?? 'now'}. SPENT is the agent turns these follow-ups woke (USD, today / all time); TODAY/LIMIT is the daily creation budget (reminders are not metered); TURNED AWAY is what that budget kept from being created today: dropped is a check-in the API answered with no error (the CLI prints one for you; an Agent's own check-in is not told), refused is a watch or act answered FOLLOWUP_BUDGET_EXCEEDED; SILENT is how often a check-in chose to stay quiet.`);
|
|
116
135
|
}
|
|
117
136
|
}
|
|
118
137
|
exports.default = FollowupsObservability;
|