@skrr-ai/cli 0.1.107 → 0.1.109

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 (175) hide show
  1. package/README.md +10 -0
  2. package/dist/base-command.d.ts +59 -0
  3. package/dist/base-command.js +118 -7
  4. package/dist/commands/agents/update.d.ts +14 -0
  5. package/dist/commands/agents/update.js +40 -1
  6. package/dist/commands/commitments/accounting.js +7 -2
  7. package/dist/commands/commitments/cost.d.ts +11 -0
  8. package/dist/commands/commitments/cost.js +26 -3
  9. package/dist/commands/commitments/create.js +2 -1
  10. package/dist/commands/commitments/operating-review.d.ts +15 -0
  11. package/dist/commands/commitments/operating-review.js +103 -50
  12. package/dist/commands/commitments/update.js +12 -5
  13. package/dist/commands/doctor.js +9 -0
  14. package/dist/commands/goals/list.js +6 -1
  15. package/dist/commands/grants/rotate.js +4 -0
  16. package/dist/commands/login.js +42 -14
  17. package/dist/commands/machines/list.js +28 -6
  18. package/dist/commands/projects/show.js +1 -1
  19. package/dist/commands/revoke-daemon.js +2 -1
  20. package/dist/commands/spaces/workflows/archive.d.ts +1 -0
  21. package/dist/commands/spaces/workflows/archive.js +1 -0
  22. package/dist/commands/spaces/workflows/artifact.d.ts +1 -0
  23. package/dist/commands/spaces/workflows/artifact.js +1 -0
  24. package/dist/commands/spaces/workflows/cancel-node.d.ts +1 -0
  25. package/dist/commands/spaces/workflows/cancel-node.js +1 -0
  26. package/dist/commands/spaces/workflows/cancel.d.ts +1 -0
  27. package/dist/commands/spaces/workflows/cancel.js +6 -2
  28. package/dist/commands/spaces/workflows/create.d.ts +1 -0
  29. package/dist/commands/spaces/workflows/create.js +7 -1
  30. package/dist/commands/spaces/workflows/events.d.ts +1 -0
  31. package/dist/commands/spaces/workflows/events.js +1 -0
  32. package/dist/commands/spaces/workflows/fixtures/create.d.ts +1 -0
  33. package/dist/commands/spaces/workflows/fixtures/create.js +1 -0
  34. package/dist/commands/spaces/workflows/fixtures/list.d.ts +1 -0
  35. package/dist/commands/spaces/workflows/fixtures/list.js +1 -0
  36. package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +1 -0
  37. package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +1 -0
  38. package/dist/commands/spaces/workflows/list.d.ts +1 -0
  39. package/dist/commands/spaces/workflows/list.js +1 -0
  40. package/dist/commands/spaces/workflows/node-types.d.ts +2 -0
  41. package/dist/commands/spaces/workflows/node-types.js +24 -6
  42. package/dist/commands/spaces/workflows/pause.d.ts +1 -0
  43. package/dist/commands/spaces/workflows/pause.js +1 -0
  44. package/dist/commands/spaces/workflows/plan/show.d.ts +1 -0
  45. package/dist/commands/spaces/workflows/plan/show.js +1 -0
  46. package/dist/commands/spaces/workflows/plan/update.d.ts +1 -0
  47. package/dist/commands/spaces/workflows/plan/update.js +1 -0
  48. package/dist/commands/spaces/workflows/proposals/apply.d.ts +1 -0
  49. package/dist/commands/spaces/workflows/proposals/apply.js +1 -0
  50. package/dist/commands/spaces/workflows/proposals/confirm.d.ts +1 -0
  51. package/dist/commands/spaces/workflows/proposals/confirm.js +1 -0
  52. package/dist/commands/spaces/workflows/proposals/create.d.ts +1 -0
  53. package/dist/commands/spaces/workflows/proposals/create.js +1 -0
  54. package/dist/commands/spaces/workflows/proposals/dismiss.d.ts +1 -0
  55. package/dist/commands/spaces/workflows/proposals/dismiss.js +1 -0
  56. package/dist/commands/spaces/workflows/proposals/list.d.ts +1 -0
  57. package/dist/commands/spaces/workflows/proposals/list.js +1 -0
  58. package/dist/commands/spaces/workflows/publish.d.ts +1 -0
  59. package/dist/commands/spaces/workflows/publish.js +9 -0
  60. package/dist/commands/spaces/workflows/reconcile.d.ts +1 -0
  61. package/dist/commands/spaces/workflows/reconcile.js +1 -0
  62. package/dist/commands/spaces/workflows/resume.d.ts +1 -0
  63. package/dist/commands/spaces/workflows/resume.js +1 -0
  64. package/dist/commands/spaces/workflows/retry.d.ts +1 -0
  65. package/dist/commands/spaces/workflows/retry.js +1 -0
  66. package/dist/commands/spaces/workflows/run.d.ts +1 -0
  67. package/dist/commands/spaces/workflows/run.js +14 -7
  68. package/dist/commands/spaces/workflows/runs.d.ts +1 -0
  69. package/dist/commands/spaces/workflows/runs.js +1 -0
  70. package/dist/commands/spaces/workflows/show.d.ts +25 -0
  71. package/dist/commands/spaces/workflows/show.js +42 -4
  72. package/dist/commands/spaces/workflows/signal.d.ts +12 -0
  73. package/dist/commands/spaces/workflows/signal.js +40 -2
  74. package/dist/commands/spaces/workflows/start.d.ts +1 -0
  75. package/dist/commands/spaces/workflows/start.js +1 -0
  76. package/dist/commands/spaces/workflows/task-execution/create.d.ts +1 -0
  77. package/dist/commands/spaces/workflows/task-execution/create.js +1 -0
  78. package/dist/commands/spaces/workflows/test.d.ts +1 -0
  79. package/dist/commands/spaces/workflows/test.js +1 -0
  80. package/dist/commands/spaces/workflows/triggers/create.d.ts +1 -0
  81. package/dist/commands/spaces/workflows/triggers/create.js +1 -0
  82. package/dist/commands/spaces/workflows/triggers/fire.d.ts +1 -0
  83. package/dist/commands/spaces/workflows/triggers/fire.js +1 -0
  84. package/dist/commands/spaces/workflows/triggers/list.d.ts +1 -0
  85. package/dist/commands/spaces/workflows/triggers/list.js +1 -0
  86. package/dist/commands/spaces/workflows/triggers/update.d.ts +1 -0
  87. package/dist/commands/spaces/workflows/triggers/update.js +1 -0
  88. package/dist/commands/spaces/workflows/update.d.ts +1 -0
  89. package/dist/commands/spaces/workflows/update.js +4 -0
  90. package/dist/commands/spaces/workflows/validate.d.ts +1 -0
  91. package/dist/commands/spaces/workflows/validate.js +15 -0
  92. package/dist/commands/tasks/activity.js +6 -2
  93. package/dist/commands/tasks/bulk-update.d.ts +1 -0
  94. package/dist/commands/tasks/bulk-update.js +7 -0
  95. package/dist/commands/tasks/complete.js +2 -1
  96. package/dist/commands/tasks/create-tree.d.ts +69 -0
  97. package/dist/commands/tasks/create-tree.js +413 -47
  98. package/dist/commands/tasks/list.d.ts +2 -0
  99. package/dist/commands/tasks/list.js +19 -1
  100. package/dist/commands/tasks/rearm-recurrence.d.ts +22 -0
  101. package/dist/commands/tasks/rearm-recurrence.js +68 -0
  102. package/dist/commands/tasks/show.d.ts +1 -0
  103. package/dist/commands/tasks/show.js +17 -3
  104. package/dist/commands/tasks/timeline.js +4 -0
  105. package/dist/commands/tasks/update.d.ts +1 -0
  106. package/dist/commands/tasks/update.js +6 -1
  107. package/dist/commands/triggers/create.js +8 -2
  108. package/dist/commands/triggers/parse-intent.d.ts +7 -0
  109. package/dist/commands/triggers/parse-intent.js +31 -9
  110. package/dist/commands/workspaces/grants.js +23 -3
  111. package/dist/commands/workspaces/members.d.ts +20 -0
  112. package/dist/commands/workspaces/members.js +64 -0
  113. package/dist/commands/workspaces/stewardship.js +14 -2
  114. package/dist/help.js +12 -0
  115. package/dist/hooks/command-not-found.js +27 -1
  116. package/dist/lib/command-miss.d.ts +52 -2
  117. package/dist/lib/command-miss.js +187 -18
  118. package/dist/lib/commitment-loop-status.d.ts +8 -0
  119. package/dist/lib/commitment-loop-status.js +45 -0
  120. package/dist/lib/commitment-product.js +13 -1
  121. package/dist/lib/commitments.d.ts +16 -2
  122. package/dist/lib/commitments.js +48 -8
  123. package/dist/lib/daemon-command-hint.d.ts +15 -0
  124. package/dist/lib/daemon-command-hint.js +21 -0
  125. package/dist/lib/daemon-setup.js +10 -1
  126. package/dist/lib/daemonBrokerRefusal.js +3 -2
  127. package/dist/lib/daemonHandoff.js +2 -1
  128. package/dist/lib/deployed-build.d.ts +43 -0
  129. package/dist/lib/deployed-build.js +66 -0
  130. package/dist/lib/grants.d.ts +27 -1
  131. package/dist/lib/grants.js +39 -21
  132. package/dist/lib/json-mode.d.ts +11 -0
  133. package/dist/lib/json-mode.js +19 -0
  134. package/dist/lib/json-output.d.ts +25 -0
  135. package/dist/lib/json-output.js +30 -0
  136. package/dist/lib/list-output.d.ts +9 -0
  137. package/dist/lib/list-output.js +20 -1
  138. package/dist/lib/local-daemon-readiness.d.ts +90 -0
  139. package/dist/lib/local-daemon-readiness.js +143 -0
  140. package/dist/lib/machines.d.ts +117 -0
  141. package/dist/lib/machines.js +139 -0
  142. package/dist/lib/managed-instruction-local.d.ts +2 -0
  143. package/dist/lib/managed-instruction-local.js +2 -0
  144. package/dist/lib/profile-machine-identity-guard.d.ts +18 -0
  145. package/dist/lib/profile-machine-identity-guard.js +29 -0
  146. package/dist/lib/request-field-flags.d.ts +20 -0
  147. package/dist/lib/request-field-flags.js +34 -0
  148. package/dist/lib/stewardship-output.d.ts +1 -1
  149. package/dist/lib/stewardship-output.js +26 -30
  150. package/dist/lib/task-batch.d.ts +61 -4
  151. package/dist/lib/task-batch.js +316 -80
  152. package/dist/lib/task-economics.d.ts +5 -0
  153. package/dist/lib/task-economics.js +15 -0
  154. package/dist/lib/task-recurrence-outcome.d.ts +6 -6
  155. package/dist/lib/task-recurrence-outcome.js +27 -3
  156. package/dist/lib/tasks.d.ts +39 -0
  157. package/dist/lib/tasks.js +132 -0
  158. package/dist/lib/triggers.d.ts +31 -1
  159. package/dist/lib/triggers.js +55 -1
  160. package/dist/lib/workflow-issues.d.ts +14 -0
  161. package/dist/lib/workflow-issues.js +32 -0
  162. package/dist/lib/workflow-run-view.d.ts +55 -0
  163. package/dist/lib/workflow-run-view.js +105 -0
  164. package/dist/lib/workspaces.d.ts +31 -4
  165. package/dist/lib/workspaces.js +43 -0
  166. package/dist/lib/write-target.d.ts +29 -0
  167. package/dist/lib/write-target.js +72 -0
  168. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/workspaceIsolationProbeWire.d.ts +51 -0
  169. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/workspaceIsolationProbeWire.js +50 -0
  170. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/workspaceIsolationProbeWire.d.ts +51 -0
  171. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/workspaceIsolationProbeWire.js +46 -0
  172. package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
  173. package/dist/node_modules/@skrr-ai/data-provider/index.js +7896 -7524
  174. package/oclif.manifest.json +376 -52
  175. package/package.json +19 -1
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.noQuestionsSentence = noQuestionsSentence;
4
+ exports.formatOperatingReview = formatOperatingReview;
4
5
  const core_1 = require("@oclif/core");
