@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.
Files changed (123) hide show
  1. package/dist/base-command.d.ts +23 -0
  2. package/dist/base-command.js +72 -0
  3. package/dist/commands/agents/chat.js +7 -0
  4. package/dist/commands/agents/goals/list.d.ts +2 -2
  5. package/dist/commands/agents/goals/list.js +2 -2
  6. package/dist/commands/commitments/action-history.js +1 -1
  7. package/dist/commands/commitments/cases.js +3 -3
  8. package/dist/commands/commitments/check-now.d.ts +10 -2
  9. package/dist/commands/commitments/check-now.js +53 -3
  10. package/dist/commands/commitments/create.d.ts +6 -14
  11. package/dist/commands/commitments/create.js +61 -6
  12. package/dist/commands/commitments/doctor.js +3 -1
  13. package/dist/commands/commitments/effective-policy.d.ts +11 -1
  14. package/dist/commands/commitments/effective-policy.js +84 -4
  15. package/dist/commands/commitments/hypotheses.js +12 -12
  16. package/dist/commands/commitments/next-tick.js +5 -0
  17. package/dist/commands/commitments/observations.js +18 -17
  18. package/dist/commands/commitments/pack/list.js +2 -1
  19. package/dist/commands/commitments/pack/plan.d.ts +6 -0
  20. package/dist/commands/commitments/pack/plan.js +19 -0
  21. package/dist/commands/commitments/preflight.d.ts +19 -0
  22. package/dist/commands/commitments/preflight.js +108 -10
  23. package/dist/commands/commitments/trigger-status.js +8 -0
  24. package/dist/commands/commitments/update.d.ts +1 -0
  25. package/dist/commands/commitments/update.js +45 -4
  26. package/dist/commands/commitments/wake-capabilities.js +13 -0
  27. package/dist/commands/compass/archive.js +4 -0
  28. package/dist/commands/compass/commitments.js +15 -1
  29. package/dist/commands/compass/create.js +11 -3
  30. package/dist/commands/compass/effective-policy.d.ts +1 -0
  31. package/dist/commands/compass/effective-policy.js +8 -7
  32. package/dist/commands/compass/revert.d.ts +8 -0
  33. package/dist/commands/compass/revert.js +25 -1
  34. package/dist/commands/compass/revisions.d.ts +2 -0
  35. package/dist/commands/compass/revisions.js +18 -2
  36. package/dist/commands/compass/tactic.d.ts +5 -3
  37. package/dist/commands/compass/tactic.js +8 -7
  38. package/dist/commands/compass/update.js +19 -3
  39. package/dist/commands/followups/act.js +1 -1
  40. package/dist/commands/followups/cancel.js +13 -0
  41. package/dist/commands/followups/observability.js +20 -1
  42. package/dist/commands/followups/plans/create.js +12 -1
  43. package/dist/commands/followups/show.js +13 -0
  44. package/dist/commands/followups/watch.js +1 -1
  45. package/dist/commands/goals/create.d.ts +1 -0
  46. package/dist/commands/goals/create.js +4 -1
  47. package/dist/commands/goals/planner-config.d.ts +11 -0
  48. package/dist/commands/goals/planner-config.js +16 -0
  49. package/dist/commands/goals/revisions.js +3 -19
  50. package/dist/commands/machines/update.d.ts +5 -3
  51. package/dist/commands/machines/update.js +70 -9
  52. package/dist/commands/northstars/create.js +3 -1
  53. package/dist/commands/northstars/governance/configure.d.ts +4 -0
  54. package/dist/commands/northstars/governance/configure.js +75 -9
  55. package/dist/commands/northstars/intents/decide.d.ts +6 -0
  56. package/dist/commands/northstars/intents/decide.js +69 -15
  57. package/dist/commands/northstars/intents/list.d.ts +2 -1
  58. package/dist/commands/northstars/intents/list.js +15 -5
  59. package/dist/commands/northstars/intents.d.ts +26 -0
  60. package/dist/commands/northstars/intents.js +49 -0
  61. package/dist/commands/northstars/list.d.ts +1 -0
  62. package/dist/commands/northstars/list.js +24 -3
  63. package/dist/commands/northstars/recommendations/list.d.ts +1 -1
  64. package/dist/commands/northstars/recommendations/list.js +3 -3
  65. package/dist/commands/northstars/recommendations.d.ts +19 -0
  66. package/dist/commands/northstars/recommendations.js +42 -0
  67. package/dist/commands/northstars/review-now.d.ts +1 -0
  68. package/dist/commands/northstars/review-now.js +10 -4
  69. package/dist/commands/northstars/reviews.d.ts +1 -0
  70. package/dist/commands/northstars/reviews.js +19 -3
  71. package/dist/commands/northstars/update.js +8 -1
  72. package/dist/commands/proposals/list.js +11 -2
  73. package/dist/commands/proposals/show.js +9 -1
  74. package/dist/commands/spaces/auto-executor/preview.d.ts +14 -1
  75. package/dist/commands/spaces/auto-executor/preview.js +35 -1
  76. package/dist/commands/spaces/auto-executor/run.d.ts +17 -0
  77. package/dist/commands/spaces/auto-executor/run.js +60 -2
  78. package/dist/commands/spaces/files/upload.js +1 -2
  79. package/dist/commands/spaces/index.js +23 -0
  80. package/dist/commands/spaces/revisions.js +3 -2
  81. package/dist/commands/tasks/revisions.js +3 -2
  82. package/dist/commands/triggers/fire-detail.js +2 -0
  83. package/dist/generated/agent-guides.json +69 -69
  84. package/dist/lib/agentic-stream.d.ts +9 -0
  85. package/dist/lib/agentic-stream.js +14 -0
  86. package/dist/lib/command-miss.js +11 -2
  87. package/dist/lib/commitment-attention-copy.d.ts +96 -0
  88. package/dist/lib/commitment-attention-copy.js +209 -0
  89. package/dist/lib/commitment-loop-status.d.ts +6 -0
  90. package/dist/lib/commitment-loop-status.js +16 -6
  91. package/dist/lib/commitments.d.ts +88 -0
  92. package/dist/lib/commitments.js +188 -0
  93. package/dist/lib/compass-body-help.d.ts +20 -0
  94. package/dist/lib/compass-body-help.js +61 -0
  95. package/dist/lib/compass-refusals.d.ts +35 -0
  96. package/dist/lib/compass-refusals.js +50 -0
  97. package/dist/lib/compasses.d.ts +80 -4
  98. package/dist/lib/compasses.js +232 -12
  99. package/dist/lib/followups.d.ts +22 -1
  100. package/dist/lib/followups.js +21 -1
  101. package/dist/lib/format.d.ts +11 -0
  102. package/dist/lib/format.js +29 -0
  103. package/dist/lib/initiatives.d.ts +9 -2
  104. package/dist/lib/initiatives.js +13 -2
  105. package/dist/lib/machines.d.ts +14 -1
  106. package/dist/lib/machines.js +24 -0
  107. package/dist/lib/northstars.d.ts +158 -24
  108. package/dist/lib/northstars.js +538 -26
  109. package/dist/lib/proposal-decision-command.js +21 -1
  110. package/dist/lib/proposals.d.ts +26 -1
  111. package/dist/lib/proposals.js +163 -0
  112. package/dist/lib/rate-limit-retry.d.ts +5 -0
  113. package/dist/lib/rate-limit-retry.js +19 -0
  114. package/dist/lib/revision-actor.d.ts +2 -0
  115. package/dist/lib/revision-actor.js +16 -0
  116. package/dist/lib/roles.d.ts +1 -1
  117. package/dist/lib/space-charter.js +9 -0
  118. package/dist/lib/task-asset-upload.js +1 -2
  119. package/dist/lib/triggers.d.ts +33 -1
  120. package/dist/lib/triggers.js +77 -3
  121. package/dist/node_modules/@skrr-ai/data-provider/index.js +7537 -7474
  122. package/oclif.manifest.json +357 -34
  123. package/package.json +4 -4
