pi-usereq 0.87.0 → 0.89.0

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.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # PI-useReq/pi-usereq (0.87.0)
1
+ # PI-useReq/pi-usereq (0.89.0)
2
2
 
3
3
  <p align="center">
4
4
  <img src="https://img.shields.io/badge/python-3.11%2B-3776AB?style=flat-square&logo=python&logoColor=white" alt="Python 3.11+">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-usereq",
3
- "version": "0.87.0",
3
+ "version": "0.89.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Ogekuri/PI-useReq.git"
@@ -126,6 +126,20 @@ export function buildCommandReportErrorEntryData(
126
126
  };
127
127
  }
128
128
 
129
+ /**
130
+ * @brief Serializes one durable command report entry into its complete plain-text form.
131
+ * @details Joins the `pi-usereq <command>: execution report` header with every per-operation outcome line using newline separators so notification `%%OUTPUT%%` substitution carries exactly the report content rendered in the transcript. Runtime is O(n) in aggregate report-line length. No external state is mutated.
132
+ * @param[in] data {CommandReportEntryData} Report entry payload to serialize.
133
+ * @return {string} Complete execution-report text starting with the report header.
134
+ * @satisfies REQ-436, REQ-448
135
+ */
136
+ export function buildCommandReportEntryText(data: CommandReportEntryData): string {
137
+ return [
138
+ `pi-usereq ${data.command}: execution report`,
139
+ ...data.lines,
140
+ ].join("\n");
141
+ }
142
+
129
143
  /**
130
144
  * @brief Appends one durable command report entry to the active session when the host supports custom entries.
131
145
  * @details Probes the optional `pi.appendEntry(...)` surface before use so legacy hosts and offline harnesses without custom-entry support skip persistence silently; supported hosts persist the payload as a `custom` session entry that survives session restore while remaining excluded from LLM context. Runtime is O(1) plus delegated session-entry persistence. Side effects include session-file entry persistence on supported hosts.
@@ -80,10 +80,10 @@ export const DEFAULT_PI_NOTIFY_PUSHOVER_TITLE = "%%PROMT%% @ %%BASE%% [%%TIME%%]
80
80
 
81
81
  /**
82
82
  * @brief Defines the default Pushover text template.
83
- * @details Prefixes outbound Pushover messages with the terminal outcome token and preserves the raw prompt arguments on the following line so notifications remain traceable to the invoked prompt command. Access complexity is O(1).
84
- * @satisfies REQ-185
83
+ * @details Delivers the final LLM agent output as the outbound Pushover message body so completed prompt runs push the last assistant message instead of the invoked command arguments; `buildPiNotifyPushoverBody` falls back to the terminal outcome token when the substituted body resolves empty. Access complexity is O(1).
84
+ * @satisfies REQ-185, REQ-450
85
85
  */
86
- export const DEFAULT_PI_NOTIFY_PUSHOVER_TEXT = "%%RESULT%%\n%%ARGS%%";
86
+ export const DEFAULT_PI_NOTIFY_PUSHOVER_TEXT = "%%OUTPUT%%";
87
87
 
88
88
  /**
89
89
  * @brief Defines the Pushover Message API `message` field limit in characters.
@@ -801,21 +801,23 @@ function truncatePiNotifyPushoverBody(body: string): string {
801
801
 
802
802
  /**
803
803
  * @brief Builds the Pushover message body for one prompt-end request.
804
- * @details Resolves the configured `notify-pushover-text` template with raw runtime placeholder substitution so the pushed text remains configurable and deterministic, then head-truncates over-limit bodies to the Pushover Message API `message` limit. Runtime is O(n) in template length. No external state is mutated.
804
+ * @details Resolves the configured `notify-pushover-text` template with raw runtime placeholder substitution, falls back to the terminal outcome token when the fully substituted body resolves empty so Pushover delivery never targets an empty `message` field, then head-truncates over-limit bodies to the Pushover Message API `message` limit. Runtime is O(n) in template length. No external state is mutated.
805
805
  * @param[in] config {PiNotifyConfigFields} Effective notification configuration.
806
806
  * @param[in] outcome {PiNotifyOutcome} Classified prompt-end outcome.
807
807
  * @param[in] request {PiNotifyEventRequest} Prompt-end request metadata.
808
808
  * @return {string} Pushover message body within the 1024-character API limit.
809
- * @satisfies REQ-185, REQ-186, REQ-187, REQ-199, REQ-443, REQ-444, REQ-445
809
+ * @satisfies REQ-185, REQ-186, REQ-187, REQ-199, REQ-443, REQ-444, REQ-445, REQ-450
810
810
  */
