@skrr-ai/cli 0.1.108 → 0.1.110

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 (202) hide show
  1. package/README.md +10 -0
  2. package/dist/base-command.d.ts +74 -0
  3. package/dist/base-command.js +182 -24
  4. package/dist/commands/agents/triggers/create.js +1 -1
  5. package/dist/commands/agents/triggers/update.js +1 -1
  6. package/dist/commands/agents/update.d.ts +25 -0
  7. package/dist/commands/agents/update.js +98 -3
  8. package/dist/commands/commitments/accounting.js +7 -2
  9. package/dist/commands/commitments/cost.d.ts +11 -0
  10. package/dist/commands/commitments/cost.js +26 -3
  11. package/dist/commands/commitments/create.js +2 -1
  12. package/dist/commands/commitments/operating-review.d.ts +15 -0
  13. package/dist/commands/commitments/operating-review.js +103 -50
  14. package/dist/commands/commitments/update.js +12 -5
  15. package/dist/commands/daemon/install.js +17 -1
  16. package/dist/commands/daemon/login.js +14 -0
  17. package/dist/commands/doctor.js +9 -0
  18. package/dist/commands/goals/list.js +6 -1
  19. package/dist/commands/grants/rotate.js +4 -0
  20. package/dist/commands/harnesses/prune.d.ts +26 -0
  21. package/dist/commands/harnesses/prune.js +172 -0
  22. package/dist/commands/login.js +53 -14
  23. package/dist/commands/machines/list.js +28 -6
  24. package/dist/commands/projects/show.js +1 -1
  25. package/dist/commands/revoke-daemon.js +2 -1
  26. package/dist/commands/spaces/workflows/archive.d.ts +1 -0
  27. package/dist/commands/spaces/workflows/archive.js +1 -0
  28. package/dist/commands/spaces/workflows/artifact.d.ts +1 -0
  29. package/dist/commands/spaces/workflows/artifact.js +1 -0
  30. package/dist/commands/spaces/workflows/cancel-node.d.ts +1 -0
  31. package/dist/commands/spaces/workflows/cancel-node.js +1 -0
  32. package/dist/commands/spaces/workflows/cancel.d.ts +1 -0
  33. package/dist/commands/spaces/workflows/cancel.js +6 -2
  34. package/dist/commands/spaces/workflows/create.d.ts +1 -0
  35. package/dist/commands/spaces/workflows/create.js +7 -1
  36. package/dist/commands/spaces/workflows/events.d.ts +1 -0
  37. package/dist/commands/spaces/workflows/events.js +1 -0
  38. package/dist/commands/spaces/workflows/fixtures/create.d.ts +1 -0
  39. package/dist/commands/spaces/workflows/fixtures/create.js +1 -0
  40. package/dist/commands/spaces/workflows/fixtures/list.d.ts +1 -0
  41. package/dist/commands/spaces/workflows/fixtures/list.js +1 -0
  42. package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +1 -0
  43. package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +1 -0
  44. package/dist/commands/spaces/workflows/list.d.ts +1 -0
  45. package/dist/commands/spaces/workflows/list.js +1 -0
  46. package/dist/commands/spaces/workflows/node-types.d.ts +2 -0
  47. package/dist/commands/spaces/workflows/node-types.js +24 -6
  48. package/dist/commands/spaces/workflows/pause.d.ts +1 -0
  49. package/dist/commands/spaces/workflows/pause.js +1 -0
  50. package/dist/commands/spaces/workflows/plan/show.d.ts +1 -0
  51. package/dist/commands/spaces/workflows/plan/show.js +1 -0
  52. package/dist/commands/spaces/workflows/plan/update.d.ts +1 -0
  53. package/dist/commands/spaces/workflows/plan/update.js +1 -0
  54. package/dist/commands/spaces/workflows/proposals/apply.d.ts +1 -0
  55. package/dist/commands/spaces/workflows/proposals/apply.js +1 -0
  56. package/dist/commands/spaces/workflows/proposals/confirm.d.ts +1 -0
  57. package/dist/commands/spaces/workflows/proposals/confirm.js +1 -0
  58. package/dist/commands/spaces/workflows/proposals/create.d.ts +1 -0
  59. package/dist/commands/spaces/workflows/proposals/create.js +1 -0
  60. package/dist/commands/spaces/workflows/proposals/dismiss.d.ts +1 -0
  61. package/dist/commands/spaces/workflows/proposals/dismiss.js +1 -0
  62. package/dist/commands/spaces/workflows/proposals/list.d.ts +1 -0
  63. package/dist/commands/spaces/workflows/proposals/list.js +1 -0
  64. package/dist/commands/spaces/workflows/publish.d.ts +1 -0
  65. package/dist/commands/spaces/workflows/publish.js +9 -0
  66. package/dist/commands/spaces/workflows/reconcile.d.ts +1 -0
  67. package/dist/commands/spaces/workflows/reconcile.js +1 -0
  68. package/dist/commands/spaces/workflows/resume.d.ts +1 -0
  69. package/dist/commands/spaces/workflows/resume.js +1 -0
  70. package/dist/commands/spaces/workflows/retry.d.ts +1 -0
  71. package/dist/commands/spaces/workflows/retry.js +1 -0
  72. package/dist/commands/spaces/workflows/run.d.ts +1 -0
  73. package/dist/commands/spaces/workflows/run.js +14 -7
  74. package/dist/commands/spaces/workflows/runs.d.ts +1 -0
  75. package/dist/commands/spaces/workflows/runs.js +1 -0
  76. package/dist/commands/spaces/workflows/show.d.ts +25 -0
  77. package/dist/commands/spaces/workflows/show.js +42 -4
  78. package/dist/commands/spaces/workflows/signal.d.ts +12 -0
  79. package/dist/commands/spaces/workflows/signal.js +40 -2
  80. package/dist/commands/spaces/workflows/start.d.ts +1 -0
  81. package/dist/commands/spaces/workflows/start.js +4 -1
  82. package/dist/commands/spaces/workflows/task-execution/create.d.ts +1 -0
  83. package/dist/commands/spaces/workflows/task-execution/create.js +1 -0
  84. package/dist/commands/spaces/workflows/test.d.ts +1 -0
  85. package/dist/commands/spaces/workflows/test.js +1 -0
  86. package/dist/commands/spaces/workflows/triggers/create.d.ts +1 -0
  87. package/dist/commands/spaces/workflows/triggers/create.js +1 -0
  88. package/dist/commands/spaces/workflows/triggers/fire.d.ts +1 -0
  89. package/dist/commands/spaces/workflows/triggers/fire.js +1 -0
  90. package/dist/commands/spaces/workflows/triggers/list.d.ts +1 -0
  91. package/dist/commands/spaces/workflows/triggers/list.js +1 -0
  92. package/dist/commands/spaces/workflows/triggers/update.d.ts +1 -0
  93. package/dist/commands/spaces/workflows/triggers/update.js +1 -0
  94. package/dist/commands/spaces/workflows/update.d.ts +1 -0
  95. package/dist/commands/spaces/workflows/update.js +4 -0
  96. package/dist/commands/spaces/workflows/validate.d.ts +1 -0
  97. package/dist/commands/spaces/workflows/validate.js +27 -2
  98. package/dist/commands/tasks/activity.js +17 -3
  99. package/dist/commands/tasks/bulk-update.d.ts +1 -0
  100. package/dist/commands/tasks/bulk-update.js +7 -0
  101. package/dist/commands/tasks/complete.js +2 -1
  102. package/dist/commands/tasks/create-tree.d.ts +69 -0
  103. package/dist/commands/tasks/create-tree.js +413 -47
  104. package/dist/commands/tasks/list.d.ts +2 -0
  105. package/dist/commands/tasks/list.js +25 -3
  106. package/dist/commands/tasks/rearm-recurrence.d.ts +22 -0
  107. package/dist/commands/tasks/rearm-recurrence.js +87 -0
  108. package/dist/commands/tasks/show.d.ts +9 -0
  109. package/dist/commands/tasks/show.js +79 -33
  110. package/dist/commands/tasks/timeline.js +4 -0
  111. package/dist/commands/tasks/unschedule.js +5 -1
  112. package/dist/commands/tasks/update.d.ts +1 -0
  113. package/dist/commands/tasks/update.js +17 -2
  114. package/dist/commands/triggers/audit.js +12 -3
  115. package/dist/commands/triggers/create.js +9 -3
  116. package/dist/commands/triggers/fire-detail.d.ts +7 -0
  117. package/dist/commands/triggers/fire-detail.js +30 -12
  118. package/dist/commands/triggers/fire.js +13 -3
  119. package/dist/commands/triggers/parse-intent.d.ts +7 -0
  120. package/dist/commands/triggers/parse-intent.js +31 -9
  121. package/dist/commands/triggers/update.js +1 -1
  122. package/dist/commands/workspaces/grants.js +20 -3
  123. package/dist/commands/workspaces/members.d.ts +20 -0
  124. package/dist/commands/workspaces/members.js +64 -0
  125. package/dist/commands/workspaces/stewardship.js +14 -2
  126. package/dist/help.js +12 -0
  127. package/dist/hooks/command-not-found.js +27 -1
  128. package/dist/lib/command-miss.d.ts +52 -2
  129. package/dist/lib/command-miss.js +187 -18
  130. package/dist/lib/commitment-loop-status.d.ts +8 -0
  131. package/dist/lib/commitment-loop-status.js +45 -0
  132. package/dist/lib/commitment-product.js +5 -2
  133. package/dist/lib/commitments.d.ts +18 -3
  134. package/dist/lib/commitments.js +85 -45
  135. package/dist/lib/daemon-command-hint.d.ts +15 -0
  136. package/dist/lib/daemon-command-hint.js +21 -0
  137. package/dist/lib/daemon-machine-identity-copy.d.ts +14 -0
  138. package/dist/lib/daemon-machine-identity-copy.js +27 -0
  139. package/dist/lib/daemon-machine-identity.d.ts +27 -0
  140. package/dist/lib/daemon-machine-identity.js +61 -0
  141. package/dist/lib/daemon-setup.js +10 -1
  142. package/dist/lib/daemonBrokerRefusal.js +3 -2
  143. package/dist/lib/daemonHandoff.d.ts +19 -1
  144. package/dist/lib/daemonHandoff.js +61 -1
  145. package/dist/lib/deployed-build.d.ts +43 -0
  146. package/dist/lib/deployed-build.js +66 -0
  147. package/dist/lib/grants.d.ts +27 -1
  148. package/dist/lib/grants.js +39 -21
  149. package/dist/lib/harnesses.d.ts +71 -0
  150. package/dist/lib/harnesses.js +70 -0
  151. package/dist/lib/json-mode.d.ts +11 -0
  152. package/dist/lib/json-mode.js +19 -0
  153. package/dist/lib/json-output.d.ts +25 -0
  154. package/dist/lib/json-output.js +30 -0
  155. package/dist/lib/list-output.d.ts +10 -1
  156. package/dist/lib/list-output.js +22 -1
  157. package/dist/lib/local-daemon-readiness.d.ts +90 -0
  158. package/dist/lib/local-daemon-readiness.js +143 -0
  159. package/dist/lib/machines.d.ts +117 -0
  160. package/dist/lib/machines.js +139 -0
  161. package/dist/lib/managed-instruction-local.d.ts +2 -0
  162. package/dist/lib/managed-instruction-local.js +2 -0
  163. package/dist/lib/profile-machine-identity-guard.d.ts +18 -0
  164. package/dist/lib/profile-machine-identity-guard.js +39 -0
  165. package/dist/lib/request-field-flags.d.ts +20 -0
  166. package/dist/lib/request-field-flags.js +34 -0
  167. package/dist/lib/stewardship-output.d.ts +1 -1
  168. package/dist/lib/stewardship-output.js +26 -30
  169. package/dist/lib/task-batch.d.ts +61 -4
  170. package/dist/lib/task-batch.js +316 -80
  171. package/dist/lib/task-economics.d.ts +15 -0
  172. package/dist/lib/task-economics.js +39 -2
  173. package/dist/lib/task-recurrence-outcome.d.ts +6 -6
  174. package/dist/lib/task-recurrence-outcome.js +27 -3
  175. package/dist/lib/tasks.d.ts +39 -0
  176. package/dist/lib/tasks.js +132 -0
  177. package/dist/lib/triggers.d.ts +42 -1
  178. package/dist/lib/triggers.js +98 -2
  179. package/dist/lib/workflow-issues.d.ts +14 -0
  180. package/dist/lib/workflow-issues.js +32 -0
  181. package/dist/lib/workflow-run-view.d.ts +59 -0
  182. package/dist/lib/workflow-run-view.js +110 -0
  183. package/dist/lib/workspaces.d.ts +48 -4
  184. package/dist/lib/workspaces.js +55 -0
  185. package/dist/lib/write-target.d.ts +29 -0
  186. package/dist/lib/write-target.js +72 -0
  187. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +1 -1
  188. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +5 -3
  189. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.d.ts +60 -0
  190. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/machineUuid.js +130 -6
  191. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/workspaceIsolationProbeWire.d.ts +51 -0
  192. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/workspaceIsolationProbeWire.js +50 -0
  193. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +1 -1
  194. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +1 -1
  195. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.d.ts +60 -0
  196. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/machineUuid.js +128 -6
  197. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/workspaceIsolationProbeWire.d.ts +51 -0
  198. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/workspaceIsolationProbeWire.js +46 -0
  199. package/dist/node_modules/@skrr-ai/auth-core/package.json +11 -1
  200. package/dist/node_modules/@skrr-ai/data-provider/index.js +7523 -7140
  201. package/oclif.manifest.json +473 -59
  202. package/package.json +28 -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)',
