@graypark/loophaus 3.4.0 → 3.5.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/README.ko.md +81 -17
- package/README.md +69 -15
- package/dist/.claude-plugin/plugin.json +11 -0
- package/dist/LICENSE +21 -0
- package/dist/README.ko.md +422 -0
- package/dist/README.md +336 -0
- package/dist/bin/install.d.ts +3 -0
- package/dist/bin/install.d.ts.map +1 -0
- package/{bin/install.mjs → dist/bin/install.js} +3 -5
- package/dist/bin/install.js.map +1 -0
- package/dist/bin/loophaus.d.ts +3 -0
- package/dist/bin/loophaus.d.ts.map +1 -0
- package/dist/bin/loophaus.js +654 -0
- package/dist/bin/loophaus.js.map +1 -0
- package/dist/bin/uninstall.d.ts +8 -0
- package/dist/bin/uninstall.d.ts.map +1 -0
- package/dist/bin/uninstall.js +209 -0
- package/dist/bin/uninstall.js.map +1 -0
- package/dist/codex/commands/cancel-ralph.md +30 -0
- package/dist/codex/commands/ralph-loop.md +73 -0
- package/dist/commands/cancel-ralph.md +23 -0
- package/dist/commands/help.md +96 -0
- package/dist/commands/loop-plan.md +257 -0
- package/dist/commands/loop-pulse.md +38 -0
- package/dist/commands/loop-stop.md +29 -0
- package/dist/commands/loop.md +17 -0
- package/dist/commands/ralph-loop.md +18 -0
- package/dist/core/cost-tracker.d.ts +33 -0
- package/dist/core/cost-tracker.d.ts.map +1 -0
- package/dist/core/cost-tracker.js +41 -0
- package/dist/core/cost-tracker.js.map +1 -0
- package/dist/core/engine.d.ts +4 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +109 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/event-logger.d.ts +5 -0
- package/dist/core/event-logger.d.ts.map +1 -0
- package/dist/core/event-logger.js +48 -0
- package/dist/core/event-logger.js.map +1 -0
- package/dist/core/events.d.ts +34 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +44 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/io-helpers.d.ts +3 -0
- package/dist/core/io-helpers.d.ts.map +1 -0
- package/dist/core/io-helpers.js +65 -0
- package/dist/core/io-helpers.js.map +1 -0
- package/dist/core/loop-registry.d.ts +10 -0
- package/dist/core/loop-registry.d.ts.map +1 -0
- package/dist/core/loop-registry.js +37 -0
- package/dist/core/loop-registry.js.map +1 -0
- package/dist/core/merge-strategy.d.ts +7 -0
- package/dist/core/merge-strategy.d.ts.map +1 -0
- package/dist/core/merge-strategy.js +82 -0
- package/dist/core/merge-strategy.js.map +1 -0
- package/dist/core/parallel-runner.d.ts +32 -0
- package/dist/core/parallel-runner.d.ts.map +1 -0
- package/dist/core/parallel-runner.js +88 -0
- package/dist/core/parallel-runner.js.map +1 -0
- package/dist/core/policy.d.ts +22 -0
- package/dist/core/policy.d.ts.map +1 -0
- package/dist/core/policy.js +54 -0
- package/dist/core/policy.js.map +1 -0
- package/dist/core/quality-scorer.d.ts +40 -0
- package/dist/core/quality-scorer.d.ts.map +1 -0
- package/dist/core/quality-scorer.js +128 -0
- package/dist/core/quality-scorer.js.map +1 -0
- package/dist/core/refine-loop.d.ts +16 -0
- package/dist/core/refine-loop.d.ts.map +1 -0
- package/dist/core/refine-loop.js +26 -0
- package/dist/core/refine-loop.js.map +1 -0
- package/dist/core/session.d.ts +27 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +67 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/trace-analyzer.d.ts +28 -0
- package/dist/core/trace-analyzer.d.ts.map +1 -0
- package/dist/core/trace-analyzer.js +46 -0
- package/dist/core/trace-analyzer.js.map +1 -0
- package/dist/core/types.d.ts +99 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/validate.d.ts +7 -0
- package/dist/core/validate.d.ts.map +1 -0
- package/dist/core/validate.js +55 -0
- package/dist/core/validate.js.map +1 -0
- package/dist/core/worktree.d.ts +13 -0
- package/dist/core/worktree.d.ts.map +1 -0
- package/dist/core/worktree.js +108 -0
- package/dist/core/worktree.js.map +1 -0
- package/dist/hooks/hooks.json +15 -0
- package/dist/hooks/stop-hook.mjs +111 -0
- package/dist/lib/paths.d.ts +18 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +74 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/lib/stop-hook-core.d.ts +19 -0
- package/dist/lib/stop-hook-core.d.ts.map +1 -0
- package/dist/lib/stop-hook-core.js +36 -0
- package/dist/lib/stop-hook-core.js.map +1 -0
- package/dist/package.json +61 -0
- package/dist/platforms/claude-code/adapter.mjs +20 -0
- package/dist/platforms/claude-code/installer.d.mts +3 -0
- package/dist/platforms/claude-code/installer.mjs +173 -0
- package/dist/platforms/codex-cli/adapter.mjs +20 -0
- package/dist/platforms/codex-cli/installer.d.mts +2 -0
- package/dist/platforms/codex-cli/installer.mjs +247 -0
- package/dist/platforms/kiro-cli/adapter.mjs +21 -0
- package/dist/platforms/kiro-cli/installer.d.mts +3 -0
- package/dist/platforms/kiro-cli/installer.mjs +257 -0
- package/dist/scripts/setup-ralph-loop.sh +145 -0
- package/dist/skills/ralph-claude-cancel/SKILL.md +23 -0
- package/dist/skills/ralph-claude-interview/SKILL.md +184 -0
- package/dist/skills/ralph-claude-loop/SKILL.md +101 -0
- package/dist/skills/ralph-claude-orchestrator/SKILL.md +129 -0
- package/dist/skills/ralph-interview/SKILL.md +275 -0
- package/dist/skills/ralph-orchestrator/SKILL.md +254 -0
- package/dist/store/state-store.d.ts +17 -0
- package/dist/store/state-store.d.ts.map +1 -0
- package/dist/store/state-store.js +108 -0
- package/dist/store/state-store.js.map +1 -0
- package/hooks/stop-hook.mjs +6 -6
- package/package.json +11 -7
- package/platforms/claude-code/installer.d.mts +3 -0
- package/platforms/claude-code/installer.mjs +2 -2
- package/platforms/codex-cli/installer.d.mts +2 -0
- package/platforms/codex-cli/installer.mjs +1 -1
- package/platforms/kiro-cli/installer.d.mts +3 -0
- package/bin/loophaus.mjs +0 -521
- package/bin/uninstall.mjs +0 -255
- package/core/cost-tracker.mjs +0 -44
- package/core/engine.mjs +0 -123
- package/core/event-logger.mjs +0 -37
- package/core/events.mjs +0 -48
- package/core/io-helpers.mjs +0 -33
- package/core/loop-registry.mjs +0 -37
- package/core/loop.schema.json +0 -29
- package/core/merge-strategy.mjs +0 -72
- package/core/parallel-runner.mjs +0 -94
- package/core/policy.mjs +0 -58
- package/core/quality-scorer.mjs +0 -136
- package/core/refine-loop.mjs +0 -29
- package/core/session.mjs +0 -66
- package/core/state.schema.json +0 -24
- package/core/trace-analyzer.mjs +0 -51
- package/core/validate.mjs +0 -54
- package/core/worktree.mjs +0 -97
- package/lib/paths.mjs +0 -99
- package/lib/stop-hook-core.mjs +0 -42
- package/store/state-store.mjs +0 -106
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { LoopEvent } from "./types.js";
|
|
2
|
+
export declare const EventType: {
|
|
3
|
+
readonly ITERATION: "iteration";
|
|
4
|
+
readonly STOP: "stop";
|
|
5
|
+
readonly CONTINUE: "continue";
|
|
6
|
+
readonly DECISION: "decision";
|
|
7
|
+
readonly STORY_COMPLETE: "story_complete";
|
|
8
|
+
readonly TEST_RESULT: "test_result";
|
|
9
|
+
readonly COST: "cost";
|
|
10
|
+
readonly VERIFY_SCRIPT: "verify_script";
|
|
11
|
+
readonly VERIFY_FAILED: "verify_failed";
|
|
12
|
+
readonly LOOP_START: "loop_start";
|
|
13
|
+
readonly LOOP_END: "loop_end";
|
|
14
|
+
readonly CHECKPOINT: "checkpoint";
|
|
15
|
+
readonly ERROR: "error";
|
|
16
|
+
readonly STATE_CHANGE: "state_change";
|
|
17
|
+
readonly QUALITY_SCORE: "quality_score";
|
|
18
|
+
readonly REFINE_ATTEMPT: "refine_attempt";
|
|
19
|
+
readonly REFINE_KEEP: "refine_keep";
|
|
20
|
+
readonly REFINE_DISCARD: "refine_discard";
|
|
21
|
+
};
|
|
22
|
+
export type EventTypeName = typeof EventType[keyof typeof EventType];
|
|
23
|
+
export declare function filterByType(events: LoopEvent[], type: string): LoopEvent[];
|
|
24
|
+
export declare function filterByTimeRange(events: LoopEvent[], start: Date, end: Date): LoopEvent[];
|
|
25
|
+
export declare function filterByLoopId(events: LoopEvent[], loopId: string): LoopEvent[];
|
|
26
|
+
export interface EventSummary {
|
|
27
|
+
counts: Record<string, number>;
|
|
28
|
+
total: number;
|
|
29
|
+
durationMs: number;
|
|
30
|
+
firstTs: string | undefined;
|
|
31
|
+
lastTs: string | undefined;
|
|
32
|
+
}
|
|
33
|
+
export declare function summarizeEvents(events: LoopEvent[]): EventSummary;
|
|
34
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../core/events.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;CAmBZ,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,OAAO,SAAS,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAErE,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAE3E;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,SAAS,EAAE,CAK1F;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,CAE/E;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,YAAY,CASjE"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Event type constants and filter utilities
|
|
2
|
+
export const EventType = {
|
|
3
|
+
ITERATION: "iteration",
|
|
4
|
+
STOP: "stop",
|
|
5
|
+
CONTINUE: "continue",
|
|
6
|
+
DECISION: "decision",
|
|
7
|
+
STORY_COMPLETE: "story_complete",
|
|
8
|
+
TEST_RESULT: "test_result",
|
|
9
|
+
COST: "cost",
|
|
10
|
+
VERIFY_SCRIPT: "verify_script",
|
|
11
|
+
VERIFY_FAILED: "verify_failed",
|
|
12
|
+
LOOP_START: "loop_start",
|
|
13
|
+
LOOP_END: "loop_end",
|
|
14
|
+
CHECKPOINT: "checkpoint",
|
|
15
|
+
ERROR: "error",
|
|
16
|
+
STATE_CHANGE: "state_change",
|
|
17
|
+
QUALITY_SCORE: "quality_score",
|
|
18
|
+
REFINE_ATTEMPT: "refine_attempt",
|
|
19
|
+
REFINE_KEEP: "refine_keep",
|
|
20
|
+
REFINE_DISCARD: "refine_discard",
|
|
21
|
+
};
|
|
22
|
+
export function filterByType(events, type) {
|
|
23
|
+
return events.filter(e => e.event === type);
|
|
24
|
+
}
|
|
25
|
+
export function filterByTimeRange(events, start, end) {
|
|
26
|
+
return events.filter(e => {
|
|
27
|
+
const ts = new Date(e.ts).getTime();
|
|
28
|
+
return ts >= start.getTime() && ts <= end.getTime();
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export function filterByLoopId(events, loopId) {
|
|
32
|
+
return events.filter(e => e.loop_id === loopId);
|
|
33
|
+
}
|
|
34
|
+
export function summarizeEvents(events) {
|
|
35
|
+
const counts = {};
|
|
36
|
+
for (const e of events) {
|
|
37
|
+
counts[e.event] = (counts[e.event] || 0) + 1;
|
|
38
|
+
}
|
|
39
|
+
const first = events[0];
|
|
40
|
+
const last = events[events.length - 1];
|
|
41
|
+
const durationMs = first && last ? new Date(last.ts).getTime() - new Date(first.ts).getTime() : 0;
|
|
42
|
+
return { counts, total: events.length, durationMs, firstTs: first?.ts, lastTs: last?.ts };
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../core/events.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAI5C,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,SAAS,EAAE,WAAW;IACtB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IACpB,cAAc,EAAE,gBAAgB;IAChC,WAAW,EAAE,aAAa;IAC1B,IAAI,EAAE,MAAM;IACZ,aAAa,EAAE,eAAe;IAC9B,aAAa,EAAE,eAAe;IAC9B,UAAU,EAAE,YAAY;IACxB,QAAQ,EAAE,UAAU;IACpB,UAAU,EAAE,YAAY;IACxB,KAAK,EAAE,OAAO;IACd,YAAY,EAAE,cAAc;IAC5B,aAAa,EAAE,eAAe;IAC9B,cAAc,EAAE,gBAAgB;IAChC,WAAW,EAAE,aAAa;IAC1B,cAAc,EAAE,gBAAgB;CACxB,CAAC;AAIX,MAAM,UAAU,YAAY,CAAC,MAAmB,EAAE,IAAY;IAC5D,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAmB,EAAE,KAAW,EAAE,GAAS;IAC3E,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;QACvB,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,EAAY,CAAC,CAAC,OAAO,EAAE,CAAC;QAC9C,OAAO,EAAE,IAAI,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAmB,EAAE,MAAc;IAChE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;AAClD,CAAC;AAUD,MAAM,UAAU,eAAe,CAAC,MAAmB;IACjD,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,EAAY,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,EAAY,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACtH,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,EAAwB,EAAE,MAAM,EAAE,IAAI,EAAE,EAAwB,EAAE,CAAC;AACxI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io-helpers.d.ts","sourceRoot":"","sources":["../../core/io-helpers.ts"],"names":[],"mappings":"AAwBA,wBAAsB,oBAAoB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BnF;AAUD,wBAAsB,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAatE"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const DEBUG = process.env.LOOPHAUS_DEBUG === "1";
|
|
4
|
+
function debug(msg) {
|
|
5
|
+
if (DEBUG)
|
|
6
|
+
process.stderr.write(`[loophaus:debug] ${msg}\n`);
|
|
7
|
+
}
|
|
8
|
+
function isFileNotFound(err) {
|
|
9
|
+
return err != null && typeof err === "object" && ("code" in err) && (err.code === "ENOENT" || err.code === "ENOTDIR");
|
|
10
|
+
}
|
|
11
|
+
export async function getLastAssistantText(transcriptPath) {
|
|
12
|
+
if (!transcriptPath)
|
|
13
|
+
return "";
|
|
14
|
+
try {
|
|
15
|
+
const raw = await readFile(transcriptPath, "utf-8");
|
|
16
|
+
const lines = raw.trim().split("\n");
|
|
17
|
+
const recent = lines.filter((line) => {
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(line).role === "assistant";
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}).slice(-100);
|
|
25
|
+
for (let i = recent.length - 1; i >= 0; i--) {
|
|
26
|
+
try {
|
|
27
|
+
const obj = JSON.parse(recent[i]);
|
|
28
|
+
const contents = obj.message?.content || obj.content;
|
|
29
|
+
if (Array.isArray(contents)) {
|
|
30
|
+
for (let j = contents.length - 1; j >= 0; j--) {
|
|
31
|
+
if (contents[j].type === "text" && contents[j].text)
|
|
32
|
+
return contents[j].text;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else if (typeof contents === "string")
|
|
36
|
+
return contents;
|
|
37
|
+
}
|
|
38
|
+
catch { /* skip malformed line */ }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
if (isFileNotFound(err)) {
|
|
43
|
+
debug(`Transcript not found: ${transcriptPath}`);
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
throw new Error(`Failed to read transcript ${transcriptPath}: ${err.message}`);
|
|
47
|
+
}
|
|
48
|
+
return "";
|
|
49
|
+
}
|
|
50
|
+
export async function hasPendingStories(cwd) {
|
|
51
|
+
const prdPath = join(cwd || process.cwd(), "prd.json");
|
|
52
|
+
try {
|
|
53
|
+
const raw = await readFile(prdPath, "utf-8");
|
|
54
|
+
const prd = JSON.parse(raw);
|
|
55
|
+
return Array.isArray(prd.userStories) && prd.userStories.some((s) => s.passes === false);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
if (isFileNotFound(err)) {
|
|
59
|
+
debug(`prd.json not found at ${prdPath}`);
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`Failed to read prd.json at ${prdPath}: ${err.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=io-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io-helpers.js","sourceRoot":"","sources":["../../core/io-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface LoopEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
active?: boolean;
|
|
4
|
+
error?: string;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
export declare function listLoops(cwd?: string): Promise<LoopEntry[]>;
|
|
8
|
+
export declare function getLoop(name: string, cwd?: string): Promise<LoopEntry | null>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=loop-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-registry.d.ts","sourceRoot":"","sources":["../../core/loop-registry.ts"],"names":[],"mappings":"AAKA,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,wBAAsB,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CA0BlE;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAGnF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// core/loop-registry.ts — Multi-loop registry for named loop instances
|
|
2
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
export async function listLoops(cwd) {
|
|
5
|
+
const loopsDir = join(cwd || process.cwd(), ".loophaus", "loops");
|
|
6
|
+
const loops = [];
|
|
7
|
+
try {
|
|
8
|
+
const entries = await readdir(loopsDir, { withFileTypes: true });
|
|
9
|
+
for (const entry of entries) {
|
|
10
|
+
if (!entry.isDirectory())
|
|
11
|
+
continue;
|
|
12
|
+
const statePath = join(loopsDir, entry.name, "state.json");
|
|
13
|
+
try {
|
|
14
|
+
const raw = await readFile(statePath, "utf-8");
|
|
15
|
+
const state = JSON.parse(raw);
|
|
16
|
+
loops.push({ name: entry.name, ...state });
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
loops.push({ name: entry.name, active: false, error: "unreadable" });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch { /* no loops dir */ }
|
|
24
|
+
const defaultPath = join(cwd || process.cwd(), ".loophaus", "state.json");
|
|
25
|
+
try {
|
|
26
|
+
const raw = await readFile(defaultPath, "utf-8");
|
|
27
|
+
const state = JSON.parse(raw);
|
|
28
|
+
loops.unshift({ name: "(default)", ...state });
|
|
29
|
+
}
|
|
30
|
+
catch { /* no default */ }
|
|
31
|
+
return loops;
|
|
32
|
+
}
|
|
33
|
+
export async function getLoop(name, cwd) {
|
|
34
|
+
const loops = await listLoops(cwd);
|
|
35
|
+
return loops.find(l => l.name === name) || null;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=loop-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-registry.js","sourceRoot":"","sources":["../../core/loop-registry.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAY;IAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAClE,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACjE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAAE,SAAS;YACnC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;YAC3D,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC;gBACzD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;IAE9B,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;IAC1E,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC;QACzD,KAAK,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAE5B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAY,EAAE,GAAY;IACtD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MergeResult } from "./types.js";
|
|
2
|
+
export declare const STRATEGIES: Record<string, string>;
|
|
3
|
+
export declare function mergeSequential(branches: string[], targetBranch?: string): Promise<MergeResult[]>;
|
|
4
|
+
export declare function mergeSquash(branches: string[]): Promise<MergeResult[]>;
|
|
5
|
+
export declare function mergeCherryPick(branches: string[]): Promise<MergeResult[]>;
|
|
6
|
+
export declare function merge(strategy: string, branches: string[], targetBranch?: string): Promise<MergeResult[]>;
|
|
7
|
+
//# sourceMappingURL=merge-strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-strategy.d.ts","sourceRoot":"","sources":["../../core/merge-strategy.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAI7C,CAAC;AAEF,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,YAAY,GAAE,MAAe,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAa/G;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAc5E;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAiBhF;AAED,wBAAsB,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAS/G"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// core/merge-strategy.ts
|
|
2
|
+
// Strategies for merging parallel worktree results back
|
|
3
|
+
import { execFile } from "node:child_process";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
const execFileAsync = promisify(execFile);
|
|
6
|
+
export const STRATEGIES = {
|
|
7
|
+
sequential: "Merge branches one by one in order",
|
|
8
|
+
"cherry-pick": "Cherry-pick specific commits from each branch",
|
|
9
|
+
squash: "Squash each branch into a single commit before merging",
|
|
10
|
+
};
|
|
11
|
+
export async function mergeSequential(branches, targetBranch = "main") {
|
|
12
|
+
const results = [];
|
|
13
|
+
for (const branch of branches) {
|
|
14
|
+
try {
|
|
15
|
+
await execFileAsync("git", ["merge", branch, "--no-edit"]);
|
|
16
|
+
results.push({ branch, status: "merged" });
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
results.push({ branch, status: "conflict", error: err.message });
|
|
20
|
+
try {
|
|
21
|
+
await execFileAsync("git", ["merge", "--abort"]);
|
|
22
|
+
}
|
|
23
|
+
catch { }
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return results;
|
|
28
|
+
}
|
|
29
|
+
export async function mergeSquash(branches) {
|
|
30
|
+
const results = [];
|
|
31
|
+
for (const branch of branches) {
|
|
32
|
+
try {
|
|
33
|
+
await execFileAsync("git", ["merge", "--squash", branch]);
|
|
34
|
+
await execFileAsync("git", ["commit", "-m", `squash: merge ${branch}`]);
|
|
35
|
+
results.push({ branch, status: "squashed" });
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
results.push({ branch, status: "conflict", error: err.message });
|
|
39
|
+
try {
|
|
40
|
+
await execFileAsync("git", ["merge", "--abort"]);
|
|
41
|
+
}
|
|
42
|
+
catch { }
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return results;
|
|
47
|
+
}
|
|
48
|
+
export async function mergeCherryPick(branches) {
|
|
49
|
+
const results = [];
|
|
50
|
+
for (const branch of branches) {
|
|
51
|
+
try {
|
|
52
|
+
const { stdout } = await execFileAsync("git", ["log", `main..${branch}`, "--format=%H", "--reverse"]);
|
|
53
|
+
const commits = stdout.trim().split("\n").filter(Boolean);
|
|
54
|
+
for (const commit of commits) {
|
|
55
|
+
await execFileAsync("git", ["cherry-pick", commit]);
|
|
56
|
+
}
|
|
57
|
+
results.push({ branch, status: "cherry-picked", commits: commits.length });
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
results.push({ branch, status: "conflict", error: err.message });
|
|
61
|
+
try {
|
|
62
|
+
await execFileAsync("git", ["cherry-pick", "--abort"]);
|
|
63
|
+
}
|
|
64
|
+
catch { }
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return results;
|
|
69
|
+
}
|
|
70
|
+
export async function merge(strategy, branches, targetBranch) {
|
|
71
|
+
if (!strategy || typeof strategy !== "string")
|
|
72
|
+
throw new Error("Merge strategy is required");
|
|
73
|
+
if (!Array.isArray(branches))
|
|
74
|
+
throw new Error("Branches must be an array");
|
|
75
|
+
switch (strategy) {
|
|
76
|
+
case "sequential": return mergeSequential(branches, targetBranch);
|
|
77
|
+
case "squash": return mergeSquash(branches);
|
|
78
|
+
case "cherry-pick": return mergeCherryPick(branches);
|
|
79
|
+
default: throw new Error(`Unknown merge strategy: ${strategy}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=merge-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-strategy.js","sourceRoot":"","sources":["../../core/merge-strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
interface Story {
|
|
2
|
+
id: string;
|
|
3
|
+
priority?: number;
|
|
4
|
+
passes?: boolean;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
interface ParallelResult {
|
|
8
|
+
success: boolean;
|
|
9
|
+
message: string;
|
|
10
|
+
worktrees?: Array<{
|
|
11
|
+
name: string;
|
|
12
|
+
path: string;
|
|
13
|
+
branch: string;
|
|
14
|
+
stories: string[];
|
|
15
|
+
}>;
|
|
16
|
+
results?: never[];
|
|
17
|
+
}
|
|
18
|
+
interface CleanupResult {
|
|
19
|
+
name: string;
|
|
20
|
+
removed: boolean;
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function distributeStories(stories: Story[], n: number): Story[][];
|
|
24
|
+
export declare function runParallel({ prdPath, count, baseBranch, cwd }: {
|
|
25
|
+
prdPath: string;
|
|
26
|
+
count?: number;
|
|
27
|
+
baseBranch?: string;
|
|
28
|
+
cwd?: string;
|
|
29
|
+
}): Promise<ParallelResult>;
|
|
30
|
+
export declare function cleanupParallel(): Promise<CleanupResult[]>;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=parallel-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallel-runner.d.ts","sourceRoot":"","sources":["../../core/parallel-runner.ts"],"names":[],"mappings":"AAWA,UAAU,KAAK;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAcD,UAAU,cAAc;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC;CACnB;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,KAAK,EAAE,EAAE,CAKxE;AAED,wBAAsB,WAAW,CAAC,EAAE,OAAO,EAAE,KAAS,EAAE,UAAmB,EAAE,GAAG,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CA0DnL;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAchE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// core/parallel-runner.ts
|
|
2
|
+
// Parallel loop execution across worktrees
|
|
3
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
4
|
+
import { join, resolve, dirname } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { createWorktree, removeWorktree, listWorktrees } from "./worktree.js";
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const HOOKS_DIR = resolve(dirname(__filename), "..", "hooks");
|
|
9
|
+
export function distributeStories(stories, n) {
|
|
10
|
+
const sorted = [...stories].sort((a, b) => (a.priority || 999) - (b.priority || 999));
|
|
11
|
+
const buckets = Array.from({ length: n }, () => []);
|
|
12
|
+
sorted.forEach((story, i) => buckets[i % n].push(story));
|
|
13
|
+
return buckets;
|
|
14
|
+
}
|
|
15
|
+
export async function runParallel({ prdPath, count = 2, baseBranch = "HEAD", cwd }) {
|
|
16
|
+
const raw = await readFile(prdPath, "utf-8");
|
|
17
|
+
const prd = JSON.parse(raw);
|
|
18
|
+
const pending = (prd.userStories || []).filter(s => !s.passes);
|
|
19
|
+
if (pending.length === 0) {
|
|
20
|
+
return { success: true, message: "No pending stories.", results: [] };
|
|
21
|
+
}
|
|
22
|
+
const effectiveCount = Math.min(count, pending.length);
|
|
23
|
+
const buckets = distributeStories(pending, effectiveCount);
|
|
24
|
+
const worktrees = [];
|
|
25
|
+
for (let i = 0; i < effectiveCount; i++) {
|
|
26
|
+
const name = `parallel-${i}`;
|
|
27
|
+
try {
|
|
28
|
+
const wt = await createWorktree(name, baseBranch);
|
|
29
|
+
worktrees.push({ ...wt, stories: buckets[i] });
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
for (const prev of worktrees) {
|
|
33
|
+
try {
|
|
34
|
+
await removeWorktree(prev.name);
|
|
35
|
+
}
|
|
36
|
+
catch { }
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`Failed to create worktree ${name}: ${err.message}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (const wt of worktrees) {
|
|
42
|
+
const wtPrd = {
|
|
43
|
+
...prd,
|
|
44
|
+
userStories: wt.stories,
|
|
45
|
+
};
|
|
46
|
+
const wtPrdPath = join(wt.path, "prd.json");
|
|
47
|
+
await writeFile(wtPrdPath, JSON.stringify(wtPrd, null, 2), "utf-8");
|
|
48
|
+
const stateDir = join(wt.path, ".loophaus");
|
|
49
|
+
await mkdir(stateDir, { recursive: true });
|
|
50
|
+
await writeFile(join(stateDir, "state.json"), JSON.stringify({
|
|
51
|
+
active: true,
|
|
52
|
+
prompt: `Implement stories from prd.json. Work on one story at a time.`,
|
|
53
|
+
completionPromise: "TASK COMPLETE",
|
|
54
|
+
maxIterations: wt.stories.length * 2 + 3,
|
|
55
|
+
currentIteration: 0,
|
|
56
|
+
sessionId: "",
|
|
57
|
+
name: wt.name,
|
|
58
|
+
startedAt: new Date().toISOString(),
|
|
59
|
+
}, null, 2), "utf-8");
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
success: true,
|
|
63
|
+
worktrees: worktrees.map(wt => ({
|
|
64
|
+
name: wt.name,
|
|
65
|
+
path: wt.path,
|
|
66
|
+
branch: wt.branch,
|
|
67
|
+
stories: wt.stories.map(s => s.id),
|
|
68
|
+
})),
|
|
69
|
+
message: `Created ${effectiveCount} parallel worktrees with ${pending.length} stories distributed.`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export async function cleanupParallel() {
|
|
73
|
+
const worktrees = await listWorktrees();
|
|
74
|
+
const results = [];
|
|
75
|
+
for (const wt of worktrees) {
|
|
76
|
+
if (wt.name.startsWith("parallel-")) {
|
|
77
|
+
try {
|
|
78
|
+
await removeWorktree(wt.name);
|
|
79
|
+
results.push({ name: wt.name, removed: true });
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
results.push({ name: wt.name, removed: false, error: err.message });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return results;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=parallel-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallel-runner.js","sourceRoot":"","sources":["../../core/parallel-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PolicyResult } from "./types.js";
|
|
2
|
+
interface PolicyCondition {
|
|
3
|
+
type: string;
|
|
4
|
+
value: number;
|
|
5
|
+
}
|
|
6
|
+
interface Policy {
|
|
7
|
+
id: string;
|
|
8
|
+
conditions: PolicyCondition[];
|
|
9
|
+
}
|
|
10
|
+
interface PolicyContext {
|
|
11
|
+
totalCost?: number;
|
|
12
|
+
errorCount?: number;
|
|
13
|
+
}
|
|
14
|
+
interface PolicyState {
|
|
15
|
+
currentIteration: number;
|
|
16
|
+
startedAt?: string;
|
|
17
|
+
}
|
|
18
|
+
declare const DEFAULT_POLICY: Policy;
|
|
19
|
+
export declare function loadPolicy(cwd?: string): Promise<Policy>;
|
|
20
|
+
export declare function evaluatePolicy(policy: Policy, state: PolicyState, context?: PolicyContext): PolicyResult;
|
|
21
|
+
export { DEFAULT_POLICY };
|
|
22
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../core/policy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,YAAY,CAAC;AAEhE,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,MAAM;IACd,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,UAAU,aAAa;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,WAAW;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,cAAc,EAAE,MAKrB,CAAC;AAEF,wBAAsB,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ9D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,GAAE,aAAkB,GAAG,YAAY,CAmC5G;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const DEFAULT_POLICY = {
|
|
4
|
+
id: "default",
|
|
5
|
+
conditions: [
|
|
6
|
+
{ type: "max_iterations", value: 20 },
|
|
7
|
+
],
|
|
8
|
+
};
|
|
9
|
+
export async function loadPolicy(cwd) {
|
|
10
|
+
const policyPath = join(cwd || process.cwd(), ".loophaus", "policy.json");
|
|
11
|
+
try {
|
|
12
|
+
const raw = await readFile(policyPath, "utf-8");
|
|
13
|
+
return JSON.parse(raw);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return DEFAULT_POLICY;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function evaluatePolicy(policy, state, context = {}) {
|
|
20
|
+
const violations = [];
|
|
21
|
+
for (const condition of policy.conditions || []) {
|
|
22
|
+
switch (condition.type) {
|
|
23
|
+
case "max_iterations":
|
|
24
|
+
if (state.currentIteration > condition.value) {
|
|
25
|
+
violations.push({ type: "max_iterations", limit: condition.value, current: state.currentIteration });
|
|
26
|
+
}
|
|
27
|
+
break;
|
|
28
|
+
case "max_cost":
|
|
29
|
+
if (context.totalCost && context.totalCost > condition.value) {
|
|
30
|
+
violations.push({ type: "max_cost", limit: condition.value, current: context.totalCost });
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
case "max_time_minutes":
|
|
34
|
+
if (state.startedAt) {
|
|
35
|
+
const elapsed = (Date.now() - new Date(state.startedAt).getTime()) / 60000;
|
|
36
|
+
if (elapsed > condition.value) {
|
|
37
|
+
violations.push({ type: "max_time_minutes", limit: condition.value, current: Math.round(elapsed) });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
break;
|
|
41
|
+
case "max_errors":
|
|
42
|
+
if (context.errorCount && context.errorCount > condition.value) {
|
|
43
|
+
violations.push({ type: "max_errors", limit: condition.value, current: context.errorCount });
|
|
44
|
+
}
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
shouldStop: violations.length > 0,
|
|
50
|
+
violations,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export { DEFAULT_POLICY };
|
|
54
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../core/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAwBjC,MAAM,cAAc,GAAW;IAC7B,EAAE,EAAE,SAAS;IACb,UAAU,EAAE;QACV,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAAE,EAAE;KACtC;CACF,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAY;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;IAC1E,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAW,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,CAAC;IACxB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,KAAkB,EAAE,UAAyB,EAAE;IAC5F,MAAM,UAAU,GAAsB,EAAE,CAAC;IAEzC,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;QAChD,QAAQ,SAAS,CAAC,IAAI,EAAE,CAAC;YACvB,KAAK,gBAAgB;gBACnB,IAAI,KAAK,CAAC,gBAAgB,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;oBAC7C,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC;gBACvG,CAAC;gBACD,MAAM;YACR,KAAK,UAAU;gBACb,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;oBAC7D,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;gBAC5F,CAAC;gBACD,MAAM;YACR,KAAK,kBAAkB;gBACrB,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;oBACpB,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC;oBAC3E,IAAI,OAAO,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;wBAC9B,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;oBACtG,CAAC;gBACH,CAAC;gBACD,MAAM;YACR,KAAK,YAAY;gBACf,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;oBAC/D,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;gBAC/F,CAAC;gBACD,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO;QACL,UAAU,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC;QACjC,UAAU;KACX,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
interface ScoreResult {
|
|
2
|
+
score: number;
|
|
3
|
+
grade: string;
|
|
4
|
+
breakdown: Record<string, number>;
|
|
5
|
+
}
|
|
6
|
+
type ResultValue = number | {
|
|
7
|
+
score?: number;
|
|
8
|
+
} | undefined | null;
|
|
9
|
+
export declare function scoreStory(results: Record<string, ResultValue>): ScoreResult;
|
|
10
|
+
interface EvaluateConfig {
|
|
11
|
+
testCommand?: string;
|
|
12
|
+
typecheckCommand?: string;
|
|
13
|
+
lintCommand?: string;
|
|
14
|
+
verifyScript?: string;
|
|
15
|
+
}
|
|
16
|
+
interface EvaluationResult extends ScoreResult {
|
|
17
|
+
storyId: string;
|
|
18
|
+
results: Record<string, number>;
|
|
19
|
+
}
|
|
20
|
+
export declare function evaluateStory(storyId: string, cwd: string, config?: EvaluateConfig): Promise<EvaluationResult>;
|
|
21
|
+
interface LogEntry {
|
|
22
|
+
storyId: string;
|
|
23
|
+
attempt: number;
|
|
24
|
+
score: number;
|
|
25
|
+
status: string;
|
|
26
|
+
description: string;
|
|
27
|
+
commit?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function logResult(entry: LogEntry, cwd?: string): Promise<void>;
|
|
30
|
+
interface ResultEntry {
|
|
31
|
+
storyId: string;
|
|
32
|
+
attempt: number;
|
|
33
|
+
score: number;
|
|
34
|
+
status: string;
|
|
35
|
+
description: string;
|
|
36
|
+
commit: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function readResults(cwd?: string): Promise<ResultEntry[]>;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=quality-scorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-scorer.d.ts","sourceRoot":"","sources":["../../core/quality-scorer.ts"],"names":[],"mappings":"AAwBA,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,KAAK,WAAW,GAAG,MAAM,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAAG,IAAI,CAAC;AAElE,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,WAAW,CAmB5E;AAED,UAAU,cAAc;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,gBAAiB,SAAQ,WAAW;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,cAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmExH;AAED,UAAU,QAAQ;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAa5E;AAED,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAYtE"}
|