scai 0.1.138 → 0.1.139
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/dist/agents/MainAgent.js
CHANGED
|
@@ -230,8 +230,8 @@ export class MainAgent {
|
|
|
230
230
|
userOutput("All input/output logs can be found at ~/.scai/input_output.log");
|
|
231
231
|
logLine("RUN", "complete", stopRun());
|
|
232
232
|
// ───────────── LOG FINAL CONTEXT ─────────────
|
|
233
|
-
|
|
234
|
-
console.dir(this.context, { depth: null, colors: true });
|
|
233
|
+
console.log("\n[DEBUG] Final MainAgent context:");
|
|
234
|
+
console.dir(this.context, { depth: null, colors: true });
|
|
235
235
|
return stepIO;
|
|
236
236
|
}
|
|
237
237
|
/* ───────────── helpers ───────────── */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// File: src/modules/writeFileModule.ts
|
|
2
2
|
import fs from "fs/promises";
|
|
3
3
|
import path from "path";
|
|
4
|
+
import chalk from "chalk";
|
|
4
5
|
import { normalizePath } from "../utils/contentUtils.js";
|
|
5
6
|
import { logInputOutput } from "../utils/promptLogHelper.js";
|
|
6
7
|
export const writeFileStep = {
|
|
@@ -10,54 +11,54 @@ export const writeFileStep = {
|
|
|
10
11
|
groups: ["finalize"],
|
|
11
12
|
run: async (input) => {
|
|
12
13
|
var _a;
|
|
14
|
+
console.log(">>> writeFileStep starting");
|
|
13
15
|
const context = input.context;
|
|
14
16
|
const mode = input.data?.mode ?? "overwrite";
|
|
15
17
|
const writtenFiles = [];
|
|
16
18
|
const errors = [];
|
|
17
|
-
/* ───────────── guard ───────────── */
|
|
18
19
|
if (!context) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
data: {
|
|
22
|
-
writeMode: mode,
|
|
23
|
-
writtenFiles,
|
|
24
|
-
errors: ["Missing execution context"]
|
|
25
|
-
}
|
|
26
|
-
};
|
|
20
|
+
console.error("writeFileStep: Missing execution context");
|
|
21
|
+
return { query: input.query, data: { writeMode: mode, writtenFiles, errors: ["Missing execution context"] } };
|
|
27
22
|
}
|
|
23
|
+
console.log("writeFileStep: context exists");
|
|
24
|
+
console.log("writeFileStep: mode =", mode);
|
|
25
|
+
console.log("writeFileStep: existing touchedFiles =", context.plan?.touchedFiles);
|
|
28
26
|
const artifacts = context.execution?.codeTransformArtifacts?.files ?? [];
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
errors: ["No codeTransform artifacts found to write"]
|
|
36
|
-
}
|
|
37
|
-
};
|
|
27
|
+
console.log("writeFileStep: found codeTransformArtifacts.files =", artifacts.length);
|
|
28
|
+
if (artifacts.length) {
|
|
29
|
+
console.log("writeFileStep: filePaths =", artifacts.map(f => f.filePath));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.warn("writeFileStep: No artifacts found to write");
|
|
38
33
|
}
|
|
39
|
-
/* ───────────── write files ───────────── */
|
|
40
34
|
for (const f of artifacts) {
|
|
35
|
+
console.log("Processing artifact:", f.filePath);
|
|
41
36
|
const filePath = normalizePath(f.filePath);
|
|
42
37
|
if (!filePath) {
|
|
43
|
-
|
|
38
|
+
const msg = `Invalid filePath: ${f.filePath}`;
|
|
39
|
+
console.error(msg);
|
|
40
|
+
errors.push(msg);
|
|
44
41
|
continue;
|
|
45
42
|
}
|
|
46
43
|
if (typeof f.content !== "string" || !f.content.trim()) {
|
|
47
|
-
|
|
44
|
+
const msg = `No content to write for ${filePath}`;
|
|
45
|
+
console.error(msg);
|
|
46
|
+
errors.push(msg);
|
|
48
47
|
continue;
|
|
49
48
|
}
|
|
50
49
|
try {
|
|
51
50
|
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
52
51
|
await fs.writeFile(filePath, f.content, "utf-8");
|
|
52
|
+
console.log(chalk.green(`✅ Wrote file: ${filePath}`));
|
|
53
53
|
writtenFiles.push(filePath);
|
|
54
54
|
}
|
|
55
55
|
catch (err) {
|
|
56
56
|
const msg = err?.message ?? String(err);
|
|
57
|
+
console.error(chalk.red(`❌ Failed writing ${filePath}: ${msg}`));
|
|
57
58
|
errors.push(`${filePath}: ${msg}`);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
+
// mark files as touched if not already
|
|
61
62
|
context.plan ?? (context.plan = {});
|
|
62
63
|
(_a = context.plan).touchedFiles ?? (_a.touchedFiles = []);
|
|
63
64
|
for (const file of writtenFiles) {
|
|
@@ -65,15 +66,13 @@ export const writeFileStep = {
|
|
|
65
66
|
context.plan.touchedFiles.push(file);
|
|
66
67
|
}
|
|
67
68
|
}
|
|
69
|
+
console.log("writeFileStep: touchedFiles after run =", context.plan.touchedFiles);
|
|
68
70
|
const output = {
|
|
69
71
|
query: input.query,
|
|
70
|
-
data: {
|
|
71
|
-
writeMode: mode,
|
|
72
|
-
writtenFiles,
|
|
73
|
-
errors
|
|
74
|
-
}
|
|
72
|
+
data: { writeMode: mode, writtenFiles, errors }
|
|
75
73
|
};
|
|
76
74
|
logInputOutput("writeFile", "output", output.data);
|
|
75
|
+
console.log(">>> writeFileStep complete");
|
|
77
76
|
return output;
|
|
78
77
|
}
|
|
79
78
|
};
|
|
@@ -31,7 +31,7 @@ export const codeTransformModule = {
|
|
|
31
31
|
description: "Transforms a single file specified in the current plan step based on user instruction.",
|
|
32
32
|
groups: ["transform"],
|
|
33
33
|
run: async (input) => {
|
|
34
|
-
var _a, _b, _c
|
|
34
|
+
var _a, _b, _c;
|
|
35
35
|
const query = typeof input.query === "string" ? input.query : String(input.query ?? "");
|
|
36
36
|
const context = input.context;
|
|
37
37
|
if (!context) {
|
|
@@ -48,10 +48,8 @@ export const codeTransformModule = {
|
|
|
48
48
|
return { query, data: { files: [], errors: [`Target file not found or missing code: ${targetFile}`] } };
|
|
49
49
|
}
|
|
50
50
|
const normalizedQuery = context.analysis?.intent?.normalizedQuery ?? query;
|
|
51
|
-
|
|
52
|
-
const fileAnalysis = context.analysis?.fileAnalysis?.[file.path]; // ✅ correct
|
|
51
|
+
const fileAnalysis = context.analysis?.fileAnalysis?.[file.path];
|
|
53
52
|
const proposed = fileAnalysis?.proposedChanges;
|
|
54
|
-
// 🔹 NEW: pre-render guidance block for prompts
|
|
55
53
|
const proposedChangesBlock = proposed
|
|
56
54
|
? `
|
|
57
55
|
Proposed changes for this file:
|
|
@@ -64,6 +62,8 @@ ${proposed.rationale ? `- Rationale: ${proposed.rationale}` : ""}
|
|
|
64
62
|
const outputs = [];
|
|
65
63
|
const perFileErrors = [];
|
|
66
64
|
const tokenCount = countTokens(file.code);
|
|
65
|
+
context.execution || (context.execution = {});
|
|
66
|
+
(_a = context.execution).codeTransformArtifacts || (_a.codeTransformArtifacts = { files: [] });
|
|
67
67
|
// ───────────── SMALL FILE ─────────────
|
|
68
68
|
if (tokenCount <= SINGLE_SHOT_TOKEN_LIMIT) {
|
|
69
69
|
logInputOutput("codeTransform", "output", {
|
|
@@ -109,29 +109,32 @@ JSON schema:
|
|
|
109
109
|
responseSnippet: String(llmResponse.data ?? "").slice(0, 200),
|
|
110
110
|
});
|
|
111
111
|
const cleaned = await cleanupModule.run({ query, content: llmResponse.data });
|
|
112
|
-
|
|
112
|
+
let finalContent;
|
|
113
|
+
let notes = undefined;
|
|
113
114
|
if (typeof cleaned.data === 'string') {
|
|
114
|
-
|
|
115
|
+
// Raw code returned
|
|
116
|
+
finalContent = cleaned.data;
|
|
117
|
+
console.debug(chalk.yellow(` - [cleanupModule] Using raw code output for ${file.path}`));
|
|
118
|
+
}
|
|
119
|
+
else if (cleaned.data &&
|
|
120
|
+
typeof cleaned.data === 'object' &&
|
|
121
|
+
Array.isArray(cleaned.data.files)) {
|
|
122
|
+
// Structured JSON returned
|
|
123
|
+
const structured = cleaned.data;
|
|
124
|
+
const out = structured.files.find(f => f.filePath === file.path);
|
|
125
|
+
finalContent = out?.content ?? file.code;
|
|
126
|
+
notes = out?.notes;
|
|
127
|
+
perFileErrors.push(...(structured.errors ?? []));
|
|
115
128
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
: null;
|
|
120
|
-
if (!out || typeof out.content !== "string") {
|
|
121
|
-
return { query, data: { files: [], errors: [`Model did not return valid content for ${file.path}`] } };
|
|
129
|
+
else {
|
|
130
|
+
// Fallback
|
|
131
|
+
finalContent = file.code;
|
|
122
132
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
perFileErrors.push(...(structured.errors ?? []));
|
|
126
|
-
context.execution || (context.execution = {});
|
|
127
|
-
(_a = context.execution).codeTransformArtifacts || (_a.codeTransformArtifacts = { files: [] });
|
|
133
|
+
outputs.push({ filePath: file.path, content: finalContent, notes });
|
|
134
|
+
// ensure artifacts are updated
|
|
128
135
|
context.execution.codeTransformArtifacts.files =
|
|
129
136
|
context.execution.codeTransformArtifacts.files.filter(f => f.filePath !== file.path);
|
|
130
|
-
context.execution.codeTransformArtifacts.files.push(
|
|
131
|
-
filePath: file.path,
|
|
132
|
-
content: finalContent,
|
|
133
|
-
notes: perFileErrors.length ? perFileErrors.join("; ") : undefined,
|
|
134
|
-
});
|
|
137
|
+
context.execution.codeTransformArtifacts.files.push(outputs[0]);
|
|
135
138
|
context.plan || (context.plan = {});
|
|
136
139
|
(_b = context.plan).touchedFiles || (_b.touchedFiles = []);
|
|
137
140
|
if (!context.plan.touchedFiles.includes(file.path))
|
|
@@ -141,12 +144,16 @@ JSON schema:
|
|
|
141
144
|
return output;
|
|
142
145
|
}
|
|
143
146
|
catch (err) {
|
|
144
|
-
|
|
147
|
+
const finalContent = file.code;
|
|
148
|
+
outputs.push({ filePath: file.path, content: finalContent });
|
|
149
|
+
perFileErrors.push(`LLM call or cleanup failed: ${err.message}`);
|
|
150
|
+
context.execution.codeTransformArtifacts.files.push(outputs[0]);
|
|
151
|
+
const output = { query, data: { files: outputs, errors: perFileErrors } };
|
|
152
|
+
return output;
|
|
145
153
|
}
|
|
146
154
|
}
|
|
147
155
|
// ───────────── LARGE FILE (chunked) ─────────────
|
|
148
156
|
const chunks = splitCodeIntoChunks(file.code, CHUNK_TOKEN_LIMIT);
|
|
149
|
-
// ⚠️ USER-FACING WARNING
|
|
150
157
|
console.warn(chalk.yellow([
|
|
151
158
|
"",
|
|
152
159
|
"⚠️ Large file detected — falling back to chunked transformation",
|
|
@@ -215,13 +222,13 @@ ${chunk}
|
|
|
215
222
|
logInputOutput("codeTransform", "output", { file: file.path, chunkIndex: i + 1, error: err.message, message: "Chunk transformation failed, original preserved" });
|
|
216
223
|
}
|
|
217
224
|
}
|
|
218
|
-
|
|
219
|
-
outputs.push({ filePath: file.path, content:
|
|
220
|
-
context.execution
|
|
221
|
-
|
|
222
|
-
context.execution.codeTransformArtifacts.files.push(
|
|
225
|
+
const finalContent = transformedChunks.join("\n");
|
|
226
|
+
outputs.push({ filePath: file.path, content: finalContent });
|
|
227
|
+
context.execution.codeTransformArtifacts.files =
|
|
228
|
+
context.execution.codeTransformArtifacts.files.filter(f => f.filePath !== file.path);
|
|
229
|
+
context.execution.codeTransformArtifacts.files.push(outputs[0]);
|
|
223
230
|
context.plan || (context.plan = {});
|
|
224
|
-
(
|
|
231
|
+
(_c = context.plan).touchedFiles || (_c.touchedFiles = []);
|
|
225
232
|
if (!context.plan.touchedFiles.includes(file.path))
|
|
226
233
|
context.plan.touchedFiles.push(file.path);
|
|
227
234
|
const output = { query, data: { files: outputs, errors: perFileErrors } };
|