@@ -11,6 +11,12 @@ const northstars_1 = require("../../../lib/northstars");
11
11
  * hours later against a portfolio that has since changed is invalidated rather
12
12
  * than forced through. That is the point of approving an INTENT rather than
13
13
  * queueing a command.
14
+ *
15
+ * ONE exit rule: the command exits 0 only when the thing asked for now holds
16
+ * (an approval left the intent `applied`, a rejection left it `rejected`).
17
+ * Retrying a decision that already took effect is a replay and also exits 0;
18
+ * everything else exits 1 with a sentence, and `--json` keeps the raw code plus
19
+ * `reasonText`.
14
20
  */
15
21
  class NorthstarsIntentsDecide extends base_command_1.BaseCommand {
16
22
  static description = 'Approve or reject a pending northstar management intent';
@@ -40,32 +46,80 @@ class NorthstarsIntentsDecide extends base_command_1.BaseCommand {
40
46
  if (!flags.approve && !flags.reject) {
41
47
  this.error('Pass --approve or --reject.');
42
48
  }
49
+ const ctx = {
50
+ northstarId: args.northstarId,
51
+ intentId: args.intentId,
52
+ decision: flags.approve ? 'approve' : 'reject',
53
+ bin: this.config.bin,
54
+ };
43
55
  let result;
44
56
  try {
45
57
  result = await northstars_1.northstarApi.decideIntent(args.northstarId, args.intentId, {
46
- decision: flags.approve ? 'approve' : 'reject',
58
+ decision: ctx.decision,
47
59
  ...(flags.review ? { reviewId: flags.review } : {}),
48
60
  });
49
61
  }
50
62
  catch (err) {
63
+ // The server refuses a decision with a bare code (`northstar_version_drift`,
64
+ // `intent_not_pending`). Say what it means, and keep the code.
65
+ const status = err?.status;
66
+ const { body } = (0, base_command_1.apiRefusal)(err);
67
+ if ((status === 404 || status === 409) && body && typeof body.reason === 'string') {
68
+ const { code, text } = (0, northstars_1.describeDecisionRefusal)(body, ctx);
69
+ // A retry of a decision that already took effect (the first response was
70
+ // lost, or a hedge raced itself) leaves the state that was asked for.
71
+ const verdict = typeof body.verdict === 'string' ? body.verdict : undefined;
72
+ const alreadyHolds = code === 'intent_not_pending' &&
73
+ ((ctx.decision === 'approve' && verdict === 'applied') ||
74
+ (ctx.decision === 'reject' && verdict === 'rejected'));
75
+ if (alreadyHolds) {
76
+ if (flags.json) {
77
+ this.log(JSON.stringify({
78
+ ok: true,
79
+ verdict,
80
+ replayed: true,
81
+ ...(body.decidedAt ? { decidedAt: body.decidedAt } : {}),
82
+ ...(body.decidedByYou !== undefined ? { decidedByYou: body.decidedByYou } : {}),
83
+ reasonText: text,
84
+ }, null, 2));
85
+ }
86
+ else {
87
+ this.log(`${args.intentId} → ${verdict}`);
88
+ this.log(text);
89
+ }
90
+ return;
91
+ }
92
+ this.failWithCliError({
93
+ message: text,
94
+ code,
95
+ status,
96
+ exit: 1,
97
+ retryable: false,
98
+ details: { ...body, reasonText: text },
99
+ });
100
+ }
51
101
  this.handleApiError(err);
52
102
  }
53
- if (flags.json) {
54
- this.log(JSON.stringify(result, null, 2));
55
- return;
56
- }
57
- const verdict = String(result.verdict ?? 'unknown');
58
- if (result.proposalOnly) {
59
- // A proposal is a decision to act BY HAND. Saying so avoids the reasonable
60
- // assumption that approving it made something happen.
61
- this.log(`Recorded: ${args.intentId} approved as a proposal — no mutation was performed.`);
103
+ const outcome = (0, northstars_1.describeDecisionOutcome)(result, ctx);
104
+ if (outcome.exitCode === 0) {
105
+ if (flags.json) {
106
+ this.log(JSON.stringify({ ...result, ...(outcome.text ? { reasonText: outcome.text } : {}) }, null, 2));
107
+ return;
108
+ }
109
+ this.log(outcome.headline);
110
+ if (outcome.text)
111
+ this.log(outcome.text);
62
112
  return;
63
113
  }
64
- this.log(`${args.intentId} → ${verdict}`);
65
- const applyResult = result.applyResult;
66
- if (applyResult && applyResult.applied !== true && applyResult.reason) {
67
- this.log(`Not applied: ${String(applyResult.reason)}`);
68
- }
114
+ if (!flags.json)
115
+ this.log(outcome.headline);
116
+ this.failWithCliError({
117
+ message: outcome.text ?? outcome.headline,
118
+ code: outcome.code ?? 'intent_not_applied',
119
+ exit: 1,
120
+ retryable: false,
121
+ details: { ...result, reasonText: outcome.text },
122
+ });
69
123
  }
70
124
  }
71
125
  exports.default = NorthstarsIntentsDecide;
@@ -1,6 +1,6 @@
1
1
  import { BaseCommand } from '../../../base-command';
2
2
  /**
3
- * `skrr northstars intents <northstar-id>` — management intents across recent
3
+ * `skrr northstars intents list <northstar-id>` — management intents across recent
4
4
  * reviews, newest first.
5
5
  *
6
6
  * Flattened across reviews on purpose: the question a person asks is "what is
@@ -17,6 +17,7 @@ export default class NorthstarsIntentsList extends BaseCommand {
17
17
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
18
  status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
19
19
  limit: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
20
+ wide: import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
21
  };
21
22
  run(): Promise<void>;
22
23
  }
@@ -5,7 +5,7 @@ const core_1 = require("@oclif/core");
5
5
  const base_command_1 = require("../../../base-command");
6
6
  const northstars_1 = require("../../../lib/northstars");
7
7
  /**
8
- * `skrr northstars intents <northstar-id>` — management intents across recent
8
+ * `skrr northstars intents list <northstar-id>` — management intents across recent
9
9
  * reviews, newest first.
10
10
  *
11
11
  * Flattened across reviews on purpose: the question a person asks is "what is
@@ -15,9 +15,9 @@ const northstars_1 = require("../../../lib/northstars");
15
15
  class NorthstarsIntentsList extends base_command_1.BaseCommand {
16
16
  static description = 'List northstar management intents (default: everything recent)';
17
17
  static examples = [
18
- '<%= config.bin %> northstars intents nst_abc123',
19
- '<%= config.bin %> northstars intents nst_abc123 --status awaiting_approval',
20
- '<%= config.bin %> northstars intents nst_abc123 --status applied --json',
18
+ '<%= config.bin %> northstars intents list nst_abc123',
19
+ '<%= config.bin %> northstars intents list nst_abc123 --status awaiting_approval',
20
+ '<%= config.bin %> northstars intents list nst_abc123 --status applied --json',
21
21
  ];
22
22
  static args = {
23
23
  northstarId: core_1.Args.string({ ignoreStdin: true, description: 'Northstar ID', required: true }),
@@ -29,6 +29,7 @@ class NorthstarsIntentsList extends base_command_1.BaseCommand {
29
29
  options: [...northstars_1.NORTHSTAR_INTENT_VERDICTS],
30
30
  }),
31
31
  limit: core_1.Flags.integer({ description: 'Max intents (1..500)', min: 1, max: 500 }),
32
+ wide: northstars_1.northstarWideFlag,
32
33
  };
33
34
  async run() {
34
35
  this.requireAuth();
@@ -47,7 +48,16 @@ class NorthstarsIntentsList extends base_command_1.BaseCommand {
47
48
  this.printJsonResult((0, list_output_1.listResult)(response));
48
49
  return;
49
50
  }
50
- (0, northstars_1.renderIntentList)(response.data ?? [], (line) => this.log(line));
51
+ const rows = response.data ?? [];
52
+ (0, northstars_1.renderIntentList)(rows, (line) => this.log(line), { wide: flags.wide });
53
+ const footer = (0, northstars_1.listFooter)({
54
+ shown: rows.length,
55
+ hasMore: response.has_more === true,
56
+ limit: flags.limit ?? 100,
57
+ max: 500,
58
+ });
59
+ if (footer)
60
+ this.log(footer);
51
61
  }
52
62
  }
53
63
  exports.default = NorthstarsIntentsList;
@@ -0,0 +1,26 @@
1
+ import NorthstarsIntentsList from './intents/list';
2
+ /**
3
+ * `skrr northstars intents <northstar-id>` — the topic's default: list the intents.
4
+ *
5
+ * `intents` is a topic (`list`, `decide`), and every sibling read command
6
+ * (`show`, `reviews`) works with just a northstar id. Without this command
7
+ * `northstars intents nst_abc123` was answered with "is not a command" and a
8
+ * did-you-mean that listed `create` and `delete` first, while the help examples
9
+ * printed exactly that form. Listing is read-only, so it is the safe default; the
10
+ * subcommands are untouched (oclif resolves the longest command id first, so
11
+ * `intents decide …` and `intents list …` still reach their own commands).
12
+ *
13
+ * With no northstar id it prints the topic help instead of a bare missing-argument error.
14
+ */
15
+ export default class NorthstarsIntents extends NorthstarsIntentsList {
16
+ static description: string;
17
+ static examples: string[];
18
+ static args: typeof NorthstarsIntentsList.args;
19
+ static flags: {
20
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
21
+ status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
22
+ limit: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
23
+ wide: import("@oclif/core/interfaces").BooleanFlag<boolean>;
24
+ };
25
+ run(): Promise<void>;
26
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const core_1 = require("@oclif/core");
7
+ const list_1 = __importDefault(require("./intents/list"));
8
+ /**
9
+ * `skrr northstars intents <northstar-id>` — the topic's default: list the intents.
10
+ *
11
+ * `intents` is a topic (`list`, `decide`), and every sibling read command
12
+ * (`show`, `reviews`) works with just a northstar id. Without this command
13
+ * `northstars intents nst_abc123` was answered with "is not a command" and a
14
+ * did-you-mean that listed `create` and `delete` first, while the help examples
15
+ * printed exactly that form. Listing is read-only, so it is the safe default; the
16
+ * subcommands are untouched (oclif resolves the longest command id first, so
17
+ * `intents decide …` and `intents list …` still reach their own commands).
18
+ *
19
+ * With no northstar id it prints the topic help instead of a bare missing-argument error.
20
+ */
21
+ class NorthstarsIntents extends list_1.default {
22
+ static description = 'List northstar management intents; subcommands: list, decide (`intents <id>` is `intents list <id>`)';
23
+ static examples = [
24
+ '<%= config.bin %> northstars intents nst_abc123',
25
+ '<%= config.bin %> northstars intents nst_abc123 --status awaiting_approval',
26
+ '<%= config.bin %> northstars intents list nst_abc123',
27
+ '<%= config.bin %> northstars intents decide nst_abc123 nsi_xyz --approve',
28
+ ];
29
+ // Own, not inherited: oclif spreads the command class into the parser input, and a static a
30
+ // subclass only inherits is dropped (OSK-15346). The argument is optional so a bare
31
+ // `skrr northstars intents` can show the subcommands rather than fail on a missing id.
32
+ static args = {
33
+ northstarId: core_1.Args.string({
34
+ ignoreStdin: true,
35
+ description: 'Northstar ID (omit to see the subcommands)',
36
+ required: false,
37
+ }),
38
+ };
39
+ static flags = list_1.default.flags;
40
+ async run() {
41
+ const { args } = await this.parse(NorthstarsIntents);
42
+ if (!args.northstarId) {
43
+ await this.config.runCommand('help', ['northstars', 'intents']);
44
+ return;
45
+ }
46
+ await super.run();
47
+ }
48
+ }
49
+ exports.default = NorthstarsIntents;
@@ -13,6 +13,7 @@ export default class NorthstarsList extends BaseCommand {
13
13
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
14
  status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
15
  limit: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
+ cursor: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
17
  };
17
18
  run(): Promise<void>;
18
19
  }
@@ -21,14 +21,24 @@ class NorthstarsList extends base_command_1.BaseCommand {
21
21
  static flags = {
22
22
  json: core_1.Flags.boolean({ description: 'Output as JSON' }),
23
23
  status: core_1.Flags.string({ description: 'Filter by status', options: [...northstars_1.NORTHSTAR_STATUSES] }),
24
- limit: core_1.Flags.integer({ description: 'Max results (1..100)', min: 1, max: 100 }),
24
+ limit: core_1.Flags.integer({ description: 'Max results (1..100, default 50)', min: 1, max: 100 }),
25
+ cursor: core_1.Flags.string({
26
+ description: 'Continue from the next_cursor a previous page returned',
27
+ }),
25
28
  };
26
29
  async run() {
27
30
  this.requireAuth();
28
31
  const { flags } = await this.parse(NorthstarsList);
29
32
  let response;
30
33
  try {
31
- response = await northstars_1.northstarApi.list({ status: flags.status, limit: flags.limit });
34
+ // Cursor paging is always on: it is the only list path that returns a cursor, and the
35
+ // default page is sent explicitly so it stays the 50 this command always listed.
36
+ response = await northstars_1.northstarApi.list({
37
+ status: flags.status,
38
+ limit: flags.limit ?? northstars_1.NORTHSTAR_LIST_DEFAULT_LIMIT,
39
+ pagination: 'cursor',
40
+ cursor: flags.cursor,
41
+ });
32
42
  }
33
43
  catch (err) {
34
44
  this.handleApiError(err);
@@ -37,7 +47,18 @@ class NorthstarsList extends base_command_1.BaseCommand {
37
47
  this.printJsonResult((0, list_output_1.listResult)(response));
38
48
  return;
39
49
  }
40
- (0, northstars_1.renderNorthstarList)(response.data ?? [], (line) => this.log(line));
50
+ const rows = response.data ?? [];
51
+ (0, northstars_1.renderNorthstarList)(rows, (line) => this.log(line));
52
+ const footer = (0, northstars_1.listFooter)({
53
+ shown: rows.length,
54
+ hasMore: response.has_more === true,
55
+ limit: flags.limit ?? northstars_1.NORTHSTAR_LIST_DEFAULT_LIMIT,
56
+ max: 100,
57
+ nextCursor: response.next_cursor,
58
+ cursor: true,
59
+ });
60
+ if (footer)
61
+ this.log(footer);
41
62
  }
42
63
  }
43
64
  exports.default = NorthstarsList;
@@ -1,6 +1,6 @@
1
1
  import { BaseCommand } from '../../../base-command';
2
2
  /**
3
- * `skrr northstars recommendations <id>` — the deterministic reviewer's
3
+ * `skrr northstars recommendations list <id>` — the deterministic reviewer's
4
4
  * user-facing suggestions.
5
5
  *
6
6
  * These are NOT the same thing as management intents. A recommendation is
@@ -5,7 +5,7 @@ const core_1 = require("@oclif/core");
5
5
  const base_command_1 = require("../../../base-command");
6
6
  const northstars_1 = require("../../../lib/northstars");
7
7
  /**
8
- * `skrr northstars recommendations <id>` — the deterministic reviewer's
8
+ * `skrr northstars recommendations list <id>` — the deterministic reviewer's
9
9
  * user-facing suggestions.
10
10
  *
11
11
  * These are NOT the same thing as management intents. A recommendation is
@@ -16,8 +16,8 @@ const northstars_1 = require("../../../lib/northstars");
16
16
  class NorthstarsRecommendationsList extends base_command_1.BaseCommand {
17
17
  static description = "List a northstar's deterministic portfolio recommendations";
18
18
  static examples = [
19
- '<%= config.bin %> northstars recommendations nst_abc123',
20
- '<%= config.bin %> northstars recommendations nst_abc123 --status open',
19
+ '<%= config.bin %> northstars recommendations list nst_abc123',
20
+ '<%= config.bin %> northstars recommendations list nst_abc123 --status open',
21
21
  ];
22
22
  static args = {
23
23
  northstarId: core_1.Args.string({ ignoreStdin: true, description: 'Northstar ID', required: true }),
@@ -0,0 +1,19 @@
1
+ import NorthstarsRecommendationsList from './recommendations/list';
2
+ /**
3
+ * `skrr northstars recommendations <northstar-id>` — the topic's default: list them.
4
+ *
5
+ * Same reasoning as `northstars intents`: the help examples showed this form and it was
6
+ * answered with "is not a command". Listing is read-only, so it is the safe default;
7
+ * `recommendations apply` and `recommendations dismiss` still resolve to their own
8
+ * commands (the longest command id wins). With no northstar id it prints the topic help.
9
+ */
10
+ export default class NorthstarsRecommendations extends NorthstarsRecommendationsList {
11
+ static description: string;
12
+ static examples: string[];
13
+ static args: typeof NorthstarsRecommendationsList.args;
14
+ static flags: {
15
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
+ status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ };
18
+ run(): Promise<void>;
19
+ }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const core_1 = require("@oclif/core");
7
+ const list_1 = __importDefault(require("./recommendations/list"));
8
+ /**
9
+ * `skrr northstars recommendations <northstar-id>` — the topic's default: list them.
10
+ *
11
+ * Same reasoning as `northstars intents`: the help examples showed this form and it was
12
+ * answered with "is not a command". Listing is read-only, so it is the safe default;
13
+ * `recommendations apply` and `recommendations dismiss` still resolve to their own
14
+ * commands (the longest command id wins). With no northstar id it prints the topic help.
15
+ */
16
+ class NorthstarsRecommendations extends list_1.default {
17
+ static description = "List a northstar's recommendations; subcommands: list, apply, dismiss (`recommendations <id>` is `recommendations list <id>`)";
18
+ static examples = [
19
+ '<%= config.bin %> northstars recommendations nst_abc123',
20
+ '<%= config.bin %> northstars recommendations nst_abc123 --status open',
21
+ '<%= config.bin %> northstars recommendations list nst_abc123',
22
+ '<%= config.bin %> northstars recommendations apply nst_abc123 <rec-id>',
23
+ ];
24
+ // Own, not inherited (see `northstars intents`).
25
+ static args = {
26
+ northstarId: core_1.Args.string({
27
+ ignoreStdin: true,
28
+ description: 'Northstar ID (omit to see the subcommands)',
29
+ required: false,
30
+ }),
31
+ };
32
+ static flags = list_1.default.flags;
33
+ async run() {
34
+ const { args } = await this.parse(NorthstarsRecommendations);
35
+ if (!args.northstarId) {
36
+ await this.config.runCommand('help', ['northstars', 'recommendations']);
37
+ return;
38
+ }
39
+ await super.run();
40
+ }
41
+ }
42
+ exports.default = NorthstarsRecommendations;
@@ -16,6 +16,7 @@ export default class NorthstarsReviewNow extends BaseCommand {
16
16
  };
17
17
  static flags: {
18
18
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
19
+ wide: import("@oclif/core/interfaces").BooleanFlag<boolean>;
19
20
  };
20
21
  run(): Promise<void>;
21
22
  }
@@ -23,6 +23,7 @@ class NorthstarsReviewNow extends base_command_1.BaseCommand {
23
23
  };
24
24
  static flags = {
25
25
  json: core_1.Flags.boolean({ description: 'Output as JSON' }),
26
+ wide: northstars_1.northstarWideFlag,
26
27
  };
27
28
  async run() {
28
29
  this.requireAuth();
@@ -44,18 +45,23 @@ class NorthstarsReviewNow extends base_command_1.BaseCommand {
44
45
  if (review) {
45
46
  this.log(`Review ${String(review.id)} (${String(review.status)})`);
46
47
  }
47
- const allocations = Array.isArray(result.allocations) ? result.allocations.length : 0;
48
- this.log(`Allocations ${allocations} commitment(s) re-budgeted`);
48
+ this.log((0, northstars_1.describeReviewAllocations)(result));
49
49
  this.log(`Applied ${String(result.appliedIntents ?? 0)} intent(s)`);
50
50
  if (governanceRun) {
51
51
  this.log(governanceRun.reserved
52
52
  ? `Agent run ${String(governanceRun.runId)} reserved — results land asynchronously`
53
- : `Agent run not started (${String(governanceRun.reason ?? 'unknown')})`);
53
+ : `Agent run not started: ${(0, northstars_1.describeNorthstarReason)(typeof governanceRun.reason === 'string' ? governanceRun.reason : undefined)}`);
54
54
  }
55
55
  const intents = review?.intents ?? [];
56
+ // An intent budget that cut the review short must not read as "nothing to report".
57
+ const snapshot = review?.deterministicSnapshot;
58
+ const governance = result.governance;
59
+ const budgetNote = (0, northstars_1.intentBudgetNote)(snapshot?.truncatedIntents, governance?.maxIntentsPerReview);
60
+ if (budgetNote)
61
+ this.log(budgetNote);
56
62
  if (intents.length) {
57
63
  this.log('');
58
- (0, northstars_1.renderIntentList)(intents, (line) => this.log(line));
64
+ (0, northstars_1.renderIntentList)(intents, (line) => this.log(line), { wide: flags.wide });
59
65
  }
60
66
  }
61
67
  }
