pi-usereq 0.69.0 → 0.71.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.69.0)
1
+ # PI-useReq/pi-usereq (0.71.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+">
@@ -290,7 +290,7 @@ The interactive configuration menu exposes every user-facing setting; changes ar
290
290
  - **Language static code checkers** — per-language `enable`/`disable` flags and the global `Command`-module checker definitions (view/remove/reset with confirmation).
291
291
  - **Enable tools** — the subset of configurable startup tools activated for the project: the `files-*` and project tools plus the embedded pi tools (`read`, `bash`, `edit`, `write` enabled by default; `find`, `grep`, `ls` configurable and disabled by default).
292
292
  - **Notifications** — command-notify, sound, and Pushover settings with per-event routing (completed/interrupted/failed).
293
- - **Debug** — local debug logging: log file, log-on-status filter, status-change/workflow-event toggles, enabled tools/prompts, and `Enable debug commands for tools`.
293
+ - **Debug** — local debug logging: global enablement, prompt-content logging (`Enable debug prompts` plus `Log path for prompts`), log file, log-on-status filter, status-change/workflow-event toggles, enabled tools/prompts, and `Enable debug commands for tools`.
294
294
  - **Show local/global configuration** — write the exact config file contents into the editor.
295
295
  - **Reset defaults** — restore the default configuration with a confirmation preview.
296
296
  - **Models** (not a setting) — the menu exposes no model management: models, custom providers, and authentication are configured at the pi client level and simply shared with pi-usereq commands at runtime.
@@ -320,6 +320,20 @@ The extension renders a status field in the pi status line showing: extension id
320
320
  - Config-gated slash commands that run the project tools and write the output into the editor: `debug-compress`, `debug-references`, `debug-static-check`, `debug-summarize`, `debug-tokens`.
321
321
  - Standalone debug harness: `scripts/pi-usereq-debug.sh` (bash wrapper) and `scripts/debug-extension.ts` with subcommands `inspect`, `session-start`, `command`, `tool`, and `sdk-smoke`.
322
322
  - Debug logging writes to the configured `DEBUG_LOG_FILE`, filtered by prompt/tool name and workflow status.
323
+ - **Prompt content logging** — when both `Debug` and `Enable debug prompts` are enabled (the `Debug > Enable debug prompts` menu entry), the exact rendered prompt delivered to the LLM agent through `sendMessage`/`sendUserMessage` is saved under `Log path for prompts` (`DEBUG_PROMPTS_LOG_PATH`, default `/tmp/PI-useReq`). Each run writes one file named `<timestamp>-<command>` (a `YYYYMMDDHHMMSSmmm` timestamp plus the `/req-*` command used, e.g. `20261009072235123-req-implement`) whose content is byte-identical to what reached the model. Prompt logging is subordinate to the global `Debug` flag and to the `Log on status` workflow filter; nothing is written while `Debug` is disabled. Relative log paths resolve against the project root, and trailing slashes are stripped from the configured path.
324
+
325
+ Because the saved file contains exactly what pi-usereq sent, you can replicate the same send from the `pi` CLI, outside pi-usereq and without the extension installed:
326
+
327
+ ```bash
328
+ # Replay the exact saved prompt as a one-shot task argument
329
+ pi -p "$(cat /tmp/PI-useReq/20261009072235123-req-implement)"
330
+
331
+ # Feed extra material on stdin while replaying an analysis request
332
+ cat errors.log | pi -p "Analyze these errors and suggest how to fix them"
333
+
334
+ # Reuse a saved prompt as coding-style guidance through an appended system prompt
335
+ pi -p "Rewrite this function" --append-system-prompt /tmp/PI-useReq/20261009072235123-req-implement
336
+ ```
323
337
 
324
338
 