811
811
  function buildPiNotifyPushoverBody(
812
812
  config: PiNotifyConfigFields,
813
813
  outcome: PiNotifyOutcome,
814
814
  request: PiNotifyEventRequest,
815
815
  ): string {
816
- return truncatePiNotifyPushoverBody(
817
- substitutePiNotifyTextTemplate(config["notify-pushover-text"], request, outcome),
818
- );
816
+ const substitutedBody = substitutePiNotifyTextTemplate(config["notify-pushover-text"], request, outcome);
817
+ const resolvedBody = substitutedBody.trim().length > 0
818
+ ? substitutedBody
819
+ : formatPiNotifyResult(outcome);
820
+ return truncatePiNotifyPushoverBody(resolvedBody);
819
821
  }
820
822
 
821
823
  /**
@@ -893,7 +895,7 @@ export function setPiNotifySpawnForTests(spawnImpl: PiNotifySpawn | undefined):
893
895
 
894
896
  /**
895
897
  * @brief Dispatches prompt-end notify, sound, and Pushover effects for one agent-end payload.
896
- * @details Classifies the terminal outcome, executes `PI_NOTIFY_CMD` when command-notify prerequisites are satisfied, executes the configured sound command when sound prerequisites are satisfied, and dispatches the native Pushover request when Pushover prerequisites are satisfied; `%%OUTPUT%%` resolves from the caller-supplied final agent output and Pushover bodies are head-truncated to the provider message limit. Runtime is O(m + c + b) in message count, command length, and Pushover payload size. Side effects include child-process spawning and outbound HTTPS requests.
898
+ * @details Classifies the terminal outcome from the `agent_end` payload and delegates to `runPiNotifyEffectsForOutcome(...)`; `%%OUTPUT%%` resolves from the caller-supplied final agent output and Pushover bodies are head-truncated to the provider message limit. Runtime is O(m + c + b) in message count, command length, and Pushover payload size. Side effects include child-process spawning and outbound HTTPS requests.
897
899
  * @param[in] config {PiNotifyConfigFields} Effective notification configuration.
898
900
  * @param[in] event {Pick<AgentEndEvent, "messages">} Agent-end payload subset.
899
901
  * @param[in] request {PiNotifyEventRequest | undefined} Optional prompt-end request metadata used for command-notify and Pushover substitution.
@@ -905,7 +907,23 @@ export function runPiNotifyEffects(
905
907
  event: Pick<AgentEndEvent, "messages">,
906
908
  request?: PiNotifyEventRequest,
907
909
  ): void {
908
- const outcome = classifyPiNotifyOutcome(event);
910
+ runPiNotifyEffectsForOutcome(config, classifyPiNotifyOutcome(event), request);
911
+ }
912
+
913
+ /**
914
+ * @brief Dispatches prompt-end notify, sound, and Pushover effects for one explicit prompt-end outcome.
915
+ * @details Executes `PI_NOTIFY_CMD` when command-notify prerequisites are satisfied, executes the configured sound command when sound prerequisites are satisfied, and dispatches the native Pushover request when Pushover prerequisites are satisfied; `%%OUTPUT%%` resolves from the caller-supplied final agent output or command process output, and Pushover bodies head-truncate to the provider message limit with an outcome-token fallback for empty bodies. Agentic callers classify the outcome from the `agent_end` payload through `runPiNotifyEffects(...)`; non-agentic `req-references` and `req-reset` command callers pass the explicit completed or failed outcome per REQ-447. Runtime is O(c + b) in command length and Pushover payload size. Side effects include child-process spawning and outbound HTTPS requests.
916
+ * @param[in] config {PiNotifyConfigFields} Effective notification configuration.
917
+ * @param[in] outcome {PiNotifyOutcome} Explicit prompt-end outcome.
918
+ * @param[in] request {PiNotifyEventRequest | undefined} Optional prompt-end request metadata used for command-notify and Pushover substitution.
919
+ * @return {void} No return value.
920
+ * @satisfies REQ-131, REQ-132, REQ-133, REQ-166, REQ-167, REQ-168, REQ-169, REQ-172, REQ-176, REQ-178, REQ-184, REQ-185, REQ-186, REQ-187, REQ-199, REQ-443, REQ-444, REQ-445, REQ-447, REQ-450
921
+ */
922
+ export function runPiNotifyEffectsForOutcome(
923
+ config: PiNotifyConfigFields,
924
+ outcome: PiNotifyOutcome,
925
+ request?: PiNotifyEventRequest,
926
+ ): void {
909
927
  if (shouldRunPiNotifyCommand(config, outcome, request)) {
910
928
  runPiNotifyCommand(config, outcome, request as PiNotifyEventRequest);
911
929
  }
@@ -59,6 +59,29 @@ export interface ReqResetCommandExecutionResult {
59
59
  errorMessage?: string;
60
60
  }
61
61
 
62
+ /**
63
+ * @brief Builds the per-operation outcome lines of one `req-reset` run for `%%OUTPUT%%` notification substitution.
64
+ * @details Emits one machine-readable line per recovery or cleanup fact — terminal outcome, execution-transcript preservation, `base-path` restoration, removed generated worktree count, removed generated branch count — and appends the surfaced error diagnostic for failed runs so prompt-end notification effects carry exactly the output produced during the process. Runtime is O(1). No external state is mutated.
65
+ * @param[in] executionResult {ReqResetCommandExecutionResult} Recovery and cleanup outcome facts of the attempted run.
66
+ * @return {string[]} Ordered outcome lines starting with the terminal outcome.
67
+ * @satisfies REQ-449
68
+ */
69
+ export function buildReqResetCommandOutcomeLines(
70
+ executionResult: ReqResetCommandExecutionResult,
71
+ ): string[] {
72
+ const lines = [
73
+ `outcome: ${executionResult.errorMessage ? "error" : "success"}`,
74
+ `transcript preserved: ${executionResult.transcriptPreserved ? "yes" : "no"}`,
75
+ `base-path restored: ${executionResult.restoredBasePath ? "yes" : "no"}`,
76
+ `worktrees removed: ${executionResult.removedWorktreeDirs.length}`,
77
+ `branches removed: ${executionResult.removedBranchNames.length}`,
78
+ ];
79
+ if (executionResult.errorMessage) {
80
+ lines.push(`error: ${executionResult.errorMessage}`);
81
+ }
82
+ return lines;
83
+ }
84
+
62
85
  /**
63
86
  * @brief Describes the session-bound context surface reused during `req-reset` recovery.
64
87
  * @details Reuses the session-switching contract already accepted by `restorePromptCommandExecution(...)` so the dedicated reset command can restore the original session without depending on concrete pi runtime classes. The alias is compile-time only and introduces no runtime cost.
package/src/index.ts CHANGED
@@ -61,7 +61,9 @@ import {
61
61
  normalizePiNotifyTemplateValue,
62
62
  parsePiNotifyControlSequenceText,
63
63
  runPiNotifyEffects,
64
+ runPiNotifyEffectsForOutcome,
64
65
  type PiNotifyEventRequest,
66
+ type PiNotifyOutcome,
65
67
  type PiNotifyPushoverPriority,
66
68
  type PiNotifySoundLevel,
67
69
  } from "./core/pi-notify.js";
@@ -118,6 +120,7 @@ import {
118
120
  } from "./core/req-references-command.js";
119
121
  import {
120
122
  REQ_RESET_COMMAND_DESCRIPTION,
123
+ buildReqResetCommandOutcomeLines,
121
124
  executeReqResetCommandExecution,
122
125
  prepareReqResetCommandExecution,
123
126
  type ReqResetCommandExecutionResult,
@@ -176,6 +179,7 @@ import {
176
179
  import { ensureBundledResourcesAccessible, readBundledPromptDescription } from "./core/resources.js";
177
180
  import {
178
181
  appendCommandReportEntry,
182
+ buildCommandReportEntryText,
179
183
  buildCommandReportErrorEntryData,
180
184
  buildReqReferencesCommandReportEntryData,
181
185
  registerCommandReportEntryRenderer,
@@ -1239,6 +1243,32 @@ function notifyContextSafely(
1239
1243
  }
1240
1244
  }
1241
1245
 
1246
+ /**
1247
+ * @brief Dispatches prompt-end notification effects for one non-agentic command outcome.
1248
+ * @details Builds the effective notification configuration subset with the active runtime sound level and forwards the explicit completed or failed outcome plus the command-produced process output into `runPiNotifyEffectsForOutcome(...)`, so `req-references` and `req-reset` completions feed the same command-notify, sound, and Pushover gates as `agent_end` runs. Runtime is O(1) plus delegated effect cost. Side effects include optional child-process spawning and outbound HTTPS requests.
1249
+ * @param[in] statusController {PiUsereqStatusController} Mutable status controller supplying the active runtime sound level.
1250
+ * @param[in] config {UseReqConfig} Effective project configuration.
1251
+ * @param[in] outcome {PiNotifyOutcome} Explicit terminal command outcome.
1252
+ * @param[in] request {PiNotifyEventRequest} Prompt-end request metadata carrying the command process output.
1253
+ * @return {void} No return value.
1254
+ * @satisfies REQ-447, REQ-448, REQ-449
1255
+ */
1256
+ function dispatchNonAgenticCommandNotifyEffects(
1257
+ statusController: PiUsereqStatusController,
1258
+ config: UseReqConfig,
1259
+ outcome: PiNotifyOutcome,
1260
+ request: PiNotifyEventRequest,
1261
+ ): void {
1262
+ runPiNotifyEffectsForOutcome(
1263
+ {
1264
+ ...config,
1265
+ "notify-sound": getPiUsereqRuntimeSoundLevel(statusController),
1266
+ },
1267
+ outcome,
1268
+ request,
1269
+ );
1270
+ }
1271
+
1242
1272
  /**
1243
1273
  * @brief Emits the final context-retention reminder info notification for a successfully completed `/req-*` orchestration.
1244
1274
  * @details Builds one message stating that the session context content was retained, recommending a clean-context session start before the next `/req-*` command, and appending the current context-usage percentage when the controller holds a normalized snapshot. Delivers exclusively through `notifyContextSafely(...)`, so stale replacement-session contexts are suppressed, and performs no session message send and no session switch. Runtime is O(1). Side effect is user notification delivery only when the supplied context is still active.
@@ -3459,11 +3489,11 @@ function resolveReqResetPromptRequest(
3459
3489
 
3460
3490
  /**
3461
3491
  * @brief Registers the specialized `req-reset` slash command.
3462
- * @details Registers the non-agentic prompt-recovery command that accepts any current workflow state, reuses persisted prompt runtime state when available, restores the original session-backed `base-path`, force-removes matching generated worktrees plus branches, clears recoverable prompt state when restoration succeeds, and notifies pi without starting an LLM session or creating a worktree. Runtime is dominated by session restoration plus git cleanup. Side effects include command registration, status-controller mutation, active-session replacement, worktree deletion, branch deletion, and user notifications.
3492
+ * @details Registers the non-agentic prompt-recovery command that accepts any current workflow state, reuses persisted prompt runtime state when available, restores the original session-backed `base-path`, force-removes matching generated worktrees plus branches, clears recoverable prompt state when restoration succeeds, notifies pi without starting an LLM session or creating a worktree, and dispatches prompt-end notification effects carrying the command process output as `%%OUTPUT%%`. Runtime is dominated by session restoration plus git cleanup. Side effects include command registration, status-controller mutation, active-session replacement, worktree deletion, branch deletion, user notifications, and optional prompt-end notify, sound, and Pushover dispatch.
3463
3493
  * @param[in] pi {ExtensionAPI} Active extension API instance.
3464
3494
  * @param[in,out] statusController {PiUsereqStatusController} Mutable status controller.
3465
3495
  * @return {void} No return value.
3466
- * @satisfies REQ-304, REQ-305, REQ-306, REQ-307, REQ-308, REQ-309, REQ-310, REQ-311, REQ-312, REQ-313, REQ-441
3496
+ * @satisfies REQ-304, REQ-305, REQ-306, REQ-307, REQ-308, REQ-309, REQ-310, REQ-311, REQ-312, REQ-313, REQ-441, REQ-447, REQ-449
3467
3497
  */
3468
3498
  function registerReqResetCommand(
3469
3499
  pi: ExtensionAPI,
@@ -3471,7 +3501,8 @@ function registerReqResetCommand(
3471
3501
  ): void {
3472
3502
  pi.registerCommand("req-reset", {
3473
3503
  description: REQ_RESET_COMMAND_DESCRIPTION,
3474
- handler: async (_args, ctx) => {
3504
+ handler: async (args, ctx) => {
3505
+ const commandStartMs = Date.now();
3475
3506
  const promptRequest = resolveReqResetPromptRequest(statusController);
3476
3507
  const resetModelSelection = promptRequest?.originalModel
3477
3508
  ?? resolveCurrentModelSelection((ctx as unknown as PromptModelSelectionContextSurface).model);
@@ -3505,6 +3536,13 @@ function registerReqResetCommand(
3505
3536
  const message = error instanceof Error ? error.message : String(error);
3506
3537
  setPiUsereqWorkflowState(statusController, "error", resetContext);
3507
3538
  notifyContextSafely(resetContext, message, "error");
3539
+ dispatchNonAgenticCommandNotifyEffects(statusController, config, "failed", {
3540
+ promptName: "req-reset",
3541
+ promptArgs: args,
3542
+ basePath: projectBase,
3543
+ completionTimeMs: Math.max(0, Date.now() - commandStartMs),
3544
+ agentOutput: message,
3545
+ });
3508
3546
  throw error;
3509
3547
  }
3510
3548
 
@@ -3519,6 +3557,13 @@ function registerReqResetCommand(
3519
3557
  if (executionResult.errorMessage) {
3520
3558
  setPiUsereqWorkflowState(statusController, "error", resetContext);
3521
3559
  notifyContextSafely(resetContext, executionResult.errorMessage, "error");
3560
+ dispatchNonAgenticCommandNotifyEffects(statusController, config, "failed", {
3561
+ promptName: "req-reset",
3562
+ promptArgs: args,
3563
+ basePath: projectBase,
3564
+ completionTimeMs: Math.max(0, Date.now() - commandStartMs),
3565
+ agentOutput: buildReqResetCommandOutcomeLines(executionResult).join("\n"),
3566
+ });
3522
3567
  throw new ReqError(executionResult.errorMessage, 1);
3523
3568
  }
3524
3569
 
@@ -3527,6 +3572,13 @@ function registerReqResetCommand(
3527
3572
  ? `SUCCESS: req-reset restored base-path and removed ${executionResult.removedWorktreeDirs.length} worktree(s) plus ${executionResult.removedBranchNames.length} branch(es).`
3528
3573
  : `SUCCESS: req-reset removed ${executionResult.removedWorktreeDirs.length} worktree(s) plus ${executionResult.removedBranchNames.length} branch(es) and restored idle state.`;
3529
3574
  notifyContextSafely(resetContext, successMessage, "info");
3575
+ dispatchNonAgenticCommandNotifyEffects(statusController, config, "completed", {
3576
+ promptName: "req-reset",
3577
+ promptArgs: args,
3578
+ basePath: projectBase,
3579
+ completionTimeMs: Math.max(0, Date.now() - commandStartMs),
3580
+ agentOutput: buildReqResetCommandOutcomeLines(executionResult).join("\n"),
3581
+ });
3530
3582
  notifyContextRetentionReminder(statusController, resetContext);
3531
3583
  },
3532
3584
  });
@@ -3534,11 +3586,11 @@ function registerReqResetCommand(
3534
3586
 
3535
3587
  /**
3536
3588
  * @brief Registers the specialized `req-references` slash command.
3537
- * @details Registers the non-agentic references-maintenance command that rejects non-`idle` invocations by transitioning workflow state to `error` before direct execution, otherwise reuses slash-command-owned git validation, transitions workflow state through `checking|running|idle`, regenerates `REFERENCES.md` directly from configured source directories, stages only the generated file, creates the fixed-message git commit, verifies repository cleanliness, appends one durable `pi-usereq.command-report` session entry recording the executed operations with their outcomes so the report renders in the transcript and survives session restore, and emits execution notifications that conform to the operations actually performed — one stating whether the references file was updated or already matched the generated content and one stating whether the fixed-message commit was created or skipped — regardless of the update and commit outcomes, without starting an LLM session or creating a worktree. Runtime is dominated by git subprocess execution plus source-summary generation. Side effects include command registration, status-controller mutation, filesystem writes, git index/history mutation, session-entry persistence, and user notifications.
3589
+ * @details Registers the non-agentic references-maintenance command that rejects non-`idle` invocations by transitioning workflow state to `error` before direct execution, otherwise reuses slash-command-owned git validation, transitions workflow state through `checking|running|idle`, regenerates `REFERENCES.md` directly from configured source directories, stages only the generated file, creates the fixed-message git commit, verifies repository cleanliness, appends one durable `pi-usereq.command-report` session entry recording the executed operations with their outcomes so the report renders in the transcript and survives session restore, emits execution notifications that conform to the operations actually performed — one stating whether the references file was updated or already matched the generated content and one stating whether the fixed-message commit was created or skipped — regardless of the update and commit outcomes, dispatches prompt-end notification effects carrying the complete execution-report text (header plus per-operation outcome lines) as `%%OUTPUT%%` for completed and failed runs, all without starting an LLM session or creating a worktree. Runtime is dominated by git subprocess execution plus source-summary generation. Side effects include command registration, status-controller mutation, filesystem writes, git index/history mutation, session-entry persistence, user notifications, and optional prompt-end notify, sound, and Pushover dispatch.
3538
3590
  * @param[in] pi {ExtensionAPI} Active extension API instance.
3539
3591
  * @param[in,out] statusController {PiUsereqStatusController} Mutable status controller.
3540
3592
  * @return {void} No return value.
3541
- * @satisfies REQ-200, REQ-221, REQ-224, REQ-298, REQ-299, REQ-300, REQ-301, REQ-302, REQ-303, REQ-436, REQ-437, REQ-438, REQ-441
3593
+ * @satisfies REQ-200, REQ-221, REQ-224, REQ-298, REQ-299, REQ-300, REQ-301, REQ-302, REQ-303, REQ-436, REQ-437, REQ-438, REQ-441, REQ-447, REQ-448
3542
3594
  */
3543
3595
  function registerReqReferencesCommand(
3544
3596
  pi: ExtensionAPI,
@@ -3546,7 +3598,8 @@ function registerReqReferencesCommand(
3546
3598
  ): void {
3547
3599
  pi.registerCommand("req-references", {
3548
3600
  description: REQ_REFERENCES_COMMAND_DESCRIPTION,
3549
- handler: async (_args, ctx) => {
3601
+ handler: async (args, ctx) => {
3602
+ const commandStartMs = Date.now();
3550
3603
  if (statusController.state.workflowState !== "idle") {
3551
3604
  rejectNonIdleReqCommand(statusController, ctx);
3552
3605
  }
@@ -3589,6 +3642,13 @@ function registerReqReferencesCommand(
3589
3642
  : `SUCCESS: req-references completed with a clean repository (${executionResult.referencesChanged ? "references updated" : "references unchanged"}; ${executionResult.commitCreated ? "commit created" : "commit skipped"}).`,
3590
3643
  "info",
3591
3644
  );
3645
+ dispatchNonAgenticCommandNotifyEffects(statusController, config, "completed", {
3646
+ promptName: "req-references",
3647
+ promptArgs: args,
3648
+ basePath: projectBase,
3649
+ completionTimeMs: Math.max(0, Date.now() - commandStartMs),
3650
+ agentOutput: buildCommandReportEntryText(buildReqReferencesCommandReportEntryData(executionResult)),
3651
+ });
3592
3652
  notifyContextRetentionReminder(statusController, ctx);
3593
3653
  } catch (error) {
3594
3654
  statusController.state.pendingPromptRequest = undefined;
@@ -3597,6 +3657,13 @@ function registerReqReferencesCommand(
3597
3657
  const message = error instanceof Error ? error.message : String(error);
3598
3658
  appendCommandReportEntry(pi, buildCommandReportErrorEntryData("req-references", message));
3599
3659
  notifyContextSafely(ctx, message, "error");
3660
+ dispatchNonAgenticCommandNotifyEffects(statusController, config, "failed", {
3661
+ promptName: "req-references",
3662
+ promptArgs: args,
3663
+ basePath: projectBase,
3664
+ completionTimeMs: Math.max(0, Date.now() - commandStartMs),
3665
+ agentOutput: buildCommandReportEntryText(buildCommandReportErrorEntryData("req-references", message)),
3666
+ });
3600
3667
  throw error;
3601
3668
  }
3602
3669
  },