@skrr-ai/cli 0.1.104 → 0.1.106

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 (111) hide show
  1. package/dist/base-command.js +6 -2
  2. package/dist/commands/agenda/trigger/list.js +2 -0
  3. package/dist/commands/agents/chat.js +4 -1
  4. package/dist/commands/agents/operating-plan.js +5 -2
  5. package/dist/commands/agents/triggers/create.js +3 -1
  6. package/dist/commands/agents/triggers/fire.js +2 -0
  7. package/dist/commands/agents/triggers/replay.js +2 -0
  8. package/dist/commands/agents/triggers/update.js +12 -4
  9. package/dist/commands/commitments/action-history.js +7 -2
  10. package/dist/commands/commitments/cadence-decisions.js +6 -1
  11. package/dist/commands/commitments/cadence-requests/decide.d.ts +1 -1
  12. package/dist/commands/commitments/cadence-requests/decide.js +1 -1
  13. package/dist/commands/commitments/doctor.js +7 -1
  14. package/dist/commands/commitments/observations.js +7 -1
  15. package/dist/commands/commitments/operating-review.d.ts +15 -0
  16. package/dist/commands/commitments/operating-review.js +23 -2
  17. package/dist/commands/commitments/preflight.d.ts +12 -0
  18. package/dist/commands/commitments/preflight.js +23 -9
  19. package/dist/commands/commitments/reflection.js +6 -1
  20. package/dist/commands/commitments/show.js +3 -1
  21. package/dist/commands/commitments/trigger-status.js +2 -22
  22. package/dist/commands/commitments/wake-capabilities.d.ts +13 -0
  23. package/dist/commands/commitments/wake-capabilities.js +39 -3
  24. package/dist/commands/daemon/logs.d.ts +73 -3
  25. package/dist/commands/daemon/logs.js +304 -17
  26. package/dist/commands/followups/act.js +13 -1
  27. package/dist/commands/followups/checkin.js +11 -2
  28. package/dist/commands/followups/reschedule.js +13 -1
  29. package/dist/commands/proposals/discard.d.ts +1 -1
  30. package/dist/commands/proposals/keep.d.ts +1 -1
  31. package/dist/commands/proposals/list.d.ts +7 -0
  32. package/dist/commands/proposals/list.js +31 -5
  33. package/dist/commands/proposals/show.d.ts +2 -1
  34. package/dist/commands/proposals/show.js +31 -4
  35. package/dist/commands/proposals/snooze.d.ts +1 -1
  36. package/dist/commands/requests/create.js +8 -3
  37. package/dist/commands/spaces/workflows/create.js +3 -3
  38. package/dist/commands/tasks/complete.js +4 -0
  39. package/dist/commands/tasks/create.d.ts +2 -0
  40. package/dist/commands/tasks/create.js +17 -3
  41. package/dist/commands/tasks/deliverable/add.d.ts +2 -0
  42. package/dist/commands/tasks/deliverable/add.js +22 -7
  43. package/dist/commands/tasks/deliverable/list.d.ts +13 -0
  44. package/dist/commands/tasks/deliverable/list.js +34 -1
  45. package/dist/commands/tasks/economics-compare.js +7 -1
  46. package/dist/commands/tasks/expectations.d.ts +10 -0
  47. package/dist/commands/tasks/expectations.js +31 -3
  48. package/dist/commands/tasks/list.d.ts +9 -0
  49. package/dist/commands/tasks/list.js +40 -5
  50. package/dist/commands/tasks/report.js +1 -1
  51. package/dist/commands/tasks/result/show.d.ts +7 -0
  52. package/dist/commands/tasks/result/show.js +32 -1
  53. package/dist/commands/tasks/result/submit.js +1 -1
  54. package/dist/commands/tasks/retry-schedule.js +11 -1
  55. package/dist/commands/tasks/show.d.ts +6 -0
  56. package/dist/commands/tasks/show.js +23 -0
  57. package/dist/commands/tasks/update.d.ts +3 -0
  58. package/dist/commands/tasks/update.js +23 -3
  59. package/dist/commands/triggers/audit.js +6 -2
  60. package/dist/commands/triggers/create.js +3 -1
  61. package/dist/commands/triggers/fire.d.ts +1 -0
  62. package/dist/commands/triggers/fire.js +16 -1
  63. package/dist/commands/triggers/preflight.js +6 -5
  64. package/dist/commands/triggers/replay.js +2 -0
  65. package/dist/commands/triggers/update.js +12 -4
  66. package/dist/commands/workspaces/stewardship.js +5 -1
  67. package/dist/lib/agentic-stream.d.ts +9 -0
  68. package/dist/lib/agentic-stream.js +38 -18
  69. package/dist/lib/commitment-event-wakes.d.ts +8 -0
  70. package/dist/lib/commitment-event-wakes.js +39 -0
  71. package/dist/lib/commitment-ledgers.d.ts +9 -0
  72. package/dist/lib/commitment-ledgers.js +126 -0
  73. package/dist/lib/commitments.d.ts +102 -2
  74. package/dist/lib/commitments.js +208 -8
  75. package/dist/lib/delegated-cli.js +13 -2
  76. package/dist/lib/followups.d.ts +6 -0
  77. package/dist/lib/followups.js +12 -0
  78. package/dist/lib/message-content.d.ts +6 -0
  79. package/dist/lib/message-content.js +24 -0
  80. package/dist/lib/operating-plan-loops.d.ts +8 -0
  81. package/dist/lib/operating-plan-loops.js +32 -0
  82. package/dist/lib/preflight-copy.d.ts +27 -0
  83. package/dist/lib/preflight-copy.js +89 -0
  84. package/dist/lib/proposal-decision-command.d.ts +1 -1
  85. package/dist/lib/proposal-decision-command.js +27 -3
  86. package/dist/lib/proposals.d.ts +17 -0
  87. package/dist/lib/proposals.js +41 -0
  88. package/dist/lib/stewardship-output.js +57 -12
  89. package/dist/lib/task-economics-line.d.ts +30 -0
  90. package/dist/lib/task-economics-line.js +49 -0
  91. package/dist/lib/task-economics.d.ts +15 -0
  92. package/dist/lib/task-economics.js +73 -8
  93. package/dist/lib/task-recurrence-outcome.d.ts +19 -0
  94. package/dist/lib/task-recurrence-outcome.js +30 -0
  95. package/dist/lib/triggers.d.ts +42 -0
  96. package/dist/lib/triggers.js +136 -2
  97. package/dist/lib/widgetTerminalText.d.ts +8 -0
  98. package/dist/lib/widgetTerminalText.js +116 -0
  99. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.d.ts +33 -0
  100. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/cliHandoffWire.js +27 -0
  101. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.d.ts +28 -5
  102. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.js +50 -5
  103. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.d.ts +33 -0
  104. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/cliHandoffWire.js +26 -0
  105. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.d.ts +28 -5
  106. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.js +50 -5
  107. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  108. package/dist/node_modules/@skrr-ai/data-provider/index.js +7261 -7056
  109. package/docs/v1/operations.md +1 -1
  110. package/oclif.manifest.json +116 -72
  111. package/package.json +1 -1
