pi-usereq 0.39.0 → 0.40.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.
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  title: "PI-useReq Requirements"
3
3
  description: Software requirements specification
4
- version: "0.0.70"
5
- date: "2026-07-09"
4
+ version: "0.0.71"
5
+ date: "2026-07-10"
6
6
  author: "OpenAI Codex"
7
7
  scope:
8
8
  paths:
@@ -89,6 +89,7 @@ PI-useReq is a TypeScript pi extension plus companion Node CLI and standalone ex
89
89
  - **DES-010**: MUST centralize event-driven context snapshots, run-timing state, prompt-orchestration workflow state, and status-bar rendering through shared extension-status helpers.
90
90
  - **DES-011**: MUST implement `.github/workflows/release-npm.yml` as a two-job GitHub Actions pipeline where `check-branch` gates `build-release`, preserving changelog-driven GitHub Release creation while adding npm publication.
91
91
  - **DES-015**: MUST implement config-gated `debug-compress`, `debug-references`, `debug-static-check`, and `debug-tokens` slash-command wrappers in `src/index.ts` that reuse existing tool-runner execution paths.
92
+ - **DES-016**: MUST deliver rendered bundled-prompt content to the LLM through `sendMessage` as a `display:false` custom message with `triggerTurn:true` and MUST NOT use `sendUserMessage` when `sendMessage` is available.
92
93
 
93
94
  ### 3.2 Functions
94
95
  - **REQ-001**: MUST access bundled prompts, git execution instructions, templates, and guidelines from `<installation-path>/resources` without requiring user-home resource copies before prompt or tool execution.
@@ -157,6 +158,10 @@ PI-useReq is a TypeScript pi extension plus companion Node CLI and standalone ex
157
158
  - **REQ-066**: MUST omit `reset-context` and `context-reset` fields from persisted local and global configuration.
158
159
  - **REQ-067**: MUST send every bundled prompt-backed `req-<prompt>` payload into the current active session.
159
160
  - **REQ-068**: MUST use one prompt-delivery path that sends bundled prompt-backed `req-<prompt>` payloads through the forked execution session by using only the replacement-session context for post-switch session-bound operations.
161
+ - **REQ-334**: MUST NOT display rendered prompt content on screen when delivering bundled prompt-backed `req-<prompt>` commands and MUST deliver the full rendered content only to the LLM agent.
162
+ - **REQ-335**: MUST display a command invocation summary on screen for every bundled prompt-backed `req-<prompt>` command containing the command name, passed arguments, and active configuration.
163
+ - **REQ-336**: MUST render the command invocation summary with the command name without the `req-` prefix in uppercase and the user request arguments.
164
+ - **REQ-337**: MUST include `docs-dir`, `src-dir`, `tests-dir`, enabled context files, `AUTO_GIT_COMMIT`, effective `GIT_WORKTREE_ENABLED`, `GIT_WORKTREE_PREFIX`, enabled static-check languages, and `enabled-tools` in the command invocation summary.
160
165
  - **REQ-008**: MUST provide a `Language static code checkers` submenu that adds global Command entries by guided language flow, removes configured global checker entries, toggles local per-language enablement, and resets static-check configuration.
161
166
  - **REQ-160**: MUST hardcode `Command` as the only user-configurable static-check module and omit module-selection UI from static-check configuration menus.
162
167
  - **REQ-161**: MUST hide `Dummy` from user-configurable static-check menus while preserving existing-config parsing and debug-driver support for `Dummy` entries.
@@ -506,6 +511,7 @@ PI-useReq is a TypeScript pi extension plus companion Node CLI and standalone ex
506
511
  - **TST-065**: MUST verify default startup-tool enablement matches the documented enabled and disabled tool matrix.
507
512
  - **TST-110**: MUST verify `Enable tools` toggles, enable-all, disable-all, and reset-defaults persist only in global configuration.
508
513
  - **TST-066**: MUST verify `req-<prompt>` commands keep working when extension custom-tool registrations are removed from the runtime inventory.
514
+ - **TST-121**: MUST verify bundled prompt-backed `req-<prompt>` commands deliver the full rendered prompt content through the fallback `sendUserMessage` channel when the runtime does not expose `sendMessage`.
509
515
  - **TST-059**: MUST verify every agent-tool registration defines custom `renderResult` and that compact rendering shows essential invocation parameters while expanded rendering avoids fallback raw-content display.
