@mobrienv/autoloop-harness 0.8.0 → 0.9.2
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/acceptance.d.ts +31 -0
- package/dist/acceptance.js +69 -0
- package/dist/acceptance.js.map +1 -0
- package/dist/ask.d.ts +16 -0
- package/dist/ask.js +47 -0
- package/dist/ask.js.map +1 -0
- package/dist/backend/types.d.ts +3 -0
- package/dist/backend/types.js +3 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/circuit-breaker.d.ts +27 -0
- package/dist/circuit-breaker.js +41 -0
- package/dist/circuit-breaker.js.map +1 -0
- package/dist/completion-lint.d.ts +29 -0
- package/dist/completion-lint.js +51 -0
- package/dist/completion-lint.js.map +1 -0
- package/dist/config-helpers.js +141 -8
- package/dist/config-helpers.js.map +1 -1
- package/dist/control/command-adapter.d.ts +19 -0
- package/dist/control/command-adapter.js +57 -0
- package/dist/control/command-adapter.js.map +1 -0
- package/dist/control/dispatch.js +14 -0
- package/dist/control/dispatch.js.map +1 -1
- package/dist/control/types.d.ts +11 -2
- package/dist/display.d.ts +9 -2
- package/dist/display.js +37 -1
- package/dist/display.js.map +1 -1
- package/dist/emit.d.ts +27 -0
- package/dist/emit.js +321 -2
- package/dist/emit.js.map +1 -1
- package/dist/events.d.ts +36 -3
- package/dist/fanout-runner.d.ts +25 -0
- package/dist/fanout-runner.js +54 -0
- package/dist/fanout-runner.js.map +1 -0
- package/dist/file-mod-audit.d.ts +29 -0
- package/dist/file-mod-audit.js +63 -0
- package/dist/file-mod-audit.js.map +1 -0
- package/dist/git-diff.d.ts +19 -0
- package/dist/git-diff.js +74 -0
- package/dist/git-diff.js.map +1 -0
- package/dist/hooks.d.ts +78 -0
- package/dist/hooks.js +239 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.js +181 -5
- package/dist/index.js.map +1 -1
- package/dist/intent.d.ts +45 -0
- package/dist/intent.js +127 -0
- package/dist/intent.js.map +1 -0
- package/dist/iteration-diff.d.ts +32 -0
- package/dist/iteration-diff.js +92 -0
- package/dist/iteration-diff.js.map +1 -0
- package/dist/iteration.d.ts +20 -0
- package/dist/iteration.js +383 -16
- package/dist/iteration.js.map +1 -1
- package/dist/metareview.d.ts +9 -1
- package/dist/metareview.js +68 -30
- package/dist/metareview.js.map +1 -1
- package/dist/notify.d.ts +9 -2
- package/dist/notify.js +16 -4
- package/dist/notify.js.map +1 -1
- package/dist/parallel.d.ts +16 -0
- package/dist/parallel.js +28 -1
- package/dist/parallel.js.map +1 -1
- package/dist/postconditions.d.ts +25 -0
- package/dist/postconditions.js +107 -0
- package/dist/postconditions.js.map +1 -0
- package/dist/postfire-verify.d.ts +31 -0
- package/dist/postfire-verify.js +64 -0
- package/dist/postfire-verify.js.map +1 -0
- package/dist/premature-quit.d.ts +25 -0
- package/dist/premature-quit.js +54 -0
- package/dist/premature-quit.js.map +1 -0
- package/dist/progress.d.ts +20 -0
- package/dist/progress.js +56 -0
- package/dist/progress.js.map +1 -0
- package/dist/prompt.js +8 -2
- package/dist/prompt.js.map +1 -1
- package/dist/provisional.d.ts +42 -0
- package/dist/provisional.js +92 -0
- package/dist/provisional.js.map +1 -0
- package/dist/registry-bridge.js +25 -0
- package/dist/registry-bridge.js.map +1 -1
- package/dist/resume.d.ts +61 -0
- package/dist/resume.js +226 -0
- package/dist/resume.js.map +1 -0
- package/dist/scratchpad.js +27 -8
- package/dist/scratchpad.js.map +1 -1
- package/dist/stage.d.ts +21 -0
- package/dist/stage.js +131 -0
- package/dist/stage.js.map +1 -0
- package/dist/stop.d.ts +29 -2
- package/dist/stop.js +106 -0
- package/dist/stop.js.map +1 -1
- package/dist/suspend-state.d.ts +32 -0
- package/dist/suspend-state.js +104 -0
- package/dist/suspend-state.js.map +1 -0
- package/dist/tamper.d.ts +21 -0
- package/dist/tamper.js +88 -0
- package/dist/tamper.js.map +1 -0
- package/dist/types.d.ts +247 -2
- package/dist/types.js +91 -1
- package/dist/types.js.map +1 -1
- package/dist/wave/finalize-wave.d.ts +15 -5
- package/dist/wave/finalize-wave.js +56 -2
- package/dist/wave/finalize-wave.js.map +1 -1
- package/dist/wave/launch-branches.d.ts +23 -2
- package/dist/wave/launch-branches.js +56 -3
- package/dist/wave/launch-branches.js.map +1 -1
- package/dist/wave/stage-branch-runner.d.ts +12 -0
- package/dist/wave/stage-branch-runner.js +130 -0
- package/dist/wave/stage-branch-runner.js.map +1 -0
- package/dist/wave/types.d.ts +40 -2
- package/dist/wave.d.ts +32 -1
- package/dist/wave.js +163 -34
- package/dist/wave.js.map +1 -1
- package/package.json +83 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fanout-runner.js","sourceRoot":"","sources":["../src/fanout-runner.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,+EAA+E;AAC/E,kFAAkF;AAClF,4EAA4E;AAC5E,sEAAsE;AAEtE,OAAO,EAAE,QAAQ,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,EAGL,WAAW,GAEZ,MAAM,gCAAgC,CAAC;AAaxC;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAkB;IACpD,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YACvC,QAAQ,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,KAAK,EAAE;YAChC,OAAO,EAAE,KAAK,CAAC,EAAE;YACjB,IAAI;YACJ,SAAS,EAAE,IAAI;YACf,KAAK;SACN,CAAC,CAAC,CAAC;IACN,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QAC9C,QAAQ,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,KAAK,EAAE;QAChC,OAAO,EAAE,KAAK,CAAC,EAAE;QACjB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,IAAI;QACrB,KAAK;KACN,CAAC,CAAC,CAAC;AACN,CAAC;AAID;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAkB,EAClB,SAAuB,EACvB,WAAmB;IAEnB,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAChE,IAAI,CAAC;YACH,OAAO,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { IterationContext } from "./prompt.js";
|
|
2
|
+
import type { LoopContext } from "./types.js";
|
|
3
|
+
export type FileModViolationReason = "disallowed_tools" | "read_only";
|
|
4
|
+
export interface FileModViolation {
|
|
5
|
+
role: string;
|
|
6
|
+
files: string[];
|
|
7
|
+
reason: FileModViolationReason;
|
|
8
|
+
}
|
|
9
|
+
export interface FileModAuditResult {
|
|
10
|
+
ran: boolean;
|
|
11
|
+
violated: boolean;
|
|
12
|
+
violations: FileModViolation[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Ralph-parity emit-boundary audit (opt-in via `event_loop.audit_file_mods`).
|
|
16
|
+
* Compares the working tree against HEAD after every iteration; if the
|
|
17
|
+
* single acting role (`iter.allowedRoles[0]`, the same convention used for
|
|
18
|
+
* per-role backend overrides) declares `disallowedTools`/`readOnly` and
|
|
19
|
+
* files changed during the iteration, journals + emits a typed
|
|
20
|
+
* `policy.file_modification_violation` event carrying the role and file
|
|
21
|
+
* list. Purely observational: the harness itself never stops or rejects
|
|
22
|
+
* completion on this result — it exists for parent orchestrators to react to.
|
|
23
|
+
*
|
|
24
|
+
* No-ops (returns `{ ran: false, ... }`) when the policy is disabled, and
|
|
25
|
+
* `{ ran: true, violated: false, ... }` outside a git work tree, when no
|
|
26
|
+
* files changed, when the acting role is ambiguous/unknown, or when the
|
|
27
|
+
* acting role has no file-mutation restriction.
|
|
28
|
+
*/
|
|
29
|
+
export declare function runFileModAudit(loop: LoopContext, iter: IterationContext, iteration: number): FileModAuditResult;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsonField } from "@mobrienv/autoloop-core";
|
|
2
|
+
import { appendEvent } from "@mobrienv/autoloop-core/journal";
|
|
3
|
+
import { changedFiles, isGitRepo } from "./git-diff.js";
|
|
4
|
+
/**
|
|
5
|
+
* Ralph-parity emit-boundary audit (opt-in via `event_loop.audit_file_mods`).
|
|
6
|
+
* Compares the working tree against HEAD after every iteration; if the
|
|
7
|
+
* single acting role (`iter.allowedRoles[0]`, the same convention used for
|
|
8
|
+
* per-role backend overrides) declares `disallowedTools`/`readOnly` and
|
|
9
|
+
* files changed during the iteration, journals + emits a typed
|
|
10
|
+
* `policy.file_modification_violation` event carrying the role and file
|
|
11
|
+
* list. Purely observational: the harness itself never stops or rejects
|
|
12
|
+
* completion on this result — it exists for parent orchestrators to react to.
|
|
13
|
+
*
|
|
14
|
+
* No-ops (returns `{ ran: false, ... }`) when the policy is disabled, and
|
|
15
|
+
* `{ ran: true, violated: false, ... }` outside a git work tree, when no
|
|
16
|
+
* files changed, when the acting role is ambiguous/unknown, or when the
|
|
17
|
+
* acting role has no file-mutation restriction.
|
|
18
|
+
*/
|
|
19
|
+
export function runFileModAudit(loop, iter, iteration) {
|
|
20
|
+
if (!loop.policy?.fileModAudit) {
|
|
21
|
+
return { ran: false, violated: false, violations: [] };
|
|
22
|
+
}
|
|
23
|
+
const workDir = loop.paths.workDir;
|
|
24
|
+
if (!isGitRepo(workDir)) {
|
|
25
|
+
return { ran: true, violated: false, violations: [] };
|
|
26
|
+
}
|
|
27
|
+
const files = changedFiles(workDir);
|
|
28
|
+
if (files.length === 0) {
|
|
29
|
+
return { ran: true, violated: false, violations: [] };
|
|
30
|
+
}
|
|
31
|
+
// Autoloop runs a single backend per iteration; allowedRoles[0] is the
|
|
32
|
+
// acting role for this turn (same convention prompt.ts uses to resolve
|
|
33
|
+
// per-role backend overrides). Ambiguous/empty routing is skipped rather
|
|
34
|
+
// than guessed, to avoid false-positive violations.
|
|
35
|
+
if (iter.allowedRoles.length !== 1) {
|
|
36
|
+
return { ran: true, violated: false, violations: [] };
|
|
37
|
+
}
|
|
38
|
+
const roleId = iter.allowedRoles[0];
|
|
39
|
+
const role = loop.topology.roles.find((r) => r.id === roleId);
|
|
40
|
+
if (!role) {
|
|
41
|
+
return { ran: true, violated: false, violations: [] };
|
|
42
|
+
}
|
|
43
|
+
const reason = role.readOnly
|
|
44
|
+
? "read_only"
|
|
45
|
+
: (role.disallowedTools?.length ?? 0) > 0
|
|
46
|
+
? "disallowed_tools"
|
|
47
|
+
: null;
|
|
48
|
+
if (!reason) {
|
|
49
|
+
return { ran: true, violated: false, violations: [] };
|
|
50
|
+
}
|
|
51
|
+
const violation = { role: roleId, files, reason };
|
|
52
|
+
appendEvent(loop.paths.journalFile, loop.runtime.runId, String(iteration), "policy.file_modification_violation", `${jsonField("role", roleId)}, ${jsonField("files", files.join(","))}, ${jsonField("reason", reason)}`);
|
|
53
|
+
loop.onEvent?.({
|
|
54
|
+
type: "policy.file_modification_violation",
|
|
55
|
+
runId: loop.runtime.runId,
|
|
56
|
+
iteration,
|
|
57
|
+
role: roleId,
|
|
58
|
+
files,
|
|
59
|
+
reason,
|
|
60
|
+
});
|
|
61
|
+
return { ran: true, violated: true, violations: [violation] };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=file-mod-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-mod-audit.js","sourceRoot":"","sources":["../src/file-mod-audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface AddedLine {
|
|
2
|
+
file: string;
|
|
3
|
+
text: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function isGitRepo(workDir: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Lines introduced this run: added (`+`) lines from `git diff HEAD` plus the
|
|
8
|
+
* full contents of untracked, non-ignored files (which a diff against HEAD does
|
|
9
|
+
* not include). This is the surface a reward-hack would land on.
|
|
10
|
+
*/
|
|
11
|
+
export declare function collectAddedLines(workDir: string): AddedLine[];
|
|
12
|
+
/**
|
|
13
|
+
* Files changed this run: tracked files differing from HEAD plus untracked,
|
|
14
|
+
* non-ignored files. Used to detect whether a given class of file (e.g. tests)
|
|
15
|
+
* was touched during the run that claims completion.
|
|
16
|
+
*/
|
|
17
|
+
export declare function changedFiles(workDir: string): string[];
|
|
18
|
+
/** Dirty working tree entries from `git status --porcelain`. */
|
|
19
|
+
export declare function porcelainStatus(workDir: string): string[];
|
package/dist/git-diff.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
function git(workDir, args) {
|
|
3
|
+
const res = spawnSync("git", args, {
|
|
4
|
+
cwd: workDir,
|
|
5
|
+
encoding: "utf-8",
|
|
6
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
7
|
+
});
|
|
8
|
+
return { ok: res.status === 0, stdout: res.stdout ?? "" };
|
|
9
|
+
}
|
|
10
|
+
export function isGitRepo(workDir) {
|
|
11
|
+
return git(workDir, ["rev-parse", "--is-inside-work-tree"]).ok;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Lines introduced this run: added (`+`) lines from `git diff HEAD` plus the
|
|
15
|
+
* full contents of untracked, non-ignored files (which a diff against HEAD does
|
|
16
|
+
* not include). This is the surface a reward-hack would land on.
|
|
17
|
+
*/
|
|
18
|
+
export function collectAddedLines(workDir) {
|
|
19
|
+
const lines = [];
|
|
20
|
+
const diff = git(workDir, ["diff", "--unified=0", "--no-color", "HEAD"]);
|
|
21
|
+
if (diff.ok) {
|
|
22
|
+
let file = "";
|
|
23
|
+
for (const raw of diff.stdout.split("\n")) {
|
|
24
|
+
if (raw.startsWith("+++ b/")) {
|
|
25
|
+
file = raw.slice(6);
|
|
26
|
+
}
|
|
27
|
+
else if (raw.startsWith("+++ ")) {
|
|
28
|
+
file = raw.slice(4);
|
|
29
|
+
}
|
|
30
|
+
else if (raw.startsWith("+") && !raw.startsWith("+++")) {
|
|
31
|
+
lines.push({ file, text: raw.slice(1) });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
for (const file of untrackedFiles(workDir)) {
|
|
36
|
+
const content = spawnSync("cat", [file], {
|
|
37
|
+
cwd: workDir,
|
|
38
|
+
encoding: "utf-8",
|
|
39
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
40
|
+
});
|
|
41
|
+
if (content.status === 0) {
|
|
42
|
+
for (const text of (content.stdout ?? "").split("\n")) {
|
|
43
|
+
lines.push({ file, text });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return lines;
|
|
48
|
+
}
|
|
49
|
+
function untrackedFiles(workDir) {
|
|
50
|
+
const res = git(workDir, ["ls-files", "--others", "--exclude-standard"]);
|
|
51
|
+
return res.ok ? res.stdout.split("\n").filter(Boolean) : [];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Files changed this run: tracked files differing from HEAD plus untracked,
|
|
55
|
+
* non-ignored files. Used to detect whether a given class of file (e.g. tests)
|
|
56
|
+
* was touched during the run that claims completion.
|
|
57
|
+
*/
|
|
58
|
+
export function changedFiles(workDir) {
|
|
59
|
+
const tracked = git(workDir, ["diff", "--name-only", "--no-color", "HEAD"]);
|
|
60
|
+
const files = new Set();
|
|
61
|
+
if (tracked.ok) {
|
|
62
|
+
for (const f of tracked.stdout.split("\n").filter(Boolean))
|
|
63
|
+
files.add(f);
|
|
64
|
+
}
|
|
65
|
+
for (const f of untrackedFiles(workDir))
|
|
66
|
+
files.add(f);
|
|
67
|
+
return [...files];
|
|
68
|
+
}
|
|
69
|
+
/** Dirty working tree entries from `git status --porcelain`. */
|
|
70
|
+
export function porcelainStatus(workDir) {
|
|
71
|
+
const res = git(workDir, ["status", "--porcelain"]);
|
|
72
|
+
return res.ok ? res.stdout.split("\n").filter(Boolean) : [];
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=git-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-diff.js","sourceRoot":"","sources":["../src/git-diff.ts"],"names":[],"mappings":"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"}
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { HookPhase } from "@mobrienv/autoloop-core/hooks-schema";
|
|
2
|
+
import type { LoopContext, StopReason } from "./types.js";
|
|
3
|
+
export interface HookEnv {
|
|
4
|
+
AUTOLOOP_PROJECT_DIR: string;
|
|
5
|
+
AUTOLOOP_RUN_ID: string;
|
|
6
|
+
AUTOLOOP_PRESET: string;
|
|
7
|
+
AUTOLOOP_TASKS_FILE: string;
|
|
8
|
+
AUTOLOOP_ITERATION?: string;
|
|
9
|
+
AUTOLOOP_GIT_SHA_BEFORE?: string;
|
|
10
|
+
AUTOLOOP_GIT_SHA_AFTER?: string;
|
|
11
|
+
/** Run stop reason, set on post_run (e.g. "completed" = success). */
|
|
12
|
+
AUTOLOOP_STOP_REASON?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function buildHookEnv(loop: LoopContext, extra?: {
|
|
15
|
+
iteration?: number;
|
|
16
|
+
gitShaBefore?: string;
|
|
17
|
+
gitShaAfter?: string;
|
|
18
|
+
stopReason?: StopReason;
|
|
19
|
+
}): HookEnv;
|
|
20
|
+
export declare function captureGitSha(cwd: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Legacy single-hook entry point (`runHook`). Kept for backward compatibility
|
|
23
|
+
* with any external callers/tests; internally the engine runs hooks through
|
|
24
|
+
* `runPhaseHooks` which layers policy + mutation on top of this same spawn +
|
|
25
|
+
* journal behavior.
|
|
26
|
+
*/
|
|
27
|
+
export declare function runHook(loop: LoopContext, name: string, cmd: string, hookEnv: HookEnv, iteration?: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Parse a mutation directive from hook stdout, given which kind of mutation
|
|
30
|
+
* this hook is configured for:
|
|
31
|
+
*
|
|
32
|
+
* - `mutate="prompt"`: a fenced block (`<<<AUTOLOOP_MUTATE>>> ... <<<END>>>`)
|
|
33
|
+
* or a `{"prompt": "..."}` JSON line take precedence; otherwise the *entire*
|
|
34
|
+
* trimmed stdout becomes the new prompt (so a hook can be as simple as
|
|
35
|
+
* `echo "new prompt text"`).
|
|
36
|
+
* - `mutate="event"`: requires a JSON object with `topic` and/or `payload`
|
|
37
|
+
* (there is no plain-text form — an emitted event is structured, not free
|
|
38
|
+
* text).
|
|
39
|
+
*
|
|
40
|
+
* Empty/malformed stdout is not an error — it simply yields no mutation
|
|
41
|
+
* (returns null), since a hook may run for its side effects alone.
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseMutationDirective(stdout: string, mutate: "prompt" | "event"): {
|
|
44
|
+
prompt?: string;
|
|
45
|
+
topic?: string;
|
|
46
|
+
payload?: string;
|
|
47
|
+
} | null;
|
|
48
|
+
export interface PhaseHookResult {
|
|
49
|
+
/** Mutated prompt, when a `mutate="prompt"` hook produced one (pre_iteration). */
|
|
50
|
+
mutatedPrompt?: string;
|
|
51
|
+
/** Mutated event, when a `mutate="event"` hook produced one (pre_emit). */
|
|
52
|
+
mutatedEvent?: {
|
|
53
|
+
topic?: string;
|
|
54
|
+
payload?: string;
|
|
55
|
+
};
|
|
56
|
+
/** True when a `block` hook failed — caller must abort/fail. */
|
|
57
|
+
blocked: boolean;
|
|
58
|
+
/** Detail message for the first blocking failure, if any. */
|
|
59
|
+
blockedMessage?: string;
|
|
60
|
+
/** True when a `suspend` hook fired and the run should stop (out-of-process
|
|
61
|
+
* phases can't block; the caller is responsible for tearing down). */
|
|
62
|
+
suspended: boolean;
|
|
63
|
+
}
|
|
64
|
+
export interface RunPhaseHooksOptions {
|
|
65
|
+
iteration?: number;
|
|
66
|
+
gitShaBefore?: string;
|
|
67
|
+
gitShaAfter?: string;
|
|
68
|
+
stopReason?: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Run every hook configured for `phase`, in declaration order, applying each
|
|
72
|
+
* hook's error policy and (if configured) parsing a mutation directive from
|
|
73
|
+
* its stdout. Later hooks in the same phase see the not-yet-applied original
|
|
74
|
+
* inputs — mutation from multiple hooks in one phase is last-write-wins
|
|
75
|
+
* (whichever hook mutates last), which keeps the model simple and matches
|
|
76
|
+
* the common case of a single hook per phase.
|
|
77
|
+
*/
|
|
78
|
+
export declare function runPhaseHooks(loop: LoopContext, phase: HookPhase, hookEnv: HookEnv, opts?: RunPhaseHooksOptions): Promise<PhaseHookResult>;
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { appendEvent } from "@mobrienv/autoloop-core/journal";
|
|
3
|
+
import { log, printHookOutput } from "./display.js";
|
|
4
|
+
import { writeSuspendState } from "./suspend-state.js";
|
|
5
|
+
export function buildHookEnv(loop, extra) {
|
|
6
|
+
const env = {
|
|
7
|
+
// The work dir is the repo being worked (where .autoloop/issue-sync.toml lives);
|
|
8
|
+
// projectDir can be the preset directory, which is not what hooks want.
|
|
9
|
+
AUTOLOOP_PROJECT_DIR: loop.paths.workDir,
|
|
10
|
+
AUTOLOOP_RUN_ID: loop.runtime.runId,
|
|
11
|
+
AUTOLOOP_PRESET: loop.launch.preset,
|
|
12
|
+
AUTOLOOP_TASKS_FILE: loop.paths.tasksFile,
|
|
13
|
+
};
|
|
14
|
+
if (extra?.iteration !== undefined) {
|
|
15
|
+
env.AUTOLOOP_ITERATION = String(extra.iteration);
|
|
16
|
+
}
|
|
17
|
+
if (extra?.gitShaBefore !== undefined) {
|
|
18
|
+
env.AUTOLOOP_GIT_SHA_BEFORE = extra.gitShaBefore;
|
|
19
|
+
}
|
|
20
|
+
if (extra?.gitShaAfter !== undefined) {
|
|
21
|
+
env.AUTOLOOP_GIT_SHA_AFTER = extra.gitShaAfter;
|
|
22
|
+
}
|
|
23
|
+
if (extra?.stopReason !== undefined) {
|
|
24
|
+
env.AUTOLOOP_STOP_REASON = extra.stopReason;
|
|
25
|
+
}
|
|
26
|
+
return env;
|
|
27
|
+
}
|
|
28
|
+
export function captureGitSha(cwd) {
|
|
29
|
+
try {
|
|
30
|
+
const result = spawnSync("git", ["rev-parse", "HEAD"], {
|
|
31
|
+
cwd,
|
|
32
|
+
encoding: "utf-8",
|
|
33
|
+
});
|
|
34
|
+
if (result.status === 0 && result.stdout) {
|
|
35
|
+
return result.stdout.trim();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
/* not a git repo or git not available — return empty */
|
|
40
|
+
}
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
function spawnHook(loop, name, cmd, hookEnv) {
|
|
44
|
+
const env = { ...process.env };
|
|
45
|
+
for (const [k, v] of Object.entries(hookEnv)) {
|
|
46
|
+
if (v !== undefined)
|
|
47
|
+
env[k] = v;
|
|
48
|
+
}
|
|
49
|
+
const result = spawnSync(cmd, {
|
|
50
|
+
shell: true,
|
|
51
|
+
cwd: loop.paths.workDir,
|
|
52
|
+
encoding: "utf-8",
|
|
53
|
+
env,
|
|
54
|
+
});
|
|
55
|
+
const combined = (result.stdout ?? "") +
|
|
56
|
+
(result.stderr ? `\n[stderr]\n${result.stderr}` : "");
|
|
57
|
+
const failed = result.status !== 0 || Boolean(result.error);
|
|
58
|
+
if (failed && result.error) {
|
|
59
|
+
log(loop, "debug", `hook ${name} spawn error: ${result.error.message}`);
|
|
60
|
+
}
|
|
61
|
+
return { status: result.status ?? -1, combined, failed };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Legacy single-hook entry point (`runHook`). Kept for backward compatibility
|
|
65
|
+
* with any external callers/tests; internally the engine runs hooks through
|
|
66
|
+
* `runPhaseHooks` which layers policy + mutation on top of this same spawn +
|
|
67
|
+
* journal behavior.
|
|
68
|
+
*/
|
|
69
|
+
export function runHook(loop, name, cmd, hookEnv, iteration) {
|
|
70
|
+
if (!cmd)
|
|
71
|
+
return;
|
|
72
|
+
log(loop, "debug", `hook ${name} start cmd=${JSON.stringify(cmd)}`);
|
|
73
|
+
const { status, combined, failed } = spawnHook(loop, name, cmd, hookEnv);
|
|
74
|
+
appendEvent(loop.paths.journalFile, loop.runtime.runId, iteration ?? "", "hook.output", `"hook": ${JSON.stringify(name)}, "exit_code": ${status}, "output": ${JSON.stringify(combined.trim())}`);
|
|
75
|
+
printHookOutput(name, status, combined.trim(), failed);
|
|
76
|
+
if (failed) {
|
|
77
|
+
const msg = firstFailureLine(name, status, combined);
|
|
78
|
+
log(loop, "warn", msg);
|
|
79
|
+
if (loop.hooks.strict && name === "pre_run") {
|
|
80
|
+
throw new Error(`Aborting run: ${msg}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
log(loop, "debug", `hook ${name} ok`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function firstFailureLine(name, status, combined) {
|
|
88
|
+
const stderrIdx = combined.indexOf("\n[stderr]\n");
|
|
89
|
+
const detail = (stderrIdx >= 0 ? combined.slice(stderrIdx + 10) : "").trim() ||
|
|
90
|
+
(stderrIdx >= 0 ? combined.slice(0, stderrIdx) : combined).trim();
|
|
91
|
+
const firstLine = detail
|
|
92
|
+
.split("\n")
|
|
93
|
+
.map((l) => l.trim())
|
|
94
|
+
.find((l) => l.length > 0) ?? "";
|
|
95
|
+
return `hook ${name} failed (exit ${status}): ${firstLine}`;
|
|
96
|
+
}
|
|
97
|
+
// --- Mutation directive parsing --------------------------------------------
|
|
98
|
+
const MUTATE_FENCE_RE = /<<<AUTOLOOP_MUTATE>>>\n?([\s\S]*?)\n?<<<END>>>/;
|
|
99
|
+
/**
|
|
100
|
+
* Parse a mutation directive from hook stdout, given which kind of mutation
|
|
101
|
+
* this hook is configured for:
|
|
102
|
+
*
|
|
103
|
+
* - `mutate="prompt"`: a fenced block (`<<<AUTOLOOP_MUTATE>>> ... <<<END>>>`)
|
|
104
|
+
* or a `{"prompt": "..."}` JSON line take precedence; otherwise the *entire*
|
|
105
|
+
* trimmed stdout becomes the new prompt (so a hook can be as simple as
|
|
106
|
+
* `echo "new prompt text"`).
|
|
107
|
+
* - `mutate="event"`: requires a JSON object with `topic` and/or `payload`
|
|
108
|
+
* (there is no plain-text form — an emitted event is structured, not free
|
|
109
|
+
* text).
|
|
110
|
+
*
|
|
111
|
+
* Empty/malformed stdout is not an error — it simply yields no mutation
|
|
112
|
+
* (returns null), since a hook may run for its side effects alone.
|
|
113
|
+
*/
|
|
114
|
+
export function parseMutationDirective(stdout, mutate) {
|
|
115
|
+
if (!stdout?.trim())
|
|
116
|
+
return null;
|
|
117
|
+
const trimmed = stdout.trim();
|
|
118
|
+
const fenced = MUTATE_FENCE_RE.exec(stdout);
|
|
119
|
+
if (fenced && mutate === "prompt") {
|
|
120
|
+
return { prompt: fenced[1] };
|
|
121
|
+
}
|
|
122
|
+
if (trimmed.startsWith("{")) {
|
|
123
|
+
try {
|
|
124
|
+
const obj = JSON.parse(trimmed);
|
|
125
|
+
const out = {};
|
|
126
|
+
if (typeof obj.prompt === "string")
|
|
127
|
+
out.prompt = obj.prompt;
|
|
128
|
+
if (typeof obj.topic === "string")
|
|
129
|
+
out.topic = obj.topic;
|
|
130
|
+
if (typeof obj.payload === "string")
|
|
131
|
+
out.payload = obj.payload;
|
|
132
|
+
if (Object.keys(out).length > 0)
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
/* not JSON — fall through to the plain-text prompt case below */
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (mutate === "prompt")
|
|
140
|
+
return { prompt: trimmed };
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Run every hook configured for `phase`, in declaration order, applying each
|
|
145
|
+
* hook's error policy and (if configured) parsing a mutation directive from
|
|
146
|
+
* its stdout. Later hooks in the same phase see the not-yet-applied original
|
|
147
|
+
* inputs — mutation from multiple hooks in one phase is last-write-wins
|
|
148
|
+
* (whichever hook mutates last), which keeps the model simple and matches
|
|
149
|
+
* the common case of a single hook per phase.
|
|
150
|
+
*/
|
|
151
|
+
export async function runPhaseHooks(loop, phase, hookEnv, opts = {}) {
|
|
152
|
+
// Defensive default: hand-built test LoopContexts (and any older caller
|
|
153
|
+
// that predates `hooks.specs`) may omit it entirely.
|
|
154
|
+
const specs = (loop.hooks.specs ?? []).filter((s) => s.phase === phase);
|
|
155
|
+
const result = { blocked: false, suspended: false };
|
|
156
|
+
const iterationStr = opts.iteration !== undefined ? String(opts.iteration) : "";
|
|
157
|
+
for (const spec of specs) {
|
|
158
|
+
if (!spec.command)
|
|
159
|
+
continue;
|
|
160
|
+
log(loop, "debug", `hook ${phase} start cmd=${JSON.stringify(spec.command)} on_error=${spec.onError} mutate=${spec.mutate}`);
|
|
161
|
+
const { status, combined, failed } = spawnHook(loop, phase, spec.command, hookEnv);
|
|
162
|
+
appendEvent(loop.paths.journalFile, loop.runtime.runId, iterationStr, "hook.output", `"hook": ${JSON.stringify(phase)}, "exit_code": ${status}, "output": ${JSON.stringify(combined.trim())}`);
|
|
163
|
+
printHookOutput(phase, status, combined.trim(), failed);
|
|
164
|
+
if (!failed && spec.mutate !== "none") {
|
|
165
|
+
const stdoutOnly = combined.split("\n[stderr]\n")[0];
|
|
166
|
+
const directive = parseMutationDirective(stdoutOnly, spec.mutate);
|
|
167
|
+
if (directive) {
|
|
168
|
+
if (spec.mutate === "prompt" && directive.prompt !== undefined) {
|
|
169
|
+
result.mutatedPrompt = directive.prompt;
|
|
170
|
+
}
|
|
171
|
+
else if (spec.mutate === "event") {
|
|
172
|
+
result.mutatedEvent = {
|
|
173
|
+
topic: directive.topic,
|
|
174
|
+
payload: directive.payload,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (!failed) {
|
|
180
|
+
log(loop, "debug", `hook ${phase} ok`);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const msg = firstFailureLine(phase, status, combined);
|
|
184
|
+
switch (spec.onError) {
|
|
185
|
+
case "warn":
|
|
186
|
+
log(loop, "warn", msg);
|
|
187
|
+
break;
|
|
188
|
+
case "block":
|
|
189
|
+
log(loop, "error", `hook ${phase} blocked run: ${msg}`);
|
|
190
|
+
result.blocked = true;
|
|
191
|
+
result.blockedMessage = msg;
|
|
192
|
+
return result;
|
|
193
|
+
case "suspend": {
|
|
194
|
+
// Durable suspend: write versioned state and stop this call site
|
|
195
|
+
// immediately. The run process ends (see stopSuspended in the
|
|
196
|
+
// call sites); a later `autoloop resume` (a fresh process) reads
|
|
197
|
+
// suspend-state.json and continues from `resumeIteration`. This
|
|
198
|
+
// deliberately does NOT block in-process — emit's pre_emit/post_emit
|
|
199
|
+
// hooks run in a disposable subprocess and could never block the
|
|
200
|
+
// harness loop anyway, so in-process phases use the same simple,
|
|
201
|
+
// uniform "stop and let resume pick it back up" contract.
|
|
202
|
+
log(loop, "warn", `hook ${phase} suspended run: ${msg}`);
|
|
203
|
+
const resumeIteration = suspendResumeIteration(phase, opts.iteration);
|
|
204
|
+
writeSuspendState(loop.paths.stateDir, {
|
|
205
|
+
runId: loop.runtime.runId,
|
|
206
|
+
phase,
|
|
207
|
+
iteration: opts.iteration ?? 0,
|
|
208
|
+
reason: msg,
|
|
209
|
+
hookCommand: spec.command,
|
|
210
|
+
createdAt: new Date().toISOString(),
|
|
211
|
+
resumeIteration,
|
|
212
|
+
}, loop.paths.journalFile);
|
|
213
|
+
result.suspended = true;
|
|
214
|
+
result.blockedMessage = msg;
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return result;
|
|
220
|
+
}
|
|
221
|
+
function suspendResumeIteration(phase, iteration) {
|
|
222
|
+
const iter = iteration ?? 0;
|
|
223
|
+
switch (phase) {
|
|
224
|
+
case "pre_run":
|
|
225
|
+
return 1;
|
|
226
|
+
case "pre_iteration":
|
|
227
|
+
return iter;
|
|
228
|
+
case "post_iteration":
|
|
229
|
+
case "post_emit":
|
|
230
|
+
return iter + 1;
|
|
231
|
+
case "pre_emit":
|
|
232
|
+
return iter;
|
|
233
|
+
case "post_run":
|
|
234
|
+
return iter + 1;
|
|
235
|
+
default:
|
|
236
|
+
return iter;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
+
import type { LiveControlAdapter } from "./control/adapter.js";
|
|
1
2
|
import { emit as emitCmd } from "./emit.js";
|
|
2
|
-
import type { LoopContext, RunOptions, RunSummary } from "./types.js";
|
|
3
|
-
export
|
|
3
|
+
import type { LoopContext, RunOptions, RunSummary, StopReason } from "./types.js";
|
|
4
|
+
export { STOP_REASONS } from "./types.js";
|
|
5
|
+
export type { LoopContext, RunOptions, RunSummary, StopReason };
|
|
4
6
|
export declare function run(projectDir: string, promptOverride: string | null, selfCommand: string, runOptions: RunOptions): Promise<RunSummary>;
|
|
7
|
+
/**
|
|
8
|
+
* Drive the iteration loop for an already-built, already-registered
|
|
9
|
+
* LoopContext, starting at `startIteration`. Owns abort/teardown wiring,
|
|
10
|
+
* the tracked-iterate recursion, session cleanup, post-run worktree
|
|
11
|
+
* lifecycle, and finish notifications. Shared by `run()` and `resume()` so
|
|
12
|
+
* both paths exercise identical signal handlers, stop handlers, and
|
|
13
|
+
* registry/journal behavior.
|
|
14
|
+
*/
|
|
15
|
+
export declare function driveLoop(loop: LoopContext, runOptions: RunOptions, startIteration: number): Promise<RunSummary>;
|
|
16
|
+
export { buildResumeContext, determineResumeIteration, type ResumeOptions, type ResumeResult, resume, } from "./resume.js";
|
|
5
17
|
export { emitCmd as emit };
|
|
6
18
|
export declare function runParallelBranchCli(projectDir: string, branchDir: string, selfCommand: string, onEvent?: (event: import("./events.js").LoopEvent) => void): Promise<void>;
|
|
19
|
+
export declare function buildControlAdapter(loop: LoopContext): LiveControlAdapter | undefined;
|