@@ -573,7 +588,9 @@ class TasksList extends base_command_1.BaseCommand {
573
588
  Array.isArray(response.data)) {
574
589
  response = {
575
590
  ...response,
576
- data: (0, data_provider_1.rankEconomicItems)(response.data),
591
+ // Each row carries the `economicsRank` it was sorted by, so `--json` shows the same SCORE
592
+ // as the table, computed once in the shared ranking (OSK-16476).
593
+ data: (0, data_provider_1.annotateEconomicRank)(response.data),
577
594
  rank_applied: { key: 'economics', scope: 'fetched_page' },
578
595
  };
579
596
  }
@@ -678,7 +695,9 @@ class TasksList extends base_command_1.BaseCommand {
678
695
  : 'Unknown',
679
696
  effort: economics?.effortHours !== undefined ? `${economics.effortHours}h` : 'Unknown',
680
697
  risk: economics?.risk ?? 'Unknown',
681
- score: (0, task_economics_1.economicsScoreText)(economics),
698
+ score: t.economicsRank
699
+ ? (0, task_economics_1.scoreText)(t.economicsRank.score)
700
+ : (0, task_economics_1.economicsScoreText)(economics),
682
701
  basis: economics?.basis && Object.prototype.hasOwnProperty.call(basis, economics.basis)
683
702
  ? basis[economics.basis]
684
703
  : 'Unknown',
@@ -711,7 +730,8 @@ class TasksList extends base_command_1.BaseCommand {
711
730
  if (flags.rank)
712
731
  this.log('\nRanked only within this fetched page; estimates are claims, not measured savings.\n' +
713
732
  '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.');
733
+ '— means savings, effort or risk is missing (or outside the plausible range), so the row is not scored ' +
734
+ 'and sorts after every scored row: larger stated savings first, then rows with no estimate.');
715
735
  if (r?.next_cursor) {
716
736
  this.log('');
717
737
  this.log(`Next page: --cursor ${r.next_cursor}`);
@@ -719,6 +739,8 @@ class TasksList extends base_command_1.BaseCommand {
719
739
  const note = (0, list_output_1.limitNote)(flags.limit, items.length, Boolean(r?.has_more));
720
740
  for (const line of (0, list_output_1.warningLines)(note.warning ? [note.warning] : []))
721
741
  this.log(line);
742
+ for (const line of (0, list_output_1.textModeProjectionNotes)(flags))
743
+ this.log(line);
722
744
  }
723
745
  }
724
746
  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,87 @@
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
+ // The server's sentence IS the answer: it is derived with the JSON fields, so the two can
64
+ // never disagree (round 3 of OSK-15321 found them disagreeing). The fallback below is only
65
+ // for an older server that sends no `message`.
66
+ if (typeof result.message === 'string' && result.message) {
67
+ this.log(result.message);
68
+ return;
69
+ }
70
+ // Never call a successor with no schedule "armed": it will not fire (#4262 verification).
71
+ let line;
72
+ if (!result.successor.scheduledFor) {
73
+ line = `The next occurrence ${next} of the series from ${from} exists but has no schedule, so nothing will fire it on its own; start it by hand or give it a time with \`${this.config.bin} tasks schedule ${next} --at <ISO time>\`.`;
74
+ }
75
+ else if (result.rescheduled) {
76
+ line = `The next occurrence ${next} existed but had no schedule; it is now scheduled${when}. The failure marker is cleared.`;
77
+ }
78
+ else if (result.alreadyArmed) {
79
+ line = `The series from ${from} was already armed: next occurrence ${next}${when}. The failure marker is cleared.`;
80
+ }
81
+ else {
82
+ line = `Re-armed the series from ${from}: next occurrence ${next} is scheduled${when}.`;
83
+ }
84
+ this.log(line);
85
+ }
86
+ }
87
+ exports.default = TasksRearmRecurrence;
@@ -69,6 +69,14 @@ export declare function labelsLine(labelIds?: string[], nameById?: Map<string, s
69
69
  * reassigning the task changes only the implied kind.
70
70
  */
71
71
  export declare function taskExecutorLabel(t: Record<string, unknown>, bin?: string): string;
72
+ /**
73
+ * The `Resolution:` lines for any resolved Task: how it ended, the reason the
74
+ * closer recorded, who closed it, and what the close stood on. The reason used to
75
+ * be JSON-only, so text showed "Task workflow type is cancelled" for every
76
+ * cancel, and a Task its Workflow step cancelled could not be told from one a
77
+ * person cancelled by hand (OSK-16475). Silent for an open Task.
78
+ */
79
+ export declare function resolutionLines(t: Record<string, unknown>, names?: Map<string, string>): string[];
72
80
  /**
73
81
  * The `Recurrence:` line for a series whose next occurrence was never armed.
74
82
  * Silent otherwise: a healthy series has nothing to say here.
@@ -112,6 +120,7 @@ export default class TasksShow extends BaseCommand {
112
120
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
113
121
  task: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
114
122
  'no-enrich': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
123
+ 'description-format': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
115
124
  };
116
125
  run(): Promise<void>;
117
126
  /**
@@ -6,6 +6,7 @@ exports.completionLines = completionLines;
6
6
  exports.reviewPolicyLine = reviewPolicyLine;
7
7
  exports.labelsLine = labelsLine;
8
8
  exports.taskExecutorLabel = taskExecutorLabel;
9
+ exports.resolutionLines = resolutionLines;
9
10
  exports.recurrenceArmFailureLines = recurrenceArmFailureLines;
10
11
  exports.taskFailureLines = taskFailureLines;
11
12
  const core_1 = require("@oclif/core");
@@ -21,6 +22,7 @@ const label_ref_1 = require("../../lib/label-ref");
21
22
  const principal_display_1 = require("../../lib/principal-display");
22
23
  const task_economics_line_1 = require("../../lib/task-economics-line");
23
24
  const format_1 = require("../../lib/format");
25
+ const task_recurrence_outcome_1 = require("../../lib/task-recurrence-outcome");
24
26
  /**
25
27
  * Where to look next — as COMMANDS, not as facts about the task.
26
28
  *
@@ -150,6 +152,43 @@ function taskExecutorLabel(t, bin = 'skrr') {
150
152
  return '-';
151
153
  }
152
154
  }
155
+ function resolverLabel(by, names) {
156
+ if (!by || typeof by !== 'object' || !by.kind)
157
+ return null;
158
+ const kind = String(by.kind);
159
+ if (kind === 'human')
160
+ return `person ${(0, principal_display_1.displayPrincipal)(by.userId, names)}`;
161
+ if (kind === 'agent')
162
+ return `agent ${(0, principal_display_1.displayPrincipal)(by.agentId, names)}`;
163
+ if (kind === 'system')
164
+ return `system${by.service ? ` (${String(by.service)})` : ''}`;
165
+ if (kind === 'integration')
166
+ return `integration${by.provider ? ` (${String(by.provider)})` : ''}`;
167
+ return kind;
168
+ }
169
+ /**
170
+ * The `Resolution:` lines for any resolved Task: how it ended, the reason the
171
+ * closer recorded, who closed it, and what the close stood on. The reason used to
172
+ * be JSON-only, so text showed "Task workflow type is cancelled" for every
173
+ * cancel, and a Task its Workflow step cancelled could not be told from one a
174
+ * person cancelled by hand (OSK-16475). Silent for an open Task.
175
+ */
176
+ function resolutionLines(t, names) {
177
+ const resolution = t.resolution;
178
+ if (!resolution || typeof resolution !== 'object' || !resolution.kind)
179
+ return [];
180
+ const reason = typeof resolution.reason === 'string' ? resolution.reason.trim() : '';
181
+ const closure = resolution.closure
182
+ ? (0, task_closure_1.closureSnapshotLines)(resolution.closure)
183
+ : [];
184
+ const lines = [`Resolution: ${String(resolution.kind)}${reason ? ` — ${reason}` : ''}`];
185
+ if (closure.length > 0)
186
+ lines.push(` ${closure.join(' ')}`);
187
+ const by = resolverLabel(resolution.resolvedBy, names);
188
+ if (by)
189
+ lines.push(`Resolved by: ${by}`);
190
+ return lines;
191
+ }
153
192
  /**
154
193
  * The `Recurrence:` line for a series whose next occurrence was never armed.
155
194
  * Silent otherwise: a healthy series has nothing to say here.
@@ -159,9 +198,17 @@ function recurrenceArmFailureLines(t, bin = 'skrr') {
159
198
  const code = recurrence?.armFailure?.code;
160
199
  if (typeof code !== 'string' || !code)
161
200
  return [];
201
+ const ref = (typeof t.identifier === 'string' && t.identifier) ||
202
+ (typeof t.id === 'string' && t.id) ||
203
+ '<task-id>';
204
+ // A finished occurrence is re-armed (`tasks schedule` refuses it, OSK-15338); a LIVE series the
205
+ // scheduler stopped on an unrunnable pattern is rescheduled with a valid one, which clears it.
206
+ const finished = ['completed', 'cancelled'].includes(String(t.statusType ?? ''));
162
207
  return [
163
208
  `Recurrence: ${(0, data_provider_1.describeRecurrenceArmFailure)(code)} (${code})`,
164
- ` Reschedule with \`${bin} tasks schedule\` to start the series again.`,
209
+ finished || t.statusType === undefined
210
+ ? ` ${(0, task_recurrence_outcome_1.recurrenceRearmHint)(code, ref, bin)}`
211
+ : ` Reschedule it with \`${bin} tasks schedule ${ref} --at <ISO time> --cron "<minute hour day month weekday>"\`.`,
165
212
  ];
166
213
  }
167
214
  /**
@@ -246,6 +293,10 @@ class TasksShow extends base_command_1.BaseCommand {
246
293
  'no-enrich': core_1.Flags.boolean({
247
294
  description: 'Skip server-side enrichment (assignee names, parent titles)',
248
295
  }),
296
+ 'description-format': core_1.Flags.string({
297
+ description: 'How to read the description. html (default) is what is stored; markdown returns it as it was written.',
298
+ options: ['html', 'markdown'],
299
+ }),
249
300
  };
250
301
  async run() {
251
302
  this.requireAuth();
@@ -304,7 +355,12 @@ class TasksShow extends base_command_1.BaseCommand {
304
355
  task = bound;
305
356
  }
306
357
  else {
307
- task = await data_provider_1.dataService.getTask(taskId, { enrich: !flags['no-enrich'] });
358
+ task = await data_provider_1.dataService.getTask(taskId, {
359
+ enrich: !flags['no-enrich'],
360
+ ...(flags['description-format'] === 'markdown'
361
+ ? { descriptionFormat: 'markdown' }
362
+ : {}),
363
+ });
308
364
  }
309
365
  }
310
366
  catch (err) {
@@ -331,13 +387,28 @@ class TasksShow extends base_command_1.BaseCommand {
331
387
  completionRead = false;
332
388
  }
333
389
  if (flags.json) {
334
- this.log(JSON.stringify({ ...t, url, completion }, null, 2));
390
+ this.printJsonResult({ ...t, url, completion });
335
391
  return;
336
392
  }
337
393
  for (const line of completionLines(completion, { read: completionRead }))
338
394
  this.log(line);
339
395
  const agents = Array.isArray(t.assigneeAgentIds) ? t.assigneeAgentIds : [];
340
396
  const users = Array.isArray(t.assigneeUserIds) ? t.assigneeUserIds : [];
397
+ // Principals print as names, not ObjectIds — same rule as labels: a
398
+ // roster that cannot be read prints ids rather than failing the command.
399
+ const resolvedBy = t.resolution?.resolvedBy;
400
+ const principalIds = [
401
+ t.author,
402
+ t.dri?.resolved?.id,
403
+ ...(Array.isArray(t.assigneeAgentIds) ? t.assigneeAgentIds : []),
404
+ ...(Array.isArray(t.assigneeUserIds) ? t.assigneeUserIds : []),
405
+ t.economics?.confirmedBy,
406
+ resolvedBy?.userId,
407
+ resolvedBy?.agentId,
408
+ ];
409
+ const principalNames = await (0, principal_display_1.resolvePrincipalNames)(principalIds, {
410
+ spaceId: t.spaceId ?? null,
411
+ });
341
412
  this.log(`ID: ${t.id ?? t._id ?? '-'}`);
342
413
  this.log(`Ref: ${t.identifier ?? (t.taskNumber ? `#${t.taskNumber}` : '-')}`);
343
414
  this.log(`Title: ${t.title ?? '-'}`);
@@ -354,25 +425,12 @@ class TasksShow extends base_command_1.BaseCommand {
354
425
  * Closing is the actor's call — a Task may be `done` with work still
355
426
  * outstanding, and `resolution.closure` is where the server recorded what
356
427
  * it stood on at close. Show it so a bare "done" never reads as "clean."
428
+ * The closure sentences share the `tasks move` receipt's renderer, so the
429
+ * two cannot disagree; the reason and the closer are printed for every
430
+ * resolved Task (OSK-16475).
357
431
  */
358
- const resolution = t.resolution;
359
- /*
360
- * Same renderer as the `tasks move` receipt, so the two cannot disagree
361
- * about a Task they are both describing.
362
- *
363
- * This copy showed an owner's ordinary close as an override:
364
- * `TASK_RESULT_REVIEW_REQUIRED` lands in `blockers` whenever the policy is
365
- * unsatisfied — including when the owner, who is not bound by the Review
366
- * they declared, closes it themselves — and this rendered it identically to
367
- * a genuine forced close. So the only read surface for "was this gate
368
- * overridden?" could not answer the question.
369
- */
370
- if (resolution?.closure) {
371
- const sentences = (0, task_closure_1.closureSnapshotLines)(resolution.closure);
372
- if (sentences.length > 0) {
373
- this.log(`Resolution: ${resolution.kind ?? '-'} — ${sentences.join(' ')}`);
374
- }
375
- }
432
+ for (const line of resolutionLines(t, principalNames))
433
+ this.log(line);
376
434
  /*
377
435
  * A Result orphaned by a spec edit is not the same as no Result.
378
436
  *
@@ -505,18 +563,6 @@ class TasksShow extends base_command_1.BaseCommand {
505
563
  }
506
564
  }
507
565
  this.log(`Labels: ${labelsLine(labelIds, labelNames)}`);
508
- // Principals print as names, not ObjectIds — same rule as labels above: a
509
- // roster that cannot be read prints ids rather than failing the command.
510
- const principalIds = [
511
- t.author,
512
- t.dri?.resolved?.id,
513
- ...(Array.isArray(t.assigneeAgentIds) ? t.assigneeAgentIds : []),
514
- ...(Array.isArray(t.assigneeUserIds) ? t.assigneeUserIds : []),
515
- t.economics?.confirmedBy,
516
- ];
517
- const principalNames = await (0, principal_display_1.resolvePrincipalNames)(principalIds, {
518
- spaceId: t.spaceId ?? null,
519
- });
520
566
  this.log(`Author: ${t.authorDisplayName || (0, principal_display_1.displayPrincipal)(t.author, principalNames)}`);
521
567
  const dri = t.dri;
522
568
  if (dri?.resolved) {
@@ -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;
@@ -5,7 +5,11 @@ 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
  class TasksUnschedule extends base_command_1.BaseCommand {
8
- static description = 'Clear the schedule on a task (no future fires)';
8
+ // Decision (OSK-15321, round 3): unschedule ENDS the series at this occurrence; it clears the
9
+ // time and the recurrence. Stopping without ending is `pause-schedule` (keeps the series,
10
+ // `resume-schedule` continues it). A series ended here by mistake is restored, settings and
11
+ // all, with `rearm-recurrence <the previous occurrence>`.
12
+ static description = 'Clear the schedule on a task and end its series here (no future fires). To stop without ending the series use pause-schedule; to restore an ended series run rearm-recurrence on the previous occurrence';
9
13
  static examples = [
10
14
  '<%= config.bin %> tasks unschedule <task-id>',
11
15
  '<%= config.bin %> tasks unschedule <task-id> --json',
@@ -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`.
@@ -538,7 +543,17 @@ class TasksUpdate extends base_command_1.BaseCommand {
538
543
  }
539
544
  const t = updated;
540
545
  const ref = t.identifier ?? (t.taskNumber ? `#${t.taskNumber}` : '');
541
- this.log(`Updated task ${t.id ?? t._id ?? taskRef}${ref ? ` (${ref})` : ''} — ${t.title ?? '(no title)'}`);
546
+ const label = `${t.id ?? t._id ?? taskRef}${ref ? ` (${ref})` : ''}`;
547
+ // The server's own answer about the estimate (OSK-16476): a no-op says so, never "Updated".
548
+ const unchanged = (0, task_economics_1.estimateUnchangedLine)(payload.economics, t);
549
+ const onlyEstimate = payloadKeys.every((key) => key === 'economics' || payload[key] === undefined);
550
+ if (unchanged && onlyEstimate) {
551
+ this.log(`Task ${label}: ${unchanged}`);
552
+ return;
553
+ }
554
+ this.log(`Updated task ${label} — ${t.title ?? '(no title)'}`);
555
+ if (unchanged)
556
+ this.log(unchanged);
542
557
  // `--yes` asserts the revocation; it does not erase that it happened.
543
558
  // Report the cost after the write too, or the evidence is silently gone.
544
559
  if (changesSpec && flags.yes && (settledSpecAssessments > 0 || acceptanceUnreadable)) {
@@ -25,17 +25,25 @@ class TriggersAudit extends base_command_1.BaseCommand {
25
25
  agent: core_1.Flags.string({ description: 'Agent ID filter for owner-wide audit history' }),
26
26
  scope: core_1.Flags.string({ description: 'Scope kind filter for owner-wide audit history' }),
27
27
  outcome: core_1.Flags.string({
28
- description: 'Outcome filter for owner-wide audit history (succeeded, failed, skipped, incomplete, capped, ...); an unknown value is refused with the full list',
28
+ description: 'Outcome filter (succeeded, failed, skipped, incomplete, capped, ...); an unknown value is refused with the full list',
29
29
  }),
30
30
  source: core_1.Flags.string({
31
- description: 'Source filter for owner-wide audit history (schedule, once, event, manual, webhook, replay, ...); an unknown value is refused with the full list',
31
+ description: 'Source filter (schedule, once, event, manual, webhook, replay, ...); an unknown value is refused with the full list',
32
32
  }),
33
33
  };
34
34
  async run() {
35
35
  this.requireAuth();
36
36
  const { args, flags } = await this.parse(TriggersAudit);
37
37
  const triggerId = args.id ?? flags.trigger;
38
- const path = triggerId
38
+ // The per-trigger route takes no filters. A filter passed with a trigger id used to be
39
+ // dropped without a word, so `--outcome failed` listed succeeded rows and exited 0 (OSK-16474).
40
+ // A filter now always reaches the filtered history, narrowed to that trigger; that history
41
+ // covers triggers you own, which is said out loud rather than discovered.
42
+ const filtered = [flags.outcome, flags.source, flags.scope, flags.agent].some((value) => value !== undefined);
43
+ if (triggerId && filtered && !flags.json) {
44
+ this.warn('Filters read the fire history of triggers you own: a trigger shared with you but owned by someone else lists no rows here (omit the filters to read its own audit).');
45
+ }
46
+ const path = triggerId && !filtered
39
47
  ? (0, triggers_1.withQuery)(`/api/triggers/${encodeURIComponent(triggerId)}/audit`, {
40
48
  limit: flags.limit,
41
49
  before: flags.before,
@@ -47,6 +55,7 @@ class TriggersAudit extends base_command_1.BaseCommand {
47
55
  agentId: flags.agent,
48
56
  outcome: flags.outcome,
49
57
  source: flags.source,
58
+ ...(triggerId ? { triggerId } : {}),
50
59
  });
51
60
  let response;
52
61
  try {
@@ -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)',
@@ -99,7 +99,7 @@ class TriggersCreate extends base_command_1.BaseCommand {
99
99
  description: 'ISO-8601 datetime after which a schedule stops firing',
100
100
  }),
101
101
  'stale-catchup-ms': core_1.Flags.integer({
102
- description: 'How late a missed occurrence may still run, in ms (a positive number). After downtime, an occurrence more than this overdue is skipped rather than run late, and the schedule moves to its next future slot. Unset: 3600000 (1 hour).',
102
+ description: 'How late a missed occurrence may still run, in ms, from 1000 (1 second) to 31622400000 (366 days). After downtime, an occurrence more than this overdue is skipped rather than run late, and the schedule moves to its next future slot. Unset: 3600000 (1 hour).',
103
103
  }),
104
104
  at: core_1.Flags.string({
105
105
  description: 'ISO-8601 datetime for once triggers. --next-run-at is also accepted with --kind once for backwards compatibility.',
@@ -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,11 @@
1
1
  import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * The text rendering of one fire. `reason` is the typed code and `errorMessage` the sentence a
4
+ * person reads; the view printed whichever came first, so a fire that resolved nothing showed
5
+ * only `Reason: no_waiting_step` and its sentence ("No step in this Space was waiting on that
6
+ * event key.") was JSON-only (OSK-16474). Both are shown now when both exist.
7
+ */
8
+ export declare function describeFireAuditDetail(detail: Record<string, unknown>, fireId: string, triggerId: string): string[];
2
9
  export default class TriggersFireDetail extends BaseCommand {
3
10
  static description: string;
4
11
  static examples: string[];
@@ -1,8 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.describeFireAuditDetail = describeFireAuditDetail;
3
4
  const core_1 = require("@oclif/core");
4
5
  const base_command_1 = require("../../base-command");
5
6
  const triggers_1 = require("../../lib/triggers");
7
+ /**
8
+ * The text rendering of one fire. `reason` is the typed code and `errorMessage` the sentence a
9
+ * person reads; the view printed whichever came first, so a fire that resolved nothing showed
10
+ * only `Reason: no_waiting_step` and its sentence ("No step in this Space was waiting on that
11
+ * event key.") was JSON-only (OSK-16474). Both are shown now when both exist.
12
+ */
13
+ function describeFireAuditDetail(detail, fireId, triggerId) {
14
+ const text = (value) => (typeof value === 'string' && value.trim() ? value.trim() : '');
15
+ const lines = [
16
+ `Fire: ${String(detail._id ?? fireId)}`,
17
+ `Trigger: ${String(detail.triggerId ?? triggerId)}`,
18
+ `Fired at: ${String(detail.firedAt ?? '-')}`,
19
+ `Outcome: ${String(detail.outcome ?? '-')}`,
20
+ `Source: ${String(detail.source ?? '-')}`,
21
+ ];
22
+ const reason = text(detail.reason);
23
+ const message = text(detail.errorMessage);
24
+ if (reason)
25
+ lines.push(`Reason: ${reason}`);
26
+ if (message && message !== reason)
27
+ lines.push(`${reason ? 'Detail:' : 'Reason:'} ${message}`);
28
+ if (detail.durationMs !== undefined)
29
+ lines.push(`Duration: ${String(detail.durationMs)}ms`);
30
+ if (detail.conversationId)
31
+ lines.push(`Conversation: ${String(detail.conversationId)}`);
32
+ return lines;
33
+ }
6
34
  class TriggersFireDetail extends base_command_1.BaseCommand {
7
35
  static description = 'Show full detail for one trigger fire record';
8
36
  static examples = [
@@ -34,18 +62,8 @@ class TriggersFireDetail extends base_command_1.BaseCommand {
34
62
  this.log(JSON.stringify(detail, null, 2));
35
63
  return;
36
64
  }
37
- this.log(`Fire: ${detail._id ?? args.fireId}`);
38
- this.log(`Trigger: ${detail.triggerId ?? args.id}`);
39
- this.log(`Fired at: ${detail.firedAt ?? '-'}`);
40
- this.log(`Outcome: ${detail.outcome ?? '-'}`);
41
- this.log(`Source: ${detail.source ?? '-'}`);
42
- if (detail.reason || detail.errorMessage) {
43
- this.log(`Reason: ${detail.reason ?? detail.errorMessage}`);
44
- }
45
- if (detail.durationMs !== undefined)
46
- this.log(`Duration: ${detail.durationMs}ms`);
47
- if (detail.conversationId)
48
- this.log(`Conversation: ${detail.conversationId}`);
65
+ for (const line of describeFireAuditDetail(detail, args.fireId, args.id))
66
+ this.log(line);
49
67
  }
50
68
  }
51
69
  exports.default = TriggersFireDetail;