gsd-pi 2.38.0-dev.96dc7fb → 2.38.0-dev.98b44dc
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/README.md +15 -11
- package/dist/app-paths.js +1 -1
- package/dist/extension-registry.js +2 -2
- package/dist/remote-questions-config.js +2 -2
- package/dist/resource-loader.js +34 -1
- package/dist/resources/extensions/browser-tools/index.js +3 -1
- package/dist/resources/extensions/browser-tools/tools/verify.js +97 -0
- package/dist/resources/extensions/env-utils.js +29 -0
- package/dist/resources/extensions/get-secrets-from-user.js +5 -24
- package/dist/resources/extensions/github-sync/cli.js +284 -0
- package/dist/resources/extensions/github-sync/index.js +73 -0
- package/dist/resources/extensions/github-sync/mapping.js +67 -0
- package/dist/resources/extensions/github-sync/sync.js +424 -0
- package/dist/resources/extensions/github-sync/templates.js +118 -0
- package/dist/resources/extensions/github-sync/types.js +7 -0
- package/dist/resources/extensions/gsd/auto/session.js +6 -23
- package/dist/resources/extensions/gsd/auto-dispatch.js +8 -9
- package/dist/resources/extensions/gsd/auto-loop.js +636 -594
- package/dist/resources/extensions/gsd/auto-post-unit.js +99 -70
- package/dist/resources/extensions/gsd/auto-prompts.js +202 -48
- package/dist/resources/extensions/gsd/auto-start.js +7 -1
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +2 -1
- package/dist/resources/extensions/gsd/auto-worktree.js +3 -3
- package/dist/resources/extensions/gsd/auto.js +143 -96
- package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands.js +4 -2
- package/dist/resources/extensions/gsd/context-budget.js +2 -10
- package/dist/resources/extensions/gsd/detection.js +1 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/dist/resources/extensions/gsd/doctor-providers.js +30 -11
- package/dist/resources/extensions/gsd/doctor.js +20 -1
- package/dist/resources/extensions/gsd/exit-command.js +2 -1
- package/dist/resources/extensions/gsd/export.js +1 -1
- package/dist/resources/extensions/gsd/files.js +48 -9
- package/dist/resources/extensions/gsd/forensics.js +1 -1
- package/dist/resources/extensions/gsd/git-service.js +30 -12
- package/dist/resources/extensions/gsd/gitignore.js +16 -3
- package/dist/resources/extensions/gsd/guided-flow.js +149 -38
- package/dist/resources/extensions/gsd/health-widget-core.js +32 -70
- package/dist/resources/extensions/gsd/health-widget.js +3 -86
- package/dist/resources/extensions/gsd/index.js +24 -20
- package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
- package/dist/resources/extensions/gsd/migrate-external.js +18 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +37 -0
- package/dist/resources/extensions/gsd/paths.js +3 -0
- package/dist/resources/extensions/gsd/preferences-models.js +0 -12
- package/dist/resources/extensions/gsd/preferences-types.js +1 -1
- package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
- package/dist/resources/extensions/gsd/preferences.js +22 -11
- package/dist/resources/extensions/gsd/prompt-loader.js +6 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -3
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +28 -11
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/dist/resources/extensions/gsd/repo-identity.js +21 -4
- package/dist/resources/extensions/gsd/resource-version.js +2 -1
- package/dist/resources/extensions/gsd/roadmap-mutations.js +24 -0
- package/dist/resources/extensions/gsd/state.js +42 -23
- package/dist/resources/extensions/gsd/templates/runtime.md +21 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/dist/resources/extensions/gsd/visualizer-data.js +1 -1
- package/dist/resources/extensions/mcp-client/index.js +14 -1
- package/dist/resources/extensions/remote-questions/status.js +4 -1
- package/dist/resources/extensions/remote-questions/store.js +4 -1
- package/dist/resources/extensions/search-the-web/provider.js +2 -1
- package/dist/resources/extensions/shared/frontmatter.js +1 -1
- package/dist/resources/extensions/subagent/isolation.js +2 -1
- package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/utils/oauth/anthropic.js +2 -2
- package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +1 -1
- package/packages/pi-ai/src/utils/oauth/anthropic.ts +2 -2
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +205 -7
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +6 -1
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +223 -7
- package/packages/pi-coding-agent/src/core/skills.ts +9 -1
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/src/resources/extensions/browser-tools/index.ts +3 -0
- package/src/resources/extensions/browser-tools/tools/verify.ts +117 -0
- package/src/resources/extensions/env-utils.ts +31 -0
- package/src/resources/extensions/get-secrets-from-user.ts +5 -24
- package/src/resources/extensions/github-sync/cli.ts +364 -0
- package/src/resources/extensions/github-sync/index.ts +93 -0
- package/src/resources/extensions/github-sync/mapping.ts +81 -0
- package/src/resources/extensions/github-sync/sync.ts +556 -0
- package/src/resources/extensions/github-sync/templates.ts +183 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
- package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
- package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
- package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
- package/src/resources/extensions/github-sync/types.ts +47 -0
- package/src/resources/extensions/gsd/auto/session.ts +7 -25
- package/src/resources/extensions/gsd/auto-dispatch.ts +7 -9
- package/src/resources/extensions/gsd/auto-loop.ts +526 -545
- package/src/resources/extensions/gsd/auto-post-unit.ts +80 -44
- package/src/resources/extensions/gsd/auto-prompts.ts +247 -50
- package/src/resources/extensions/gsd/auto-start.ts +11 -1
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +3 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +3 -3
- package/src/resources/extensions/gsd/auto.ts +139 -101
- package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands.ts +5 -3
- package/src/resources/extensions/gsd/context-budget.ts +2 -12
- package/src/resources/extensions/gsd/detection.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/src/resources/extensions/gsd/doctor-providers.ts +30 -9
- package/src/resources/extensions/gsd/doctor.ts +22 -1
- package/src/resources/extensions/gsd/exit-command.ts +2 -2
- package/src/resources/extensions/gsd/export.ts +1 -1
- package/src/resources/extensions/gsd/files.ts +51 -11
- package/src/resources/extensions/gsd/forensics.ts +1 -1
- package/src/resources/extensions/gsd/git-service.ts +44 -10
- package/src/resources/extensions/gsd/gitignore.ts +17 -3
- package/src/resources/extensions/gsd/guided-flow.ts +177 -44
- package/src/resources/extensions/gsd/health-widget-core.ts +28 -80
- package/src/resources/extensions/gsd/health-widget.ts +3 -89
- package/src/resources/extensions/gsd/index.ts +24 -17
- package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
- package/src/resources/extensions/gsd/migrate-external.ts +18 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +37 -0
- package/src/resources/extensions/gsd/paths.ts +4 -0
- package/src/resources/extensions/gsd/preferences-models.ts +0 -12
- package/src/resources/extensions/gsd/preferences-types.ts +4 -4
- package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
- package/src/resources/extensions/gsd/preferences.ts +25 -11
- package/src/resources/extensions/gsd/prompt-loader.ts +7 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/src/resources/extensions/gsd/prompts/execute-task.md +5 -3
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +4 -8
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +28 -11
- package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/src/resources/extensions/gsd/repo-identity.ts +23 -4
- package/src/resources/extensions/gsd/resource-version.ts +3 -1
- package/src/resources/extensions/gsd/roadmap-mutations.ts +29 -0
- package/src/resources/extensions/gsd/state.ts +39 -21
- package/src/resources/extensions/gsd/templates/runtime.md +21 -0
- package/src/resources/extensions/gsd/templates/task-plan.md +3 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +122 -68
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +16 -54
- package/src/resources/extensions/gsd/tests/parsers.test.ts +131 -14
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +140 -0
- package/src/resources/extensions/gsd/types.ts +18 -1
- package/src/resources/extensions/gsd/verification-evidence.ts +16 -0
- package/src/resources/extensions/gsd/visualizer-data.ts +1 -1
- package/src/resources/extensions/mcp-client/index.ts +17 -1
- package/src/resources/extensions/remote-questions/status.ts +5 -1
- package/src/resources/extensions/remote-questions/store.ts +5 -1
- package/src/resources/extensions/search-the-web/provider.ts +2 -1
- package/src/resources/extensions/shared/frontmatter.ts +1 -1
- package/src/resources/extensions/subagent/isolation.ts +3 -1
- package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
- package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
- package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
- package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
- package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
- package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
- package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
- package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
- package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
- package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
- package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
- package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
|
@@ -1,426 +0,0 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
splitIntoChunks,
|
|
6
|
-
scoreChunks,
|
|
7
|
-
chunkByRelevance,
|
|
8
|
-
formatChunks,
|
|
9
|
-
} from "../semantic-chunker.js";
|
|
10
|
-
import type { Chunk, ChunkResult } from "../semantic-chunker.js";
|
|
11
|
-
|
|
12
|
-
// ─── Test Fixtures ──────────────────────────────────────────────────────────
|
|
13
|
-
|
|
14
|
-
const TYPESCRIPT_CODE = `import { readFile } from "node:fs/promises";
|
|
15
|
-
import { join } from "node:path";
|
|
16
|
-
|
|
17
|
-
export interface Config {
|
|
18
|
-
name: string;
|
|
19
|
-
debug: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function loadConfig(path: string): Config {
|
|
23
|
-
const raw = readFileSync(path, "utf-8");
|
|
24
|
-
return JSON.parse(raw);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export async function saveConfig(path: string, config: Config): Promise<void> {
|
|
28
|
-
const data = JSON.stringify(config, null, 2);
|
|
29
|
-
await writeFile(path, data, "utf-8");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export class ConfigManager {
|
|
33
|
-
private config: Config;
|
|
34
|
-
|
|
35
|
-
constructor(private path: string) {
|
|
36
|
-
this.config = loadConfig(path);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
get(key: keyof Config) {
|
|
40
|
-
return this.config[key];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
set(key: keyof Config, value: Config[keyof Config]) {
|
|
44
|
-
this.config[key] = value;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
save() {
|
|
48
|
-
return saveConfig(this.path, this.config);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const DEFAULT_CONFIG: Config = {
|
|
53
|
-
name: "default",
|
|
54
|
-
debug: false,
|
|
55
|
-
};`;
|
|
56
|
-
|
|
57
|
-
const MARKDOWN_CONTENT = `# Project Overview
|
|
58
|
-
|
|
59
|
-
This project provides a task management system.
|
|
60
|
-
|
|
61
|
-
## Installation
|
|
62
|
-
|
|
63
|
-
Run the following command:
|
|
64
|
-
|
|
65
|
-
\`\`\`bash
|
|
66
|
-
npm install gsd
|
|
67
|
-
\`\`\`
|
|
68
|
-
|
|
69
|
-
## Usage
|
|
70
|
-
|
|
71
|
-
Import the module and initialize:
|
|
72
|
-
|
|
73
|
-
\`\`\`typescript
|
|
74
|
-
import { gsd } from "gsd";
|
|
75
|
-
gsd.init();
|
|
76
|
-
\`\`\`
|
|
77
|
-
|
|
78
|
-
## API Reference
|
|
79
|
-
|
|
80
|
-
### init()
|
|
81
|
-
|
|
82
|
-
Initializes the system.
|
|
83
|
-
|
|
84
|
-
### run(task: string)
|
|
85
|
-
|
|
86
|
-
Runs a specified task.
|
|
87
|
-
|
|
88
|
-
## Contributing
|
|
89
|
-
|
|
90
|
-
Please read CONTRIBUTING.md before submitting PRs.`;
|
|
91
|
-
|
|
92
|
-
const PLAIN_TEXT = `The quick brown fox jumps over the lazy dog. This is a sample paragraph
|
|
93
|
-
that tests plain text chunking behavior.
|
|
94
|
-
|
|
95
|
-
Another paragraph begins here. It contains different content that should
|
|
96
|
-
be separated from the first paragraph by a blank line.
|
|
97
|
-
|
|
98
|
-
A third paragraph with more text. This should form its own chunk when
|
|
99
|
-
processed by the text boundary detection.
|
|
100
|
-
|
|
101
|
-
Final paragraph wrapping up the test content.`;
|
|
102
|
-
|
|
103
|
-
// ─── splitIntoChunks — TypeScript Code ──────────────────────────────────────
|
|
104
|
-
|
|
105
|
-
test("splitIntoChunks splits TypeScript code at function/class/export boundaries", () => {
|
|
106
|
-
const chunks = splitIntoChunks(TYPESCRIPT_CODE);
|
|
107
|
-
assert.ok(chunks.length > 1, `Expected multiple chunks, got ${chunks.length}`);
|
|
108
|
-
|
|
109
|
-
// Should find boundaries at export interface, export function, export class, const
|
|
110
|
-
const contents = chunks.map((c) => c.content);
|
|
111
|
-
const hasInterface = contents.some((c) => c.includes("export interface Config"));
|
|
112
|
-
const hasLoadConfig = contents.some((c) => c.includes("export function loadConfig"));
|
|
113
|
-
const hasClass = contents.some((c) => c.includes("export class ConfigManager"));
|
|
114
|
-
assert.ok(hasInterface, "Should have a chunk containing the interface");
|
|
115
|
-
assert.ok(hasLoadConfig, "Should have a chunk containing loadConfig");
|
|
116
|
-
assert.ok(hasClass, "Should have a chunk containing ConfigManager");
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
test("splitIntoChunks preserves all content across chunks", () => {
|
|
120
|
-
const chunks = splitIntoChunks(TYPESCRIPT_CODE);
|
|
121
|
-
const reassembled = chunks.map((c) => c.content).join("\n");
|
|
122
|
-
assert.equal(reassembled, TYPESCRIPT_CODE);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test("splitIntoChunks assigns correct line numbers", () => {
|
|
126
|
-
const chunks = splitIntoChunks(TYPESCRIPT_CODE);
|
|
127
|
-
// First chunk starts at line 1
|
|
128
|
-
assert.equal(chunks[0].startLine, 1);
|
|
129
|
-
// Last chunk ends at total line count
|
|
130
|
-
const totalLines = TYPESCRIPT_CODE.split("\n").length;
|
|
131
|
-
assert.equal(chunks[chunks.length - 1].endLine, totalLines);
|
|
132
|
-
// Chunks should be contiguous
|
|
133
|
-
for (let i = 1; i < chunks.length; i++) {
|
|
134
|
-
assert.equal(chunks[i].startLine, chunks[i - 1].endLine + 1,
|
|
135
|
-
`Chunk ${i} should start right after chunk ${i - 1}`);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// ─── splitIntoChunks — Markdown ─────────────────────────────────────────────
|
|
140
|
-
|
|
141
|
-
test("splitIntoChunks splits markdown at heading boundaries", () => {
|
|
142
|
-
const chunks = splitIntoChunks(MARKDOWN_CONTENT);
|
|
143
|
-
assert.ok(chunks.length > 1, `Expected multiple chunks, got ${chunks.length}`);
|
|
144
|
-
|
|
145
|
-
const contents = chunks.map((c) => c.content);
|
|
146
|
-
const hasOverview = contents.some((c) => c.includes("# Project Overview"));
|
|
147
|
-
const hasInstallation = contents.some((c) => c.includes("## Installation"));
|
|
148
|
-
const hasApi = contents.some((c) => c.includes("## API Reference"));
|
|
149
|
-
assert.ok(hasOverview, "Should have overview chunk");
|
|
150
|
-
assert.ok(hasInstallation, "Should have installation chunk");
|
|
151
|
-
assert.ok(hasApi, "Should have API reference chunk");
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// ─── splitIntoChunks — Plain Text ───────────────────────────────────────────
|
|
155
|
-
|
|
156
|
-
test("splitIntoChunks splits plain text at paragraph boundaries", () => {
|
|
157
|
-
const chunks = splitIntoChunks(PLAIN_TEXT);
|
|
158
|
-
assert.ok(chunks.length >= 2, `Expected multiple chunks, got ${chunks.length}`);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// ─── splitIntoChunks — Edge Cases ───────────────────────────────────────────
|
|
162
|
-
|
|
163
|
-
test("splitIntoChunks returns empty array for empty content", () => {
|
|
164
|
-
assert.deepEqual(splitIntoChunks(""), []);
|
|
165
|
-
assert.deepEqual(splitIntoChunks(" "), []);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
test("splitIntoChunks handles single-line content", () => {
|
|
169
|
-
const chunks = splitIntoChunks("const x = 1;");
|
|
170
|
-
assert.equal(chunks.length, 1);
|
|
171
|
-
assert.equal(chunks[0].content, "const x = 1;");
|
|
172
|
-
assert.equal(chunks[0].startLine, 1);
|
|
173
|
-
assert.equal(chunks[0].endLine, 1);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
test("splitIntoChunks merges tiny chunks below minLines into predecessor", () => {
|
|
177
|
-
const content = `export function foo() {
|
|
178
|
-
return 1;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export function bar() {
|
|
182
|
-
return 2;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export function baz() {
|
|
186
|
-
return 3;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const x = 1;`;
|
|
190
|
-
|
|
191
|
-
// With high minLines, tiny chunks get merged
|
|
192
|
-
const chunks = splitIntoChunks(content, { minLines: 5, maxLines: 80 });
|
|
193
|
-
for (let i = 0; i < chunks.length; i++) {
|
|
194
|
-
const lineCount = chunks[i].endLine - chunks[i].startLine + 1;
|
|
195
|
-
// First chunk may be smaller, but subsequent ones should be >= minLines or merged
|
|
196
|
-
if (i > 0) {
|
|
197
|
-
assert.ok(lineCount >= 3, `Chunk ${i} has only ${lineCount} lines`);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
test("splitIntoChunks respects maxLines by splitting oversized chunks", () => {
|
|
203
|
-
// Build a long function
|
|
204
|
-
const longLines = ["export function longFunc() {"];
|
|
205
|
-
for (let i = 0; i < 100; i++) {
|
|
206
|
-
longLines.push(` const v${i} = ${i};`);
|
|
207
|
-
}
|
|
208
|
-
longLines.push("}");
|
|
209
|
-
const content = longLines.join("\n");
|
|
210
|
-
|
|
211
|
-
const chunks = splitIntoChunks(content, { minLines: 1, maxLines: 30 });
|
|
212
|
-
for (const chunk of chunks) {
|
|
213
|
-
const lineCount = chunk.endLine - chunk.startLine + 1;
|
|
214
|
-
assert.ok(lineCount <= 30, `Chunk has ${lineCount} lines, exceeding maxLines=30`);
|
|
215
|
-
}
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
// ─── scoreChunks ────────────────────────────────────────────────────────────
|
|
219
|
-
|
|
220
|
-
test("scoreChunks scores chunk with query terms higher than chunk without", () => {
|
|
221
|
-
const chunks: Chunk[] = [
|
|
222
|
-
{ content: "function loadConfig reads configuration from disk", startLine: 1, endLine: 1, score: 0 },
|
|
223
|
-
{ content: "function saveData writes data to database storage", startLine: 2, endLine: 2, score: 0 },
|
|
224
|
-
];
|
|
225
|
-
|
|
226
|
-
const scored = scoreChunks(chunks, "loadConfig configuration disk");
|
|
227
|
-
const configChunk = scored.find((c) => c.content.includes("loadConfig"))!;
|
|
228
|
-
const dataChunk = scored.find((c) => c.content.includes("saveData"))!;
|
|
229
|
-
assert.ok(configChunk.score > dataChunk.score,
|
|
230
|
-
`Config chunk (${configChunk.score}) should score higher than data chunk (${dataChunk.score})`);
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
test("scoreChunks normalizes scores between 0 and 1", () => {
|
|
234
|
-
const chunks: Chunk[] = [
|
|
235
|
-
{ content: "alpha beta gamma delta", startLine: 1, endLine: 1, score: 0 },
|
|
236
|
-
{ content: "epsilon zeta eta theta", startLine: 2, endLine: 2, score: 0 },
|
|
237
|
-
];
|
|
238
|
-
|
|
239
|
-
const scored = scoreChunks(chunks, "alpha gamma");
|
|
240
|
-
for (const chunk of scored) {
|
|
241
|
-
assert.ok(chunk.score >= 0 && chunk.score <= 1,
|
|
242
|
-
`Score ${chunk.score} should be between 0 and 1`);
|
|
243
|
-
}
|
|
244
|
-
// At least one chunk should have score 1 (the max)
|
|
245
|
-
assert.ok(scored.some((c) => c.score === 1), "Max scoring chunk should be normalized to 1");
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
test("scoreChunks returns all zero scores when no query terms match", () => {
|
|
249
|
-
const chunks: Chunk[] = [
|
|
250
|
-
{ content: "alpha beta gamma", startLine: 1, endLine: 1, score: 0 },
|
|
251
|
-
{ content: "delta epsilon zeta", startLine: 2, endLine: 2, score: 0 },
|
|
252
|
-
];
|
|
253
|
-
|
|
254
|
-
const scored = scoreChunks(chunks, "xxxxxxxxx yyyyyyyyy");
|
|
255
|
-
for (const chunk of scored) {
|
|
256
|
-
assert.equal(chunk.score, 0, "Non-matching chunks should have score 0");
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
test("scoreChunks handles empty query gracefully", () => {
|
|
261
|
-
const chunks: Chunk[] = [
|
|
262
|
-
{ content: "some content here", startLine: 1, endLine: 1, score: 0 },
|
|
263
|
-
];
|
|
264
|
-
const scored = scoreChunks(chunks, "");
|
|
265
|
-
assert.equal(scored[0].score, 0);
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
test("scoreChunks handles empty chunks array", () => {
|
|
269
|
-
const scored = scoreChunks([], "some query");
|
|
270
|
-
assert.deepEqual(scored, []);
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
test("scoreChunks filters stop words from query", () => {
|
|
274
|
-
const chunks: Chunk[] = [
|
|
275
|
-
{ content: "the configuration module handles loading", startLine: 1, endLine: 1, score: 0 },
|
|
276
|
-
{ content: "database connection pool management system", startLine: 2, endLine: 2, score: 0 },
|
|
277
|
-
];
|
|
278
|
-
|
|
279
|
-
// "the" and "is" are stop words; "configuration" should be the only scoring term
|
|
280
|
-
const scored = scoreChunks(chunks, "the configuration is");
|
|
281
|
-
const configChunk = scored.find((c) => c.content.includes("configuration"))!;
|
|
282
|
-
const dbChunk = scored.find((c) => c.content.includes("database"))!;
|
|
283
|
-
assert.ok(configChunk.score > dbChunk.score);
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
// ─── chunkByRelevance ───────────────────────────────────────────────────────
|
|
287
|
-
|
|
288
|
-
test("chunkByRelevance selects top-scoring chunks up to maxChunks", () => {
|
|
289
|
-
const result = chunkByRelevance(TYPESCRIPT_CODE, "ConfigManager save config", {
|
|
290
|
-
maxChunks: 2,
|
|
291
|
-
minScore: 0,
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
assert.ok(result.chunks.length <= 2, `Expected at most 2 chunks, got ${result.chunks.length}`);
|
|
295
|
-
assert.ok(result.totalChunks > 2, "Total chunks should be more than selected");
|
|
296
|
-
assert.ok(result.omittedChunks > 0, "Should have omitted chunks");
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
test("chunkByRelevance returns chunks in original document order", () => {
|
|
300
|
-
const result = chunkByRelevance(TYPESCRIPT_CODE, "Config loadConfig saveConfig", {
|
|
301
|
-
maxChunks: 10,
|
|
302
|
-
minScore: 0,
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
for (let i = 1; i < result.chunks.length; i++) {
|
|
306
|
-
assert.ok(result.chunks[i].startLine > result.chunks[i - 1].startLine,
|
|
307
|
-
"Chunks should be in ascending line order");
|
|
308
|
-
}
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
test("chunkByRelevance respects minScore filtering", () => {
|
|
312
|
-
const result = chunkByRelevance(TYPESCRIPT_CODE, "ConfigManager", {
|
|
313
|
-
maxChunks: 10,
|
|
314
|
-
minScore: 0.5,
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
for (const chunk of result.chunks) {
|
|
318
|
-
assert.ok(chunk.score >= 0.5,
|
|
319
|
-
`Chunk score ${chunk.score} should be >= minScore 0.5`);
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
test("chunkByRelevance calculates savings percent", () => {
|
|
324
|
-
const result = chunkByRelevance(TYPESCRIPT_CODE, "ConfigManager", {
|
|
325
|
-
maxChunks: 1,
|
|
326
|
-
minScore: 0,
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
assert.ok(result.savingsPercent >= 0 && result.savingsPercent <= 100,
|
|
330
|
-
`Savings ${result.savingsPercent}% should be between 0 and 100`);
|
|
331
|
-
if (result.omittedChunks > 0) {
|
|
332
|
-
assert.ok(result.savingsPercent > 0, "Should have positive savings when chunks are omitted");
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
test("chunkByRelevance handles empty content", () => {
|
|
337
|
-
const result = chunkByRelevance("", "query");
|
|
338
|
-
assert.deepEqual(result.chunks, []);
|
|
339
|
-
assert.equal(result.totalChunks, 0);
|
|
340
|
-
assert.equal(result.omittedChunks, 0);
|
|
341
|
-
assert.equal(result.savingsPercent, 0);
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
test("chunkByRelevance uses default options when none provided", () => {
|
|
345
|
-
const result = chunkByRelevance(TYPESCRIPT_CODE, "Config");
|
|
346
|
-
assert.ok(result.chunks.length <= 5, "Default maxChunks should be 5");
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
// ─── formatChunks ───────────────────────────────────────────────────────────
|
|
350
|
-
|
|
351
|
-
test("formatChunks produces line range markers", () => {
|
|
352
|
-
const result: ChunkResult = {
|
|
353
|
-
chunks: [
|
|
354
|
-
{ content: "line one\nline two", startLine: 1, endLine: 2, score: 1 },
|
|
355
|
-
{ content: "line ten\nline eleven", startLine: 10, endLine: 11, score: 0.5 },
|
|
356
|
-
],
|
|
357
|
-
totalChunks: 5,
|
|
358
|
-
omittedChunks: 3,
|
|
359
|
-
savingsPercent: 60,
|
|
360
|
-
};
|
|
361
|
-
|
|
362
|
-
const formatted = formatChunks(result, "src/config.ts");
|
|
363
|
-
assert.ok(formatted.includes("[Lines 1-2]"), "Should include first line range");
|
|
364
|
-
assert.ok(formatted.includes("[Lines 10-11]"), "Should include second line range");
|
|
365
|
-
assert.ok(formatted.includes("line one\nline two"), "Should include first chunk content");
|
|
366
|
-
assert.ok(formatted.includes("line ten\nline eleven"), "Should include second chunk content");
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
test("formatChunks shows omission indicators between non-contiguous chunks", () => {
|
|
370
|
-
const result: ChunkResult = {
|
|
371
|
-
chunks: [
|
|
372
|
-
{ content: "first chunk", startLine: 1, endLine: 5, score: 1 },
|
|
373
|
-
{ content: "second chunk", startLine: 81, endLine: 90, score: 0.5 },
|
|
374
|
-
],
|
|
375
|
-
totalChunks: 4,
|
|
376
|
-
omittedChunks: 2,
|
|
377
|
-
savingsPercent: 50,
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
const formatted = formatChunks(result, "src/main.ts");
|
|
381
|
-
assert.ok(formatted.includes("[...75 lines omitted...]"),
|
|
382
|
-
`Expected omission marker, got:\n${formatted}`);
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
test("formatChunks handles empty result", () => {
|
|
386
|
-
const result: ChunkResult = {
|
|
387
|
-
chunks: [],
|
|
388
|
-
totalChunks: 0,
|
|
389
|
-
omittedChunks: 0,
|
|
390
|
-
savingsPercent: 0,
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
const formatted = formatChunks(result, "empty.ts");
|
|
394
|
-
assert.ok(formatted.includes("empty.ts"), "Should mention the file path");
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
test("formatChunks does not show omission for contiguous chunks", () => {
|
|
398
|
-
const result: ChunkResult = {
|
|
399
|
-
chunks: [
|
|
400
|
-
{ content: "chunk one", startLine: 1, endLine: 5, score: 1 },
|
|
401
|
-
{ content: "chunk two", startLine: 6, endLine: 10, score: 0.8 },
|
|
402
|
-
],
|
|
403
|
-
totalChunks: 2,
|
|
404
|
-
omittedChunks: 0,
|
|
405
|
-
savingsPercent: 0,
|
|
406
|
-
};
|
|
407
|
-
|
|
408
|
-
const formatted = formatChunks(result, "src/test.ts");
|
|
409
|
-
assert.ok(!formatted.includes("omitted"), "Contiguous chunks should not show omission");
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
// ─── inlineFileSmart integration tests ─────────────────────────────────────
|
|
413
|
-
|
|
414
|
-
// These test the formatChunks function in the context of how it'll be used
|
|
415
|
-
test("formatChunks includes file path in line range headers", () => {
|
|
416
|
-
const result = chunkByRelevance(
|
|
417
|
-
"export function foo() {}\n\nexport function bar() {}\n\nexport function baz() {}",
|
|
418
|
-
"foo function",
|
|
419
|
-
{ maxChunks: 1 },
|
|
420
|
-
);
|
|
421
|
-
const formatted = formatChunks(result, "src/utils.ts");
|
|
422
|
-
assert.ok(
|
|
423
|
-
formatted.includes("src/utils.ts") || formatted.includes("[Lines"),
|
|
424
|
-
"Formatted output should include file path or line range markers",
|
|
425
|
-
);
|
|
426
|
-
});
|