@skrr-ai/cli 0.1.128 → 0.1.130
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 +12 -0
- package/dist/base-command.js +65 -0
- package/dist/commands/agenda/trigger/create.js +9 -1
- package/dist/commands/agenda/trigger/list.d.ts +2 -1
- package/dist/commands/agenda/trigger/list.js +55 -6
- package/dist/commands/agents/create.js +3 -1
- package/dist/commands/agents/reflect.d.ts +6 -0
- package/dist/commands/agents/reflect.js +45 -6
- package/dist/commands/agents/schedule-overview.d.ts +17 -0
- package/dist/commands/agents/schedule-overview.js +33 -9
- package/dist/commands/agents/triggers/policy.js +3 -1
- package/dist/commands/browser/persistent-profile.d.ts +22 -0
- package/dist/commands/browser/persistent-profile.js +46 -0
- package/dist/commands/commitments/create.js +3 -1
- package/dist/commands/commitments/effective-policy.js +6 -0
- package/dist/commands/commitments/explain.js +10 -1
- package/dist/commands/commitments/plan.d.ts +14 -0
- package/dist/commands/commitments/plan.js +32 -0
- package/dist/commands/commitments/preflight.d.ts +1 -1
- package/dist/commands/commitments/preflight.js +12 -4
- package/dist/commands/commitments/show.d.ts +9 -0
- package/dist/commands/commitments/show.js +14 -1
- package/dist/commands/compass/revisions.d.ts +6 -2
- package/dist/commands/compass/revisions.js +13 -5
- package/dist/commands/compass/tactic.d.ts +5 -0
- package/dist/commands/compass/tactic.js +14 -0
- package/dist/commands/followups/plans/create.js +1 -1
- package/dist/commands/harnesses/list.js +1 -1
- package/dist/commands/northstars/create.js +6 -1
- package/dist/commands/northstars/governance/configure.js +1 -1
- package/dist/commands/northstars/intents/decide.js +2 -3
- package/dist/commands/northstars/list.js +1 -1
- package/dist/commands/northstars/review-now.js +5 -0
- package/dist/commands/northstars/reviews.js +15 -3
- package/dist/commands/northstars/show.js +1 -1
- package/dist/commands/spaces/auto-executor/runs.d.ts +9 -1
- package/dist/commands/spaces/auto-executor/runs.js +18 -1
- package/dist/commands/spaces/heartbeats/create.js +7 -5
- package/dist/commands/spaces/heartbeats/status.js +10 -0
- package/dist/commands/spaces/heartbeats/update.js +5 -3
- package/dist/commands/store/artifacts/releases.d.ts +20 -0
- package/dist/commands/store/artifacts/releases.js +85 -0
- package/dist/commands/store/library.d.ts +14 -0
- package/dist/commands/store/library.js +71 -0
- package/dist/commands/tasks/archive.js +6 -0
- package/dist/commands/tasks/list.d.ts +48 -0
- package/dist/commands/tasks/list.js +141 -9
- package/dist/commands/tasks/pause-schedule.js +1 -1
- package/dist/commands/tasks/remind.js +23 -11
- package/dist/commands/tasks/resume-schedule.js +4 -1
- package/dist/commands/tasks/retry-schedule.js +6 -3
- package/dist/commands/tasks/schedule.js +35 -8
- package/dist/commands/tasks/self-schedule.d.ts +56 -0
- package/dist/commands/tasks/self-schedule.js +179 -21
- package/dist/commands/tasks/show.js +4 -0
- package/dist/lib/agent-trigger-listing.d.ts +26 -0
- package/dist/lib/agent-trigger-listing.js +63 -0
- package/dist/lib/agentic-stream.js +138 -41
- package/dist/lib/commitment-ledgers.js +3 -1
- package/dist/lib/commitments.d.ts +24 -0
- package/dist/lib/commitments.js +64 -4
- package/dist/lib/compasses.d.ts +2 -0
- package/dist/lib/iso-instant.d.ts +52 -0
- package/dist/lib/iso-instant.js +162 -0
- package/dist/lib/northstars.d.ts +87 -4
- package/dist/lib/northstars.js +226 -94
- package/dist/lib/proposals.js +6 -2
- package/dist/lib/reflection.d.ts +58 -0
- package/dist/lib/reflection.js +115 -6
- package/dist/lib/store-artifact-releases.d.ts +39 -0
- package/dist/lib/store-artifact-releases.js +12 -0
- package/dist/lib/store-library.d.ts +37 -0
- package/dist/lib/store-library.js +12 -0
- package/dist/lib/task-calendar.d.ts +19 -0
- package/dist/lib/task-calendar.js +72 -0
- package/dist/lib/task-operations.js +2 -0
- package/dist/lib/task-recurrence-outcome.js +3 -1
- package/dist/lib/task-recurrence-summary.d.ts +15 -0
- package/dist/lib/task-recurrence-summary.js +228 -0
- package/dist/lib/task-reminder.d.ts +28 -0
- package/dist/lib/task-reminder.js +50 -0
- package/dist/lib/task-schedule-notes.d.ts +46 -0
- package/dist/lib/task-schedule-notes.js +71 -0
- package/dist/lib/triggers.d.ts +31 -2
- package/dist/lib/triggers.js +38 -18
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.js +11 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.d.ts +9 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +22 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.d.ts +123 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/executorStopReceipt.js +160 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +19 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.js +11 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.d.ts +9 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +28 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.d.ts +123 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/executorStopReceipt.js +173 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +3 -1
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +6772 -6675
- package/oclif.manifest.json +282 -40
- package/package.json +1 -1
package/dist/base-command.d.ts
CHANGED
|
@@ -580,6 +580,18 @@ export declare function describeHarnessUnavailable(body: Record<string, unknown>
|
|
|
580
580
|
* Exported for tests.
|
|
581
581
|
*/
|
|
582
582
|
export declare function describeGitHubUnavailable(): string;
|
|
583
|
+
/**
|
|
584
|
+
* Frame a typed `TASK_LIST_TIMEOUT` failure as what it is — a list too broad for the database's
|
|
585
|
+
* time limit — rather than a control-plane outage.
|
|
586
|
+
*
|
|
587
|
+
* `GET /api/tasks` answers 503 with this code when its one aggregate is cut off at `maxTimeMS`,
|
|
588
|
+
* which an unscoped list over every accessible Space reaches because no index serves its sort
|
|
589
|
+
* across the access filter. Lead with the server's `cause`/`remedy`, falling back to the CLI's
|
|
590
|
+
* own sentence: the 5xx redaction boundary generalizes a bare message in production.
|
|
591
|
+
*
|
|
592
|
+
* Exported for tests.
|
|
593
|
+
*/
|
|
594
|
+
export declare function describeTaskListTimeout(body: Record<string, unknown> | null, bin?: string): string;
|
|
583
595
|
/**
|
|
584
596
|
* Frame a typed `LABEL_SUGGESTION_UNAVAILABLE` failure as what it is — the
|
|
585
597
|
* suggestion's hosted-inference call found no billing payer — rather than a
|
package/dist/base-command.js
CHANGED
|
@@ -9,6 +9,7 @@ exports.commitmentActivationHint = commitmentActivationHint;
|
|
|
9
9
|
exports.withSubject = withSubject;
|
|
10
10
|
exports.describeHarnessUnavailable = describeHarnessUnavailable;
|
|
11
11
|
exports.describeGitHubUnavailable = describeGitHubUnavailable;
|
|
12
|
+
exports.describeTaskListTimeout = describeTaskListTimeout;
|
|
12
13
|
exports.describeLabelSuggestionUnavailable = describeLabelSuggestionUnavailable;
|
|
13
14
|
exports.describeGitHubAppNotConfigured = describeGitHubAppNotConfigured;
|
|
14
15
|
exports.describeResourceNotFound = describeResourceNotFound;
|
|
@@ -1573,6 +1574,20 @@ class BaseCommand extends core_1.Command {
|
|
|
1573
1574
|
details: envelopeDetails(body),
|
|
1574
1575
|
});
|
|
1575
1576
|
}
|
|
1577
|
+
else if (bodyCode === 'TASK_LIST_TIMEOUT') {
|
|
1578
|
+
// The list was too broad for the database's time limit — a 503 the API sent on purpose,
|
|
1579
|
+
// with the narrower question to ask. The outage branch below would say skrr is down,
|
|
1580
|
+
// record an incident, and tell an agent to retry the very query that cannot finish
|
|
1581
|
+
// (OSK-21284).
|
|
1582
|
+
this.failWithCliError({
|
|
1583
|
+
message: say(describeTaskListTimeout(body, this.config.bin)),
|
|
1584
|
+
code: bodyCode,
|
|
1585
|
+
status: e.status,
|
|
1586
|
+
exit: 1,
|
|
1587
|
+
retryable: false,
|
|
1588
|
+
details: envelopeDetails(body),
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1576
1591
|
else if (bodyCode === 'LABEL_SUGGESTION_UNAVAILABLE') {
|
|
1577
1592
|
// The label-suggestion route found no inference payer — a per-call
|
|
1578
1593
|
// condition the API deliberately reported, not a platform outage,
|
|
@@ -1602,6 +1617,21 @@ class BaseCommand extends core_1.Command {
|
|
|
1602
1617
|
details: envelopeDetails(body),
|
|
1603
1618
|
});
|
|
1604
1619
|
}
|
|
1620
|
+
else if (commitmentBodyErrorCode(body)) {
|
|
1621
|
+
// These Commitment routes send the code in upper-case `error`, which `refusalCodeOf` does not
|
|
1622
|
+
// read as a code, so the documented code (the guide's refusal table) never reached `error.code`:
|
|
1623
|
+
// a program saw `HTTP_400` or `HTTP_409` and had to know to look in `details.error` (OSK-21102).
|
|
1624
|
+
// Read them by name, as the activation and Compass refusals are, rather than widening
|
|
1625
|
+
// `refusalCodeOf` for every route. The message is the server's, unchanged.
|
|
1626
|
+
this.failWithCliError({
|
|
1627
|
+
message: say(bodyMessage || e.message),
|
|
1628
|
+
code: commitmentBodyErrorCode(body),
|
|
1629
|
+
status: e.status,
|
|
1630
|
+
exit: 1,
|
|
1631
|
+
retryable: false,
|
|
1632
|
+
details: envelopeDetails(body),
|
|
1633
|
+
});
|
|
1634
|
+
}
|
|
1605
1635
|
else if ((e.status === 409 || e.status === 404) && (0, compass_refusals_1.compassRefusalCode)(body)) {
|
|
1606
1636
|
// The Compass routes sent the code in upper-case `error`, which `refusalCodeOf` does not
|
|
1607
1637
|
// read as a code, so a stale writer saw `HTTP_409` and a mistyped version `NOT_FOUND`,
|
|
@@ -2294,6 +2324,21 @@ function apiRefusal(err) {
|
|
|
2294
2324
|
}
|
|
2295
2325
|
/** The typed code the server refuses a Commitment activation with. */
|
|
2296
2326
|
const COMMITMENT_ACTIVATION_BLOCKED = 'COMMITMENT_ACTIVATION_BLOCKED';
|
|
2327
|
+
/**
|
|
2328
|
+
* Commitment refusals the routes send in upper-case `error` (OSK-21102): the retired `mode` and
|
|
2329
|
+
* `policy.autonomyMode` fields, a cadence window no single wall-clock pattern holds, and an edit that
|
|
2330
|
+
* tries to activate a draft (which only `resume` may do).
|
|
2331
|
+
*/
|
|
2332
|
+
const COMMITMENT_BODY_ERROR_CODES = new Set([
|
|
2333
|
+
'COMMITMENT_MODE_RETIRED',
|
|
2334
|
+
'COMMITMENT_POLICY_RETIRED',
|
|
2335
|
+
'COMMITMENT_CADENCE_WINDOW_UNSUPPORTED',
|
|
2336
|
+
'COMMITMENT_RESUME_REQUIRES_EXPLICIT_ACTION',
|
|
2337
|
+
]);
|
|
2338
|
+
function commitmentBodyErrorCode(body) {
|
|
2339
|
+
const value = stringProp(body, 'error');
|
|
2340
|
+
return value && COMMITMENT_BODY_ERROR_CODES.has(value) ? value : undefined;
|
|
2341
|
+
}
|
|
2297
2342
|
/**
|
|
2298
2343
|
* The remedy a refused Commitment activation carries.
|
|
2299
2344
|
*
|
|
@@ -2388,6 +2433,26 @@ function describeGitHubUnavailable() {
|
|
|
2388
2433
|
return ('GitHub is temporarily unreachable, so this request could not be completed. ' +
|
|
2389
2434
|
'skrr itself answered, so this is not a skrr outage — try again shortly.');
|
|
2390
2435
|
}
|
|
2436
|
+
/**
|
|
2437
|
+
* Frame a typed `TASK_LIST_TIMEOUT` failure as what it is — a list too broad for the database's
|
|
2438
|
+
* time limit — rather than a control-plane outage.
|
|
2439
|
+
*
|
|
2440
|
+
* `GET /api/tasks` answers 503 with this code when its one aggregate is cut off at `maxTimeMS`,
|
|
2441
|
+
* which an unscoped list over every accessible Space reaches because no index serves its sort
|
|
2442
|
+
* across the access filter. Lead with the server's `cause`/`remedy`, falling back to the CLI's
|
|
2443
|
+
* own sentence: the 5xx redaction boundary generalizes a bare message in production.
|
|
2444
|
+
*
|
|
2445
|
+
* Exported for tests.
|
|
2446
|
+
*/
|
|
2447
|
+
function describeTaskListTimeout(body, bin = 'skrr') {
|
|
2448
|
+
const cause = stringProp(body, 'cause') ||
|
|
2449
|
+
'The task list took too long: it spans every task you can see across all your workspaces and ' +
|
|
2450
|
+
'Spaces, and the database could not return the newest page within its time limit.';
|
|
2451
|
+
const remedy = stringProp(body, 'remedy') ||
|
|
2452
|
+
`Name where to look: a workspace (\`${bin} workspaces use <workspace-id>\`, or \`--workspace <workspace-id>\`) ` +
|
|
2453
|
+
`or a Space (\`${bin} tasks list --space <space-id>\`).`;
|
|
2454
|
+
return `${cause}\n → ${remedy}`;
|
|
2455
|
+
}
|
|
2391
2456
|
/**
|
|
2392
2457
|
* Frame a typed `LABEL_SUGGESTION_UNAVAILABLE` failure as what it is — the
|
|
2393
2458
|
* suggestion's hosted-inference call found no billing payer — rather than a
|
|
@@ -48,7 +48,9 @@ class AgendaTriggerCreate extends base_command_1.BaseCommand {
|
|
|
48
48
|
description: 'IANA timezone for the cron (defaults to UTC). Only used with --kind=schedule.',
|
|
49
49
|
}),
|
|
50
50
|
'delay-minutes': core_1.Flags.integer({
|
|
51
|
-
description: 'Minutes from now to fire — required when --kind=self_scheduled.
|
|
51
|
+
description: 'Minutes from now to fire — required when --kind=self_scheduled. ' +
|
|
52
|
+
`Range: ${data_provider_1.AGENDA_SELF_SCHEDULED_DELAY_MIN_MINUTES}..${data_provider_1.AGENDA_SELF_SCHEDULED_DELAY_MAX_MINUTES} ` +
|
|
53
|
+
`(${data_provider_1.AGENDA_SELF_SCHEDULED_DELAY_MIN_MINUTES} minutes..24 hours).`,
|
|
52
54
|
}),
|
|
53
55
|
'max-fires-per-day': core_1.Flags.integer({
|
|
54
56
|
description: 'Daily cap on fires. Required for self_scheduled (1..96); defaults to 96 for schedule when omitted.',
|
|
@@ -91,6 +93,12 @@ class AgendaTriggerCreate extends base_command_1.BaseCommand {
|
|
|
91
93
|
if (typeof flags['delay-minutes'] !== 'number') {
|
|
92
94
|
this.error('--delay-minutes is required when --kind=self_scheduled', { exit: 2 });
|
|
93
95
|
}
|
|
96
|
+
// The server holds the same range, but its refusal arrives after the round trip. The sentence
|
|
97
|
+
// is data-provider's, so what is said here and what the route says cannot differ (OSK-21500).
|
|
98
|
+
const delayRefusal = (0, data_provider_1.describeAgendaDelayMinutesRefusal)(flags['delay-minutes']);
|
|
99
|
+
if (delayRefusal) {
|
|
100
|
+
this.error(`--delay-minutes: ${delayRefusal}`, { exit: 2 });
|
|
101
|
+
}
|
|
94
102
|
if (typeof flags['max-fires-per-day'] !== 'number') {
|
|
95
103
|
this.error('--max-fires-per-day is required when --kind=self_scheduled', { exit: 2 });
|
|
96
104
|
}
|
|
@@ -12,7 +12,8 @@ import { BaseCommand } from '../../../base-command';
|
|
|
12
12
|
export declare function isUnconfirmedTurnCapture(trigger: Record<string, unknown>): boolean;
|
|
13
13
|
/**
|
|
14
14
|
* `skrr agenda trigger list <agent-id>` — show all triggers registered for
|
|
15
|
-
* an agent (any kind, not just agenda-created ones)
|
|
15
|
+
* an agent (any kind, not just agenda-created ones), including the ones the
|
|
16
|
+
* platform manages for its Commitments (the daily self-reflection check).
|
|
16
17
|
*/
|
|
17
18
|
export default class AgendaTriggerList extends BaseCommand {
|
|
18
19
|
static description: string;
|
|
@@ -7,6 +7,7 @@ const data_provider_1 = require("@skrr-ai/data-provider");
|
|
|
7
7
|
const base_command_1 = require("../../../base-command");
|
|
8
8
|
const format_1 = require("../../../lib/format");
|
|
9
9
|
const triggers_1 = require("../../../lib/triggers");
|
|
10
|
+
const agent_trigger_listing_1 = require("../../../lib/agent-trigger-listing");
|
|
10
11
|
/**
|
|
11
12
|
* A schedule persisted while handling a conversation turn, for which no explicit
|
|
12
13
|
* confirmation was recorded.
|
|
@@ -27,10 +28,11 @@ function isUnconfirmedTurnCapture(trigger) {
|
|
|
27
28
|
}
|
|
28
29
|
/**
|
|
29
30
|
* `skrr agenda trigger list <agent-id>` — show all triggers registered for
|
|
30
|
-
* an agent (any kind, not just agenda-created ones)
|
|
31
|
+
* an agent (any kind, not just agenda-created ones), including the ones the
|
|
32
|
+
* platform manages for its Commitments (the daily self-reflection check).
|
|
31
33
|
*/
|
|
32
34
|
class AgendaTriggerList extends base_command_1.BaseCommand {
|
|
33
|
-
static description =
|
|
35
|
+
static description = "List every trigger registered against an agent, including the ones the platform manages for its Commitments (SOURCE 'system'). A passive agent (--initial-always-on off) still has a daily self-reflection check.";
|
|
34
36
|
static examples = [
|
|
35
37
|
'<%= config.bin %> agenda trigger list <agent-id>',
|
|
36
38
|
'<%= config.bin %> agenda trigger list <agent-id> --unconfirmed',
|
|
@@ -55,17 +57,50 @@ class AgendaTriggerList extends base_command_1.BaseCommand {
|
|
|
55
57
|
catch (err) {
|
|
56
58
|
this.handleApiError(err);
|
|
57
59
|
}
|
|
60
|
+
const r = response;
|
|
61
|
+
const listed = r?.data ?? [];
|
|
62
|
+
// The per-agent route lists `scope: 'agent'` rows only; the Commitment triggers a passive agent still owns
|
|
63
|
+
// live under `commitment_watcher`. `--unconfirmed` is about turn captures, which are agent-scoped, so it
|
|
64
|
+
// skips the extra read.
|
|
65
|
+
let extra = [];
|
|
66
|
+
let extraUnreadable = null;
|
|
67
|
+
if (!flags.unconfirmed) {
|
|
68
|
+
try {
|
|
69
|
+
const universal = await triggers_1.triggerApi.list((0, triggers_1.withQuery)('/api/triggers', { refEntity: [`agent:${args.agentId}`], limit: 200 }));
|
|
70
|
+
extra = (0, agent_trigger_listing_1.triggersMissingFromAgentList)(listed, (universal?.triggers ?? []));
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
extraUnreadable = err instanceof Error ? err.message : String(err);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
58
76
|
if (flags.json) {
|
|
59
|
-
this.printJsonResult((0, list_output_1.listResult)(
|
|
77
|
+
this.printJsonResult((0, list_output_1.listResult)(r && typeof r === 'object'
|
|
78
|
+
? {
|
|
79
|
+
...r,
|
|
80
|
+
data: [...listed, ...extra],
|
|
81
|
+
...(extraUnreadable
|
|
82
|
+
? {
|
|
83
|
+
warnings: [
|
|
84
|
+
{
|
|
85
|
+
code: 'system_triggers_unreadable',
|
|
86
|
+
value: extraUnreadable,
|
|
87
|
+
hint: systemTriggersUnreadable(args.agentId, extraUnreadable),
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
}
|
|
91
|
+
: {}),
|
|
92
|
+
}
|
|
93
|
+
: response));
|
|
60
94
|
return;
|
|
61
95
|
}
|
|
62
|
-
|
|
63
|
-
let items = r?.data ?? [];
|
|
96
|
+
let items = [...listed, ...extra];
|
|
64
97
|
if (flags.unconfirmed) {
|
|
65
98
|
items = items.filter((t) => isUnconfirmedTurnCapture(t));
|
|
66
99
|
}
|
|
67
100
|
if (items.length === 0) {
|
|
68
101
|
this.log(flags.unconfirmed ? 'No unconfirmed turn-captured schedules.' : 'No triggers.');
|
|
102
|
+
if (extraUnreadable)
|
|
103
|
+
this.log(systemTriggersUnreadable(args.agentId, extraUnreadable));
|
|
69
104
|
return;
|
|
70
105
|
}
|
|
71
106
|
const rows = items.map((t) => {
|
|
@@ -81,7 +116,7 @@ class AgendaTriggerList extends base_command_1.BaseCommand {
|
|
|
81
116
|
label: String(t.label ?? '-').slice(0, 40),
|
|
82
117
|
next: String(next).slice(0, 25),
|
|
83
118
|
fires: String(fires),
|
|
84
|
-
source: isUnconfirmedTurnCapture(t)
|
|
119
|
+
source: (0, agent_trigger_listing_1.sourceLabel)(t, isUnconfirmedTurnCapture(t)),
|
|
85
120
|
};
|
|
86
121
|
});
|
|
87
122
|
(0, format_1.renderTable)(rows, [
|
|
@@ -93,6 +128,15 @@ class AgendaTriggerList extends base_command_1.BaseCommand {
|
|
|
93
128
|
{ key: 'fires', header: 'FIRES' },
|
|
94
129
|
{ key: 'source', header: 'SOURCE' },
|
|
95
130
|
], (line) => this.log(line));
|
|
131
|
+
if (rows.some((row) => row.source.startsWith('system'))) {
|
|
132
|
+
this.log('');
|
|
133
|
+
for (const line of (0, agent_trigger_listing_1.systemManagedLegend)(args.agentId, this.config.bin))
|
|
134
|
+
this.log(line);
|
|
135
|
+
}
|
|
136
|
+
if (extraUnreadable) {
|
|
137
|
+
this.log('');
|
|
138
|
+
this.log(systemTriggersUnreadable(args.agentId, extraUnreadable));
|
|
139
|
+
}
|
|
96
140
|
if (rows.some((row) => row.source === 'turn*')) {
|
|
97
141
|
// Deliberately not "the agent scheduled this by itself". The capture layer
|
|
98
142
|
// cannot tell "remind me at 9" from a nudge the agent invented, so the
|
|
@@ -105,3 +149,8 @@ class AgendaTriggerList extends base_command_1.BaseCommand {
|
|
|
105
149
|
}
|
|
106
150
|
}
|
|
107
151
|
exports.default = AgendaTriggerList;
|
|
152
|
+
/** Said, not skipped: a missing read must not look like an agent with no Commitment triggers. */
|
|
153
|
+
function systemTriggersUnreadable(agentId, reason) {
|
|
154
|
+
return (`Platform-managed (Commitment) triggers could not be read (${reason}); this list may be incomplete. ` +
|
|
155
|
+
`Try: skrr triggers list --ref-entity agent:${agentId}`);
|
|
156
|
+
}
|
|
@@ -245,7 +245,9 @@ class AgentsCreate extends base_command_1.BaseCommand {
|
|
|
245
245
|
description: 'Default working directory for local Harness sessions',
|
|
246
246
|
}),
|
|
247
247
|
'initial-always-on': core_1.Flags.string({
|
|
248
|
-
description: 'Start autonomous work after creation (default: on). Use off for a passive agent; explicit chat still works.
|
|
248
|
+
description: 'Start autonomous work after creation (default: on). Use off for a passive agent; explicit chat still works. ' +
|
|
249
|
+
'A passive agent is still seeded with the system-managed daily self-reflection Commitment: `agenda trigger list <agent>` shows its trigger (SOURCE "system", marked "suspended" while the platform holds it for Always-On being off) ' +
|
|
250
|
+
'and `commitments list --agent <agent> --include-system` finds the Commitment to pause. Relationship-loop seeding is configured separately.',
|
|
249
251
|
options: ['on', 'off'],
|
|
250
252
|
}),
|
|
251
253
|
'no-relationship-loops': core_1.Flags.boolean({
|
|
@@ -32,5 +32,11 @@ export default class AgentsReflect extends BaseCommand {
|
|
|
32
32
|
run(): Promise<void>;
|
|
33
33
|
private runDisable;
|
|
34
34
|
private runEnableOrRetune;
|
|
35
|
+
/**
|
|
36
|
+
* Parse `--set-cadence` and apply the reflection window. A cadence that is not one
|
|
37
|
+
* (`0`, `1 month`, empty) is a usage error naming the rule, raised before anything is
|
|
38
|
+
* written, not an API failure.
|
|
39
|
+
*/
|
|
40
|
+
private boundRequestedCadence;
|
|
35
41
|
private runStatus;
|
|
36
42
|
}
|
|
@@ -55,12 +55,16 @@ class AgentsReflect extends base_command_1.BaseCommand {
|
|
|
55
55
|
this.requireAuth();
|
|
56
56
|
const { args, flags } = await this.parse(AgentsReflect);
|
|
57
57
|
const agentId = args.id;
|
|
58
|
+
// Only the status view prints whether the loop's fires run, so only it asks the server for
|
|
59
|
+
// that verdict (a policy read); enabling, retuning and pausing do not.
|
|
60
|
+
const isStatus = !flags.disable && !flags.enable && flags['set-cadence'] === undefined;
|
|
58
61
|
let existing;
|
|
59
62
|
try {
|
|
60
63
|
const list = await triggers_1.triggerApi.list((0, triggers_1.withQuery)('/api/triggers', {
|
|
61
64
|
scope: 'agent',
|
|
62
65
|
refEntity: (0, triggers_1.agentRefEntity)(agentId),
|
|
63
66
|
limit: 200,
|
|
67
|
+
include: isStatus ? 'autonomy' : undefined,
|
|
64
68
|
}));
|
|
65
69
|
existing = (0, reflection_1.findReflectionTrigger)(list.triggers ?? []);
|
|
66
70
|
}
|
|
@@ -103,14 +107,23 @@ class AgentsReflect extends base_command_1.BaseCommand {
|
|
|
103
107
|
// Resolve the target cadence: explicit --set-cadence, else keep the existing
|
|
104
108
|
// interval when just --enabling, else the default.
|
|
105
109
|
let minutes;
|
|
110
|
+
let bounds = null;
|
|
106
111
|
if (flags['set-cadence'] !== undefined) {
|
|
107
|
-
|
|
112
|
+
bounds = this.boundRequestedCadence(flags['set-cadence']);
|
|
113
|
+
minutes = bounds.minutes;
|
|
108
114
|
}
|
|
109
115
|
else {
|
|
110
116
|
minutes =
|
|
111
117
|
(existing && (0, reflection_1.reflectionCadenceMinutes)(existing)) || reflection_1.DEFAULT_REFLECTION_CADENCE_MINUTES;
|
|
112
118
|
}
|
|
113
119
|
const cadence = (0, reflection_1.describeCadenceMinutes)(minutes);
|
|
120
|
+
// What was ASKED for, beside what was applied: a request the window moved is said so
|
|
121
|
+
// (OSK-21493), in the text and in `--json`, instead of only the clamped number.
|
|
122
|
+
const clampNote = bounds ? (0, reflection_1.describeCadenceClamp)(bounds) : null;
|
|
123
|
+
const requested = {
|
|
124
|
+
requestedCadence: bounds ? (0, reflection_1.describeCadenceMinutes)(bounds.requestedMinutes) : null,
|
|
125
|
+
...(clampNote ? { clamped: true, note: clampNote } : {}),
|
|
126
|
+
};
|
|
114
127
|
if (existing?.id) {
|
|
115
128
|
const patch = {
|
|
116
129
|
enabled: true,
|
|
@@ -124,10 +137,12 @@ class AgentsReflect extends base_command_1.BaseCommand {
|
|
|
124
137
|
}
|
|
125
138
|
const updated = await triggers_1.triggerApi.update(existing.id, patch);
|
|
126
139
|
if (flags.json) {
|
|
127
|
-
this.log(JSON.stringify({ ok: true, agentId, action: 'retuned', cadence, trigger: updated }, null, 2));
|
|
140
|
+
this.log(JSON.stringify({ ok: true, agentId, action: 'retuned', ...requested, cadence, trigger: updated }, null, 2));
|
|
128
141
|
return;
|
|
129
142
|
}
|
|
130
143
|
this.log(`Self-reflection loop retuned — agent ${agentId} now reflects every ${cadence}.`);
|
|
144
|
+
if (clampNote)
|
|
145
|
+
this.log(`Note: ${clampNote}`);
|
|
131
146
|
this.log(`Trigger: ${existing.id}`);
|
|
132
147
|
return;
|
|
133
148
|
}
|
|
@@ -138,12 +153,30 @@ class AgentsReflect extends base_command_1.BaseCommand {
|
|
|
138
153
|
});
|
|
139
154
|
const created = await triggers_1.triggerApi.create(payload);
|
|
140
155
|
if (flags.json) {
|
|
141
|
-
this.log(JSON.stringify({ ok: true, agentId, action: 'enabled', cadence, trigger: created }, null, 2));
|
|
156
|
+
this.log(JSON.stringify({ ok: true, agentId, action: 'enabled', ...requested, cadence, trigger: created }, null, 2));
|
|
142
157
|
return;
|
|
143
158
|
}
|
|
144
159
|
this.log(`Self-reflection loop enabled — agent ${agentId} will reflect every ${cadence}.`);
|
|
160
|
+
if (clampNote)
|
|
161
|
+
this.log(`Note: ${clampNote}`);
|
|
145
162
|
this.log(`Trigger: ${created.id ?? '(created)'}`);
|
|
146
|
-
this.log(`Next run: ${(0,
|
|
163
|
+
this.log(`Next run: ${(0, reflection_1.reflectionNextRunLabel)(created)}`);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Parse `--set-cadence` and apply the reflection window. A cadence that is not one
|
|
167
|
+
* (`0`, `1 month`, empty) is a usage error naming the rule, raised before anything is
|
|
168
|
+
* written, not an API failure.
|
|
169
|
+
*/
|
|
170
|
+
boundRequestedCadence(raw) {
|
|
171
|
+
try {
|
|
172
|
+
return (0, reflection_1.applyCadenceBounds)((0, reflection_1.parseCadenceToMinutes)(raw));
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
if (err instanceof reflection_1.InvalidCadenceError) {
|
|
176
|
+
this.failWithCliError({ message: err.message, code: err.code, exit: 2, retryable: false });
|
|
177
|
+
}
|
|
178
|
+
throw err;
|
|
179
|
+
}
|
|
147
180
|
}
|
|
148
181
|
runStatus(agentId, existing, json) {
|
|
149
182
|
if (!existing) {
|
|
@@ -165,7 +198,8 @@ class AgentsReflect extends base_command_1.BaseCommand {
|
|
|
165
198
|
enabled: existing.enabled !== false,
|
|
166
199
|
cadence,
|
|
167
200
|
cadenceMinutes: minutes ?? null,
|
|
168
|
-
nextRun: (0,
|
|
201
|
+
nextRun: (0, reflection_1.reflectionNextRunLabel)(existing),
|
|
202
|
+
...(0, reflection_1.reflectionAutonomyFields)(existing),
|
|
169
203
|
trigger: existing,
|
|
170
204
|
}, null, 2));
|
|
171
205
|
return;
|
|
@@ -173,8 +207,13 @@ class AgentsReflect extends base_command_1.BaseCommand {
|
|
|
173
207
|
this.log(`Self-reflection loop for agent ${agentId}:`);
|
|
174
208
|
this.log(` Status: ${existing.enabled === false ? 'paused' : 'active'}`);
|
|
175
209
|
this.log(` Cadence: every ${cadence}`);
|
|
176
|
-
this.log(` Next run: ${(0,
|
|
210
|
+
this.log(` Next run: ${(0, reflection_1.reflectionNextRunLabel)(existing)}`);
|
|
177
211
|
this.log(` Trigger: ${existing.id ?? '-'}`);
|
|
212
|
+
// "active" with a next run says the loop is armed, not that its fires run: under some
|
|
213
|
+
// initiative modes they only create an inbox suggestion (OSK-21606).
|
|
214
|
+
const autonomyNote = (0, reflection_1.reflectionAutonomyNote)(existing, this.config.bin);
|
|
215
|
+
if (autonomyNote)
|
|
216
|
+
this.log(` Note: ${autonomyNote}`);
|
|
178
217
|
if (existing.enabled === false) {
|
|
179
218
|
this.log('');
|
|
180
219
|
this.log('Re-enable it with: ' + `${this.config.bin} agents reflect ${agentId} --enable`);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
|
+
import { type TriggerDefinition } from '../../lib/triggers';
|
|
2
3
|
/**
|
|
3
4
|
* `skrr agents schedule-overview <agent-id>` — the one-call "full visibility"
|
|
4
5
|
* view an agent needs when it wakes to think: PAST (recent fires) + FUTURE
|
|
@@ -25,3 +26,19 @@ export default class AgentsScheduleOverview extends BaseCommand {
|
|
|
25
26
|
};
|
|
26
27
|
run(): Promise<void>;
|
|
27
28
|
}
|
|
29
|
+
/** The reflection loop as `--json` reports it. A paused loop has no next run (`-`). */
|
|
30
|
+
export declare function reflectionSummary(reflection: TriggerDefinition): {
|
|
31
|
+
autonomy?: "runs" | "suggests_only";
|
|
32
|
+
note?: string;
|
|
33
|
+
triggerId: string | undefined;
|
|
34
|
+
enabled: boolean;
|
|
35
|
+
cadence: string;
|
|
36
|
+
nextRun: string;
|
|
37
|
+
};
|
|
38
|
+
/** The reflection loop as the text view prints it. */
|
|
39
|
+
export declare function reflectionLine(reflection: TriggerDefinition): string;
|
|
40
|
+
/**
|
|
41
|
+
* The line under the loop when the server says its fires do not run for the owner (OSK-21606),
|
|
42
|
+
* else null. "active · next <time>" only says the loop is armed.
|
|
43
|
+
*/
|
|
44
|
+
export declare function reflectionNoteLine(reflection: TriggerDefinition, bin: string): string | null;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reflectionSummary = reflectionSummary;
|
|
4
|
+
exports.reflectionLine = reflectionLine;
|
|
5
|
+
exports.reflectionNoteLine = reflectionNoteLine;
|
|
3
6
|
const core_1 = require("@oclif/core");
|
|
4
7
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
8
|
const base_command_1 = require("../../base-command");
|
|
@@ -51,6 +54,8 @@ class AgentsScheduleOverview extends base_command_1.BaseCommand {
|
|
|
51
54
|
scope: 'agent',
|
|
52
55
|
refEntity: (0, triggers_1.agentRefEntity)(agentId),
|
|
53
56
|
limit: 200,
|
|
57
|
+
// Whether the reflection loop's fires run: its row carries the verdict (OSK-21606).
|
|
58
|
+
include: 'autonomy',
|
|
54
59
|
})),
|
|
55
60
|
// Filter SERVER-side. Fetching an unfiltered page and filtering in memory
|
|
56
61
|
// silently truncates the section for any user with more tasks than
|
|
@@ -72,14 +77,7 @@ class AgentsScheduleOverview extends base_command_1.BaseCommand {
|
|
|
72
77
|
if (flags.json) {
|
|
73
78
|
this.log(JSON.stringify({
|
|
74
79
|
agentId,
|
|
75
|
-
reflection: reflection
|
|
76
|
-
? {
|
|
77
|
-
triggerId: reflection.id,
|
|
78
|
-
enabled: reflection.enabled !== false,
|
|
79
|
-
cadence: describeCadence(reflection),
|
|
80
|
-
nextRun: (0, triggers_1.nextRunLabel)(reflection),
|
|
81
|
-
}
|
|
82
|
-
: null,
|
|
80
|
+
reflection: reflection ? reflectionSummary(reflection) : null,
|
|
83
81
|
upcoming,
|
|
84
82
|
recentFires: fires,
|
|
85
83
|
openTasks,
|
|
@@ -97,7 +95,10 @@ class AgentsScheduleOverview extends base_command_1.BaseCommand {
|
|
|
97
95
|
this.log(` none — enable with: ${this.config.bin} agents reflect ${agentId} --set-cadence 6h`);
|
|
98
96
|
}
|
|
99
97
|
else {
|
|
100
|
-
this.log(
|
|
98
|
+
this.log(reflectionLine(reflection));
|
|
99
|
+
const note = reflectionNoteLine(reflection, this.config.bin);
|
|
100
|
+
if (note)
|
|
101
|
+
this.log(note);
|
|
101
102
|
}
|
|
102
103
|
// FUTURE.
|
|
103
104
|
this.log('');
|
|
@@ -190,6 +191,29 @@ function describeCadence(trigger) {
|
|
|
190
191
|
const minutes = (0, reflection_1.reflectionCadenceMinutes)(trigger);
|
|
191
192
|
return minutes ? (0, reflection_1.describeCadenceMinutes)(minutes) : 'unknown';
|
|
192
193
|
}
|
|
194
|
+
/** The reflection loop as `--json` reports it. A paused loop has no next run (`-`). */
|
|
195
|
+
function reflectionSummary(reflection) {
|
|
196
|
+
return {
|
|
197
|
+
triggerId: reflection.id,
|
|
198
|
+
enabled: reflection.enabled !== false,
|
|
199
|
+
cadence: describeCadence(reflection),
|
|
200
|
+
nextRun: (0, reflection_1.reflectionNextRunLabel)(reflection),
|
|
201
|
+
// Whether its fires run, when the server said; absent means it did not.
|
|
202
|
+
...(0, reflection_1.reflectionAutonomyFields)(reflection),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/** The reflection loop as the text view prints it. */
|
|
206
|
+
function reflectionLine(reflection) {
|
|
207
|
+
return ` ${reflection.enabled === false ? 'paused' : 'active'} · every ${describeCadence(reflection)} · next ${(0, reflection_1.reflectionNextRunLabel)(reflection)} · ${reflection.id ?? '-'}`;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* The line under the loop when the server says its fires do not run for the owner (OSK-21606),
|
|
211
|
+
* else null. "active · next <time>" only says the loop is armed.
|
|
212
|
+
*/
|
|
213
|
+
function reflectionNoteLine(reflection, bin) {
|
|
214
|
+
const note = (0, reflection_1.reflectionAutonomyNote)(reflection, bin);
|
|
215
|
+
return note ? ` Note: ${note}` : null;
|
|
216
|
+
}
|
|
193
217
|
function settledValue(result) {
|
|
194
218
|
return result.status === 'fulfilled' ? result.value : undefined;
|
|
195
219
|
}
|
|
@@ -56,7 +56,9 @@ class AgentsTriggersPolicy extends base_command_1.BaseCommand {
|
|
|
56
56
|
description: 'Allowed trigger kind under auto_run_limited (repeatable or comma-separated)',
|
|
57
57
|
multiple: true,
|
|
58
58
|
}),
|
|
59
|
-
'max-fires-per-day': core_1.Flags.integer({
|
|
59
|
+
'max-fires-per-day': core_1.Flags.integer({
|
|
60
|
+
description: 'Daily cap on how often this agent can wake itself: its Task returns and self_scheduled triggers, whatever cap they carry',
|
|
61
|
+
}),
|
|
60
62
|
'max-per-hour': core_1.Flags.integer({ description: 'Agent initiative hourly fire cap' }),
|
|
61
63
|
'working-hours': core_1.Flags.string({ description: 'Policy workingHours JSON object' }),
|
|
62
64
|
'quiet-hours': core_1.Flags.string({ description: 'Policy quietHours JSON object' }),
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
/**
|
|
3
|
+
* Whether browser sessions on THIS computer share one profile that keeps its
|
|
4
|
+
* logins and cache, instead of a fresh one each.
|
|
5
|
+
*
|
|
6
|
+
* The setting lives in the daemon's own config on this computer, so it is
|
|
7
|
+
* forwarded to the daemon rather than sent to the API: a browser that stays
|
|
8
|
+
* signed in is the person at the machine's decision, and a request from the
|
|
9
|
+
* cloud must not be able to make it (the same boundary as `browser
|
|
10
|
+
* cloud-agents`). The profile is the daemon's own, never the everyday Chrome.
|
|
11
|
+
*/
|
|
12
|
+
export default class BrowserPersistentProfile extends Command {
|
|
13
|
+
static description: string;
|
|
14
|
+
static examples: string[];
|
|
15
|
+
static args: {
|
|
16
|
+
action: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
17
|
+
};
|
|
18
|
+
static flags: {
|
|
19
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
20
|
+
};
|
|
21
|
+
run(): Promise<void>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const browser_1 = require("../browser");
|
|
5
|
+
/**
|
|
6
|
+
* Whether browser sessions on THIS computer share one profile that keeps its
|
|
7
|
+
* logins and cache, instead of a fresh one each.
|
|
8
|
+
*
|
|
9
|
+
* The setting lives in the daemon's own config on this computer, so it is
|
|
10
|
+
* forwarded to the daemon rather than sent to the API: a browser that stays
|
|
11
|
+
* signed in is the person at the machine's decision, and a request from the
|
|
12
|
+
* cloud must not be able to make it (the same boundary as `browser
|
|
13
|
+
* cloud-agents`). The profile is the daemon's own, never the everyday Chrome.
|
|
14
|
+
*/
|
|
15
|
+
class BrowserPersistentProfile extends core_1.Command {
|
|
16
|
+
static description = 'Keep one browser profile (logins, cookies, cache) across browser sessions on this computer (off by default)';
|
|
17
|
+
static examples = [
|
|
18
|
+
'<%= config.bin %> browser persistent-profile status',
|
|
19
|
+
'<%= config.bin %> browser persistent-profile on',
|
|
20
|
+
'<%= config.bin %> browser persistent-profile off',
|
|
21
|
+
'<%= config.bin %> browser persistent-profile reset',
|
|
22
|
+
];
|
|
23
|
+
static args = {
|
|
24
|
+
action: core_1.Args.string({
|
|
25
|
+
description: 'on, off, status, or reset (sign out of everything and delete the profile)',
|
|
26
|
+
required: true,
|
|
27
|
+
options: ['on', 'off', 'status', 'reset'],
|
|
28
|
+
// Without this oclif reads stdin for a missing positional, so the command
|
|
29
|
+
// hangs when run from a pipe or a non-tty instead of refusing. Enforced
|
|
30
|
+
// by ARG_IMPLICIT_STDIN_ENABLED in the command-hygiene audit.
|
|
31
|
+
ignoreStdin: true,
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
static flags = {
|
|
35
|
+
json: core_1.Flags.boolean({ description: 'Output JSON' }),
|
|
36
|
+
};
|
|
37
|
+
async run() {
|
|
38
|
+
const { args, flags } = await this.parse(BrowserPersistentProfile);
|
|
39
|
+
await (0, browser_1.forwardBrowserCommand)(this, [
|
|
40
|
+
'persistent-profile',
|
|
41
|
+
args.action,
|
|
42
|
+
...(flags.json ? ['--json'] : []),
|
|
43
|
+
]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.default = BrowserPersistentProfile;
|
|
@@ -260,7 +260,9 @@ JSON
|
|
|
260
260
|
<%= config.bin %> compass commitments <compass-id> --agent <agent-id> # lists it once it is bound`,
|
|
261
261
|
];
|
|
262
262
|
static flags = {
|
|
263
|
-
json: core_1.Flags.boolean({
|
|
263
|
+
json: core_1.Flags.boolean({
|
|
264
|
+
description: 'Output the created commitment as JSON: the commitment itself, not wrapped (commitments show --json puts it under .commitment)',
|
|
265
|
+
}),
|
|
264
266
|
'from-json': core_1.Flags.string({
|
|
265
267
|
description: `JSON file (or "-" for stdin) for fields not exposed as flags. See examples below for daily times, named agent_run keys, zero budgets and "compassId" (binds a Compass; fixed at creation). ${commitment_attention_copy_1.QUIET_HOURS_HELP} ${commitment_attention_copy_1.EVENT_SOURCES_HELP}`,
|
|
266
268
|
}),
|
|
@@ -7,6 +7,7 @@ const base_command_1 = require("../../base-command");
|
|
|
7
7
|
const commitments_1 = require("../../lib/commitments");
|
|
8
8
|
const commitment_product_1 = require("../../lib/commitment-product");
|
|
9
9
|
const commitment_attention_copy_1 = require("../../lib/commitment-attention-copy");
|
|
10
|
+
const northstars_1 = require("../../lib/northstars");
|
|
10
11
|
/** Which limit binds the daily action runs — the fix lives on that object. */
|
|
11
12
|
const RUN_LIMIT_BINDING_LABELS = {
|
|
12
13
|
northstar_allocation: 'Northstar allocation',
|
|
@@ -71,6 +72,11 @@ function budgetDayLines(policy) {
|
|
|
71
72
|
? 'no ceiling'
|
|
72
73
|
: `${value}/day`;
|
|
73
74
|
lines.push(`Northstar shared pools: action runs ${pool(shared.actionRunsPerDay, shared.actionRunsPerDayState)} · observation runs ${pool(shared.observationRunsPerDay, shared.observationRunsPerDayState)}`);
|
|
75
|
+
// A pool below the number of linked active commitments is still handed out at the floor of
|
|
76
|
+
// 1/day each: the same sentence `northstars governance show` and `review-now` print (OSK-21334).
|
|
77
|
+
const floorNote = (0, northstars_1.runBudgetFloorNote)(policy.portfolio?.runBudgetFloor);
|
|
78
|
+
if (floorNote)
|
|
79
|
+
lines.push(`! ${floorNote}`);
|
|
74
80
|
}
|
|
75
81
|
return lines;
|
|
76
82
|
}
|
|
@@ -24,13 +24,22 @@ class CommitmentsExplain extends base_command_1.BaseCommand {
|
|
|
24
24
|
this.requireAuth();
|
|
25
25
|
const { args, flags } = await this.parse(CommitmentsExplain);
|
|
26
26
|
try {
|
|
27
|
-
|
|
27
|
+
// The explanation names neither the bound Compass nor its status, so the text view reads the
|
|
28
|
+
// Commitment beside it (the read `show` renders). `--json` stays the explanation as the
|
|
29
|
+
// server sent it, with no extra request. A failed read must not fail the explanation
|
|
30
|
+
// (OSK-21332): it becomes a "not shown" line instead.
|
|
31
|
+
const [explanation, read] = await Promise.all([
|
|
32
|
+
commitments_1.commitmentApi.explain(args.commitmentId),
|
|
33
|
+
flags.json ? null : commitments_1.commitmentApi.get(args.commitmentId).catch(() => null),
|
|
34
|
+
]);
|
|
28
35
|
if (flags.json) {
|
|
29
36
|
this.log(JSON.stringify(explanation, null, 2));
|
|
30
37
|
return;
|
|
31
38
|
}
|
|
32
39
|
for (const line of (0, commitments_1.formatCommitmentExplanation)(explanation))
|
|
33
40
|
this.log(line);
|
|
41
|
+
for (const line of (0, commitments_1.explainCompassLines)(args.commitmentId, read?.commitment))
|
|
42
|
+
this.log(line);
|
|
34
43
|
}
|
|
35
44
|
catch (err) {
|
|
36
45
|
this.handleApiError(err);
|