@skrr-ai/cli 0.1.127 → 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/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/planner-config.d.ts +11 -0
- package/dist/commands/goals/planner-config.js +16 -0
- 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/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/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 +1 -1
- package/dist/lib/triggers.js +11 -3
- package/dist/node_modules/@skrr-ai/data-provider/index.js +6504 -6493
- package/oclif.manifest.json +350 -34
- package/package.json +4 -4
|
@@ -55,20 +55,20 @@ class CommitmentsHypotheses extends base_command_1.BaseCommand {
|
|
|
55
55
|
this.handleApiError(err);
|
|
56
56
|
}
|
|
57
57
|
if (flags.json) {
|
|
58
|
+
// One JSON document and nothing else: has_more / next_cursor are in it.
|
|
58
59
|
this.log(JSON.stringify(response, null, 2));
|
|
60
|
+
return;
|
|
59
61
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
(0, commitments_1.renderCommitmentHypotheses)(response, (line) => this.log(line), { emptyMessage });
|
|
71
|
-
}
|
|
62
|
+
// A filtered-out list is not an empty ledger — say which filter did it
|
|
63
|
+
// (OSK-10953).
|
|
64
|
+
const filters = [
|
|
65
|
+
flags.status ? `--status ${flags.status}` : null,
|
|
66
|
+
flags['investigation-key'] ? `--investigation-key ${flags['investigation-key']}` : null,
|
|
67
|
+
].filter(Boolean);
|
|
68
|
+
const emptyMessage = filters.length
|
|
69
|
+
? `No hypotheses match ${filters.join(' ')}.`
|
|
70
|
+
: 'No hypotheses recorded.';
|
|
71
|
+
(0, commitments_1.renderCommitmentHypotheses)(response, (line) => this.log(line), { emptyMessage });
|
|
72
72
|
(0, commitments_1.renderListPageHint)(response, (line) => this.log(line));
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -71,6 +71,11 @@ function formatNextTick(projection) {
|
|
|
71
71
|
// is entirely in that: a reader who thinks a check just ran will misread
|
|
72
72
|
// every number on the commitment afterwards.
|
|
73
73
|
'Projection only — no check was recorded, no budget spent, no action routed.',
|
|
74
|
+
// And what it does not MODEL (OSK-21104): it decides from the evidence alone. A real Check also
|
|
75
|
+
// applies the repeat-evidence window, earlier Runs and owed retries, today's Run budget, the
|
|
76
|
+
// dispatch breaker and the attention contract, so it can stop sooner than this, or run a
|
|
77
|
+
// retry this does not show. Without the sentence a projected `enqueue_agent_turn` reads as a promise.
|
|
78
|
+
"It decides from the evidence alone: a real check also applies the repeat-evidence window, earlier runs and owed retries, today's run budget, the dispatch breaker and the attention contract, so it can stop sooner (or run a retry) than shown here.",
|
|
74
79
|
'',
|
|
75
80
|
`Posture: ${decision.posture ?? '-'}`,
|
|
76
81
|
`Health: ${decision.health ?? '-'}`,
|
|
@@ -152,25 +152,26 @@ class CommitmentsObservations extends base_command_1.BaseCommand {
|
|
|
152
152
|
this.handleApiError(err);
|
|
153
153
|
}
|
|
154
154
|
if (flags.json) {
|
|
155
|
+
// One JSON document and nothing else: has_more / next_cursor are in it
|
|
156
|
+
// (OSK-21118).
|
|
155
157
|
this.printJsonResult(response);
|
|
158
|
+
return;
|
|
156
159
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
(0, commitments_1.renderCommitmentObservations)(response, (line) => this.log(line), { emptyMessage });
|
|
173
|
-
}
|
|
160
|
+
// "The commitment has none" and "your filter matched none" are different
|
|
161
|
+
// facts; a filter that empties the list must not claim the first
|
|
162
|
+
// (OSK-10953).
|
|
163
|
+
const filters = [
|
|
164
|
+
flags.latest ? '--latest' : null,
|
|
165
|
+
flags['declared-only'] ? '--declared-only' : null,
|
|
166
|
+
flags['changed-only'] ? '--changed-only' : null,
|
|
167
|
+
flags.since ? `--since ${flags.since}` : null,
|
|
168
|
+
].filter(Boolean);
|
|
169
|
+
const emptyMessage = filters.length
|
|
170
|
+
? `No observations match ${filters.join(' ')}.`
|
|
171
|
+
: 'No observations recorded.';
|
|
172
|
+
if (response?.truncated)
|
|
173
|
+
this.log(`TRUNCATED: ${response.omitted} current keys omitted; increase --limit (max 200).`);
|
|
174
|
+
(0, commitments_1.renderCommitmentObservations)(response, (line) => this.log(line), { emptyMessage });
|
|
174
175
|
(0, commitments_1.renderListPageHint)(response, (line) => this.log(line));
|
|
175
176
|
}
|
|
176
177
|
}
|
|
@@ -41,7 +41,8 @@ class CommitmentsPackList extends base_command_1.BaseCommand {
|
|
|
41
41
|
(0, format_1.renderTable)(rows.map((pack) => ({
|
|
42
42
|
id: String(pack.id),
|
|
43
43
|
version: String(pack.version),
|
|
44
|
-
|
|
44
|
+
// The catalogue names a Pack `label`; reading only `title` printed a blank column for all eight.
|
|
45
|
+
title: String(pack.label || pack.title || ''),
|
|
45
46
|
})), [
|
|
46
47
|
// No maxWidth: a clipped pack id cannot be pasted into `pack plan --pack` (OSK-6175).
|
|
47
48
|
{ key: 'id', header: 'PACK ID' },
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
import { type CommitmentPackPlanResponse } from '../../../lib/commitments';
|
|
3
|
+
/**
|
|
4
|
+
* Lines for what the plan says will stop the loop from ever being activated. `bind` would still
|
|
5
|
+
* write a draft, so a reader who sees only "Nothing was created" must also see this.
|
|
6
|
+
*/
|
|
7
|
+
export declare function formatReadiness(readiness: CommitmentPackPlanResponse['readiness']): string[];
|
|
2
8
|
/**
|
|
3
9
|
* Draft what a Pack WOULD create, without creating it.
|
|
4
10
|
*
|
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatReadiness = formatReadiness;
|
|
3
4
|
const core_1 = require("@oclif/core");
|
|
4
5
|
const base_command_1 = require("../../../base-command");
|
|
5
6
|
const commitments_1 = require("../../../lib/commitments");
|
|
7
|
+
/**
|
|
8
|
+
* Lines for what the plan says will stop the loop from ever being activated. `bind` would still
|
|
9
|
+
* write a draft, so a reader who sees only "Nothing was created" must also see this.
|
|
10
|
+
*/
|
|
11
|
+
function formatReadiness(readiness) {
|
|
12
|
+
if (!readiness?.length)
|
|
13
|
+
return [];
|
|
14
|
+
const lines = [];
|
|
15
|
+
for (const item of readiness) {
|
|
16
|
+
lines.push(`Not ready: ${item.label} — ${item.reason}`);
|
|
17
|
+
if (item.hint)
|
|
18
|
+
lines.push(` ${item.hint}`);
|
|
19
|
+
}
|
|
20
|
+
lines.push(' `bind` would still create the draft, but `pack activate` will be refused until this is fixed.');
|
|
21
|
+
return lines;
|
|
22
|
+
}
|
|
6
23
|
/**
|
|
7
24
|
* Draft what a Pack WOULD create, without creating it.
|
|
8
25
|
*
|
|
@@ -87,6 +104,8 @@ class CommitmentsPackPlan extends base_command_1.BaseCommand {
|
|
|
87
104
|
const holder = placement.holder === 'space_lead' ? ' (the Space lead)' : '';
|
|
88
105
|
this.log(`Space loop: ${placement.spaceId}, held by ${placement.agentId}${holder}`);
|
|
89
106
|
}
|
|
107
|
+
for (const line of formatReadiness(result.readiness))
|
|
108
|
+
this.log(line);
|
|
90
109
|
this.log('\nNothing was created. Pass this digest to `skrr commitments pack bind --plan-digest`.');
|
|
91
110
|
}
|
|
92
111
|
}
|
|
@@ -35,7 +35,26 @@ export declare function nextRunsLines(report: {
|
|
|
35
35
|
verdict?: string;
|
|
36
36
|
nextRuns?: string[];
|
|
37
37
|
}): string[];
|
|
38
|
+
/**
|
|
39
|
+
* The first line of a preflight. `Ready to run` is a statement about activation (no blocking gate),
|
|
40
|
+
* and it sat directly above a spend-gate warning that the daily Run budget is 0, i.e. that no agent
|
|
41
|
+
* turn can ever start (OSK-21224). The verdict stays `ready` on purpose: a zero ACTION budget does
|
|
42
|
+
* not stop the sensing lane, so refusing activation would be wrong for a Commitment that only
|
|
43
|
+
* observes. The headline carries the caveat instead of contradicting the gate below it.
|
|
44
|
+
*/
|
|
45
|
+
export declare function preflightHeadline(report: Pick<CommitmentPreflightReport, 'verdict' | 'gates'>, persisted: boolean): string;
|
|
38
46
|
export declare function preflightGateLines(gate: PreflightGate, verbose?: boolean): string[];
|
|
47
|
+
/**
|
|
48
|
+
* The `Attention:` footer, and under it the settings behind the verdict (OSK-21120).
|
|
49
|
+
*
|
|
50
|
+
* "delivery allowed now" is the same words for a cap of 1, a mute lifted and no limit at all, so
|
|
51
|
+
* the cap, the gap and the no-reply rule are said beside it. `policy` is the stored policy the
|
|
52
|
+
* report was computed from, or the unsaved one under `--from-json`; without it nothing is said
|
|
53
|
+
* about the settings, rather than a guess. The raw reason code (`policy_nudge_muted`) is printed only
|
|
54
|
+
* with `--verbose`: beside the sentence it said the same thing twice, in a vocabulary nobody types
|
|
55
|
+
* (OSK-21124).
|
|
56
|
+
*/
|
|
57
|
+
export declare function attentionFooterLines(attention: CommitmentPreflightReport['attention'] | undefined, policy?: Record<string, any> | null, verbose?: boolean): string[];
|
|
39
58
|
export default class CommitmentsPreflight extends BaseCommand {
|
|
40
59
|
static description: string;
|
|
41
60
|
static examples: string[];
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.nextRunsLines = nextRunsLines;
|
|
4
|
+
exports.preflightHeadline = preflightHeadline;
|
|
4
5
|
exports.preflightGateLines = preflightGateLines;
|
|
6
|
+
exports.attentionFooterLines = attentionFooterLines;
|
|
5
7
|
const core_1 = require("@oclif/core");
|
|
6
8
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
7
9
|
const base_command_1 = require("../../base-command");
|
|
8
10
|
const commitments_1 = require("../../lib/commitments");
|
|
9
11
|
const prompt_1 = require("../../lib/prompt");
|
|
12
|
+
const commitment_attention_copy_1 = require("../../lib/commitment-attention-copy");
|
|
10
13
|
const preflight_copy_1 = require("../../lib/preflight-copy");
|
|
11
14
|
/**
|
|
12
15
|
* The lines one preflight gate contributes.
|
|
@@ -41,6 +44,25 @@ function nextRunsLines(report) {
|
|
|
41
44
|
: 'Next runs:';
|
|
42
45
|
return ['', header, ...report.nextRuns.map((run) => ` ${run}`)];
|
|
43
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* The first line of a preflight. `Ready to run` is a statement about activation (no blocking gate),
|
|
49
|
+
* and it sat directly above a spend-gate warning that the daily Run budget is 0, i.e. that no agent
|
|
50
|
+
* turn can ever start (OSK-21224). The verdict stays `ready` on purpose: a zero ACTION budget does
|
|
51
|
+
* not stop the sensing lane, so refusing activation would be wrong for a Commitment that only
|
|
52
|
+
* observes. The headline carries the caveat instead of contradicting the gate below it.
|
|
53
|
+
*/
|
|
54
|
+
function preflightHeadline(report, persisted) {
|
|
55
|
+
const label = persisted ? 'Preflight' : 'Pre-create preview (nothing persisted)';
|
|
56
|
+
if (report.verdict === 'blocked')
|
|
57
|
+
return `${label}: Run is blocked`;
|
|
58
|
+
if (report.verdict !== 'ready')
|
|
59
|
+
return `${label}: A capability or configuration check is still needed`;
|
|
60
|
+
const reasons = report.gates?.find((gate) => gate.id === 'budget_bounds')?.detail?.reasons;
|
|
61
|
+
const noActionRuns = Array.isArray(reasons) && reasons.includes('action_runs_zero');
|
|
62
|
+
return noActionRuns
|
|
63
|
+
? `${label}: Ready to run, but its daily Run budget is 0, so no agent turn will start`
|
|
64
|
+
: `${label}: Ready to run`;
|
|
65
|
+
}
|
|
44
66
|
function preflightGateLines(gate, verbose = false) {
|
|
45
67
|
// "Could it contact you now?" is not a Run gate. It answers whether a message
|
|
46
68
|
// would reach the owner, and a limit the owner set themselves (zero nudges a day,
|
|
@@ -50,15 +72,36 @@ function preflightGateLines(gate, verbose = false) {
|
|
|
50
72
|
// (OSK-15420). Say what it is in words, and which setting moves it.
|
|
51
73
|
if (gate.id === 'attention' && gate.verdict === 'block') {
|
|
52
74
|
const copy = (0, data_provider_1.describeSuppression)(gate.reason);
|
|
75
|
+
// "Held until your quiet hours end." named no time and no zone; the report has both (OSK-21122).
|
|
76
|
+
const quietEnd = gate.reason === 'policy_quiet_hours'
|
|
77
|
+
? (0, commitment_attention_copy_1.describeQuietHoursEnd)(gate.detail?.quietHours)
|
|
78
|
+
: null;
|
|
53
79
|
const lines = [
|
|
54
80
|
` ${'info'.padEnd(5)} ${gate.label} — ${copy.title.toLowerCase()}${verbose && gate.reason ? ` (${gate.reason})` : ''}`,
|
|
55
|
-
` ${copy.detail}`,
|
|
81
|
+
` ${quietEnd ?? copy.detail}`,
|
|
56
82
|
];
|
|
57
|
-
|
|
83
|
+
// Whose quiet hours these are, when they are not the Commitment's own (OSK-21151): a reader
|
|
84
|
+
// would otherwise be sent to a field this Commitment does not hold.
|
|
85
|
+
const note = gate.detail?.note;
|
|
86
|
+
if (typeof note === 'string' && note.trim())
|
|
87
|
+
lines.push(` ${note.trim()}`);
|
|
88
|
+
// The policy field is a path into JSON, not something to type: the sentence above says what
|
|
89
|
+
// it means, so the path joins the code behind --verbose (OSK-21124).
|
|
90
|
+
if (verbose && copy.settingKey)
|
|
58
91
|
lines.push(` Setting: ${copy.settingKey}`);
|
|
59
92
|
return lines;
|
|
60
93
|
}
|
|
61
|
-
|
|
94
|
+
// A `block` the report itself marks advisory stops nothing: it is not a Run-admission gate, so it
|
|
95
|
+
// never feeds the verdict or `pack activate`. Printed BLOCK, `pack preflight` read "ready" above
|
|
96
|
+
// two BLOCK lines (dogfooded on a goal_advance draft); the tag has to mean what the report means.
|
|
97
|
+
const advisoryBlock = gate.verdict === 'block' && gate.admission === 'advisory';
|
|
98
|
+
const mark = advisoryBlock
|
|
99
|
+
? 'info'
|
|
100
|
+
: gate.verdict === 'pass'
|
|
101
|
+
? 'ok'
|
|
102
|
+
: gate.verdict === 'block'
|
|
103
|
+
? 'BLOCK'
|
|
104
|
+
: 'warn';
|
|
62
105
|
// A BLOCKING gate always states its reason. `ok` gates got a helpful `note`
|
|
63
106
|
// and `warn` gates got a reason token, and the BLOCK gates — the only ones
|
|
64
107
|
// that stop the run — got the label and nothing: two of them side by side,
|
|
@@ -75,7 +118,8 @@ function preflightGateLines(gate, verbose = false) {
|
|
|
75
118
|
const hasNote = typeof note === 'string' && Boolean(note.trim());
|
|
76
119
|
const showReason = verbose || (gate.verdict === 'block' && !hasNote);
|
|
77
120
|
const lines = [
|
|
78
|
-
` ${mark.padEnd(5)} ${gate.label}${showReason && gate.reason ? ` — ${gate.reason}` : ''}
|
|
121
|
+
` ${mark.padEnd(5)} ${gate.label}${showReason && gate.reason ? ` — ${gate.reason}` : ''}` +
|
|
122
|
+
(advisoryBlock ? ' (advisory: does not stop a run)' : ''),
|
|
79
123
|
];
|
|
80
124
|
if (hasNote) {
|
|
81
125
|
lines.push(` ${String(note).trim()}`);
|
|
@@ -92,6 +136,13 @@ function preflightGateLines(gate, verbose = false) {
|
|
|
92
136
|
else if (status === 'invalid') {
|
|
93
137
|
lines.push(' Active owner rules: unknown (stored rules invalid).');
|
|
94
138
|
}
|
|
139
|
+
else if (status === 'archived' &&
|
|
140
|
+
typeof count === 'number' &&
|
|
141
|
+
Number.isSafeInteger(count) &&
|
|
142
|
+
count >= 0) {
|
|
143
|
+
// The Compass is archived, not unreadable: its rules are counted, and still enforced.
|
|
144
|
+
lines.push(` Active owner rules: ${count} (on the archived Compass, still enforced).`);
|
|
145
|
+
}
|
|
95
146
|
else if (status === 'available' &&
|
|
96
147
|
typeof count === 'number' &&
|
|
97
148
|
Number.isSafeInteger(count) &&
|
|
@@ -116,6 +167,29 @@ function preflightGateLines(gate, verbose = false) {
|
|
|
116
167
|
lines.push(` ${sentence}`);
|
|
117
168
|
return lines;
|
|
118
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* The `Attention:` footer, and under it the settings behind the verdict (OSK-21120).
|
|
172
|
+
*
|
|
173
|
+
* "delivery allowed now" is the same words for a cap of 1, a mute lifted and no limit at all, so
|
|
174
|
+
* the cap, the gap and the no-reply rule are said beside it. `policy` is the stored policy the
|
|
175
|
+
* report was computed from, or the unsaved one under `--from-json`; without it nothing is said
|
|
176
|
+
* about the settings, rather than a guess. The raw reason code (`policy_nudge_muted`) is printed only
|
|
177
|
+
* with `--verbose`: beside the sentence it said the same thing twice, in a vocabulary nobody types
|
|
178
|
+
* (OSK-21124).
|
|
179
|
+
*/
|
|
180
|
+
function attentionFooterLines(attention, policy, verbose = false) {
|
|
181
|
+
const code = verbose && attention?.suppressedBy ? ` (${attention.suppressedBy})` : '';
|
|
182
|
+
const lines = [
|
|
183
|
+
'',
|
|
184
|
+
`Attention: ${attention?.allowed ? 'delivery allowed now' : `held back — ${(0, data_provider_1.describeSuppression)(attention?.suppressedBy).title.toLowerCase()}${code}`}`,
|
|
185
|
+
];
|
|
186
|
+
if (policy) {
|
|
187
|
+
for (const line of (0, commitment_attention_copy_1.nudgeSettingLines)((0, commitment_attention_copy_1.nudgeSettingsFromPolicy)(policy)))
|
|
188
|
+
lines.push(` ${line}`);
|
|
189
|
+
lines.push(` Quiet hours: ${(0, commitment_attention_copy_1.describeQuietHours)(policy.quietHours)}`);
|
|
190
|
+
}
|
|
191
|
+
return lines;
|
|
192
|
+
}
|
|
119
193
|
class CommitmentsPreflight extends base_command_1.BaseCommand {
|
|
120
194
|
static description = 'Dry-run a commitment: runtime gates, capabilities, attention policy and upcoming runs (runs nothing)';
|
|
121
195
|
static examples = [
|
|
@@ -151,16 +225,37 @@ class CommitmentsPreflight extends base_command_1.BaseCommand {
|
|
|
151
225
|
this.error('--next must be between 1 and 10', { exit: 1 });
|
|
152
226
|
}
|
|
153
227
|
let report;
|
|
228
|
+
// The policy the verdict was computed from, for the settings printed under it.
|
|
229
|
+
let policy = null;
|
|
154
230
|
try {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
231
|
+
if (args.id) {
|
|
232
|
+
report = await commitments_1.commitmentApi.preflight(args.id, flags.next);
|
|
233
|
+
try {
|
|
234
|
+
policy =
|
|
235
|
+
(await commitments_1.commitmentApi.get(args.id))?.commitment?.policy ?? null;
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
policy = null;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
const rawBody = await (0, prompt_1.readJsonBody)(flags['from-json']);
|
|
243
|
+
const draft = (0, commitments_1.normalizeCreateBody)(rawBody);
|
|
244
|
+
const ignoredWarning = (0, commitments_1.ignoredCreateKeysWarning)((0, commitments_1.ignoredCreateKeys)(rawBody));
|
|
245
|
+
if (ignoredWarning)
|
|
246
|
+
this.warn(ignoredWarning);
|
|
247
|
+
policy = draft.policy ?? {};
|
|
248
|
+
const quietHoursProblem = (0, commitment_attention_copy_1.quietHoursInputProblem)(policy);
|
|
249
|
+
if (quietHoursProblem)
|
|
250
|
+
throw new Error(quietHoursProblem);
|
|
251
|
+
report = await commitments_1.commitmentApi.draftPreflight({
|
|
252
|
+
commitment: draft,
|
|
159
253
|
...(flags['event-fixture']
|
|
160
254
|
? { eventFixture: await (0, prompt_1.readJsonBody)(flags['event-fixture']) }
|
|
161
255
|
: {}),
|
|
162
256
|
...(flags.next !== undefined ? { nextRunCount: flags.next } : {}),
|
|
163
257
|
});
|
|
258
|
+
}
|
|
164
259
|
}
|
|
165
260
|
catch (err) {
|
|
166
261
|
this.handleApiError(err);
|
|
@@ -170,7 +265,9 @@ class CommitmentsPreflight extends base_command_1.BaseCommand {
|
|
|
170
265
|
this.log(JSON.stringify(report, null, 2));
|
|
171
266
|
return;
|
|
172
267
|
}
|
|
173
|
-
this.log(
|
|
268
|
+
this.log(preflightHeadline(report, Boolean(args.id)));
|
|
269
|
+
for (const line of (0, commitments_1.activationRefusalLines)(report.activation))
|
|
270
|
+
this.log(line);
|
|
174
271
|
// Whose permissions the run will use (OSK-11975), before the gates, so an
|
|
175
272
|
// Execute Commitment on a plan-mode Agent is the first thing read
|
|
176
273
|
// (OSK-12065).
|
|
@@ -211,7 +308,8 @@ class CommitmentsPreflight extends base_command_1.BaseCommand {
|
|
|
211
308
|
(endpoint.reason ? ` (${endpoint.reason})` : '') +
|
|
212
309
|
(!endpoint.available && endpoint.detail ? ` — ${endpoint.detail}` : ''));
|
|
213
310
|
}
|
|
214
|
-
|
|
311
|
+
for (const line of attentionFooterLines(report.attention, policy, flags.verbose))
|
|
312
|
+
this.log(line);
|
|
215
313
|
if (report.verdict === 'blocked')
|
|
216
314
|
process.exitCode = 1;
|
|
217
315
|
}
|
|
@@ -82,6 +82,14 @@ function formatTriggerStatus(status) {
|
|
|
82
82
|
'(fired or disabled — cannot wake this commitment)');
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
+
// The plan can be converged and every row enabled while nothing can wake (Always-On off). `convergence`
|
|
86
|
+
// is a fact about the rows; this is the other fact, from the same projection `commitments status` reads.
|
|
87
|
+
const wake = status.wake;
|
|
88
|
+
if (wake?.held) {
|
|
89
|
+
lines.push(`Wakes: HELD — ${wake.reason ?? 'blocked'}`);
|
|
90
|
+
if (wake.detail)
|
|
91
|
+
lines.push(` ${String(wake.detail).replace(/\s+/g, ' ').trim()}`);
|
|
92
|
+
}
|
|
85
93
|
const bindings = Array.isArray(status.bindings) ? status.bindings : [];
|
|
86
94
|
lines.push('');
|
|
87
95
|
if (bindings.length === 0) {
|
|
@@ -49,6 +49,7 @@ export default class CommitmentsUpdate extends BaseCommand {
|
|
|
49
49
|
'cadence-mode': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
50
50
|
timezone: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
51
51
|
isolation: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
52
|
+
'max-nudges': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
52
53
|
'max-concurrent-runs': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
53
54
|
'concurrency-reason': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
54
55
|
};
|
|
@@ -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() {
|