@tea-agent/loop-agent 0.1.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.
Files changed (264) hide show
  1. package/AGENTS.md +121 -0
  2. package/CHANGELOG.md +37 -0
  3. package/README.md +144 -0
  4. package/bin/loop-agent.js +21 -0
  5. package/dist/adapters/aimax.js +91 -0
  6. package/dist/adapters/context.js +32 -0
  7. package/dist/adapters/index.js +28 -0
  8. package/dist/adapters/loop-agent.js +98 -0
  9. package/dist/adapters/types.js +1 -0
  10. package/dist/cli/catalog.js +259 -0
  11. package/dist/cli/help.js +55 -0
  12. package/dist/cli/index.js +3 -0
  13. package/dist/cli/program.js +505 -0
  14. package/dist/cli.js +12 -0
  15. package/dist/commands/closeout.js +13 -0
  16. package/dist/commands/coverage-audit.js +14 -0
  17. package/dist/commands/cursor-prompt.js +222 -0
  18. package/dist/commands/cursor-worker.js +43 -0
  19. package/dist/commands/dag-approve.js +102 -0
  20. package/dist/commands/dag-final-verification.js +76 -0
  21. package/dist/commands/dag-init-hybrid.js +56 -0
  22. package/dist/commands/dag-reconcile-tasks.js +51 -0
  23. package/dist/commands/dag-reject.js +91 -0
  24. package/dist/commands/dag-report.js +177 -0
  25. package/dist/commands/dag-resume.js +34 -0
  26. package/dist/commands/dag-run-task.js +470 -0
  27. package/dist/commands/dag-validate.js +186 -0
  28. package/dist/commands/dag-workflow-compile.js +91 -0
  29. package/dist/commands/dag-workflow-plan.js +130 -0
  30. package/dist/commands/dag-workflow-validate.js +66 -0
  31. package/dist/commands/delegate.js +132 -0
  32. package/dist/commands/docs-archive.js +5 -0
  33. package/dist/commands/docs-audit.js +5 -0
  34. package/dist/commands/doctor.js +50 -0
  35. package/dist/commands/goal.js +92 -0
  36. package/dist/commands/handoff-check.js +5 -0
  37. package/dist/commands/harvest.js +44 -0
  38. package/dist/commands/inspect.js +11 -0
  39. package/dist/commands/instructions.js +195 -0
  40. package/dist/commands/knowledge.js +64 -0
  41. package/dist/commands/loop-benchmark.js +72 -0
  42. package/dist/commands/loop.js +241 -0
  43. package/dist/commands/new-task.js +5 -0
  44. package/dist/commands/pi-prompt.js +181 -0
  45. package/dist/commands/pi-reuse-benchmark.js +153 -0
  46. package/dist/commands/plan-list.js +5 -0
  47. package/dist/commands/promote-run.js +29 -0
  48. package/dist/commands/reference-index.js +16 -0
  49. package/dist/commands/run-dag.js +184 -0
  50. package/dist/commands/spine.js +38 -0
  51. package/dist/commands/stats.js +84 -0
  52. package/dist/commands/status.js +56 -0
  53. package/dist/commands/study-init.js +192 -0
  54. package/dist/commands/workflow.js +259 -0
  55. package/dist/commands/worktree-create.js +31 -0
  56. package/dist/commands/worktree-list.js +5 -0
  57. package/dist/commands/worktree-remove.js +26 -0
  58. package/dist/cursor-worker-entry.js +8 -0
  59. package/dist/executors/config-core.js +55 -0
  60. package/dist/executors/config.js +2 -0
  61. package/dist/executors/cursor-artifacts.js +33 -0
  62. package/dist/executors/cursor-execution-log.js +81 -0
  63. package/dist/executors/cursor-executor-artifacts.js +135 -0
  64. package/dist/executors/cursor-executor.js +468 -0
  65. package/dist/executors/cursor-run.js +115 -0
  66. package/dist/executors/cursor-tool.js +94 -0
  67. package/dist/executors/cursor-worker-client.js +213 -0
  68. package/dist/executors/cursor-worker-protocol.js +18 -0
  69. package/dist/executors/cursor-worker-server.js +54 -0
  70. package/dist/executors/cursor-worker.js +3 -0
  71. package/dist/executors/cursor.js +6 -0
  72. package/dist/executors/dag-cursor-executor.js +88 -0
  73. package/dist/executors/dag-pi-executor.js +322 -0
  74. package/dist/executors/dag-static-executor.js +45 -0
  75. package/dist/executors/dag.js +4 -0
  76. package/dist/executors/index.js +8 -0
  77. package/dist/executors/model-routing.js +60 -0
  78. package/dist/executors/pi-event-serializer.js +43 -0
  79. package/dist/executors/pi-executor.js +606 -0
  80. package/dist/executors/pi-reuse-benchmark.js +316 -0
  81. package/dist/executors/pi-runtime-reuse.js +29 -0
  82. package/dist/executors/pi-sdk-executor.js +255 -0
  83. package/dist/executors/pi-sdk.js +1 -0
  84. package/dist/executors/pi.js +3 -0
  85. package/dist/executors/shell-executor.js +300 -0
  86. package/dist/executors/shell-presets.js +47 -0
  87. package/dist/executors/shell-verification.js +251 -0
  88. package/dist/executors/shell-write-guard.js +126 -0
  89. package/dist/executors/shell.js +3 -0
  90. package/dist/executors/static.js +1 -0
  91. package/dist/governance/checks.js +434 -0
  92. package/dist/governance/harness.js +9 -0
  93. package/dist/governance/index.js +3 -0
  94. package/dist/governance/manifest-types.js +128 -0
  95. package/dist/governance/manifest.js +2 -0
  96. package/dist/governance/path-guard.js +69 -0
  97. package/dist/governance/path-guards.js +2 -0
  98. package/dist/governance/profiles.js +3 -0
  99. package/dist/governance/requirement-coverage.js +425 -0
  100. package/dist/governance/skill-safety.js +135 -0
  101. package/dist/governance/spine-audit.js +152 -0
  102. package/dist/records/closeout.js +2 -0
  103. package/dist/records/harvest.js +236 -0
  104. package/dist/records/index.js +3 -0
  105. package/dist/records/one-shot-runs.js +421 -0
  106. package/dist/records/promotion.js +199 -0
  107. package/dist/shared/artifacts-core.js +88 -0
  108. package/dist/shared/artifacts.js +2 -0
  109. package/dist/shared/context-files.js +32 -0
  110. package/dist/shared/context.js +2 -0
  111. package/dist/shared/copy-dir.js +17 -0
  112. package/dist/shared/git-progress.js +165 -0
  113. package/dist/shared/index.js +5 -0
  114. package/dist/shared/logger.js +23 -0
  115. package/dist/shared/one-shot-prompt-args.js +98 -0
  116. package/dist/shared/path-refs.js +31 -0
  117. package/dist/shared/prompts.js +26 -0
  118. package/dist/shared/reference-context.js +238 -0
  119. package/dist/shared/timeout-policy.js +19 -0
  120. package/dist/shared/timeout.js +1 -0
  121. package/dist/shared/types.js +5 -0
  122. package/dist/task/config-types.js +97 -0
  123. package/dist/task/config.js +2 -0
  124. package/dist/task/delegate.js +220 -0
  125. package/dist/task/goal-audit.js +51 -0
  126. package/dist/task/goal-policy.js +8 -0
  127. package/dist/task/goal.js +3 -0
  128. package/dist/task/ids.js +1 -0
  129. package/dist/task/index.js +9 -0
  130. package/dist/task/lifecycle.js +1 -0
  131. package/dist/task/paths.js +1 -0
  132. package/dist/task/read-model.js +149 -0
  133. package/dist/task/runtime.js +699 -0
  134. package/dist/task/source-state.js +1 -0
  135. package/dist/task/state.js +55 -0
  136. package/dist/task/subagent-guidance.js +1 -0
  137. package/dist/task/workflow-state-types.js +92 -0
  138. package/dist/task/worktree-cleanup.js +140 -0
  139. package/dist/task/worktree.js +171 -0
  140. package/dist/workflows/dag/authoring.js +8 -0
  141. package/dist/workflows/dag/authority-surface.js +138 -0
  142. package/dist/workflows/dag/canvas-observer.js +474 -0
  143. package/dist/workflows/dag/decision-envelope.js +502 -0
  144. package/dist/workflows/dag/decision-evidence.js +153 -0
  145. package/dist/workflows/dag/decision-gates.js +1 -0
  146. package/dist/workflows/dag/executor-registry.js +25 -0
  147. package/dist/workflows/dag/facts.js +4 -0
  148. package/dist/workflows/dag/failure-category.js +111 -0
  149. package/dist/workflows/dag/final-verification.js +180 -0
  150. package/dist/workflows/dag/governance-constants.js +5 -0
  151. package/dist/workflows/dag/governance-profile.js +405 -0
  152. package/dist/workflows/dag/index.js +6 -0
  153. package/dist/workflows/dag/init-hybrid.js +855 -0
  154. package/dist/workflows/dag/knowledge-curator.js +162 -0
  155. package/dist/workflows/dag/lifecycle.js +484 -0
  156. package/dist/workflows/dag/prompt-source.js +88 -0
  157. package/dist/workflows/dag/prompt.js +130 -0
  158. package/dist/workflows/dag/reconcile-tasks.js +404 -0
  159. package/dist/workflows/dag/recovery-recommendation.js +226 -0
  160. package/dist/workflows/dag/repair-artifact.js +136 -0
  161. package/dist/workflows/dag/report.js +1019 -0
  162. package/dist/workflows/dag/runner.js +1677 -0
  163. package/dist/workflows/dag/runtime.js +5 -0
  164. package/dist/workflows/dag/skill-instructions.js +471 -0
  165. package/dist/workflows/dag/skills.js +41 -0
  166. package/dist/workflows/dag/spec.js +3 -0
  167. package/dist/workflows/dag/topo.js +30 -0
  168. package/dist/workflows/dag/types.js +275 -0
  169. package/dist/workflows/dag/upstream-artifacts.js +95 -0
  170. package/dist/workflows/dag/validate.js +527 -0
  171. package/dist/workflows/dynamic/artifacts.js +65 -0
  172. package/dist/workflows/dynamic/compile.js +360 -0
  173. package/dist/workflows/dynamic/compileTypes.js +1 -0
  174. package/dist/workflows/dynamic/errors.js +5 -0
  175. package/dist/workflows/dynamic/index.js +7 -0
  176. package/dist/workflows/dynamic/profiles.js +156 -0
  177. package/dist/workflows/dynamic/spec.js +114 -0
  178. package/dist/workflows/dynamic/validate.js +275 -0
  179. package/dist/workflows/loop/actions.js +1334 -0
  180. package/dist/workflows/loop/benchmark.js +510 -0
  181. package/dist/workflows/loop/closeout.js +134 -0
  182. package/dist/workflows/loop/context.js +48 -0
  183. package/dist/workflows/loop/events.js +25 -0
  184. package/dist/workflows/loop/hash.js +32 -0
  185. package/dist/workflows/loop/index.js +8 -0
  186. package/dist/workflows/loop/paths.js +17 -0
  187. package/dist/workflows/loop/rounds.js +81 -0
  188. package/dist/workflows/loop/signals.js +55 -0
  189. package/dist/workflows/loop/state.js +116 -0
  190. package/dist/workflows/loop/templates.js +54 -0
  191. package/dist/workflows/loop/types.js +28 -0
  192. package/docs/README.md +62 -0
  193. package/docs/agent-dag-recovery-playbook.md +158 -0
  194. package/docs/agent-dag-runner.md +40 -0
  195. package/docs/cursor-executor-usage.md +25 -0
  196. package/docs/decisions/README.md +3 -0
  197. package/docs/design/README.md +36 -0
  198. package/docs/development-principles.md +71 -0
  199. package/docs/dynamic-workflow-dag-engine-roadmap.md +1749 -0
  200. package/docs/exec-plans/README.md +6 -0
  201. package/docs/exec-plans/active/README.md +5 -0
  202. package/docs/exec-plans/completed/README.md +5 -0
  203. package/docs/feature-workflow.md +184 -0
  204. package/docs/harness-methodology-debugging.md +153 -0
  205. package/docs/harness-methodology-tdd.md +130 -0
  206. package/docs/harness-methodology-verification.md +27 -0
  207. package/docs/loop-agent-harness.md +42 -0
  208. package/docs/progress/README.md +3 -0
  209. package/docs/reports/README.md +3 -0
  210. package/docs/templates/adr.md +60 -0
  211. package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -0
  212. package/docs/templates/agent-dag-decision-envelope.schema.json +213 -0
  213. package/docs/templates/agent-dag-decision-gate-dogfood-report.md +117 -0
  214. package/docs/templates/agent-dag-decision-gate.prompt.md +246 -0
  215. package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -0
  216. package/docs/templates/agent-dag-report.schema.json +423 -0
  217. package/docs/templates/agent-dag-review-verdict.prompt.md +68 -0
  218. package/docs/templates/agent-dag.base.json +195 -0
  219. package/docs/templates/agent-dag.final-verification.json +190 -0
  220. package/docs/templates/agent-dag.schema.json +316 -0
  221. package/docs/templates/agent-dag.supervised-implementation.json +500 -0
  222. package/docs/templates/exec-plan.md +64 -0
  223. package/docs/templates/feature-spec.md +53 -0
  224. package/docs/templates/hybrid-dag.json +193 -0
  225. package/docs/templates/progress-log.md +17 -0
  226. package/docs/templates/project-start-checklist.md +9 -0
  227. package/docs/templates/qa-report.md +42 -0
  228. package/docs/templates/sprint-contract.md +29 -0
  229. package/docs/verification-matrix.md +30 -0
  230. package/examples/decision-gate-agent-dag.json +123 -0
  231. package/examples/example-dag.json +51 -0
  232. package/examples/hybrid-loop-agent-dag.json +194 -0
  233. package/harness.json +92 -0
  234. package/package.json +61 -0
  235. package/skills/ai-engineering-context/SKILL.md +48 -0
  236. package/skills/loop-agent/SKILL.md +260 -0
  237. package/skills/loop-agent/references/README.md +63 -0
  238. package/skills/loop-agent/references/command-reference.md +315 -0
  239. package/skills/loop-agent/references/harness-policy.md +258 -0
  240. package/skills/loop-agent/references/hybrid-dag.md +216 -0
  241. package/skills/loop-agent/references/learned/README.md +21 -0
  242. package/skills/loop-agent/references/model-routing.md +36 -0
  243. package/skills/loop-agent/references/multi-worktree.md +54 -0
  244. package/skills/loop-agent/references/one-shot-runs.md +85 -0
  245. package/skills/loop-agent/references/orchestrator-and-interventions.md +169 -0
  246. package/skills/loop-agent/references/pi-prompt.md +23 -0
  247. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +83 -0
  248. package/skills/loop-agent/references/post-implementation-and-patterns.md +44 -0
  249. package/skills/loop-agent/references/task-workflow.md +84 -0
  250. package/skills/loop-agent/references/verification-and-failure-handling.md +74 -0
  251. package/skills/requesting-code-review/SKILL.md +101 -0
  252. package/skills/requesting-code-review/code-reviewer.md +168 -0
  253. package/skills/systematic-debugging/CREATION-LOG.md +119 -0
  254. package/skills/systematic-debugging/SKILL.md +296 -0
  255. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  256. package/skills/systematic-debugging/condition-based-waiting.md +115 -0
  257. package/skills/systematic-debugging/defense-in-depth.md +122 -0
  258. package/skills/systematic-debugging/find-polluter.sh +63 -0
  259. package/skills/systematic-debugging/root-cause-tracing.md +169 -0
  260. package/skills/systematic-debugging/test-academic.md +14 -0
  261. package/skills/systematic-debugging/test-pressure-1.md +58 -0
  262. package/skills/systematic-debugging/test-pressure-2.md +68 -0
  263. package/skills/systematic-debugging/test-pressure-3.md +69 -0
  264. package/skills/verification-before-completion/SKILL.md +154 -0