510
516
  - **TST-086**: MUST verify bundled prompt-backed `req-<prompt>` commands abort before prompt dispatch when the persisted execution-session header cwd or `process.cwd()` differs from the expected execution path, and abort before merge when persisted execution-session header metadata or verified worktree artifacts diverge, while stale pre-switch context probes alone do not abort.
511
517
  - **TST-113**: MUST verify default local configuration persists `DEBUG_TOOL_COMMANDS_ENABLED=disable`, and the `Debug` submenu renders `Enable debug commands for tools` before `Log file`.
@@ -575,8 +575,9 @@
575
575
  - `buildIgnoredGitStatusPaths(...)`: ignore extension-owned debug-log artifacts during cleanliness verification [`src/core/req-references-command.ts`]
576
576
  - `renderPrompt(...)`: render prompt-command payloads with bundled commit-instruction expansion, conditional pi.dev governance guidance, and `%%CONTEXT_FILES%%` context-file injection [`src/core/prompts.ts`]
577
577
  - `buildContextFilesBlock(...)`: build the markdown block injected at `%%CONTEXT_FILES%%` from enabled context files in documented order with pre-substituted `%%DOC_PATH%%` file references and four-backtick fences [`src/core/prompts.ts`]
578
- - `deliverPromptCommand(...)`: dispatch prompt replay into the current recorded session [`src/index.ts`]
579
- - External boundaries: `RecordingExtensionAPI.sendUserMessage(...)` records the delivered prompt payload.
578
+ - `renderPromptCommandSummary(...)`: render the on-screen command invocation summary with command name, user request arguments, and active configuration fields [`src/core/prompts.ts`]
579
+ - `deliverPromptCommand(...)`: dispatch the rendered prompt as a hidden `display:false` custom message plus a `display:true` summary into the current recorded session, falling back to `sendUserMessage(...)` when `sendMessage(...)` is unavailable [`src/index.ts`]
580
+ - External boundaries: `RecordingExtensionAPI.sendMessage(...)` or fallback `RecordingExtensionAPI.sendUserMessage(...)` records the delivered prompt payload plus summary.
580
581
  - `configurePiUsereq(...)`: execute the interactive configuration menu [`src/index.ts`]
581
582
  - `buildPiUsereqMenuChoices(...)`: serialize top-level settings actions including the `Context Files` injection toggle row, effective worktree locking, plus display-only local and global config-path rows [`src/index.ts`]
582
583
  - `formatLocalConfigPathForMenu(...)`: format the current local config path with the shared `~`-relative path formatter for menu display [`src/index.ts`]
@@ -879,10 +880,11 @@
879
880
  - `writePersistedPromptCommandSessionContext(...)`: store the reusable command-capable replacement-session context for later closure handling [`src/core/prompt-command-state.ts`]
880
881
  - `clearPersistedPromptCommandSessionContext(...)`: drop reusable command-context persistence when worktree routing is inactive [`src/core/prompt-command-state.ts`]
881
882
  - `logPromptWorkflowEvent(...)`: append selected workflow-activation debug entries [`src/index.ts`]
882
- - `deliverPromptCommand(...)`: start dispatch of the rendered prompt into the current active session after execution-session activation is verified, preferring replacement-session `sendUserMessage(...)` when available, returning the delivery promise so the final `running` transition is recorded immediately after handoff begins instead of after the full prompt run completes, and suppressing the documented stale post-restore rejection once the prompt was already accepted [`src/index.ts`]
883
+ - `renderPromptCommandSummary(...)`: render the on-screen command invocation summary with command name without the `req-` prefix in uppercase, user request arguments, and active configuration fields [`src/core/prompts.ts`]
884
+ - `deliverPromptCommand(...)`: start dispatch of the rendered prompt as a hidden `display:false` custom message with `triggerTurn:true` plus a `display:true` command invocation summary into the current active session after execution-session activation is verified, preferring replacement-session `sendMessage(...)` when available, falling back to `sendUserMessage(...)` when `sendMessage(...)` is unavailable, returning the delivery promise so the final `running` transition is recorded immediately after handoff begins instead of after the full prompt run completes, and suppressing the documented stale post-restore rejection once the prompt was already accepted [`src/index.ts`]
883
885
  - `writePersistedPromptCommandRuntimeState(...)`: mirror the prepared prompt execution plan into process-scoped persistence before the worktree session switch returns control [`src/core/prompt-command-state.ts`]