@@ -18,6 +18,7 @@ export default class NorthstarsReviews extends BaseCommand {
18
18
  limit: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
19
19
  status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
20
20
  review: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
21
+ wide: import("@oclif/core/interfaces").BooleanFlag<boolean>;
21
22
  };
22
23
  run(): Promise<void>;
23
24
  }
@@ -29,6 +29,7 @@ class NorthstarsReviews extends base_command_1.BaseCommand {
29
29
  options: [...northstars_1.NORTHSTAR_REVIEW_STATUSES],
30
30
  }),
31
31
  review: core_1.Flags.string({ description: 'Show ONE review in full, including its intents' }),
32
+ wide: northstars_1.northstarWideFlag,
32
33
  };
33
34
  async run() {
34
35
  this.requireAuth();
@@ -53,14 +54,20 @@ class NorthstarsReviews extends base_command_1.BaseCommand {
53
54
  if (review.autonomousRunId)
54
55
  this.log(`Agent run ${review.autonomousRunId}`);
55
56
  if (review.reason)
56
- this.log(`Reason ${review.reason}`);
57
+ this.log(`Reason ${(0, northstars_1.describeReviewReason)(review.reason)}`);
57
58
  const snapshot = review.deterministicSnapshot;
58
59
  if (snapshot) {
59
60
  this.log(`Health ${String(snapshot.health ?? '—')}`);
60
61
  this.log(`Allocations written ${String(snapshot.allocationsWritten ?? 0)}`);
61
62
  }
63
+ // A review the intent budget cut short is not a review with nothing to say.
64
+ const budgetNote = (0, northstars_1.intentBudgetNote)(snapshot?.truncatedIntents, snapshot?.intentCounts?.total);
65
+ if (budgetNote)
66
+ this.log(budgetNote);
62
67
  this.log('');
63
- (0, northstars_1.renderIntentList)(review.intents ?? [], (line) => this.log(line));
68
+ if (budgetNote && (review.intents ?? []).length === 0)
69
+ return;
70
+ (0, northstars_1.renderIntentList)(review.intents ?? [], (line) => this.log(line), { wide: flags.wide });
64
71
  return;
65
72
  }
66
73
  let response;
@@ -77,7 +84,16 @@ class NorthstarsReviews extends base_command_1.BaseCommand {
77
84
  this.log(JSON.stringify(response, null, 2));
78
85
  return;
79
86
  }
80
- (0, northstars_1.renderReviewList)(response.data ?? [], (line) => this.log(line));
87
+ const rows = response.data ?? [];
88
+ (0, northstars_1.renderReviewList)(rows, (line) => this.log(line));
89
+ const footer = (0, northstars_1.listFooter)({
90
+ shown: rows.length,
91
+ hasMore: response.has_more === true,
92
+ limit: flags.limit ?? 20,
93
+ max: 100,
94
+ });
95
+ if (footer)
96
+ this.log(footer);
81
97
  }
