@skrr-ai/cli 0.1.108 → 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 (174) 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/commitments.d.ts +16 -2
  121. package/dist/lib/commitments.js +48 -8
  122. package/dist/lib/daemon-command-hint.d.ts +15 -0
  123. package/dist/lib/daemon-command-hint.js +21 -0
  124. package/dist/lib/daemon-setup.js +10 -1
  125. package/dist/lib/daemonBrokerRefusal.js +3 -2
  126. package/dist/lib/daemonHandoff.js +2 -1
  127. package/dist/lib/deployed-build.d.ts +43 -0
  128. package/dist/lib/deployed-build.js +66 -0
  129. package/dist/lib/grants.d.ts +27 -1
  130. package/dist/lib/grants.js +39 -21
  131. package/dist/lib/json-mode.d.ts +11 -0
  132. package/dist/lib/json-mode.js +19 -0
  133. package/dist/lib/json-output.d.ts +25 -0
  134. package/dist/lib/json-output.js +30 -0
  135. package/dist/lib/list-output.d.ts +9 -0
  136. package/dist/lib/list-output.js +20 -1
  137. package/dist/lib/local-daemon-readiness.d.ts +90 -0
  138. package/dist/lib/local-daemon-readiness.js +143 -0
  139. package/dist/lib/machines.d.ts +117 -0
  140. package/dist/lib/machines.js +139 -0
  141. package/dist/lib/managed-instruction-local.d.ts +2 -0
  142. package/dist/lib/managed-instruction-local.js +2 -0
  143. package/dist/lib/profile-machine-identity-guard.d.ts +18 -0
  144. package/dist/lib/profile-machine-identity-guard.js +29 -0
  145. package/dist/lib/request-field-flags.d.ts +20 -0
  146. package/dist/lib/request-field-flags.js +34 -0
  147. package/dist/lib/stewardship-output.d.ts +1 -1
  148. package/dist/lib/stewardship-output.js +26 -30
  149. package/dist/lib/task-batch.d.ts +61 -4
  150. package/dist/lib/task-batch.js +316 -80
  151. package/dist/lib/task-economics.d.ts +5 -0
  152. package/dist/lib/task-economics.js +15 -0
  153. package/dist/lib/task-recurrence-outcome.d.ts +6 -6
  154. package/dist/lib/task-recurrence-outcome.js +27 -3
  155. package/dist/lib/tasks.d.ts +39 -0
  156. package/dist/lib/tasks.js +132 -0
  157. package/dist/lib/triggers.d.ts +31 -1
  158. package/dist/lib/triggers.js +55 -1
  159. package/dist/lib/workflow-issues.d.ts +14 -0
  160. package/dist/lib/workflow-issues.js +32 -0
  161. package/dist/lib/workflow-run-view.d.ts +55 -0
  162. package/dist/lib/workflow-run-view.js +105 -0
  163. package/dist/lib/workspaces.d.ts +31 -4
  164. package/dist/lib/workspaces.js +43 -0
  165. package/dist/lib/write-target.d.ts +29 -0
  166. package/dist/lib/write-target.js +72 -0
  167. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/workspaceIsolationProbeWire.d.ts +51 -0
  168. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/workspaceIsolationProbeWire.js +50 -0
  169. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/workspaceIsolationProbeWire.d.ts +51 -0
  170. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/workspaceIsolationProbeWire.js +46 -0
  171. package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
  172. package/dist/node_modules/@skrr-ai/data-provider/index.js +6718 -6370
  173. package/oclif.manifest.json +376 -52
  174. package/package.json +19 -1