884
- - `isStaleExtensionContextError(...)`: classify stale post-restore delivery rejections from replacement-session `sendUserMessage(...)` [`src/core/extension-status.ts`]
885
- - External boundaries: replacement-session `sendUserMessage(...)` or fallback `pi.sendUserMessage(...)` delivers the rendered prompt payload into the active `AgentSession`.
886
+ - `isStaleExtensionContextError(...)`: classify stale post-restore delivery rejections from replacement-session `sendMessage(...)` [`src/core/extension-status.ts`]
887
+ - External boundaries: replacement-session `sendMessage(...)` or `pi.sendMessage(...)` delivers the hidden rendered prompt payload plus the displayed summary into the active `AgentSession`; fallback replacement-session `sendUserMessage(...)` or `pi.sendUserMessage(...)` delivers the rendered prompt payload when `sendMessage(...)` is unavailable.
886
888
  - `abortPromptCommandExecution(...)`: restore the original session-backed base path and delete created worktree resources when command-side preflight or prompt handoff fails [`src/core/prompt-command-runtime.ts`]
887
889
  - `restorePromptCommandExecution(...)`: switch back to the original session through replacement-session-aware `ctx.switchSession(sessionPath, { withSession })` handling, reuse the persisted replacement-session context when lifecycle hooks omit `switchSession()`, carry forward the returned replacement-session context for later session-bound work, re-align `process.cwd()` to `base-path`, confirm `process.cwd()` plus the persisted original-session file header cwd when the file is already persisted, append optional workflow-restore debug entries, clear active worktree path facts, and best-effort realign the live `ctx.cwd` mirror when worktree routing was active without failing on stale or getter-only context mirrors [`src/core/prompt-command-runtime.ts`]
888
890
  - `resolvePromptCommandSwitchContext(...)`: prefer the live command context or fall back to the persisted replacement-session context keyed by the execution-session file [`src/core/prompt-command-runtime.ts`]
@@ -6,7 +6,17 @@
6
6
 
7
7
  import fs from "node:fs";
8
8
  import path from "node:path";
9
- import { buildPromptReplacementPaths, DEFAULT_DOCS_DIR, type UseReqConfig } from "./config.js";
9
+ import {
10
+ buildPromptReplacementPaths,
11
+ DEFAULT_DOCS_DIR,
12
+ DEFAULT_STATIC_CHECK_LANGUAGES,
13
+ resolveEffectiveGitWorktreeEnabled,
14
+ type UseReqConfig,
15
+ } from "./config.js";
16
+ import {
17
+ comparePiUsereqStartupToolNames,
18
+ type PiUsereqStartupToolName,
19
+ } from "./pi-usereq-tools.js";
10
20
  import { formatRuntimePathForDisplay, normalizeRelativeDirContract } from "./path-context.js";
11
21
  import type {
12
22
  PromptCommandExecutionPlan,
@@ -355,3 +365,61 @@ export function renderPrompt(
355
365
  }
356
366
  return adapted.split("%%CONTEXT_FILES%%").join("");
357
367
  }