@@ -171,7 +171,7 @@ class TasksReport extends base_command_1.BaseCommand {
171
171
  this.log(JSON.stringify({ ...result, url }, null, 2));
172
172
  return;
173
173
  }
174
- this.log(`Submitted Result v${result.result.version} on task ${task.id}.${url ? ` ${url}` : ''}`);
174
+ this.log(`Submitted Result v${result.result.version} (${result.result.id}) on task ${task.id}.${url ? ` ${url}` : ''}`);
175
175
  }
176
176
  }
177
177
  exports.default = TasksReport;
@@ -1,4 +1,11 @@
1
+ import type { TaskResultRecord } from '@skrr-ai/data-provider';
1
2
  import { BaseCommand } from '../../../base-command';
3
+ /**
4
+ * What a reviewer needs to accept ONE exact Result (OSK-15430). `result show` printed the summary and
5
+ * the conclusion, and kept the Result id (the value `tasks review --result-id` requires), the linked
6
+ * deliverables, the evidence, the remaining work and the Result it supersedes for `--json`.
7
+ */
8
+ export declare function describeResultDetail(current: TaskResultRecord, all?: TaskResultRecord[]): string[];
2
9
  export default class TasksResultShow extends BaseCommand {
3
10
  static description: string;
4
11
  static args: {
@@ -1,10 +1,39 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.describeResultDetail = describeResultDetail;
3
4
  const core_1 = require("@oclif/core");
4
5
  const data_provider_1 = require("@skrr-ai/data-provider");
5
6
  const base_command_1 = require("../../../base-command");
6
7
  const task_resolver_1 = require("../../../lib/task-resolver");
7
8
  const task_legacy_1 = require("../../../lib/task-legacy");
9
+ /**
10
+ * What a reviewer needs to accept ONE exact Result (OSK-15430). `result show` printed the summary and
11
+ * the conclusion, and kept the Result id (the value `tasks review --result-id` requires), the linked
12
+ * deliverables, the evidence, the remaining work and the Result it supersedes for `--json`.
13
+ */
14
+ function describeResultDetail(current, all = []) {
15
+ const lines = [];
16
+ if (current.supersedesResultId) {
17
+ const previous = all.find((row) => row.id === current.supersedesResultId);
18
+ lines.push(`Supersedes: ${current.supersedesResultId}${previous ? ` (v${previous.version})` : ''}`);
19
+ }
20
+ const links = current.resourceLinkIds ?? [];
21
+ lines.push(`Deliverables: ${links.length > 0 ? links.join(', ') : 'none linked'}`);
22
+ const evidence = current.evidenceRefs ?? [];
23
+ lines.push(`Evidence: ${evidence.length > 0
24
+ ? evidence.map((ref) => `${ref.kind}:${ref.id}`).join(', ')
25
+ : 'none attached'}`);
26
+ const remaining = current.remainingWork ?? [];
27
+ if (remaining.length > 0) {
28
+ lines.push('Remaining work:');
29
+ for (const item of remaining)
30
+ lines.push(` - ${item.summary}`);
31
+ }
32
+ else {
33
+ lines.push('Remaining work: none declared');
34
+ }
35
+ return lines;
36
+ }
8
37
  class TasksResultShow extends base_command_1.BaseCommand {
9
38
  static description = 'Show the current Task Result and its exact Review';
10
39
  static args = {
@@ -32,9 +61,11 @@ class TasksResultShow extends base_command_1.BaseCommand {
32
61
  if (!current)
33
62
  return this.log(await (0, task_legacy_1.emptyCanonicalView)(task.id, 'Result'));
34
63
  const review = result.reviews.find((row) => row.resultId === current.id);
35
- this.log(`Result v${current.version}\n${current.summary}`);
64
+ this.log(`Result v${current.version} ${current.id}\n${current.summary}`);
36
65
  if (current.conclusion)
37
66
  this.log(`Conclusion (${current.conclusion.type}): ${JSON.stringify(current.conclusion.value)}`);
67
+ for (const line of describeResultDetail(current, result.results))
68
+ this.log(line);
38
69
  // Only "awaiting" while a review can still be recorded. A closed Task
39
70
  // refuses one outright (`TASK_REOPEN_REQUIRED`), so the old wording named a
40
71
  // state nothing could ever leave — and a reader could not tell it from a
@@ -211,7 +211,7 @@ class TasksResultSubmit extends base_command_1.BaseCommand {
211
211
  // managed instructions told the agent to read the status the call returns,
212
212
  // which the call did not carry. Submitting a Result is not closing a Task;
213
213
  // the response now reports where it stands and this prints exactly that.
214
- this.log(`Submitted Result v${result.result.version} for ${task.id}.`);
214
+ this.log(`Submitted Result v${result.result.version} (${result.result.id}) for ${task.id}.`);
215
215
  for (const line of (0, task_closure_1.closureReport)(result.closure, { closing: false }))
216
216
  this.log(line);
217
217
  if (url)
@@ -40,7 +40,17 @@ class TasksRetrySchedule extends base_command_1.BaseCommand {
40
40
  const t = result;
41
41
  const ref = t.identifier ?? (t.taskNumber ? `#${t.taskNumber}` : '');
42
42
  const when = flags.at ?? t.scheduledFor ?? '(server default)';
43
- this.log(`Re-armed schedule for task ${t.id ?? t._id ?? taskRef}${ref ? ` (${ref})` : ''} → ${when}`);
43
+ const retry = t.scheduleRetry;
44
+ const subject = `task ${t.id ?? t._id ?? taskRef}${ref ? ` (${ref})` : ''}`;
45
+ if (retry?.changed === false) {
46
+ this.log(`Schedule for ${subject} is already armed for ${when}; nothing changed.`);
47
+ }
48
+ else if (retry?.armedFirstSchedule) {
49
+ this.log(`Armed a first schedule for ${subject} → ${when} (it had none; \`tasks schedule\` is the command for that).`);
50
+ }
51
+ else {
52
+ this.log(`Re-armed schedule for ${subject} → ${when}`);
53
+ }
44
54
  }
45
55
  }
46
56
  exports.default = TasksRetrySchedule;
@@ -50,6 +50,12 @@ export declare function completionLines(projection: {
50
50
  } | null | undefined, { read }?: {
51
51
  read?: boolean;
52
52
  }): string[];
53
+ /**
54
+ * The review-policy line, or null for the default. Only a non-default policy is printed: `none` is
55
+ * every Task that never asked, and printing it would add a line to all of them. Without this the
56
+ * policy was readable in --json alone (OSK-15434).
57
+ */
58
+ export declare function reviewPolicyLine(policy: unknown): string | null;
53
59
  export declare function labelsLine(labelIds?: string[], nameById?: Map<string, string>): string;
54
60
  /**
55
61
  * The `Executor:` value — who does this task, and whether anyone said so.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.taskPointerLines = taskPointerLines;
4
4
  exports.blockerDetailLines = blockerDetailLines;
5
5
  exports.completionLines = completionLines;
6
+ exports.reviewPolicyLine = reviewPolicyLine;
6
7
  exports.labelsLine = labelsLine;
7
8
  exports.taskExecutorLabel = taskExecutorLabel;
8
9
  exports.recurrenceArmFailureLines = recurrenceArmFailureLines;
@@ -18,6 +19,7 @@ const web_url_1 = require("../../lib/web-url");
18
19
  const html_text_1 = require("../../lib/html-text");
19
20
  const label_ref_1 = require("../../lib/label-ref");
20
21
  const principal_display_1 = require("../../lib/principal-display");
22
+ const task_economics_line_1 = require("../../lib/task-economics-line");
21
23
  const format_1 = require("../../lib/format");
22
24
  /**
23
25
  * Where to look next — as COMMANDS, not as facts about the task.
@@ -108,6 +110,16 @@ function completionLines(projection, { read = true } = {}) {
108
110
  : [];
109
111
  return [`Done? ${sentence}`, ...also.map((row) => ` also: ${row.trim()}`)];
110
112
  }
113
+ /**
114
+ * The review-policy line, or null for the default. Only a non-default policy is printed: `none` is
115
+ * every Task that never asked, and printing it would add a line to all of them. Without this the
116
+ * policy was readable in --json alone (OSK-15434).
117
+ */
118
+ function reviewPolicyLine(policy) {
119
+ return policy === 'required'
120
+ ? 'Review policy: required — closing by anyone but the author needs an accepted independent Review'
121
+ : null;
122
+ }
111
123
  function labelsLine(labelIds, nameById) {
112
124
  const ids = (labelIds ?? []).filter((id) => typeof id === 'string' && id.length > 0);
113
125
  if (ids.length === 0)
@@ -466,6 +478,9 @@ class TasksShow extends base_command_1.BaseCommand {
466
478
  }
467
479
  }
468
480
  this.log(`Priority: ${t.priority ?? '-'}`);
481
+ const review = reviewPolicyLine(t.reviewPolicy);
482
+ if (review)
483
+ this.log(review);
469
484
  this.log(`Parent: ${t.parentId ?? '-'}`);
470
485
  this.log(`Space: ${t.spaceId ?? '-'}`);
471
486
  // Printed beside Space and Goal because `--project` is accepted on create
@@ -497,6 +512,7 @@ class TasksShow extends base_command_1.BaseCommand {
497
512
  t.dri?.resolved?.id,
498
513
  ...(Array.isArray(t.assigneeAgentIds) ? t.assigneeAgentIds : []),
499
514
  ...(Array.isArray(t.assigneeUserIds) ? t.assigneeUserIds : []),
515
+ t.economics?.confirmedBy,
500
516
  ];
501
517
  const principalNames = await (0, principal_display_1.resolvePrincipalNames)(principalIds, {
502
518
  spaceId: t.spaceId ?? null,
@@ -516,6 +532,13 @@ class TasksShow extends base_command_1.BaseCommand {
516
532
  this.log(`Assignees: ${agents.length} agent(s), ${users.length} user(s)${agents.length + users.length > 0
517
533
  ? ` — ${[...agents, ...users].map((id) => (0, principal_display_1.displayPrincipal)(id, principalNames)).join(', ')}`
518
534
  : ''}`);
535
+ const economics = t.economics;
536
+ const economicsText = (0, task_economics_line_1.economicsLine)(economics, economics?.confirmedBy ? (0, principal_display_1.displayPrincipal)(economics.confirmedBy, principalNames) : undefined);
537
+ if (economicsText)
538
+ this.log(`Economics: ${economicsText}`);
539
+ const rationale = economicsText ? (0, task_economics_line_1.economicsRationaleLine)(economics) : null;
540
+ if (rationale)
541
+ this.log(`Rationale: ${rationale}`);
519
542
  const actionability = t.actionability;
520
543
  if (actionability) {
521
544
  this.log(actionability.state === 'terminal'
@@ -21,6 +21,8 @@ export default class TasksUpdate extends BaseCommand {
21
21
  per: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
22
22
  effort: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
23
23
  risk: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
24
+ confidence: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
+ rationale: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
24
26
  estimate: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
27
  /**
26
28
  * Declared, hidden, and refused — on purpose. (S4 dogfood finding)
@@ -43,6 +45,7 @@ export default class TasksUpdate extends BaseCommand {
43
45
  */
44
46
  status: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
45
47
  'duplicate-of': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
48
+ 'review-policy': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
46
49
  goal: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
47
50
  cycle: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
48
51
  space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
@@ -63,13 +63,27 @@ class TasksUpdate extends base_command_1.BaseCommand {
63
63
  }),
64
64
  'start-date': core_1.Flags.string({ description: 'New planned start date (ISO string)' }),
65
65
  'due-date': core_1.Flags.string({ description: 'New due date (ISO string)' }),
66
- savings: core_1.Flags.string({ description: 'Expected USD savings (requires --per)' }),
66
+ savings: core_1.Flags.string({
67
+ description: 'Expected USD savings (requires --per). An estimate you write as a person is recorded as Human confirmed under your name, and an Agent edit is then refused with a 409; an Agent writes an Agent estimate. Re-sending the same values changes nothing.',
68
+ }),
67
69
  per: core_1.Flags.string({
68
70
  options: ['month', 'year', 'once'],
69
71
  description: 'Savings period (requires --savings)',
70
72
  }),
71
- effort: core_1.Flags.string({ description: 'Expected effort in hours, nonnegative' }),
72
- risk: core_1.Flags.string({ options: ['low', 'medium', 'high'], description: 'Expected risk' }),
73
+ effort: core_1.Flags.string({
74
+ description: 'Expected effort in hours, nonnegative (part of the estimate; see --savings)',
75
+ }),
76
+ risk: core_1.Flags.string({
77
+ options: ['low', 'medium', 'high'],
78
+ description: 'Expected risk (part of the estimate; see --savings)',
79
+ }),
80
+ confidence: core_1.Flags.string({
81
+ options: ['low', 'medium', 'high'],
82
+ description: 'How sure the estimate is (part of the estimate; see --savings). An earlier confidence stays on the claim until you replace it.',
83
+ }),
84
+ rationale: core_1.Flags.string({
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
+ }),
73
87
  estimate: core_1.Flags.integer({
74
88
  description: 'New estimate value from the Space estimate scale. Requires a scale on the Space (or an ' +
75
89
  'ancestor it inherits from); with none set, the server drops the value. Set the scale ' +
@@ -101,6 +115,11 @@ class TasksUpdate extends base_command_1.BaseCommand {
101
115
  'duplicate-of': core_1.Flags.string({
102
116
  description: 'Mark this task as a duplicate of the canonical task (merges collaboration)',
103
117
  }),
118
+ 'review-policy': core_1.Flags.string({
119
+ options: ['none', 'required'],
120
+ description: "Raise or lower the review bar: 'required' means closing this Task needs someone other than the " +
121
+ "Result author to accept it, 'none' (the default) does not. Not a specification change.",
122
+ }),
104
123
  // Goal and space moves live here; status and PROJECT moves live on
105
124
  // `tasks move`. Nothing said so, and these two flags read as the complete
106
125
  // set of "move this task somewhere" options — which is how a reader
@@ -405,6 +424,7 @@ class TasksUpdate extends base_command_1.BaseCommand {
405
424
  driAgentId: flags['dri-agent'],
406
425
  driUserId: flags['dri-user'],
407
426
  executionMode: flags['execution-mode'],
427
+ reviewPolicy: flags['review-policy'],
408
428
  addAssigneeAgentIds: flags['add-assignee-agent'],
409
429
  removeAssigneeAgentIds: flags['remove-assignee-agent'],
410
430
  addAssigneeUserIds: flags['add-assignee-user'],
@@ -24,8 +24,12 @@ class TriggersAudit extends base_command_1.BaseCommand {
24
24
  trigger: core_1.Flags.string({ description: 'Trigger ID filter for owner-wide audit history' }),
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
- outcome: core_1.Flags.string({ description: 'Outcome filter for owner-wide audit history' }),
28
- source: core_1.Flags.string({ description: 'Source filter for owner-wide audit history' }),
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',
29
+ }),
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',
32
+ }),
29
33
  };
30
34
  async run() {
31
35
  this.requireAuth();
@@ -98,7 +98,9 @@ class TriggersCreate extends base_command_1.BaseCommand {
98
98
  'end-at': core_1.Flags.string({
99
99
  description: 'ISO-8601 datetime after which a schedule stops firing',
100
100
  }),
101
- 'stale-catchup-ms': core_1.Flags.integer({ description: 'Schedule stale catch-up window in ms' }),
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).',
103
+ }),
102
104
  at: core_1.Flags.string({
103
105
  description: 'ISO-8601 datetime for once triggers. --next-run-at is also accepted with --kind once for backwards compatibility.',
104
106
  }),
@@ -8,6 +8,7 @@ export default class TriggersFire extends BaseCommand {
8
8
  static flags: {
9
9
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
10
  'from-json': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ strict: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
12
  };
12
13
  run(): Promise<void>;
13
14
  }
@@ -9,6 +9,7 @@ class TriggersFire extends base_command_1.BaseCommand {
9
9
  static examples = [
10
10
  '<%= config.bin %> triggers fire <trigger-id>',
11
11
  '<%= config.bin %> triggers fire <trigger-id> --from-json fire-options.json --json',
12
+ '<%= config.bin %> triggers fire <trigger-id> --strict # exit 1 unless the fire succeeded',
12
13
  ];
13
14
  static args = {
14
15
  id: core_1.Args.string({ description: 'Trigger ID', required: true, ignoreStdin: true }),
@@ -16,7 +17,14 @@ class TriggersFire extends base_command_1.BaseCommand {
16
17
  static flags = {
17
18
  json: core_1.Flags.boolean({ description: 'Output as JSON' }),
18
19
  'from-json': core_1.Flags.string({
19
- description: 'Path to a JSON file (or "-" for stdin) to use as fire options',
20
+ description: 'Path to a JSON file (or "-" for stdin) of fire options. Read: occurrenceId (a key of your own; ' +
21
+ 'firing it again is the same fire) and, for an event trigger only, event ({payload}; the ' +
22
+ 'entity and event type come from the trigger). Any other key is ignored, and the answer names it',
23
+ }),
24
+ strict: core_1.Flags.boolean({
25
+ description: 'Exit 1 unless the fire was accepted (outcome succeeded, in_progress or awaiting_runtime, or a ' +
26
+ 'repeat of one that was). A fire that resolved nothing or was refused (incomplete, skipped, ' +
27
+ 'failed, …) exits 1 with it; without it every outcome exits 0',
20
28
  }),
21
29
  };
22
30
  async run() {
@@ -36,14 +44,21 @@ class TriggersFire extends base_command_1.BaseCommand {
36
44
  catch (err) {
37
45
  this.handleApiError(err);
38
46
  }
47
+ const accepted = (0, triggers_1.fireWasAccepted)(result);
39
48
  if (flags.json) {
40
49
  this.log(JSON.stringify(result, null, 2));
50
+ if (flags.strict && !accepted)
51
+ this.exit(1);
41
52
  return;
42
53
  }
43
54
  this.log(`Fire requested: outcome=${String(result.outcome ?? '-')} reason=${String(result.reason ?? '-')}`);
55
+ for (const line of (0, triggers_1.describeFireDetail)(result))
56
+ this.log(line);
44
57
  const note = (0, triggers_1.describeScheduledFire)(result);
45
58
  if (note)
46
59
  this.log(note);
60
+ if (flags.strict && !accepted)
61
+ this.exit(1);
47
62
  }
48
63
  }
49
64
  exports.default = TriggersFire;
@@ -125,13 +125,14 @@ class TriggersPreflight extends base_command_1.BaseCommand {
125
125
  else if (report.prompt?.note) {
126
126
  this.log(`\nPrompt: ${report.prompt.note}`);
127
127
  }
128
- if (report.schedule?.nextFires?.length) {
129
- this.log(`\nNext fires (${report.schedule.timezone}):`);
130
- for (const at of report.schedule.nextFires)
131
- this.log(` ${at}`);
128
+ const fireLines = (0, triggers_1.nextFireLines)(report.schedule);
129
+ if (fireLines.length) {
130
+ this.log('');
131
+ for (const line of fireLines)
132
+ this.log(line);
132
133
  }
133
134
  if (report.destination) {
134
- this.log(`\nDestination: ${JSON.stringify(report.destination)}`);
135
+ this.log(`\nDestination: ${(0, triggers_1.destinationLine)(report.destination)}`);
135
136
  }
136
137
  // Non-zero when the trigger would not autonomously run, so this is usable
137
138
  // in a script or a pre-deploy check. `2` for indeterminate keeps "blocked"
@@ -46,6 +46,8 @@ class TriggersReplay extends base_command_1.BaseCommand {
46
46
  return;
47
47
  }
48
48
  this.log(`Replay requested: ok=${String(result.ok ?? '-')} outcome=${String(result.outcome ?? '-')} reason=${String(result.reason ?? '-')}`);
49
+ for (const line of (0, triggers_1.describeFireDetail)(result))
50
+ this.log(line);
49
51
  }
50
52
  }
51
53
  exports.default = TriggersReplay;
@@ -55,9 +55,13 @@ class TriggersUpdate extends base_command_1.BaseCommand {
55
55
  'end-at': core_1.Flags.string({
56
56
  description: 'ISO-8601 datetime after which a schedule stops firing',
57
57
  }),
58
- 'stale-catchup-ms': core_1.Flags.integer({ description: 'Schedule stale catch-up window in ms' }),
58
+ 'stale-catchup-ms': core_1.Flags.integer({
59
+ 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).',
60
+ }),
59
61
  at: core_1.Flags.string({ description: 'ISO-8601 datetime for once triggers' }),
60
- entity: core_1.Flags.string({ description: 'Event entity type for event triggers' }),
62
+ entity: core_1.Flags.string({
63
+ description: 'Event entity type for event triggers (create only; refused on update)',
64
+ }),
61
65
  event: core_1.Flags.string({ description: 'Event type for event triggers' }),
62
66
  'filter-mode': core_1.Flags.string({
63
67
  description: 'Event filter mode',
@@ -72,8 +76,12 @@ class TriggersUpdate extends base_command_1.BaseCommand {
72
76
  'max-per-hour': core_1.Flags.integer({ description: 'Event hourly cap' }),
73
77
  probability: core_1.Flags.string({ description: 'Stochastic probability from 0 to 1' }),
74
78
  'jitter-ms': core_1.Flags.integer({ description: 'Stochastic jitter in ms' }),
75
- 'eval-interval-minutes': core_1.Flags.integer({ description: 'Stochastic eval interval in minutes' }),
76
- 'next-run-at': core_1.Flags.string({ description: 'ISO datetime for self_scheduled triggers' }),
79
+ 'eval-interval-minutes': core_1.Flags.integer({
80
+ description: 'Stochastic eval interval in minutes (create only; refused on update)',
81
+ }),
82
+ 'next-run-at': core_1.Flags.string({
83
+ description: 'ISO datetime: alias of --at for once triggers; for self_scheduled triggers it is set at create and refused on update',
84
+ }),
77
85
  'form-title': core_1.Flags.string({ description: 'Form heading for form triggers' }),
78
86
  'form-subtitle': core_1.Flags.string({ description: 'Form subtitle for form triggers' }),
79
87
  'form-fields': core_1.Flags.string({ description: 'Form fields JSON array for form triggers' }),
@@ -11,7 +11,11 @@ class WorkspacesStewardship extends base_command_1.BaseCommand {
11
11
  ];
12
12
  static args = {
13
13
  workspaceId: core_1.Args.string({ required: true, ignoreStdin: true, description: 'Workspace ID' }),
14
- userId: core_1.Args.string({ required: true, ignoreStdin: true, description: 'Member user ID' }),
14
+ userId: core_1.Args.string({
15
+ required: true,
16
+ ignoreStdin: true,
17
+ description: 'Member user ID: 24 hexadecimal characters, not an email (`skrr whoami` prints your own)',
18
+ }),
15
19
  };
16
20
  static flags = {
17
21
  json: core_1.Flags.boolean({ description: 'Output metadata and coverage as JSON' }),
@@ -705,6 +705,15 @@ export declare class AgenticStreamClient {
705
705
  private flushPendingEnvelopes;
706
706
  /** Poll even while a tool is quiet: a pre-join start has no later live event to reveal its gap. */
707
707
  private catchUpEnvelopes;
708
+ /**
709
+ * The answer so far, as a terminal shows it: each widget block as its fallback
710
+ * sentence (see `widgetTerminalText.ts`). `accumulated` stays the raw text the
711
+ * stream delivered, because the reconciliation below compares it with what the
712
+ * server sent; this is what every ANSWER lane (`text.delta`, the printed text,
713
+ * `run.result`) reads. While the run is live a trailing line that could still become
714
+ * a block opener is held back, so nothing printed is ever retracted.
715
+ */
716
+ private answerText;
708
717
  private applySessionOutput;
709
718
  private installHandlers;
710
719
  private handlePermission;
@@ -28,6 +28,7 @@ const node_readline_1 = require("node:readline");
28
28
  const socket_io_client_1 = require("socket.io-client");
29
29
  const data_provider_1 = require("@skrr-ai/data-provider");
30
30
  const config_1 = require("./config");
31
+ const widgetTerminalText_1 = require("./widgetTerminalText");
31
32
  const publicEndpoints_generated_1 = require("./publicEndpoints.generated");
32
33
  const dpop_auth_1 = require("./dpop-auth");
33
34
  /**
@@ -1407,6 +1408,17 @@ class AgenticStreamClient {
1407
1408
  });
1408
1409
  return this.replayFlight;
1409
1410
  }
1411
+ /**
1412
+ * The answer so far, as a terminal shows it: each widget block as its fallback
1413
+ * sentence (see `widgetTerminalText.ts`). `accumulated` stays the raw text the
1414
+ * stream delivered, because the reconciliation below compares it with what the
1415
+ * server sent; this is what every ANSWER lane (`text.delta`, the printed text,
1416
+ * `run.result`) reads. While the run is live a trailing line that could still become
1417
+ * a block opener is held back, so nothing printed is ever retracted.
1418
+ */
1419
+ answerText() {
1420
+ return (0, widgetTerminalText_1.widgetsAsText)(this.accumulated, { final: false });
1421
+ }
1410
1422
  applySessionOutput(event) {
1411
1423
  // The agent's words arrive HERE for agentic runs, inside `envelopes`, and
1412
1424
  // `event.text` is null. Normalising the frame without reading them meant
@@ -1439,7 +1451,7 @@ class AgenticStreamClient {
1439
1451
  const envelopeText = envelopesText(scoped);
1440
1452
  if (envelopeText) {
1441
1453
  this.accumulated += envelopeText;
1442
- this.emit({ ...scoped, type: 'text.delta', text: this.accumulated });
1454
+ this.emit({ ...scoped, type: 'text.delta', text: this.answerText() });
1443
1455
  }
1444
1456
  // A daemon-routed turn carries its tool calls HERE and nowhere else.
1445
1457
  // Projecting them gives both execution paths one vocabulary (OSK-7730).
@@ -1518,7 +1530,7 @@ class AgenticStreamClient {
1518
1530
  this.accumulated += delta;
1519
1531
  if (typeof event.messageId === 'string')
1520
1532
  this.responseMessageId = event.messageId;
1521
- this.emit({ ...event, type: 'text.delta', text: this.accumulated });
1533
+ this.emit({ ...event, type: 'text.delta', text: this.answerText() });
1522
1534
  });
1523
1535
  socket.on('session:stream', (event) => {
1524
1536
  if (!match(event))
@@ -1933,35 +1945,35 @@ class AgenticStreamClient {
1933
1945
  // The banner moved the cursor to a fresh line, so nothing of the answer
1934
1946
  // is on screen after it: the next snapshot must be printed from where the
1935
1947
  // text left off, not from column 0 of a line that no longer holds it.
1936
- this.renderedText = this.accumulated;
1948
+ this.renderedText = this.answerText();
1937
1949
  }
1938
1950
  else if (event.type === 'tool.completed') {
1939
1951
  output.write(`${describeToolEnd(event.toolName, event.status)}\n`);
1940
- this.renderedText = this.accumulated;
1952
+ this.renderedText = this.answerText();
1941
1953
  }
1942
1954
  else if (event.type === 'stream.gap') {
1943
1955
  // Said WHILE READING, which is the only moment it helps: a truncated
1944
1956
  // live answer looks like a complete short answer, and by the terminal
1945
1957
  // event the reader has already believed it (OSK-7631).
1946
1958
  output.write(`\n${String(event.message ?? '')}\n`);
1947
- this.renderedText = this.accumulated;
1959
+ this.renderedText = this.answerText();
1948
1960
  }
1949
1961
  else if (event.type === 'permission.resolved') {
1950
1962
  const verb = event.decision === 'allow' ? 'allowed' : 'denied';
1951
1963
  output.write(`\n[permission] ${String(event.toolName ?? 'tool')} ${verb} by ${String(event.decidedBy ?? '')}\n`);
1952
- this.renderedText = this.accumulated;
1964
+ this.renderedText = this.answerText();
1953
1965
  }
1954
1966
  else if (event.type === 'session.notice') {
1955
1967
  output.write(`\n[session] ${String(event.message ?? '')}\n`);
1956
- this.renderedText = this.accumulated;
1968
+ this.renderedText = this.answerText();
1957
1969
  }
1958
1970
  else if (event.type === 'transport.disconnected') {
1959
1971
  output.write(`\n[reconnecting] ${String(event.reason ?? '')}\n`);
1960
- this.renderedText = this.accumulated;
1972
+ this.renderedText = this.answerText();
1961
1973
  }
1962
1974
  else if (event.type === 'permission.requested') {
1963
1975
  output.write(`\n[${event.type}] ${describePermission(event)}\n`);
1964
- this.renderedText = this.accumulated;
1976
+ this.renderedText = this.answerText();
1965
1977
  }
1966
1978
  else if (event.type === 'permission.cancelled') {
1967
1979
  // A request the run stopped waiting for (OSK-12197). Without this line
@@ -1970,11 +1982,11 @@ class AgenticStreamClient {
1970
1982
  ? event.message
1971
1983
  : `closed (${String(event.reason ?? 'cancelled')})`;
1972
1984
  output.write(`\n[permission] ${String(event.toolName ?? 'tool')}: ${why}\n`);
1973
- this.renderedText = this.accumulated;
1985
+ this.renderedText = this.answerText();
1974
1986
  }
1975
1987
  else if (event.type === 'question.requested') {
1976
1988
  output.write(`\n[${event.type}]\n`);
1977
- this.renderedText = this.accumulated;
1989
+ this.renderedText = this.answerText();
1978
1990
  }
1979
1991
  else if (event.type === 'question.cancelled') {
1980
1992
  // A question the run stopped waiting for (OSK-12208).
@@ -1982,17 +1994,17 @@ class AgenticStreamClient {
1982
1994
  ? event.message
1983
1995
  : `closed (${String(event.reason ?? 'cancelled')})`;
1984
1996
  output.write(`\n[question] ${why}\n`);
1985
- this.renderedText = this.accumulated;
1997
+ this.renderedText = this.answerText();
1986
1998
  }
1987
1999
  else if (event.type === 'permission.approved' && event.auto === true) {
1988
2000
  // Said out loud, because nobody was asked: the flag approved it, and a
1989
2001
  // reader of this log should see which tools that covered (OSK-10323).
1990
2002
  output.write(`\n[permission] ${describePermission(event)} allowed by --approve-tools\n`);
1991
- this.renderedText = this.accumulated;
2003
+ this.renderedText = this.answerText();
1992
2004
  }
1993
2005
  else if (event.type === 'question.answered' && event.nonInteractive) {
1994
2006
  output.write('\n[question] no terminal to answer on, so the question was dismissed unanswered\n');
1995
- this.renderedText = this.accumulated;
2007
+ this.renderedText = this.answerText();
1996
2008
  }
1997
2009
  }
1998
2010
  /**
@@ -2014,7 +2026,7 @@ class AgenticStreamClient {
2014
2026
  'machine is still working on it. Waiting up to ' +
2015
2027
  `${formatWaitDuration(Number(event.waitMs) || 0)} for its reply ` +
2016
2028
  '(Ctrl-C stops waiting; it does not stop your machine).\n');
2017
- this.renderedText = this.accumulated;
2029
+ this.renderedText = this.answerText();
2018
2030
  return true;
2019
2031
  }
2020
2032
  if (event.type === 'run.completed') {
@@ -2063,7 +2075,10 @@ class AgenticStreamClient {
2063
2075
  // no `result` — so `run.result` is filled from the record, or the notice's
2064
2076
  // promise is false exactly when it was made (OSK-12132).
2065
2077
  if (this.lostRanges.length && this.options.reconcileTerminal) {
2066
- const streamedText = this.accumulated;
2078
+ // The record's text is the server's projection (a widget block is its fallback
2079
+ // sentence), so the comparison is made with what the reader was shown, not with
2080
+ // the raw block that the stream carried.
2081
+ const streamedText = (0, widgetTerminalText_1.widgetsAsText)(this.accumulated, { final: true });
2067
2082
  void this.readRecordedText().then((recorded) => {
2068
2083
  this.settleGapVerdict(streamedText, recorded);
2069
2084
  this.settle(status, event, recorded?.text || undefined);
@@ -2134,14 +2149,19 @@ class AgenticStreamClient {
2134
2149
  // The record wins over a stream known to have lost chunks, unless what
2135
2150
  // arrived is already longer (the record lags a completed stream, never the
2136
2151
  // other way round).
2137
- if (recordedText && recordedText.length > this.accumulated.length) {
2152
+ // (Compared as the reader sees it: the record holds a widget as its fallback sentence,
2153
+ // which is shorter than the block the stream carried, and the raw length would never lose.)
2154
+ if (recordedText &&
2155
+ recordedText.length > (0, widgetTerminalText_1.widgetsAsText)(this.accumulated, { final: true }).length) {
2138
2156
  this.accumulated = recordedText;
2139
2157
  }
2140
2158
  // The finished answer, as every other surface shows it: the web applies
2141
2159
  // this same sanitizer, so a scheduling JSON block or leaked function-call
2142
2160
  // XML the model wrote into its reply is removed here too instead of being
2143
2161
  // printed as part of the agent's answer.
2144
- this.accumulated = (0, data_provider_1.sanitizeFinalText)(this.accumulated);
2162
+ // A widget is its fallback sentence in a terminal, first: the sanitizer must read
2163
+ // prose and never a widget's script (the server projects before it sanitizes, too).
2164
+ this.accumulated = (0, data_provider_1.sanitizeFinalText)((0, widgetTerminalText_1.widgetsAsText)(this.accumulated, { final: true }));
2145
2165
  if (!this.options.quiet && !this.options.jsonl && this.accumulated) {
2146
2166
  const output = this.options.output ?? process.stdout;
2147
2167
  const { append, shown } = renderableDelta(this.renderedText, this.accumulated);
@@ -0,0 +1,8 @@
1
+ import type { EventWakeCapabilities } from './commitments';
2
+ /**
3
+ * The "Event wakes:" block, one renderer for `trigger-status` and `wake-capabilities`. The second
4
+ * used to word its own conclusion ("configured sources may wake the Agent", a column marked
5
+ * ACTIVE) and contradicted the first for the same Commitment (OSK-15428, OSK-15419); printing the
6
+ * same facts in the same words is the only way the two cannot disagree.
7
+ */
8
+ export declare function eventWakeLines(caps: EventWakeCapabilities): string[];