pi-usereq 0.4.0 → 0.6.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/.gitignore +3 -0
- package/CHANGELOG.md +41 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/{req → pi-usereq}/docs/REFERENCES.md +499 -491
- package/{req → pi-usereq}/docs/REQUIREMENTS.md +84 -62
- package/{req → pi-usereq}/docs/WORKFLOW.md +87 -102
- package/src/core/agent-tool-json.ts +42 -193
- package/src/core/compress-payload.ts +7 -15
- package/src/core/config.ts +39 -12
- package/src/core/extension-status.ts +94 -58
- package/src/core/find-payload.ts +21 -44
- package/src/core/pi-notify.ts +198 -11
- package/src/core/reference-payload.ts +6 -14
- package/src/core/runtime-project-paths.ts +3 -32
- package/src/core/settings-menu.ts +9 -4
- package/src/core/static-check.ts +35 -171
- package/src/core/token-counter.ts +3 -121
- package/src/index.ts +339 -180
- package/tests/attended-results-scenarios.ts +3 -13
- package/tests/cli-command-option-parity.test.ts +21 -12
- package/tests/debug-extension-harness.test.ts +20 -22
- package/tests/extension-registration.test.ts +394 -157
- package/tests/oracle-project.test.ts +8 -3
- package/tests/oracle-standalone.test.ts +7 -13
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_c.c.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_cpp.cpp.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_csharp.cs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_elixir.ex.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_go.go.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_haskell.hs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_java.java.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_javascript.js.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_kotlin.kt.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_lua.lua.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_perl.pl.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_php.php.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_python.py.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_ruby.rb.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_rust.rs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_scala.scala.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_shell.sh.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_swift.swift.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_typescript.ts.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_zig.zig.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_c.c.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_cpp.cpp.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_csharp.cs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_elixir.ex.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_go.go.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_haskell.hs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_java.java.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_javascript.js.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_kotlin.kt.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_lua.lua.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_perl.pl.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_php.php.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_python.py.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_ruby.rb.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_rust.rs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_scala.scala.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_shell.sh.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_swift.swift.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_typescript.ts.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_zig.zig.json +0 -5
|
@@ -357,16 +357,6 @@ function buildStandaloneScenarios(): AttendedScenario[] {
|
|
|
357
357
|
path.posix.join("standalone", "test-static-check-dummy", `${fixtureName}.json`),
|
|
358
358
|
["--test-static-check", "dummy", relativeFixturePath],
|
|
359
359
|
),
|
|
360
|
-
createStandaloneScenario(
|
|
361
|
-
`standalone/test-static-check-pylance/${fixtureName}`,
|
|
362
|
-
path.posix.join("standalone", "test-static-check-pylance", `${fixtureName}.json`),
|
|
363
|
-
["--test-static-check", "pylance", relativeFixturePath],
|
|
364
|
-
),
|
|
365
|
-
createStandaloneScenario(
|
|
366
|
-
`standalone/test-static-check-ruff/${fixtureName}`,
|
|
367
|
-
path.posix.join("standalone", "test-static-check-ruff", `${fixtureName}.json`),
|
|
368
|
-
["--test-static-check", "ruff", relativeFixturePath],
|
|
369
|
-
),
|
|
370
360
|
createStandaloneScenario(
|
|
371
361
|
`standalone/test-static-check-command/${fixtureName}`,
|
|
372
362
|
path.posix.join("standalone", "test-static-check-command", `${fixtureName}.json`),
|
|
@@ -470,14 +460,14 @@ function buildProjectScenarios(): AttendedScenario[] {
|
|
|
470
460
|
"--provider",
|
|
471
461
|
"claude:prompts",
|
|
472
462
|
"--enable-static-check",
|
|
473
|
-
"Python=
|
|
463
|
+
"Python=Command,git,--version",
|
|
474
464
|
],
|
|
475
465
|
cwd: projectBase,
|
|
476
466
|
normalize: createProjectNormalizer(projectBase),
|
|
477
467
|
cleanup: () => removePath(projectBase),
|
|
478
468
|
postAssert: () => {
|
|
479
469
|
const payload = JSON.parse(fs.readFileSync(getProjectConfigPath(projectBase), "utf8")) as UseReqConfig;
|
|
480
|
-
assert.deepEqual(payload["static-check"].Python, [{ module: "
|
|
470
|
+
assert.deepEqual(payload["static-check"].Python, [{ module: "Command", cmd: "git", params: ["--version"] }]);
|
|
481
471
|
},
|
|
482
472
|
};
|
|
483
473
|
},
|
|
@@ -488,7 +478,7 @@ function buildProjectScenarios(): AttendedScenario[] {
|
|
|
488
478
|
const script = [
|
|
489
479
|
"from pathlib import Path",
|
|
490
480
|
"from usereq.cli import save_config",
|
|
491
|
-
`save_config(Path(${JSON.stringify(projectBase)}), 'guidelines', 'docs', 'tests', ['src'], static_check_config={'Python': [{'module': '
|
|
481
|
+
`save_config(Path(${JSON.stringify(projectBase)}), 'guidelines', 'docs', 'tests', ['src'], static_check_config={'Python': [{'module': 'Command', 'cmd': 'git', 'params': ['--version']} ]})`,
|
|
492
482
|
].join("\n");
|
|
493
483
|
const result = runPythonInline(script, projectBase);
|
|
494
484
|
return createProjectNormalizer(projectBase)(toArchivedCliResult(result));
|
|
@@ -583,6 +583,14 @@ const TARGET_CASES: TargetParityCase[] = [
|
|
|
583
583
|
assert.equal(result.status, 1);
|
|
584
584
|
assert.match(result.stderr, /not an executable program/);
|
|
585
585
|
assert.ok(!fs.existsSync(getProjectConfigPath(projectBase)));
|
|
586
|
+
|
|
587
|
+
const removedModule = runNodeCli(
|
|
588
|
+
["--base", projectBase, "--enable-static-check", "Python=Ruff"],
|
|
589
|
+
projectBase,
|
|
590
|
+
);
|
|
591
|
+
assert.equal(removedModule.status, 1);
|
|
592
|
+
assert.match(removedModule.stderr, /unknown module/i);
|
|
593
|
+
assert.ok(!fs.existsSync(getProjectConfigPath(projectBase)));
|
|
586
594
|
},
|
|
587
595
|
},
|
|
588
596
|
{
|
|
@@ -594,16 +602,19 @@ const TARGET_CASES: TargetParityCase[] = [
|
|
|
594
602
|
"--base",
|
|
595
603
|
projectBase,
|
|
596
604
|
"--enable-static-check",
|
|
597
|
-
"Python=
|
|
605
|
+
"Python=Command,git,--version",
|
|
598
606
|
"--enable-static-check",
|
|
599
607
|
"C=Command,git,--version",
|
|
600
608
|
"--enable-static-check",
|
|
601
|
-
"Python=
|
|
609
|
+
"Python=Command,git,--help",
|
|
602
610
|
],
|
|
603
611
|
projectBase,
|
|
604
612
|
);
|
|
605
613
|
assert.equal(persisted.status, 0, persisted.stderr);
|
|
606
|
-
assert.deepEqual(getStaticCheckEntries(projectBase, "Python"), [
|
|
614
|
+
assert.deepEqual(getStaticCheckEntries(projectBase, "Python"), [
|
|
615
|
+
{ module: "Command", cmd: "git", params: ["--version"] },
|
|
616
|
+
{ module: "Command", cmd: "git", params: ["--help"] },
|
|
617
|
+
]);
|
|
607
618
|
assert.deepEqual(getStaticCheckEntries(projectBase, "C"), [{ module: "Command", cmd: "git", params: ["--version"] }]);
|
|
608
619
|
},
|
|
609
620
|
},
|
|
@@ -616,9 +627,9 @@ const TARGET_CASES: TargetParityCase[] = [
|
|
|
616
627
|
"--base",
|
|
617
628
|
projectBase,
|
|
618
629
|
"--enable-static-check",
|
|
619
|
-
"Python=
|
|
630
|
+
"Python=Command,git,--version",
|
|
620
631
|
"--enable-static-check",
|
|
621
|
-
"Python=
|
|
632
|
+
"Python=Command,git,--version",
|
|
622
633
|
"--enable-static-check",
|
|
623
634
|
"C=Command,git,--version",
|
|
624
635
|
"--enable-static-check",
|
|
@@ -627,7 +638,7 @@ const TARGET_CASES: TargetParityCase[] = [
|
|
|
627
638
|
projectBase,
|
|
628
639
|
);
|
|
629
640
|
assert.equal(result.status, 0, result.stderr);
|
|
630
|
-
assert.deepEqual(getStaticCheckEntries(projectBase, "Python"), [{ module: "
|
|
641
|
+
assert.deepEqual(getStaticCheckEntries(projectBase, "Python"), [{ module: "Command", cmd: "git", params: ["--version"] }]);
|
|
631
642
|
assert.deepEqual(getStaticCheckEntries(projectBase, "C"), [
|
|
632
643
|
{ module: "Command", cmd: "git", params: ["--version"] },
|
|
633
644
|
{ module: "Command", cmd: "git", params: ["--help"] },
|
|
@@ -641,7 +652,7 @@ const TARGET_CASES: TargetParityCase[] = [
|
|
|
641
652
|
const preloaded = {
|
|
642
653
|
...config,
|
|
643
654
|
"static-check": {
|
|
644
|
-
Python: [{ module: "
|
|
655
|
+
Python: [{ module: "Dummy", meta: "debug-note" } as unknown as Record<string, unknown>],
|
|
645
656
|
JavaScript: [{ module: "Command", cmd: "git", params: ["--version"] }],
|
|
646
657
|
} as unknown as UseReqConfig["static-check"],
|
|
647
658
|
} as UseReqConfig;
|
|
@@ -651,9 +662,7 @@ const TARGET_CASES: TargetParityCase[] = [
|
|
|
651
662
|
"--base",
|
|
652
663
|
projectBase,
|
|
653
664
|
"--enable-static-check",
|
|
654
|
-
"Python=
|
|
655
|
-
"--enable-static-check",
|
|
656
|
-
"Python=Ruff",
|
|
665
|
+
"Python=Command,git,--version",
|
|
657
666
|
"--enable-static-check",
|
|
658
667
|
"JavaScript=Command,git,--help",
|
|
659
668
|
],
|
|
@@ -661,8 +670,8 @@ const TARGET_CASES: TargetParityCase[] = [
|
|
|
661
670
|
);
|
|
662
671
|
assert.equal(result.status, 0, result.stderr);
|
|
663
672
|
assert.deepEqual(getStaticCheckEntries(projectBase, "Python"), [
|
|
664
|
-
{ module: "
|
|
665
|
-
{ module: "
|
|
673
|
+
{ module: "Dummy" },
|
|
674
|
+
{ module: "Command", cmd: "git", params: ["--version"] },
|
|
666
675
|
]);
|
|
667
676
|
assert.deepEqual(getStaticCheckEntries(projectBase, "JavaScript"), [
|
|
668
677
|
{ module: "Command", cmd: "git", params: ["--version"] },
|
|
@@ -165,9 +165,9 @@ test("inspectExtension surfaces agent-oriented find tool descriptions and schema
|
|
|
165
165
|
|
|
166
166
|
assert.ok(filesFind, "missing files-find tool");
|
|
167
167
|
assert.ok(find, "missing find tool");
|
|
168
|
-
assert.match(filesFind.description ?? "", /
|
|
168
|
+
assert.match(filesFind.description ?? "", /token-optimized JSON payload/);
|
|
169
169
|
assert.ok(filesFind.promptGuidelines?.some((line) => line.includes("Supported tags [Typescript]:")));
|
|
170
|
-
assert.match(String((filesFind.parameters as { description?: string } | undefined)?.description ?? ""), /
|
|
170
|
+
assert.match(String((filesFind.parameters as { description?: string } | undefined)?.description ?? ""), /Static supported-tag matrices are documented in tool registration metadata/);
|
|
171
171
|
assert.match(find.description ?? "", /configured project source directories/);
|
|
172
172
|
assert.ok(find.promptGuidelines?.some((line) => line.includes("Regex rule:")));
|
|
173
173
|
assert.match(String((find.parameters as { description?: string } | undefined)?.description ?? ""), /Regex matches construct names only/);
|
|
@@ -185,7 +185,7 @@ test("inspectExtension surfaces agent-oriented compression tool descriptions and
|
|
|
185
185
|
|
|
186
186
|
assert.ok(filesCompress, "missing files-compress tool");
|
|
187
187
|
assert.ok(compress, "missing compress tool");
|
|
188
|
-
assert.match(filesCompress.description ?? "", /
|
|
188
|
+
assert.match(filesCompress.description ?? "", /summary, repository, files, and execution sections/);
|
|
189
189
|
assert.ok(filesCompress.promptGuidelines?.some((line) => line.includes("Line-number behavior:")));
|
|
190
190
|
assert.match(String((filesCompress.parameters as { description?: string } | undefined)?.description ?? ""), /structured compressed lines/);
|
|
191
191
|
assert.match(compress.description ?? "", /configured project source directories/);
|
|
@@ -212,7 +212,7 @@ test("inspectExtension surfaces structured utility tool descriptions and schema
|
|
|
212
212
|
assert.ok(docsCheck, "missing docs-check tool");
|
|
213
213
|
assert.ok(gitWtCreate, "missing git-wt-create tool");
|
|
214
214
|
|
|
215
|
-
assert.match(gitPath.description ?? "", /
|
|
215
|
+
assert.match(gitPath.description ?? "", /token-optimized JSON payload/);
|
|
216
216
|
assert.ok(gitPath.promptGuidelines?.some((line) => line.includes("Output contract:")));
|
|
217
217
|
assert.match(String((gitPath.parameters as { description?: string } | undefined)?.description ?? ""), /path_value/);
|
|
218
218
|
|
|
@@ -220,9 +220,9 @@ test("inspectExtension surfaces structured utility tool descriptions and schema
|
|
|
220
220
|
assert.ok(filesStaticCheck.promptGuidelines?.some((line) => line.includes("Failure contract:")));
|
|
221
221
|
assert.match(String((filesStaticCheck.parameters as { description?: string } | undefined)?.description ?? ""), /configured checker modules/);
|
|
222
222
|
|
|
223
|
-
assert.match(gitCheck.description ?? "", /
|
|
223
|
+
assert.match(gitCheck.description ?? "", /token-optimized JSON payload/);
|
|
224
224
|
assert.ok(gitCheck.promptGuidelines?.some((line) => line.includes("Behavior contract:")));
|
|
225
|
-
assert.match(String((gitCheck.parameters as { description?: string } | undefined)?.description ?? ""), /
|
|
225
|
+
assert.match(String((gitCheck.parameters as { description?: string } | undefined)?.description ?? ""), /aggregate repository status fields/);
|
|
226
226
|
|
|
227
227
|
assert.match(docsCheck.description ?? "", /remediation prompt commands/);
|
|
228
228
|
assert.ok(docsCheck.promptGuidelines?.some((line) => line.includes("Specialization trigger:")));
|
|
@@ -246,18 +246,18 @@ test("replaySessionStart captures active tools, statuses, and cwd semantics", as
|
|
|
246
246
|
assert.deepEqual([...report.activeTools].sort(), ["git-path", "static-check"]);
|
|
247
247
|
assert.equal(report.effectiveCtxCwd, projectBase);
|
|
248
248
|
assert.equal(report.effectiveProcessCwd, projectBase);
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
);
|
|
253
|
-
assert.match(
|
|
254
|
-
status,
|
|
255
|
-
/<accent>context:<\/accent><bg-from-fg-accent><warning>CLEAR<\/warning><\/bg-from-fg-accent>/,
|
|
256
|
-
);
|
|
257
|
-
assert.match(status, /<accent>elapsed:<\/accent><warning>idle<\/warning>/);
|
|
258
|
-
assert.match(status, /<accent>last:<\/accent><warning>N\/A<\/warning>/);
|
|
259
|
-
assert.match(status, /<accent>beep:<\/accent><warning>none<\/warning>/);
|
|
249
|
+
const normalizedBasePath = projectBase.split(path.sep).join("/");
|
|
250
|
+
assert.match(status, new RegExp(`<accent>base:</accent><warning>${normalizedBasePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}</warning>`));
|
|
251
|
+
assert.match(status, /<accent>context:<\/accent><bg-from-fg-accent><warning>◀ CLEAR ▶ <\/warning><\/bg-from-fg-accent>/);
|
|
252
|
+
assert.match(status, /<accent>elapsed:<\/accent><warning> ⏱︎ --:-- ⚑ --:-- ⌛︎ --:--<\/warning>/);
|
|
253
|
+
assert.match(status, /<accent>beep:<\/accent><warning>end,esc,err<\/warning>/);
|
|
260
254
|
assert.match(status, /<accent>sound:<\/accent><warning>none<\/warning>/);
|
|
255
|
+
assert.match(status, /<accent>pushover:<\/accent><warning>off<\/warning>/);
|
|
256
|
+
assert.doesNotMatch(status, /<accent>docs:<\/accent>/);
|
|
257
|
+
assert.doesNotMatch(status, /<accent>src:<\/accent>/);
|
|
258
|
+
assert.doesNotMatch(status, /<accent>tests:<\/accent>/);
|
|
259
|
+
assert.doesNotMatch(status, /<accent>git:<\/accent>/);
|
|
260
|
+
assert.doesNotMatch(status, /<accent>tools:<\/accent>/);
|
|
261
261
|
assert.equal(report.ui.notifications.length, 0);
|
|
262
262
|
} finally {
|
|
263
263
|
fs.rmSync(projectBase, { recursive: true, force: true });
|
|
@@ -294,7 +294,8 @@ test("replayCommand captures interactive UI side effects", async () => {
|
|
|
294
294
|
|
|
295
295
|
assert.deepEqual(report.activeTools, []);
|
|
296
296
|
assert.ok(report.ui.notifications.some((entry) => entry.message === "Disabled all configurable active tools"));
|
|
297
|
-
assert.
|
|
297
|
+
assert.doesNotMatch(report.ui.statuses["pi-usereq"] ?? "", /<accent>tools:<\/accent>/);
|
|
298
|
+
assert.match(report.ui.statuses["pi-usereq"] ?? "", /<accent>elapsed:<\/accent><warning> ⏱︎ --:-- ⚑ --:-- ⌛︎ --:--<\/warning>/);
|
|
298
299
|
} finally {
|
|
299
300
|
fs.rmSync(projectBase, { recursive: true, force: true });
|
|
300
301
|
}
|
|
@@ -307,9 +308,7 @@ test("replayTool captures tool results and cwd semantics", async () => {
|
|
|
307
308
|
const toolResult = report.toolResult as {
|
|
308
309
|
content?: Array<{ type: string; text?: string }>;
|
|
309
310
|
details?: {
|
|
310
|
-
request: { project_base_path: string };
|
|
311
311
|
result: { path_value: string; path_present: boolean };
|
|
312
|
-
runtime_paths: { git_path: string };
|
|
313
312
|
execution: { code: number };
|
|
314
313
|
};
|
|
315
314
|
};
|
|
@@ -317,8 +316,7 @@ test("replayTool captures tool results and cwd semantics", async () => {
|
|
|
317
316
|
assert.equal(report.effectiveCtxCwd, projectBase);
|
|
318
317
|
assert.equal(report.effectiveProcessCwd, projectBase);
|
|
319
318
|
assert.deepEqual(JSON.parse(toolResult.content?.[0]?.text ?? "{}"), JSON.parse(JSON.stringify(toolResult.details)));
|
|
320
|
-
assert.equal(toolResult.details?.
|
|
321
|
-
assert.equal(toolResult.details?.result.path_value, toolResult.details?.runtime_paths.git_path);
|
|
319
|
+
assert.equal(toolResult.details?.result.path_value, projectBase);
|
|
322
320
|
assert.equal(toolResult.details?.result.path_present, true);
|
|
323
321
|
assert.equal(toolResult.details?.execution.code, 0);
|
|
324
322
|
} finally {
|