pi-usereq 0.5.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/CHANGELOG.md +10 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/pi-usereq/docs/REFERENCES.md +364 -393
- package/pi-usereq/docs/REQUIREMENTS.md +20 -19
- package/pi-usereq/docs/WORKFLOW.md +21 -29
- package/src/core/agent-tool-json.ts +42 -193
- package/src/core/compress-payload.ts +7 -15
- package/src/core/find-payload.ts +21 -44
- package/src/core/reference-payload.ts +6 -14
- package/src/core/token-counter.ts +3 -121
- package/src/index.ts +64 -100
- package/tests/debug-extension-harness.test.ts +15 -21
- package/tests/extension-registration.test.ts +23 -86
|
@@ -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:")));
|
|
@@ -247,18 +247,15 @@ test("replaySessionStart captures active tools, statuses, and cwd semantics", as
|
|
|
247
247
|
assert.equal(report.effectiveCtxCwd, projectBase);
|
|
248
248
|
assert.equal(report.effectiveProcessCwd, projectBase);
|
|
249
249
|
const normalizedBasePath = projectBase.split(path.sep).join("/");
|
|
250
|
-
assert.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
),
|
|
254
|
-
);
|
|
255
|
-
assert.match(
|
|
256
|
-
status,
|
|
257
|
-
/<accent>context:<\/accent><bg-from-fg-accent><warning>CLEAR<\/warning><\/bg-from-fg-accent>/,
|
|
258
|
-
);
|
|
259
|
-
assert.match(status, /<accent>et:<\/accent><warning>▶idle,↻--:--,Σ--:--<\/warning>/);
|
|
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>/);
|
|
260
253
|
assert.match(status, /<accent>beep:<\/accent><warning>end,esc,err<\/warning>/);
|
|
261
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>/);
|
|
262
259
|
assert.doesNotMatch(status, /<accent>git:<\/accent>/);
|
|
263
260
|
assert.doesNotMatch(status, /<accent>tools:<\/accent>/);
|
|
264
261
|
assert.equal(report.ui.notifications.length, 0);
|
|
@@ -298,7 +295,7 @@ test("replayCommand captures interactive UI side effects", async () => {
|
|
|
298
295
|
assert.deepEqual(report.activeTools, []);
|
|
299
296
|
assert.ok(report.ui.notifications.some((entry) => entry.message === "Disabled all configurable active tools"));
|
|
300
297
|
assert.doesNotMatch(report.ui.statuses["pi-usereq"] ?? "", /<accent>tools:<\/accent>/);
|
|
301
|
-
assert.match(report.ui.statuses["pi-usereq"] ?? "", /<accent>
|
|
298
|
+
assert.match(report.ui.statuses["pi-usereq"] ?? "", /<accent>elapsed:<\/accent><warning> ⏱︎ --:-- ⚑ --:-- ⌛︎ --:--<\/warning>/);
|
|
302
299
|
} finally {
|
|
303
300
|
fs.rmSync(projectBase, { recursive: true, force: true });
|
|
304
301
|
}
|
|
@@ -311,9 +308,7 @@ test("replayTool captures tool results and cwd semantics", async () => {
|
|
|
311
308
|
const toolResult = report.toolResult as {
|
|
312
309
|
content?: Array<{ type: string; text?: string }>;
|
|
313
310
|
details?: {
|
|
314
|
-
request: { project_base_path: string };
|
|
315
311
|
result: { path_value: string; path_present: boolean };
|
|
316
|
-
runtime_paths: { git_path: string };
|
|
317
312
|
execution: { code: number };
|
|
318
313
|
};
|
|
319
314
|
};
|
|
@@ -321,8 +316,7 @@ test("replayTool captures tool results and cwd semantics", async () => {
|
|
|
321
316
|
assert.equal(report.effectiveCtxCwd, projectBase);
|
|
322
317
|
assert.equal(report.effectiveProcessCwd, projectBase);
|
|
323
318
|
assert.deepEqual(JSON.parse(toolResult.content?.[0]?.text ?? "{}"), JSON.parse(JSON.stringify(toolResult.details)));
|
|
324
|
-
assert.equal(toolResult.details?.
|
|
325
|
-
assert.equal(toolResult.details?.result.path_value, toolResult.details?.runtime_paths.git_path);
|
|
319
|
+
assert.equal(toolResult.details?.result.path_value, projectBase);
|
|
326
320
|
assert.equal(toolResult.details?.result.path_present, true);
|
|
327
321
|
assert.equal(toolResult.details?.execution.code, 0);
|
|
328
322
|
} finally {
|
|
@@ -606,13 +606,13 @@ test("token tools register agent-oriented descriptions and schema details", () =
|
|
|
606
606
|
assert.ok(filesTokens, "missing files-tokens tool");
|
|
607
607
|
assert.ok(tokens, "missing tokens tool");
|
|
608
608
|
|
|
609
|
-
assert.match(filesTokens.description ?? "", /
|
|
609
|
+
assert.match(filesTokens.description ?? "", /token-optimized JSON payload/);
|
|
610
610
|
assert.ok(filesTokens.promptGuidelines?.some((line) => line.includes("Output contract:")));
|
|
611
|
-
assert.match(String((filesTokens.parameters as { description?: string } | undefined)?.description ?? ""), /
|
|
611
|
+
assert.match(String((filesTokens.parameters as { description?: string } | undefined)?.description ?? ""), /token metrics/);
|
|
612
612
|
|
|
613
613
|
assert.match(tokens.description ?? "", /canonical docs/);
|
|
614
|
-
assert.ok(tokens.promptGuidelines?.some((line) => line.includes("
|
|
615
|
-
assert.match(String((tokens.parameters as { description?: string } | undefined)?.description ?? ""), /
|
|
614
|
+
assert.ok(tokens.promptGuidelines?.some((line) => line.includes("registration metadata")));
|
|
615
|
+
assert.match(String((tokens.parameters as { description?: string } | undefined)?.description ?? ""), /token-optimized JSON shape/);
|
|
616
616
|
});
|
|
617
617
|
|
|
618
618
|
test("reference tools register agent-oriented descriptions and schema details", () => {
|
|
@@ -624,7 +624,7 @@ test("reference tools register agent-oriented descriptions and schema details",
|
|
|
624
624
|
assert.ok(filesReferences, "missing files-references tool");
|
|
625
625
|
assert.ok(references, "missing references tool");
|
|
626
626
|
|
|
627
|
-
assert.match(filesReferences.description ?? "", /
|
|
627
|
+
assert.match(filesReferences.description ?? "", /summary, repository, files, and execution sections/);
|
|
628
628
|
assert.ok(filesReferences.promptGuidelines?.some((line) => line.includes("Numeric contract:")));
|
|
629
629
|
assert.ok(filesReferences.promptGuidelines?.some((line) => line.includes("Behavior contract:")));
|
|
630
630
|
assert.match(String((filesReferences.parameters as { description?: string } | undefined)?.description ?? ""), /structured Doxygen fields/);
|
|
@@ -644,11 +644,11 @@ test("find tools register agent-oriented descriptions and schema details", () =>
|
|
|
644
644
|
assert.ok(filesFind, "missing files-find tool");
|
|
645
645
|
assert.ok(find, "missing find tool");
|
|
646
646
|
|
|
647
|
-
assert.match(filesFind.description ?? "", /
|
|
647
|
+
assert.match(filesFind.description ?? "", /token-optimized JSON payload/);
|
|
648
648
|
assert.ok(filesFind.promptGuidelines?.some((line) => line.includes("Regex rule:")));
|
|
649
649
|
assert.ok(filesFind.promptGuidelines?.some((line) => line.includes("Supported tags [Typescript]:")));
|
|
650
650
|
assert.ok(filesFind.promptGuidelines?.some((line) => line.includes("Supported tags [Python]:")));
|
|
651
|
-
assert.match(String((filesFind.parameters as { description?: string } | undefined)?.description ?? ""), /
|
|
651
|
+
assert.match(String((filesFind.parameters as { description?: string } | undefined)?.description ?? ""), /Static supported-tag matrices are documented in tool registration metadata/);
|
|
652
652
|
|
|
653
653
|
assert.match(find.description ?? "", /configured project source directories/);
|
|
654
654
|
assert.ok(find.promptGuidelines?.some((line) => line.includes("source_directory_paths")));
|
|
@@ -665,7 +665,7 @@ test("compression tools register agent-oriented descriptions and schema details"
|
|
|
665
665
|
assert.ok(filesCompress, "missing files-compress tool");
|
|
666
666
|
assert.ok(compress, "missing compress tool");
|
|
667
667
|
|
|
668
|
-
assert.match(filesCompress.description ?? "", /
|
|
668
|
+
assert.match(filesCompress.description ?? "", /summary, repository, files, and execution sections/);
|
|
669
669
|
assert.ok(filesCompress.promptGuidelines?.some((line) => line.includes("Line-number behavior:")));
|
|
670
670
|
assert.ok(filesCompress.promptGuidelines?.some((line) => line.includes("Behavior contract:")));
|
|
671
671
|
assert.match(String((filesCompress.parameters as { description?: string } | undefined)?.description ?? ""), /structured compressed lines/);
|
|
@@ -676,7 +676,7 @@ test("compression tools register agent-oriented descriptions and schema details"
|
|
|
676
676
|
assert.match(String((compress.parameters as { description?: string } | undefined)?.description ?? ""), /structured compressed lines/);
|
|
677
677
|
});
|
|
678
678
|
|
|
679
|
-
test("files-tokens returns structured source facts
|
|
679
|
+
test("files-tokens returns token-optimized structured source facts", async () => {
|
|
680
680
|
const { projectBase } = initFixtureRepo({
|
|
681
681
|
fixtures: [],
|
|
682
682
|
docs: {
|
|
@@ -693,10 +693,6 @@ test("files-tokens returns structured source facts and separated guidance", asyn
|
|
|
693
693
|
}) as {
|
|
694
694
|
content?: Array<{ type: string; text?: string }>;
|
|
695
695
|
details?: {
|
|
696
|
-
request: {
|
|
697
|
-
base_dir_path: string;
|
|
698
|
-
requested_input_paths: string[];
|
|
699
|
-
};
|
|
700
696
|
summary: {
|
|
701
697
|
counted_file_count: number;
|
|
702
698
|
skipped_file_count: number;
|
|
@@ -709,14 +705,8 @@ test("files-tokens returns structured source facts and separated guidance", asyn
|
|
|
709
705
|
line_count: number;
|
|
710
706
|
byte_count: number;
|
|
711
707
|
primary_heading_text?: string;
|
|
708
|
+
error_message?: string;
|
|
712
709
|
}>;
|
|
713
|
-
guidance: {
|
|
714
|
-
source_observations: {
|
|
715
|
-
skipped_inputs: Array<{ input_path: string; canonical_path: string; reason: string }>;
|
|
716
|
-
};
|
|
717
|
-
derived_recommendations: Array<{ kind: string; ordered_paths: string[] }>;
|
|
718
|
-
actionable_next_steps: Array<{ kind: string; ordered_paths: string[] }>;
|
|
719
|
-
};
|
|
720
710
|
execution: {
|
|
721
711
|
stderr: string;
|
|
722
712
|
};
|
|
@@ -725,8 +715,6 @@ test("files-tokens returns structured source facts and separated guidance", asyn
|
|
|
725
715
|
|
|
726
716
|
const payload = result.details!;
|
|
727
717
|
assert.deepEqual(JSON.parse(result.content?.[0]?.text ?? "{}"), JSON.parse(JSON.stringify(payload)));
|
|
728
|
-
assert.equal(payload.request.base_dir_path, projectBase);
|
|
729
|
-
assert.deepEqual(payload.request.requested_input_paths, [`${DEFAULT_DOCS_DIR}/REQUIREMENTS.md`, `${DEFAULT_DOCS_DIR}/MISSING.md`]);
|
|
730
718
|
assert.equal(payload.summary.counted_file_count, 1);
|
|
731
719
|
assert.equal(payload.summary.skipped_file_count, 1);
|
|
732
720
|
assert.equal(payload.files[0]?.canonical_path, `${DEFAULT_DOCS_DIR}/REQUIREMENTS.md`);
|
|
@@ -734,11 +722,8 @@ test("files-tokens returns structured source facts and separated guidance", asyn
|
|
|
734
722
|
assert.equal(payload.files[0]?.end_line_number, payload.files[0]?.line_count);
|
|
735
723
|
assert.ok((payload.files[0]?.byte_count ?? 0) > 0);
|
|
736
724
|
assert.equal(payload.files[0]?.primary_heading_text, "Requirements");
|
|
737
|
-
assert.
|
|
738
|
-
|
|
739
|
-
]);
|
|
740
|
-
assert.equal(payload.guidance.derived_recommendations[0]?.kind, "prioritize_high_token_paths");
|
|
741
|
-
assert.equal(payload.guidance.actionable_next_steps[0]?.kind, "read_top_token_paths_first");
|
|
725
|
+
assert.equal(payload.files[1]?.canonical_path, `${DEFAULT_DOCS_DIR}/MISSING.md`);
|
|
726
|
+
assert.equal(payload.files[1]?.error_message, "not found");
|
|
742
727
|
assert.match(payload.execution.stderr, new RegExp(`skipped: ${DEFAULT_DOCS_DIR.replace("/", "\\/")}/MISSING\\.md: not found`));
|
|
743
728
|
} finally {
|
|
744
729
|
fs.rmSync(projectBase, { recursive: true, force: true });
|
|
@@ -771,9 +756,6 @@ export function buildSample(input: string): string {
|
|
|
771
756
|
}) as {
|
|
772
757
|
content?: Array<{ type: string; text?: string }>;
|
|
773
758
|
details?: {
|
|
774
|
-
request: {
|
|
775
|
-
requested_input_paths: string[];
|
|
776
|
-
};
|
|
777
759
|
summary: {
|
|
778
760
|
analyzed_file_count: number;
|
|
779
761
|
skipped_file_count: number;
|
|
@@ -808,7 +790,6 @@ export function buildSample(input: string): string {
|
|
|
808
790
|
|
|
809
791
|
const payload = result.details!;
|
|
810
792
|
assert.deepEqual(JSON.parse(result.content?.[0]?.text ?? "{}"), JSON.parse(JSON.stringify(payload)));
|
|
811
|
-
assert.deepEqual(payload.request.requested_input_paths, ["src/sample.ts", "src/missing.ts"]);
|
|
812
793
|
assert.equal(payload.summary.analyzed_file_count, 1);
|
|
813
794
|
assert.equal(payload.summary.skipped_file_count, 1);
|
|
814
795
|
assert.deepEqual(payload.repository.file_canonical_paths, ["src/sample.ts"]);
|
|
@@ -912,10 +893,6 @@ export function buildSample(input: string): string {
|
|
|
912
893
|
}) as {
|
|
913
894
|
content?: Array<{ type: string; text?: string }>;
|
|
914
895
|
details?: {
|
|
915
|
-
request: {
|
|
916
|
-
line_number_mode: string;
|
|
917
|
-
requested_input_paths: string[];
|
|
918
|
-
};
|
|
919
896
|
summary: {
|
|
920
897
|
compressed_file_count: number;
|
|
921
898
|
skipped_file_count: number;
|
|
@@ -950,8 +927,6 @@ export function buildSample(input: string): string {
|
|
|
950
927
|
|
|
951
928
|
const payload = result.details!;
|
|
952
929
|
assert.deepEqual(JSON.parse(result.content?.[0]?.text ?? "{}"), JSON.parse(JSON.stringify(payload)));
|
|
953
|
-
assert.equal(payload.request.line_number_mode, "enabled");
|
|
954
|
-
assert.deepEqual(payload.request.requested_input_paths, ["src/sample.ts", "src/missing.ts"]);
|
|
955
930
|
assert.equal(payload.summary.compressed_file_count, 1);
|
|
956
931
|
assert.equal(payload.summary.skipped_file_count, 1);
|
|
957
932
|
assert.equal(payload.summary.total_symbol_count, 1);
|
|
@@ -999,10 +974,6 @@ test("compress returns a structured repository-scoped compression payload", asyn
|
|
|
999
974
|
}) as {
|
|
1000
975
|
content?: Array<{ type: string; text?: string }>;
|
|
1001
976
|
details?: {
|
|
1002
|
-
request: {
|
|
1003
|
-
scope: string;
|
|
1004
|
-
line_number_mode: string;
|
|
1005
|
-
};
|
|
1006
977
|
summary: {
|
|
1007
978
|
compressed_file_count: number;
|
|
1008
979
|
total_compressed_line_count: number;
|
|
@@ -1026,8 +997,6 @@ test("compress returns a structured repository-scoped compression payload", asyn
|
|
|
1026
997
|
|
|
1027
998
|
const payload = result.details!;
|
|
1028
999
|
assert.deepEqual(JSON.parse(result.content?.[0]?.text ?? "{}"), JSON.parse(JSON.stringify(payload)));
|
|
1029
|
-
assert.equal(payload.request.scope, "configured-source-directories");
|
|
1030
|
-
assert.equal(payload.request.line_number_mode, "disabled");
|
|
1031
1000
|
assert.equal(payload.summary.compressed_file_count, 2);
|
|
1032
1001
|
assert.ok((payload.summary.total_compressed_line_count ?? 0) >= 2);
|
|
1033
1002
|
assert.deepEqual(payload.repository.source_directory_paths, ["src"]);
|
|
@@ -1071,12 +1040,6 @@ export function buildSample(input: string): string {
|
|
|
1071
1040
|
}) as {
|
|
1072
1041
|
content?: Array<{ type: string; text?: string }>;
|
|
1073
1042
|
details?: {
|
|
1074
|
-
request: {
|
|
1075
|
-
tag_filter_values: string[];
|
|
1076
|
-
tag_filter_status: string;
|
|
1077
|
-
line_number_mode: string;
|
|
1078
|
-
requested_input_paths: string[];
|
|
1079
|
-
};
|
|
1080
1043
|
summary: {
|
|
1081
1044
|
search_status: string;
|
|
1082
1045
|
matched_file_count: number;
|
|
@@ -1084,7 +1047,7 @@ export function buildSample(input: string): string {
|
|
|
1084
1047
|
total_match_count: number;
|
|
1085
1048
|
};
|
|
1086
1049
|
repository: {
|
|
1087
|
-
|
|
1050
|
+
file_canonical_paths: string[];
|
|
1088
1051
|
};
|
|
1089
1052
|
files: Array<{
|
|
1090
1053
|
canonical_path: string;
|
|
@@ -1117,15 +1080,11 @@ export function buildSample(input: string): string {
|
|
|
1117
1080
|
|
|
1118
1081
|
const payload = result.details!;
|
|
1119
1082
|
assert.deepEqual(JSON.parse(result.content?.[0]?.text ?? "{}"), JSON.parse(JSON.stringify(payload)));
|
|
1120
|
-
assert.deepEqual(payload.request.tag_filter_values, ["FUNCTION"]);
|
|
1121
|
-
assert.equal(payload.request.tag_filter_status, "valid");
|
|
1122
|
-
assert.equal(payload.request.line_number_mode, "enabled");
|
|
1123
|
-
assert.deepEqual(payload.request.requested_input_paths, ["src/sample.ts", "src/missing.ts"]);
|
|
1124
1083
|
assert.equal(payload.summary.search_status, "matched");
|
|
1125
1084
|
assert.equal(payload.summary.matched_file_count, 1);
|
|
1126
1085
|
assert.equal(payload.summary.skipped_file_count, 1);
|
|
1127
1086
|
assert.equal(payload.summary.total_match_count, 1);
|
|
1128
|
-
assert.
|
|
1087
|
+
assert.deepEqual(payload.repository.file_canonical_paths, ["src/sample.ts", "src/missing.ts"]);
|
|
1129
1088
|
assert.deepEqual(payload.files.map((file) => file.status), ["matched", "skipped"]);
|
|
1130
1089
|
assert.equal(payload.files[0]?.canonical_path, "src/sample.ts");
|
|
1131
1090
|
assert.equal(payload.files[0]?.match_count, 1);
|
|
@@ -1182,11 +1141,6 @@ export function buildAlpha(): number {
|
|
|
1182
1141
|
}) as {
|
|
1183
1142
|
content?: Array<{ type: string; text?: string }>;
|
|
1184
1143
|
details?: {
|
|
1185
|
-
request: {
|
|
1186
|
-
scope: string;
|
|
1187
|
-
regex_status: string;
|
|
1188
|
-
requested_file_count: number;
|
|
1189
|
-
};
|
|
1190
1144
|
summary: {
|
|
1191
1145
|
search_status: string;
|
|
1192
1146
|
matched_file_count: number;
|
|
@@ -1196,7 +1150,6 @@ export function buildAlpha(): number {
|
|
|
1196
1150
|
repository: {
|
|
1197
1151
|
source_directory_paths: string[];
|
|
1198
1152
|
file_canonical_paths: string[];
|
|
1199
|
-
supported_tags_by_language: Record<string, string[]>;
|
|
1200
1153
|
};
|
|
1201
1154
|
files: Array<{
|
|
1202
1155
|
canonical_path: string;
|
|
@@ -1216,16 +1169,12 @@ export function buildAlpha(): number {
|
|
|
1216
1169
|
|
|
1217
1170
|
const payload = result.details!;
|
|
1218
1171
|
assert.deepEqual(JSON.parse(result.content?.[0]?.text ?? "{}"), JSON.parse(JSON.stringify(payload)));
|
|
1219
|
-
assert.equal(payload.request.scope, "configured-source-directories");
|
|
1220
|
-
assert.equal(payload.request.regex_status, "valid");
|
|
1221
|
-
assert.equal(payload.request.requested_file_count, 2);
|
|
1222
1172
|
assert.equal(payload.summary.search_status, "matched");
|
|
1223
1173
|
assert.equal(payload.summary.matched_file_count, 1);
|
|
1224
1174
|
assert.equal(payload.summary.no_match_file_count, 1);
|
|
1225
1175
|
assert.equal(payload.summary.total_match_count, 1);
|
|
1226
1176
|
assert.deepEqual(payload.repository.source_directory_paths, ["src"]);
|
|
1227
1177
|
assert.deepEqual(payload.repository.file_canonical_paths, ["src/alpha.ts", "src/nested/beta.ts"]);
|
|
1228
|
-
assert.ok(payload.repository.supported_tags_by_language.typescript?.includes("FUNCTION"));
|
|
1229
1178
|
assert.deepEqual(payload.files.map((file) => file.status), ["matched", "no_match"]);
|
|
1230
1179
|
assert.equal(payload.files[0]?.matches[0]?.symbol_name, "buildAlpha");
|
|
1231
1180
|
assert.match(payload.files[0]?.matches[0]?.code_lines[0]?.display_text ?? "", /^export function buildAlpha/);
|
|
@@ -1257,31 +1206,28 @@ test("path, static-check, git, docs, and worktree tools return structured JSON p
|
|
|
1257
1206
|
content?: Array<{ text?: string }>;
|
|
1258
1207
|
details?: {
|
|
1259
1208
|
result: { path_value: string; path_present: boolean };
|
|
1260
|
-
runtime_paths: { git_path: string };
|
|
1261
1209
|
execution: { code: number };
|
|
1262
1210
|
};
|
|
1263
1211
|
};
|
|
1264
1212
|
assert.deepEqual(JSON.parse(gitPathResult.content?.[0]?.text ?? "{}"), JSON.parse(JSON.stringify(gitPathResult.details)));
|
|
1265
|
-
assert.equal(gitPathResult.details?.result.path_value,
|
|
1213
|
+
assert.equal(gitPathResult.details?.result.path_value, projectBase);
|
|
1266
1214
|
assert.equal(gitPathResult.details?.result.path_present, true);
|
|
1267
1215
|
assert.equal(gitPathResult.details?.execution.code, 0);
|
|
1268
1216
|
|
|
1269
1217
|
const basePathResult = await executeRegisteredTool(pi, "get-base-path", projectBase) as {
|
|
1270
1218
|
details?: {
|
|
1271
1219
|
result: { path_value: string };
|
|
1272
|
-
runtime_paths: { base_path: string };
|
|
1273
1220
|
execution: { code: number };
|
|
1274
1221
|
};
|
|
1275
1222
|
};
|
|
1276
|
-
assert.equal(basePathResult.details?.result.path_value,
|
|
1223
|
+
assert.equal(basePathResult.details?.result.path_value, projectBase);
|
|
1277
1224
|
assert.equal(basePathResult.details?.execution.code, 0);
|
|
1278
1225
|
|
|
1279
1226
|
const gitCheckResult = await executeRegisteredTool(pi, "git-check", projectBase) as {
|
|
1280
|
-
details?: { result: {
|
|
1227
|
+
details?: { result: { git_path_present: boolean; status: string }; execution: { code: number } };
|
|
1281
1228
|
};
|
|
1229
|
+
assert.equal(gitCheckResult.details?.result.git_path_present, true);
|
|
1282
1230
|
assert.equal(gitCheckResult.details?.result.status, "clean");
|
|
1283
|
-
assert.equal(gitCheckResult.details?.result.worktree_status, "clean");
|
|
1284
|
-
assert.equal(gitCheckResult.details?.result.head_status, "valid");
|
|
1285
1231
|
assert.equal(gitCheckResult.details?.execution.code, 0);
|
|
1286
1232
|
|
|
1287
1233
|
const docsCheckResult = await executeRegisteredTool(pi, "docs-check", projectBase) as {
|
|
@@ -1317,43 +1263,34 @@ test("path, static-check, git, docs, and worktree tools return structured JSON p
|
|
|
1317
1263
|
|
|
1318
1264
|
const staticCheckResult = await executeRegisteredTool(pi, "static-check", projectBase) as {
|
|
1319
1265
|
details?: {
|
|
1320
|
-
request: { selection_directory_paths: string[]; excluded_directory_paths: string[] };
|
|
1321
1266
|
summary: { selected_file_count: number };
|
|
1322
1267
|
files: Array<{ canonical_path: string; status: string }>;
|
|
1323
1268
|
execution: { code: number };
|
|
1324
1269
|
};
|
|
1325
1270
|
};
|
|
1326
|
-
assert.deepEqual(staticCheckResult.details?.request.selection_directory_paths, ["src", "tests"]);
|
|
1327
|
-
assert.ok(staticCheckResult.details?.request.excluded_directory_paths.includes("tests/fixtures"));
|
|
1328
1271
|
assert.equal(staticCheckResult.details?.summary.selected_file_count, 1);
|
|
1329
1272
|
assert.equal(staticCheckResult.details?.files[0]?.canonical_path, "src/check.ts");
|
|
1330
1273
|
assert.equal(staticCheckResult.details?.files[0]?.status, "selected");
|
|
1331
1274
|
assert.equal(staticCheckResult.details?.execution.code, 0);
|
|
1332
1275
|
|
|
1333
1276
|
const gitWtNameResult = await executeRegisteredTool(pi, "git-wt-name", projectBase) as {
|
|
1334
|
-
details?: { result: { worktree_name?: string
|
|
1277
|
+
details?: { result: { worktree_name?: string }; execution: { code: number } };
|
|
1335
1278
|
};
|
|
1336
1279
|
const wtName = gitWtNameResult.details?.result.worktree_name ?? "";
|
|
1337
|
-
assert.equal(gitWtNameResult.details?.result.status, "generated");
|
|
1338
|
-
assert.equal(gitWtNameResult.details?.result.format_text, "useReq-<project>-<sanitized-branch>-<YYYYMMDDHHMMSS>");
|
|
1339
1280
|
assert.match(wtName, /^useReq-/);
|
|
1340
1281
|
assert.equal(gitWtNameResult.details?.execution.code, 0);
|
|
1341
1282
|
|
|
1342
1283
|
const gitWtCreateResult = await executeRegisteredTool(pi, "git-wt-create", projectBase, { wtName }) as {
|
|
1343
|
-
details?: { result: {
|
|
1284
|
+
details?: { result: { worktree_name: string; worktree_path: string }; execution: { code: number } };
|
|
1344
1285
|
};
|
|
1345
|
-
assert.equal(gitWtCreateResult.details?.result.status, "created");
|
|
1346
1286
|
assert.equal(gitWtCreateResult.details?.result.worktree_name, wtName);
|
|
1347
|
-
assert.equal(gitWtCreateResult.details?.result.branch_name, wtName);
|
|
1348
1287
|
assert.match(gitWtCreateResult.details?.result.worktree_path ?? "", new RegExp(`${wtName}$`));
|
|
1349
1288
|
assert.equal(gitWtCreateResult.details?.execution.code, 0);
|
|
1350
1289
|
|
|
1351
1290
|
const gitWtDeleteResult = await executeRegisteredTool(pi, "git-wt-delete", projectBase, { wtName }) as {
|
|
1352
|
-
details?: { result: {
|
|
1291
|
+
details?: { result: { worktree_name: string; worktree_path: string }; execution: { code: number } };
|
|
1353
1292
|
};
|
|
1354
|
-
assert.equal(gitWtDeleteResult.details?.result.status, "deleted");
|
|
1355
1293
|
assert.equal(gitWtDeleteResult.details?.result.worktree_name, wtName);
|
|
1356
|
-
assert.equal(gitWtDeleteResult.details?.result.branch_name, wtName);
|
|
1357
1294
|
assert.match(gitWtDeleteResult.details?.result.worktree_path ?? "", new RegExp(`${wtName}$`));
|
|
1358
1295
|
assert.equal(gitWtDeleteResult.details?.execution.code, 0);
|
|
1359
1296
|
} finally {
|
|
@@ -2219,11 +2156,11 @@ test("git-path tool derives the repository root at runtime", async () => {
|
|
|
2219
2156
|
piUsereqExtension(pi);
|
|
2220
2157
|
const result = await executeRegisteredTool(pi, "git-path", projectBase) as {
|
|
2221
2158
|
content?: Array<{ text?: string }>;
|
|
2222
|
-
details?: { result: { path_value: string }
|
|
2159
|
+
details?: { result: { path_value: string } };
|
|
2223
2160
|
};
|
|
2224
2161
|
|
|
2225
2162
|
assert.deepEqual(JSON.parse(result.content?.[0]?.text ?? "{}"), JSON.parse(JSON.stringify(result.details)));
|
|
2226
|
-
assert.equal(result.details?.result.path_value,
|
|
2163
|
+
assert.equal(result.details?.result.path_value, projectBase);
|
|
2227
2164
|
} finally {
|
|
2228
2165
|
fs.rmSync(projectBase, { recursive: true, force: true });
|
|
2229
2166
|
}
|