@frankzhang2026/opencode-android-orchestrator 0.9.0 → 1.0.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/CHANGELOG.md +34 -0
- package/README.md +92 -55
- package/dist/cli.js +14 -1
- package/dist/cli.js.map +1 -1
- package/dist/config/android-sdk.d.ts +10 -0
- package/dist/config/android-sdk.d.ts.map +1 -0
- package/dist/config/android-sdk.js +50 -0
- package/dist/config/android-sdk.js.map +1 -0
- package/dist/config/commit-message-prefix.d.ts +31 -0
- package/dist/config/commit-message-prefix.d.ts.map +1 -0
- package/dist/config/commit-message-prefix.js +155 -0
- package/dist/config/commit-message-prefix.js.map +1 -0
- package/dist/config/queue-policy.d.ts +12 -0
- package/dist/config/queue-policy.d.ts.map +1 -0
- package/dist/config/queue-policy.js +18 -0
- package/dist/config/queue-policy.js.map +1 -0
- package/dist/config/verification-policy.d.ts +10 -3
- package/dist/config/verification-policy.d.ts.map +1 -1
- package/dist/config/verification-policy.js +66 -13
- package/dist/config/verification-policy.js.map +1 -1
- package/dist/doctor/index.d.ts.map +1 -1
- package/dist/doctor/index.js +3 -49
- package/dist/doctor/index.js.map +1 -1
- package/dist/doctor/installation.d.ts.map +1 -1
- package/dist/doctor/installation.js +81 -0
- package/dist/doctor/installation.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/installer/adaptive-templates.d.ts +8 -2
- package/dist/installer/adaptive-templates.d.ts.map +1 -1
- package/dist/installer/adaptive-templates.js +10 -0
- package/dist/installer/adaptive-templates.js.map +1 -1
- package/dist/installer/index.d.ts +1 -0
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +1 -0
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/init.d.ts +4 -1
- package/dist/installer/init.d.ts.map +1 -1
- package/dist/installer/init.js +60 -9
- package/dist/installer/init.js.map +1 -1
- package/dist/installer/install-manifest.d.ts +1 -0
- package/dist/installer/install-manifest.d.ts.map +1 -1
- package/dist/installer/install-manifest.js +6 -1
- package/dist/installer/install-manifest.js.map +1 -1
- package/dist/installer/opencode-config.d.ts +3 -3
- package/dist/installer/opencode-config.js +1 -1
- package/dist/installer/uninstall.d.ts.map +1 -1
- package/dist/installer/uninstall.js +5 -0
- package/dist/installer/uninstall.js.map +1 -1
- package/dist/installer/upgrade.d.ts +5 -1
- package/dist/installer/upgrade.d.ts.map +1 -1
- package/dist/installer/upgrade.js +94 -11
- package/dist/installer/upgrade.js.map +1 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +11 -5
- package/dist/plugin/index.js.map +1 -1
- package/dist/queue/approvals.d.ts +49 -0
- package/dist/queue/approvals.d.ts.map +1 -0
- package/dist/queue/approvals.js +68 -0
- package/dist/queue/approvals.js.map +1 -0
- package/dist/queue/cli.d.ts +3 -0
- package/dist/queue/cli.d.ts.map +1 -0
- package/dist/queue/cli.js +109 -0
- package/dist/queue/cli.js.map +1 -0
- package/dist/queue/executor.d.ts +24 -0
- package/dist/queue/executor.d.ts.map +1 -0
- package/dist/queue/executor.js +445 -0
- package/dist/queue/executor.js.map +1 -0
- package/dist/queue/lifecycle.d.ts +3 -0
- package/dist/queue/lifecycle.d.ts.map +1 -0
- package/dist/queue/lifecycle.js +24 -0
- package/dist/queue/lifecycle.js.map +1 -0
- package/dist/queue/queue.d.ts +154 -0
- package/dist/queue/queue.d.ts.map +1 -0
- package/dist/queue/queue.js +411 -0
- package/dist/queue/queue.js.map +1 -0
- package/dist/queue/service.d.ts +15 -0
- package/dist/queue/service.d.ts.map +1 -0
- package/dist/queue/service.js +152 -0
- package/dist/queue/service.js.map +1 -0
- package/dist/queue/storage.d.ts +30 -0
- package/dist/queue/storage.d.ts.map +1 -0
- package/dist/queue/storage.js +171 -0
- package/dist/queue/storage.js.map +1 -0
- package/dist/queue/tools.d.ts +12 -0
- package/dist/queue/tools.d.ts.map +1 -0
- package/dist/queue/tools.js +144 -0
- package/dist/queue/tools.js.map +1 -0
- package/docs/MIGRATION.md +47 -14
- package/docs/QUEUE.md +146 -0
- package/docs/SECURITY.md +48 -32
- package/docs/TROUBLESHOOTING.md +36 -11
- package/package.json +1 -1
- package/templates/.opencode/agents/scheduled-planner.md +60 -131
- package/templates/.opencode/commands/abort-task.md +6 -15
- package/templates/.opencode/commands/acceptance.md +6 -15
- package/templates/.opencode/commands/change.md +3 -1
- package/templates/.opencode/commands/resume-review.md +6 -14
- package/templates/.opencode/commands/resume-task.md +6 -23
- package/templates/.opencode/skills/scheduled-quality-orchestrator/SKILL.md +69 -248
- package/templates/AGENTS.md.fragment +8 -0
- package/templates/README.md +9 -1
- package/templates/automation/config.json +9 -2
- package/templates/automation/config.schema.json +222 -45
- package/templates/scripts/automation/abort-task.sh +4 -2
- package/templates/scripts/automation/accept-and-integrate.sh +9 -2
- package/templates/scripts/automation/acceptance-report.sh +4 -2
- package/templates/scripts/automation/approve-and-run.sh +5 -0
- package/templates/scripts/automation/begin-review.sh +1 -0
- package/templates/scripts/automation/block-task.sh +1 -0
- package/templates/scripts/automation/claim-task.sh +1 -0
- package/templates/scripts/automation/lib.sh +186 -2
- package/templates/scripts/automation/orchestrate-task.sh +12 -0
- package/templates/scripts/automation/preflight.sh +25 -4
- package/templates/scripts/automation/prepare-contract-review.sh +4 -0
- package/templates/scripts/automation/quality-gate.sh +1 -0
- package/templates/scripts/automation/record-red.sh +1 -0
- package/templates/scripts/automation/resume-review-fix.sh +1 -0
- package/templates/scripts/automation/resume-review.sh +1 -0
- package/templates/scripts/automation/resume-task.sh +1 -0
- package/templates/scripts/automation/scope-gate.sh +10 -2
- package/templates/scripts/automation/show-acceptance-review.sh +3 -0
- package/templates/scripts/automation/submit-review.sh +8 -2
- package/templates/scripts/automation/tests/run-tests.sh +59 -4
- package/templates/scripts/automation/verify-task.sh +13 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { TaskQueue, type QueueRun } from "./queue.js";
|
|
2
|
+
import { type ProcessIdentity } from "./storage.js";
|
|
3
|
+
export declare function serviceStatus(queue: TaskQueue): {
|
|
4
|
+
running: boolean;
|
|
5
|
+
owner: ProcessIdentity | null;
|
|
6
|
+
};
|
|
7
|
+
export declare function startService(queue: TaskQueue): void;
|
|
8
|
+
export declare function wakeService(queue: TaskQueue): void;
|
|
9
|
+
export declare function stopService(queue: TaskQueue): void;
|
|
10
|
+
export declare function runWorker(queue: TaskQueue, runId: string): Promise<void>;
|
|
11
|
+
/** Reconcile persisted outcomes before consuming; a wake carries no authority. */
|
|
12
|
+
export declare function dispatchOnce(queue: TaskQueue): QueueRun | null;
|
|
13
|
+
export declare function releaseStoppedLeases(queue: TaskQueue): void;
|
|
14
|
+
export declare function serve(queue: TaskQueue): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/queue/service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAoF,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAMtI,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAA;CAAE,CAInG;AAiBD,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAYnD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAElD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAGlD;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAe9E;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,GAAG,IAAI,CAM9D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAe3D;AAED,wBAAsB,KAAK,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA2C3D"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { closeSync, existsSync, mkdirSync, openSync, watch } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { atomicJson, fileLock, invariant, isAlive, processIdentity, readJson, recoverLock } from "./storage.js";
|
|
6
|
+
import { helper, QueueExecutor } from "./executor.js";
|
|
7
|
+
import { androidSdkCandidate } from "../config/android-sdk.js";
|
|
8
|
+
const entry = fileURLToPath(new URL("./cli.js", import.meta.url));
|
|
9
|
+
export function serviceStatus(queue) {
|
|
10
|
+
const path = join(queue.storage.runtime, "service.json");
|
|
11
|
+
const owner = existsSync(path) ? readJson(path) : null;
|
|
12
|
+
return { running: owner !== null && isAlive(owner), owner };
|
|
13
|
+
}
|
|
14
|
+
function detach(queue, args, logName) {
|
|
15
|
+
mkdirSync(queue.storage.runtime, { recursive: true, mode: 0o700 });
|
|
16
|
+
const log = openSync(join(queue.storage.runtime, logName), "a", 0o600);
|
|
17
|
+
try {
|
|
18
|
+
const child = spawn("node", [entry, ...args, queue.storage.root], {
|
|
19
|
+
cwd: queue.storage.root, detached: true, stdio: ["ignore", log, log],
|
|
20
|
+
env: { ...process.env, OPENCODE_ANDROID_ORCHESTRATOR_QUEUE_CLI: entry },
|
|
21
|
+
});
|
|
22
|
+
child.once("error", error => {
|
|
23
|
+
queue.storage.transaction(document => { document.fault = `Background process could not start: ${error.message}`; });
|
|
24
|
+
});
|
|
25
|
+
child.unref();
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
closeSync(log);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function startService(queue) {
|
|
32
|
+
queue.config();
|
|
33
|
+
if (!serviceStatus(queue).running) {
|
|
34
|
+
const lock = join(queue.storage.runtime, "locks/service.lock");
|
|
35
|
+
if (existsSync(lock)) {
|
|
36
|
+
const owner = readJson(lock);
|
|
37
|
+
if (isAlive(owner)) {
|
|
38
|
+
wakeService(queue);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
recoverLock(lock);
|
|
42
|
+
}
|
|
43
|
+
detach(queue, ["_serve"], "service.log");
|
|
44
|
+
}
|
|
45
|
+
wakeService(queue);
|
|
46
|
+
}
|
|
47
|
+
export function wakeService(queue) {
|
|
48
|
+
atomicJson(join(queue.storage.runtime, "wake.json"), { at: new Date().toISOString() });
|
|
49
|
+
}
|
|
50
|
+
export function stopService(queue) {
|
|
51
|
+
const status = serviceStatus(queue);
|
|
52
|
+
if (status.running && status.owner)
|
|
53
|
+
process.kill(status.owner.pid, "SIGTERM");
|
|
54
|
+
}
|
|
55
|
+
export async function runWorker(queue, runId) {
|
|
56
|
+
const owner = processIdentity(process.pid);
|
|
57
|
+
invariant(owner, "Cannot establish executor identity");
|
|
58
|
+
let run = null;
|
|
59
|
+
queue.storage.transaction(document => {
|
|
60
|
+
invariant(document.active?.id === runId && document.active.worker === null, "Execution is missing, already started, or belongs to another worker");
|
|
61
|
+
document.active.worker = owner;
|
|
62
|
+
run = structuredClone(document.active);
|
|
63
|
+
});
|
|
64
|
+
invariant(run, "Execution reservation is missing");
|
|
65
|
+
// Resolve on the source root before entering an isolated worktree. Its
|
|
66
|
+
// ignored local.properties is deliberately never copied into task workspaces.
|
|
67
|
+
const sdk = androidSdkCandidate(queue.storage.root);
|
|
68
|
+
if (sdk)
|
|
69
|
+
process.env.ANDROID_HOME = sdk.directory;
|
|
70
|
+
await new QueueExecutor(queue, run).execute();
|
|
71
|
+
}
|
|
72
|
+
/** Reconcile persisted outcomes before consuming; a wake carries no authority. */
|
|
73
|
+
export function dispatchOnce(queue) {
|
|
74
|
+
queue.reconcile();
|
|
75
|
+
releaseStoppedLeases(queue);
|
|
76
|
+
const run = queue.reserve();
|
|
77
|
+
if (run)
|
|
78
|
+
detach(queue, ["_worker", run.id], `executor-${run.id}.log`);
|
|
79
|
+
return run;
|
|
80
|
+
}
|
|
81
|
+
export function releaseStoppedLeases(queue) {
|
|
82
|
+
queue.storage.transaction(after => {
|
|
83
|
+
const leasePath = join(queue.storage.runtime, "locks/repository.workspace.lease/lease.json");
|
|
84
|
+
if (!after.active && existsSync(leasePath)) {
|
|
85
|
+
const lease = readJson(leasePath);
|
|
86
|
+
const item = after.items.find(candidate => candidate.taskId === lease.taskId);
|
|
87
|
+
if (item?.workspaceStrategy === "isolatedWorktree" && item.sealedDiff && item.sealedRunId === item.runId) {
|
|
88
|
+
const workspace = readJson(join(queue.storage.runtime, "workspaces", `${item.taskId}.json`));
|
|
89
|
+
if (workspace.executionExited) {
|
|
90
|
+
invariant(helper(workspace.taskRoot, "automation_worktree_diff_sha", [workspace.taskRoot]) === item.sealedDiff, "Isolated candidate changed before execution-slot release");
|
|
91
|
+
helper(item.sourceRoot, "automation_release_repository_lease", [item.taskId]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
export async function serve(queue) {
|
|
98
|
+
const lifecycleRelease = fileLock(join(queue.storage.runtime, "locks/lifecycle.lock"));
|
|
99
|
+
let release;
|
|
100
|
+
try {
|
|
101
|
+
const lock = join(queue.storage.runtime, "locks/service.lock");
|
|
102
|
+
if (existsSync(lock))
|
|
103
|
+
return;
|
|
104
|
+
queue.config();
|
|
105
|
+
release = fileLock(lock, 0);
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
lifecycleRelease();
|
|
109
|
+
}
|
|
110
|
+
const owner = processIdentity(process.pid);
|
|
111
|
+
invariant(owner, "Cannot identify scheduler process");
|
|
112
|
+
atomicJson(join(queue.storage.runtime, "service.json"), owner);
|
|
113
|
+
let stopped = false;
|
|
114
|
+
let wake = null;
|
|
115
|
+
const stop = () => { stopped = true; wake?.(); };
|
|
116
|
+
process.on("SIGTERM", stop);
|
|
117
|
+
process.on("SIGINT", stop);
|
|
118
|
+
const watcher = watch(queue.storage.runtime, (_event, file) => { if (file === "wake.json")
|
|
119
|
+
wake?.(); });
|
|
120
|
+
try {
|
|
121
|
+
while (!stopped) {
|
|
122
|
+
let interval = 5000;
|
|
123
|
+
try {
|
|
124
|
+
interval = queue.config().queue?.scanIntervalMs ?? 5000;
|
|
125
|
+
dispatchOnce(queue);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
process.stderr.write(`${new Date().toISOString()} ${String(error)}\n`);
|
|
129
|
+
// A public/environment fault suspends consumption but never intake.
|
|
130
|
+
try {
|
|
131
|
+
queue.storage.transaction(document => { document.fault = String(error); });
|
|
132
|
+
}
|
|
133
|
+
catch { /* keep original transaction evidence */ }
|
|
134
|
+
}
|
|
135
|
+
if (stopped)
|
|
136
|
+
break;
|
|
137
|
+
const deadlines = queue.storage.read().items.filter(item => item.state === "QUEUED" && item.notBefore).map(item => Date.parse(item.notBefore) - Date.now()).filter(delay => delay > 0);
|
|
138
|
+
const delay = Math.max(50, Math.min(interval, ...deadlines));
|
|
139
|
+
await new Promise(done => {
|
|
140
|
+
const timer = setTimeout(() => { wake = null; done(); }, delay);
|
|
141
|
+
wake = () => { clearTimeout(timer); wake = null; done(); };
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
watcher.close();
|
|
147
|
+
process.off("SIGTERM", stop);
|
|
148
|
+
process.off("SIGINT", stop);
|
|
149
|
+
release();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/queue/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare function invariant(condition: unknown, message: string): asserts condition;
|
|
2
|
+
export declare function sha256(value: string | Buffer): string;
|
|
3
|
+
export declare function git(root: string, args: readonly string[], input?: string): string;
|
|
4
|
+
export declare function safePath(root: string, path: string): string;
|
|
5
|
+
export declare function readJson<T>(path: string): T;
|
|
6
|
+
/** Replace a complete document; flush both bytes and its directory entry. */
|
|
7
|
+
export declare function atomicJson(path: string, value: unknown): void;
|
|
8
|
+
export interface ProcessIdentity {
|
|
9
|
+
pid: number;
|
|
10
|
+
started: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function processIdentity(pid: number): ProcessIdentity | null;
|
|
13
|
+
export declare function isAlive(owner: ProcessIdentity): boolean;
|
|
14
|
+
export declare function processGroupAlive(pid: number): boolean;
|
|
15
|
+
/** Exclusive creation has no timeout takeover. Unknown/dead owners fail closed.
|
|
16
|
+
* Only a verified dead owner may be removed by explicit recovery. */
|
|
17
|
+
export declare function fileLock(path: string, waitMs?: number): () => void;
|
|
18
|
+
export declare function recoverLock(path: string): boolean;
|
|
19
|
+
export declare class QueueStorage<T> {
|
|
20
|
+
private readonly initial;
|
|
21
|
+
readonly root: string;
|
|
22
|
+
readonly runtime: string;
|
|
23
|
+
readonly path: string;
|
|
24
|
+
readonly lockPath: string;
|
|
25
|
+
constructor(directory: string, initial: () => T);
|
|
26
|
+
read(): T;
|
|
27
|
+
transaction<R>(action: (document: T) => R): R;
|
|
28
|
+
relativeRuntime(path: string): string;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/queue/storage.ts"],"names":[],"mappings":"AAQA,wBAAgB,SAAS,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAEhF;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAQjF;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAS3D;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAG3C;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAY7D;AAED,MAAM,WAAW,eAAe;IAAG,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAEjE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CASnE;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAEvD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOtD;AAED;qEACqE;AACrE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAO,GAAG,MAAM,IAAI,CAwBhE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAcjD;AAED,qBAAa,YAAY,CAAC,CAAC;IAKM,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACd,SAAS,EAAE,MAAM,EAAmB,OAAO,EAAE,MAAM,CAAC;IAUhE,IAAI,IAAI,CAAC;IACT,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC;IAS7C,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAGtC"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { closeSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
4
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
|
+
export function invariant(condition, message) {
|
|
6
|
+
if (!condition)
|
|
7
|
+
throw new Error(message);
|
|
8
|
+
}
|
|
9
|
+
export function sha256(value) {
|
|
10
|
+
return createHash("sha256").update(value).digest("hex");
|
|
11
|
+
}
|
|
12
|
+
export function git(root, args, input) {
|
|
13
|
+
const result = spawnSync("git", ["-c", "core.hooksPath=/dev/null", "-C", root, ...args], {
|
|
14
|
+
encoding: "utf8", maxBuffer: 16 * 1024 * 1024,
|
|
15
|
+
...(input === undefined ? {} : { input }),
|
|
16
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
17
|
+
});
|
|
18
|
+
invariant(result.status === 0, result.error?.message ?? result.stderr.trim() ?? "Git command failed");
|
|
19
|
+
return result.stdout.trimEnd();
|
|
20
|
+
}
|
|
21
|
+
export function safePath(root, path) {
|
|
22
|
+
invariant(path.length > 0 && !path.includes("\0") && !isAbsolute(path), "Expected a repository-relative path");
|
|
23
|
+
invariant(!path.split(/[\\/]/).some(part => part === ".." || part === ".git"), "Unsafe repository path");
|
|
24
|
+
const target = resolve(root, path);
|
|
25
|
+
invariant(target.startsWith(`${resolve(root)}${sep}`), "Path escapes the repository");
|
|
26
|
+
for (let cursor = target; cursor !== resolve(root); cursor = dirname(cursor)) {
|
|
27
|
+
if (existsSync(cursor))
|
|
28
|
+
invariant(!lstatSync(cursor).isSymbolicLink(), `Symbolic link is not allowed: ${cursor}`);
|
|
29
|
+
}
|
|
30
|
+
return target;
|
|
31
|
+
}
|
|
32
|
+
export function readJson(path) {
|
|
33
|
+
invariant(!lstatSync(path).isSymbolicLink(), `Refusing symbolic-link runtime file: ${path}`);
|
|
34
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
35
|
+
}
|
|
36
|
+
/** Replace a complete document; flush both bytes and its directory entry. */
|
|
37
|
+
export function atomicJson(path, value) {
|
|
38
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
39
|
+
if (existsSync(path))
|
|
40
|
+
invariant(!lstatSync(path).isSymbolicLink(), `Refusing symbolic link: ${path}`);
|
|
41
|
+
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
42
|
+
const descriptor = openSync(temporary, "wx", 0o600);
|
|
43
|
+
try {
|
|
44
|
+
writeFileSync(descriptor, `${JSON.stringify(value, null, 2)}\n`);
|
|
45
|
+
fsyncSync(descriptor);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
closeSync(descriptor);
|
|
49
|
+
}
|
|
50
|
+
renameSync(temporary, path);
|
|
51
|
+
const directory = openSync(dirname(path), "r");
|
|
52
|
+
try {
|
|
53
|
+
fsyncSync(directory);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
closeSync(directory);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export function processIdentity(pid) {
|
|
60
|
+
invariant(Number.isInteger(pid) && pid > 0, "Invalid process ID");
|
|
61
|
+
const result = spawnSync("ps", ["-p", String(pid), "-o", "lstart=", "-o", "stat="], { encoding: "utf8" });
|
|
62
|
+
invariant(!result.error, `Cannot inspect process ownership: ${result.error?.message}`);
|
|
63
|
+
if (result.status === 1 && !result.stdout.trim())
|
|
64
|
+
return null;
|
|
65
|
+
invariant(result.status === 0 && result.stdout.trim(), "Cannot prove process ownership; recovery required");
|
|
66
|
+
const parts = result.stdout.trim().split(/\s+/);
|
|
67
|
+
if (parts.at(-1)?.startsWith("Z"))
|
|
68
|
+
return null;
|
|
69
|
+
return { pid, started: parts.slice(0, -1).join(" ") };
|
|
70
|
+
}
|
|
71
|
+
export function isAlive(owner) {
|
|
72
|
+
return processIdentity(owner.pid)?.started === owner.started;
|
|
73
|
+
}
|
|
74
|
+
export function processGroupAlive(pid) {
|
|
75
|
+
const result = spawnSync("ps", ["-axo", "pgid=,stat="], { encoding: "utf8" });
|
|
76
|
+
invariant(result.status === 0, "Cannot inspect executor process group; recovery required");
|
|
77
|
+
return result.stdout.split("\n").some(line => {
|
|
78
|
+
const [group, state] = line.trim().split(/\s+/);
|
|
79
|
+
return Number(group) === pid && !state?.startsWith("Z");
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/** Exclusive creation has no timeout takeover. Unknown/dead owners fail closed.
|
|
83
|
+
* Only a verified dead owner may be removed by explicit recovery. */
|
|
84
|
+
export function fileLock(path, waitMs = 5000) {
|
|
85
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
86
|
+
const identity = processIdentity(process.pid);
|
|
87
|
+
invariant(identity, "Cannot record lock owner");
|
|
88
|
+
const token = randomUUID();
|
|
89
|
+
let descriptor;
|
|
90
|
+
for (let attempt = 0;; attempt += 1) {
|
|
91
|
+
try {
|
|
92
|
+
descriptor = openSync(path, "wx", 0o600);
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (error.code !== "EEXIST" || attempt * 20 >= waitMs) {
|
|
97
|
+
throw new Error(`Queue transaction is occupied; retry or recover its recorded owner: ${path}`, { cause: error });
|
|
98
|
+
}
|
|
99
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 20);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
writeFileSync(descriptor, JSON.stringify({ ...identity, token }));
|
|
104
|
+
fsyncSync(descriptor);
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
closeSync(descriptor);
|
|
108
|
+
}
|
|
109
|
+
return () => {
|
|
110
|
+
const owner = readJson(path);
|
|
111
|
+
invariant(owner.token === token, "Queue lock ownership changed");
|
|
112
|
+
unlinkSync(path);
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
export function recoverLock(path) {
|
|
116
|
+
if (!existsSync(path))
|
|
117
|
+
return false;
|
|
118
|
+
const release = fileLock(`${path}.recovery`);
|
|
119
|
+
try {
|
|
120
|
+
if (!existsSync(path))
|
|
121
|
+
return false;
|
|
122
|
+
const before = readFileSync(path, "utf8");
|
|
123
|
+
const owner = readJson(path);
|
|
124
|
+
invariant(!isAlive(owner), "Lock owner is still alive; refusing recovery");
|
|
125
|
+
invariant(readFileSync(path, "utf8") === before, "Lock changed during recovery");
|
|
126
|
+
// Atomic rename preserves the original record for diagnosis. Never remove a
|
|
127
|
+
// live lock because its heartbeat is old.
|
|
128
|
+
renameSync(path, `${path}.recovered-${randomUUID()}`);
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
release();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export class QueueStorage {
|
|
136
|
+
initial;
|
|
137
|
+
root;
|
|
138
|
+
runtime;
|
|
139
|
+
path;
|
|
140
|
+
lockPath;
|
|
141
|
+
constructor(directory, initial) {
|
|
142
|
+
this.initial = initial;
|
|
143
|
+
this.root = realpathSync(git(resolve(directory), ["rev-parse", "--show-toplevel"]));
|
|
144
|
+
const common = git(this.root, ["rev-parse", "--git-common-dir"]);
|
|
145
|
+
const commonRoot = realpathSync(resolve(this.root, common));
|
|
146
|
+
this.runtime = join(commonRoot, "automation-runtime");
|
|
147
|
+
if (existsSync(this.runtime))
|
|
148
|
+
invariant(!lstatSync(this.runtime).isSymbolicLink(), "Runtime must not be a symbolic link");
|
|
149
|
+
for (const path of ["inbox", "locks", "evidence", "workspaces", "state"])
|
|
150
|
+
safePath(this.runtime, path);
|
|
151
|
+
this.path = safePath(this.runtime, "inbox/queue.json");
|
|
152
|
+
this.lockPath = safePath(this.runtime, "locks/queue.transaction.lock");
|
|
153
|
+
}
|
|
154
|
+
read() { return existsSync(this.path) ? readJson(this.path) : this.initial(); }
|
|
155
|
+
transaction(action) {
|
|
156
|
+
const release = fileLock(this.lockPath);
|
|
157
|
+
try {
|
|
158
|
+
const document = this.read();
|
|
159
|
+
const result = action(document);
|
|
160
|
+
atomicJson(this.path, document);
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
release();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
relativeRuntime(path) {
|
|
168
|
+
return relative(this.runtime, path);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/queue/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EACL,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAChE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,GAClE,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAE9E,MAAM,UAAU,SAAS,CAAC,SAAkB,EAAE,OAAe;IAC3D,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,KAAsB;IAC3C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,IAAuB,EAAE,KAAc;IACvE,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,0BAA0B,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE;QACvF,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;QAC7C,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;QACzC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,mBAAmB,EAAE,GAAG,EAAE;KAClD,CAAC,CAAC;IACH,SAAS,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,oBAAoB,CAAC,CAAC;IACtG,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,IAAY;IACjD,SAAS,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,qCAAqC,CAAC,CAAC;IAC/G,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,MAAM,CAAC,EAAE,wBAAwB,CAAC,CAAC;IACzG,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,6BAA6B,CAAC,CAAC;IACtF,KAAK,IAAI,MAAM,GAAG,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7E,IAAI,UAAU,CAAC,MAAM,CAAC;YAAE,SAAS,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,EAAE,iCAAiC,MAAM,EAAE,CAAC,CAAC;IACpH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAI,IAAY;IACtC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,EAAE,wCAAwC,IAAI,EAAE,CAAC,CAAC;IAC7F,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAM,CAAC;AACrD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,KAAc;IACrD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,IAAI,UAAU,CAAC,IAAI,CAAC;QAAE,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,EAAE,2BAA2B,IAAI,EAAE,CAAC,CAAC;IACtG,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,UAAU,EAAE,MAAM,CAAC;IAChD,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACpD,IAAI,CAAC;QACH,aAAa,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACjE,SAAS,CAAC,UAAU,CAAC,CAAC;IACxB,CAAC;YAAS,CAAC;QAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAAC,CAAC;IACpC,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC5B,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/C,IAAI,CAAC;QAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAAC,CAAC;YAAS,CAAC;QAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAAC,CAAC;AACjE,CAAC;AAID,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE,oBAAoB,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1G,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,qCAAqC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACvF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IAC9D,SAAS,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,mDAAmD,CAAC,CAAC;IAC5G,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAChD,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAsB;IAC5C,OAAO,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,KAAK,KAAK,CAAC,OAAO,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9E,SAAS,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,0DAA0D,CAAC,CAAC;IAC3F,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAC3C,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAChD,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC;AAED;qEACqE;AACrE,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,MAAM,GAAG,IAAI;IAClD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9C,SAAS,CAAC,QAAQ,EAAE,0BAA0B,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,UAAU,EAAE,CAAC;IAC3B,IAAI,UAAkB,CAAC;IACvB,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,IAAI,CAAC,EAAE,CAAC;QACrC,IAAI,CAAC;YAAC,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAAC,MAAM;QAAC,CAAC;QACxD,OAAO,KAAK,EAAE,CAAC;YACb,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,GAAG,EAAE,IAAI,MAAM,EAAE,CAAC;gBACjF,MAAM,IAAI,KAAK,CAAC,uEAAuE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACnH,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QACH,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAClE,SAAS,CAAC,UAAU,CAAC,CAAC;IACxB,CAAC;YAAS,CAAC;QAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAAC,CAAC;IACpC,OAAO,GAAG,EAAE;QACV,MAAM,KAAK,GAAG,QAAQ,CAAsC,IAAI,CAAC,CAAC;QAClE,SAAS,CAAC,KAAK,CAAC,KAAK,KAAK,KAAK,EAAE,8BAA8B,CAAC,CAAC;QACjE,UAAU,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,IAAI,WAAW,CAAC,CAAC;IAC7C,IAAI,CAAC;QACL,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QACpC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,QAAQ,CAAkB,IAAI,CAAC,CAAC;QAC9C,SAAS,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,8CAA8C,CAAC,CAAC;QAC3E,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,MAAM,EAAE,8BAA8B,CAAC,CAAC;QACjF,4EAA4E;QAC5E,0CAA0C;QAC1C,UAAU,CAAC,IAAI,EAAE,GAAG,IAAI,cAAc,UAAU,EAAE,EAAE,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC;IACZ,CAAC;YAAS,CAAC;QAAC,OAAO,EAAE,CAAC;IAAC,CAAC;AAC1B,CAAC;AAED,MAAM,OAAO,YAAY;IAKyB;IAJvC,IAAI,CAAS;IACb,OAAO,CAAS;IAChB,IAAI,CAAS;IACb,QAAQ,CAAS;IAC1B,YAAY,SAAiB,EAAmB,OAAgB;QAAhB,YAAO,GAAP,OAAO,CAAS;QAC9D,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;QACpF,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC,CAAC;QACjE,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAC5D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,CAAC;QACtD,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,cAAc,EAAE,EAAE,qCAAqC,CAAC,CAAC;QAC1H,KAAK,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACvG,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,8BAA8B,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,KAAQ,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACrF,WAAW,CAAI,MAA0B;QACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YAChC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAChC,OAAO,MAAM,CAAC;QAChB,CAAC;gBAAS,CAAC;YAAC,OAAO,EAAE,CAAC;QAAC,CAAC;IAC1B,CAAC;IACD,eAAe,CAAC,IAAY;QAC1B,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ToolDefinition } from "@opencode-ai/plugin";
|
|
2
|
+
import { ApprovalLedger } from "./approvals.js";
|
|
3
|
+
export declare const QUEUE_TOOL_NAMES: readonly ["android_orchestrator_snapshot", "android_orchestrator_intake", "android_orchestrator_queue"];
|
|
4
|
+
export declare function createQueueTools(worktree: string, approvals?: ApprovalLedger): Record<string, ToolDefinition>;
|
|
5
|
+
/** In unattended runs, executable shell syntax and indirect Git entry points
|
|
6
|
+
* cannot extend the installed agents' command allowlists. */
|
|
7
|
+
export declare function guardExecutorCommand(input: {
|
|
8
|
+
tool: string;
|
|
9
|
+
}, output: {
|
|
10
|
+
args: unknown;
|
|
11
|
+
}, directory?: string): void;
|
|
12
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/queue/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAIlF,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIhD,eAAO,MAAM,gBAAgB,yGAA0G,CAAC;AAExI,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,iBAAuB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAoGnH;AAED;6DAC6D;AAC7D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAmBjH"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { installationDoctorChecks } from "../doctor/index.js";
|
|
4
|
+
import { invariant } from "./storage.js";
|
|
5
|
+
import { ApprovalLedger } from "./approvals.js";
|
|
6
|
+
import { TaskQueue } from "./queue.js";
|
|
7
|
+
import { serviceStatus, startService, stopService, wakeService } from "./service.js";
|
|
8
|
+
export const QUEUE_TOOL_NAMES = ["android_orchestrator_snapshot", "android_orchestrator_intake", "android_orchestrator_queue"];
|
|
9
|
+
export function createQueueTools(worktree, approvals = new ApprovalLedger()) {
|
|
10
|
+
const root = resolve(worktree);
|
|
11
|
+
function bounded(context, mutation = false) {
|
|
12
|
+
invariant(!context.abort.aborted && resolve(context.worktree) === root, "Queue tool workspace mismatch or aborted call");
|
|
13
|
+
invariant(context.agent === "scheduled-planner", "Only the interactive Planner may access contract intake and queue controls");
|
|
14
|
+
if (mutation) {
|
|
15
|
+
const checks = installationDoctorChecks(root);
|
|
16
|
+
const failures = ["installation-manifest", "managed-resources", "managed-permissions"].filter(id => !checks.some(check => check.id === id && check.status === "pass"));
|
|
17
|
+
invariant(failures.length === 0, `Queue mutation requires an intact installation: ${failures.join(", ")}`);
|
|
18
|
+
}
|
|
19
|
+
return new TaskQueue(root);
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
android_orchestrator_snapshot: tool({
|
|
23
|
+
description: "Read stable committed planning code without following the active Coder's branch or working files. First request snapshot, then read its exact planningHead and path.",
|
|
24
|
+
args: { action: tool.schema.enum(["snapshot", "read"]), targetBranch: tool.schema.string().optional(), planningHead: tool.schema.string().optional(), path: tool.schema.string().optional() },
|
|
25
|
+
async execute(args, context) {
|
|
26
|
+
const queue = bounded(context);
|
|
27
|
+
return JSON.stringify(args.action === "snapshot" ? queue.snapshot(args.targetBranch) : queue.readSnapshot(args.planningHead ?? "", args.path ?? ""));
|
|
28
|
+
},
|
|
29
|
+
}),
|
|
30
|
+
android_orchestrator_intake: tool({
|
|
31
|
+
description: "Seal a proposal-approved contract and plan in the independent inbox, or enqueue its exact reviewed digest and explicit human-selected approvalText. Approval returns immediately; only the background scheduler starts execution.",
|
|
32
|
+
args: {
|
|
33
|
+
action: tool.schema.enum(["draft", "enqueue"]),
|
|
34
|
+
draftJson: tool.schema.string().optional(), key: tool.schema.string().optional(),
|
|
35
|
+
digest: tool.schema.string().optional(), approval: tool.schema.string().optional(),
|
|
36
|
+
},
|
|
37
|
+
async execute(args, context) {
|
|
38
|
+
const queue = bounded(context, true);
|
|
39
|
+
if (args.action === "draft") {
|
|
40
|
+
const draft = queue.draft(JSON.parse(args.draftJson ?? "{}"), approvals.consume(context, "proposal", "proposal"));
|
|
41
|
+
const approvalText = queue.approvalText(draft);
|
|
42
|
+
const question = approvals.prepare(context.sessionID, "enqueue", `${draft.key}:${draft.digest}`, "合同确认", `确认将 ${draft.key}(摘要 ${draft.digest.slice(0, 12)},目标 ${draft.targetBranch})按已展示的合同及提交策略入队?`, approvalText);
|
|
43
|
+
return JSON.stringify({ ...draft, approvalText, question });
|
|
44
|
+
}
|
|
45
|
+
// An exact duplicate only returns the already authorized record; it
|
|
46
|
+
// cannot recreate a cancelled task or widen its policy.
|
|
47
|
+
const existing = queue.storage.read().items.some(item => item.key === args.key);
|
|
48
|
+
const proof = existing ? undefined : approvals.consume(context, "enqueue", `${args.key}:${args.digest}`);
|
|
49
|
+
const item = queue.enqueue(args.key ?? "", args.digest ?? "", args.approval ?? "", proof);
|
|
50
|
+
let serviceError = null;
|
|
51
|
+
try {
|
|
52
|
+
startService(queue);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
serviceError = String(error);
|
|
56
|
+
}
|
|
57
|
+
return JSON.stringify({ key: item.key, state: item.state, workspaceStrategy: item.workspaceStrategy, commitPolicy: item.commitPolicy,
|
|
58
|
+
waitingReason: item.waitingReason, serviceError, pushed: false });
|
|
59
|
+
},
|
|
60
|
+
}),
|
|
61
|
+
android_orchestrator_queue: tool({
|
|
62
|
+
description: "Inspect durable queue notifications or manage the single repository executor. Acceptance, revalidation, recovery and abort all queue work through the same slot. Integration requires the latest candidate hash and human approval.",
|
|
63
|
+
args: {
|
|
64
|
+
action: tool.schema.enum(["status", "review", "start", "stop", "pause", "resume", "clear-fault", "cancel", "revoke", "acknowledge", "integrate", "revalidate", "resume-task", "resume-review", "abort", "recover", "recover-execution", "priority", "policy"]),
|
|
65
|
+
operation: tool.schema.enum(["integrate", "resume-task", "resume-review", "abort"]).optional(),
|
|
66
|
+
key: tool.schema.string().optional(), approval: tool.schema.string().optional(), candidate: tool.schema.string().optional(),
|
|
67
|
+
priority: tool.schema.number().int().min(-100).max(100).optional(),
|
|
68
|
+
workspaceStrategy: tool.schema.enum(["inPlaceExclusive", "isolatedWorktree"]).optional(),
|
|
69
|
+
commitPolicy: tool.schema.enum(["humanApproval", "autoCommit"]).optional(),
|
|
70
|
+
},
|
|
71
|
+
async execute(args, context) {
|
|
72
|
+
const queue = bounded(context, !["status", "review"].includes(args.action));
|
|
73
|
+
if (args.action === "status") {
|
|
74
|
+
if (args.key)
|
|
75
|
+
return JSON.stringify(queue.details(args.key));
|
|
76
|
+
const document = queue.storage.read();
|
|
77
|
+
return JSON.stringify({ service: serviceStatus(queue), paused: document.paused, fault: document.fault, active: document.active,
|
|
78
|
+
items: document.items.map(({ key, taskId, state, waitingReason, workspaceStrategy, commitPolicy, targetBranch, taskRoot, dependsOn, sealedDiff, candidateId, completedCommit }) => ({ key, taskId, state, waitingReason, workspaceStrategy, commitPolicy, targetBranch, taskRoot, dependsOn, sealedDiff, candidateId, completedCommit, pushed: false })),
|
|
79
|
+
notifications: document.notifications.filter(notification => !notification.acknowledged) });
|
|
80
|
+
}
|
|
81
|
+
if (args.action === "review") {
|
|
82
|
+
invariant(args.operation && args.key, "Review requires a task key and operation");
|
|
83
|
+
const item = queue.item(args.key);
|
|
84
|
+
const config = queue.config();
|
|
85
|
+
const approval = args.operation === "integrate" ? config.approvalPhrases.acceptance : args.operation === "abort" ? config.approvalPhrases.abort : config.approvalPhrases.resume;
|
|
86
|
+
invariant(approval, "Approval phrase is missing");
|
|
87
|
+
const binding = `${item.key}:${item.digest}:${item.candidateId}:${args.operation}`;
|
|
88
|
+
const question = approvals.prepare(context.sessionID, args.operation, binding, args.operation === "integrate" ? "最终验收" : args.operation === "abort" ? "中止确认" : "恢复确认", `确认对 ${item.key} 执行 ${args.operation}?候选 ${item.candidateId?.slice(0, 12) ?? "未封存"},目标 ${item.targetBranch};仅在本地处理,不推送。`, approval);
|
|
89
|
+
return JSON.stringify({ ...queue.details(args.key), operation: args.operation, question });
|
|
90
|
+
}
|
|
91
|
+
if (args.action === "start")
|
|
92
|
+
startService(queue);
|
|
93
|
+
else if (args.action === "stop")
|
|
94
|
+
stopService(queue);
|
|
95
|
+
else if (args.action === "recover-execution")
|
|
96
|
+
queue.recoverExecution();
|
|
97
|
+
else if (args.action === "priority")
|
|
98
|
+
queue.reorder(args.key ?? "", args.priority ?? NaN);
|
|
99
|
+
else if (args.action === "policy") {
|
|
100
|
+
invariant(args.workspaceStrategy && args.commitPolicy, "Specify both repository policies");
|
|
101
|
+
queue.setPolicy(args.workspaceStrategy, args.commitPolicy);
|
|
102
|
+
}
|
|
103
|
+
else if (["pause", "resume", "clear-fault", "cancel", "revoke", "acknowledge"].includes(args.action))
|
|
104
|
+
queue.control(args.action, args.key);
|
|
105
|
+
else {
|
|
106
|
+
const item = queue.item(args.key ?? "");
|
|
107
|
+
const needsApproval = ["integrate", "resume-task", "resume-review", "abort"].includes(args.action);
|
|
108
|
+
const proof = needsApproval ? approvals.consume(context, args.action, `${item.key}:${item.digest}:${item.candidateId}:${args.action}`) : undefined;
|
|
109
|
+
queue.request(args.key ?? "", (args.action === "resume-task" ? "resume" : args.action), args.approval, args.candidate, proof);
|
|
110
|
+
startService(queue);
|
|
111
|
+
}
|
|
112
|
+
wakeService(queue);
|
|
113
|
+
return JSON.stringify({ requested: args.action, key: args.key, pushed: false });
|
|
114
|
+
},
|
|
115
|
+
}),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** In unattended runs, executable shell syntax and indirect Git entry points
|
|
119
|
+
* cannot extend the installed agents' command allowlists. */
|
|
120
|
+
export function guardExecutorCommand(input, output, directory) {
|
|
121
|
+
if (!process.env.AUTOMATION_QUEUE_RUN_ID || input.tool !== "bash")
|
|
122
|
+
return;
|
|
123
|
+
const command = output.args?.command;
|
|
124
|
+
invariant(typeof command === "string", "Executor shell command is missing");
|
|
125
|
+
invariant(!/[\n\r;|&<>`\\]|\$\(/.test(command), "Shell chaining, substitution and redirection are forbidden in unattended execution");
|
|
126
|
+
const readOnlyGit = /^git (?:status(?: --short)?|diff(?: --(?:stat|name-only))?|rev-parse (?:HEAD|--show-toplevel)|ls-files|show HEAD(?: --stat)?)$/;
|
|
127
|
+
const scripts = /^\.\/scripts\/automation\/(?:status|select-task|claim-task|block-task|record-red|quality-gate|submit-review)\.sh [^\n]+$/;
|
|
128
|
+
const gradle = /^\.\/gradlew (?:(?::?[A-Za-z][A-Za-z0-9_.:-]*)(?: --tests [A-Za-z0-9_.#$*'"-]+)?)(?: (?::?[A-Za-z][A-Za-z0-9_.:-]*))*$/;
|
|
129
|
+
invariant(readOnlyGit.test(command) || scripts.test(command) || gradle.test(command), "Command is outside the unattended allowlist; direct or indirect remote push and Git mutation are forbidden");
|
|
130
|
+
if (gradle.test(command)) {
|
|
131
|
+
invariant(directory, "Gradle execution requires the recorded project configuration");
|
|
132
|
+
const config = new TaskQueue(directory).config();
|
|
133
|
+
const allowed = Object.values(config.gradleVerification).flat();
|
|
134
|
+
const arguments_ = command.slice("./gradlew ".length).split(" ");
|
|
135
|
+
for (let index = 0; index < arguments_.length; index += 1) {
|
|
136
|
+
if (arguments_[index] === "--tests") {
|
|
137
|
+
index += 1;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
invariant(allowed.includes(arguments_[index]), "Gradle task is outside the configured verification allowlist");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/queue/tools.ts"],"names":[],"mappings":"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"}
|