368
+
369
+ /**
370
+ * @brief Defines the custom-message type used for pi-usereq prompt-command screen summaries and hidden LLM prompt delivery.
371
+ * @details The constant is reused as the `customType` for both the `display:true` command invocation summary and the `display:false` hidden rendered prompt so the TUI renders only the summary while the full prompt reaches the LLM agent through the same custom-message channel. Access complexity is O(1).
372
+ * @satisfies DES-016, REQ-334
373
+ */
374
+ export const PROMPT_COMMAND_SUMMARY_CUSTOM_TYPE = "pi-usereq-prompt-command";
375
+
376
+ /**
377
+ * @brief Builds the on-screen command invocation summary for one bundled prompt-backed `req-<prompt>` command.
378
+ * @details Renders the command name without the `req-` prefix in uppercase, the user request arguments, and the active configuration fields (`docs-dir`, `src-dir`, `tests-dir`, enabled context files, `AUTO_GIT_COMMIT`, effective `GIT_WORKTREE_ENABLED`, `GIT_WORKTREE_PREFIX`, enabled static-check languages, and `enabled-tools`) so the TUI shows only a compact summary while the full rendered prompt is delivered hidden to the LLM agent. Static-check languages are emitted in canonical `DEFAULT_STATIC_CHECK_LANGUAGES` order; enabled tools are emitted in documented menu order via `comparePiUsereqStartupToolNames`. Runtime is O(l + t log t) where l is language count and t is enabled-tool count. No external state is mutated.
379
+ * @param[in] promptName {string} Bundled prompt name without the `req-` prefix.
380
+ * @param[in] args {string} User request arguments passed to the slash command.
381
+ * @param[in] config {UseReqConfig} Effective project configuration supplying directory, git, static-check, and tool fields.
382
+ * @return {string} Multi-line command invocation summary text.
383
+ * @satisfies REQ-335, REQ-336, REQ-337
384
+ */
385
+ export function renderPromptCommandSummary(
386
+ promptName: string,
387
+ args: string,
388
+ config: UseReqConfig,
389
+ ): string {
390
+ const contextFiles = CONTEXT_FILE_DESCRIPTORS
391
+ .filter((descriptor) => config[descriptor.flagKey])
392
+ .map((descriptor) => descriptor.fileName.replace(/\.md$/, "").toLowerCase())
393
+ .join(", ");
394
+ const enabledLanguages = DEFAULT_STATIC_CHECK_LANGUAGES
395
+ .filter((language) => config["static-check"][language]?.enabled === "enable")
396
+ .join(", ");
397
+ const enabledTools = [...config["enabled-tools"]]
398
+ .sort((left, right) =>
399
+ comparePiUsereqStartupToolNames(
400
+ left as PiUsereqStartupToolName,
401
+ right as PiUsereqStartupToolName,
402
+ ))
403
+ .join(", ");
404
+ const effectiveWorktree = resolveEffectiveGitWorktreeEnabled(
405
+ config.AUTO_GIT_COMMIT,
406
+ config.GIT_WORKTREE_ENABLED,
407
+ );
408
+ const lines: string[] = [
409
+ `Command: ${promptName.toUpperCase()}`,
410
+ "",
411
+ `User's Request: ${args}`,
412
+ "",
413
+ "Configuration:",
414
+ `- document dir: ${config["docs-dir"]}`,
415
+ `- source-code dirs: ${config["src-dir"].join(", ")}`,
416
+ `- unit tests dir: ${config["tests-dir"]}`,
417
+ `- context files: ${contextFiles}`,
418
+ `- auto git commit: ${config.AUTO_GIT_COMMIT}`,
419
+ `- git worktree: ${effectiveWorktree}`,
420
+ `- worktree prefix: ${config.GIT_WORKTREE_PREFIX}`,
421
+ `- static code checks: ${enabledLanguages}`,
422
+ `- enabled tools: ${enabledTools}`,
423
+ ];
424
+ return lines.join("\n");
425
+ }
package/src/index.ts CHANGED
@@ -83,7 +83,11 @@ import {
83
83
  normalizeEnabledPiUsereqTools,
84
84
  type PiUsereqStartupToolName,
85
85
  } from "./core/pi-usereq-tools.js";