5
6
  const base_command_1 = require("../../base-command");
7
+ const commitment_loop_status_1 = require("../../lib/commitment-loop-status");
6
8
  const commitments_1 = require("../../lib/commitments");
7
9
  /** What each silent loop is for, in the owner's terms rather than the role key. */
8
10
  const ROLE_PURPOSE = {
@@ -39,6 +41,79 @@ function noQuestionsSentence(alwaysOn, roles) {
39
41
  ? 'None. It has not told you anything is missing.'
40
42
  : 'None recorded yet. None of its loops has checked, so this says nothing about whether anything is missing.';
41
43
  }
44
+ /** The review as text. Pure, so the whole output can be pinned. */
45
+ function formatOperatingReview(review, loops) {
46
+ const lines = [];
47
+ const roles = review.systemCommitments || [];
48
+ const alwaysOn = review.alwaysOn === true;
49
+ const questions = review.openQuestions || [];
50
+ const portfolio = review.portfolio || {};
51
+ const metrics = review.metrics || {};
52
+ lines.push(`Agent ${review.agentId}`);
53
+ lines.push('');
54
+ // A loop's own status says `active`, but a system-managed loop is only
55
+ // given a scheduling trigger while the Agent is Always-On. Printing
56
+ // `active` beside "last checked never" without saying that read as
57
+ // "nothing has happened yet" rather than "this cannot happen", and nothing
58
+ // led the owner to the switch that decides it.
59
+ if (!alwaysOn) {
60
+ lines.push('Always-On is OFF — these loops are provisioned but will not run.');
61
+ lines.push(` skrr agents always-on enable ${review.agentId}`);
62
+ lines.push('');
63
+ }
64
+ lines.push('Background loops');
65
+ if (roles.length === 0) {
66
+ lines.push(' (none provisioned)');
67
+ }
68
+ if ('error' in loops) {
69
+ // "Cannot see" must not read as "nothing to report": say what is missing and what it hides.
70
+ lines.push(` Loop detail unavailable (${loops.error}). The states below are the stored lifecycle only; ` +
71
+ 'they do not say whether a loop is armed, what it can read, or why it last stopped.');
72
+ }
73
+ for (const role of roles) {
74
+ const key = role.systemRole || '?';
75
+ const purpose = ROLE_PURPOSE[key] ? ` — ${ROLE_PURPOSE[key]}` : '';
76
+ const contact = role.maxUserNudgesPerDay && role.maxUserNudgesPerDay > 0
77
+ ? `may contact you ${role.maxUserNudgesPerDay}/day`
78
+ : 'never contacts you';
79
+ // `idle` replaces `active` only. A paused loop is paused for its own
80
+ // reason — Relationship Pulse ships paused as a separate consent
81
+ // decision — and collapsing that into `idle` would hide a distinction
82
+ // the owner needs when they do turn Always-On on.
83
+ const state = !alwaysOn && role.status === 'active' ? 'idle' : role.status || '?';
84
+ lines.push(` ${state.padEnd(7)} ${key}${purpose}`);
85
+ lines.push(` last checked ${ago(role.lastCheckedAt)} · ${contact}`);
86
+ if ('rows' in loops) {
87
+ const row = role.id ? loops.rows.get(role.id) : undefined;
88
+ if (row) {
89
+ for (const line of (0, commitment_loop_status_1.formatLoopSummary)(row))
90
+ lines.push(` ${line}`);
91
+ }
92
+ else {
93
+ lines.push(` loop detail: not in the roster read${loops.truncated ? ' (the roster is bounded and this Agent holds more)' : ''}; run \`skrr commitments status ${role.id ?? '<id>'}\``);
94
+ }
95
+ }
96
+ }
97
+ lines.push('');
98
+ lines.push(`Open questions from this agent (${questions.length})`);
99
+ if (questions.length === 0) {
100
+ lines.push(` ${noQuestionsSentence(alwaysOn, roles)}`);
101
+ }
102
+ for (const q of questions) {
103
+ lines.push(` • ${q.question}`);
104
+ if (q.whyItMatters)
105
+ lines.push(` why: ${q.whyItMatters}`);
106
+ lines.push(` asked ${ago(q.askedAt)}`);
107
+ }
108
+ lines.push('');
109
+ const drafts = portfolio.draftCommitmentCount ?? 0;
110
+ lines.push(`Business commitments: ${portfolio.activeCommitmentCount ?? 0} active, ${portfolio.pausedCommitmentCount ?? 0} paused${drafts > 0 ? `, ${drafts} draft` : ''}`);
111
+ if (typeof metrics.awaitingApproval === 'number') {
112
+ lines.push(`Proposals awaiting your approval: ${metrics.awaitingApproval}`);
113
+ }
114
+ lines.push(`Every commitment it holds, loop by loop: skrr commitments roster --agent ${review.agentId}`);
115
+ return lines;
116
+ }
42
117
  class CommitmentsOperatingReview extends base_command_1.BaseCommand {
43
118
  static description = 'Read an agent’s system-managed commitment operating review';
44
119
  static args = {
@@ -60,61 +135,39 @@ class CommitmentsOperatingReview extends base_command_1.BaseCommand {
60
135
  catch (error) {
61
136
  this.handleApiError(error);
62
137
  }
138
+ // The roster is a second read; its failure must not take the review down with it, and must not
139
+ // pass for "nothing to report" either.
140
+ let loops;
141
+ try {
142
+ const roster = await commitments_1.commitmentApi.roster(args.agentId);
143
+ loops = {
144
+ rows: new Map((Array.isArray(roster.commitments) ? roster.commitments : []).map((row) => [
145
+ row.commitmentId,
146
+ row,
147
+ ])),
148
+ truncated: roster.truncated === true,
149
+ };
150
+ }
151
+ catch (error) {
152
+ loops = { error: error instanceof Error ? error.message : String(error) };
153
+ }
63
154
  if (flags.json) {
64
- this.log(JSON.stringify(result, null, 2));
155
+ const review = result;
156
+ const roles = review.systemCommitments || [];
157
+ this.log(JSON.stringify('error' in loops
158
+ ? { ...review, loopStatusError: loops.error }
159
+ : {
160
+ ...review,
161
+ loopStatus: roles
162
+ .map((role) => (role.id ? loops.rows.get(role.id) : undefined))
163
+ .filter((row) => row !== undefined),
164
+ }, null, 2));
65
165
  return;
66
166
  }
67
167
  // Without this the command printed raw JSON in both modes, which is why the
68
168
  // meta loops read as machinery rather than as something an owner supervises.
69
- const review = result;
70
- const roles = review.systemCommitments || [];
71
- const alwaysOn = review.alwaysOn === true;
72
- const questions = review.openQuestions || [];
73
- const portfolio = review.portfolio || {};
74
- this.log(`Agent ${review.agentId}`);
75
- this.log('');
76
- // A loop's own status says `active`, but a system-managed loop is only
77
- // given a scheduling trigger while the Agent is Always-On. Printing
78
- // `active` beside "last checked never" without saying that read as
79
- // "nothing has happened yet" rather than "this cannot happen", and nothing
80
- // led the owner to the switch that decides it.
81
- if (!alwaysOn) {
82
- this.log('Always-On is OFF — these loops are provisioned but will not run.');
83
- this.log(` skrr agents always-on enable ${review.agentId}`);
84
- this.log('');
85
- }
86
- this.log('Background loops');
87
- if (roles.length === 0) {
88
- this.log(' (none provisioned)');
89
- }
90
- for (const role of roles) {
91
- const key = role.systemRole || '?';
92
- const purpose = ROLE_PURPOSE[key] ? ` — ${ROLE_PURPOSE[key]}` : '';
93
- const contact = role.maxUserNudgesPerDay && role.maxUserNudgesPerDay > 0
94
- ? `may contact you ${role.maxUserNudgesPerDay}/day`
95
- : 'never contacts you';
96
- // `idle` replaces `active` only. A paused loop is paused for its own
97
- // reason — Relationship Pulse ships paused as a separate consent
98
- // decision — and collapsing that into `idle` would hide a distinction
99
- // the owner needs when they do turn Always-On on.
100
- const state = !alwaysOn && role.status === 'active' ? 'idle' : role.status || '?';
101
- this.log(` ${state.padEnd(7)} ${key}${purpose}`);
102
- this.log(` last checked ${ago(role.lastCheckedAt)} · ${contact}`);
103
- }
104
- this.log('');
105
- this.log(`Open questions from this agent (${questions.length})`);
106
- if (questions.length === 0) {
107
- this.log(` ${noQuestionsSentence(alwaysOn, roles)}`);
108
- }
109
- for (const q of questions) {
110
- this.log(` • ${q.question}`);
111
- if (q.whyItMatters)
112
- this.log(` why: ${q.whyItMatters}`);
113
- this.log(` asked ${ago(q.askedAt)}`);
114
- }
115
- this.log('');
116
- const drafts = portfolio.draftCommitmentCount ?? 0;
117
- this.log(`Business commitments: ${portfolio.activeCommitmentCount ?? 0} active, ${portfolio.pausedCommitmentCount ?? 0} paused${drafts > 0 ? `, ${drafts} draft` : ''}`);
169
+ for (const line of formatOperatingReview(result, loops))
170
+ this.log(line);
118
171
  }
119
172
  }
120
173
  exports.default = CommitmentsOperatingReview;
@@ -31,7 +31,8 @@ const commitments_1 = require("../../lib/commitments");
31
31
  * the contract untouched.
32
32
  */
33
33
  class CommitmentsUpdate extends base_command_1.BaseCommand {
34
- static description = "Update a commitment's contract (title, target, cadence, sources)";
34
+ static description = "Update a commitment's contract (title, target, cadence, sources). A cadence is manual, an interval or daily clock times; " +
35
+ 'it has no weekday, holiday, business-day or trading-calendar fields';
35
36
  static examples = [
36
37
  '<%= config.bin %> commitments update <commitment-id> --cadence 12h',
37
38
  '<%= config.bin %> commitments update <commitment-id> --title "Ship v2 (Q3)" --outcome "v2 is live for all users"',
@@ -275,9 +276,13 @@ JSON
275
276
  // only for a binding it still names; explicit JSON is the authored base.
276
277
  const declarations = Array.isArray(payload.watchedSources)
277
278
  ? (0, commitments_1.normalizeWatchedSourceDeclarations)(payload.watchedSources)
278
- : current?.watchedSources ?? [];
279
+ : (current?.watchedSources ?? []);
279
280
  payload.watchedSources = built.map((next) => {
280
- const scopeKey = next.source === 'space' ? 'spaceId' : next.source === 'monitor' ? 'monitorId' : undefined;
281
+ const scopeKey = next.source === 'space'
282
+ ? 'spaceId'
283
+ : next.source === 'monitor'
284
+ ? 'monitorId'
285
+ : undefined;
281
286
  const nextConfig = next.config;
282
287
  const prior = declarations.find((binding) => binding?.source === next.source &&
283
288
  (!scopeKey || binding.config?.[scopeKey] === nextConfig?.[scopeKey]));
@@ -301,7 +306,9 @@ JSON
301
306
  storedCadence[key] = existing[key];
302
307
  }
303
308
  if (payload.cadence !== undefined) {
304
- if (!payload.cadence || typeof payload.cadence !== 'object' || Array.isArray(payload.cadence)) {
309
+ if (!payload.cadence ||
310
+ typeof payload.cadence !== 'object' ||
311
+ Array.isArray(payload.cadence)) {
305
312
  this.error('cadence must be a JSON object when using cadence flags.', { exit: 1 });
306
313
  }
307
314
  }
@@ -403,7 +410,7 @@ JSON
403
410
  this.log(JSON.stringify((0, web_url_1.withCommitmentUrl)(this.cliConfig.baseURL, commitment), null, 2));
404
411
  return;
405
412
  }
406
- this.log('Updated commitment:');
413
+ this.log((0, commitments_1.describeCommitmentRevision)(commitment?.revision));
407
414
  (0, commitments_1.renderCommitmentSummary)(commitment, (line) => this.log(line));
408
415
  }
409
416
  }
@@ -49,6 +49,7 @@ const cli_runtime_1 = require("../lib/cli-runtime");
49
49
  const command_manifest_1 = require("../lib/command-manifest");
50
50
  const completion_index_1 = require("../lib/completion-index");
51
51
  const runtime_context_1 = require("../lib/runtime-context");
52
+ const deployed_build_1 = require("../lib/deployed-build");
52
53
  const outbox_1 = require("../lib/outbox");
53
54
  /**
54
55
  * What each check actually verifies, in the words a reader thinks in.
@@ -230,6 +231,9 @@ class Doctor extends base_command_1.BaseCommand {
230
231
  }
231
232
  }
232
233
  }
234
+ // OSK-15497 — which code the server is running, API and web separately.
235
+ // Public reads, no credential; a failure is reported, never an issue.
236
+ const deployed = await (0, deployed_build_1.readDeployedBuild)(this.cliConfig.baseURL);
233
237
  const now = Date.now();
234
238
  const jwtExp = this.resolvedCredential?.token
235
239
  ? (0, auth_core_1.decodeJwtExpiry)(this.resolvedCredential.token)
@@ -287,6 +291,9 @@ class Doctor extends base_command_1.BaseCommand {
287
291
  command: process.argv.slice(1).join(' '),
288
292
  },
289
293
  server: this.cliConfig.baseURL,
294
+ // The commit the server's API image and its published web shell were
295
+ // each built from. They differ whenever a release changed only one.
296
+ deployed,
290
297
  profile: (0, keychain_1.getActiveProfile)(),
291
298
  config: {
292
299
  path: (0, config_1.getConfigPath)(),
@@ -351,6 +358,8 @@ class Doctor extends base_command_1.BaseCommand {
351
358
  }
352
359
  this.log(`skrr CLI ${payload.cli.version} at ${root}`);
353
360
  this.log(`Server: ${payload.server}`);
361
+ for (const line of (0, deployed_build_1.deployedBuildLines)(deployed))
362
+ this.log(line);
354
363
  this.log(`Auth: ${payload.auth.signedIn
355
364
  ? `${account?.email ?? account?.id}`
356
365
  : serverReachability === 'unavailable'
@@ -5,6 +5,7 @@ const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../base-command");
6
6
  const web_url_1 = require("../../lib/web-url");
7
7
  const format_1 = require("../../lib/format");
8
+ const list_output_1 = require("../../lib/list-output");
8
9
  class GoalsList extends base_command_1.BaseCommand {
9
10
  static description = 'List goals';
10
11
  static examples = [
@@ -72,7 +73,11 @@ class GoalsList extends base_command_1.BaseCommand {
72
73
  this.handleApiError(err);
73
74
  }
74
75
  if (flags.json) {
75
- this.log(JSON.stringify((0, web_url_1.withDataUrls)(this.cliConfig.baseURL, response, web_url_1.goalUrlFrom), null, 2));
76
+ // The one list envelope (`{object:'list', data, has_more, next_cursor}`), so
77
+ // a script reads `.data` here exactly as it does for tasks and projects. The
78
+ // space-scoped endpoint is not paginated and answers a bare `{data}`; filling
79
+ // the missing fields is additive, so nothing that read `.data` changes.
80
+ this.log(JSON.stringify((0, web_url_1.withDataUrls)(this.cliConfig.baseURL, (0, list_output_1.toListEnvelope)(response) ?? response, web_url_1.goalUrlFrom), null, 2));
76
81
  return;
77
82
  }
78
83
  // Both listGoals and listSpaceGoals return { data: Goal[] }. The general
@@ -51,6 +51,10 @@ class GrantsRotate extends base_command_1.BaseCommand {
51
51
  }
52
52
  this.log(`Rotated grant ${grant.id}.`);
53
53
  this.log(` variables: ${grant.credential?.envKeys.join(', ') || '—'}`);
54
+ // When the server recorded the new value: the proof the rotation landed,
55
+ // without anything derived from the value itself (OSK-15358).
56
+ if (grant.credential?.setAt)
57
+ this.log(` value set: ${grant.credential.setAt}`);
54
58
  if (!grant.access) {
55
59
  this.log(' access: not declared (rotation clears the declared class; use --access to re-declare)');
56
60
  }
@@ -11,6 +11,8 @@ const config_1 = require("../lib/config");
11
11
  const cli_id_1 = require("../lib/cli-id");
12
12
  const keychain_1 = require("../lib/keychain");
13
13
  const profile_machine_identity_guard_1 = require("../lib/profile-machine-identity-guard");
14
+ const daemon_command_hint_1 = require("../lib/daemon-command-hint");
15
+ const local_daemon_readiness_1 = require("../lib/local-daemon-readiness");
14
16
  const login_1 = require("../lib/login");
15
17
  const device_code_1 = require("../lib/device-code");
16
18
  const api_fetch_1 = require("../lib/api-fetch");
@@ -121,9 +123,7 @@ class Login extends base_command_1.BaseCommand {
121
123
  async run() {
122
124
  const { flags } = await this.parse(Login);
123
125
  if ((0, profile_machine_identity_guard_1.legacyProfileSharesDefaultMachine)()) {
124
- this.error(`Profile '${(0, keychain_1.getActiveProfile)()}' was created before profiles had separate machine identities. ` +
125
- "Signing in could replace the default machine's device-key pin. " +
126
- 'Create a new profile name and sign in there; the existing profile was not changed.', { exit: 78 });
126
+ this.error((0, profile_machine_identity_guard_1.describeLegacySharedProfile)((0, keychain_1.getActiveProfile)()).join('\n'), { exit: 78 });
127
127
  }
128
128
  if (flags['base-url'] && flags.server && flags['base-url'] !== flags.server) {
129
129
  this.error('--base-url and --server were both provided with different values.', { exit: 2 });
@@ -272,8 +272,21 @@ class Login extends base_command_1.BaseCommand {
272
272
  this.log(`This machine is not set up — ${setup.detail}.`);
273
273
  }
274
274
  }
275
+ // What the daemon is, once the handoff is over: verified connected, or
276
+ // handed a credential it is not using. "Delivered" only means the
277
+ // credential was written; saying "signed in" on that, and discovering on
278
+ // the next line that nobody could verify it, was a login that
279
+ // contradicted itself (OSK-16437).
280
+ let verifiedLocalDaemonId;
281
+ let localDaemonNotReady = false;
275
282
  if (handoff.status === 'delivered') {
276
- this.log(`The local daemon was signed in too — ${handoff.detail}.`);
283
+ const reported = await (0, local_daemon_readiness_1.reportLocalDaemonAfterHandoff)({
284
+ deliveredDetail: handoff.detail,
285
+ bin: this.config.bin,
286
+ log: (line) => this.log(line),
287
+ });
288
+ verifiedLocalDaemonId = reported.daemonId;
289
+ localDaemonNotReady = reported.notReady;
277
290
  }
278
291
  else if (handoff.reason === 'platform-managed') {
279
292
  // A Dedicated guest: its daemon is the platform's, so there is
@@ -291,20 +304,35 @@ class Login extends base_command_1.BaseCommand {
291
304
  // people to re-login a healthy daemon (OSK-12189).
292
305
  this.log(`This login was not handed to the local daemon (${handoff.detail}). ` +
293
306
  `The daemon keeps whatever sign-in it already had — check it with ` +
294
- `\`${this.config.bin} daemon status\`, and run \`${this.config.bin} daemon login\` ` +
307
+ `\`${(0, daemon_command_hint_1.daemonCommandHint)('status', { bin: this.config.bin })}\`, and run ` +
308
+ `\`${(0, daemon_command_hint_1.daemonCommandHint)('login', { bin: this.config.bin })}\` ` +
295
309
  `only if that says it is signed out.`);
296
310
  }
297
- else if (handoff.status === 'failed') {
311
+ else if (handoff.status === 'failed' || handoff.reason === 'unsupported-daemon') {
312
+ // `unsupported-daemon` is a skip, not a failure, and printed nothing: the
313
+ // person was left believing the machine was signed in.
298
314
  this.log(`The local daemon was not signed in (${handoff.detail}). ` +
299
- `Run \`${this.config.bin} daemon login\` to finish.`);
315
+ `Run \`${(0, daemon_command_hint_1.daemonCommandHint)('login', { bin: this.config.bin })}\` to finish.`);
316
+ }
317
+ if (localDaemonNotReady) {
318
+ // The daemon has been described above; asking the same question of it
319
+ // again would print a second, vaguer version of the same answer.
320
+ if (!(0, managed_instruction_setup_1.shouldSkipInstructionPrompt)()) {
321
+ this.log(`Run \`${this.config.bin} instructions setup\` once it is connected.`);
322
+ }
323
+ }
324
+ else {
325
+ // Authentication above is complete. The common onboarding helper verifies
326
+ // the daemon's live account/server/profile and handles failures nonfatally.
327
+ // The wait for a daemon that was just handed a credential has already
328
+ // happened (`confirmLocalDaemonSignedIn`), and its answer is passed on.
329
+ await (0, managed_instruction_setup_1.maybeOfferManagedInstructionSetup)({
330
+ trigger: 'login',
331
+ log: (line) => this.log(line),
332
+ ...(verifiedLocalDaemonId ? { daemonId: verifiedLocalDaemonId } : {}),
333
+ waitForLocalReady: false,
334
+ });
300
335
  }
301
- // Authentication above is complete. The common onboarding helper verifies
302
- // the daemon's live account/server/profile and handles failures nonfatally.
303
- await (0, managed_instruction_setup_1.maybeOfferManagedInstructionSetup)({
304
- trigger: 'login',
305
- log: (line) => this.log(line),
306
- waitForLocalReady: handoff.status === 'delivered',
307
- });
308
336
  }
309
337
  catch (err) {
310
338
  // Ctrl-C while waiting for device-code approval: a person's decision,
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
+ const machine_uuid_1 = require("@skrr-ai/auth-core/machine-uuid");
4
5
  const base_command_1 = require("../../base-command");
6
+ const keychain_1 = require("../../lib/keychain");
5
7
  const format_1 = require("../../lib/format");
6
8
  const machines_1 = require("../../lib/machines");
7
9
  /**
@@ -23,8 +25,10 @@ class MachinesList extends base_command_1.BaseCommand {
23
25
  // with the one live machine at the top and a wall of dead ones after it
24
26
  // (OSK-7639). A list exists so someone can pick a row.
25
27
  all: core_1.Flags.boolean({
26
- description: 'Include machines that are offline, paused, stopped or terminated. Off by default — dead sandboxes ' +
27
- 'accumulate forever and bury the ones you can use.',
28
+ description: 'Include every machine, including the offline, paused, stopped or terminated hosted ones, ' +
29
+ 'and the older harness registrations a machine keeps. Off by default — dead sandboxes and ' +
30
+ 'replaced registrations accumulate forever and bury the ones you can use. Your own ' +
31
+ 'computers are listed while offline either way, with when they were last seen.',
28
32
  }),
29
33
  };
30
34
  async run() {
@@ -38,9 +42,18 @@ class MachinesList extends base_command_1.BaseCommand {
38
42
  this.handleApiError(err);
39
43
  }
40
44
  const all = machines ?? [];
41
- const shown = flags.all ? all : all.filter((m) => (0, machines_1.isReachableMachine)(m));
45
+ const reachable = flags.all ? all : all.filter((m) => (0, machines_1.isListedByDefault)(m));
46
+ // A machine row keeps every harness registration it ever had, so one daemon
47
+ // coming online made a list of four rows read as ninety-eight (OSK-16440).
48
+ // The default shows what still stands; `--all` shows the history.
49
+ const views = reachable.map((m) => (0, machines_1.machineListView)(m, {
50
+ all: flags.all === true,
51
+ hardwareMachineUuid: (0, machine_uuid_1.getHardwareMachineUuid)(),
52
+ activeProfile: (0, keychain_1.getActiveProfile)(),
53
+ }));
54
+ const shown = reachable;
42
55
  if (flags.json) {
43
- this.log(JSON.stringify(shown, null, 2));
56
+ this.log(JSON.stringify(views, null, 2));
44
57
  return;
45
58
  }
46
59
  if (all.length === 0) {
@@ -51,14 +64,17 @@ class MachinesList extends base_command_1.BaseCommand {
51
64
  this.log(`No machine is reachable right now (${(0, machines_1.hiddenMachinesSummary)(all)}) — see them with --all.`);
52
65
  return;
53
66
  }
54
- (0, format_1.renderTable)(shown.map((m) => ({
67
+ (0, format_1.renderTable)(shown.map((m, index) => ({
55
68
  // Printed in full. A hard 20-character slice with no ellipsis made
56
69
  // `machine:03548116-d36` read like a complete id and it is not — and
57
70
  // two different hosted machines rendered as byte-identical rows,
58
71
  // so the one column a list exists to be picked from could not
59
72
  // distinguish them (OSK-7621).
60
73
  id: (0, format_1.formatCell)(m.id),
61
- name: (0, format_1.formatCell)(m.preferences?.name || m.name),
74
+ // Which row is the computer in front of you, said on the row: two machines
75
+ // can carry the same hostname, and "the one I am on" is what a person is
76
+ // usually picking (OSK-16440).
77
+ name: (0, format_1.formatCell)(`${m.preferences?.name || m.name}${views[index].thisComputer ? ' (this computer)' : ''}`),
62
78
  status: (0, format_1.formatCell)((0, machines_1.machineStateLabel)(m)),
63
79
  // Both numbers matter: "2/7" is a machine that is up with most of its
64
80
  // harnesses signed out, which reads nothing like "7/7". The
@@ -88,6 +104,12 @@ class MachinesList extends base_command_1.BaseCommand {
88
104
  this.log(` ${m.preferences?.name || m.name}: ${m.statusReason}`);
89
105
  }
90
106
  }
107
+ const foldedHistory = views.reduce((sum, view) => sum + (view.hiddenHarnessCount ?? 0), 0);
108
+ if (foldedHistory > 0) {
109
+ this.log('');
110
+ this.log(`${foldedHistory} older harness registration(s) that a newer one replaced are hidden — ` +
111
+ 'pass --all to include them, or --json for the daemons each machine has registered.');
112
+ }
91
113
  if (shown.length < all.length) {
92
114
  const hidden = all.filter((m) => !shown.includes(m));
93
115
  this.log('');
@@ -52,7 +52,7 @@ class ProjectsShow extends base_command_1.BaseCommand {
52
52
  ...project,
53
53
  });
54
54
  if (flags.json) {
55
- this.log(JSON.stringify({ ...project, url }, null, 2));
55
+ this.printJsonResult({ ...project, url });
56
56
  return;
57
57
  }
58
58
  for (const line of (0, projects_1.renderProjectShow)(project)) {
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
4
4
  const base_command_1 = require("../base-command");
5
5
  const api_fetch_1 = require("../lib/api-fetch");
6
6
  const daemon_ref_1 = require("../lib/daemon-ref");
7
+ const daemon_command_hint_1 = require("../lib/daemon-command-hint");
7
8
  /**
8
9
  * `skrr revoke-daemon <id-or-prefix>`
9
10
  *
@@ -105,7 +106,7 @@ class RevokeDaemon extends base_command_1.BaseCommand {
105
106
  // Said now, not discovered later as a refresh failure: the sign-in this
106
107
  // command used was brokered by that daemon and died with it.
107
108
  this.warn(`This also signed out ${this.config.bin} on this machine: its sign-in was brokered ` +
108
- `by that daemon and was revoked with it. Run \`${this.config.bin} daemon login\` to ` +
109
+ `by that daemon and was revoked with it. Run \`${(0, daemon_command_hint_1.daemonCommandHint)('login', { bin: this.config.bin })}\` to ` +
109
110
  `re-enroll the daemon, then \`${this.config.bin} login\` to sign the CLI in again.`);
110
111
  }
111
112
  // exit 0 (default)
@@ -1,5 +1,6 @@
1
1
  import { BaseCommand } from '../../../base-command';
2
2
  export default class SpacesWorkflowsArchive extends BaseCommand {
3
+ static aliases: string[];
3
4
  static description: string;
4
5
  static args: {
5
6
  spaceId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
@@ -5,6 +5,7 @@ const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../../base-command");
6
6
  const prompt_1 = require("../../../lib/prompt");
7
7
  class SpacesWorkflowsArchive extends base_command_1.BaseCommand {
8
+ static aliases = ['workflows:archive'];
8
9
  static description = 'Archive a workflow while retaining immutable versions and run history';
9
10
  static args = {
10
11
  spaceId: core_1.Args.string({ required: true, ignoreStdin: true }),
@@ -1,5 +1,6 @@
1
1
  import { BaseCommand } from '../../../base-command';
2
2
  export default class SpacesWorkflowsArtifact extends BaseCommand {
3
+ static aliases: string[];
3
4
  static description: string;
4
5
  static args: {
5
6
  spaceId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
@@ -5,6 +5,7 @@ const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../../base-command");
6
6
  const space_output_1 = require("../../../lib/space-output");
7
7
  class SpacesWorkflowsArtifact extends base_command_1.BaseCommand {
8
+ static aliases = ['workflows:artifact'];
8
9
  static description = 'Read a persisted input or output artifact for a workflow node run';
9
10
  static args = {
10
11
  spaceId: core_1.Args.string({ description: 'Owning Space ID', required: true, ignoreStdin: true }),
@@ -1,5 +1,6 @@
1
1
  import { BaseCommand } from '../../../base-command';
2
2
  export default class SpacesWorkflowsCancelNode extends BaseCommand {
3
+ static aliases: string[];
3
4
  static description: string;
4
5
  static examples: string[];
5
6
  static args: {
@@ -6,6 +6,7 @@ const base_command_1 = require("../../../base-command");
6
6
  const prompt_1 = require("../../../lib/prompt");
7
7
  const workflow_node_control_1 = require("../../../lib/workflow-node-control");
8
8
  class SpacesWorkflowsCancelNode extends base_command_1.BaseCommand {
9
+ static aliases = ['workflows:cancel-node'];
9
10
  static description = 'Request cancellation of one exact workflow node attempt and show the returned execution state';
10
11
  static examples = [
11
12
  '<%= config.bin %> spaces workflows run <space> <run> --json > reviewed-run.json',
@@ -39,6 +39,7 @@ export declare function describePreservedChildren(spaceId: string, parentRunId:
39
39
  reviewedScope?: boolean;
40
40
  }): string[];
41
41
  export default class SpacesWorkflowsCancel extends BaseCommand {
42
+ static aliases: string[];
42
43
  static description: string;
43
44
  static args: {
44
45
  spaceId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
@@ -80,6 +80,7 @@ function describePreservedChildren(spaceId, parentRunId, children, { reviewedSco
80
80
  return lines;
81
81
  }
82
82
  class SpacesWorkflowsCancel extends base_command_1.BaseCommand {
83
+ static aliases = ['workflows:cancel'];
83
84
  static description = 'Cancel a workflow run and stop further graph coordination';
84
85
  static args = {
85
86
  spaceId: core_1.Args.string({ description: 'Owning Space ID', required: true, ignoreStdin: true }),
@@ -87,7 +88,7 @@ class SpacesWorkflowsCancel extends base_command_1.BaseCommand {
87
88
  };
88
89
  static flags = {
89
90
  json: core_1.Flags.boolean({
90
- description: 'Output the cancelled run as JSON (cancellation.scope and the waitingFor.workflowRunId of the cancelled nodes show which child runs were left running)',
91
+ description: 'Output the cancelled run as JSON (cancelReceipt.outcome says whether this request stopped it or found it already cancelled; cancellation.scope and the waitingFor.workflowRunId of the cancelled nodes show which child runs were left running)',
91
92
  }),
92
93
  scope: core_1.Flags.string({
93
94
  description: 'What happens to child workflow runs this run started: preserve_children (default) leaves them running, subtree stops every descendant run too',
@@ -128,7 +129,10 @@ class SpacesWorkflowsCancel extends base_command_1.BaseCommand {
128
129
  this.log(JSON.stringify((0, space_output_1.withSpacePerspectiveUrl)(this.cliConfig.baseURL, args.spaceId, 'workflows', run), null, 2));
129
130
  return;
130
131
  }
131
- this.log(`Cancelled workflow run ${run.id} (${run.status}).`);
132
+ // The receipt says whether THIS request stopped the run or found it stopped (and why): a
133
+ // repeat used to print "Cancelled" as if new, hiding a stop its deadline made earlier
134
+ // (OSK-15336).
135
+ this.log((0, data_provider_1.describeWorkflowRunCancelReceipt)(run.id, run.cancelReceipt));
132
136
  for (const line of describeCancellationProgress(args.spaceId, run))
133
137
  this.log(line);
134
138
  if ((run.cancellation?.scope ?? run.cancellationScope ?? scope) === 'subtree')
@@ -3,6 +3,7 @@ import { BaseCommand } from '../../../base-command';
3
3
  /** A headless-safe first draft: valid on its own, then ready for template insertion or editing. */
4
4
  export declare function starterWorkflowGraph(): WorkflowGraph;
5
5
  export default class SpacesWorkflowsCreate extends BaseCommand {
6
+ static aliases: string[];
6
7
  static description: string;
7
8
  static args: {
8
9
  spaceId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
@@ -6,6 +6,7 @@ const data_provider_1 = require("@skrr-ai/data-provider");
6
6
  const base_command_1 = require("../../../base-command");
7
7
  const prompt_1 = require("../../../lib/prompt");
8
8
  const space_output_1 = require("../../../lib/space-output");
9
+ const workflow_issues_1 = require("../../../lib/workflow-issues");
9
10
  /** A headless-safe first draft: valid on its own, then ready for template insertion or editing. */
10
11
  function starterWorkflowGraph() {
11
12
  return {
@@ -23,6 +24,7 @@ function starterWorkflowGraph() {
23
24
  };
24
25
  }
25
26
  class SpacesWorkflowsCreate extends base_command_1.BaseCommand {
27
+ static aliases = ['workflows:create'];
26
28
  static description = 'Create a workflow draft from graph or Canvas draft JSON';
27
29
  static args = { spaceId: core_1.Args.string({ required: true, ignoreStdin: true }) };
28
30
  static flags = {
@@ -94,7 +96,11 @@ class SpacesWorkflowsCreate extends base_command_1.BaseCommand {
94
96
  this.log(`Created draft ${workflow.id}: ${workflow.title}`);
95
97
  if (decorated.url)
96
98
  this.log(`URL: ${decorated.url}`);
97
- this.log(`Next: skrr spaces workflows publish ${args.spaceId} ${workflow.id}`);
99
+ for (const line of (0, workflow_issues_1.describeDraftIssues)(workflow.issues))
100
+ this.log(line);
101
+ this.log(workflow.issues?.some((issue) => issue.severity === 'error')
102
+ ? `Next: fix the draft, then skrr workflows update ${args.spaceId} ${workflow.id} --graph <file>`
103
+ : `Next: skrr workflows publish ${args.spaceId} ${workflow.id}`);
98
104
  }
99
105
  }
100
106
  exports.default = SpacesWorkflowsCreate;
@@ -2,6 +2,7 @@ import { BaseCommand } from '../../../base-command';
2
2
  export declare function workflowEventStreamHeaders(token: string | null | undefined, env?: Record<string, string | undefined>): Record<string, string>;
3
3
  /** Follow the server's metadata-only SSE invalidation stream until Ctrl-C. */
4
4
  export default class SpacesWorkflowsEvents extends BaseCommand {
5
+ static aliases: string[];
5
6
  static description: string;
6
7
  static args: {
7
8
  spaceId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
@@ -14,6 +14,7 @@ function workflowEventStreamHeaders(token, env = process.env) {
14
14
  }
15
15
  /** Follow the server's metadata-only SSE invalidation stream until Ctrl-C. */
16
16
  class SpacesWorkflowsEvents extends base_command_1.BaseCommand {
17
+ static aliases = ['workflows:events'];
17
18
  static description = 'Follow durable workflow run events (Ctrl-C to stop; fetch run details for canonical state)';
18
19
  static args = {
19
20
  spaceId: core_1.Args.string({ required: true, ignoreStdin: true }),