executant 1.4.1 → 1.4.3
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/index.js
CHANGED
|
@@ -308,9 +308,10 @@ import { zodToJsonSchema } from "zod-to-json-schema";
|
|
|
308
308
|
|
|
309
309
|
// src/lib/utils.ts
|
|
310
310
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
311
|
-
import { dirname, join } from "node:path";
|
|
311
|
+
import { basename, dirname, join } from "node:path";
|
|
312
312
|
import { fileURLToPath } from "node:url";
|
|
313
|
-
var
|
|
313
|
+
var __dir = dirname(fileURLToPath(import.meta.url));
|
|
314
|
+
var PROMPTS_DIR = basename(__dir) === "lib" ? join(__dir, "..", "prompts") : join(__dir, "prompts");
|
|
314
315
|
function stripPromptHeader(raw) {
|
|
315
316
|
return raw.replace(/^(#[^\n]*\n)+\n?/, "").trim();
|
|
316
317
|
}
|
|
@@ -1291,6 +1292,21 @@ async function runPass3Judge(description, workflow2) {
|
|
|
1291
1292
|
return { pass: true, feedback: "", skipped: true };
|
|
1292
1293
|
}
|
|
1293
1294
|
}
|
|
1295
|
+
function isNumericSequence(arr) {
|
|
1296
|
+
return arr.every((item, i) => item === String(i + 1));
|
|
1297
|
+
}
|
|
1298
|
+
function normalizeWorkflow(workflow2) {
|
|
1299
|
+
return {
|
|
1300
|
+
...workflow2,
|
|
1301
|
+
steps: workflow2.steps.map((step) => {
|
|
1302
|
+
if (Array.isArray(step.forEach) && isNumericSequence(step.forEach)) {
|
|
1303
|
+
const { forEach, ...rest } = step;
|
|
1304
|
+
return { ...rest, repeat: forEach.length };
|
|
1305
|
+
}
|
|
1306
|
+
return step;
|
|
1307
|
+
})
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1294
1310
|
async function* streamPlan(args) {
|
|
1295
1311
|
const { description, taskFile } = args;
|
|
1296
1312
|
const skipResearch = args.fast || isSimpleRequest(description);
|
|
@@ -1413,7 +1429,7 @@ ${issues}` };
|
|
|
1413
1429
|
if (!judgeResult.pass) {
|
|
1414
1430
|
yield { type: "plan:warn", message: `Judge rejected plan but retries exhausted: ${judgeResult.feedback}` };
|
|
1415
1431
|
}
|
|
1416
|
-
const { goal, vars, steps, ...rest } = zodResult.data;
|
|
1432
|
+
const { goal, vars, steps, ...rest } = normalizeWorkflow(zodResult.data);
|
|
1417
1433
|
const ordered = { goal, ...vars && { vars }, steps, ...rest };
|
|
1418
1434
|
const yamlContent = dumpYaml(ordered, {
|
|
1419
1435
|
lineWidth: -1,
|
|
@@ -1970,7 +1986,7 @@ async function* withLogger(gen, logger2) {
|
|
|
1970
1986
|
|
|
1971
1987
|
// src/retrospective.ts
|
|
1972
1988
|
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1973
|
-
import { basename, dirname as dirname4, join as join4, resolve as resolve3 } from "node:path";
|
|
1989
|
+
import { basename as basename2, dirname as dirname4, join as join4, resolve as resolve3 } from "node:path";
|
|
1974
1990
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1975
1991
|
import { spawnSync } from "node:child_process";
|
|
1976
1992
|
import { load as parseYaml2 } from "js-yaml";
|
|
@@ -2030,7 +2046,7 @@ ${metrics}
|
|
|
2030
2046
|
${content}`;
|
|
2031
2047
|
}).join("\n\n---\n\n");
|
|
2032
2048
|
const originalYaml = readFileSync5(workflowFilePath, "utf8");
|
|
2033
|
-
const taskName =
|
|
2049
|
+
const taskName = basename2(workflowFilePath, ".yaml");
|
|
2034
2050
|
const prompt = RETROSPECTIVE_PROMPT.replaceAll("{{TASK_NAME}}", taskName).replaceAll("{{ORIGINAL_GOAL}}", workflow2.goal).replaceAll("{{ORIGINAL_YAML}}", originalYaml).replaceAll("{{HIGHLIGHTS}}", highlightContents).replaceAll("{{METRICS}}", metrics);
|
|
2035
2051
|
const result = spawnSync(
|
|
2036
2052
|
"claude",
|
|
@@ -97,6 +97,11 @@ Before finalising your JSON, scan every `prompt` and `command` field you wrote.
|
|
|
97
97
|
For each field, ask: "Does this contain a file path or directory path as a string literal?"
|
|
98
98
|
If yes, extract it to `vars` and replace with `{{var_name}}`.
|
|
99
99
|
|
|
100
|
+
**Pre-Output Self-Review — Repeat (MANDATORY):**
|
|
101
|
+
Scan every `forEach` field you wrote.
|
|
102
|
+
Ask: "Is this array just sequential numbers like `["1","2","3"]` with no meaningful items?"
|
|
103
|
+
If yes, replace the entire `forEach` with `repeat: N` where N is the count. Sequential-number forEach arrays are ALWAYS wrong — they are a misuse of forEach and must be converted to `repeat: N`.
|
|
104
|
+
|
|
100
105
|
## When to Use Each Step Type
|
|
101
106
|
|
|
102
107
|
**Use `prompt` steps (AI-assisted) for:**
|
|
@@ -59,6 +59,13 @@ Are all file paths declared in `vars`?
|
|
|
59
59
|
- Do any `prompt` or `command` fields contain hardcoded file paths or directory paths?
|
|
60
60
|
- Hardcoded paths in steps (not in `vars`) are a violation
|
|
61
61
|
|
|
62
|
+
### 5. Repeat Misuse (if applicable)
|
|
63
|
+
If the user's goal mentions "N times", "repeat N", "N iterations", or "N passes":
|
|
64
|
+
|
|
65
|
+
- Does any step use `forEach` with a sequential numeric array like `["1","2","3","4","5"]`?
|
|
66
|
+
- This is always wrong — `repeat: N` must be used instead of a numeric forEach array
|
|
67
|
+
- Reject and require the offending step be converted to `repeat: N`
|
|
68
|
+
|
|
62
69
|
## Output Format
|
|
63
70
|
|
|
64
71
|
Respond with ONLY a JSON object in this exact shape:
|