86
- import { renderPrompt } from "./core/prompts.js";
86
+ import {
87
+ PROMPT_COMMAND_SUMMARY_CUSTOM_TYPE,
88
+ renderPrompt,
89
+ renderPromptCommandSummary,
90
+ } from "./core/prompts.js";
87
91
  import {
88
92
  abortPromptCommandExecution,
89
93
  activatePromptCommandExecution,
@@ -906,21 +910,53 @@ function executeStatusTool(operation: () => ToolResult): ReturnType<typeof build
906
910
 
907
911
  /**
908
912
  * @brief Starts delivery of one rendered prompt into the current active session.
909
- * @details Prefers the replacement-session `sendUserMessage(...)` helper exposed by `withSession(...)` callbacks after session replacement so post-switch prompt delivery never reuses stale pre-switch session-bound extension objects. Returns the underlying delivery promise without awaiting it so callers can record the `running` workflow transition as soon as prompt handoff is accepted instead of waiting for the full agent turn to complete on runtimes whose async replacement-session helpers resolve only after `agent_end`. When pi later invalidates that replacement-session context during successful prompt-end restoration, the helper suppresses the documented stale-extension-context rejection because the prompt was already accepted and late rethrow would surface a false orchestration failure. Falls back to `pi.sendUserMessage(...)` only for non-replacement flows or runtimes that do not expose replacement-session helpers. Runtime is O(n) in prompt length. Side effects are limited to user-message delivery.
913
+ * @details Prefers the replacement-session `sendMessage(...)` helper exposed by `withSession(...)` callbacks after session replacement so post-switch prompt delivery never reuses stale pre-switch session-bound extension objects. Delivers the rendered prompt as a `display:false` custom message with `triggerTurn:true` so the full content reaches the LLM agent without appearing on screen, and emits a `display:true` command invocation summary so the TUI shows only the compact summary. Returns the underlying hidden-delivery promise without awaiting it so callers can record the `running` workflow transition as soon as prompt handoff is accepted instead of waiting for the full agent turn to complete on runtimes whose async replacement-session helpers resolve only after `agent_end`. When pi later invalidates that replacement-session context during successful prompt-end restoration, the helper suppresses the documented stale-extension-context rejection because the prompt was already accepted and late rethrow would surface a false orchestration failure. Falls back to `sendUserMessage(...)` only for non-replacement flows or runtimes that do not expose `sendMessage`. Runtime is O(n) in prompt length. Side effects are limited to hidden prompt delivery plus on-screen summary display.
910
914
  * @param[in] pi {ExtensionAPI} Handler-scoped extension API instance retained as the fallback dispatcher.
911
915
  * @param[in] content {string} Rendered prompt markdown.
916
+ * @param[in] summary {string} Command invocation summary text displayed on screen.
912
917
  * @param[in] context {unknown} Optional replacement-session helper context.
913
918
  * @return {Promise<void>} Promise representing eventual prompt-delivery completion.
914
- * @satisfies REQ-004, REQ-067, REQ-068, REQ-227, REQ-281
919
+ * @satisfies REQ-004, REQ-067, REQ-068, REQ-227, REQ-281, REQ-334, REQ-335, DES-016
915
920
  */
916
921
  function deliverPromptCommand(
917
922
  pi: ExtensionAPI,
918
923
  content: string,
924
+ summary: string,
919
925
  context?: unknown,
920
926
  ): Promise<void> {
921
927
  const replacementContext = context as {
928
+ sendMessage?: (
929
+ message: { customType: string; content: string; display: boolean },
930
+ options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" },
931
+ ) => Promise<void> | void;
922
932
  sendUserMessage?: (message: string) => Promise<void> | void;
923
933
  } | undefined;
934
+ const summaryMessage = {
935
+ customType: PROMPT_COMMAND_SUMMARY_CUSTOM_TYPE,
936
+ content: summary,
937
+ display: true,
938
+ };
939
+ const hiddenPromptMessage = {
940
+ customType: PROMPT_COMMAND_SUMMARY_CUSTOM_TYPE,
941
+ content,
942
+ display: false,
943
+ };
944
+ if (typeof replacementContext?.sendMessage === "function") {
945
+ replacementContext.sendMessage(summaryMessage);
946
+ return Promise.resolve(
947
+ replacementContext.sendMessage(hiddenPromptMessage, { triggerTurn: true }),
948
+ ).catch((error) => {
949
+ if (isStaleExtensionContextError(error)) {
950
+ return;
951
+ }
952
+ throw error;
953
+ });
954
+ }
955
+ if (typeof pi.sendMessage === "function") {
956
+ pi.sendMessage(summaryMessage);
957
+ pi.sendMessage(hiddenPromptMessage, { triggerTurn: true });
958
+ return Promise.resolve();
959
+ }
924
960
  if (typeof replacementContext?.sendUserMessage === "function") {
925
961
  return Promise.resolve(replacementContext.sendUserMessage(content)).catch((error) => {
926
962
  if (isStaleExtensionContextError(error)) {
@@ -3073,7 +3109,12 @@ function registerPromptCommands(
3073
3109
  },
3074
3110
  );
3075
3111
  renderPiUsereqStatus(statusController, promptContext);
3076
- const promptDelivery = deliverPromptCommand(pi, content, promptContext);
3112
+ const commandSummary = renderPromptCommandSummary(
3113
+ promptName,
3114
+ args,
3115
+ config,
3116
+ );
3117
+ const promptDelivery = deliverPromptCommand(pi, content, commandSummary, promptContext);
3077
3118
  transitionPromptWorkflowState(
3078
3119
  statusController,
3079
3120
  promptContext,