82
98
  }
83
99
  exports.default = NorthstarsReviews;
@@ -32,7 +32,10 @@ class NorthstarsUpdate extends base_command_1.BaseCommand {
32
32
  tier: core_1.Flags.string({ description: 'Priority tier', options: [...northstars_1.NORTHSTAR_PRIORITY_TIERS] }),
33
33
  weight: core_1.Flags.integer({ description: 'Priority weight (0..100)', min: 0, max: 100 }),
34
34
  'total-weight': core_1.Flags.integer({ description: 'Attention budget total weight', min: 0 }),
35
- 'max-active': core_1.Flags.integer({ description: 'Soft cap on active commitments', min: 0 }),
35
+ 'max-active': core_1.Flags.integer({
36
+ description: 'Soft cap on active commitments (0 = no cap)',
37
+ min: 0,
38
+ }),
36
39
  goal: core_1.Flags.string({ description: 'Goal ID (repeatable; replaces the list)', multiple: true }),
37
40
  agent: core_1.Flags.string({
38
41
  description: 'Agent ID (repeatable; replaces the list)',
@@ -109,6 +112,10 @@ class NorthstarsUpdate extends base_command_1.BaseCommand {
109
112
  return;
110
113
  }
111
114
  this.log(`Updated ${northstar.id} — ${northstar.title} (${northstar.status}, v${northstar.version})`);
115
+ // 0 is stored, and a review treats it as "no cap": say so here, not only in `show` (OSK-21252).
116
+ if (flags['max-active'] !== undefined) {
117
+ this.log(`Attention max active ${(0, northstars_1.describeMaxActive)(northstar.attentionBudget?.maxActiveCommitments ?? flags['max-active'])}`);
118
+ }
112
119
  }
113
120
  }
114
121
  exports.default = NorthstarsUpdate;
@@ -31,12 +31,21 @@ function emptyPageLines(narrowed, nextCursor) {
31
31
  * server could not read for this viewer is in `--json`), never "none".
32
32
  */
33
33
  function aboutFor(row) {
34
- return [row.commitmentTitle, row.agent?.name].filter(Boolean).join(' · ') || '—';
34
+ const named = [row.commitmentTitle, row.agent?.name].filter(Boolean).join(' · ');
35
+ if (named)
36
+ return named;
37
+ // A Northstar intent that targets no commitment (a proposal to start one) is about its northstar.
38
+ const northstarId = row.decisionContext?.northstarId;
39
+ return northstarId ? `northstar ${northstarId}` : '—';
35
40
  }
36
41
  /** A snoozed proposal reads `proposed` in its disposition; the wake time is what tells them apart. */
37
42
  function noteFor(row) {
38
43
  if (row.sourceStatus === 'snoozed' && row.snoozedUntil)
39
44
  return `snoozed until ${row.snoozedUntil}`;
45
+ // The inbox files a policy refusal under `discarded`; for a Northstar intent say what it was.
46
+ const intent = (0, proposals_1.northstarIntentNote)(row);
47
+ if (intent)
48
+ return intent;
40
49
  if (!row.canDecide && row.undecidableReason && row.undecidableReason !== 'settled')
41
50
  return data_provider_1.PROPOSAL_UNDECIDABLE_TEXT[row.undecidableReason];
42
51
  return '—';
@@ -86,7 +95,7 @@ class ProposalsList extends base_command_1.BaseCommand {
86
95
  }
87
96
  (0, format_1.renderTable)(result.data.map((row) => ({
88
97
  id: row.id,
89
- title: row.title,
98
+ title: (0, proposals_1.proposalTitleFor)(row),
90
99
  about: aboutFor(row),
91
100
  disposition: row.disposition,
92
101
  // Most proposals carry no estimate; "unknown" read as a failure to determine one (OSK-15377).
@@ -22,7 +22,7 @@ class ProposalsShow extends base_command_1.BaseCommand {
22
22
  static flags = { json: core_1.Flags.boolean() };
23
23
  async run() {
24
24
  this.requireAuth();
25
- const { args } = await this.parse(ProposalsShow);
25
+ const { args, flags } = await this.parse(ProposalsShow);
26
26
  const ref = (0, proposals_1.resolveProposalRef)(args.kind, args.id, this.config?.bin);
27
27
  if ('error' in ref) {
28
28
  this.failWithCliError({
@@ -48,6 +48,14 @@ class ProposalsShow extends base_command_1.BaseCommand {
48
48
  }
49
49
  this.handleApiError(error);
50
50
  }
51
+ // A Northstar intent reads as words unless --json asks for the document; every other kind still
52
+ // prints its full JSON, so a script that reads it does not change.
53
+ const lines = flags.json ? null : (0, proposals_1.renderNorthstarIntentView)(result);
54
+ if (lines) {
55
+ for (const line of lines)
56
+ this.log(line);
57
+ return;
58
+ }
51
59
  this.log(JSON.stringify(result, null, 2));
52
60
  }
53
61
  }
@@ -1,5 +1,17 @@
1
- import { type SpaceAutoExecutorRefillState } from '@skrr-ai/data-provider';
1
+ import { type SpaceAutoExecutorPreviewResponse, type SpaceAutoExecutorRefillState } from '@skrr-ai/data-provider';
2
2
  import { BaseCommand } from '../../../base-command';
3
+ type PreviewSpace = SpaceAutoExecutorPreviewResponse['space'];
4
+ /**
5
+ * "Can start" is a capacity figure, not a forecast. Printed bare next to a disabled autopilot
6
+ * it read as "one task will start now" (dogfooded: `Autopilot: disabled` / `Can start: 1 now`).
7
+ */
8
+ export declare function canStartLine(space: Pick<PreviewSpace, 'autoExecuteEnabled'>, startsAvailable: number | null): string;
9
+ /**
10
+ * Whether unattended work may run in the Space at all. Turning the board off does not revoke the
11
+ * principal and a revoked one keeps a disabled board silent, so the two have to be told apart.
12
+ * Returns null for a server that predates the field, so an old API prints no claim.
13
+ */
14
+ export declare function principalLine(space: Pick<PreviewSpace, 'executionPrincipal'>, spaceRef: string): string | null;
3
15
  export default class SpacesAutoExecutorPreview extends BaseCommand {
4
16
  static description: string;
5
17
  static examples: string[];
@@ -18,3 +30,4 @@ export default class SpacesAutoExecutorPreview extends BaseCommand {
18
30
  * not report it; `null` is one that could not read it, and says so.
19
31
  */
20
32
  export declare function refillLines(refill: SpaceAutoExecutorRefillState | null | undefined): string[];
33
+ export {};