pi-usereq 0.10.0 → 0.12.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/CHANGELOG.md +66 -0
- package/README.md +6 -6
- package/package.json +1 -1
- package/pi-usereq/docs/REFERENCES.md +861 -704
- package/pi-usereq/docs/REQUIREMENTS.md +152 -95
- package/pi-usereq/docs/WORKFLOW.md +228 -65
- package/scripts/lib/extension-debug-harness.ts +2 -2
- package/scripts/tool-args-to-params.ts +2 -2
- package/src/cli.ts +12 -12
- package/src/core/debug-runtime.ts +2 -2
- package/src/core/extension-status.ts +98 -36
- package/src/core/pi-notify.ts +5 -5
- package/src/core/pi-usereq-tools.ts +4 -2
- package/src/core/prompt-command-catalog.ts +4 -5
- package/src/core/prompt-command-runtime.ts +347 -42
- package/src/core/prompts.ts +0 -2
- package/src/core/req-references-command.ts +175 -0
- package/src/core/req-reset-command.ts +323 -0
- package/src/core/resources.ts +6 -23
- package/src/core/runtime-project-paths.ts +21 -1
- package/src/core/settings-menu.ts +85 -28
- package/src/core/tool-runner.ts +26 -6
- package/src/index.ts +530 -104
- package/tests/attended-results-scenarios.ts +5 -5
- package/tests/cli-command-option-parity.test.ts +25 -25
- package/tests/debug-extension-harness.test.ts +8 -2
- package/tests/extension-registration.test.ts +1109 -76
- package/tests/oracle-project.test.ts +4 -4
- package/tests/oracle-standalone.test.ts +5 -5
- package/src/core/reference-payload.ts +0 -752
- package/src/resources/prompts/references.md +0 -64
- /package/tests/fixtures_attended_results/project/{references.json → summarize.json} +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_c.c.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_cpp.cpp.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_csharp.cs.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_elixir.ex.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_go.go.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_haskell.hs.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_java.java.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_javascript.js.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_kotlin.kt.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_lua.lua.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_perl.pl.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_php.php.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_python.py.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_ruby.rb.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_rust.rs.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_scala.scala.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_shell.sh.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_swift.swift.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_typescript.ts.json +0 -0
- /package/tests/fixtures_attended_results/standalone/{files-references → files-summarize}/fixture_zig.zig.json +0 -0
|
@@ -9,7 +9,7 @@ import { Container, SettingsList, Text, type Component, type SettingItem, type S
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @brief Describes one selectable pi-usereq settings-menu choice.
|
|
12
|
-
* @details Stores the stable action identifier, left-column label, optional label and value tone overrides, optional disabled state, right-column current value, and bottom-line description consumed by the shared settings-menu renderer. The interface is compile-time only and introduces no runtime cost.
|
|
12
|
+
* @details Stores the stable action identifier, left-column label, optional label and value tone overrides, optional disabled state, right-column current value, optional inline-cycle values, and bottom-line description consumed by the shared settings-menu renderer. The interface is compile-time only and introduces no runtime cost.
|
|
13
13
|
*/
|
|
14
14
|
export interface PiUsereqSettingsMenuChoice {
|
|
15
15
|
id: string;
|
|
@@ -18,6 +18,7 @@ export interface PiUsereqSettingsMenuChoice {
|
|
|
18
18
|
value: string;
|
|
19
19
|
valueTone?: "default" | "dim";
|
|
20
20
|
disabled?: boolean;
|
|
21
|
+
values?: readonly string[];
|
|
21
22
|
description: string;
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -35,12 +36,12 @@ export interface PiUsereqSettingsMenuBridge {
|
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* @brief Describes optional behavior overrides for one settings-menu render.
|
|
38
|
-
* @details Carries the caller-selected initial focus row
|
|
39
|
-
* preserve selection after an in-place toggle or value edit. The interface is
|
|
40
|
-
* compile-time only and introduces no runtime cost.
|
|
39
|
+
* @details Carries the caller-selected initial focus row, the optional dynamic choice supplier used to rebuild dependent rows after inline toggles, and the optional inline-change callback used to persist `SettingsList` value cycles without closing the menu. The interface is compile-time only and introduces no runtime cost.
|
|
41
40
|
*/
|
|
42
41
|
export interface PiUsereqSettingsMenuOptions {
|
|
43
42
|
initialSelectedId?: string;
|
|
43
|
+
getChoices?: () => PiUsereqSettingsMenuChoice[];
|
|
44
|
+
onChange?: (choiceId: string, newValue: string) => void;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
/**
|
|
@@ -162,7 +163,7 @@ function createImmediateSelectionComponent(choiceId: string, done: (value?: stri
|
|
|
162
163
|
|
|
163
164
|
/**
|
|
164
165
|
* @brief Builds `SettingsList` items from one menu-choice vector.
|
|
165
|
-
* @details Copies labels, current values, label-tone overrides, value-tone overrides, disabled-state semantics, and descriptions into `SettingItem` records
|
|
166
|
+
* @details Copies labels, current values, label-tone overrides, value-tone overrides, disabled-state semantics, inline-cycle values, and descriptions into `SettingItem` records. Non-disabled rows with `values` cycle inline on `Enter` or `Space`, while other non-disabled rows resolve the outer custom UI through the immediate submenu bridge. Runtime is O(n) in choice count. No external state is mutated.
|
|
166
167
|
* @param[in] theme {PiUsereqSettingsTheme} Callback-local pi theme adapter.
|
|
167
168
|
* @param[in] choices {PiUsereqSettingsMenuChoice[]} Ordered menu-choice vector.
|
|
168
169
|
* @param[in] done {(value?: string) => void} Outer custom-UI completion callback.
|
|
@@ -182,19 +183,49 @@ function buildSettingItems(
|
|
|
182
183
|
currentValue: choice.valueTone === "dim"
|
|
183
184
|
? theme.fg("dim", choice.value)
|
|
184
185
|
: choice.value,
|
|
185
|
-
|
|
186
|
+
values: choice.disabled || choice.values === undefined
|
|
187
|
+
? undefined
|
|
188
|
+
: [...choice.values],
|
|
189
|
+
submenu: choice.disabled || choice.values !== undefined
|
|
186
190
|
? undefined
|
|
187
191
|
: () => createImmediateSelectionComponent(choice.id, done),
|
|
188
192
|
}));
|
|
189
193
|
}
|
|
190
194
|
|
|
195
|
+
/**
|
|
196
|
+
* @brief Writes one best-effort selected row index into a `SettingsList` instance.
|
|
197
|
+
* @details Uses reflective access so pi-usereq can preserve focus across menu re-renders without depending on the private field at compile time. Runtime is O(1). Side effect: mutates the underlying `SettingsList` selection state when the field exists.
|
|
198
|
+
* @param[in,out] settingsList {SettingsList} Mutable settings-list instance.
|
|
199
|
+
* @param[in] selectedIndex {number} Zero-based row index to restore.
|
|
200
|
+
* @return {void} No return value.
|
|
201
|
+
*/
|
|
202
|
+
function setSettingsListSelectedIndex(
|
|
203
|
+
settingsList: SettingsList,
|
|
204
|
+
selectedIndex: number,
|
|
205
|
+
): void {
|
|
206
|
+
Reflect.set(settingsList as object, "selectedIndex", selectedIndex);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* @brief Reads the current selected row index from a `SettingsList` instance.
|
|
211
|
+
* @details Uses reflective access so pi-usereq can report the current focused row through the offline bridge without referencing the private field in the static type system. Runtime is O(1). No external state is mutated.
|
|
212
|
+
* @param[in] settingsList {SettingsList} Settings-list instance.
|
|
213
|
+
* @return {number | undefined} Zero-based selected row index when available.
|
|
214
|
+
*/
|
|
215
|
+
function getSettingsListSelectedIndex(
|
|
216
|
+
settingsList: SettingsList,
|
|
217
|
+
): number | undefined {
|
|
218
|
+
const selectedIndex = Reflect.get(settingsList as object, "selectedIndex");
|
|
219
|
+
return typeof selectedIndex === "number" ? selectedIndex : undefined;
|
|
220
|
+
}
|
|
221
|
+
|
|
191
222
|
/**
|
|
192
223
|
* @brief Renders one shared pi-usereq settings menu and resolves the selected action.
|
|
193
|
-
* @details Uses `ctx.ui.custom(...)` plus `SettingsList` so every configuration menu shares pi.dev styling, right-aligned current values, circular scrolling, bottom-line descriptions,
|
|
224
|
+
* @details Uses `ctx.ui.custom(...)` plus `SettingsList` so every configuration menu shares pi.dev styling, right-aligned current values, circular scrolling, bottom-line descriptions, optional disabled rows, and inline toggle cycles that do not close the menu. When callers provide `getChoices(...)`, dependent rows are rebuilt after inline changes while preserving focus on the changed row. The returned custom component also exposes an offline bridge for deterministic tests and debug harnesses. Runtime is O(n) in visible choice count plus user interaction cost. Side effects are limited to transient custom-UI rendering and caller-owned inline-change callbacks.
|
|
194
225
|
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
195
226
|
* @param[in] title {string} Menu title displayed in the heading and offline bridge.
|
|
196
227
|
* @param[in] choices {PiUsereqSettingsMenuChoice[]} Ordered menu-choice vector.
|
|
197
|
-
* @param[in] options {PiUsereqSettingsMenuOptions | undefined} Optional initial-focus override.
|
|
228
|
+
* @param[in] options {PiUsereqSettingsMenuOptions | undefined} Optional initial-focus override plus inline-change behavior.
|
|
198
229
|
* @return {Promise<string | undefined>} Selected choice identifier or `undefined` when cancelled.
|
|
199
230
|
* @satisfies REQ-151, REQ-152, REQ-153, REQ-154, REQ-156, REQ-192
|
|
200
231
|
*/
|
|
@@ -211,22 +242,43 @@ export async function showPiUsereqSettingsMenu(
|
|
|
211
242
|
0,
|
|
212
243
|
0,
|
|
213
244
|
);
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
245
|
+
const spacer = new Text("", 0, 0);
|
|
246
|
+
let currentChoices = options.getChoices?.() ?? choices;
|
|
247
|
+
let settingsList: SettingsList;
|
|
248
|
+
|
|
249
|
+
const buildSettingsList = (
|
|
250
|
+
menuChoices: PiUsereqSettingsMenuChoice[],
|
|
251
|
+
selectedChoiceId?: string,
|
|
252
|
+
): SettingsList => {
|
|
253
|
+
const nextSettingsList = new SettingsList(
|
|
254
|
+
buildSettingItems(theme, menuChoices, done),
|
|
255
|
+
Math.min(Math.max(menuChoices.length, 1), 12),
|
|
256
|
+
buildPiUsereqSettingsListTheme(theme),
|
|
257
|
+
(choiceId, newValue) => {
|
|
258
|
+
options.onChange?.(choiceId, newValue);
|
|
259
|
+
rebuildMenu(choiceId);
|
|
260
|
+
},
|
|
261
|
+
() => done(undefined),
|
|
262
|
+
);
|
|
263
|
+
const initialSelectedIndex = selectedChoiceId === undefined
|
|
264
|
+
? 0
|
|
265
|
+
: menuChoices.findIndex((choice) => choice.id === selectedChoiceId);
|
|
266
|
+
if (initialSelectedIndex >= 0) {
|
|
267
|
+
setSettingsListSelectedIndex(nextSettingsList, initialSelectedIndex);
|
|
268
|
+
}
|
|
269
|
+
return nextSettingsList;
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const rebuildMenu = (selectedChoiceId?: string): void => {
|
|
273
|
+
currentChoices = options.getChoices?.() ?? choices;
|
|
274
|
+
settingsList = buildSettingsList(currentChoices, selectedChoiceId);
|
|
275
|
+
container.clear();
|
|
276
|
+
container.addChild(titleText);
|
|
277
|
+
container.addChild(spacer);
|
|
278
|
+
container.addChild(settingsList);
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
rebuildMenu(options.initialSelectedId);
|
|
230
282
|
|
|
231
283
|
const component: PiUsereqSettingsMenuComponent = {
|
|
232
284
|
render(width: number): string[] {
|
|
@@ -242,13 +294,18 @@ export async function showPiUsereqSettingsMenu(
|
|
|
242
294
|
},
|
|
243
295
|
__piUsereqSettingsMenu: {
|
|
244
296
|
title,
|
|
245
|
-
choices
|
|
246
|
-
|
|
297
|
+
get choices(): PiUsereqSettingsMenuChoice[] {
|
|
298
|
+
return currentChoices;
|
|
299
|
+
},
|
|
300
|
+
get selectedChoiceId(): string | undefined {
|
|
301
|
+
const selectedIndex = getSettingsListSelectedIndex(settingsList) ?? 0;
|
|
302
|
+
return currentChoices[selectedIndex]?.id;
|
|
303
|
+
},
|
|
247
304
|
selectByLabel(label: string): boolean {
|
|
248
|
-
const choice =
|
|
305
|
+
const choice = currentChoices.find(
|
|
249
306
|
(candidate) => candidate.label === label || candidate.id === label,
|
|
250
307
|
);
|
|
251
|
-
if (!choice
|
|
308
|
+
if (!choice) {
|
|
252
309
|
return false;
|
|
253
310
|
}
|
|
254
311
|
done(choice.id);
|
package/src/core/tool-runner.ts
CHANGED
|
@@ -239,15 +239,15 @@ export function runFilesTokens(files: string[]): ToolResult {
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
/**
|
|
242
|
-
* @brief Generates the monolithic
|
|
243
|
-
* @details Delegates to `generateMarkdown(...)`, keeps output paths relative to the caller cwd, and returns the Python-compatible markdown document through stdout. Runtime is O(F + S). Side effects are limited to filesystem reads and optional stderr logging.
|
|
242
|
+
* @brief Generates the monolithic summary markdown for explicit files.
|
|
243
|
+
* @details Delegates to `generateMarkdown(...)`, keeps output paths relative to the caller cwd, and returns the Python-compatible summary markdown document through stdout. Runtime is O(F + S). Side effects are limited to filesystem reads and optional stderr logging.
|
|
244
244
|
* @param[in] files {string[]} Explicit file paths.
|
|
245
245
|
* @param[in] cwd {string} Base directory used for relative output paths. Defaults to `process.cwd()`.
|
|
246
246
|
* @param[in] verbose {boolean} When `true`, emit per-file progress diagnostics to stderr.
|
|
247
247
|
* @return {ToolResult} Successful tool result containing monolithic markdown.
|
|
248
248
|
* @satisfies REQ-011, REQ-076, REQ-077, REQ-078, REQ-079
|
|
249
249
|
*/
|
|
250
|
-
export function
|
|
250
|
+
export function runFilesSummarize(files: string[], cwd = process.cwd(), verbose = false): ToolResult {
|
|
251
251
|
try {
|
|
252
252
|
return ok(`${generateMarkdown(files, verbose, cwd)}\n`);
|
|
253
253
|
} catch (error) {
|
|
@@ -286,8 +286,8 @@ export function runFilesSearch(argsList: string[], enableLineNumbers = false, ve
|
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
/**
|
|
289
|
-
* @brief Generates the monolithic
|
|
290
|
-
* @details Resolves the project base, collects configured source files, prepends the repository file-structure markdown block, and returns the Python-compatible
|
|
289
|
+
* @brief Generates the monolithic summary markdown for configured source directories.
|
|
290
|
+
* @details Resolves the project base, collects configured source files, prepends the repository file-structure markdown block, and returns the Python-compatible summary document through stdout. Runtime is O(F log F + S). Side effects are limited to filesystem reads and optional stderr logging.
|
|
291
291
|
* @param[in] projectBase {string} Candidate project root.
|
|
292
292
|
* @param[in] config {UseReqConfig | undefined} Optional preloaded configuration.
|
|
293
293
|
* @param[in] verbose {boolean} When `true`, emit per-file diagnostics to stderr.
|
|
@@ -295,7 +295,7 @@ export function runFilesSearch(argsList: string[], enableLineNumbers = false, ve
|
|
|
295
295
|
* @throws {ReqError} Throws when no source files are found or no file can be analyzed.
|
|
296
296
|
* @satisfies REQ-014, REQ-076, REQ-077, REQ-078, REQ-079
|
|
297
297
|
*/
|
|
298
|
-
export function
|
|
298
|
+
export function runSummarize(projectBase: string, config?: UseReqConfig, verbose = false): ToolResult {
|
|
299
299
|
const [base, srcDirs] = resolveProjectSrcDirs(projectBase, config);
|
|
300
300
|
const files = collectSourceFiles(srcDirs, base);
|
|
301
301
|
if (files.length === 0) fail("Error: no source files found in configured directories.", 1);
|
|
@@ -308,6 +308,26 @@ export function runReferences(projectBase: string, config?: UseReqConfig, verbos
|
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
/**
|
|
312
|
+
* @brief Writes configured project references markdown to the canonical docs file.
|
|
313
|
+
* @details Reuses `runSummarize(...)` to generate the same file-structure-plus-summary markdown, resolves `<docs-dir>/REFERENCES.md` from the effective project configuration, overwrites the target file, and returns the status-only stdout `success`. Runtime is O(F log F + S) plus one file write. Side effects include filesystem writes.
|
|
314
|
+
* @param[in] projectBase {string} Candidate project root.
|
|
315
|
+
* @param[in] config {UseReqConfig | undefined} Optional preloaded configuration.
|
|
316
|
+
* @param[in] verbose {boolean} When `true`, emit per-file diagnostics to stderr during summary generation.
|
|
317
|
+
* @return {ToolResult} Successful tool result containing the status-only stdout payload.
|
|
318
|
+
* @throws {ReqError} Throws when source discovery, summary generation, or file writing fails.
|
|
319
|
+
* @satisfies REQ-293
|
|
320
|
+
*/
|
|
321
|
+
export function runReferences(projectBase: string, config?: UseReqConfig, verbose = false): ToolResult {
|
|
322
|
+
const base = resolveProjectBase(projectBase);
|
|
323
|
+
const effectiveConfig = config ?? loadConfig(base);
|
|
324
|
+
const docsDir = effectiveConfig["docs-dir"].replace(/[/\\]+$/, "");
|
|
325
|
+
const referencesPath = path.join(base, docsDir, "REFERENCES.md");
|
|
326
|
+
const summarizeResult = runSummarize(base, effectiveConfig, verbose);
|
|
327
|
+
fs.writeFileSync(referencesPath, summarizeResult.stdout, "utf8");
|
|
328
|
+
return ok("success\n");
|
|
329
|
+
}
|
|
330
|
+
|
|
311
331
|
/**
|
|
312
332
|
* @brief Compresses all source files from configured source directories.
|
|
313
333
|
* @details Resolves the project base, collects source files, and delegates to `compressFiles`. Runtime is O(F + S). Side effects are limited to filesystem reads and optional stderr logging.
|