pi-usereq 0.63.0 → 0.65.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.
@@ -17,7 +17,7 @@ import {
17
17
  comparePiUsereqStartupToolNames,
18
18
  type PiUsereqStartupToolName,
19
19
  } from "./pi-usereq-tools.js";
20
- import { formatContextFileSize, type ContextFileSizeFacts } from "./context-file-size.js";
20
+ import { computeContextOccupancyFacts, formatContextFileSize, sumEnabledContextFileTokens, type ContextFileSizeFacts } from "./context-file-size.js";
21
21
  import { formatRuntimePathForDisplay, normalizeRelativeDirContract } from "./path-context.js";
22
22
  import type {
23
23
  PromptCommandExecutionPlan,
@@ -387,28 +387,35 @@ export const PROMPT_COMMAND_SUMMARY_CUSTOM_TYPE = "pi-usereq-prompt-command";
387
387
 
388
388
  /**
389
389
  * @brief Builds the on-screen command invocation summary for one bundled prompt-backed `req-<prompt>` command.
390
- * @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. When measured context-file size facts are supplied, every enabled existing context file in the `context files` field is rendered as `name(<chars>c/<tokens>t)`; without facts, or for enabled missing files, the plain `name` form is rendered. Static-check languages are emitted in canonical `DEFAULT_STATIC_CHECK_LANGUAGES` order; enabled tools are emitted in documented menu order via `comparePiUsereqStartupToolNames`. The `context files`, `static code checks`, and `enabled tools` fields render the literal `none` placeholder whenever their respective enabled-item list is empty so the summary never shows a blank value. Sections are emitted in the order `Command:`, `Configuration:` with its bullet list, then `User's Request:`, each separated by one blank line. Runtime is O(l + t log t) where l is language count and t is enabled-tool count. No external state is mutated.
390
+ * @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. When measured context-file size facts are supplied, every enabled existing context file in the `context files` field is rendered as `name(<chars>c/<tokens>t)`; when the enabled existing token total contributes tokens, the field additionally appends the `[<percent>% context]` occupancy suffix against the selected model max input context (or `[<percent>%/1.0M* context]` with the documented fallback); without facts, or for enabled missing files, the plain `name` form is rendered. Static-check languages are emitted in canonical `DEFAULT_STATIC_CHECK_LANGUAGES` order; enabled tools are emitted in documented menu order via `comparePiUsereqStartupToolNames`. The `context files`, `static code checks`, and `enabled tools` fields render the literal `none` placeholder whenever their respective enabled-item list is empty so the summary never shows a blank value. Sections are emitted in the order `Command:`, `Configuration:` with its bullet list, then `User's Request:`, each separated by one blank line. Runtime is O(l + t log t) where l is language count and t is enabled-tool count. No external state is mutated.
391
391
  * @param[in] promptName {string} Bundled prompt name without the `req-` prefix.
392
392
  * @param[in] args {string} User request arguments passed to the slash command.
393
393
  * @param[in] config {UseReqConfig} Effective project configuration supplying directory, git, static-check, and tool fields.
394
394
  * @param[in] contextFileSizes {Record<string, ContextFileSizeFacts> | undefined} Optional measured context-file size facts keyed by canonical file name, consumed for `context files` size suffixes.
395
+ * @param[in] maxContextTokens {number | undefined} Selected model max input context tokens consumed by the occupancy suffix; undefined selects the documented 1,000,000-token fallback.
395
396
  * @return {string} Multi-line command invocation summary text.
396
- * @satisfies REQ-335, REQ-336, REQ-337, REQ-338, REQ-353, REQ-377
397
+ * @satisfies REQ-335, REQ-336, REQ-337, REQ-338, REQ-353, REQ-377, REQ-402, REQ-403, REQ-404, REQ-407
397
398
  */
398
399
  export function renderPromptCommandSummary(
399
400
  promptName: string,
400
401
  args: string,
401
402
  config: UseReqConfig,
402
403
  contextFileSizes?: Record<string, ContextFileSizeFacts>,
404
+ maxContextTokens?: number | undefined,
403
405
  ): string {
404
- const contextFiles = CONTEXT_FILE_DESCRIPTORS
406
+ const contextSegments = CONTEXT_FILE_DESCRIPTORS
405
407
  .filter((descriptor) => config[descriptor.flagKey])
406
408
  .map((descriptor) => {
407
409
  const baseName = descriptor.fileName.replace(/\.md$/, "").toLowerCase();
408
410
  const facts = contextFileSizes?.[descriptor.fileName];
409
411
  return facts?.exists ? `${baseName}(${formatContextFileSize(facts)})` : baseName;
410
412
  })
411
- .join(", ") || "none";
413
+ .join(", ");
414
+ const totalContextTokens = contextFileSizes ? sumEnabledContextFileTokens(config, contextFileSizes) : 0;
415
+ const contextFiles = (contextSegments || "none")
416
+ + (contextSegments && totalContextTokens > 0
417
+ ? ` ${computeContextOccupancyFacts(totalContextTokens, maxContextTokens).suffix}`
418
+ : "");
412
419
  const enabledLanguages = DEFAULT_STATIC_CHECK_LANGUAGES
413
420
  .filter((language) => config["static-check"][language]?.enabled === "enable")
414
421
  .join(", ") || "none";
@@ -196,14 +196,34 @@ function defaultJsTiktokenModuleLoader(): JsTiktokenModule {
196
196
 
197
197
  let jsTiktokenModuleLoader: () => JsTiktokenModule = defaultJsTiktokenModuleLoader;
198
198
 
199
+ const cachedTokenCounterEncodings = new Map<string, TokenCounterEncoding>();
200
+
201
+ /**
202
+ * @brief Resolves one shared tokenizer encoding for a `TokenCounter` construction.
203
+ * @details Checks the process-scoped per-encoding cache first and constructs the `js-tiktoken` encoding only on the first request per encoding name, so repeated `TokenCounter` construction across the `files-tokens` runner, canonical-doc counting, and context-file measurement reuses one parsed encoder instead of re-parsing the bundled BPE ranks each time. Runtime is O(1) after the first construction for the encoding and dominated by the single deferred `getEncoding` construction otherwise. Side effect: mutates the module-local encoding cache on first resolution per encoding name.
204
+ * @param[in] encodingName {string} `js-tiktoken` encoding identifier.
205
+ * @return {TokenCounterEncoding} Cached or newly constructed tokenizer encoding.
206
+ * @throws {ReqError} Propagates the deterministic unavailable-dependency failure when `js-tiktoken` cannot be loaded.
207
+ */
208
+ function resolveTokenCounterEncoding(encodingName: string): TokenCounterEncoding {
209
+ const cachedEncoding = cachedTokenCounterEncodings.get(encodingName);
210
+ if (cachedEncoding) {
211
+ return cachedEncoding;
212
+ }
213
+ const encoding = loadJsTiktokenModule().getEncoding(encodingName);
214
+ cachedTokenCounterEncodings.set(encodingName, encoding);
215
+ return encoding;
216
+ }
217
+
199
218
  /**
200
219
  * @brief Overrides the `js-tiktoken` loader for tests.
201
- * @details Enables deterministic dependency-failure tests without mutating repository dependencies on disk. Runtime is O(1). Side effects are limited to module-local test state.
220
+ * @details Enables deterministic dependency-failure tests without mutating repository dependencies on disk. Clears the process-scoped encoding cache so every loader swap observes fresh module behavior instead of encoders constructed by the previous loader. Runtime is O(e) in cached encoding count. Side effects are limited to module-local test state and cache reset.
202
221
  * @param[in] loader {(() => JsTiktokenModule) | undefined} Replacement loader, or `undefined` to restore the default loader.
203
222
  * @return {void} No return value.
204
223
  */
205
224
  export function setJsTiktokenModuleLoaderForTests(loader?: () => JsTiktokenModule): void {
206
225
  jsTiktokenModuleLoader = loader ?? defaultJsTiktokenModuleLoader;
226
+ cachedTokenCounterEncodings.clear();
207
227
  }
208
228
 
209
229
  /**
@@ -233,23 +253,23 @@ function loadJsTiktokenModule(): JsTiktokenModule {
233
253
 
234
254
  /**
235
255
  * @brief Encapsulates one tokenizer instance for repeated token counting.
236
- * @details Caches a `js-tiktoken` encoding object so multiple documents can be counted without repeated encoding lookup. Counting cost is O(n) in content length. The class mutates only instance state during construction.
256
+ * @details Resolves the process-scoped shared encoder for the requested encoding so multiple documents and multiple counter instances are counted without repeated encoding construction; the first construction per encoding name parses the BPE ranks once and every later `TokenCounter` reuses it through the module-local cache. Counting cost is O(n) in content length. The class mutates only instance state during construction.
237
257
  */
238
258
  export class TokenCounter {
239
259
  /**
240
260
  * @brief Stores the tokenizer implementation used for subsequent counts.
241
- * @details The field holds the encoder returned by `getEncoding`. Access complexity is O(1). The value is initialized once per instance.
261
+ * @details Holds the cached encoder resolved through the per-encoding process cache. Access complexity is O(1); construction is O(1) after the first resolution for the encoding name.
242
262
  */
243
263
  private encoding: TokenCounterEncoding;
244
264
 
245
265
  /**
246
266
  * @brief Initializes a token counter for one encoding family.
247
- * @details Resolves the named tokenizer once and reuses it across `countTokens` calls. Construction complexity is O(1) relative to caller-controlled input size. Side effects are limited to instance initialization.
267
+ * @details Resolves the shared cached tokenizer for the encoding name, constructing the underlying `js-tiktoken` encoding at most once per encoding name per process so repeated constructions from token tools and context-file measurement are constant-time cache hits. Side effects are limited to instance initialization plus the optional first-time encoding cache mutation.
248
268
  * @param[in] encodingName {string} `js-tiktoken` encoding identifier. Defaults to `cl100k_base`.
249
269
  * @return {TokenCounter} New token counter instance.
250
270
  */
251
271
  constructor(encodingName = TOKEN_COUNTER_ENCODING) {
252
- this.encoding = loadJsTiktokenModule().getEncoding(encodingName);
272
+ this.encoding = resolveTokenCounterEncoding(encodingName);
253
273
  }
254
274
 
255
275
  /**
@@ -427,7 +447,7 @@ function buildCountFileMetricsResult(filePath: string, content: string, counter:
427
447
 
428
448
  /**
429
449
  * @brief Counts tokens, characters, bytes, and lines for one in-memory content string.
430
- * @details Instantiates a `TokenCounter`, tokenizes the supplied text, and pairs the result with raw character length, UTF-8 byte size, and logical line count. Runtime is O(n). No filesystem I/O occurs.
450
+ * @details Resolves the process-cached shared `TokenCounter` encoder for the encoding, tokenizes the supplied text once, and pairs the result with raw character length, UTF-8 byte size, and logical line count. Runtime is O(n) after the one-time per-encoding encoder construction. No filesystem I/O occurs.
431
451
  * @param[in] content {string} Text payload to measure.
432
452
  * @param[in] encodingName {string} Tokenizer identifier. Defaults to `cl100k_base`.
433
453
  * @return {{ tokens: number; chars: number; bytes: number; lines: number }} Aggregate metrics for the supplied content.
package/src/index.ts CHANGED
@@ -84,8 +84,10 @@ import {
84
84
  type PiUsereqStartupToolName,
85
85
  } from "./core/pi-usereq-tools.js";
86
86
  import {
87
+ computeContextOccupancyFacts,
87
88
  formatContextFileSize,
88
89
  measureContextFileSizes,
90
+ sumEnabledContextFileTokens,
89
91
  type ContextFileName,
90
92
  type ContextFileSizeFacts,
91
93
  } from "./core/context-file-size.js";
@@ -160,6 +162,7 @@ import {
160
162
  getPiUsereqRuntimeSoundLevel,
161
163
  isStaleExtensionContextError,
162
164
  renderPiUsereqStatus,
165
+ resolveModelContextWindowTokens,
163
166
  setPiUsereqRuntimeSoundLevel,
164
167
  setPiUsereqStatusConfig,
165
168
  setPiUsereqWorkflowState,
@@ -3397,6 +3400,7 @@ function registerPromptCommands(
3397
3400
  });
3398
3401
  const projectBase = getProjectBase(commandCwd);
3399
3402
  const config = loadProjectConfig(commandCwd);
3403
+ const maxContextTokens = resolveModelContextWindowTokens(statusController.state.contextUsage);
3400
3404
  transitionPromptWorkflowState(
3401
3405
  statusController,
3402
3406
  ctx,
@@ -3427,6 +3431,7 @@ function registerPromptCommands(
3427
3431
  },
3428
3432
  originalModel,
3429
3433
  originalThinkingLevel,
3434
+ maxContextTokens,
3430
3435
  );
3431
3436
  const content = renderPrompt(
3432
3437
  promptName,
@@ -3470,6 +3475,7 @@ function registerPromptCommands(
3470
3475
  args,
3471
3476
  config,
3472
3477
  measureContextFileSizes(projectBase, config),
3478
+ maxContextTokens,
3473
3479
  );
3474
3480
  const promptDelivery = deliverPromptCommand(pi, content, commandSummary, promptContext);
3475
3481
  transitionPromptWorkflowState(
@@ -4545,44 +4551,56 @@ async function configureStaticCheckMenu(
4545
4551
  }
4546
4552
 
4547
4553
  /**
4548
- * @brief Summarizes the `Context Files` flag state with measured sizes for the top-level menu value column.
4549
- * @details Renders the three context-file flags as compact `name:on|off` segments in the documented order, appending `(<chars>c/<tokens>t)` measured size facts to every enabled segment so the top-level row exposes a runtime estimate of the injected context payload while disabled segments stay plain `name:off`. Runtime is O(1) in segment count. No external state is mutated.
4554
+ * @brief Summarizes the `Context Files` flag state with measured sizes and context occupancy for the top-level menu value column.
4555
+ * @details Renders the three context-file flags as compact `name:on|off` segments in the documented order, appending `(<chars>c/<tokens>t)` measured size facts to every enabled segment, then appends the occupancy suffix computed from the enabled existing token total against the selected model max input context (`[<percent>% context]`, or `[<percent>%/1.0M* context]` with the documented fallback) whenever that total contributes tokens, while disabled segments stay plain `name:off`. Runtime is O(1) in segment count. No external state is mutated.
4550
4556
  * @param[in] config {UseReqConfig} Effective project configuration.
4551
4557
  * @param[in] sizes {Record<ContextFileName, ContextFileSizeFacts>} Measured context-file size facts keyed by canonical file name.
4552
- * @return {string} Compact `Context Files` summary string.
4553
- * @satisfies REQ-327, REQ-376
4558
+ * @param[in] maxContextTokens {number | undefined} Selected model max input context tokens; undefined selects the documented 1,000,000-token fallback.
4559
+ * @return {string} Compact `Context Files` summary string with the occupancy suffix.
4560
+ * @satisfies REQ-327, REQ-376, REQ-402, REQ-403, REQ-404, REQ-405
4554
4561
  */
4555
4562
  function formatContextFilesSummary(
4556
4563
  config: UseReqConfig,
4557
4564
  sizes: Record<ContextFileName, ContextFileSizeFacts>,
4565
+ maxContextTokens?: number | undefined,
4558
4566
  ): string {
4559
4567
  const segments = [
4560
4568
  `requirements:${config["context-files-requirements"] ? `on(${formatContextFileSize(sizes["REQUIREMENTS.md"])})` : "off"}`,
4561
4569
  `references:${config["context-files-references"] ? `on(${formatContextFileSize(sizes["REFERENCES.md"])})` : "off"}`,
4562
4570
  `workflow:${config["context-files-workflow"] ? `on(${formatContextFileSize(sizes["WORKFLOW.md"])})` : "off"}`,
4563
4571
  ];
4564
- return segments.join(" \u2022 ");
4572
+ const summary = segments.join(" \u2022 ");
4573
+ const totalTokens = sumEnabledContextFileTokens(config, sizes);
4574
+ return totalTokens > 0
4575
+ ? `${summary} ${computeContextOccupancyFacts(totalTokens, maxContextTokens).suffix}`
4576
+ : summary;
4565
4577
  }
4566
4578
 
4567
4579
  /**
4568
4580
  * @brief Builds the shared settings-menu choices for the `Context Files` submenu.
4569
- * @details Exposes one inline toggle row per context file in the documented `REQUIREMENTS.md`, `REFERENCES.md`, `WORKFLOW.md` order whose value renders `on|off • <chars>c/<tokens>t` measured size facts plus a value-less subtree-local `Reset defaults` row. Cycle values embed the same measured facts so inline toggling keeps the size estimate visible while persisting the on|off state. Runtime is O(1) in row count. No external state is mutated.
4581
+ * @details Exposes one inline toggle row per context file in the documented `REQUIREMENTS.md`, `REFERENCES.md`, `WORKFLOW.md` order whose value renders `on|off • <chars>c/<tokens>t` measured size facts plus the context-occupancy suffix computed from the enabled existing token total against the selected model max input context, followed by a value-less subtree-local `Reset defaults` row. Cycle values embed the same measured facts and occupancy suffix so inline toggling keeps the size estimate visible while persisting the on|off state. Runtime is O(1) in row count. No external state is mutated.
4570
4582
  * @param[in] config {UseReqConfig} Effective project configuration.
4571
4583
  * @param[in] sizes {Record<ContextFileName, ContextFileSizeFacts>} Measured context-file size facts keyed by canonical file name.
4584
+ * @param[in] maxContextTokens {number | undefined} Selected model max input context tokens; undefined selects the documented 1,000,000-token fallback.
4572
4585
  * @return {PiUsereqSettingsMenuChoice[]} Ordered `Context Files` submenu choices.
4573
- * @satisfies REQ-327, REQ-328, REQ-333, REQ-375
4586
+ * @satisfies REQ-327, REQ-328, REQ-333, REQ-375, REQ-403, REQ-404, REQ-406
4574
4587
  */
4575
4588
  function buildContextFilesMenuChoices(
4576
4589
  config: UseReqConfig,
4577
4590
  sizes: Record<ContextFileName, ContextFileSizeFacts>,
4591
+ maxContextTokens?: number | undefined,
4578
4592
  ): PiUsereqSettingsMenuChoice[] {
4593
+ const totalTokens = sumEnabledContextFileTokens(config, sizes);
4594
+ const occupancySuffix = totalTokens > 0
4595
+ ? ` ${computeContextOccupancyFacts(totalTokens, maxContextTokens).suffix}`
4596
+ : "";
4579
4597
  const buildRow = (
4580
4598
  id: "context-files-requirements" | "context-files-references" | "context-files-workflow",
4581
4599
  fileName: ContextFileName,
4582
4600
  description: string,
4583
4601
  ): PiUsereqSettingsMenuChoice => {
4584
- const sizedOn = `on \u2022 ${formatContextFileSize(sizes[fileName])}`;
4585
- const sizedOff = `off \u2022 ${formatContextFileSize(sizes[fileName])}`;
4602
+ const sizedOn = `on \u2022 ${formatContextFileSize(sizes[fileName])}${occupancySuffix}`;
4603
+ const sizedOff = `off \u2022 ${formatContextFileSize(sizes[fileName])}${occupancySuffix}`;
4586
4604
  return {
4587
4605
  id,
4588
4606
  label: fileName,
@@ -4619,13 +4637,15 @@ function buildContextFilesMenuChoices(
4619
4637
  * @param[in] ctx {ExtensionCommandContext} Active command context.
4620
4638
  * @param[in,out] config {UseReqConfig} Mutable effective project configuration.
4621
4639
  * @param[in] onConfigChange {() => void} Shared persistence-plus-status callback.
4640
+ * @param[in] maxContextTokens {number | undefined} Selected model max input context tokens used by the submenu occupancy suffix; undefined selects the documented 1,000,000-token fallback.
4622
4641
  * @return {Promise<void>} Promise resolved when the submenu closes.
4623
- * @satisfies REQ-327, REQ-328, REQ-333
4642
+ * @satisfies REQ-327, REQ-328, REQ-333, REQ-406
4624
4643
  */
4625
4644
  async function configureContextFilesMenu(
4626
4645
  ctx: ExtensionCommandContext,
4627
4646
  config: UseReqConfig,
4628
4647
  onConfigChange: () => void,
4648
+ maxContextTokens?: number | undefined,
4629
4649
  ): Promise<void> {
4630
4650
  const contextFileSizes = measureContextFileSizes(getProjectBase(ctx.cwd), config);
4631
4651
  const setFlag = (flagKey: "context-files-requirements" | "context-files-references" | "context-files-workflow", enabled: boolean): void => {
@@ -4635,9 +4655,9 @@ async function configureContextFilesMenu(
4635
4655
  };
4636
4656
  let focusedChoiceId: string | undefined;
4637
4657
  while (true) {
4638
- const choice = await showPiUsereqSettingsMenu(ctx, "Context Files", buildContextFilesMenuChoices(config, contextFileSizes), {
4658
+ const choice = await showPiUsereqSettingsMenu(ctx, "Context Files", buildContextFilesMenuChoices(config, contextFileSizes, maxContextTokens), {
4639
4659
  initialSelectedId: focusedChoiceId,
4640
- getChoices: () => buildContextFilesMenuChoices(config, contextFileSizes),
4660
+ getChoices: () => buildContextFilesMenuChoices(config, contextFileSizes, maxContextTokens),
4641
4661
  onChange: (choiceId, newValue) => {
4642
4662
  if (choiceId === "context-files-requirements") {
4643
4663
  setFlag("context-files-requirements", newValue.startsWith("on"));
@@ -4688,12 +4708,14 @@ async function configureContextFilesMenu(
4688
4708
  * @details Serializes primary configuration actions into right-valued menu rows consumed by the shared settings-menu renderer, including the `Context Files` injection toggles, automatic git-commit mode, effective prompt-command worktree state, notification summary, debug summary, locked worktree rows when automatic git commit is disabled, and display-only local plus global config paths. Runtime is O(s) in source-directory count. No external state is mutated.
4689
4709
  * @param[in] cwd {string} Current working directory.
4690
4710
  * @param[in] config {UseReqConfig} Effective project configuration.
4711
+ * @param[in] maxContextTokens {number | undefined} Selected model max input context tokens used by the `Context Files` occupancy suffix; undefined selects the documented 1,000,000-token fallback.
4691
4712
  * @return {PiUsereqSettingsMenuChoice[]} Ordered top-level menu choices.
4692
- * @satisfies REQ-006, REQ-031, REQ-137, REQ-150, REQ-151, REQ-152, REQ-162, REQ-190, REQ-191, REQ-197, REQ-204, REQ-205, REQ-212, REQ-215, REQ-216, REQ-236, REQ-237, REQ-238, REQ-239, REQ-240, REQ-314, REQ-318, REQ-319, REQ-320, REQ-326, REQ-376
4713
+ * @satisfies REQ-006, REQ-031, REQ-137, REQ-150, REQ-151, REQ-152, REQ-162, REQ-190, REQ-191, REQ-197, REQ-204, REQ-205, REQ-212, REQ-215, REQ-216, REQ-236, REQ-237, REQ-238, REQ-239, REQ-240, REQ-314, REQ-318, REQ-319, REQ-320, REQ-326, REQ-376, REQ-405
4693
4714
  */
4694
4715
  function buildPiUsereqMenuChoices(
4695
4716
  cwd: string,
4696
4717
  config: UseReqConfig,
4718
+ maxContextTokens?: number | undefined,
4697
4719
  ): PiUsereqSettingsMenuChoice[] {
4698
4720
  const autoGitCommitDisabled = config.AUTO_GIT_COMMIT === "disable";
4699
4721
  const effectiveGitWorktreeEnabled = resolveEffectiveGitWorktreeEnabled(
@@ -4722,7 +4744,7 @@ function buildPiUsereqMenuChoices(
4722
4744
  {
4723
4745
  id: "context-files",
4724
4746
  label: "Context Files",
4725
- value: formatContextFilesSummary(config, measureContextFileSizes(cwd, config)),
4747
+ value: formatContextFilesSummary(config, measureContextFileSizes(cwd, config), maxContextTokens),
4726
4748
  description: "Toggle injection of REQUIREMENTS.md, REFERENCES.md, and WORKFLOW.md into prompt context through `%%CONTEXT_FILES%%`.",
4727
4749
  },
4728
4750
  {
@@ -4865,6 +4887,7 @@ async function configurePiUsereq(
4865
4887
  });
4866
4888
  let config = loadProjectConfig(ctx.cwd);
4867
4889
  const projectBase = getProjectBase(ctx.cwd);
4890
+ const maxContextTokens = resolveModelContextWindowTokens(statusController.state.contextUsage);
4868
4891
  const initialShortcut = config["notify-sound-toggle-shortcut"];
4869
4892
  const persistConfigChange = () => {
4870
4893
  Object.assign(config, normalizeConfigPaths(projectBase, config));
@@ -4878,10 +4901,10 @@ async function configurePiUsereq(
4878
4901
  const choice = await showPiUsereqSettingsMenu(
4879
4902
  ctx,
4880
4903
  "pi-usereq",
4881
- buildPiUsereqMenuChoices(ctx.cwd, config),
4904
+ buildPiUsereqMenuChoices(ctx.cwd, config, maxContextTokens),
4882
4905
  {
4883
4906
  initialSelectedId: focusedChoiceId,
4884
- getChoices: () => buildPiUsereqMenuChoices(ctx.cwd, config),
4907
+ getChoices: () => buildPiUsereqMenuChoices(ctx.cwd, config, maxContextTokens),
4885
4908
  onChange: (choiceId, newValue) => {
4886
4909
  if (choiceId === "auto-git-commit") {
4887
4910
  config.AUTO_GIT_COMMIT = newValue === "enable" ? "enable" : "disable";
@@ -4934,7 +4957,7 @@ async function configurePiUsereq(
4934
4957
  continue;
4935
4958
  }
4936
4959
  if (choice === "context-files") {
4937
- await configureContextFilesMenu(ctx, config, persistConfigChange);
4960
+ await configureContextFilesMenu(ctx, config, persistConfigChange, maxContextTokens);
4938
4961
  continue;
4939
4962
  }
4940
4963
  if (choice === "auto-git-commit") {
@@ -5079,7 +5102,7 @@ async function configurePiUsereq(
5079
5102
  { label: "Document directory", previousValue: config["docs-dir"], nextValue: defaultConfig["docs-dir"] },
5080
5103
  { label: "Source-code directories", previousValue: config["src-dir"].join(", "), nextValue: defaultConfig["src-dir"].join(", ") },
5081
5104
  { label: "Unit tests directory", previousValue: config["tests-dir"], nextValue: defaultConfig["tests-dir"] },
5082
- { label: "Context Files", previousValue: formatContextFilesSummary(config, measureContextFileSizes(ctx.cwd, config)), nextValue: formatContextFilesSummary(defaultConfig, measureContextFileSizes(ctx.cwd, defaultConfig)) },
5105
+ { label: "Context Files", previousValue: formatContextFilesSummary(config, measureContextFileSizes(ctx.cwd, config), maxContextTokens), nextValue: formatContextFilesSummary(defaultConfig, measureContextFileSizes(ctx.cwd, defaultConfig), maxContextTokens) },
5083
5106
  { label: "Auto git commit", previousValue: config.AUTO_GIT_COMMIT, nextValue: defaultConfig.AUTO_GIT_COMMIT },
5084
5107
  { label: "Git worktree", previousValue: config.GIT_WORKTREE_ENABLED, nextValue: defaultConfig.GIT_WORKTREE_ENABLED },
5085
5108
  { label: "Worktree prefix", previousValue: config.GIT_WORKTREE_PREFIX, nextValue: defaultConfig.GIT_WORKTREE_PREFIX },
@@ -0,0 +1 @@
1
+ v0.8.0
@@ -102,7 +102,7 @@ Use for: string/pattern searches inside code bodies, cross-file references, conf
102
102
  ## Execution Protocol (Global vs Local)
103
103
  You must manage the execution flow using two distinct methods:
104
104
  - **Global Roadmap** (*check-list*):
105
- - You MUST maintain a *check-list* internally with `2` Steps (one item per Step).
105
+ - You MUST maintain a *check-list* internally with `3` Steps (one item per Step).
106
106
  - **Do NOT** use the *task-list tool* for this high-level roadmap.
107
107
  - **Local Sub-tasks** (Tool Usage):
108
108
  - If a *task-list tool* is available, use it **exclusively** to manage granular sub-tasks *within* a specific step (e.g., in Step X: "1. Edit file A", "2. Edit file B"; or in Step Y: "1. Fix test K", "2. Fix test L").
@@ -123,13 +123,22 @@ During the execution flow you MUST follow these directives:
123
123
 
124
124
 
125
125
  ## Steps
126
- Create internally a *check-list* for the **Global Roadmap** including all the numbered steps below: `1..2`, and start following the roadmap at the same time, executing the instructions of Step 1. If a tool call is required in Step 1, invoke it immediately; otherwise proceed to Step 1 without additional commentary. Do not add extra intent-adjustment checks unless explicitly listed in the Steps section.
126
+ Create internally a *check-list* for the **Global Roadmap** including all the numbered steps below: `1..3`, and start following the roadmap at the same time, executing the instructions of Step 1. If a tool call is required in Step 1, invoke it immediately; otherwise proceed to Step 1 without additional commentary. Do not add extra intent-adjustment checks unless explicitly listed in the Steps section.
127
127
  1. Analyze the [User Request](#users-request)
128
128
  - Using [User Request](#users-request) as a unified semantic framework, extract all directly and tangentially related information from `%%DOC_PATH%%/REQUIREMENTS.md`, `%%DOC_PATH%%/WORKFLOW.md` and `%%DOC_PATH%%/REFERENCES.md`, prioritizing high recall to capture every borderline connection across both sources, to identify the most likely related files and functions based on explicit evidence, and treat any uncertain links as candidates without claiming completeness, then analyze the involved source code from %%SRC_PATHS%% to answer the [User Request](#users-request), ensuring compliance with %%GUIDELINES_FILES%% documents if present.
129
129
  - Do NOT create or modify tests in this workflow. If you cite tests as evidence, treat them as read-only artifacts.
130
130
  - Read %%GUIDELINES_FILES%% files and ensure any suggested follow-up changes would conform to those **guidelines**. Do not check unrelated **guidelines**.
131
- 2. Present results
131
+ 2. Generate the follow-up prompt text from the analysis outcome
132
+ - Using the Step 1 analysis outcome, classify the result against `%%DOC_PATH%%/REQUIREMENTS.md` into exactly one branch:
133
+ - IF the analysis identified an implementation behavior that conflicts with requirements (the source code must change while `%%DOC_PATH%%/REQUIREMENTS.md` stays unchanged), GENERATE the exact prompt text to pass to the LLM Agent with the `/req-fix` command, including the defect summary, the affected requirement IDs, and concrete evidence (file paths with line numbers).
134
+ - ELSE IF the analysis identified changes needed to BOTH the source code and `%%DOC_PATH%%/REQUIREMENTS.md`, GENERATE the exact prompt text to pass to the LLM Agent with the `/req-change` command, including the requested change description, the affected requirement IDs, and concrete evidence (file paths with line numbers).
135
+ - ELSE IF the analysis identified source-code modifications with the intent of improving or adjusting the sources (internals, structure, maintainability, or performance) while `%%DOC_PATH%%/REQUIREMENTS.md` stays unchanged and NO implementation behavior conflicting with requirements was identified, GENERATE the exact prompt text to pass to the LLM Agent with the `/req-refactor` command, including the improvement objective, the affected source paths/symbols, the requirement IDs constraining the behavior to preserve, and concrete evidence (file paths with line numbers).
136
+ - ELSE (no source-code or requirements modifications are required), do NOT generate any follow-up prompt text.
137
+ - Each generated follow-up prompt text (`/req-fix`, `/req-change`, or `/req-refactor`) MUST be printed ONLY when the analysis identified its corresponding trigger in the classification above, and MUST NOT be printed in any other case; when generated, carry it into Step 3 for printing under the `## **Next Workflow**` report section.
138
+ - Do NOT execute the generated follow-up prompt and do NOT apply any fix or repository modification in this workflow; this workflow remains read-only.
139
+ 3. Present results
132
140
  - PRINT, in the response, the final analysis report for a human reader using clear, easily understandable sentences and readable Markdown formatting that highlight key findings, file paths, and concise evidence. Use the fixed report schema: ## **Outcome**, ## **Requirement Delta**, ## **Design Delta**, ## **Implementation Delta**, ## **Verification Delta**, ## **Evidence**, ## **Assumptions**, ## **Next Workflow**. Final line MUST be exactly: STATUS: OK or STATUS: ERROR.
141
+ - Include the Step 2 generated follow-up prompt text under `## **Next Workflow**` ONLY when Step 2 generated it; omit the follow-up prompt text entirely in all other cases.
133
142
 
134
143
  <h2 id="users-request">User's Request</h2>
135
144
  %%ARGS%%
@@ -39,7 +39,7 @@ In scope: static analysis of user-visible behavior from %%SRC_PATHS%% and relate
39
39
  - Write root `README.md` in English.
40
40
  - Do not perform unrelated edits.
41
41
  - Analyze user-visible implementation changes, including new features, CLI parameters/options, GUI interactions, distributed APIs, and configuration-file schema updates when present.
42
- - Validate whether the current root `README.md` is aligned with implementation evidence; identify exact sections to update first, then update only missing, outdated, or incorrect user-facing content in those sections.
42
+ - Validate the current root `README.md` exhaustively against implementation evidence: enumerate every section, validate each sentence, and record a per-sentence conformance outcome before editing; then update only missing, outdated, or incorrect user-facing content.
43
43
  - Parse [User Request](#users-request) (`%%ARGS%%`) as explicit additional-edit directives, using the same anchor-based reference model used by `write.md`, and execute those directives in the same scoped README update pass.
44
44
  - Keep non-analysis documentary sections unchanged, including document headers, versioning metadata, context/scope descriptions, personal motivations, related projects, and high-level conceptual or graphical descriptions that do not alter interface usage.
45
45
  - Preserve existing README structure and formatting patterns (section order, heading hierarchy, bullet/list style, table style) whenever possible.
@@ -136,9 +136,12 @@ Create internally a *check-list* for the **Global Roadmap** including all the nu
136
136
  - Use repository evidence only; for each finding, collect file paths and line ranges.
137
137
  - Derive a compact "README coverage list" of user-visible behavior that MUST appear in root `README.md`.
138
138
  2. Validate and update root `README.md`
139
- - Read the current root `README.md` and compare it with the README coverage list from Step 1.
140
- - Identify and list the exact `README.md` sections impacted by the detected user-visible implementation changes and explicit additional edits from [User Request](#users-request) before editing.
139
+ - Read the current root `README.md` and enumerate ALL its sections and headings in document order to fix the complete validation surface.
140
+ - Validate `README.md` sentence by sentence, section by section, in document order: for every sentence, verify its content against repository implementation evidence and record exactly one outcome: `CONFORMING`, `OUTDATED`, or `UNSUPPORTED`.
141
+ - Classify non-analysis documentary sections (headers, versioning, motivations, related projects, high-level graphics) as `NOT-ANALYZED-BY-DESIGN` instead of sentence-level validation; never skip any other part or section.
142
+ - Identify and list the exact `README.md` sections impacted by the detected user-visible implementation changes, the recorded validation outcomes, and explicit additional edits from [User Request](#users-request) before editing.
141
143
  - Update only the identified sections so `README.md` reflects the current externally visible behavior and usage flows.
144
+ - Completeness gate: do NOT proceed to Step 3 until every enumerated section and every sentence has a recorded outcome and every `OUTDATED` or `UNSUPPORTED` sentence in analysis sections is corrected or removed.
142
145
  - Keep all non-analysis documentary sections unchanged (e.g., headers, versioning, context/scope narratives, motivations, related projects, high-level graphics/descriptions not tied to interface behavior).
143
146
  - Keep content focused on user interaction, setup, commands, interfaces, and observable outputs.
144
147
  - Do NOT add internal implementation details, internal architecture, private symbol names, or algorithm internals.