@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
|
@@ -5,6 +5,7 @@ const base_command_1 = require("../../../base-command");
|
|
|
5
5
|
const prompt_1 = require("../../../lib/prompt");
|
|
6
6
|
const lookbackPlans_1 = require("../../../lib/lookbackPlans");
|
|
7
7
|
const lookbackPlanHelp_1 = require("../../../lib/lookbackPlanHelp");
|
|
8
|
+
const followups_1 = require("../../../lib/followups");
|
|
8
9
|
class LookbackPlansCreate extends base_command_1.BaseCommand {
|
|
9
10
|
static description = 'Schedule a bounded plan of 1–10 lookbacks, each free to stay silent\n\n' + lookbackPlanHelp_1.LOOKBACK_PLAN_INPUT_HELP +
|
|
10
11
|
'\n\nCreate also accepts {"agentId":"...","pinnedConversationId":"...","plan":{...}}. Source and delivery destination are separate; pin the original conversation to return there.';
|
|
@@ -27,7 +28,17 @@ class LookbackPlansCreate extends base_command_1.BaseCommand {
|
|
|
27
28
|
}
|
|
28
29
|
try {
|
|
29
30
|
const result = await lookbackPlans_1.lookbackPlansApi.create(body);
|
|
30
|
-
|
|
31
|
+
if (flags.json) {
|
|
32
|
+
this.log(JSON.stringify(result, null, 2));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// The four create commands say when the server recorded weaker provenance than the CLI
|
|
36
|
+
// claimed; a plan is recorded the same way (`producerDowngraded` is in the route's answer)
|
|
37
|
+
// and only `plans show` ever said so.
|
|
38
|
+
const notice = (0, followups_1.producerDowngradeNotice)(result);
|
|
39
|
+
if (notice)
|
|
40
|
+
this.log(notice);
|
|
41
|
+
this.log((0, lookbackPlans_1.lookbackArmingLine)(result));
|
|
31
42
|
}
|
|
32
43
|
catch (err) {
|
|
33
44
|
if ((0, lookbackPlans_1.isLookbackMutationOutcomeUnknown)(err)) {
|
|
@@ -9,6 +9,7 @@ const GATE_LABEL = {
|
|
|
9
9
|
exempt_user_directed: 'fires without approval (you asked for it)',
|
|
10
10
|
exempt_system: 'fires without approval (system)',
|
|
11
11
|
user_directed_guarded: 'fires without approval (you asked for it); still held by quiet hours, approval-only action classes and the spend cap',
|
|
12
|
+
exempt_notification: 'delivered to you as a notification (no agent turn, so no approval step applies)',
|
|
12
13
|
autonomy_ladder: "follows the agent's autonomy mode",
|
|
13
14
|
approval_ladder: 'needs approval unless the autonomy mode allows it',
|
|
14
15
|
};
|
|
@@ -49,6 +50,12 @@ class FollowupsShow extends base_command_1.BaseCommand {
|
|
|
49
50
|
'settled',
|
|
50
51
|
row.terminal ? `${row.terminalAt ?? '—'} by ${row.terminalBy ?? 'unknown'}` : undefined,
|
|
51
52
|
],
|
|
53
|
+
[
|
|
54
|
+
'role',
|
|
55
|
+
row.slaFallback
|
|
56
|
+
? 'the SLA backstop of a paired watch, not a second watch: it escalates that watch when its wait outlives the deadline, and cancelling it leaves the watch without one'
|
|
57
|
+
: undefined,
|
|
58
|
+
],
|
|
52
59
|
['deadline', row.deadlineAt],
|
|
53
60
|
[
|
|
54
61
|
'waiting',
|
|
@@ -56,6 +63,12 @@ class FollowupsShow extends base_command_1.BaseCommand {
|
|
|
56
63
|
? `on an offline machine since ${row.parkedAt} (escalates after 60 minutes)`
|
|
57
64
|
: undefined,
|
|
58
65
|
],
|
|
66
|
+
[
|
|
67
|
+
'held',
|
|
68
|
+
row.held && !row.terminal
|
|
69
|
+
? `moved to ${row.held.until} — ${row.held.note ?? row.held.reason ?? 'it could not run when it came due'}`
|
|
70
|
+
: undefined,
|
|
71
|
+
],
|
|
59
72
|
['escalated to', row.escalatedInitiativeId],
|
|
60
73
|
]) {
|
|
61
74
|
if (value)
|
|
@@ -242,7 +242,7 @@ class FollowupsWatch extends base_command_1.BaseCommand {
|
|
|
242
242
|
this.log(producerNotice);
|
|
243
243
|
const row = response.followup;
|
|
244
244
|
if (response.reused) {
|
|
245
|
-
this.log(
|
|
245
|
+
this.log((0, followups_1.reusedWithoutChangeMessage)(row, 'an identical watch'));
|
|
246
246
|
return;
|
|
247
247
|
}
|
|
248
248
|
if (response.dropped) {
|
|
@@ -6,6 +6,7 @@ export default class GoalsCreate extends BaseCommand {
|
|
|
6
6
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
7
|
'from-json': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
8
|
title: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'idempotency-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
10
|
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
11
|
level: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
12
|
'target-date': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -24,6 +24,9 @@ class GoalsCreate extends base_command_1.BaseCommand {
|
|
|
24
24
|
description: 'Path to a JSON file (or "-" for stdin) to use as the request body',
|
|
25
25
|
}),
|
|
26
26
|
title: core_1.Flags.string({ description: 'Goal title (required unless set via --from-json)' }),
|
|
27
|
+
'idempotency-key': core_1.Flags.string({
|
|
28
|
+
description: 'Stable key for retries of this exact Goal creation request',
|
|
29
|
+
}),
|
|
27
30
|
description: core_1.Flags.string({ description: 'Goal description' }),
|
|
28
31
|
level: core_1.Flags.string({
|
|
29
32
|
description: 'Goal level',
|
|
@@ -126,7 +129,7 @@ class GoalsCreate extends base_command_1.BaseCommand {
|
|
|
126
129
|
payload.labelIds = resolvedLabelIds;
|
|
127
130
|
let created;
|
|
128
131
|
try {
|
|
129
|
-
created = await data_provider_1.dataService.createGoal(payload);
|
|
132
|
+
created = await data_provider_1.dataService.createGoal(payload, flags['idempotency-key'] ? { idempotencyKey: flags['idempotency-key'] } : undefined);
|
|
130
133
|
if (flags.space) {
|
|
131
134
|
const goalId = created.id;
|
|
132
135
|
if (!goalId || typeof goalId !== 'string') {
|
|
@@ -35,6 +35,17 @@ export type GoalPlannerView = {
|
|
|
35
35
|
* choose between those two, because the CLI cannot tell them apart.
|
|
36
36
|
*/
|
|
37
37
|
tickLockedAt: string | null;
|
|
38
|
+
/**
|
|
39
|
+
* Why an armed planner will not tick, or null. The scheduler only creates the planner's trigger
|
|
40
|
+
* for an ACTIVE, unarchived Goal (`GoalPlanner.shouldScheduleGoal`); for any other status the
|
|
41
|
+
* cadence is stored and `nextTickAt` is set, but nothing ever fires. Stating the cadence alone
|
|
42
|
+
* read as "armed" (dogfooded: a `planned` Goal showed `nextTickAt` in the past for good).
|
|
43
|
+
*/
|
|
44
|
+
notRunning: {
|
|
45
|
+
goalId: string | null;
|
|
46
|
+
reason: 'archived' | 'status';
|
|
47
|
+
status: string | null;
|
|
48
|
+
} | null;
|
|
38
49
|
};
|
|
39
50
|
/** Read the planner state off a Goal document (lean or typed). */
|
|
40
51
|
export declare function goalPlannerView(goal: Record<string, unknown> | undefined | null): GoalPlannerView;
|
|
@@ -13,6 +13,14 @@ function goalPlannerView(goal) {
|
|
|
13
13
|
const g = (goal ?? {});
|
|
14
14
|
const tickIntervalMs = typeof g.tickIntervalMs === 'number' ? g.tickIntervalMs : null;
|
|
15
15
|
const enabled = tickIntervalMs != null;
|
|
16
|
+
const status = str(g.status);
|
|
17
|
+
const notRunning = !enabled
|
|
18
|
+
? null
|
|
19
|
+
: g.archivedAt
|
|
20
|
+
? { goalId: str(g.id), reason: 'archived', status }
|
|
21
|
+
: status && status !== 'active'
|
|
22
|
+
? { goalId: str(g.id), reason: 'status', status }
|
|
23
|
+
: null;
|
|
16
24
|
return {
|
|
17
25
|
enabled,
|
|
18
26
|
tickIntervalMs,
|
|
@@ -21,6 +29,7 @@ function goalPlannerView(goal) {
|
|
|
21
29
|
nextTickAt: enabled ? str(g.nextTickAt) : null,
|
|
22
30
|
lastTickedAt: str(g.lastTickedAt),
|
|
23
31
|
tickLockedAt: str(g.tickLockedAt),
|
|
32
|
+
notRunning,
|
|
24
33
|
};
|
|
25
34
|
}
|
|
26
35
|
/**
|
|
@@ -44,6 +53,13 @@ function renderGoalPlannerLines(view) {
|
|
|
44
53
|
lines.push(` nextTickAt: ${view.nextTickAt}`);
|
|
45
54
|
if (view.lastTickedAt)
|
|
46
55
|
lines.push(` lastTickedAt: ${view.lastTickedAt}`);
|
|
56
|
+
if (view.notRunning) {
|
|
57
|
+
const { goalId, reason, status } = view.notRunning;
|
|
58
|
+
lines.push(reason === 'archived'
|
|
59
|
+
? ' not running: this Goal is archived, and the planner only ticks for an active Goal'
|
|
60
|
+
: ` not running: this Goal is ${status}, and the planner only ticks for an active Goal` +
|
|
61
|
+
` — \`skrr goals update ${goalId ?? '<goal-id>'} --status active\``);
|
|
62
|
+
}
|
|
47
63
|
if (view.tickLockedAt) {
|
|
48
64
|
lines.push(` tickLockedAt: ${view.tickLockedAt} (a claimed tick has not released this lock)`);
|
|
49
65
|
}
|
|
@@ -4,20 +4,7 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
6
|
const format_1 = require("../../lib/format");
|
|
7
|
-
|
|
8
|
-
* The one class of goal change this log does not contain.
|
|
9
|
-
*
|
|
10
|
-
* `PATCH /api/goals/:goalId/planner-config` writes the goal through
|
|
11
|
-
* `Goal.findOneAndUpdate` directly rather than `GoalModel.updateGoal`, which is
|
|
12
|
-
* where `RevisionService` is called from — so arming, re-timing or disarming the
|
|
13
|
-
* auto-planner (and any `maxActiveTasks` change made through that route) leaves
|
|
14
|
-
* no revision. "Who turned the planner on for this goal, and when" is the audit
|
|
15
|
-
* question a shared goal actually raises, and the table answers it with silence.
|
|
16
|
-
*
|
|
17
|
-
* Naming the gap is the honest thing the CLI can do; closing it is a server
|
|
18
|
-
* change. DELETE THIS FOOTER once the planner-config route records a revision.
|
|
19
|
-
*/
|
|
20
|
-
const PLANNER_GAP_NOTE = 'Note: auto-planner changes made with `goals planner-config` are not recorded as revisions.';
|
|
7
|
+
const revision_actor_1 = require("../../lib/revision-actor");
|
|
21
8
|
class GoalsRevisions extends base_command_1.BaseCommand {
|
|
22
9
|
static description = 'List revisions for a goal';
|
|
23
10
|
static examples = [
|
|
@@ -47,25 +34,22 @@ class GoalsRevisions extends base_command_1.BaseCommand {
|
|
|
47
34
|
const items = result?.data ?? [];
|
|
48
35
|
if (items.length === 0) {
|
|
49
36
|
this.log('No revisions.');
|
|
50
|
-
this.log(PLANNER_GAP_NOTE);
|
|
51
37
|
return;
|
|
52
38
|
}
|
|
53
39
|
const rows = items.map((rev) => ({
|
|
54
40
|
version: String(rev.revisionNumber ?? '-'),
|
|
55
41
|
changeType: String(rev.changeType ?? '-'),
|
|
56
|
-
user:
|
|
42
|
+
user: (0, revision_actor_1.revisionActorLabel)(rev),
|
|
57
43
|
changes: String(Array.isArray(rev.changes) ? rev.changes.length : 0),
|
|
58
44
|
when: rev.createdAt ? String(rev.createdAt).slice(0, 19).replace('T', ' ') : '-',
|
|
59
45
|
}));
|
|
60
46
|
(0, format_1.renderTable)(rows, [
|
|
61
47
|
{ key: 'version', header: 'REV' },
|
|
62
48
|
{ key: 'changeType', header: 'CHANGE' },
|
|
63
|
-
{ key: 'user', header: '
|
|
49
|
+
{ key: 'user', header: 'ACTOR' },
|
|
64
50
|
{ key: 'changes', header: 'FIELDS' },
|
|
65
51
|
{ key: 'when', header: 'AT' },
|
|
66
52
|
], (line) => this.log(line));
|
|
67
|
-
this.log('');
|
|
68
|
-
this.log(PLANNER_GAP_NOTE);
|
|
69
53
|
}
|
|
70
54
|
}
|
|
71
55
|
exports.default = GoalsRevisions;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
2
|
/**
|
|
3
|
-
* Rename / describe / tag a machine.
|
|
3
|
+
* Rename / describe / tag a machine, and choose its icon.
|
|
4
4
|
*
|
|
5
5
|
* `preferences` is the ONLY user-editable part of a machine — identities,
|
|
6
6
|
* capabilities and lifecycle stay authoritative in the daemon, harness and
|
|
7
|
-
* lease records this aggregate reads. The name set here
|
|
8
|
-
* rename the machine for anyone else.
|
|
7
|
+
* lease records this aggregate reads. The name and icon set here are yours: they
|
|
8
|
+
* do not rename or re-draw the machine for anyone else.
|
|
9
9
|
*/
|
|
10
10
|
export default class MachinesUpdate extends BaseCommand {
|
|
11
11
|
static description: string;
|
|
@@ -19,6 +19,8 @@ export default class MachinesUpdate extends BaseCommand {
|
|
|
19
19
|
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
20
|
tag: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
21
|
'clear-tags': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
22
|
+
icon: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
'icon-file': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
24
|
};
|
|
23
25
|
run(): Promise<void>;
|
|
24
26
|
}
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
4
7
|
const base_command_1 = require("../../base-command");
|
|
8
|
+
const agent_visual_refs_1 = require("../../lib/agent-visual-refs");
|
|
5
9
|
const machines_1 = require("../../lib/machines");
|
|
6
10
|
/**
|
|
7
|
-
* Rename / describe / tag a machine.
|
|
11
|
+
* Rename / describe / tag a machine, and choose its icon.
|
|
8
12
|
*
|
|
9
13
|
* `preferences` is the ONLY user-editable part of a machine — identities,
|
|
10
14
|
* capabilities and lifecycle stay authoritative in the daemon, harness and
|
|
11
|
-
* lease records this aggregate reads. The name set here
|
|
12
|
-
* rename the machine for anyone else.
|
|
15
|
+
* lease records this aggregate reads. The name and icon set here are yours: they
|
|
16
|
+
* do not rename or re-draw the machine for anyone else.
|
|
13
17
|
*/
|
|
14
18
|
class MachinesUpdate extends base_command_1.BaseCommand {
|
|
15
|
-
static description = 'Rename a machine,
|
|
19
|
+
static description = 'Rename a machine, set its description, tags and icon';
|
|
16
20
|
static examples = [
|
|
17
21
|
'<%= config.bin %> machines update 03548116 --name "Work laptop"',
|
|
18
22
|
'<%= config.bin %> machines update 03548116 --tag personal --tag macbook',
|
|
19
23
|
'<%= config.bin %> machines update 03548116 --clear-tags',
|
|
24
|
+
'<%= config.bin %> machines update 03548116 --icon laptop',
|
|
25
|
+
'<%= config.bin %> machines update 03548116 --icon none',
|
|
26
|
+
'<%= config.bin %> machines update 03548116 --icon-file ./mac.png',
|
|
20
27
|
];
|
|
21
28
|
static args = {
|
|
22
29
|
machine: core_1.Args.string({
|
|
@@ -37,6 +44,15 @@ class MachinesUpdate extends base_command_1.BaseCommand {
|
|
|
37
44
|
description: 'Remove all tags',
|
|
38
45
|
exclusive: ['tag'],
|
|
39
46
|
}),
|
|
47
|
+
icon: core_1.Flags.string({
|
|
48
|
+
description: `Icon for this machine: ${data_provider_1.MACHINE_ICON_PRESET_IDS.join(', ')}. ` +
|
|
49
|
+
'"none" goes back to the default.',
|
|
50
|
+
exclusive: ['icon-file'],
|
|
51
|
+
}),
|
|
52
|
+
'icon-file': core_1.Flags.string({
|
|
53
|
+
description: 'Use your own image as the icon (.png, .jpg, .jpeg, .webp or .gif). It is resized to a square.',
|
|
54
|
+
exclusive: ['icon'],
|
|
55
|
+
}),
|
|
40
56
|
};
|
|
41
57
|
async run() {
|
|
42
58
|
this.requireAuth();
|
|
@@ -50,17 +66,61 @@ class MachinesUpdate extends base_command_1.BaseCommand {
|
|
|
50
66
|
patch.tags = [];
|
|
51
67
|
else if (flags.tag)
|
|
52
68
|
patch.tags = flags.tag;
|
|
53
|
-
if (
|
|
69
|
+
if (flags.icon !== undefined) {
|
|
70
|
+
try {
|
|
71
|
+
patch.icon = (0, machines_1.parseMachineIconFlag)(flags.icon);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
this.error(err.message, { exit: 1 });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Everything that can be refused without a request is refused before one is
|
|
78
|
+
// sent, so a typo'd path never leaves the other changes half applied.
|
|
79
|
+
let upload;
|
|
80
|
+
const iconFile = flags['icon-file'];
|
|
81
|
+
if (iconFile !== undefined) {
|
|
82
|
+
const type = (0, agent_visual_refs_1.imageUploadMimeType)(iconFile);
|
|
83
|
+
if (!type) {
|
|
84
|
+
this.error(`--icon-file must be a .png, .jpg, .jpeg, .webp or .gif image (got ${(0, node_path_1.basename)(iconFile)}).`, { exit: 1 });
|
|
85
|
+
}
|
|
86
|
+
let bytes;
|
|
87
|
+
try {
|
|
88
|
+
bytes = await (0, promises_1.readFile)(iconFile);
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
this.error(`--icon-file: cannot read ${iconFile} (${err.message}).`, {
|
|
92
|
+
exit: 1,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
upload = { bytes, type, filename: (0, node_path_1.basename)(iconFile) };
|
|
96
|
+
}
|
|
97
|
+
const hasPatch = Object.keys(patch).length > 0;
|
|
98
|
+
if (!hasPatch && !upload) {
|
|
54
99
|
// Sending an empty patch would return the machine unchanged and read as
|
|
55
100
|
// success, which is the wrong answer to "I asked you to change something".
|
|
56
|
-
this.error('Nothing to update. Pass --name, --description, --tag, or --
|
|
57
|
-
exit: 1,
|
|
58
|
-
});
|
|
101
|
+
this.error('Nothing to update. Pass --name, --description, --tag, --clear-tags, --icon, or --icon-file.', { exit: 1 });
|
|
59
102
|
}
|
|
60
103
|
let machine;
|
|
61
104
|
try {
|
|
62
105
|
const resolved = (0, machines_1.resolveMachineRef)(await (0, machines_1.listMachines)(), args.machine);
|
|
63
|
-
|
|
106
|
+
if (hasPatch)
|
|
107
|
+
machine = await (0, machines_1.updateMachine)(resolved.id, patch);
|
|
108
|
+
if (upload) {
|
|
109
|
+
const form = new FormData();
|
|
110
|
+
// Typed, or the route refuses it as application/octet-stream (OSK-9841).
|
|
111
|
+
form.append('file', new Blob([new Uint8Array(upload.bytes)], { type: upload.type }), upload.filename);
|
|
112
|
+
try {
|
|
113
|
+
await data_provider_1.dataService.uploadMachineIcon(resolved.id, form);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
if (hasPatch)
|
|
117
|
+
this.warn('The other changes were saved, but the icon was not uploaded.');
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
120
|
+
// The upload answers only the icon; read the machine back so what is
|
|
121
|
+
// printed is what is stored.
|
|
122
|
+
machine = await (0, machines_1.getMachine)(resolved.id);
|
|
123
|
+
}
|
|
64
124
|
}
|
|
65
125
|
catch (err) {
|
|
66
126
|
this.handleApiError(err);
|
|
@@ -77,6 +137,7 @@ class MachinesUpdate extends base_command_1.BaseCommand {
|
|
|
77
137
|
this.log(` description ${machine.preferences.description}`);
|
|
78
138
|
}
|
|
79
139
|
this.log(` tags ${machine.preferences?.tags?.join(', ') || '-'}`);
|
|
140
|
+
this.log(` icon ${(0, machines_1.describeMachineIcon)(machine.preferences?.icon)}`);
|
|
80
141
|
}
|
|
81
142
|
}
|
|
82
143
|
exports.default = MachinesUpdate;
|
|
@@ -31,7 +31,7 @@ class NorthstarsCreate extends base_command_1.BaseCommand {
|
|
|
31
31
|
min: 0,
|
|
32
32
|
}),
|
|
33
33
|
'max-active': core_1.Flags.integer({
|
|
34
|
-
description: 'Soft cap on simultaneously active commitments',
|
|
34
|
+
description: 'Soft cap on simultaneously active commitments (0 = no cap)',
|
|
35
35
|
min: 0,
|
|
36
36
|
}),
|
|
37
37
|
goal: core_1.Flags.string({
|
|
@@ -98,6 +98,8 @@ class NorthstarsCreate extends base_command_1.BaseCommand {
|
|
|
98
98
|
}
|
|
99
99
|
this.log(`Created ${created.id} — ${created.title} (${created.status})`);
|
|
100
100
|
this.log(`URL: ${created.url ?? '-'}`);
|
|
101
|
+
if (flags['max-active'] === 0)
|
|
102
|
+
this.log('Attention max active 0 (no cap)');
|
|
101
103
|
this.log(flags['review-interval-hours'] !== undefined
|
|
102
104
|
? `Review runs every ${flags['review-interval-hours']}h.`
|
|
103
105
|
: 'Review is manual — set --review-interval-hours or run `skrr northstars review-now`.');
|
|
@@ -22,6 +22,7 @@ export default class NorthstarsGovernanceConfigure extends BaseCommand {
|
|
|
22
22
|
allow: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
23
|
'require-approval-for': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
24
|
protect: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
|
+
'clear-protected': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
25
26
|
'max-intents-per-review': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
26
27
|
'max-auto-per-review': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
27
28
|
'max-auto-per-day': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -30,8 +31,11 @@ export default class NorthstarsGovernanceConfigure extends BaseCommand {
|
|
|
30
31
|
'max-interval-hours': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
31
32
|
'max-relative-change': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
32
33
|
'max-observation-runs-per-day': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
34
|
+
'clear-max-observation-runs-per-day': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
33
35
|
'max-runs-per-day': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
36
|
+
'clear-max-runs-per-day': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
34
37
|
'max-concurrent-runs': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
38
|
+
'clear-max-concurrent-runs': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
35
39
|
'critical-reserve': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
36
40
|
};
|
|
37
41
|
run(): Promise<void>;
|
|
@@ -19,6 +19,8 @@ class NorthstarsGovernanceConfigure extends base_command_1.BaseCommand {
|
|
|
19
19
|
'<%= config.bin %> northstars governance configure nst_abc123 --execution approval',
|
|
20
20
|
'<%= config.bin %> northstars governance configure nst_abc123 --execution bounded_auto --allow request_commitment_check --max-auto-per-day 3',
|
|
21
21
|
'<%= config.bin %> northstars governance configure nst_abc123 --protect cmt_1 --protect cmt_2',
|
|
22
|
+
'<%= config.bin %> northstars governance configure nst_abc123 --clear-protected',
|
|
23
|
+
'<%= config.bin %> northstars governance configure nst_abc123 --clear-max-runs-per-day',
|
|
22
24
|
];
|
|
23
25
|
static args = {
|
|
24
26
|
northstarId: core_1.Args.string({ ignoreStdin: true, description: 'Northstar ID', required: true }),
|
|
@@ -30,7 +32,7 @@ class NorthstarsGovernanceConfigure extends base_command_1.BaseCommand {
|
|
|
30
32
|
options: [...northstars_1.NORTHSTAR_ANALYSIS_MODES],
|
|
31
33
|
}),
|
|
32
34
|
execution: core_1.Flags.string({
|
|
33
|
-
description:
|
|
35
|
+
description: "What happens to management intents: advisory records them (none is applied), approval asks first, bounded_auto applies a narrow set. In every mode a review still writes each linked active commitment's allocation (cadence band, run share); it never pauses, resumes, reprioritizes or checks in advisory",
|
|
34
36
|
options: [...northstars_1.NORTHSTAR_EXECUTION_MODES],
|
|
35
37
|
}),
|
|
36
38
|
'reviewer-agent': core_1.Flags.string({
|
|
@@ -48,8 +50,13 @@ class NorthstarsGovernanceConfigure extends base_command_1.BaseCommand {
|
|
|
48
50
|
multiple: true,
|
|
49
51
|
}),
|
|
50
52
|
protect: core_1.Flags.string({
|
|
51
|
-
description: 'Commitment the governor may never touch (repeatable; replaces the current list)',
|
|
53
|
+
description: 'Commitment the governor may never touch (repeatable; replaces the current list; --clear-protected empties it)',
|
|
52
54
|
multiple: true,
|
|
55
|
+
exclusive: ['clear-protected'],
|
|
56
|
+
}),
|
|
57
|
+
'clear-protected': core_1.Flags.boolean({
|
|
58
|
+
description: 'Remove every protected commitment (the list becomes empty)',
|
|
59
|
+
exclusive: ['protect'],
|
|
53
60
|
}),
|
|
54
61
|
'max-intents-per-review': core_1.Flags.integer({
|
|
55
62
|
description: 'Cap on intents per review',
|
|
@@ -88,16 +95,31 @@ class NorthstarsGovernanceConfigure extends base_command_1.BaseCommand {
|
|
|
88
95
|
description: 'Opt-in portfolio observation runs per UTC day',
|
|
89
96
|
min: 0,
|
|
90
97
|
max: 10000,
|
|
98
|
+
exclusive: ['clear-max-observation-runs-per-day'],
|
|
99
|
+
}),
|
|
100
|
+
'clear-max-observation-runs-per-day': core_1.Flags.boolean({
|
|
101
|
+
description: 'Un-set the observation ceiling (0 means never look; un-set means no ceiling)',
|
|
102
|
+
exclusive: ['max-observation-runs-per-day'],
|
|
91
103
|
}),
|
|
92
104
|
'max-runs-per-day': core_1.Flags.integer({
|
|
93
105
|
description: 'Portfolio-wide action run budget (execution, NOT attention)',
|
|
94
106
|
min: 0,
|
|
95
107
|
max: 10000,
|
|
108
|
+
exclusive: ['clear-max-runs-per-day'],
|
|
109
|
+
}),
|
|
110
|
+
'clear-max-runs-per-day': core_1.Flags.boolean({
|
|
111
|
+
description: 'Un-set the action run budget (0 is a setting, not un-set)',
|
|
112
|
+
exclusive: ['max-runs-per-day'],
|
|
96
113
|
}),
|
|
97
114
|
'max-concurrent-runs': core_1.Flags.integer({
|
|
98
|
-
description: 'Portfolio concurrency cap',
|
|
115
|
+
description: 'Portfolio concurrency cap (recorded, not yet enforced: nothing limits concurrent runs yet)',
|
|
99
116
|
min: 0,
|
|
100
117
|
max: 1000,
|
|
118
|
+
exclusive: ['clear-max-concurrent-runs'],
|
|
119
|
+
}),
|
|
120
|
+
'clear-max-concurrent-runs': core_1.Flags.boolean({
|
|
121
|
+
description: 'Un-set the concurrency cap',
|
|
122
|
+
exclusive: ['max-concurrent-runs'],
|
|
101
123
|
}),
|
|
102
124
|
'critical-reserve': core_1.Flags.string({
|
|
103
125
|
description: 'Fraction of the execution budget held for critical commitments (0..1)',
|
|
@@ -119,8 +141,17 @@ class NorthstarsGovernanceConfigure extends base_command_1.BaseCommand {
|
|
|
119
141
|
body.allowedIntentKinds = flags.allow;
|
|
120
142
|
if (flags['require-approval-for'])
|
|
121
143
|
body.requireApprovalFor = flags['require-approval-for'];
|
|
122
|
-
if (flags
|
|
144
|
+
if (flags['clear-protected']) {
|
|
145
|
+
body.protectedCommitmentIds = [];
|
|
146
|
+
}
|
|
147
|
+
else if (flags.protect) {
|
|
148
|
+
// An empty value used to reach the server and come back as
|
|
149
|
+
// `protectedCommitmentIds.0: Too small`, a REST field name nobody typed.
|
|
150
|
+
if (flags.protect.some((id) => id.trim() === '')) {
|
|
151
|
+
this.error('--protect needs a commitment id. To remove every protected commitment, pass --clear-protected.');
|
|
152
|
+
}
|
|
123
153
|
body.protectedCommitmentIds = flags.protect;
|
|
154
|
+
}
|
|
124
155
|
if (flags['max-intents-per-review'] !== undefined) {
|
|
125
156
|
body.maxIntentsPerReview = flags['max-intents-per-review'];
|
|
126
157
|
}
|
|
@@ -150,12 +181,21 @@ class NorthstarsGovernanceConfigure extends base_command_1.BaseCommand {
|
|
|
150
181
|
if (Object.keys(cadencePolicy).length)
|
|
151
182
|
body.cadencePolicy = cadencePolicy;
|
|
152
183
|
const executionBudget = {};
|
|
153
|
-
|
|
184
|
+
// `null` is how the API un-sets a budget; 0 is a setting and is never read as "un-set".
|
|
185
|
+
if (flags['clear-max-observation-runs-per-day'])
|
|
186
|
+
executionBudget.maxObservationRunsPerDay = null;
|
|
187
|
+
else if (flags['max-observation-runs-per-day'] !== undefined)
|
|
154
188
|
executionBudget.maxObservationRunsPerDay = flags['max-observation-runs-per-day'];
|
|
155
|
-
if (flags['max-runs-per-day']
|
|
189
|
+
if (flags['clear-max-runs-per-day']) {
|
|
190
|
+
executionBudget.maxRunsPerDay = null;
|
|
191
|
+
}
|
|
192
|
+
else if (flags['max-runs-per-day'] !== undefined) {
|
|
156
193
|
executionBudget.maxRunsPerDay = flags['max-runs-per-day'];
|
|
157
194
|
}
|
|
158
|
-
if (flags['max-concurrent-runs']
|
|
195
|
+
if (flags['clear-max-concurrent-runs']) {
|
|
196
|
+
executionBudget.maxConcurrentRuns = null;
|
|
197
|
+
}
|
|
198
|
+
else if (flags['max-concurrent-runs'] !== undefined) {
|
|
159
199
|
executionBudget.maxConcurrentRuns = flags['max-concurrent-runs'];
|
|
160
200
|
}
|
|
161
201
|
if (flags['critical-reserve'] !== undefined) {
|
|
@@ -170,12 +210,16 @@ class NorthstarsGovernanceConfigure extends base_command_1.BaseCommand {
|
|
|
170
210
|
if (Object.keys(body).length === 0) {
|
|
171
211
|
this.error('Nothing to configure — pass at least one flag.');
|
|
172
212
|
}
|
|
213
|
+
let written;
|
|
173
214
|
try {
|
|
174
|
-
await northstars_1.northstarApi.configureGovernance(args.northstarId, body);
|
|
215
|
+
written = await northstars_1.northstarApi.configureGovernance(args.northstarId, body);
|
|
175
216
|
}
|
|
176
217
|
catch (err) {
|
|
177
218
|
this.handleApiError(err);
|
|
178
219
|
}
|
|
220
|
+
// The write response says what the server did to the linked commitments; the status
|
|
221
|
+
// re-read below does not (OSK-21245).
|
|
222
|
+
const refresh = (0, northstars_1.readAllocationRefresh)(written);
|
|
179
223
|
// Re-read the STATUS rather than echoing the write response: the effective
|
|
180
224
|
// policy is what the server resolved, and readiness (is the reviewer even
|
|
181
225
|
// online?) is the part a configure command must not leave the user guessing.
|
|
@@ -187,10 +231,32 @@ class NorthstarsGovernanceConfigure extends base_command_1.BaseCommand {
|
|
|
187
231
|
this.handleApiError(err);
|
|
188
232
|
}
|
|
189
233
|
if (flags.json) {
|
|
190
|
-
this.log(JSON.stringify(
|
|
234
|
+
this.log(JSON.stringify(refresh
|
|
235
|
+
? {
|
|
236
|
+
...status,
|
|
237
|
+
allocationsRefreshed: refresh.refreshed,
|
|
238
|
+
allocationsPending: refresh.pending,
|
|
239
|
+
allocationsRefreshFailed: refresh.failed,
|
|
240
|
+
}
|
|
241
|
+
: status, null, 2));
|
|
191
242
|
return;
|
|
192
243
|
}
|
|
193
244
|
(0, northstars_1.renderGovernance)(status, (line) => this.log(line));
|
|
245
|
+
const summary = (0, northstars_1.describeAllocationRefresh)(refresh, {
|
|
246
|
+
northstarId: args.northstarId,
|
|
247
|
+
inputsSent: northstars_1.ALLOCATION_INPUT_FLAGS.some((flag) => flags[flag] !== undefined && flags[flag] !== false),
|
|
248
|
+
bin: this.config?.bin,
|
|
249
|
+
});
|
|
250
|
+
if (summary.lines.length)
|
|
251
|
+
this.log('');
|
|
252
|
+
for (const line of summary.lines)
|
|
253
|
+
this.log(line);
|
|
254
|
+
for (const warning of summary.warnings)
|
|
255
|
+
this.warn(warning);
|
|
256
|
+
if (flags['max-concurrent-runs'] !== undefined) {
|
|
257
|
+
this.log('');
|
|
258
|
+
this.log('Note: --max-concurrent-runs is recorded but not yet enforced. Nothing limits concurrent runs across this northstar; each commitment keeps its own concurrency limit.');
|
|
259
|
+
}
|
|
194
260
|
}
|
|
195
261
|
}
|
|
196
262
|
exports.default = NorthstarsGovernanceConfigure;
|
|
@@ -7,6 +7,12 @@ import { BaseCommand } from '../../../base-command';
|
|
|
7
7
|
* hours later against a portfolio that has since changed is invalidated rather
|
|
8
8
|
* than forced through. That is the point of approving an INTENT rather than
|
|
9
9
|
* queueing a command.
|
|
10
|
+
*
|
|
11
|
+
* ONE exit rule: the command exits 0 only when the thing asked for now holds
|
|
12
|
+
* (an approval left the intent `applied`, a rejection left it `rejected`).
|
|
13
|
+
* Retrying a decision that already took effect is a replay and also exits 0;
|
|
14
|
+
* everything else exits 1 with a sentence, and `--json` keeps the raw code plus
|
|
15
|
+
* `reasonText`.
|
|
10
16
|
*/
|
|
11
17
|
export default class NorthstarsIntentsDecide extends BaseCommand {
|
|
12
18
|
static description: string;
|