325
339
  ## Note on Git usage
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-usereq",
3
- "version": "0.69.0",
3
+ "version": "0.71.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Ogekuri/PI-useReq.git"
@@ -35,6 +35,8 @@ import {
35
35
  DEFAULT_DEBUG_ENABLED,
36
36
  DEFAULT_DEBUG_LOG_FILE,
37
37
  DEFAULT_DEBUG_LOG_ON_STATUS,
38
+ DEFAULT_DEBUG_PROMPTS_ENABLED,
39
+ DEFAULT_DEBUG_PROMPTS_LOG_PATH,
38
40
  DEFAULT_DEBUG_STATUS_CHANGES,
39
41
  DEFAULT_DEBUG_TOOL_COMMANDS_ENABLED,
40
42
  DEFAULT_DEBUG_WORKFLOW_EVENTS,
@@ -43,9 +45,12 @@ import {
43
45
  normalizeDebugEnabledTools,
44
46
  normalizeDebugLogFile,
45
47
  normalizeDebugLogOnStatus,
48
+ normalizeDebugPromptsEnabled,
49
+ normalizeDebugPromptsLogPath,
46
50
  normalizeDebugStatusChanges,
47
51
  normalizeDebugToolCommandsEnabled,
48
52
  normalizeDebugWorkflowEvents,
53
+ type DebugPromptsEnabled,
49
54
  type DebugToolCommandsEnabled,
50
55
  } from "./debug-runtime.js";
51
56
  import { normalizeEnabledPiUsereqTools } from "./pi-usereq-tools.js";
@@ -94,6 +99,8 @@ export interface UseReqConfig {
94
99
  GIT_WORKTREE_PREFIX: string;
95
100
  DEBUG_ENABLED: "enable" | "disable";
96
101
  DEBUG_LOG_FILE: string;
102
+ DEBUG_PROMPTS_ENABLED: DebugPromptsEnabled;
103
+ DEBUG_PROMPTS_LOG_PATH: string;
97
104
  DEBUG_STATUS_CHANGES: "enable" | "disable";
98
105
  DEBUG_WORKFLOW_EVENTS: "enable" | "disable";
99
106
  DEBUG_TOOL_COMMANDS_ENABLED: DebugToolCommandsEnabled;
@@ -154,6 +161,8 @@ interface UseReqLocalConfig {
154
161
  "static-check": Record<string, LocalStaticCheckLanguageConfig>;
155
162
  DEBUG_ENABLED: "enable" | "disable";
156
163
  DEBUG_LOG_FILE: string;
164
+ DEBUG_PROMPTS_ENABLED: DebugPromptsEnabled;
165
+ DEBUG_PROMPTS_LOG_PATH: string;
157
166
  DEBUG_STATUS_CHANGES: "enable" | "disable";
158
167
  DEBUG_WORKFLOW_EVENTS: "enable" | "disable";
159
168
  DEBUG_TOOL_COMMANDS_ENABLED: DebugToolCommandsEnabled;
@@ -214,14 +223,14 @@ export const DEFAULT_TESTS_DIR = "tests";
214
223
  export const DEFAULT_SRC_DIRS = ["src"];
215
224
  /**
216
225
  * @brief Defines the default value for every persisted context-file injection flag.
217
- * @details Each `%%CONTEXT_FILES%%` injection toggle defaults to disabled so the bundled canonical documents are excluded from the prompt context unless the user explicitly enables one. Lookup complexity is O(1).
226
+ * @details Each `%%CONTEXT_FILES%%` injection toggle defaults to enabled so the bundled canonical documents enter the prompt context on new projects unless the user explicitly disables one. Lookup complexity is O(1).
218
227
  * @satisfies REQ-328
219
228
  */
220
- export const DEFAULT_CONTEXT_FILES_FLAG = false;
229
+ export const DEFAULT_CONTEXT_FILES_FLAG = true;
221
230
 
222
231
  /**
223
232
  * @brief Normalizes one persisted context-file injection flag.
224
- * @details Returns the documented default (`false`) for missing or non-boolean values and preserves only explicit boolean input, so any malformed persisted entry keeps context-file injection disabled. Runtime is O(1). No external state is mutated.
233
+ * @details Returns the documented default (`true`) for missing or non-boolean values and preserves only explicit boolean input, so any malformed persisted entry keeps context-file injection enabled. Runtime is O(1). No external state is mutated.
225
234
  * @param[in] value {unknown} Candidate persisted context-file flag.
226
235
  * @return {boolean} Normalized context-file injection flag.
227
236
  * @satisfies REQ-328
@@ -578,7 +587,7 @@ export function getGlobalConfigPath(): string {
578
587
  * @details Populates canonical docs/test/source directories, derives local static-check enable defaults from the supplied global checker definitions, and seeds documented debug defaults including tool-wrapper command registration without any cross-project fields. Runtime is O(l). No filesystem side effects occur.
579
588
  * @param[in] globalStaticCheckConfig {Record<string, GlobalStaticCheckLanguageConfig>} Global checker definitions used to derive local enable defaults.
580
589
  * @return {UseReqLocalConfig} Fresh default local configuration object.
581
- * @satisfies CTN-019, REQ-328
590
+ * @satisfies CTN-019, REQ-328, REQ-413, REQ-414
582
591
  */
583
592
  function getDefaultLocalConfig(
584
593
  globalStaticCheckConfig: Record<string, GlobalStaticCheckLanguageConfig>,
@@ -593,6 +602,8 @@ function getDefaultLocalConfig(
593
602
  "static-check": getDefaultLocalStaticCheckConfig(globalStaticCheckConfig),
594
603
  DEBUG_ENABLED: DEFAULT_DEBUG_ENABLED,
595
604
  DEBUG_LOG_FILE: DEFAULT_DEBUG_LOG_FILE,
605
+ DEBUG_PROMPTS_ENABLED: DEFAULT_DEBUG_PROMPTS_ENABLED,
606
+ DEBUG_PROMPTS_LOG_PATH: DEFAULT_DEBUG_PROMPTS_LOG_PATH,
596
607
  DEBUG_STATUS_CHANGES: DEFAULT_DEBUG_STATUS_CHANGES,
597
608
  DEBUG_WORKFLOW_EVENTS: DEFAULT_DEBUG_WORKFLOW_EVENTS,
598
609
  DEBUG_TOOL_COMMANDS_ENABLED: DEFAULT_DEBUG_TOOL_COMMANDS_ENABLED,
@@ -645,7 +656,7 @@ function getDefaultGlobalConfig(): UseReqGlobalConfig {
645
656
  * @param[in] localConfig {UseReqLocalConfig} Persisted local configuration.
646
657
  * @param[in] globalConfig {UseReqGlobalConfig} Persisted global configuration.
647
658
  * @return {UseReqConfig} Effective merged configuration.
648
- * @satisfies REQ-328
659
+ * @satisfies REQ-328, REQ-413, REQ-414
649
660
  */
650
661
  function mergeConfigScopes(
651
662
  localConfig: UseReqLocalConfig,
@@ -682,6 +693,8 @@ function mergeConfigScopes(
682
693
  GIT_WORKTREE_PREFIX: normalizeGitWorktreePrefix(globalConfig.GIT_WORKTREE_PREFIX),
683
694
  DEBUG_ENABLED: normalizeDebugEnabled(localConfig.DEBUG_ENABLED),
684
695
  DEBUG_LOG_FILE: normalizeDebugLogFile(localConfig.DEBUG_LOG_FILE),
696
+ DEBUG_PROMPTS_ENABLED: normalizeDebugPromptsEnabled(localConfig.DEBUG_PROMPTS_ENABLED),
697
+ DEBUG_PROMPTS_LOG_PATH: normalizeDebugPromptsLogPath(localConfig.DEBUG_PROMPTS_LOG_PATH),
685
698
  DEBUG_STATUS_CHANGES: normalizeDebugStatusChanges(localConfig.DEBUG_STATUS_CHANGES),
686
699
  DEBUG_WORKFLOW_EVENTS: normalizeDebugWorkflowEvents(localConfig.DEBUG_WORKFLOW_EVENTS),
687
700
  DEBUG_TOOL_COMMANDS_ENABLED: normalizeDebugToolCommandsEnabled(localConfig.DEBUG_TOOL_COMMANDS_ENABLED),
@@ -724,7 +737,7 @@ function mergeConfigScopes(
724
737
  * @details Composes documented local and global defaults, then merges them into the effective runtime config consumed by CLI and extension code. Time complexity is O(l + c). No filesystem side effects occur.
725
738
  * @param[in] _projectBase {string} Absolute project root path retained for stable call sites.
726
739
  * @return {UseReqConfig} Fresh default effective configuration object.
727
- * @satisfies CTN-001, CTN-012, CTN-013, CTN-018, CTN-019, REQ-066, REQ-137, REQ-146, REQ-163, REQ-174, REQ-178, REQ-184, REQ-185, REQ-196, REQ-204, REQ-205, REQ-212, REQ-236, REQ-237, REQ-238, REQ-239, REQ-249, REQ-250, REQ-251, REQ-252, REQ-277, REQ-315, REQ-316
740
+ * @satisfies CTN-001, CTN-012, CTN-013, CTN-018, CTN-019, REQ-066, REQ-137, REQ-146, REQ-163, REQ-174, REQ-178, REQ-184, REQ-185, REQ-196, REQ-204, REQ-205, REQ-212, REQ-236, REQ-237, REQ-238, REQ-239, REQ-249, REQ-250, REQ-251, REQ-252, REQ-277, REQ-315, REQ-316, REQ-413, REQ-414
728
741
  */
729
742
  export function getDefaultConfig(_projectBase: string): UseReqConfig {
730
743
  const globalConfig = getDefaultGlobalConfig();
@@ -853,7 +866,7 @@ function normalizeGlobalStaticCheckConfig(
853
866
  * @param[in] projectBase {string} Absolute project root path.
854
867
  * @param[in] defaultStaticCheckConfig {Record<string, LocalStaticCheckLanguageConfig>} Local static-check enable defaults derived from the current global checker map.
855
868
  * @return {UseReqLocalConfig} Sanitized local configuration.
856
- * @satisfies CTN-019, REQ-328
869
+ * @satisfies CTN-019, REQ-328, REQ-413, REQ-414
857
870
  */
858
871
  function loadLocalConfig(
859
872
  projectBase: string,
@@ -872,6 +885,8 @@ function loadLocalConfig(
872
885
  "static-check": normalizeLocalStaticCheckConfig(undefined, defaultStaticCheckConfig),
873
886
  DEBUG_ENABLED: DEFAULT_DEBUG_ENABLED,
874
887
  DEBUG_LOG_FILE: DEFAULT_DEBUG_LOG_FILE,
888
+ DEBUG_PROMPTS_ENABLED: DEFAULT_DEBUG_PROMPTS_ENABLED,
889
+ DEBUG_PROMPTS_LOG_PATH: DEFAULT_DEBUG_PROMPTS_LOG_PATH,
875
890
  DEBUG_STATUS_CHANGES: DEFAULT_DEBUG_STATUS_CHANGES,
876
891
  DEBUG_WORKFLOW_EVENTS: DEFAULT_DEBUG_WORKFLOW_EVENTS,
877
892
  DEBUG_TOOL_COMMANDS_ENABLED: DEFAULT_DEBUG_TOOL_COMMANDS_ENABLED,
@@ -902,6 +917,8 @@ function loadLocalConfig(
902
917
  "static-check": normalizeLocalStaticCheckConfig(data["static-check"], defaultStaticCheckConfig),
903
918
  DEBUG_ENABLED: normalizeDebugEnabled(data.DEBUG_ENABLED),
904
919
  DEBUG_LOG_FILE: normalizeDebugLogFile(data.DEBUG_LOG_FILE),
920
+ DEBUG_PROMPTS_ENABLED: normalizeDebugPromptsEnabled(data.DEBUG_PROMPTS_ENABLED),
921
+ DEBUG_PROMPTS_LOG_PATH: normalizeDebugPromptsLogPath(data.DEBUG_PROMPTS_LOG_PATH),
905
922
  DEBUG_STATUS_CHANGES: normalizeDebugStatusChanges(data.DEBUG_STATUS_CHANGES),
906
923
  DEBUG_WORKFLOW_EVENTS: normalizeDebugWorkflowEvents(data.DEBUG_WORKFLOW_EVENTS),
907
924
  DEBUG_TOOL_COMMANDS_ENABLED: normalizeDebugToolCommandsEnabled(data.DEBUG_TOOL_COMMANDS_ENABLED),
@@ -965,7 +982,7 @@ function loadGlobalConfig(): UseReqGlobalConfig {
965
982
  * @param[in] projectBase {string} Absolute project root path.
966
983
  * @return {UseReqConfig} Sanitized effective configuration.
967
984
  * @throws {ReqError} Throws with exit code `11` when either persisted config file contains invalid JSON or a non-object payload.
968
- * @satisfies CTN-012, CTN-013, CTN-018, CTN-019, REQ-066, REQ-137, REQ-146, REQ-163, REQ-174, REQ-178, REQ-184, REQ-185, REQ-196, REQ-204, REQ-205, REQ-212, REQ-215, REQ-234, REQ-235, REQ-236, REQ-237, REQ-238, REQ-239, REQ-249, REQ-277, REQ-315, REQ-316
985
+ * @satisfies CTN-012, CTN-013, CTN-018, CTN-019, REQ-066, REQ-137, REQ-146, REQ-163, REQ-174, REQ-178, REQ-184, REQ-185, REQ-196, REQ-204, REQ-205, REQ-212, REQ-215, REQ-234, REQ-235, REQ-236, REQ-237, REQ-238, REQ-239, REQ-249, REQ-277, REQ-315, REQ-316, REQ-413, REQ-414
969
986
  */
970
987
  export function loadConfig(projectBase: string): UseReqConfig {
971
988
  const globalConfig = loadGlobalConfig();
@@ -981,7 +998,7 @@ export function loadConfig(projectBase: string): UseReqConfig {
981
998
  * @details Copies only project-scoped keys into a fresh object so runtime-derived metadata plus global checker, tool, git, and notification fields never reach `.pi-usereq.json`, while preserving the debug tool-wrapper command flag beside other local debug settings. Runtime is O(n) in config size. No external state is mutated.
982
999
  * @param[in] config {UseReqConfig} Effective configuration object.
983
1000
  * @return {UseReqLocalConfig} Persistable local configuration payload.
984
- * @satisfies CTN-012, CTN-013, CTN-019, REQ-104, REQ-146, REQ-249, REQ-316, REQ-277, REQ-328
1001
+ * @satisfies CTN-012, CTN-013, CTN-019, REQ-104, REQ-146, REQ-249, REQ-316, REQ-277, REQ-328, REQ-413, REQ-414
985
1002
  */
986
1003
  function buildPersistedLocalConfig(config: UseReqConfig): UseReqLocalConfig {
987
1004
  const normalizedSrcDir = config["src-dir"]
@@ -1007,6 +1024,8 @@ function buildPersistedLocalConfig(config: UseReqConfig): UseReqLocalConfig {
1007
1024
  ),
1008
1025
  DEBUG_ENABLED: normalizeDebugEnabled(config.DEBUG_ENABLED),
1009
1026
  DEBUG_LOG_FILE: normalizeDebugLogFile(config.DEBUG_LOG_FILE),
1027
+ DEBUG_PROMPTS_ENABLED: normalizeDebugPromptsEnabled(config.DEBUG_PROMPTS_ENABLED),
1028
+ DEBUG_PROMPTS_LOG_PATH: normalizeDebugPromptsLogPath(config.DEBUG_PROMPTS_LOG_PATH),
1010
1029
  DEBUG_STATUS_CHANGES: normalizeDebugStatusChanges(config.DEBUG_STATUS_CHANGES),
1011
1030
  DEBUG_WORKFLOW_EVENTS: normalizeDebugWorkflowEvents(config.DEBUG_WORKFLOW_EVENTS),
1012
1031
  DEBUG_TOOL_COMMANDS_ENABLED: normalizeDebugToolCommandsEnabled(config.DEBUG_TOOL_COMMANDS_ENABLED),
@@ -52,6 +52,20 @@ export const DEFAULT_DEBUG_WORKFLOW_EVENTS = "disable" as const;
52
52
  */
53
53
  export const DEFAULT_DEBUG_TOOL_COMMANDS_ENABLED = "disable" as const;
54
54
 
55
+ /**
56
+ * @brief Defines the default debug-prompt content logging mode.
57
+ * @details New configs do not save dispatched prompt content until the user explicitly enables prompt debug logging from the `Debug` submenu. Access complexity is O(1).
58
+ * @satisfies CTN-013, REQ-413
59
+ */
60
+ export const DEFAULT_DEBUG_PROMPTS_ENABLED = "disable" as const;
61
+
62
+ /**
63
+ * @brief Defines the default debug prompt log path.
64
+ * @details New configurations write dispatched prompt content files under `/tmp/PI-useReq` unless the user overrides the path; trailing separators are stripped per CTN-014. Access complexity is O(1).
65
+ * @satisfies CTN-013, CTN-014, REQ-414
66
+ */
67
+ export const DEFAULT_DEBUG_PROMPTS_LOG_PATH = "/tmp/PI-useReq";
68
+
55
69
  /**
56
70
  * @brief Defines the default workflow-status filter used by debug logging.
57
71
  * @details New configs log only entries whose workflow state equals `running` until the user selects a broader or different workflow-state filter. Access complexity is O(1).
@@ -111,6 +125,12 @@ export type DebugWorkflowEvents = "enable" | "disable";
111
125
  */
112
126
  export type DebugToolCommandsEnabled = "enable" | "disable";
113
127
 
128
+ /**
129
+ * @brief Represents one persisted debug-prompt content logging flag.
130
+ * @details Restricts prompt-content debug file emission to the documented `enable|disable` domain. The alias is compile-time only and introduces no runtime cost.
131
+ */
132
+ export type DebugPromptsEnabled = "enable" | "disable";
133
+
114
134
  /**
115
135
  * @brief Represents one persisted workflow-status filter value.
116
136
  * @details Restricts debug log filtering to `any` or one explicit documented workflow state. The alias is compile-time only and introduces no runtime cost.
@@ -215,6 +235,32 @@ export function normalizeDebugToolCommandsEnabled(value: unknown): DebugToolComm
215
235
  return value === "enable" ? "enable" : DEFAULT_DEBUG_TOOL_COMMANDS_ENABLED;
216
236
  }
217
237
 
238
+ /**
239
+ * @brief Normalizes one persisted debug-prompt content logging flag.
240
+ * @details Accepts only the documented `enable|disable` values and falls back to `DEFAULT_DEBUG_PROMPTS_ENABLED` for all other payloads. Runtime is O(1). No external state is mutated.
241
+ * @param[in] value {unknown} Candidate persisted prompt-debug enable payload.
242
+ * @return {DebugPromptsEnabled} Canonical prompt-debug enable value.
243
+ * @satisfies REQ-413
244
+ */
245
+ export function normalizeDebugPromptsEnabled(value: unknown): DebugPromptsEnabled {
246
+ return value === "enable" ? "enable" : DEFAULT_DEBUG_PROMPTS_ENABLED;
247
+ }
248
+
249
+ /**
250
+ * @brief Normalizes one persisted debug prompt log path value.
251
+ * @details Accepts only non-empty strings, trims surrounding whitespace, strips every trailing separator so persisted paths stay trailing-slash-free per CTN-014, and falls back to `DEFAULT_DEBUG_PROMPTS_LOG_PATH` when the candidate is absent or blank. Runtime is O(n) in path length. No external state is mutated.
252
+ * @param[in] value {unknown} Candidate persisted prompt-log path payload.
253
+ * @return {string} Canonical trailing-slash-free prompt-log path value.
254
+ * @satisfies CTN-014, REQ-414
255
+ */
256
+ export function normalizeDebugPromptsLogPath(value: unknown): string {
257
+ if (typeof value !== "string") {
258
+ return DEFAULT_DEBUG_PROMPTS_LOG_PATH;
259
+ }
260
+ const trimmedValue = value.trim().replace(/[\\/]+$/g, "");
261
+ return trimmedValue === "" ? DEFAULT_DEBUG_PROMPTS_LOG_PATH : trimmedValue;
262
+ }
263
+
218
264
  /**
219
265
  * @brief Normalizes one persisted debug workflow-status filter.
220
266
  * @details Accepts only the documented `any` token or one explicit workflow state and falls back to `DEFAULT_DEBUG_LOG_ON_STATUS` for all other payloads. Runtime is O(1). No external state is mutated.
@@ -305,6 +351,21 @@ export function resolveDebugLogPath(projectBase: string, config: UseReqConfig):
305
351
  : path.resolve(projectBase, configuredPath);
306
352
  }
307
353
 
354
+ /**
355
+ * @brief Resolves the absolute debug prompt log directory for one project base.
356
+ * @details Preserves absolute configured paths and otherwise resolves relative values against the original project base so prompt-worktree cleanup cannot discard accumulated prompt debug evidence. Runtime is O(p) in path length. No external state is mutated.
357
+ * @param[in] projectBase {string} Absolute original project base path.
358
+ * @param[in] config {UseReqConfig} Effective project configuration.
359
+ * @return {string} Absolute debug prompt log directory path.
360
+ * @satisfies REQ-414
361
+ */
362
+ export function resolveDebugPromptsLogPath(projectBase: string, config: UseReqConfig): string {
363
+ const configuredPath = normalizeDebugPromptsLogPath(config.DEBUG_PROMPTS_LOG_PATH);
364
+ return path.isAbsolute(configuredPath)
365
+ ? path.normalize(configuredPath)
366
+ : path.resolve(projectBase, configuredPath);
367
+ }
368
+
308
369
  /**
309
370
  * @brief Tests whether one tool execution should be appended to the debug log.
310
371
  * @details Requires global debug enablement, membership in `DEBUG_ENABLED_TOOLS`, and a matching workflow-state filter before any filesystem work occurs. Runtime is O(n) in configured selector count. No external state is mutated.
@@ -379,6 +440,25 @@ export function shouldLogDebugPromptWorkflowEvent(
379
440
  && normalizeDebugWorkflowEvents(config.DEBUG_WORKFLOW_EVENTS) === "enable";
380
441
  }
381
442
 
443
+ /**
444
+ * @brief Tests whether one dispatched prompt content file should be written.
445
+ * @details Requires global debug enablement, explicit prompt-content debug enablement, and a matching workflow-state filter before any filesystem work occurs; prompt-content logging is therefore fully subordinate to the global `Debug` flag. Runtime is O(1). No external state is mutated.
446
+ * @param[in] config {UseReqConfig} Effective project configuration.
447
+ * @param[in] workflowState {DebugWorkflowState} Current workflow state.
448
+ * @param[in] promptName {PromptCommandName} Bundled prompt name.
449
+ * @return {boolean} `true` when the prompt content file should be written.
450
+ * @satisfies REQ-413, REQ-416
451
+ */
452
+ export function shouldLogDebugPromptContent(
453
+ config: UseReqConfig,
454
+ workflowState: DebugWorkflowState,
455
+ promptName: PromptCommandName,
456
+ ): boolean {
457
+ return normalizeDebugEnabled(config.DEBUG_ENABLED) === "enable"
458
+ && normalizeDebugPromptsEnabled(config.DEBUG_PROMPTS_ENABLED) === "enable"
459
+ && matchesDebugWorkflowState(normalizeDebugLogOnStatus(config.DEBUG_LOG_ON_STATUS), workflowState);
460
+ }
461
+
382
462
  /**
383
463
  * @brief Serializes arbitrary debug payloads into deterministic JSON-compatible values.
384
464
  * @details Converts `Error` instances into structured records, elides functions, stringifies bigint values, and falls back to a best-effort string when JSON serialization fails. Runtime is O(n) in payload size. No external state is mutated.
@@ -564,3 +644,69 @@ export function logDebugPromptWorkflowEvent(
564
644
  is_error: isError,
565
645
  });
566
646
  }
647
+
648
+ /**
649
+ * @brief Formats one write-time timestamp as the `YYYYMMDDHHMMSSmmm` prompt debug prefix.
650
+ * @details Zero-pads calendar fields to their canonical widths, appends three millisecond digits, and joins every segment without separators so generated prompt debug filenames stay lexicographically sortable and collision-resistant within one second. Runtime is O(1). No external state is mutated.
651
+ * @param[in] date {Date} Write-time timestamp to encode.
652
+ * @return {string} `YYYYMMDDHHMMSSmmm` timestamp prefix.
653
+ * @satisfies REQ-417
654
+ */
655
+ export function formatPromptDebugTimestamp(date: Date): string {
656
+ const pad = (value: number, length = 2): string => String(value).padStart(length, "0");
657
+ return [
658
+ pad(date.getFullYear(), 4),
659
+ pad(date.getMonth() + 1),
660
+ pad(date.getDate()),
661
+ pad(date.getHours()),
662
+ pad(date.getMinutes()),
663
+ pad(date.getSeconds()),
664
+ pad(date.getMilliseconds(), 3),
665
+ ].join("");
666
+ }
667
+
668
+ /**
669
+ * @brief Builds one prompt debug filename for one bundled prompt.
670
+ * @details Combines the write-time `YYYYMMDDHHMMSSmmm` timestamp with the invokable `req-*` command name so every saved file can be replayed from the pi CLI and attributed to the originating `/req-*` prompt. Runtime is O(1). No external state is mutated.
671
+ * @param[in] promptName {PromptCommandName} Bundled prompt name.
672
+ * @param[in] date {Date} Write-time timestamp. Defaults to the current wall-clock time.
673
+ * @return {string} Prompt debug filename in the `<timestamp>-<req-command>` shape.
674
+ * @satisfies REQ-417
675
+ */
676
+ export function formatPromptDebugFileName(
677
+ promptName: PromptCommandName,
678
+ date = new Date(),
679
+ ): string {
680
+ return `${formatPromptDebugTimestamp(date)}-${getDebugPromptName(promptName)}`;
681
+ }
682
+
683
+ /**
684
+ * @brief Writes one dispatched prompt content file when prompt debug logging is enabled.
685
+ * @details Applies global-debug, prompt-debug, and workflow-state gating before creating the configured prompt log directory and writing the exact delivered prompt content into one `<timestamp>-<req-command>` file so the send can be replayed from the pi CLI without pi-usereq installed. Runtime is dominated by one directory creation plus one file write when enabled and O(1) otherwise. Side effects include directory creation and file creation only for enabled matching entries.
686
+ * @param[in] projectBase {string} Absolute original project base path.
687
+ * @param[in] config {UseReqConfig} Effective project configuration.
688
+ * @param[in] workflowState {DebugWorkflowState} Current workflow state.
689
+ * @param[in] promptName {PromptCommandName} Bundled prompt name.
690
+ * @param[in] content {string} Exact rendered prompt content delivered through `sendMessage` or `sendUserMessage`.
691
+ * @return {boolean} `true` when the prompt content file is written; otherwise `false`.
692
+ * @satisfies REQ-416, REQ-417, REQ-418
693
+ */
694
+ export function logDebugPromptContent(
695
+ projectBase: string,
696
+ config: UseReqConfig,
697
+ workflowState: DebugWorkflowState,
698
+ promptName: PromptCommandName,
699
+ content: string,
700
+ ): boolean {
701
+ if (!shouldLogDebugPromptContent(config, workflowState, promptName)) {
702
+ return false;
703
+ }
704
+ const logDirectory = resolveDebugPromptsLogPath(projectBase, config);
705
+ try {
706
+ fs.mkdirSync(logDirectory, { recursive: true });
707
+ fs.writeFileSync(path.join(logDirectory, formatPromptDebugFileName(promptName)), content, "utf8");
708
+ return true;
709
+ } catch {
710
+ return false;
711
+ }
712
+ }
package/src/index.ts CHANGED
@@ -128,9 +128,12 @@ import {
128
128
  DEBUG_WORKFLOW_STATES,
129
129
  DEFAULT_DEBUG_LOG_FILE,
130
130
  DEFAULT_DEBUG_LOG_ON_STATUS,
131
+ DEFAULT_DEBUG_PROMPTS_ENABLED,
132
+ DEFAULT_DEBUG_PROMPTS_LOG_PATH,
131
133
  DEFAULT_DEBUG_STATUS_CHANGES,
132
134
  DEFAULT_DEBUG_TOOL_COMMANDS_ENABLED,
133
135
  DEFAULT_DEBUG_WORKFLOW_EVENTS,
136
+ logDebugPromptContent,
134
137
  logDebugPromptEvent,
135
138
  logDebugPromptWorkflowEvent,
136
139
  logDebugToolExecution,
@@ -138,6 +141,8 @@ import {
138
141
  normalizeDebugEnabledTools,
139
142
  normalizeDebugLogFile,
140
143
  normalizeDebugLogOnStatus,
144
+ normalizeDebugPromptsEnabled,
145
+ normalizeDebugPromptsLogPath,
141
146
  normalizeDebugStatusChanges,
142
147
  normalizeDebugToolCommandsEnabled,
143
148
  normalizeDebugWorkflowEvents,
@@ -1778,14 +1783,16 @@ function getDebugToolToggleNames(): PiUsereqStartupToolName[] {
1778
1783
 
1779
1784
  /**
1780
1785
  * @brief Restores the debug configuration subtree to its documented defaults.
1781
- * @details Resets global debug enablement, log path, tool-wrapper command registration, workflow-state filter, dedicated workflow-event logging, and selected tool plus prompt debug toggles without mutating unrelated settings. Runtime is O(1). Side effect: mutates `config`.
1786
+ * @details Resets global debug enablement, log path, prompt-content debug enablement plus prompt log path, tool-wrapper command registration, workflow-state filter, dedicated workflow-event logging, and selected tool plus prompt debug toggles without mutating unrelated settings. Runtime is O(1). Side effect: mutates `config`.
1782
1787
  * @param[in,out] config {UseReqConfig} Mutable configuration object.
1783
1788
  * @return {void} No return value.
1784
- * @satisfies REQ-236, REQ-237, REQ-238, REQ-239, REQ-195, REQ-277, REQ-322
1789
+ * @satisfies REQ-236, REQ-237, REQ-238, REQ-239, REQ-195, REQ-277, REQ-322, REQ-413, REQ-414, REQ-420
1785
1790
  */
1786
1791
  function resetDebugConfigToDefaults(config: UseReqConfig): void {
1787
1792
  config.DEBUG_ENABLED = "disable";
1788
1793
  config.DEBUG_LOG_FILE = DEFAULT_DEBUG_LOG_FILE;
1794
+ config.DEBUG_PROMPTS_ENABLED = DEFAULT_DEBUG_PROMPTS_ENABLED;
1795
+ config.DEBUG_PROMPTS_LOG_PATH = DEFAULT_DEBUG_PROMPTS_LOG_PATH;
1789
1796
  config.DEBUG_STATUS_CHANGES = DEFAULT_DEBUG_STATUS_CHANGES;
1790
1797
  config.DEBUG_WORKFLOW_EVENTS = DEFAULT_DEBUG_WORKFLOW_EVENTS;
1791
1798
  config.DEBUG_TOOL_COMMANDS_ENABLED = DEFAULT_DEBUG_TOOL_COMMANDS_ENABLED;
@@ -1870,10 +1877,10 @@ async function selectDebugLogOnStatus(
1870
1877
 
1871
1878
  /**
1872
1879
  * @brief Builds the shared settings-menu choices for debug logging configuration.
1873
- * @details Serializes global debug controls plus tool-wrapper command registration, workflow-state, dedicated workflow-event, per-tool, and per-prompt toggles into one submenu, deriving inventories from the canonical tool and prompt lists and dimming locked rows while debug is disabled. Runtime is O(t + p). No external state is mutated.
1880
+ * @details Serializes global debug controls plus prompt-content debug controls, tool-wrapper command registration, workflow-state, dedicated workflow-event, per-tool, and per-prompt toggles into one submenu, deriving inventories from the canonical tool and prompt lists and dimming locked rows while debug is disabled. Runtime is O(t + p). No external state is mutated.
1874
1881
  * @param[in] config {UseReqConfig} Effective project configuration.
1875
1882
  * @return {PiUsereqSettingsMenuChoice[]} Ordered debug-menu choices.
1876
- * @satisfies REQ-240, REQ-241, REQ-242, REQ-243, REQ-193, REQ-277, REQ-321, REQ-322
1883
+ * @satisfies REQ-240, REQ-241, REQ-242, REQ-243, REQ-193, REQ-277, REQ-321, REQ-322, REQ-415
1877
1884
  */
1878
1885
  function buildDebugMenuChoices(config: UseReqConfig): PiUsereqSettingsMenuChoice[] {
1879
1886
  const debugEnabled = config.DEBUG_ENABLED === "enable";
@@ -1887,6 +1894,25 @@ function buildDebugMenuChoices(config: UseReqConfig): PiUsereqSettingsMenuChoice
1887
1894
  values: ["enable", "disable"],
1888
1895
  description: "Enable or disable all debug logging behavior and unlock the remaining Debug rows.",
1889
1896
  },
1897
+ buildDebugMenuChoice(
1898
+ {
1899
+ id: "debug-prompts-enabled",
1900
+ label: "Enable debug prompts",
1901
+ value: normalizeDebugPromptsEnabled(config.DEBUG_PROMPTS_ENABLED),
1902
+ values: ["enable", "disable"],
1903
+ description: "Enable or disable saving the exact dispatched prompt content into the debug prompt log path.",
1904
+ },
1905
+ debugEnabled,
1906
+ ),
1907
+ buildDebugMenuChoice(
1908
+ {
1909
+ id: "debug-prompts-log-path",
1910
+ label: "Log path for prompts",
1911
+ value: config.DEBUG_PROMPTS_LOG_PATH,
1912
+ description: "Edit the directory where dispatched prompt contents are saved as `<timestamp>-<req-command>` files. Relative paths resolve against the original project base.",
1913
+ },
1914
+ debugEnabled,
1915
+ ),
1890
1916
  buildDebugMenuChoice(
1891
1917
  {
1892
1918
  id: "debug-tool-commands-enabled",
@@ -1965,12 +1991,12 @@ function buildDebugMenuChoices(config: UseReqConfig): PiUsereqSettingsMenuChoice
1965
1991
 
1966
1992
  /**
1967
1993
  * @brief Runs the interactive Debug submenu.
1968
- * @details Lets the user toggle global debug enablement, tool-wrapper command registration, debug file and workflow filters, dedicated workflow-event logging, per-tool selectors, and per-prompt selectors while preserving row focus across re-renders. Runtime depends on user interaction count. Side effects include UI updates, config mutation, and optional debug command registration.
1994
+ * @details Lets the user toggle global debug enablement, prompt-content debug enablement plus prompt log path, tool-wrapper command registration, debug file and workflow filters, dedicated workflow-event logging, per-tool selectors, and per-prompt selectors while preserving row focus across re-renders. Runtime depends on user interaction count. Side effects include UI updates, config mutation, and optional debug command registration.
1969
1995
  * @param[in] pi {ExtensionAPI} Active extension API instance.
1970
1996
  * @param[in] ctx {ExtensionCommandContext} Active command context.
1971
1997
  * @param[in,out] config {UseReqConfig} Mutable configuration object.
1972
1998
  * @return {Promise<void>} Promise resolved when the submenu closes.
1973
- * @satisfies REQ-236, REQ-237, REQ-238, REQ-239, REQ-240, REQ-241, REQ-242, REQ-243, REQ-192, REQ-193, REQ-195, REQ-277, REQ-321, REQ-322, REQ-323
1999
+ * @satisfies REQ-236, REQ-237, REQ-238, REQ-239, REQ-240, REQ-241, REQ-242, REQ-243, REQ-192, REQ-193, REQ-195, REQ-277, REQ-321, REQ-322, REQ-323, REQ-413, REQ-414, REQ-415, REQ-420
1974
2000
  */
1975
2001
  async function configureDebugMenu(
1976
2002
  pi: ExtensionAPI,
@@ -1999,6 +2025,12 @@ async function configureDebugMenu(
1999
2025
  ctx.ui.notify(`Debug ${config.DEBUG_ENABLED}`, "info");
2000
2026
  return;
2001
2027
  }
2028
+ if (choiceId === "debug-prompts-enabled") {
2029
+ config.DEBUG_PROMPTS_ENABLED = normalizeDebugPromptsEnabled(newValue);
2030
+ onConfigChange();
2031
+ ctx.ui.notify(`Debug prompts ${config.DEBUG_PROMPTS_ENABLED}`, "info");
2032
+ return;
2033
+ }
2002
2034
  if (choiceId === "debug-tool-commands-enabled") {
2003
2035
  updateDebugToolCommandsEnabled(newValue);
2004
2036
  return;
@@ -2063,6 +2095,8 @@ async function configureDebugMenu(
2063
2095
  const resetPreview: ResetConfirmationChange[] = [
2064
2096
  { label: "Debug", previousValue: config.DEBUG_ENABLED, nextValue: "disable" },
2065
2097
  { label: "Log file", previousValue: config.DEBUG_LOG_FILE, nextValue: DEFAULT_DEBUG_LOG_FILE },
2098
+ { label: "Enable debug prompts", previousValue: normalizeDebugPromptsEnabled(config.DEBUG_PROMPTS_ENABLED), nextValue: DEFAULT_DEBUG_PROMPTS_ENABLED },
2099
+ { label: "Log path for prompts", previousValue: config.DEBUG_PROMPTS_LOG_PATH, nextValue: DEFAULT_DEBUG_PROMPTS_LOG_PATH },
2066
2100
  { label: "Enable debug commands for tools", previousValue: normalizeDebugToolCommandsEnabled(config.DEBUG_TOOL_COMMANDS_ENABLED), nextValue: DEFAULT_DEBUG_TOOL_COMMANDS_ENABLED },
2067
2101
  { label: "Status changes", previousValue: normalizeDebugStatusChanges(config.DEBUG_STATUS_CHANGES), nextValue: DEFAULT_DEBUG_STATUS_CHANGES },
2068
2102
  { label: "Workflow events", previousValue: normalizeDebugWorkflowEvents(config.DEBUG_WORKFLOW_EVENTS), nextValue: DEFAULT_DEBUG_WORKFLOW_EVENTS },
@@ -2090,6 +2124,23 @@ async function configureDebugMenu(
2090
2124
  ctx.ui.notify("Debug rows are locked while Debug is disabled", "info");
2091
2125
  continue;
2092
2126
  }
2127
+ if (choice === "debug-prompts-enabled") {
2128
+ config.DEBUG_PROMPTS_ENABLED = normalizeDebugPromptsEnabled(
2129
+ config.DEBUG_PROMPTS_ENABLED === "enable" ? "disable" : "enable",
2130
+ );
2131
+ onConfigChange();
2132
+ ctx.ui.notify(`Debug prompts ${config.DEBUG_PROMPTS_ENABLED}`, "info");
2133
+ continue;
2134
+ }
2135
+ if (choice === "debug-prompts-log-path") {
2136
+ const value = await ctx.ui.input("Log path for prompts", config.DEBUG_PROMPTS_LOG_PATH);
2137
+ if (value !== undefined) {
2138
+ config.DEBUG_PROMPTS_LOG_PATH = normalizeDebugPromptsLogPath(value);
2139
+ onConfigChange();
2140
+ ctx.ui.notify(`Debug prompt log path set to ${config.DEBUG_PROMPTS_LOG_PATH}`, "info");
2141
+ }
2142
+ continue;
2143
+ }
2093
2144
  if (choice === "debug-log-file") {
2094
2145
  const value = await ctx.ui.input("Log file", config.DEBUG_LOG_FILE);
2095
2146
  if (value !== undefined) {
@@ -3379,11 +3430,11 @@ function registerReqReferencesCommand(
3379
3430
 
3380
3431
  /**
3381
3432
  * @brief Registers bundled prompt-backed commands with the extension.
3382
- * @details Creates one prompt-template-backed `req-<prompt>` command per bundled prompt name. Each handler rejects non-`idle` workflow state by transitioning the shared workflow state to `error` before command-side preflight, otherwise transitions the shared workflow state through `checking`, `error`, and `running`, runs dedicated prompt-command git and required-doc preflight checks, optionally prepares a dedicated worktree execution plan using the active session directory, persists the prompt metadata needed for switch-triggered rebinding, switches the active session to the verified execution cwd before prompt handoff, logs dedicated workflow-activation diagnostics, renders the prompt, starts prompt delivery into the forked active session, records `running` immediately after delivery handoff begins, and then awaits the wrapped prompt-delivery promise whose stale post-restore rejections are suppressed. Runtime is O(p) for registration; handler cost depends on prompt preflight, worktree preparation, session switching, prompt rendering, prompt dispatch, and optional debug logging. Side effects include command registration, status-controller mutation, worktree creation, active-session replacement, optional worktree rollback, user-message delivery during execution, and optional debug-log writes.
3433
+ * @details Creates one prompt-template-backed `req-<prompt>` command per bundled prompt name. Each handler rejects non-`idle` workflow state by transitioning the shared workflow state to `error` before command-side preflight, otherwise transitions the shared workflow state through `checking`, `error`, and `running`, runs dedicated prompt-command git and required-doc preflight checks, optionally prepares a dedicated worktree execution plan using the active session directory, persists the prompt metadata needed for switch-triggered rebinding, switches the active session to the verified execution cwd before prompt handoff, logs dedicated workflow-activation diagnostics, renders the prompt, starts prompt delivery into the forked active session, records `running` immediately after delivery handoff begins, saves the exact delivered prompt content into the debug prompt log path when prompt debug logging is enabled, and then awaits the wrapped prompt-delivery promise whose stale post-restore rejections are suppressed. Runtime is O(p) for registration; handler cost depends on prompt preflight, worktree preparation, session switching, prompt rendering, prompt dispatch, and optional debug logging. Side effects include command registration, status-controller mutation, worktree creation, active-session replacement, optional worktree rollback, optional prompt-content debug file creation, user-message delivery during execution, and optional debug-log writes.
3383
3434
  * @param[in] pi {ExtensionAPI} Active extension API instance.
3384
3435
  * @param[in,out] statusController {PiUsereqStatusController} Mutable status controller.
3385
3436
  * @return {void} No return value.
3386
- * @satisfies REQ-004, REQ-067, REQ-068, REQ-169, REQ-200, REQ-201, REQ-202, REQ-203, REQ-206, REQ-207, REQ-219, REQ-220, REQ-221, REQ-224, REQ-225, REQ-226, REQ-227, REQ-245, REQ-246, REQ-247, REQ-277, REQ-281, REQ-377
3437
+ * @satisfies REQ-004, REQ-067, REQ-068, REQ-169, REQ-200, REQ-201, REQ-202, REQ-203, REQ-206, REQ-207, REQ-219, REQ-220, REQ-221, REQ-224, REQ-225, REQ-226, REQ-227, REQ-245, REQ-246, REQ-247, REQ-277, REQ-281, REQ-377, REQ-416, REQ-417, REQ-418
3387
3438
  */
3388
3439
  function registerPromptCommands(
3389
3440
  pi: ExtensionAPI,
@@ -3489,6 +3540,13 @@ function registerPromptCommands(
3489
3540
  promptName,
3490
3541
  "running",
3491
3542
  );
3543
+ logDebugPromptContent(
3544
+ projectBase,
3545
+ config,
3546
+ statusController.state.workflowState,
3547
+ promptName,
3548
+ content,
3549
+ );
3492
3550
  await promptDelivery;
3493
3551
  } catch (error) {
3494
3552
  if (shouldIgnoreLatePromptDeliveryFailure(error, statusController.state.workflowState, executionPlan)) {