@@ -105,6 +105,8 @@ export default class TasksList extends BaseCommand {
105
105
  subscribed: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
106
106
  'include-snoozed': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
107
107
  'external-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
108
+ 'external-key-prefix': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
109
+ 'description-format': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
108
110
  tag: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
109
111
  'label-id': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
110
112
  q: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
@@ -48,6 +48,7 @@ const FILTER_FLAGS = new Set([
48
48
  'subscribed',
49
49
  'include-snoozed',
50
50
  'external-key',
51
+ 'external-key-prefix',
51
52
  'blocked-by',
52
53
  'blocks',
53
54
  'due-before',
@@ -286,6 +287,13 @@ function buildListParams(flags, assigneeUserId) {
286
287
  ...(flag('external-key')
287
288
  ? { externalKey: flag('external-key') }
288
289
  : {}),
290
+ ...(flag('external-key-prefix')
291
+ ? { externalKeyPrefix: flag('external-key-prefix') }
292
+ : {}),
293
+ // A presentation of each row, not a filter: it is deliberately not in FILTER_FLAGS.
294
+ ...(flag('description-format') === 'markdown'
295
+ ? { descriptionFormat: 'markdown' }
296
+ : {}),
289
297
  ...(flag('blocked-by') ? { blockedBy: flag('blocked-by') } : {}),
290
298
  ...(flag('blocks') ? { blocks: flag('blocks') } : {}),
291
299
  ...(flag('due-before') ? { dueBefore: flag('due-before') } : {}),
@@ -469,6 +477,13 @@ class TasksList extends base_command_1.BaseCommand {
469
477
  description: 'Include tasks you have personally snoozed (hidden by default)',
470
478
  }),
471
479
  'external-key': core_1.Flags.string({ description: 'Filter by external key' }),
480
+ 'external-key-prefix': core_1.Flags.string({
481
+ description: 'Filter to tasks whose external key starts with this literal prefix, e.g. every task of one tree written under --external-key-prefix. Combine with --space; see also `tasks create-tree --verify`.',
482
+ }),
483
+ 'description-format': core_1.Flags.string({
484
+ description: 'JSON/text: how to read each description. html (default) is what is stored; markdown returns it as it was written, so a description you wrote compares equal to the one you read back.',
485
+ options: ['html', 'markdown'],
486
+ }),
472
487
  tag: core_1.Flags.string({
473
488
  description: 'Filter to tasks carrying EVERY listed tag (repeatable, AND-intersection, ' +
474
489
  'case-insensitive)',
@@ -711,7 +726,8 @@ class TasksList extends base_command_1.BaseCommand {
711
726
  if (flags.rank)
712
727
  this.log('\nRanked only within this fetched page; estimates are claims, not measured savings.\n' +
713
728
  'SCORE = annualized USD savings / max(effort hours, 0.5) x risk factor (low 1, medium 0.6, high 0.25); ' +
714
- '— means savings, effort or risk is missing, so the row is not scored and sorts last.');
729
+ '— means savings, effort or risk is missing (or outside the plausible range), so the row is not scored ' +
730
+ 'and sorts after every scored row: larger stated savings first, then rows with no estimate.');
715
731
  if (r?.next_cursor) {
716
732
  this.log('');
717
733
  this.log(`Next page: --cursor ${r.next_cursor}`);
@@ -719,6 +735,8 @@ class TasksList extends base_command_1.BaseCommand {
719
735
  const note = (0, list_output_1.limitNote)(flags.limit, items.length, Boolean(r?.has_more));
720
736
  for (const line of (0, list_output_1.warningLines)(note.warning ? [note.warning] : []))
721
737
  this.log(line);
738
+ for (const line of (0, list_output_1.textModeProjectionNotes)(flags))
739
+ this.log(line);
722
740
  }
723
741
  }
724
742
  exports.default = TasksList;
@@ -0,0 +1,22 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * Continue a recurring series whose next occurrence was never armed (OSK-15338).
4
+ *
5
+ * The failure (`recurrence.armFailure`) is recorded on the FINISHED occurrence, and `tasks schedule`
6
+ * refuses a finished Task, so this is the command every surface names for the way back. It arms the
7
+ * occurrence the series is owed and clears the failure; `--cron` / `--timezone` correct the series
8
+ * first, which is the only cure for an `invalid_pattern` failure.
9
+ */
10
+ export default class TasksRearmRecurrence extends BaseCommand {
11
+ static description: string;
12
+ static examples: string[];
13
+ static args: {
14
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
15
+ };
16
+ static flags: {
17
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
18
+ cron: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
19
+ timezone: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
20
+ };
21
+ run(): Promise<void>;
22
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const data_provider_1 = require("@skrr-ai/data-provider");
5
+ const base_command_1 = require("../../base-command");
6
+ const web_url_1 = require("../../lib/web-url");
7
+ /**
8
+ * Continue a recurring series whose next occurrence was never armed (OSK-15338).
9
+ *
10
+ * The failure (`recurrence.armFailure`) is recorded on the FINISHED occurrence, and `tasks schedule`
11
+ * refuses a finished Task, so this is the command every surface names for the way back. It arms the
12
+ * occurrence the series is owed and clears the failure; `--cron` / `--timezone` correct the series
13
+ * first, which is the only cure for an `invalid_pattern` failure.
14
+ */
15
+ class TasksRearmRecurrence extends base_command_1.BaseCommand {
16
+ static description = 'Re-arm a recurring series from the finished occurrence whose next occurrence was never scheduled';
17
+ static examples = [
18
+ '<%= config.bin %> tasks rearm-recurrence OSK-42',
19
+ '<%= config.bin %> tasks rearm-recurrence OSK-42 --cron "0 9 * * 1-5" --timezone America/New_York',
20
+ ];
21
+ static args = {
22
+ id: core_1.Args.string({
23
+ description: 'The finished occurrence (Task ID or identifier) that carries the arm failure',
24
+ required: true,
25
+ ignoreStdin: true,
26
+ }),
27
+ };
28
+ static flags = {
29
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
30
+ cron: core_1.Flags.string({
31
+ description: 'Correct the series pattern first: five cron fields "minute hour day-of-month month day-of-week", e.g. "0 9 * * 1-5"',
32
+ }),
33
+ timezone: core_1.Flags.string({
34
+ description: 'Correct the series timezone first (IANA zone, e.g. America/New_York)',
35
+ }),
36
+ };
37
+ async run() {
38
+ this.requireAuth();
39
+ const { args, flags } = await this.parse(TasksRearmRecurrence);
40
+ const taskRef = await this.resolveEntityRef('task', args.id);
41
+ let result;
42
+ try {
43
+ result = await data_provider_1.dataService.rearmTaskRecurrence({
44
+ taskId: taskRef,
45
+ pattern: flags.cron,
46
+ timezone: flags.timezone,
47
+ });
48
+ }
49
+ catch (err) {
50
+ this.handleApiError(err);
51
+ }
52
+ if (flags.json) {
53
+ this.log(JSON.stringify({
54
+ ...result,
55
+ task: (0, web_url_1.withTaskUrl)(this.cliConfig.baseURL, result.task),
56
+ }, null, 2));
57
+ return;
58
+ }
59
+ const finished = result.task;
60
+ const from = finished.identifier || finished.id || taskRef;
61
+ const next = result.successor.identifier || result.successor.id;
62
+ const when = result.successor.scheduledFor ? ` for ${result.successor.scheduledFor}` : '';
63
+ this.log(result.alreadyArmed
64
+ ? `The series from ${from} was already armed: next occurrence ${next}${when}. The failure marker is cleared.`
65
+ : `Re-armed the series from ${from}: next occurrence ${next} is scheduled${when}.`);
66
+ }
67
+ }
68
+ exports.default = TasksRearmRecurrence;
@@ -112,6 +112,7 @@ export default class TasksShow extends BaseCommand {
112
112
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
113
113
  task: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
114
114
  'no-enrich': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
115
+ 'description-format': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
115
116
  };
116
117
  run(): Promise<void>;
117
118
  /**
@@ -21,6 +21,7 @@ const label_ref_1 = require("../../lib/label-ref");
21
21
  const principal_display_1 = require("../../lib/principal-display");
22
22
  const task_economics_line_1 = require("../../lib/task-economics-line");
23
23
  const format_1 = require("../../lib/format");
24
+ const task_recurrence_outcome_1 = require("../../lib/task-recurrence-outcome");
24
25
  /**
25
26
  * Where to look next — as COMMANDS, not as facts about the task.
26
27
  *
@@ -159,9 +160,13 @@ function recurrenceArmFailureLines(t, bin = 'skrr') {
159
160
  const code = recurrence?.armFailure?.code;
160
161
  if (typeof code !== 'string' || !code)
161
162
  return [];
163
+ const ref = (typeof t.identifier === 'string' && t.identifier) ||
164
+ (typeof t.id === 'string' && t.id) ||
165
+ '<task-id>';
162
166
  return [
163
167
  `Recurrence: ${(0, data_provider_1.describeRecurrenceArmFailure)(code)} (${code})`,
164
- ` Reschedule with \`${bin} tasks schedule\` to start the series again.`,
168
+ // Not `tasks schedule`: that refuses the finished occurrence carrying this failure (OSK-15338).
169
+ ` ${(0, task_recurrence_outcome_1.recurrenceRearmHint)(code, ref, bin)}`,
165
170
  ];
166
171
  }
167
172
  /**
@@ -246,6 +251,10 @@ class TasksShow extends base_command_1.BaseCommand {
246
251
  'no-enrich': core_1.Flags.boolean({
247
252
  description: 'Skip server-side enrichment (assignee names, parent titles)',
248
253
  }),
254
+ 'description-format': core_1.Flags.string({
255
+ description: 'How to read the description. html (default) is what is stored; markdown returns it as it was written.',
256
+ options: ['html', 'markdown'],
257
+ }),
249
258
  };
250
259
  async run() {
251
260
  this.requireAuth();
@@ -304,7 +313,12 @@ class TasksShow extends base_command_1.BaseCommand {
304
313
  task = bound;
305
314
  }
306
315
  else {
307
- task = await data_provider_1.dataService.getTask(taskId, { enrich: !flags['no-enrich'] });
316
+ task = await data_provider_1.dataService.getTask(taskId, {
317
+ enrich: !flags['no-enrich'],
318
+ ...(flags['description-format'] === 'markdown'
319
+ ? { descriptionFormat: 'markdown' }
320
+ : {}),
321
+ });
308
322
  }
309
323
  }
310
324
  catch (err) {
@@ -331,7 +345,7 @@ class TasksShow extends base_command_1.BaseCommand {
331
345
  completionRead = false;
332
346
  }
333
347
  if (flags.json) {
334
- this.log(JSON.stringify({ ...t, url, completion }, null, 2));
348
+ this.printJsonResult({ ...t, url, completion });
335
349
  return;
336
350
  }
337
351
  for (const line of completionLines(completion, { read: completionRead }))
@@ -5,6 +5,7 @@ const core_1 = require("@oclif/core");
5
5
  const data_provider_1 = require("@skrr-ai/data-provider");
6
6
  const base_command_1 = require("../../base-command");
7
7
  const format_1 = require("../../lib/format");
8
+ const task_economics_1 = require("../../lib/task-economics");
8
9
  const task_legacy_1 = require("../../lib/task-legacy");
9
10
  /**
10
11
  * `<action> (<k=v ...>)`, or just the preview when there is nothing to add.
@@ -13,6 +14,9 @@ const task_legacy_1 = require("../../lib/task-legacy");
13
14
  * renders `details` with, so the two surfaces describe one entry the same way.
14
15
  */
15
16
  function withDetails(item) {
17
+ // An estimate change reads as from-what-to-what, the same line `tasks activity` prints.
18
+ if (typeof item.type === 'string' && item.type.startsWith(data_provider_1.TASK_ECONOMICS_ACTIVITY_TYPE_PREFIX))
19
+ return (0, task_economics_1.describeEconomicsChange)(item.data);
16
20
  const preview = String(item.preview ?? '-');
17
21
  const details = (0, format_1.formatCell)(item.data ?? item.details, '');
18
22
  return details ? `${preview} (${details})` : preview;
@@ -23,6 +23,7 @@ export default class TasksUpdate extends BaseCommand {
23
23
  risk: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
24
24
  confidence: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
25
  rationale: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
26
+ 'retract-estimate': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
26
27
  estimate: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
27
28
  /**
28
29
  * Declared, hidden, and refused — on purpose. (S4 dogfood finding)
@@ -84,6 +84,10 @@ class TasksUpdate extends base_command_1.BaseCommand {
84
84
  rationale: core_1.Flags.string({
85
85
  description: 'Why the estimate is what it is, up to 500 characters (part of the estimate). An earlier rationale stays on the claim, under its new basis, until you replace it.',
86
86
  }),
87
+ 'retract-estimate': core_1.Flags.boolean({
88
+ description: "Remove the Task's economic estimate (savings, effort, risk, confidence and rationale). Recorded in `tasks activity` as task.economics.retracted under your name; an Agent cannot retract an estimate a person confirmed (409).",
89
+ exclusive: ['savings', 'per', 'effort', 'risk', 'confidence', 'rationale'],
90
+ }),
87
91
  estimate: core_1.Flags.integer({
88
92
  description: 'New estimate value from the Space estimate scale. Requires a scale on the Space (or an ' +
89
93
  'ancestor it inherits from); with none set, the server drops the value. Set the scale ' +
@@ -410,7 +414,8 @@ class TasksUpdate extends base_command_1.BaseCommand {
410
414
  startDate: flags['start-date'],
411
415
  dueDate: flags['due-date'],
412
416
  estimate: flags.estimate,
413
- economics: (0, task_economics_1.economicsFromFlags)(flags, body.economics),
417
+ // `null` is the retraction the server records as its own Activity event (OSK-15370).
418
+ economics: flags['retract-estimate'] ? null : (0, task_economics_1.economicsFromFlags)(flags, body.economics),
414
419
  // Never sent: `taskUpdateMutationGuard` refuses any payload carrying
415
420
  // `status` before the request is built. It is merged in only so the guard
416
421
  // sees it and answers with the sentence that names `tasks move`.
@@ -7,7 +7,7 @@ const builtinActions_1 = require("../../lib/builtinActions");
7
7
  const triggers_1 = require("../../lib/triggers");
8
8
  const web_url_1 = require("../../lib/web-url");
9
9
  class TriggersCreate extends base_command_1.BaseCommand {
10
- static description = 'Create a universal trigger';
10
+ static description = 'Create a universal trigger. A schedule trigger skips an occurrence that is overdue by more than its catch-up window (--stale-catchup-ms)';
11
11
  static examples = [
12
12
  '<%= config.bin %> triggers create --scope agent --ref agentId=<agent-id> --kind schedule --mode send_message --cron "0 9 * * *" --prompt "Prepare the daily brief"',
13
13
  '<%= config.bin %> triggers create --scope agent --ref agentId=<agent-id> --kind once --mode send_message --at 2026-06-01T15:30:00Z --prompt "Send the launch recap"',
@@ -65,7 +65,7 @@ class TriggersCreate extends base_command_1.BaseCommand {
65
65
  }),
66
66
  'effect-options': core_1.Flags.string({ description: 'Effect policy options JSON object' }),
67
67
  'workflow-event-key': core_1.Flags.string({
68
- description: 'Exact event key the parked workflow step waits on (required for mode=workflow_signal). Resolves steps in the scope Space; the trigger owner must hold Space edit access at every fire',
68
+ description: 'Exact event key the parked workflow step waits on (required for mode=workflow_signal). Resolves steps in the scope Space; the trigger owner must hold Space edit access at every fire. A person resolves one wait by hand with `skrr workflows signal`',
69
69
  }),
70
70
  'workflow-outcome': core_1.Flags.string({
71
71
  description: 'How the resolved step settles (default success)',
@@ -290,6 +290,8 @@ class TriggersCreate extends base_command_1.BaseCommand {
290
290
  dryRun: flags['dry-run'],
291
291
  });
292
292
  (0, triggers_1.mergeObjectField)(payload, 'execution', execution);
293
+ const mergedExecution = payload.execution;
294
+ (0, triggers_1.assertModeRequiredFlags)(mergedExecution?.mode, flags, mergedExecution);
293
295
  (0, triggers_1.mergeTriggerKindConfig)(payload, flags.kind ?? payload.kind, {
294
296
  schedule,
295
297
  once,
@@ -304,6 +306,10 @@ class TriggersCreate extends base_command_1.BaseCommand {
304
306
  this.error(err.message, { exit: 1 });
305
307
  }
306
308
  this.validatePayload(payload);
309
+ // A body assembled from flags: the server's field paths are read back as those flags. A
310
+ // body the person wrote (--from-json) keeps the paths, which are then what they typed.
311
+ if (!flags['from-json'])
312
+ this.requestFieldFlags = triggers_1.TRIGGER_CREATE_FIELD_FLAGS;
307
313
  let trigger;
308
314
  try {
309
315
  trigger = await triggers_1.triggerApi.create(payload);
@@ -1,4 +1,5 @@
1
1
  import { BaseCommand } from '../../base-command';
2
+ import { type TriggerParseIntentResponse } from '../../lib/triggers';
2
3
  export default class TriggersParseIntent extends BaseCommand {
3
4
  static description: string;
4
5
  static examples: string[];
@@ -14,3 +15,9 @@ export default class TriggersParseIntent extends BaseCommand {
14
15
  };
15
16
  run(): Promise<void>;
16
17
  }
18
+ /**
19
+ * The human rendering of a parse. Every unsupported condition is printed on its own line, never
20
+ * folded into the proposal (OSK-15402: "skip market holidays" was dropped while the summary claimed
21
+ * "every NYSE trading day"), and a clarifying question names the supported way to answer it.
22
+ */
23
+ export declare function parseIntentLines(result: TriggerParseIntentResponse, bin?: string): string[];
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseIntentLines = parseIntentLines;
3
4
  const core_1 = require("@oclif/core");
4
5
  const base_command_1 = require("../../base-command");
5
6
  const prompt_1 = require("../../lib/prompt");
@@ -21,11 +22,11 @@ class TriggersParseIntent extends base_command_1.BaseCommand {
21
22
  multiple: true,
22
23
  }),
23
24
  message: core_1.Flags.string({
24
- description: 'User message to parse (repeatable; messages are appended as user turns)',
25
+ description: 'User message to parse (repeatable; appended as user turns, after --history-json when both are given)',
25
26
  multiple: true,
26
27
  }),
27
28
  'history-json': core_1.Flags.string({
28
- description: 'Full parser history JSON array of {role:"user"|"assistant",content:string} objects',
29
+ description: 'Parser history JSON array of {role:"user"|"assistant",content:string} objects. To answer a clarifying question, pass the `history` a previous --json run returned and add your reply with --message',
29
30
  }),
30
31
  timezone: core_1.Flags.string({ description: 'IANA timezone used for relative times' }),
31
32
  now: core_1.Flags.string({ description: 'Override current ISO timestamp used for relative times' }),
@@ -51,7 +52,10 @@ class TriggersParseIntent extends base_command_1.BaseCommand {
51
52
  if (history)
52
53
  body.history = history;
53
54
  if (flags.message && flags.message.length > 0) {
54
- body.history = flags.message.map((content) => ({ role: 'user', content }));
55
+ // Appended, never replacing: a reply to a clarifying question only means something after
56
+ // the question it answers (OSK-15402). It used to discard --history-json entirely.
57
+ const prior = Array.isArray(body.history) ? body.history : [];
58
+ body.history = [...prior, ...flags.message.map((content) => ({ role: 'user', content }))];
55
59
  }
56
60
  if (flags.timezone)
57
61
  body.timezone = flags.timezone;
@@ -83,12 +87,30 @@ class TriggersParseIntent extends base_command_1.BaseCommand {
83
87
  this.log(JSON.stringify(result, null, 2));
84
88
  return;
85
89
  }
86
- this.log(result.message ?? '(no parser message)');
87
- this.log(`Needs clarification: ${result.needsClarification ? 'yes' : 'no'}`);
88
- if (result.proposedTrigger) {
89
- this.log('');
90
- this.log(JSON.stringify(result.proposedTrigger, null, 2));
91
- }
90
+ for (const line of parseIntentLines(result, this.config.bin))
91
+ this.log(line);
92
92
  }
93
93
  }
94
94
  exports.default = TriggersParseIntent;
95
+ /**
96
+ * The human rendering of a parse. Every unsupported condition is printed on its own line, never
97
+ * folded into the proposal (OSK-15402: "skip market holidays" was dropped while the summary claimed
98
+ * "every NYSE trading day"), and a clarifying question names the supported way to answer it.
99
+ */
100
+ function parseIntentLines(result, bin = 'skrr') {
101
+ const lines = [result.message ?? '(no parser message)'];
102
+ lines.push(`Needs clarification: ${result.needsClarification ? 'yes' : 'no'}`);
103
+ const unsupported = Array.isArray(result.unsupported) ? result.unsupported : [];
104
+ if (unsupported.length > 0) {
105
+ lines.push('', 'Not applied by this trigger:');
106
+ for (const item of unsupported)
107
+ lines.push(` - "${item.text}" (${item.kind}): ${item.reason}`);
108
+ }
109
+ if (result.proposedTrigger) {
110
+ lines.push('', JSON.stringify(result.proposedTrigger, null, 2));
111
+ }
112
+ else if (result.needsClarification) {
113
+ lines.push('', 'To answer, run it again with your reply after the earlier messages, e.g.', ` ${bin} triggers parse-intent --scope <kind> --ref <key=value> --message "<first message>" --message "<your answer>"`, 'or pass the returned `history` (see --json) with --history-json and add --message "<your answer>".');
114
+ }
115
+ return lines;
116
+ }
@@ -18,10 +18,11 @@ class WorkspacesGrants extends base_command_1.BaseCommand {
18
18
  const { args, flags } = await this.parse(WorkspacesGrants);
19
19
  try {
20
20
  const report = await (0, workspaces_1.listWorkspaceGrants)(args.workspaceId);
21
- if (flags.json)
21
+ if (flags.json) {
22
22
  this.log(JSON.stringify(report, null, 2));
23
- else
24
- (0, stewardship_output_1.printWorkspaceGrants)(report, (line) => this.log(line));
23
+ return;
24
+ }
25
+ (0, stewardship_output_1.printWorkspaceGrants)(report, (line) => this.log(line), await memberNames(args.workspaceId));
25
26
  }
26
27
  catch (error) {
27
28
  this.handleApiError(error);
@@ -29,3 +30,22 @@ class WorkspacesGrants extends base_command_1.BaseCommand {
29
30
  }
30
31
  }
31
32
  exports.default = WorkspacesGrants;
33
+ /**
34
+ * Owner ids to names, for the table's OWNER column (OSK-15357). Best effort: the
35
+ * report is already authoritative, and a members read that fails only leaves
36
+ * the column showing ids, as it did before.
37
+ */
38
+ async function memberNames(workspaceId) {
39
+ try {
40
+ const members = await (0, workspaces_1.listWorkspaceMembers)(workspaceId);
41
+ return new Map(members
42
+ .map((member) => [
43
+ String(member.userId),
44
+ member.user?.name || member.user?.username || member.user?.email || '',
45
+ ])
46
+ .filter(([, name]) => name));
47
+ }
48
+ catch {
49
+ return new Map();
50
+ }
51
+ }
@@ -0,0 +1,20 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * `skrr workspaces members` — who is in a workspace, with the user id the
4
+ * other workspace commands take (OSK-15356).
5
+ *
6
+ * `workspaces stewardship` needs a member's user id, and nothing in this
7
+ * command family printed one but `skrr whoami` (your own). An owner handing
8
+ * over a departing member's work had no way to find theirs.
9
+ */
10
+ export default class WorkspacesMembers extends BaseCommand {
11
+ static description: string;
12
+ static examples: string[];
13
+ static args: {
14
+ workspaceId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
15
+ };
16
+ static flags: {
17
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
18
+ };
19
+ run(): Promise<void>;
20
+ }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_command_1 = require("../../base-command");
5
+ const format_1 = require("../../lib/format");
6
+ const workspaces_1 = require("../../lib/workspaces");
7
+ /**
8
+ * `skrr workspaces members` — who is in a workspace, with the user id the
9
+ * other workspace commands take (OSK-15356).
10
+ *
11
+ * `workspaces stewardship` needs a member's user id, and nothing in this
12
+ * command family printed one but `skrr whoami` (your own). An owner handing
13
+ * over a departing member's work had no way to find theirs.
14
+ */
15
+ class WorkspacesMembers extends base_command_1.BaseCommand {
16
+ static description = 'List the current members of a workspace with their user ids and roles';
17
+ static examples = [
18
+ '<%= config.bin %> workspaces members <workspace-id>',
19
+ '<%= config.bin %> workspaces members <workspace-id> --json',
20
+ ];
21
+ static args = {
22
+ workspaceId: core_1.Args.string({ required: true, ignoreStdin: true, description: 'Workspace ID' }),
23
+ };
24
+ static flags = {
25
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
26
+ };
27
+ async run() {
28
+ this.requireAuth();
29
+ const { args, flags } = await this.parse(WorkspacesMembers);
30
+ let members;
31
+ try {
32
+ members = await (0, workspaces_1.listWorkspaceMembers)(args.workspaceId);
33
+ }
34
+ catch (error) {
35
+ this.handleApiError(error);
36
+ return;
37
+ }
38
+ if (flags.json) {
39
+ this.log(JSON.stringify(members, null, 2));
40
+ return;
41
+ }
42
+ if (members.length === 0) {
43
+ this.log('No current members.');
44
+ return;
45
+ }
46
+ (0, format_1.renderTable)(members.map((member) => ({
47
+ userId: String(member.userId),
48
+ name: member.user?.name || member.user?.username || '—',
49
+ email: member.user?.email || '—',
50
+ role: member.role || '—',
51
+ joined: member.joinedAt || '—',
52
+ })), [
53
+ { key: 'userId', header: 'USER ID', verbatim: true },
54
+ { key: 'name', header: 'NAME', maxWidth: 28 },
55
+ { key: 'email', header: 'EMAIL', maxWidth: 36 },
56
+ { key: 'role', header: 'ROLE' },
57
+ { key: 'joined', header: 'JOINED' },
58
+ ], (line) => this.log(line));
59
+ this.log('');
60
+ this.log('Current members only: someone who has left is not listed. ' +
61
+ `\`skrr workspaces stewardship ${args.workspaceId} <user-id|email>\` reads one member's handover.`);
62
+ }
63
+ }
64
+ exports.default = WorkspacesMembers;
@@ -8,13 +8,15 @@ class WorkspacesStewardship extends base_command_1.BaseCommand {
8
8
  static description = 'Read a member’s workspace stewardship metadata (person owner/admin only)';
9
9
  static examples = [
10
10
  '<%= config.bin %> workspaces stewardship <workspace-id> <user-id> --json',
11
+ '<%= config.bin %> workspaces stewardship <workspace-id> person@example.com',
11
12
  ];
12
13
  static args = {
13
14
  workspaceId: core_1.Args.string({ required: true, ignoreStdin: true, description: 'Workspace ID' }),
14
15
  userId: core_1.Args.string({
15
16
  required: true,
16
17
  ignoreStdin: true,
17
- description: 'Member user ID: 24 hexadecimal characters, not an email (`skrr whoami` prints your own)',
18
+ description: "Member user ID (24 hexadecimal characters) or a current member's email. " +
19
+ '`skrr workspaces members <workspace-id>` lists them; `skrr whoami` prints your own',
18
20
  }),
19
21
  };
20
22
  static flags = {
@@ -23,8 +25,18 @@ class WorkspacesStewardship extends base_command_1.BaseCommand {
23
25
  async run() {
24
26
  this.requireAuth();
25
27
  const { args, flags } = await this.parse(WorkspacesStewardship);
28
+ let userId;
26
29
  try {
27
- const report = await (0, workspaces_1.getWorkspaceStewardship)(args.workspaceId, args.userId);
30
+ userId = await (0, workspaces_1.resolveMemberUserId)(args.workspaceId, args.userId);
31
+ }
32
+ catch (error) {
33
+ if (error instanceof workspaces_1.MemberReferenceError)
34
+ this.error(error.message, { exit: 1 });
35
+ this.handleApiError(error);
36
+ return;
37
+ }
38
+ try {
39
+ const report = await (0, workspaces_1.getWorkspaceStewardship)(args.workspaceId, userId);
28
40
  if (flags.json)
29
41
  this.log(JSON.stringify(report, null, 2));
30
42
  else
package/dist/help.js CHANGED
@@ -61,6 +61,18 @@ class SkrrHelp extends core_1.Help {
61
61
  // so it must fall through — only an id that is neither a command nor a
62
62
  // topic is a miss.
63
63
  if (id && !this.config.findCommand(id) && !this.config.findTopic(id)) {
64
+ // `skrr tasks get --help` is asked about the command `skrr tasks get` runs
65
+ // as: the same synonym the hook resolves when it is run (OSK-16434).
66
+ const flagStart = argv.findIndex((token) => token.startsWith('-'));
67
+ const words = flagStart === -1 ? argv : argv.slice(0, flagStart);
68
+ const synonym = (0, command_miss_1.resolveVerbSynonym)(lookup, words);
69
+ if (synonym) {
70
+ return super.showHelp([
71
+ ...synonym.id.split(':'),
72
+ ...synonym.rest,
73
+ ...(flagStart === -1 ? [] : argv.slice(flagStart)),
74
+ ]);
75
+ }
64
76
  throw new Error((0, command_miss_1.describeCommandMiss)(lookup, id));
65
77
  }
66
78
  return super.showHelp(argv);
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
3
4
  const command_manifest_1 = require("../lib/command-manifest");
4
5
  const usage_discovery_1 = require("../lib/usage-discovery");
5
6
  const command_miss_1 = require("../lib/command-miss");
7
+ const json_mode_1 = require("../lib/json-mode");
6
8
  /**
7
9
  * Turn "command not found" back into the truth when the command DOES exist.
8
10
  *
@@ -65,6 +67,30 @@ const hook = async function (opts) {
65
67
  throw err;
66
68
  }
67
69
  }
70
+ const lookup = (0, command_miss_1.lookupFromConfig)(this.config);
71
+ const rawArgv = process.argv.slice(2);
72
+ const words = (0, command_miss_1.typedCommandWords)(id, rawArgv);
73
+ // A read verb spelled the other way (`tasks get`, `machines ls`) means the
74
+ // command that exists. Run it rather than refuse: refusing sent a reader to a
75
+ // suggestion list that did not contain the command they meant (OSK-16434).
76
+ // Only `list`/`ls` and `show`/`get`, only when the typed spelling is not a
77
+ // command of that topic, and only when the other one is.
78
+ const synonym = (0, command_miss_1.resolveVerbSynonym)(lookup, words);
79
+ if (synonym) {
80
+ // Said to a person, never to a pipe: a script gets its output undisturbed.
81
+ if (process.stderr.isTTY && !(0, json_mode_1.wantsJsonFromArgv)(rawArgv)) {
82
+ process.stderr.write(`\`${synonym.typed}\` is \`${synonym.resolved}\`.\n`);
83
+ }
84
+ return this.config.runCommand(synonym.id, [...synonym.rest, ...(opts.argv ?? [])]);
85
+ }
86
+ // `--json` asked for a document. A miss is a refusal like any other, and every
87
+ // other refusal prints `{ok:false, error}`; this one printed prose, so the
88
+ // pipe into `jq` failed on the prose and hid the refusal (OSK-16434). Exit
89
+ // status 1, as before.
90
+ if ((0, json_mode_1.wantsJsonFromArgv)([...rawArgv, ...(opts.argv ?? [])])) {
91
+ process.stdout.write(`${JSON.stringify((0, command_miss_1.commandMissEnvelope)(lookup, id, words), null, 2)}\n`);
92
+ core_1.Errors.exit(1);
93
+ }
68
94
  // The message itself lives in `lib/command-miss`, shared with the help
69
95
  // class — `skrr daemon reload` reaches this hook and `skrr daemon reload
70
96
  // --help` does not, so the two surfaces have to read from one description or
@@ -76,7 +102,7 @@ const hook = async function (opts) {
76
102
  // — a typo would silently look like success, which is far worse than the
77
103
  // message this hook was written to improve. (I shipped exactly that for one
78
104
  // build; `skrr shortcuts lst` said nothing and exited 0.)
79
- throw new Error((0, command_miss_1.describeCommandMiss)((0, command_miss_1.lookupFromConfig)(this.config), id));
105
+ throw new Error((0, command_miss_1.describeCommandMiss)(lookup, id));
80
106
  };
81
107
  exports.default = hook;
82
108
  class VirtualUsageFlagError extends Error {