@@ -0,0 +1,213 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { createInterface } from 'node:readline';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { DEFAULT_CURSOR_TIMEOUT_MS, } from './cursor-executor.js';
6
+ const WORKER_MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
7
+ const WORKER_ENTRY = path.join(WORKER_MODULE_DIR, '../cursor-worker-entry.ts');
8
+ let workerProcess = null;
9
+ let workerBoot = null;
10
+ const pending = new Map();
11
+ let nextId = 1;
12
+ const DEFAULT_RPC_RESPONSE_GRACE_MS = 5_000;
13
+ const CURSOR_WORKER_STOP_SIGNAL = 'SIGTERM';
14
+ function getRpcResponseGraceMs() {
15
+ const raw = process.env.CURSOR_WORKER_RPC_GRACE_MS?.trim();
16
+ if (raw) {
17
+ const parsed = Number(raw);
18
+ if (Number.isFinite(parsed) && parsed >= 0)
19
+ return parsed;
20
+ }
21
+ return DEFAULT_RPC_RESPONSE_GRACE_MS;
22
+ }
23
+ export function isCursorWorkerEnabled() {
24
+ const raw = process.env.CURSOR_USE_WORKER?.trim().toLowerCase();
25
+ return raw === '1' || raw === 'true' || raw === 'yes';
26
+ }
27
+ /** True when this process should accept worker RPC (child), not delegate to a worker. */
28
+ export function isCursorWorkerChild() {
29
+ return process.env.CURSOR_WORKER_CHILD === '1';
30
+ }
31
+ export function shouldUseCursorWorker(options) {
32
+ if (options?.runHook)
33
+ return false;
34
+ if (isCursorWorkerChild())
35
+ return false;
36
+ if (options?.useWorker === true)
37
+ return true;
38
+ return isCursorWorkerEnabled();
39
+ }
40
+ function workerScriptArgs() {
41
+ return ['--import', 'tsx/esm', WORKER_ENTRY];
42
+ }
43
+ export function getCursorWorkerEntryPath() {
44
+ return WORKER_ENTRY;
45
+ }
46
+ function dispatchResponse(line) {
47
+ let parsed;
48
+ try {
49
+ parsed = JSON.parse(line);
50
+ }
51
+ catch {
52
+ return;
53
+ }
54
+ const waiter = pending.get(parsed.id);
55
+ if (!waiter)
56
+ return;
57
+ pending.delete(parsed.id);
58
+ waiter.resolve(parsed);
59
+ }
60
+ async function ensureWorkerProcess() {
61
+ if (workerProcess && !workerProcess.killed && workerProcess.exitCode === null) {
62
+ return workerProcess;
63
+ }
64
+ if (!workerBoot) {
65
+ workerBoot = new Promise((resolve, reject) => {
66
+ const child = spawn(process.execPath, workerScriptArgs(), {
67
+ cwd: process.cwd(),
68
+ env: { ...process.env, CURSOR_WORKER_CHILD: '1' },
69
+ stdio: ['pipe', 'pipe', 'pipe'],
70
+ });
71
+ workerProcess = child;
72
+ const rl = createInterface({ input: child.stdout });
73
+ rl.on('line', dispatchResponse);
74
+ child.stderr?.on('data', (chunk) => {
75
+ const text = chunk.toString('utf-8').trim();
76
+ if (text)
77
+ process.stderr.write(`[cursor-worker] ${text}\n`);
78
+ });
79
+ child.on('error', (err) => {
80
+ workerBoot = null;
81
+ reject(err);
82
+ });
83
+ child.on('exit', (code) => {
84
+ if (workerProcess !== child)
85
+ return;
86
+ workerProcess = null;
87
+ workerBoot = null;
88
+ for (const [, waiter] of pending) {
89
+ waiter.reject(new Error(`cursor worker exited with code ${code ?? 'unknown'}`));
90
+ }
91
+ pending.clear();
92
+ });
93
+ // ping to confirm ready
94
+ const pingId = '__boot__';
95
+ const bootWaiter = new Promise((res, rej) => {
96
+ const timeout = setTimeout(() => rej(new Error('cursor worker boot timeout')), 30_000);
97
+ pending.set(pingId, {
98
+ resolve: (response) => {
99
+ clearTimeout(timeout);
100
+ if (!response.ok) {
101
+ rej(new Error('cursor worker ping failed'));
102
+ return;
103
+ }
104
+ res();
105
+ },
106
+ reject: (err) => {
107
+ clearTimeout(timeout);
108
+ rej(err);
109
+ },
110
+ });
111
+ });
112
+ child.stdin.write(`${JSON.stringify({ id: pingId, type: 'ping' })}\n`);
113
+ bootWaiter.then(() => resolve()).catch(reject);
114
+ });
115
+ }
116
+ await workerBoot;
117
+ if (!workerProcess)
118
+ throw new Error('cursor worker failed to start');
119
+ return workerProcess;
120
+ }
121
+ export async function stopCursorWorker(signal = CURSOR_WORKER_STOP_SIGNAL) {
122
+ const pid = workerProcess?.pid;
123
+ const hadLiveWorker = Boolean(workerProcess && workerProcess.exitCode === null && !workerProcess.killed);
124
+ if (hadLiveWorker && workerProcess) {
125
+ try {
126
+ workerProcess.kill(signal);
127
+ }
128
+ catch {
129
+ /* ignore ESRCH / race with natural exit */
130
+ }
131
+ }
132
+ workerProcess = null;
133
+ workerBoot = null;
134
+ for (const [, waiter] of pending) {
135
+ waiter.reject(new Error('cursor worker stopped'));
136
+ }
137
+ pending.clear();
138
+ return {
139
+ workerPid: pid,
140
+ workerTerminationAttempted: hadLiveWorker,
141
+ workerStopSignal: hadLiveWorker ? signal : undefined,
142
+ };
143
+ }
144
+ /** Test-only: reset module singletons between cases. */
145
+ export async function resetCursorWorkerStateForTests() {
146
+ await stopCursorWorker();
147
+ nextId = 1;
148
+ }
149
+ export function isCursorWorkerRunning() {
150
+ return Boolean(workerProcess && workerProcess.exitCode === null && !workerProcess.killed);
151
+ }
152
+ export async function executeCursorTaskViaWorker(options) {
153
+ const child = await ensureWorkerProcess();
154
+ const id = `req-${nextId++}`;
155
+ const request = {
156
+ id,
157
+ type: 'execute',
158
+ task: options.task,
159
+ cwd: options.cwd,
160
+ model: options.model,
161
+ timeoutMs: options.timeoutMs,
162
+ runDir: options.runDir,
163
+ artifactDir: options.artifactDir,
164
+ };
165
+ const taskTimeoutMs = options.timeoutMs ?? DEFAULT_CURSOR_TIMEOUT_MS;
166
+ const rpcGraceMs = getRpcResponseGraceMs();
167
+ const responsePromise = new Promise((resolve, reject) => {
168
+ const timer = setTimeout(() => {
169
+ pending.delete(id);
170
+ void stopCursorWorker().then((stopResult) => {
171
+ resolve({
172
+ id,
173
+ ok: true,
174
+ result: {
175
+ ok: false,
176
+ status: 'timeout',
177
+ failureCategory: 'timeout',
178
+ model: options.model ?? 'default',
179
+ durationMs: taskTimeoutMs,
180
+ stdout: '',
181
+ stderr: `cursor worker request timeout after ${taskTimeoutMs}ms`,
182
+ details: {
183
+ timedOut: true,
184
+ timeoutKind: 'rpc',
185
+ cancelDeferred: true,
186
+ cancelAttempted: false,
187
+ workerPid: stopResult.workerPid,
188
+ workerTerminationAttempted: stopResult.workerTerminationAttempted,
189
+ workerStopSignal: stopResult.workerStopSignal,
190
+ workerRestartDeferred: true,
191
+ },
192
+ },
193
+ });
194
+ });
195
+ }, taskTimeoutMs + rpcGraceMs);
196
+ pending.set(id, {
197
+ resolve: (value) => {
198
+ clearTimeout(timer);
199
+ resolve(value);
200
+ },
201
+ reject: (err) => {
202
+ clearTimeout(timer);
203
+ reject(err);
204
+ },
205
+ });
206
+ });
207
+ child.stdin.write(`${JSON.stringify(request)}\n`);
208
+ const response = await responsePromise;
209
+ if (!response.ok) {
210
+ throw new Error(response.error);
211
+ }
212
+ return response.result;
213
+ }
@@ -0,0 +1,18 @@
1
+ export function parseWorkerRequestLine(line) {
2
+ const parsed = JSON.parse(line);
3
+ if (!parsed || typeof parsed !== 'object' || !('id' in parsed) || !('type' in parsed)) {
4
+ throw new Error('invalid worker request');
5
+ }
6
+ if (parsed.type === 'ping')
7
+ return parsed;
8
+ if (parsed.type === 'execute') {
9
+ if (typeof parsed.task !== 'string' || typeof parsed.cwd !== 'string') {
10
+ throw new Error('execute request requires task and cwd');
11
+ }
12
+ return parsed;
13
+ }
14
+ throw new Error(`unknown worker request type: ${parsed.type}`);
15
+ }
16
+ export function serializeWorkerResponse(response) {
17
+ return `${JSON.stringify(response)}\n`;
18
+ }
@@ -0,0 +1,54 @@
1
+ import { createInterface } from 'node:readline';
2
+ import { executeCursorTask } from './cursor-executor.js';
3
+ import { parseWorkerRequestLine, serializeWorkerResponse, } from './cursor-worker-protocol.js';
4
+ export async function handleCursorWorkerRequest(request) {
5
+ if (request.type === 'ping') {
6
+ return {
7
+ id: request.id,
8
+ ok: true,
9
+ result: {
10
+ ok: true,
11
+ status: 'completed',
12
+ failureCategory: 'success',
13
+ model: 'worker',
14
+ durationMs: 0,
15
+ stdout: 'pong',
16
+ stderr: '',
17
+ details: { worker: true },
18
+ },
19
+ };
20
+ }
21
+ try {
22
+ const result = await executeCursorTask({
23
+ task: request.task,
24
+ cwd: request.cwd,
25
+ model: request.model,
26
+ timeoutMs: request.timeoutMs,
27
+ runDir: request.runDir,
28
+ artifactDir: request.artifactDir,
29
+ });
30
+ return { id: request.id, ok: true, result };
31
+ }
32
+ catch (error) {
33
+ const message = error instanceof Error ? error.message : String(error);
34
+ return { id: request.id, ok: false, error: message };
35
+ }
36
+ }
37
+ export async function runCursorWorkerOnStreams(input, output) {
38
+ const rl = createInterface({ input, crlfDelay: Infinity });
39
+ for await (const line of rl) {
40
+ const trimmed = line.trim();
41
+ if (!trimmed)
42
+ continue;
43
+ let response;
44
+ try {
45
+ const request = parseWorkerRequestLine(trimmed);
46
+ response = await handleCursorWorkerRequest(request);
47
+ }
48
+ catch (error) {
49
+ const message = error instanceof Error ? error.message : String(error);
50
+ response = { id: 'unknown', ok: false, error: message };
51
+ }
52
+ output.write(serializeWorkerResponse(response));
53
+ }
54
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./cursor-worker-client.js";
2
+ export * from "./cursor-worker-protocol.js";
3
+ export * from "./cursor-worker-server.js";
@@ -0,0 +1,6 @@
1
+ export * from "./cursor-artifacts.js";
2
+ export * from "./cursor-execution-log.js";
3
+ export * from "./cursor-executor-artifacts.js";
4
+ export * from "./cursor-executor.js";
5
+ export * from "./cursor-run.js";
6
+ export * from "./cursor-tool.js";
@@ -0,0 +1,88 @@
1
+ import { mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { executeCursorTask } from "./cursor-executor.js";
4
+ import { writeCursorExecutorArtifacts } from "./cursor-executor-artifacts.js";
5
+ import { buildCursorExecutionLogRecord, persistCursorExecutionLog, } from "./cursor-execution-log.js";
6
+ import { readGitStatusPorcelain, runPostRunWriteGuard, } from "./shell-write-guard.js";
7
+ export async function executeDagCursorNode(input, meta) {
8
+ const started = Date.now();
9
+ let beforeStatus;
10
+ try {
11
+ beforeStatus = await readGitStatusPorcelain(input.cwd);
12
+ }
13
+ catch {
14
+ // Non-git cwd: skip write guard (documented limitation).
15
+ beforeStatus = undefined;
16
+ }
17
+ const artifactDir = path.join(meta.runDir, "artifacts", input.task.id);
18
+ await mkdir(artifactDir, { recursive: true });
19
+ const result = await executeCursorTask({
20
+ task: input.prompt,
21
+ cwd: input.cwd,
22
+ model: input.model,
23
+ useWorker: true,
24
+ artifactDir,
25
+ });
26
+ const executionContext = {
27
+ channel: "dag",
28
+ cwd: input.cwd,
29
+ dagRunId: meta.runId,
30
+ dagNodeId: input.task.id,
31
+ };
32
+ await persistCursorExecutionLog(meta.runDir, buildCursorExecutionLogRecord({
33
+ context: executionContext,
34
+ model: input.model,
35
+ prompt: input.prompt,
36
+ result,
37
+ }));
38
+ await writeCursorExecutorArtifacts(path.join(meta.runDir, input.task.id), {
39
+ prompt: input.prompt,
40
+ model: input.model,
41
+ context: executionContext,
42
+ result,
43
+ });
44
+ let writeGuardOk = true;
45
+ let writeGuardViolations = [];
46
+ if (beforeStatus !== undefined) {
47
+ try {
48
+ const guard = await runPostRunWriteGuard({
49
+ rootCwd: input.cwd,
50
+ beforeStatus,
51
+ writePolicy: input.task.writePolicy,
52
+ writeSet: input.task.writeSet,
53
+ allowedPaths: input.task.allowedPaths,
54
+ forbiddenPaths: input.task.forbiddenPaths,
55
+ concurrentSiblingWriteSets: meta.concurrentSiblingWriteSets,
56
+ });
57
+ writeGuardOk = guard.ok;
58
+ writeGuardViolations = guard.violations;
59
+ }
60
+ catch {
61
+ writeGuardOk = false;
62
+ writeGuardViolations = ["write guard failed: git status unavailable"];
63
+ }
64
+ }
65
+ const ok = result.ok && writeGuardOk;
66
+ const stderrParts = [result.stderr];
67
+ if (!writeGuardOk) {
68
+ stderrParts.push(`write guard failed: ${writeGuardViolations.join(", ")}`);
69
+ if (meta.writeGuardAttribution === "best-effort") {
70
+ stderrParts.push("write guard note: concurrent rank writers use best-effort per-node attribution; keep same-rank writeSet entries disjoint");
71
+ }
72
+ }
73
+ const executionResult = {
74
+ ok,
75
+ stdout: result.stdout,
76
+ stderr: stderrParts.filter(Boolean).join("\n\n"),
77
+ failureCategory: !result.ok
78
+ ? result.failureCategory
79
+ : !writeGuardOk
80
+ ? "write-guard"
81
+ : result.failureCategory,
82
+ durationMs: result.durationMs ?? Date.now() - started,
83
+ };
84
+ if (result.tokensUsed !== undefined) {
85
+ executionResult.tokensUsed = result.tokensUsed;
86
+ }
87
+ return executionResult;
88
+ }