lazycodex-ai 5.0.0-beta.45 → 5.0.0-beta.47
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/cli/index.js +43 -27
- package/dist/cli-node/index.js +43 -27
- package/package.json +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +15 -7
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +294 -96
- package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.js +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +12 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +21 -6
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.js +10 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.d.ts +4 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +25 -57
- package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.d.ts +9 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.js +227 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +17 -3
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +10 -7
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +18 -7
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/constants.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +24 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +25 -5
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-missing-recovery.ts +11 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +34 -64
- package/packages/omo-codex/plugin/components/ulw-loop/src/state-lock.ts +239 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +16 -3
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-template.test.ts +14 -4
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-checkpoint-continuation.test.ts +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-checkpoint.test.ts +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-commands.test.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-complete-goals.test.ts +3 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +10 -8
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +12 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-json-errors.test.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-scope-required.test.ts +144 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-status-next-actions.test.ts +7 -5
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-steering-batch.test.ts +8 -3
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-validation-batch.test.ts +6 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/cli-session.ts +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/quality-gate-builder.ts +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-io-cross-process.test.ts +106 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-io.test.ts +36 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +37 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/state-lock.test.ts +218 -0
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +12 -12
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +2 -1
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +10 -7
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +2 -2
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
|
|
6
|
+
import type { UlwLoopPlan } from "../src/types.ts";
|
|
7
|
+
|
|
8
|
+
type EvidenceModule = typeof import("../src/evidence.ts");
|
|
9
|
+
|
|
10
|
+
const NOW = "2026-09-07T00:00:00.000Z";
|
|
11
|
+
const SCOPE = { sessionId: "s1" } as const;
|
|
12
|
+
const CRITERIA = ["C001", "C002", "C003"] as const;
|
|
13
|
+
|
|
14
|
+
let repoRoot: string;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
repoRoot = await mkdtemp(join(tmpdir(), "ulw-cross-process-"));
|
|
18
|
+
await mkdir(join(repoRoot, ".omo", "ulw-loop", "s1"), { recursive: true });
|
|
19
|
+
await writeFile(join(repoRoot, ".omo", "ulw-loop", "s1", "goals.json"), `${JSON.stringify(plan(), null, 2)}\n`);
|
|
20
|
+
await writeFile(join(repoRoot, ".omo", "ulw-loop", "s1", "ledger.jsonl"), "");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(async () => {
|
|
24
|
+
vi.resetModules();
|
|
25
|
+
await rm(repoRoot, { recursive: true, force: true });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
function plan(): UlwLoopPlan {
|
|
29
|
+
return {
|
|
30
|
+
version: 1,
|
|
31
|
+
evidenceLayoutVersion: 2,
|
|
32
|
+
createdAt: NOW,
|
|
33
|
+
updatedAt: NOW,
|
|
34
|
+
briefPath: ".omo/ulw-loop/s1/brief.md",
|
|
35
|
+
goalsPath: ".omo/ulw-loop/s1/goals.json",
|
|
36
|
+
ledgerPath: ".omo/ulw-loop/s1/ledger.jsonl",
|
|
37
|
+
codexGoalMode: "aggregate",
|
|
38
|
+
activeGoalId: "G001",
|
|
39
|
+
goals: [
|
|
40
|
+
{
|
|
41
|
+
id: "G001",
|
|
42
|
+
title: "Goal one",
|
|
43
|
+
objective: "Goal one",
|
|
44
|
+
status: "in_progress",
|
|
45
|
+
attempt: 1,
|
|
46
|
+
createdAt: NOW,
|
|
47
|
+
updatedAt: NOW,
|
|
48
|
+
successCriteria: CRITERIA.map((id) => ({
|
|
49
|
+
id,
|
|
50
|
+
scenario: `scenario ${id}`,
|
|
51
|
+
userModel: "happy",
|
|
52
|
+
expectedEvidence: "evidence",
|
|
53
|
+
essential: true,
|
|
54
|
+
capturedEvidence: null,
|
|
55
|
+
status: "pending",
|
|
56
|
+
})),
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Each isolated import evaluates plan-io again, so every instance owns a fresh
|
|
63
|
+
// in-process promise chain: the same situation as separate CLI processes
|
|
64
|
+
// sharing one state directory.
|
|
65
|
+
async function loadIsolatedEvidenceModule(): Promise<EvidenceModule> {
|
|
66
|
+
vi.resetModules();
|
|
67
|
+
return await import("../src/evidence.ts");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function readPlanFile(): Promise<UlwLoopPlan> {
|
|
71
|
+
return JSON.parse(await readFile(join(repoRoot, ".omo", "ulw-loop", "s1", "goals.json"), "utf8"));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function readLedgerKinds(): Promise<readonly string[]> {
|
|
75
|
+
const raw = await readFile(join(repoRoot, ".omo", "ulw-loop", "s1", "ledger.jsonl"), "utf8");
|
|
76
|
+
return raw
|
|
77
|
+
.split("\n")
|
|
78
|
+
.filter((line) => line.trim().length > 0)
|
|
79
|
+
.map((line) => JSON.parse(line).kind);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
describe("record-evidence across independent module instances", () => {
|
|
83
|
+
describe("#given three evidence writers that share only the state directory", () => {
|
|
84
|
+
it("#when they record different criteria concurrently #then every criterion lands in goals.json", async () => {
|
|
85
|
+
const writers: { readonly criterionId: string; readonly module: EvidenceModule }[] = [];
|
|
86
|
+
for (const criterionId of CRITERIA) {
|
|
87
|
+
writers.push({ criterionId, module: await loadIsolatedEvidenceModule() });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await Promise.all(
|
|
91
|
+
writers.map(({ criterionId, module }) =>
|
|
92
|
+
module.recordEvidence(
|
|
93
|
+
repoRoot,
|
|
94
|
+
{ goalId: "G001", criterionId, status: "pass", evidence: `proof ${criterionId}` },
|
|
95
|
+
SCOPE,
|
|
96
|
+
),
|
|
97
|
+
),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const persisted = await readPlanFile();
|
|
101
|
+
const statuses = persisted.goals[0]?.successCriteria.map((criterion) => criterion.status);
|
|
102
|
+
expect(statuses).toEqual(["pass", "pass", "pass"]);
|
|
103
|
+
expect(await readLedgerKinds()).toEqual(["evidence_captured", "evidence_captured", "evidence_captured"]);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
1
2
|
import { appendFile, copyFile, mkdir, mkdtemp, readdir, readFile, writeFile } from "node:fs/promises";
|
|
2
3
|
import { tmpdir } from "node:os";
|
|
3
4
|
import { join } from "node:path";
|
|
@@ -140,8 +141,8 @@ describe("readUlwLoopPlan", () => {
|
|
|
140
141
|
const legacyObjective = "Complete all ulw-loop stories in .omo/ulw-loop/goals.json: G001 Build auth service";
|
|
141
142
|
await writeRawPlan(repoRoot, makePlan({ codexObjective: legacyObjective }));
|
|
142
143
|
|
|
143
|
-
// when
|
|
144
|
-
const plan = await readUlwLoopPlan(repoRoot);
|
|
144
|
+
// when: read inside the mutation lock, the way every mutating command does
|
|
145
|
+
const plan = await withUlwLoopMutationLock(repoRoot, () => readUlwLoopPlan(repoRoot));
|
|
145
146
|
|
|
146
147
|
// then
|
|
147
148
|
expect(plan.codexObjective).toBe(STABLE_OBJECTIVE);
|
|
@@ -155,6 +156,39 @@ describe("readUlwLoopPlan", () => {
|
|
|
155
156
|
before: { codexObjective: legacyObjective },
|
|
156
157
|
});
|
|
157
158
|
});
|
|
159
|
+
|
|
160
|
+
it("readUlwLoopPlan refuses to migrate a legacy aggregate plan outside the mutation lock (no unlocked write on a read path)", async () => {
|
|
161
|
+
// given: the same legacy plan, but the read is not wrapped in withUlwLoopMutationLock
|
|
162
|
+
const legacyObjective = "Complete all ulw-loop stories in .omo/ulw-loop/goals.json: G001 Build auth service";
|
|
163
|
+
await writeRawPlan(repoRoot, makePlan({ codexObjective: legacyObjective }));
|
|
164
|
+
|
|
165
|
+
// when
|
|
166
|
+
let caught: unknown;
|
|
167
|
+
try {
|
|
168
|
+
await readUlwLoopPlan(repoRoot);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
caught = error;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// then: it refuses with a recovery hint and writes nothing
|
|
174
|
+
expect(caught).toBeInstanceOf(UlwLoopError);
|
|
175
|
+
expect((caught as UlwLoopError).code).toBe("ULW_LOOP_MIGRATION_REQUIRED");
|
|
176
|
+
const persisted = JSON.parse(await readFile(ulwLoopGoalsPath(repoRoot), "utf8"));
|
|
177
|
+
expect(persisted.codexObjective).toBe(legacyObjective);
|
|
178
|
+
expect(existsSync(ulwLoopLedgerPath(repoRoot))).toBe(false);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("a read of an already-migrated plan outside the lock still succeeds", async () => {
|
|
182
|
+
// given
|
|
183
|
+
await writeRawPlan(repoRoot, makePlan({ codexObjective: STABLE_OBJECTIVE }));
|
|
184
|
+
|
|
185
|
+
// when
|
|
186
|
+
const plan = await readUlwLoopPlan(repoRoot);
|
|
187
|
+
|
|
188
|
+
// then
|
|
189
|
+
expect(plan.codexObjective).toBe(STABLE_OBJECTIVE);
|
|
190
|
+
expect(existsSync(ulwLoopLedgerPath(repoRoot))).toBe(false);
|
|
191
|
+
});
|
|
158
192
|
});
|
|
159
193
|
|
|
160
194
|
describe("writePlan", () => {
|
|
@@ -543,3 +543,40 @@ describe("applySpawnGuards gate-artifact check before reviewer quota", () => {
|
|
|
543
543
|
expect(counters["lazycodex-gate-reviewer:g1:a1"]).toBe(1);
|
|
544
544
|
});
|
|
545
545
|
});
|
|
546
|
+
|
|
547
|
+
describe("applySpawnGuards session state lock", () => {
|
|
548
|
+
function lockPath(): string {
|
|
549
|
+
return join(sessionDir(), ".state.lock");
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
it("#given the state lock held by a live process past the timeout #when guarded #then denies without counting", () => {
|
|
553
|
+
writeGoals();
|
|
554
|
+
mkdirSync(sessionDir(), { recursive: true });
|
|
555
|
+
writeFileSync(
|
|
556
|
+
lockPath(),
|
|
557
|
+
JSON.stringify({ pid: process.pid, createdAt: new Date().toISOString(), token: "live" }),
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
const output = applySpawnGuards(payload("spawn_agent", { message: "scan" }), { lockTimeoutMs: 100 });
|
|
561
|
+
|
|
562
|
+
expect(deny(output).permissionDecision).toBe("deny");
|
|
563
|
+
expect(deny(output).permissionDecisionReason).toContain("state lock");
|
|
564
|
+
expect(existsSync(join(sessionDir(), "spawn-count.json"))).toBe(false);
|
|
565
|
+
expect(existsSync(lockPath())).toBe(true);
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
it("#given a stale lock from a dead process #when guarded #then reclaims it and counts normally", () => {
|
|
569
|
+
writeGoals();
|
|
570
|
+
mkdirSync(sessionDir(), { recursive: true });
|
|
571
|
+
writeFileSync(
|
|
572
|
+
lockPath(),
|
|
573
|
+
JSON.stringify({ pid: 2147483646, createdAt: "2026-01-01T00:00:00.000Z", token: "gone" }),
|
|
574
|
+
);
|
|
575
|
+
|
|
576
|
+
expect(applySpawnGuards(payload("spawn_agent", { message: "scan" }), { lockTimeoutMs: 1000 })).toBe("");
|
|
577
|
+
|
|
578
|
+
const counter = JSON.parse(readFileSync(join(sessionDir(), "spawn-count.json"), "utf8"));
|
|
579
|
+
expect(counter.count).toBe(1);
|
|
580
|
+
expect(existsSync(lockPath())).toBe(false);
|
|
581
|
+
});
|
|
582
|
+
});
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { type ChildProcess, spawn } from "node:child_process";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
3
|
+
import { mkdtemp, rm, utimes, writeFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
7
|
+
|
|
8
|
+
import { ULW_LOOP_LOCK_TIMEOUT_CODE, withStateLock, withStateLockSync } from "../src/state-lock.ts";
|
|
9
|
+
import { UlwLoopError } from "../src/types.ts";
|
|
10
|
+
|
|
11
|
+
let workDir: string;
|
|
12
|
+
let lockPath: string;
|
|
13
|
+
const children: ChildProcess[] = [];
|
|
14
|
+
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
workDir = await mkdtemp(join(tmpdir(), "ulw-state-lock-"));
|
|
17
|
+
lockPath = join(workDir, ".omo", "ulw-loop", "s1", ".state.lock");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
for (const child of children.splice(0)) {
|
|
22
|
+
if (child.exitCode === null) child.kill("SIGKILL");
|
|
23
|
+
}
|
|
24
|
+
await rm(workDir, { recursive: true, force: true });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const HOLDER_SCRIPT = `
|
|
28
|
+
const fs = require("node:fs");
|
|
29
|
+
const [lockPath, holdMs] = process.argv.slice(1);
|
|
30
|
+
fs.mkdirSync(require("node:path").dirname(lockPath), { recursive: true });
|
|
31
|
+
const fd = fs.openSync(lockPath, "wx");
|
|
32
|
+
fs.writeSync(fd, JSON.stringify({ pid: process.pid, createdAt: new Date().toISOString(), token: "holder-" + process.pid }));
|
|
33
|
+
fs.closeSync(fd);
|
|
34
|
+
process.stdout.write("HELD\\n");
|
|
35
|
+
setTimeout(() => {
|
|
36
|
+
fs.writeFileSync(lockPath + ".released", "");
|
|
37
|
+
fs.unlinkSync(lockPath);
|
|
38
|
+
}, Number(holdMs));
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
interface ForeignHolder {
|
|
42
|
+
readonly released: () => boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// A real second process holds the lock file the way another CLI invocation
|
|
46
|
+
// would. Release is observed through a marker file so the check also works
|
|
47
|
+
// while the synchronous acquirer has the event loop blocked.
|
|
48
|
+
function spawnForeignHolder(holdMs: number): Promise<ForeignHolder> {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const child = spawn(process.execPath, ["-e", HOLDER_SCRIPT, lockPath, String(holdMs)], {
|
|
51
|
+
stdio: ["ignore", "pipe", "inherit"],
|
|
52
|
+
});
|
|
53
|
+
children.push(child);
|
|
54
|
+
let output = "";
|
|
55
|
+
child.stdout.setEncoding("utf8");
|
|
56
|
+
child.stdout.on("data", (chunk: string) => {
|
|
57
|
+
output += chunk;
|
|
58
|
+
if (output.includes("HELD")) resolve({ released: () => existsSync(`${lockPath}.released`) });
|
|
59
|
+
});
|
|
60
|
+
child.once("error", reject);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function spawnExitedProcess(): Promise<number> {
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const child = spawn(process.execPath, ["-e", "process.exit(0)"], { stdio: "ignore" });
|
|
67
|
+
child.once("exit", () => {
|
|
68
|
+
if (child.pid === undefined) reject(new Error("child had no pid"));
|
|
69
|
+
else resolve(child.pid);
|
|
70
|
+
});
|
|
71
|
+
child.once("error", reject);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function ownerPid(): number {
|
|
76
|
+
const record: unknown = JSON.parse(readFileSync(lockPath, "utf8"));
|
|
77
|
+
if (typeof record !== "object" || record === null || !("pid" in record) || typeof record.pid !== "number") {
|
|
78
|
+
throw new Error("lock record has no pid");
|
|
79
|
+
}
|
|
80
|
+
return record.pid;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
describe("withStateLock", () => {
|
|
84
|
+
describe("#given a lock held by another live process", () => {
|
|
85
|
+
it("#when acquiring #then it waits for that process to release before running the body", async () => {
|
|
86
|
+
const holder = await spawnForeignHolder(300);
|
|
87
|
+
|
|
88
|
+
const observedReleaseFirst = await withStateLock(lockPath, async () => holder.released(), {
|
|
89
|
+
timeoutMs: 5_000,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(observedReleaseFirst).toBe(true);
|
|
93
|
+
expect(existsSync(lockPath)).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("#when the holder outlives the timeout #then it fails closed without running the body", async () => {
|
|
97
|
+
await spawnForeignHolder(5_000);
|
|
98
|
+
let bodyRan = false;
|
|
99
|
+
|
|
100
|
+
const attempt = withStateLock(
|
|
101
|
+
lockPath,
|
|
102
|
+
async () => {
|
|
103
|
+
bodyRan = true;
|
|
104
|
+
},
|
|
105
|
+
{ timeoutMs: 150 },
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
await expect(attempt).rejects.toMatchObject({ code: ULW_LOOP_LOCK_TIMEOUT_CODE });
|
|
109
|
+
await expect(attempt).rejects.toBeInstanceOf(UlwLoopError);
|
|
110
|
+
expect(bodyRan).toBe(false);
|
|
111
|
+
expect(existsSync(lockPath)).toBe(true);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe("#given a lock left behind by a process that is gone", () => {
|
|
116
|
+
it("#when acquiring #then the stale lock is reclaimed immediately", async () => {
|
|
117
|
+
const deadPid = await spawnExitedProcess();
|
|
118
|
+
mkdirSync(join(workDir, ".omo", "ulw-loop", "s1"), { recursive: true });
|
|
119
|
+
await writeFile(
|
|
120
|
+
lockPath,
|
|
121
|
+
JSON.stringify({ pid: deadPid, createdAt: new Date().toISOString(), token: "gone" }),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const seenOwner = await withStateLock(lockPath, async () => ownerPid(), { timeoutMs: 1_000 });
|
|
125
|
+
|
|
126
|
+
expect(seenOwner).toBe(process.pid);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("#when a legacy record without a token is young #then it is treated as mid-write and waited on, not stolen", async () => {
|
|
130
|
+
mkdirSync(join(workDir, ".omo", "ulw-loop", "s1"), { recursive: true });
|
|
131
|
+
await writeFile(lockPath, JSON.stringify({ pid: process.pid, createdAt: new Date().toISOString() }));
|
|
132
|
+
|
|
133
|
+
const attempt = withStateLock(lockPath, async () => "unreachable", { timeoutMs: 150, staleMs: 60_000 });
|
|
134
|
+
|
|
135
|
+
await expect(attempt).rejects.toMatchObject({ code: ULW_LOOP_LOCK_TIMEOUT_CODE });
|
|
136
|
+
expect(existsSync(lockPath)).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe("#given a live holder whose lock is older than staleMs", () => {
|
|
141
|
+
it("#when acquiring #then age alone never reclaims it and the waiter fails closed", async () => {
|
|
142
|
+
await spawnForeignHolder(5_000);
|
|
143
|
+
const holderPid = ownerPid();
|
|
144
|
+
const twoMinutesAgo = new Date(Date.now() - 120_000);
|
|
145
|
+
await utimes(lockPath, twoMinutesAgo, twoMinutesAgo);
|
|
146
|
+
let bodyRan = false;
|
|
147
|
+
|
|
148
|
+
const attempt = withStateLock(
|
|
149
|
+
lockPath,
|
|
150
|
+
async () => {
|
|
151
|
+
bodyRan = true;
|
|
152
|
+
},
|
|
153
|
+
{ timeoutMs: 200, staleMs: 60_000 },
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
await expect(attempt).rejects.toMatchObject({ code: ULW_LOOP_LOCK_TIMEOUT_CODE });
|
|
157
|
+
expect(bodyRan).toBe(false);
|
|
158
|
+
expect(ownerPid()).toBe(holderPid);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe("#given the lock changed hands while the body ran", () => {
|
|
163
|
+
it("#when the original owner releases #then it leaves the successor's lock in place", async () => {
|
|
164
|
+
const foreign = JSON.stringify({ pid: process.pid, createdAt: new Date().toISOString(), token: "successor" });
|
|
165
|
+
|
|
166
|
+
await withStateLock(lockPath, async () => {
|
|
167
|
+
await writeFile(lockPath, foreign);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
expect(existsSync(lockPath)).toBe(true);
|
|
171
|
+
expect(readFileSync(lockPath, "utf8")).toBe(foreign);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("#when the record is unreadable but older than staleMs #then it is reclaimed", async () => {
|
|
175
|
+
mkdirSync(join(workDir, ".omo", "ulw-loop", "s1"), { recursive: true });
|
|
176
|
+
await writeFile(lockPath, "not json");
|
|
177
|
+
const twoMinutesAgo = new Date(Date.now() - 120_000);
|
|
178
|
+
await utimes(lockPath, twoMinutesAgo, twoMinutesAgo);
|
|
179
|
+
|
|
180
|
+
const seenOwner = await withStateLock(lockPath, async () => ownerPid(), {
|
|
181
|
+
timeoutMs: 1_000,
|
|
182
|
+
staleMs: 60_000,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
expect(seenOwner).toBe(process.pid);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe("#given the body throws", () => {
|
|
190
|
+
it("#when it rejects #then the lock is released and the error propagates", async () => {
|
|
191
|
+
const failure = withStateLock(lockPath, async () => {
|
|
192
|
+
throw new Error("body exploded");
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
await expect(failure).rejects.toThrow("body exploded");
|
|
196
|
+
expect(existsSync(lockPath)).toBe(false);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe("withStateLockSync", () => {
|
|
202
|
+
it("#given a lock held by another live process #when acquiring #then it blocks until release", async () => {
|
|
203
|
+
const holder = await spawnForeignHolder(300);
|
|
204
|
+
|
|
205
|
+
const observedReleaseFirst = withStateLockSync(lockPath, () => holder.released(), { timeoutMs: 5_000 });
|
|
206
|
+
|
|
207
|
+
expect(observedReleaseFirst).toBe(true);
|
|
208
|
+
expect(existsSync(lockPath)).toBe(false);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("#given the holder outlives the timeout #when acquiring #then it throws the timeout error", async () => {
|
|
212
|
+
await spawnForeignHolder(5_000);
|
|
213
|
+
|
|
214
|
+
expect(() => withStateLockSync(lockPath, () => "unreachable", { timeoutMs: 150 })).toThrow(
|
|
215
|
+
expect.objectContaining({ code: ULW_LOOP_LOCK_TIMEOUT_CODE }),
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/git-bash/dist/cli.js\" hook post-compact",
|
|
9
9
|
"timeout": 5,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Resetting Git Bash MCP Reminder",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\git-bash\\dist\\cli.js\" hook post-compact"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/lsp/dist/cli.js\" hook post-compact",
|
|
9
9
|
"timeout": 5,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Resetting LSP Diagnostics Cache",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\lsp\\dist\\cli.js\" hook post-compact"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook post-compact",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Resetting Project Rule Cache",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook post-compact"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/comment-checker/dist/cli.js\" hook post-tool-use",
|
|
9
9
|
"timeout": 30,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Checking Comments",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\comment-checker\\dist\\cli.js\" hook post-tool-use"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/lsp/dist/cli.js\" hook post-tool-use",
|
|
9
9
|
"timeout": 60,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Checking LSP Diagnostics",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\lsp\\dist\\cli.js\" hook post-tool-use"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"type": "command",
|
|
9
9
|
"command": "node \"${PLUGIN_ROOT}/components/teammode/dist/cli.js\" hook post-tool-use",
|
|
10
10
|
"timeout": 10,
|
|
11
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
11
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Checking Thread Title Hygiene",
|
|
12
12
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\teammode\\dist\\cli.js\" hook post-tool-use"
|
|
13
13
|
}
|
|
14
14
|
]
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook post-tool-use",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Matching Project Rules",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook post-tool-use"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook pre-tool-use",
|
|
9
9
|
"timeout": 5,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Enforcing Unlimited Goal Budget",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook pre-tool-use"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"type": "command",
|
|
9
9
|
"command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook pre-tool-use-spawn",
|
|
10
10
|
"timeout": 5,
|
|
11
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
11
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Guarding Ulw-Loop Spawns",
|
|
12
12
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook pre-tool-use-spawn"
|
|
13
13
|
}
|
|
14
14
|
]
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/git-bash/dist/cli.js\" hook pre-tool-use",
|
|
9
9
|
"timeout": 5,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Recommending Git Bash MCP",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\git-bash\\dist\\cli.js\" hook pre-tool-use"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/scripts/auto-update.mjs\" hook session-start",
|
|
9
9
|
"timeout": 15,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Checking Auto Update",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\scripts\\auto-update.mjs\" hook session-start"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/bootstrap/dist/cli.js\" hook session-start",
|
|
9
9
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\bootstrap.ps1\"",
|
|
10
10
|
"timeout": 30,
|
|
11
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
11
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Checking Bootstrap Provisioning"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
14
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook session-start",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Loading Project Rules",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook session-start"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/telemetry/dist/cli.js\" hook session-start",
|
|
9
9
|
"timeout": 15,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Recording Session Telemetry",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\telemetry\\dist\\cli.js\" hook session-start"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/ulw-execute-continuation/dist/cli.js\" hook stop",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Checking Ulw-Execute Continuation",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-execute-continuation\\dist\\cli.js\" hook stop"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook stop",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Checking Ulw-Loop Resume",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook stop"
|
|
12
12
|
}
|
|
13
13
|
]
|
package/packages/omo-codex/plugin/hooks/subagent-stop-checking-ulw-execute-continuation.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/ulw-execute-continuation/dist/cli.js\" hook subagent-stop",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Checking Ulw-Execute Continuation",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-execute-continuation\\dist\\cli.js\" hook subagent-stop"
|
|
12
12
|
}
|
|
13
13
|
]
|
package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/lazycodex-executor-verify/dist/cli.js\" hook subagent-stop",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Verifying LazyCodex Executor Evidence",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\lazycodex-executor-verify\\dist\\cli.js\" hook subagent-stop"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/ultrawork/dist/cli.js\" hook user-prompt-submit",
|
|
9
9
|
"timeout": 5,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Checking Ultrawork Trigger",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ultrawork\\dist\\cli.js\" hook user-prompt-submit"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/ulw-loop/dist/cli.js\" hook user-prompt-submit",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Checking Ulw-Loop Steering",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\ulw-loop\\dist\\cli.js\" hook user-prompt-submit"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/rules/dist/cli.js\" hook user-prompt-submit",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.47) Loading Project Rules",
|
|
11
11
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\node-dispatch.ps1\" \"${PLUGIN_ROOT}\\components\\rules\\dist\\cli.js\" hook user-prompt-submit"
|
|
12
12
|
}
|
|
13
13
|
]
|