localptp 0.1.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/LICENSE +23 -0
- package/README.md +159 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.js +344 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/config.d.ts +14 -0
- package/dist/commands/config.js +65 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/context.d.ts +12 -0
- package/dist/commands/context.js +176 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/doctor.d.ts +16 -0
- package/dist/commands/doctor.js +54 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/index.d.ts +13 -0
- package/dist/commands/index.js +70 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +15 -0
- package/dist/commands/init.js +46 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/plan.d.ts +17 -0
- package/dist/commands/plan.js +170 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/resume.d.ts +17 -0
- package/dist/commands/resume.js +75 -0
- package/dist/commands/resume.js.map +1 -0
- package/dist/commands/review.d.ts +17 -0
- package/dist/commands/review.js +67 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/run.d.ts +24 -0
- package/dist/commands/run.js +65 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/step.d.ts +44 -0
- package/dist/commands/step.js +50 -0
- package/dist/commands/step.js.map +1 -0
- package/dist/commands/summarize.d.ts +17 -0
- package/dist/commands/summarize.js +276 -0
- package/dist/commands/summarize.js.map +1 -0
- package/dist/commands/task.d.ts +13 -0
- package/dist/commands/task.js +53 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/core/activePointer.d.ts +28 -0
- package/dist/core/activePointer.js +84 -0
- package/dist/core/activePointer.js.map +1 -0
- package/dist/core/approval.d.ts +12 -0
- package/dist/core/approval.js +34 -0
- package/dist/core/approval.js.map +1 -0
- package/dist/core/configManager.d.ts +32 -0
- package/dist/core/configManager.js +177 -0
- package/dist/core/configManager.js.map +1 -0
- package/dist/core/contextBuilder.d.ts +40 -0
- package/dist/core/contextBuilder.js +406 -0
- package/dist/core/contextBuilder.js.map +1 -0
- package/dist/core/memoryLoader.d.ts +4 -0
- package/dist/core/memoryLoader.js +35 -0
- package/dist/core/memoryLoader.js.map +1 -0
- package/dist/core/memoryManager.d.ts +41 -0
- package/dist/core/memoryManager.js +181 -0
- package/dist/core/memoryManager.js.map +1 -0
- package/dist/core/memoryPolicy.d.ts +23 -0
- package/dist/core/memoryPolicy.js +73 -0
- package/dist/core/memoryPolicy.js.map +1 -0
- package/dist/core/modelClient.d.ts +37 -0
- package/dist/core/modelClient.js +160 -0
- package/dist/core/modelClient.js.map +1 -0
- package/dist/core/patchManager.d.ts +89 -0
- package/dist/core/patchManager.js +801 -0
- package/dist/core/patchManager.js.map +1 -0
- package/dist/core/plannerJson.d.ts +23 -0
- package/dist/core/plannerJson.js +118 -0
- package/dist/core/plannerJson.js.map +1 -0
- package/dist/core/promptManager.d.ts +16 -0
- package/dist/core/promptManager.js +35 -0
- package/dist/core/promptManager.js.map +1 -0
- package/dist/core/prompts.d.ts +8 -0
- package/dist/core/prompts.js +18 -0
- package/dist/core/prompts.js.map +1 -0
- package/dist/core/repoIndexer.d.ts +21 -0
- package/dist/core/repoIndexer.js +557 -0
- package/dist/core/repoIndexer.js.map +1 -0
- package/dist/core/reviewEngine.d.ts +53 -0
- package/dist/core/reviewEngine.js +229 -0
- package/dist/core/reviewEngine.js.map +1 -0
- package/dist/core/runLoop.d.ts +26 -0
- package/dist/core/runLoop.js +103 -0
- package/dist/core/runLoop.js.map +1 -0
- package/dist/core/runStep.d.ts +42 -0
- package/dist/core/runStep.js +586 -0
- package/dist/core/runStep.js.map +1 -0
- package/dist/core/safetyManager.d.ts +7 -0
- package/dist/core/safetyManager.js +202 -0
- package/dist/core/safetyManager.js.map +1 -0
- package/dist/core/sessionManager.d.ts +35 -0
- package/dist/core/sessionManager.js +265 -0
- package/dist/core/sessionManager.js.map +1 -0
- package/dist/core/stopConditions.d.ts +24 -0
- package/dist/core/stopConditions.js +18 -0
- package/dist/core/stopConditions.js.map +1 -0
- package/dist/core/taskManager.d.ts +26 -0
- package/dist/core/taskManager.js +312 -0
- package/dist/core/taskManager.js.map +1 -0
- package/dist/core/testRunner.d.ts +27 -0
- package/dist/core/testRunner.js +71 -0
- package/dist/core/testRunner.js.map +1 -0
- package/dist/prompts/coder.d.ts +3 -0
- package/dist/prompts/coder.js +46 -0
- package/dist/prompts/coder.js.map +1 -0
- package/dist/prompts/planner.d.ts +3 -0
- package/dist/prompts/planner.js +44 -0
- package/dist/prompts/planner.js.map +1 -0
- package/dist/prompts/reviewer.d.ts +3 -0
- package/dist/prompts/reviewer.js +41 -0
- package/dist/prompts/reviewer.js.map +1 -0
- package/dist/prompts/summarizer.d.ts +3 -0
- package/dist/prompts/summarizer.js +65 -0
- package/dist/prompts/summarizer.js.map +1 -0
- package/dist/prompts/testFixer.d.ts +3 -0
- package/dist/prompts/testFixer.js +33 -0
- package/dist/prompts/testFixer.js.map +1 -0
- package/dist/repl/approver.d.ts +15 -0
- package/dist/repl/approver.js +21 -0
- package/dist/repl/approver.js.map +1 -0
- package/dist/repl/dispatch.d.ts +48 -0
- package/dist/repl/dispatch.js +164 -0
- package/dist/repl/dispatch.js.map +1 -0
- package/dist/repl/loop.d.ts +14 -0
- package/dist/repl/loop.js +124 -0
- package/dist/repl/loop.js.map +1 -0
- package/dist/repl/tokenize.d.ts +13 -0
- package/dist/repl/tokenize.js +56 -0
- package/dist/repl/tokenize.js.map +1 -0
- package/dist/templates/memory.d.ts +13 -0
- package/dist/templates/memory.js +32 -0
- package/dist/templates/memory.js.map +1 -0
- package/dist/types/config.d.ts +235 -0
- package/dist/types/config.js +66 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/context.d.ts +78 -0
- package/dist/types/context.js +141 -0
- package/dist/types/context.js.map +1 -0
- package/dist/types/index.d.ts +117 -0
- package/dist/types/index.js +24 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/model.d.ts +35 -0
- package/dist/types/model.js +16 -0
- package/dist/types/model.js.map +1 -0
- package/dist/types/patch.d.ts +38 -0
- package/dist/types/patch.js +11 -0
- package/dist/types/patch.js.map +1 -0
- package/dist/types/plan.d.ts +86 -0
- package/dist/types/plan.js +27 -0
- package/dist/types/plan.js.map +1 -0
- package/dist/types/review.d.ts +33 -0
- package/dist/types/review.js +24 -0
- package/dist/types/review.js.map +1 -0
- package/dist/types/run.d.ts +34 -0
- package/dist/types/run.js +2 -0
- package/dist/types/run.js.map +1 -0
- package/dist/types/session.d.ts +21 -0
- package/dist/types/session.js +2 -0
- package/dist/types/session.js.map +1 -0
- package/dist/types/summary.d.ts +65 -0
- package/dist/types/summary.js +26 -0
- package/dist/types/summary.js.map +1 -0
- package/dist/types/task.d.ts +31 -0
- package/dist/types/task.js +10 -0
- package/dist/types/task.js.map +1 -0
- package/dist/types/test.d.ts +16 -0
- package/dist/types/test.js +2 -0
- package/dist/types/test.js.map +1 -0
- package/dist/utils/fs.d.ts +13 -0
- package/dist/utils/fs.js +65 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/gitRoot.d.ts +5 -0
- package/dist/utils/gitRoot.js +21 -0
- package/dist/utils/gitRoot.js.map +1 -0
- package/dist/utils/logger.d.ts +15 -0
- package/dist/utils/logger.js +60 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/paths.d.ts +13 -0
- package/dist/utils/paths.js +24 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/tokenEstimate.d.ts +5 -0
- package/dist/utils/tokenEstimate.js +8 -0
- package/dist/utils/tokenEstimate.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Builder (HLD-SRD §3.7, §6, §9, §10.1).
|
|
3
|
+
*
|
|
4
|
+
* `buildContext` is a PURE, deterministic function: it performs no I/O and
|
|
5
|
+
* reads only the data handed to it (including a preloaded `fileContents` map).
|
|
6
|
+
* It therefore takes no ModelClient and structurally cannot call the model.
|
|
7
|
+
*
|
|
8
|
+
* Pipeline: heuristic selection (task-driven, else preview) → per-file hard cap
|
|
9
|
+
* → assembly → the §3.7 seven-step over-budget reduction ladder.
|
|
10
|
+
*/
|
|
11
|
+
import path from "node:path";
|
|
12
|
+
import { estimateTokens } from "../utils/tokenEstimate.js";
|
|
13
|
+
import { KNOWN_BINARY_EXT } from "./repoIndexer.js";
|
|
14
|
+
import { CODER_SYSTEM_PROMPT } from "./prompts.js";
|
|
15
|
+
import { firstIncompleteSubtask, } from "../types/context.js";
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Memory selection order (HLD-SRD §3.7)
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
/**
|
|
20
|
+
* Conditional memory in priority order. `coding-rules.md` is intentionally
|
|
21
|
+
* absent — it is the always-include, ladder-protected project-rules file.
|
|
22
|
+
*/
|
|
23
|
+
const CONDITIONAL_MEMORY_ORDER = [
|
|
24
|
+
"project-brief.md",
|
|
25
|
+
"file-index.md",
|
|
26
|
+
"data-model.md",
|
|
27
|
+
"api-map.md",
|
|
28
|
+
"external-integrations.md",
|
|
29
|
+
"decisions.md",
|
|
30
|
+
"test-plan.md",
|
|
31
|
+
];
|
|
32
|
+
const ALWAYS_MEMORY = ["coding-rules.md"];
|
|
33
|
+
const TRUNCATION_MARKER = "\n… [truncated]\n";
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Helpers
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
function toPosix(p) {
|
|
38
|
+
return p.replace(/\\/g, "/");
|
|
39
|
+
}
|
|
40
|
+
function stripExt(p) {
|
|
41
|
+
const ext = path.posix.extname(p);
|
|
42
|
+
return ext ? p.slice(0, -ext.length) : p;
|
|
43
|
+
}
|
|
44
|
+
function isBinaryEntry(f) {
|
|
45
|
+
if (f.language === "binary")
|
|
46
|
+
return true;
|
|
47
|
+
return KNOWN_BINARY_EXT.has(f.extension.toLowerCase());
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a relative import specifier (`./x`, `../y`) against indexed paths by
|
|
51
|
+
* suffix match. Returns the matched indexed path, or undefined. Bare package
|
|
52
|
+
* specifiers and node builtins are ignored (return undefined).
|
|
53
|
+
*/
|
|
54
|
+
function resolveImport(specifier, fromPath, byPath) {
|
|
55
|
+
if (!specifier.startsWith("."))
|
|
56
|
+
return undefined; // package / builtin
|
|
57
|
+
// Normalize the specifier relative to the importing file's directory.
|
|
58
|
+
const fromDir = path.posix.dirname(toPosix(fromPath));
|
|
59
|
+
const resolved = stripExt(toPosix(path.posix.normalize(`${fromDir}/${specifier}`)));
|
|
60
|
+
// Exact (extensionless) match first, then index-suffix match.
|
|
61
|
+
for (const indexed of byPath.keys()) {
|
|
62
|
+
if (stripExt(indexed) === resolved)
|
|
63
|
+
return indexed;
|
|
64
|
+
}
|
|
65
|
+
const tail = stripExt(toPosix(specifier).replace(/^\.\//, "").replace(/^\.\.\//, ""));
|
|
66
|
+
for (const indexed of byPath.keys()) {
|
|
67
|
+
const ix = stripExt(indexed);
|
|
68
|
+
if (ix === tail || ix.endsWith(`/${tail}`))
|
|
69
|
+
return indexed;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The import-neighbor source files of a set of seed files: every indexed file
|
|
75
|
+
* a seed's `imports[]` resolves to (by suffix match), excluding the seeds
|
|
76
|
+
* themselves. Deterministic: sorted by size asc then path asc.
|
|
77
|
+
*/
|
|
78
|
+
export function importNeighbors(seedFiles, index) {
|
|
79
|
+
const byPath = new Map();
|
|
80
|
+
for (const f of index.files)
|
|
81
|
+
byPath.set(toPosix(f.path), f);
|
|
82
|
+
const seeds = new Set(seedFiles.map(toPosix));
|
|
83
|
+
const found = new Map();
|
|
84
|
+
for (const seed of seeds) {
|
|
85
|
+
const entry = byPath.get(seed);
|
|
86
|
+
if (!entry)
|
|
87
|
+
continue;
|
|
88
|
+
for (const spec of entry.imports) {
|
|
89
|
+
const resolved = resolveImport(spec, seed, byPath);
|
|
90
|
+
if (resolved && !seeds.has(resolved)) {
|
|
91
|
+
const f = byPath.get(resolved);
|
|
92
|
+
if (f && !isBinaryEntry(f))
|
|
93
|
+
found.set(resolved, f);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return [...found.values()].sort(compareBySizeThenPath).map((f) => f.path);
|
|
98
|
+
}
|
|
99
|
+
function compareBySizeThenPath(a, b) {
|
|
100
|
+
if (a.size !== b.size)
|
|
101
|
+
return a.size - b.size;
|
|
102
|
+
return a.path.localeCompare(b.path);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* A no-model summary: an index header (path/language/exports/size) followed by
|
|
106
|
+
* the file's first 20 non-blank lines.
|
|
107
|
+
*/
|
|
108
|
+
export function summarizeFile(entry, body) {
|
|
109
|
+
const exportsStr = entry.exports.length > 0 ? entry.exports.join(", ") : "(none)";
|
|
110
|
+
const header = `// ${entry.path} · ${entry.language} · ${entry.size} bytes · exports: ${exportsStr}`;
|
|
111
|
+
const head = body
|
|
112
|
+
.split(/\r?\n/)
|
|
113
|
+
.filter((l) => l.trim().length > 0)
|
|
114
|
+
.slice(0, 20)
|
|
115
|
+
.join("\n");
|
|
116
|
+
return `${header}\n${head}`;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A snippet: the first `floor(maxChars / 2)` characters plus a truncation
|
|
120
|
+
* marker. Bodies already at-or-under the snippet size are returned unchanged.
|
|
121
|
+
*/
|
|
122
|
+
export function snippetFile(body, maxChars) {
|
|
123
|
+
const limit = Math.floor(maxChars / 2);
|
|
124
|
+
if (body.length <= limit)
|
|
125
|
+
return body;
|
|
126
|
+
return body.slice(0, limit) + TRUNCATION_MARKER;
|
|
127
|
+
}
|
|
128
|
+
/** Hard-cap a body to `maxChars` (selection-time cap, assumption 5a). */
|
|
129
|
+
function hardCap(body, maxChars) {
|
|
130
|
+
if (body.length <= maxChars)
|
|
131
|
+
return body;
|
|
132
|
+
return body.slice(0, maxChars) + TRUNCATION_MARKER;
|
|
133
|
+
}
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Direct-test matching
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
/** The basename stem of a test path, stripping `.test`/`.spec` and `test_`. */
|
|
138
|
+
function sourceStemsForTest(testPath) {
|
|
139
|
+
const base = path.posix.basename(toPosix(testPath));
|
|
140
|
+
const noExt = stripExt(base); // e.g. Foo.test, test_foo, foo_test
|
|
141
|
+
const stems = new Set();
|
|
142
|
+
// Foo.test / Foo.spec → Foo
|
|
143
|
+
const dotted = noExt.replace(/\.(test|spec)$/i, "");
|
|
144
|
+
stems.add(dotted);
|
|
145
|
+
// test_foo → foo / foo_test → foo
|
|
146
|
+
stems.add(noExt.replace(/^test_/i, "").replace(/_test$/i, ""));
|
|
147
|
+
return [...stems];
|
|
148
|
+
}
|
|
149
|
+
/** Is `test` a direct test of `source`? (import resolves OR basename-stem). */
|
|
150
|
+
function isDirectTestOf(test, source, byPath) {
|
|
151
|
+
// (a) import resolution
|
|
152
|
+
for (const spec of test.imports) {
|
|
153
|
+
if (resolveImport(spec, test.path, byPath) === toPosix(source.path)) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// (b) basename-stem match
|
|
158
|
+
const sourceStem = stripExt(path.posix.basename(toPosix(source.path)));
|
|
159
|
+
return sourceStemsForTest(test.path).includes(sourceStem);
|
|
160
|
+
}
|
|
161
|
+
export function selectFiles(inputs) {
|
|
162
|
+
const { config, index, task } = inputs;
|
|
163
|
+
const ctx = config.context;
|
|
164
|
+
const warnings = [];
|
|
165
|
+
const byPath = new Map();
|
|
166
|
+
for (const f of index.files)
|
|
167
|
+
byPath.set(toPosix(f.path), f);
|
|
168
|
+
// Edit files: the current subtask's likelyFiles (capped).
|
|
169
|
+
let editFiles = [];
|
|
170
|
+
if (task) {
|
|
171
|
+
const subtask = firstIncompleteSubtask(task) ?? task.subtasks?.[0];
|
|
172
|
+
const likely = subtask?.likelyFiles ?? [];
|
|
173
|
+
// Keep only files that exist in the index and are not binary.
|
|
174
|
+
editFiles = likely
|
|
175
|
+
.map(toPosix)
|
|
176
|
+
.filter((p) => {
|
|
177
|
+
const f = byPath.get(p);
|
|
178
|
+
return f !== undefined && !isBinaryEntry(f);
|
|
179
|
+
})
|
|
180
|
+
.slice(0, ctx.maxEditFilesPerStep);
|
|
181
|
+
}
|
|
182
|
+
// Source files.
|
|
183
|
+
let sourceFiles;
|
|
184
|
+
let testFiles = [];
|
|
185
|
+
if (task) {
|
|
186
|
+
const neighbors = ctx.includeImportNeighbors
|
|
187
|
+
? importNeighbors(editFiles, index)
|
|
188
|
+
: [];
|
|
189
|
+
// Combined non-edit selection (neighbors + tests) is bounded by
|
|
190
|
+
// maxFilesPerStep. Edit files are reserved first and never dropped.
|
|
191
|
+
const combined = [...editFiles];
|
|
192
|
+
const seen = new Set(editFiles);
|
|
193
|
+
const room = () => combined.length < ctx.maxFilesPerStep;
|
|
194
|
+
for (const n of neighbors) {
|
|
195
|
+
if (!room())
|
|
196
|
+
break;
|
|
197
|
+
if (seen.has(n))
|
|
198
|
+
continue;
|
|
199
|
+
combined.push(n);
|
|
200
|
+
seen.add(n);
|
|
201
|
+
}
|
|
202
|
+
sourceFiles = combined.slice();
|
|
203
|
+
// Direct tests of any selected source file, filling remaining room.
|
|
204
|
+
if (ctx.includeTests) {
|
|
205
|
+
const selectedSources = sourceFiles
|
|
206
|
+
.map((p) => byPath.get(p))
|
|
207
|
+
.filter((f) => f !== undefined);
|
|
208
|
+
const testCandidates = index.files
|
|
209
|
+
.filter((f) => f.isTest && !isBinaryEntry(f))
|
|
210
|
+
.filter((t) => !seen.has(toPosix(t.path)))
|
|
211
|
+
.filter((t) => selectedSources.some((s) => isDirectTestOf(t, s, byPath)))
|
|
212
|
+
.sort(compareBySizeThenPath);
|
|
213
|
+
for (const t of testCandidates) {
|
|
214
|
+
if (!room())
|
|
215
|
+
break;
|
|
216
|
+
const p = toPosix(t.path);
|
|
217
|
+
if (seen.has(p))
|
|
218
|
+
continue;
|
|
219
|
+
testFiles.push(p);
|
|
220
|
+
seen.add(p);
|
|
221
|
+
combined.push(p);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
// Preview: smallest-first sample of non-test, non-config, non-binary source.
|
|
227
|
+
const sample = index.files
|
|
228
|
+
.filter((f) => !f.isTest && !f.isConfig && !isBinaryEntry(f))
|
|
229
|
+
.sort(compareBySizeThenPath)
|
|
230
|
+
.slice(0, ctx.maxFilesPerStep)
|
|
231
|
+
.map((f) => toPosix(f.path));
|
|
232
|
+
sourceFiles = sample;
|
|
233
|
+
warnings.push("No active task — showing a budget-capped preview. Run `localptp task \"…\"` to scope context.");
|
|
234
|
+
if (index.files.length === 0) {
|
|
235
|
+
warnings.push("No source files indexed.");
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return { editFiles, sourceFiles, testFiles, warnings };
|
|
239
|
+
}
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// Memory selection
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
function selectMemory(memory) {
|
|
244
|
+
const always = ALWAYS_MEMORY.filter((name) => memory[name] !== undefined);
|
|
245
|
+
const conditional = CONDITIONAL_MEMORY_ORDER.filter((name) => memory[name] !== undefined);
|
|
246
|
+
return { always, conditional };
|
|
247
|
+
}
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
// buildContext
|
|
250
|
+
// ---------------------------------------------------------------------------
|
|
251
|
+
const NARROW_TASK_WARNING = "Context package exceeds configured budget. Try narrowing the task or allow summaries/snippets.";
|
|
252
|
+
export function buildContext(inputs) {
|
|
253
|
+
const { role, config, index, memory, task, session, fileContents } = inputs;
|
|
254
|
+
const ctx = config.context;
|
|
255
|
+
const byPath = new Map();
|
|
256
|
+
for (const f of index.files)
|
|
257
|
+
byPath.set(toPosix(f.path), f);
|
|
258
|
+
const sel = selectFiles(inputs);
|
|
259
|
+
const warnings = [...sel.warnings];
|
|
260
|
+
// System prompt: §10.1 body, role-labeled header.
|
|
261
|
+
const systemPrompt = `[role: ${role}]\n${CODER_SYSTEM_PROMPT}`;
|
|
262
|
+
// Memory selection.
|
|
263
|
+
const mem = selectMemory(memory);
|
|
264
|
+
// Conditional memory may be dropped by ladder step 6 (reverse priority).
|
|
265
|
+
let conditionalMemory = [...mem.conditional];
|
|
266
|
+
// Resolve bodies for selected source/test files, hard-capped per assumption 5a.
|
|
267
|
+
// A path absent from fileContents (e.g. deleted since index) is dropped.
|
|
268
|
+
const bodyFor = (p) => {
|
|
269
|
+
const raw = fileContents[toPosix(p)];
|
|
270
|
+
if (raw === undefined)
|
|
271
|
+
return undefined;
|
|
272
|
+
return hardCap(raw, ctx.maxFileChars);
|
|
273
|
+
};
|
|
274
|
+
const presentSource = sel.sourceFiles.filter((p) => bodyFor(p) !== undefined);
|
|
275
|
+
const presentTests = sel.testFiles.filter((p) => bodyFor(p) !== undefined);
|
|
276
|
+
// Edit files are the protected subset of source actually present.
|
|
277
|
+
const editPresent = new Set(sel.editFiles.filter((p) => presentSource.includes(toPosix(p))).map(toPosix));
|
|
278
|
+
// Ladder state: which secondary source files are summarized / snippeted.
|
|
279
|
+
const summarized = new Set();
|
|
280
|
+
const snippeted = new Set();
|
|
281
|
+
// --- assembly -----------------------------------------------------------
|
|
282
|
+
const buildUserPrompt = () => {
|
|
283
|
+
const parts = [];
|
|
284
|
+
// Always-include task + session summaries (protected).
|
|
285
|
+
if (task) {
|
|
286
|
+
const goal = task.goal ?? "(no goal stated)";
|
|
287
|
+
const subtask = firstIncompleteSubtask(task) ?? task.subtasks?.[0];
|
|
288
|
+
parts.push(`## Task\n\nGoal: ${goal}`);
|
|
289
|
+
if (subtask)
|
|
290
|
+
parts.push(`Current subtask: ${subtask.text}`);
|
|
291
|
+
}
|
|
292
|
+
if (session) {
|
|
293
|
+
const lines = [];
|
|
294
|
+
if (session.currentState)
|
|
295
|
+
lines.push(`Current state: ${session.currentState}`);
|
|
296
|
+
if (session.nextStep)
|
|
297
|
+
lines.push(`Next step: ${session.nextStep}`);
|
|
298
|
+
if (lines.length > 0)
|
|
299
|
+
parts.push(`## Session\n\n${lines.join("\n")}`);
|
|
300
|
+
}
|
|
301
|
+
// Memory: always-include first (protected), then surviving conditional.
|
|
302
|
+
const memNames = [...mem.always, ...conditionalMemory];
|
|
303
|
+
for (const name of memNames) {
|
|
304
|
+
parts.push(`## Memory: ${name}\n\n${memory[name]}`);
|
|
305
|
+
}
|
|
306
|
+
// Source files.
|
|
307
|
+
for (const p of presentSource) {
|
|
308
|
+
const entry = byPath.get(toPosix(p));
|
|
309
|
+
const raw = bodyFor(p);
|
|
310
|
+
if (raw === undefined || !entry)
|
|
311
|
+
continue;
|
|
312
|
+
let body = raw;
|
|
313
|
+
if (summarized.has(toPosix(p))) {
|
|
314
|
+
body = summarizeFile(entry, fileContents[toPosix(p)] ?? raw);
|
|
315
|
+
}
|
|
316
|
+
else if (snippeted.has(toPosix(p))) {
|
|
317
|
+
body = snippetFile(raw, ctx.maxFileChars);
|
|
318
|
+
}
|
|
319
|
+
parts.push(`## Source: ${p}\n\n${body}`);
|
|
320
|
+
}
|
|
321
|
+
// Test files.
|
|
322
|
+
for (const p of presentTests) {
|
|
323
|
+
const raw = bodyFor(p);
|
|
324
|
+
if (raw === undefined)
|
|
325
|
+
continue;
|
|
326
|
+
let body = raw;
|
|
327
|
+
if (snippeted.has(toPosix(p)))
|
|
328
|
+
body = snippetFile(raw, ctx.maxFileChars);
|
|
329
|
+
parts.push(`## Test: ${p}\n\n${body}`);
|
|
330
|
+
}
|
|
331
|
+
return parts.join("\n\n");
|
|
332
|
+
};
|
|
333
|
+
const totalChars = () => systemPrompt.length + buildUserPrompt().length;
|
|
334
|
+
// --- budget ladder ------------------------------------------------------
|
|
335
|
+
const editSet = editPresent; // protected (steps 1–2)
|
|
336
|
+
const directTestSet = new Set(presentTests.map(toPosix)); // protected (step 3)
|
|
337
|
+
/** Secondary (non-edit, non-direct-test) source files, in selection order. */
|
|
338
|
+
const secondarySource = () => presentSource.filter((p) => !editSet.has(toPosix(p)) && !directTestSet.has(toPosix(p)));
|
|
339
|
+
if (totalChars() > ctx.maxContextChars) {
|
|
340
|
+
// Step 4 — summarize secondary source files.
|
|
341
|
+
let didSummarize = false;
|
|
342
|
+
for (const p of secondarySource()) {
|
|
343
|
+
if (totalChars() <= ctx.maxContextChars)
|
|
344
|
+
break;
|
|
345
|
+
if (!summarized.has(toPosix(p))) {
|
|
346
|
+
summarized.add(toPosix(p));
|
|
347
|
+
didSummarize = true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (didSummarize) {
|
|
351
|
+
warnings.push("Budget: replaced secondary source files with index summaries.");
|
|
352
|
+
}
|
|
353
|
+
// Step 5 — snippet remaining over-budget files (eligible = non-edit,
|
|
354
|
+
// non-direct-test; summarized files are already small, skip).
|
|
355
|
+
if (totalChars() > ctx.maxContextChars) {
|
|
356
|
+
let didSnippet = false;
|
|
357
|
+
for (const p of secondarySource()) {
|
|
358
|
+
if (totalChars() <= ctx.maxContextChars)
|
|
359
|
+
break;
|
|
360
|
+
const key = toPosix(p);
|
|
361
|
+
if (summarized.has(key))
|
|
362
|
+
continue;
|
|
363
|
+
if (!snippeted.has(key)) {
|
|
364
|
+
snippeted.add(key);
|
|
365
|
+
didSnippet = true;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (didSnippet) {
|
|
369
|
+
warnings.push("Budget: snippeted remaining over-budget files.");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// Step 6 — drop low-relevance memory (reverse conditional priority).
|
|
373
|
+
if (totalChars() > ctx.maxContextChars && conditionalMemory.length > 0) {
|
|
374
|
+
const dropped = [];
|
|
375
|
+
// Reverse priority: drop the lowest-priority conditional memory first.
|
|
376
|
+
while (totalChars() > ctx.maxContextChars &&
|
|
377
|
+
conditionalMemory.length > 0) {
|
|
378
|
+
const drop = conditionalMemory[conditionalMemory.length - 1];
|
|
379
|
+
conditionalMemory = conditionalMemory.slice(0, -1);
|
|
380
|
+
dropped.push(drop);
|
|
381
|
+
}
|
|
382
|
+
if (dropped.length > 0) {
|
|
383
|
+
warnings.push(`Budget: dropped low-relevance memory (${dropped.join(", ")}).`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
// Step 7 — still over budget: warn to narrow the task. Package still returned.
|
|
387
|
+
if (totalChars() > ctx.maxContextChars) {
|
|
388
|
+
warnings.push(NARROW_TASK_WARNING);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
// --- finalize -----------------------------------------------------------
|
|
392
|
+
const userPrompt = buildUserPrompt();
|
|
393
|
+
const includedMemoryFiles = [...mem.always, ...conditionalMemory];
|
|
394
|
+
const estimatedTokens = estimateTokens(systemPrompt + userPrompt);
|
|
395
|
+
return {
|
|
396
|
+
role,
|
|
397
|
+
systemPrompt,
|
|
398
|
+
userPrompt,
|
|
399
|
+
includedMemoryFiles,
|
|
400
|
+
includedSourceFiles: presentSource.map(toPosix),
|
|
401
|
+
includedTestFiles: presentTests.map(toPosix),
|
|
402
|
+
estimatedTokens,
|
|
403
|
+
warnings,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
//# sourceMappingURL=contextBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextBuilder.js","sourceRoot":"","sources":["../../src/core/contextBuilder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory loader (HLD-SRD §3.4, §3.7).
|
|
3
|
+
*
|
|
4
|
+
* Reads the top-level `/ai/*.md` files into a `name → content` map for the
|
|
5
|
+
* Context Builder. Subdirectories (`tasks/`, `sessions/`) and non-markdown
|
|
6
|
+
* files are ignored. A missing `/ai` dir yields an empty map (no crash).
|
|
7
|
+
*/
|
|
8
|
+
import { promises as fs } from "node:fs";
|
|
9
|
+
import { layout } from "../utils/paths.js";
|
|
10
|
+
export async function loadMemoryFiles(root) {
|
|
11
|
+
const l = layout(root);
|
|
12
|
+
const out = {};
|
|
13
|
+
let entries;
|
|
14
|
+
try {
|
|
15
|
+
entries = await fs.readdir(l.aiDir, { withFileTypes: true });
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Missing /ai dir (or unreadable) — degrade to an empty memory map.
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
if (!entry.isFile())
|
|
23
|
+
continue;
|
|
24
|
+
if (!entry.name.toLowerCase().endsWith(".md"))
|
|
25
|
+
continue;
|
|
26
|
+
try {
|
|
27
|
+
out[entry.name] = await fs.readFile(l.memoryFile(entry.name), "utf8");
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// A file that vanished mid-read is simply omitted.
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=memoryLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryLoader.js","sourceRoot":"","sources":["../../src/core/memoryLoader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAM3C,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,GAAG,GAAgB,EAAE,CAAC;IAE5B,IAAI,OAAmC,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;QACpE,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,SAAS;QAC9B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QACxD,IAAI,CAAC;YACH,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QACxE,CAAC;QAAC,MAAM,CAAC;YACP,mDAAmD;QACrD,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Layout } from "../utils/paths.js";
|
|
2
|
+
/**
|
|
3
|
+
* Per-entry character cap for appended memory entries (design §3, assumption 3).
|
|
4
|
+
* Content longer than this cap is truncated before writing.
|
|
5
|
+
*/
|
|
6
|
+
export declare const MAX_ENTRY_CHARS = 280;
|
|
7
|
+
export interface ScaffoldReport {
|
|
8
|
+
created: string[];
|
|
9
|
+
preserved: string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Replace or append a marker-delimited section in a file.
|
|
13
|
+
*
|
|
14
|
+
* Markers: `<!-- BEGIN localcoder:<markerId> -->` / `<!-- END localcoder:<markerId> -->`
|
|
15
|
+
*
|
|
16
|
+
* - If both markers exist: replaces the inner region with `\n${body}\n`, preserving
|
|
17
|
+
* all content outside.
|
|
18
|
+
* - If markers are absent: appends a fresh BEGIN/body/END block.
|
|
19
|
+
* - If duplicate BEGIN markers: replaces the first complete block, warns.
|
|
20
|
+
* - If file doesn't exist: creates it with just the marker block.
|
|
21
|
+
*/
|
|
22
|
+
export declare function updateMarkerSection(filePath: string, markerId: string, body: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Append a dated, length-capped entry under `sectionHeading` in `filePath`.
|
|
25
|
+
*
|
|
26
|
+
* Algorithm:
|
|
27
|
+
* 1. Read the file (or default to a title heading if absent).
|
|
28
|
+
* 2. Build the entry line: `- YYYY-MM-DD — <truncated content>`.
|
|
29
|
+
* 3. If the file already contains that exact line anywhere inside
|
|
30
|
+
* `## sectionHeading` → return (de-dupe same-day identical entry).
|
|
31
|
+
* 4. If `## sectionHeading` exists: insert the entry at the END of that
|
|
32
|
+
* section (just before the next `## ` of same/lower level or EOF).
|
|
33
|
+
* 5. If not: append a fresh `\n## sectionHeading\n<entry>\n` block.
|
|
34
|
+
* 6. Write file — only the inserted line differs; all prior prose is intact.
|
|
35
|
+
*/
|
|
36
|
+
export declare function appendMemoryEntry(filePath: string, sectionHeading: string, rawEntry: string): Promise<void>;
|
|
37
|
+
export declare class MemoryManager {
|
|
38
|
+
private readonly layout;
|
|
39
|
+
constructor(layout: Layout);
|
|
40
|
+
scaffold(): Promise<ScaffoldReport>;
|
|
41
|
+
}
|