slavedriver 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 (240) hide show
  1. package/README.md +165 -0
  2. package/agents/executor.md +26 -0
  3. package/agents/planner.md +41 -0
  4. package/agents/researcher.md +28 -0
  5. package/agents/verifier.md +25 -0
  6. package/dist/agents/backends/claude-code.d.ts +2 -0
  7. package/dist/agents/backends/claude-code.js +215 -0
  8. package/dist/agents/backends/claude-code.js.map +1 -0
  9. package/dist/agents/backends/mock.d.ts +9 -0
  10. package/dist/agents/backends/mock.js +31 -0
  11. package/dist/agents/backends/mock.js.map +1 -0
  12. package/dist/agents/context-builder.d.ts +10 -0
  13. package/dist/agents/context-builder.js +61 -0
  14. package/dist/agents/context-builder.js.map +1 -0
  15. package/dist/agents/prompt-compiler.d.ts +27 -0
  16. package/dist/agents/prompt-compiler.js +549 -0
  17. package/dist/agents/prompt-compiler.js.map +1 -0
  18. package/dist/agents/runtime.d.ts +40 -0
  19. package/dist/agents/runtime.js +2 -0
  20. package/dist/agents/runtime.js.map +1 -0
  21. package/dist/cli/arg-parser.d.ts +6 -0
  22. package/dist/cli/arg-parser.js +59 -0
  23. package/dist/cli/arg-parser.js.map +1 -0
  24. package/dist/cli/commands/config.d.ts +9 -0
  25. package/dist/cli/commands/config.js +120 -0
  26. package/dist/cli/commands/config.js.map +1 -0
  27. package/dist/cli/commands/dashboard.d.ts +1 -0
  28. package/dist/cli/commands/dashboard.js +54 -0
  29. package/dist/cli/commands/dashboard.js.map +1 -0
  30. package/dist/cli/commands/find-root.d.ts +14 -0
  31. package/dist/cli/commands/find-root.js +55 -0
  32. package/dist/cli/commands/find-root.js.map +1 -0
  33. package/dist/cli/commands/init.d.ts +1 -0
  34. package/dist/cli/commands/init.js +65 -0
  35. package/dist/cli/commands/init.js.map +1 -0
  36. package/dist/cli/commands/next.d.ts +1 -0
  37. package/dist/cli/commands/next.js +61 -0
  38. package/dist/cli/commands/next.js.map +1 -0
  39. package/dist/cli/commands/plan.d.ts +2 -0
  40. package/dist/cli/commands/plan.js +53 -0
  41. package/dist/cli/commands/plan.js.map +1 -0
  42. package/dist/cli/commands/replan.d.ts +1 -0
  43. package/dist/cli/commands/replan.js +54 -0
  44. package/dist/cli/commands/replan.js.map +1 -0
  45. package/dist/cli/commands/run-pipeline.d.ts +2 -0
  46. package/dist/cli/commands/run-pipeline.js +74 -0
  47. package/dist/cli/commands/run-pipeline.js.map +1 -0
  48. package/dist/cli/commands/run.d.ts +2 -0
  49. package/dist/cli/commands/run.js +106 -0
  50. package/dist/cli/commands/run.js.map +1 -0
  51. package/dist/cli/commands/status.d.ts +1 -0
  52. package/dist/cli/commands/status.js +51 -0
  53. package/dist/cli/commands/status.js.map +1 -0
  54. package/dist/cli/commands/verify.d.ts +1 -0
  55. package/dist/cli/commands/verify.js +63 -0
  56. package/dist/cli/commands/verify.js.map +1 -0
  57. package/dist/cli/commands/wizard.d.ts +8 -0
  58. package/dist/cli/commands/wizard.js +39 -0
  59. package/dist/cli/commands/wizard.js.map +1 -0
  60. package/dist/cli/index.d.ts +2 -0
  61. package/dist/cli/index.js +82 -0
  62. package/dist/cli/index.js.map +1 -0
  63. package/dist/cli/wizard/index.d.ts +11 -0
  64. package/dist/cli/wizard/index.js +40 -0
  65. package/dist/cli/wizard/index.js.map +1 -0
  66. package/dist/cli/wizard/interview.d.ts +26 -0
  67. package/dist/cli/wizard/interview.js +284 -0
  68. package/dist/cli/wizard/interview.js.map +1 -0
  69. package/dist/cli/wizard/prompt.d.ts +18 -0
  70. package/dist/cli/wizard/prompt.js +72 -0
  71. package/dist/cli/wizard/prompt.js.map +1 -0
  72. package/dist/cli/wizard/template-generator.d.ts +8 -0
  73. package/dist/cli/wizard/template-generator.js +133 -0
  74. package/dist/cli/wizard/template-generator.js.map +1 -0
  75. package/dist/mcp/index.d.ts +2 -0
  76. package/dist/mcp/index.js +68 -0
  77. package/dist/mcp/index.js.map +1 -0
  78. package/dist/mcp/protocol.d.ts +33 -0
  79. package/dist/mcp/protocol.js +82 -0
  80. package/dist/mcp/protocol.js.map +1 -0
  81. package/dist/mcp/resources.d.ts +20 -0
  82. package/dist/mcp/resources.js +101 -0
  83. package/dist/mcp/resources.js.map +1 -0
  84. package/dist/mcp/run-manager.d.ts +36 -0
  85. package/dist/mcp/run-manager.js +179 -0
  86. package/dist/mcp/run-manager.js.map +1 -0
  87. package/dist/mcp/server.d.ts +13 -0
  88. package/dist/mcp/server.js +99 -0
  89. package/dist/mcp/server.js.map +1 -0
  90. package/dist/mcp/tools.d.ts +32 -0
  91. package/dist/mcp/tools.js +259 -0
  92. package/dist/mcp/tools.js.map +1 -0
  93. package/dist/orchestrator/alert-types.d.ts +16 -0
  94. package/dist/orchestrator/alert-types.js +2 -0
  95. package/dist/orchestrator/alert-types.js.map +1 -0
  96. package/dist/orchestrator/alerts.d.ts +20 -0
  97. package/dist/orchestrator/alerts.js +76 -0
  98. package/dist/orchestrator/alerts.js.map +1 -0
  99. package/dist/orchestrator/checkpoints.d.ts +8 -0
  100. package/dist/orchestrator/checkpoints.js +24 -0
  101. package/dist/orchestrator/checkpoints.js.map +1 -0
  102. package/dist/orchestrator/engine.d.ts +71 -0
  103. package/dist/orchestrator/engine.js +420 -0
  104. package/dist/orchestrator/engine.js.map +1 -0
  105. package/dist/orchestrator/phase-gates.d.ts +6 -0
  106. package/dist/orchestrator/phase-gates.js +127 -0
  107. package/dist/orchestrator/phase-gates.js.map +1 -0
  108. package/dist/orchestrator/plan-approval.d.ts +10 -0
  109. package/dist/orchestrator/plan-approval.js +51 -0
  110. package/dist/orchestrator/plan-approval.js.map +1 -0
  111. package/dist/orchestrator/safety.d.ts +22 -0
  112. package/dist/orchestrator/safety.js +126 -0
  113. package/dist/orchestrator/safety.js.map +1 -0
  114. package/dist/orchestrator/task-graph.d.ts +17 -0
  115. package/dist/orchestrator/task-graph.js +156 -0
  116. package/dist/orchestrator/task-graph.js.map +1 -0
  117. package/dist/orchestrator/wave-executor.d.ts +37 -0
  118. package/dist/orchestrator/wave-executor.js +237 -0
  119. package/dist/orchestrator/wave-executor.js.map +1 -0
  120. package/dist/session/in-process.d.ts +2 -0
  121. package/dist/session/in-process.js +149 -0
  122. package/dist/session/in-process.js.map +1 -0
  123. package/dist/session/log-capture.d.ts +7 -0
  124. package/dist/session/log-capture.js +56 -0
  125. package/dist/session/log-capture.js.map +1 -0
  126. package/dist/session/manager.d.ts +20 -0
  127. package/dist/session/manager.js +2 -0
  128. package/dist/session/manager.js.map +1 -0
  129. package/dist/state/file-store.d.ts +3 -0
  130. package/dist/state/file-store.js +124 -0
  131. package/dist/state/file-store.js.map +1 -0
  132. package/dist/state/lock.d.ts +6 -0
  133. package/dist/state/lock.js +71 -0
  134. package/dist/state/lock.js.map +1 -0
  135. package/dist/state/plan-parser.d.ts +6 -0
  136. package/dist/state/plan-parser.js +54 -0
  137. package/dist/state/plan-parser.js.map +1 -0
  138. package/dist/state/store.d.ts +27 -0
  139. package/dist/state/store.js +2 -0
  140. package/dist/state/store.js.map +1 -0
  141. package/dist/steps/events.d.ts +49 -0
  142. package/dist/steps/events.js +2 -0
  143. package/dist/steps/events.js.map +1 -0
  144. package/dist/steps/pipeline.d.ts +14 -0
  145. package/dist/steps/pipeline.js +284 -0
  146. package/dist/steps/pipeline.js.map +1 -0
  147. package/dist/steps/plan-parser.d.ts +35 -0
  148. package/dist/steps/plan-parser.js +147 -0
  149. package/dist/steps/plan-parser.js.map +1 -0
  150. package/dist/steps/runner.d.ts +13 -0
  151. package/dist/steps/runner.js +155 -0
  152. package/dist/steps/runner.js.map +1 -0
  153. package/dist/steps/store.d.ts +26 -0
  154. package/dist/steps/store.js +164 -0
  155. package/dist/steps/store.js.map +1 -0
  156. package/dist/steps/types.d.ts +36 -0
  157. package/dist/steps/types.js +2 -0
  158. package/dist/steps/types.js.map +1 -0
  159. package/dist/tui/app.d.ts +15 -0
  160. package/dist/tui/app.js +297 -0
  161. package/dist/tui/app.js.map +1 -0
  162. package/dist/tui/banner.d.ts +1 -0
  163. package/dist/tui/banner.js +11 -0
  164. package/dist/tui/banner.js.map +1 -0
  165. package/dist/tui/colors.d.ts +22 -0
  166. package/dist/tui/colors.js +30 -0
  167. package/dist/tui/colors.js.map +1 -0
  168. package/dist/tui/components/agent-panel.d.ts +8 -0
  169. package/dist/tui/components/agent-panel.js +80 -0
  170. package/dist/tui/components/agent-panel.js.map +1 -0
  171. package/dist/tui/components/header.d.ts +15 -0
  172. package/dist/tui/components/header.js +69 -0
  173. package/dist/tui/components/header.js.map +1 -0
  174. package/dist/tui/components/status-bar.d.ts +2 -0
  175. package/dist/tui/components/status-bar.js +8 -0
  176. package/dist/tui/components/status-bar.js.map +1 -0
  177. package/dist/tui/components/task-board.d.ts +3 -0
  178. package/dist/tui/components/task-board.js +96 -0
  179. package/dist/tui/components/task-board.js.map +1 -0
  180. package/dist/tui/display.d.ts +23 -0
  181. package/dist/tui/display.js +125 -0
  182. package/dist/tui/display.js.map +1 -0
  183. package/dist/tui/input.d.ts +2 -0
  184. package/dist/tui/input.js +44 -0
  185. package/dist/tui/input.js.map +1 -0
  186. package/dist/tui/layout-master.d.ts +7 -0
  187. package/dist/tui/layout-master.js +31 -0
  188. package/dist/tui/layout-master.js.map +1 -0
  189. package/dist/tui/layout.d.ts +13 -0
  190. package/dist/tui/layout.js +37 -0
  191. package/dist/tui/layout.js.map +1 -0
  192. package/dist/tui/pane-formatter.d.ts +27 -0
  193. package/dist/tui/pane-formatter.js +153 -0
  194. package/dist/tui/pane-formatter.js.map +1 -0
  195. package/dist/tui/renderer.d.ts +8 -0
  196. package/dist/tui/renderer.js +30 -0
  197. package/dist/tui/renderer.js.map +1 -0
  198. package/dist/tui/screen.d.ts +12 -0
  199. package/dist/tui/screen.js +32 -0
  200. package/dist/tui/screen.js.map +1 -0
  201. package/dist/tui/structured-display.d.ts +5 -0
  202. package/dist/tui/structured-display.js +74 -0
  203. package/dist/tui/structured-display.js.map +1 -0
  204. package/dist/tui/tmux-display.d.ts +6 -0
  205. package/dist/tui/tmux-display.js +187 -0
  206. package/dist/tui/tmux-display.js.map +1 -0
  207. package/dist/tui/tmux.d.ts +26 -0
  208. package/dist/tui/tmux.js +265 -0
  209. package/dist/tui/tmux.js.map +1 -0
  210. package/dist/types.d.ts +15 -0
  211. package/dist/types.js +2 -0
  212. package/dist/types.js.map +1 -0
  213. package/dist/utils/git.d.ts +6 -0
  214. package/dist/utils/git.js +35 -0
  215. package/dist/utils/git.js.map +1 -0
  216. package/dist/utils/hello.d.ts +1 -0
  217. package/dist/utils/hello.js +4 -0
  218. package/dist/utils/hello.js.map +1 -0
  219. package/dist/utils/id.d.ts +1 -0
  220. package/dist/utils/id.js +5 -0
  221. package/dist/utils/id.js.map +1 -0
  222. package/dist/utils/jsonl.d.ts +2 -0
  223. package/dist/utils/jsonl.js +18 -0
  224. package/dist/utils/jsonl.js.map +1 -0
  225. package/dist/utils/logger.d.ts +20 -0
  226. package/dist/utils/logger.js +40 -0
  227. package/dist/utils/logger.js.map +1 -0
  228. package/dist/utils/pricing.d.ts +3 -0
  229. package/dist/utils/pricing.js +26 -0
  230. package/dist/utils/pricing.js.map +1 -0
  231. package/dist/utils/xml.d.ts +13 -0
  232. package/dist/utils/xml.js +67 -0
  233. package/dist/utils/xml.js.map +1 -0
  234. package/dist/utils/yaml.d.ts +5 -0
  235. package/dist/utils/yaml.js +126 -0
  236. package/dist/utils/yaml.js.map +1 -0
  237. package/package.json +45 -0
  238. package/templates/CONSTITUTION.md +10 -0
  239. package/templates/STATE.md +3 -0
  240. package/templates/config.json +11 -0
@@ -0,0 +1,51 @@
1
+ import { createInterface } from 'node:readline';
2
+ export async function requestCliApproval(plan) {
3
+ console.log('\n' + '='.repeat(60));
4
+ console.log('PLAN APPROVAL REQUIRED');
5
+ console.log('='.repeat(60));
6
+ console.log(plan);
7
+ console.log('='.repeat(60));
8
+ const answer = await askQuestion('Approve this plan? [y/N] ');
9
+ const approved = answer.trim().toLowerCase() === 'y';
10
+ return {
11
+ approved,
12
+ reason: approved ? undefined : 'Plan rejected by user',
13
+ };
14
+ }
15
+ function askQuestion(prompt) {
16
+ const rl = createInterface({
17
+ input: process.stdin,
18
+ output: process.stdout,
19
+ });
20
+ return new Promise((resolve) => {
21
+ rl.question(prompt, (answer) => {
22
+ rl.close();
23
+ resolve(answer);
24
+ });
25
+ });
26
+ }
27
+ export function createApprovalCallback(mode) {
28
+ if (mode === 'cli') {
29
+ return async (plan) => {
30
+ const result = await requestCliApproval(plan);
31
+ return result.approved;
32
+ };
33
+ }
34
+ // TUI mode: approval is handled by the TUI overlay
35
+ // The engine emits 'approval_required' event and waits for callback resolution
36
+ let resolveApproval = null;
37
+ const callback = async (_plan) => {
38
+ return new Promise((resolve) => {
39
+ resolveApproval = resolve;
40
+ });
41
+ };
42
+ // Attach resolver so TUI can call it
43
+ callback.resolve = (approved) => {
44
+ if (resolveApproval) {
45
+ resolveApproval(approved);
46
+ resolveApproval = null;
47
+ }
48
+ };
49
+ return callback;
50
+ }
51
+ //# sourceMappingURL=plan-approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-approval.js","sourceRoot":"","sources":["../../src/orchestrator/plan-approval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAOhD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAY;IACnD,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAE5B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,2BAA2B,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC;IAErD,OAAO;QACL,QAAQ;QACR,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,uBAAuB;KACvD,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,EAAE,GAAG,eAAe,CAAC;QACzB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;YAC7B,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAmB;IACxD,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,OAAO,KAAK,EAAE,IAAY,EAAE,EAAE;YAC5B,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC9C,OAAO,MAAM,CAAC,QAAQ,CAAC;QACzB,CAAC,CAAC;IACJ,CAAC;IAED,mDAAmD;IACnD,+EAA+E;IAC/E,IAAI,eAAe,GAAyC,IAAI,CAAC;IAEjE,MAAM,QAAQ,GAAG,KAAK,EAAE,KAAa,EAAoB,EAAE;QACzD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,eAAe,GAAG,OAAO,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,qCAAqC;IACpC,QAAyC,CAAC,OAAO,GAAG,CAAC,QAAiB,EAAE,EAAE;QACzE,IAAI,eAAe,EAAE,CAAC;YACpB,eAAe,CAAC,QAAQ,CAAC,CAAC;YAC1B,eAAe,GAAG,IAAI,CAAC;QACzB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { ProjectConfig } from '../types.js';
2
+ export interface SafetyCheck {
3
+ readonly passed: boolean;
4
+ readonly code: string;
5
+ readonly message: string;
6
+ }
7
+ export interface SafetyState {
8
+ totalInputTokens: number;
9
+ totalOutputTokens: number;
10
+ totalIterations: number;
11
+ totalAgentInvocations: number;
12
+ activeAgents: number;
13
+ startTimeMs: number;
14
+ }
15
+ export declare function checkIterations(state: SafetyState, config: ProjectConfig): SafetyCheck;
16
+ export declare function checkConcurrency(state: SafetyState, config: ProjectConfig): SafetyCheck;
17
+ export declare function checkPath(filePath: string, config: ProjectConfig): SafetyCheck;
18
+ export declare function checkCommand(command: string, config: ProjectConfig): SafetyCheck;
19
+ export declare function checkTokens(state: SafetyState, config: ProjectConfig): SafetyCheck;
20
+ export declare function checkWallTime(state: SafetyState, config: ProjectConfig): SafetyCheck;
21
+ export declare function checkInvocations(state: SafetyState, config: ProjectConfig): SafetyCheck;
22
+ export declare function checkAll(state: SafetyState, config: ProjectConfig): SafetyCheck[];
@@ -0,0 +1,126 @@
1
+ export function checkIterations(state, config) {
2
+ const passed = state.totalIterations < config.maxIterations;
3
+ return {
4
+ passed,
5
+ code: 'ITERATIONS_EXCEEDED',
6
+ message: passed
7
+ ? 'Iterations within limits'
8
+ : `Iterations exceeded: ${state.totalIterations} >= ${config.maxIterations}`,
9
+ };
10
+ }
11
+ export function checkConcurrency(state, config) {
12
+ const passed = state.activeAgents < config.maxConcurrentAgents;
13
+ return {
14
+ passed,
15
+ code: 'CONCURRENCY_EXCEEDED',
16
+ message: passed
17
+ ? 'Concurrency within limits'
18
+ : `Concurrency exceeded: ${state.activeAgents} >= ${config.maxConcurrentAgents}`,
19
+ };
20
+ }
21
+ function matchesGlob(filePath, pattern) {
22
+ // Handle directory patterns like "credentials/"
23
+ if (pattern.endsWith('/')) {
24
+ const dir = pattern.slice(0, -1);
25
+ return filePath === dir || filePath.startsWith(dir + '/');
26
+ }
27
+ // Handle glob patterns like "*.key"
28
+ if (pattern.includes('*')) {
29
+ const regex = new RegExp('^' +
30
+ pattern
31
+ .split('*')
32
+ .map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
33
+ .join('.*') +
34
+ '$');
35
+ // Match against the full path and the basename
36
+ const basename = filePath.split('/').pop() ?? filePath;
37
+ return regex.test(filePath) || regex.test(basename);
38
+ }
39
+ // Exact match or basename match
40
+ const basename = filePath.split('/').pop() ?? filePath;
41
+ return filePath === pattern || basename === pattern;
42
+ }
43
+ export function checkPath(filePath, config) {
44
+ for (const pattern of config.excludedPaths) {
45
+ if (matchesGlob(filePath, pattern)) {
46
+ return {
47
+ passed: false,
48
+ code: 'PATH_EXCLUDED',
49
+ message: `Path excluded: '${filePath}' matches pattern '${pattern}'`,
50
+ };
51
+ }
52
+ }
53
+ return {
54
+ passed: true,
55
+ code: 'PATH_EXCLUDED',
56
+ message: 'Path is allowed',
57
+ };
58
+ }
59
+ export function checkCommand(command, config) {
60
+ for (const excluded of config.excludedCommands) {
61
+ if (command.includes(excluded)) {
62
+ return {
63
+ passed: false,
64
+ code: 'COMMAND_EXCLUDED',
65
+ message: `Command excluded: '${command}' contains '${excluded}'`,
66
+ };
67
+ }
68
+ }
69
+ return {
70
+ passed: true,
71
+ code: 'COMMAND_EXCLUDED',
72
+ message: 'Command is allowed',
73
+ };
74
+ }
75
+ export function checkTokens(state, config) {
76
+ if (config.maxTotalTokens === undefined) {
77
+ return { passed: true, code: 'TOKENS_EXCEEDED', message: 'Token limit not configured' };
78
+ }
79
+ const total = state.totalInputTokens + state.totalOutputTokens;
80
+ const passed = total < config.maxTotalTokens;
81
+ return {
82
+ passed,
83
+ code: 'TOKENS_EXCEEDED',
84
+ message: passed
85
+ ? 'Tokens within limits'
86
+ : `Tokens exceeded: ${total} >= ${config.maxTotalTokens}`,
87
+ };
88
+ }
89
+ export function checkWallTime(state, config) {
90
+ if (config.maxWallTimeSeconds === undefined) {
91
+ return { passed: true, code: 'WALL_TIME_EXCEEDED', message: 'Wall time limit not configured' };
92
+ }
93
+ const elapsedSeconds = (Date.now() - state.startTimeMs) / 1000;
94
+ const passed = elapsedSeconds < config.maxWallTimeSeconds;
95
+ return {
96
+ passed,
97
+ code: 'WALL_TIME_EXCEEDED',
98
+ message: passed
99
+ ? 'Wall time within limits'
100
+ : `Wall time exceeded: ${elapsedSeconds.toFixed(0)}s >= ${config.maxWallTimeSeconds}s`,
101
+ };
102
+ }
103
+ export function checkInvocations(state, config) {
104
+ if (config.maxAgentInvocations === undefined) {
105
+ return { passed: true, code: 'INVOCATIONS_EXCEEDED', message: 'Invocation limit not configured' };
106
+ }
107
+ const passed = state.totalAgentInvocations < config.maxAgentInvocations;
108
+ return {
109
+ passed,
110
+ code: 'INVOCATIONS_EXCEEDED',
111
+ message: passed
112
+ ? 'Invocations within limits'
113
+ : `Invocations exceeded: ${state.totalAgentInvocations} >= ${config.maxAgentInvocations}`,
114
+ };
115
+ }
116
+ export function checkAll(state, config) {
117
+ const checks = [
118
+ checkTokens(state, config),
119
+ checkIterations(state, config),
120
+ checkConcurrency(state, config),
121
+ checkWallTime(state, config),
122
+ checkInvocations(state, config),
123
+ ];
124
+ return checks.filter((c) => !c.passed);
125
+ }
126
+ //# sourceMappingURL=safety.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safety.js","sourceRoot":"","sources":["../../src/orchestrator/safety.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Task } from '../types.js';
2
+ export interface TaskGraph {
3
+ addTask(task: Task): void;
4
+ removeTask(id: string): void;
5
+ getTask(id: string): Task | undefined;
6
+ getAllTasks(): Task[];
7
+ getWave(waveNumber: number): Task[];
8
+ getWaves(): Task[][];
9
+ getDependencies(taskId: string): Task[];
10
+ getDependents(taskId: string): Task[];
11
+ isReady(taskId: string): boolean;
12
+ getReadyTasks(): Task[];
13
+ topologicalSort(): Task[];
14
+ hasCycle(): boolean;
15
+ validateDependencies(): string[];
16
+ }
17
+ export declare function createTaskGraph(): TaskGraph;
@@ -0,0 +1,156 @@
1
+ export function createTaskGraph() {
2
+ const tasks = new Map();
3
+ function addTask(task) {
4
+ if (tasks.has(task.id)) {
5
+ throw new Error(`Task with id '${task.id}' already exists`);
6
+ }
7
+ tasks.set(task.id, task);
8
+ }
9
+ function removeTask(id) {
10
+ tasks.delete(id);
11
+ }
12
+ function getTask(id) {
13
+ return tasks.get(id);
14
+ }
15
+ function getAllTasks() {
16
+ return [...tasks.values()];
17
+ }
18
+ function getWave(waveNumber) {
19
+ return getAllTasks().filter((t) => t.wave === waveNumber);
20
+ }
21
+ function getWaves() {
22
+ const waveMap = new Map();
23
+ for (const task of tasks.values()) {
24
+ const list = waveMap.get(task.wave);
25
+ if (list) {
26
+ list.push(task);
27
+ }
28
+ else {
29
+ waveMap.set(task.wave, [task]);
30
+ }
31
+ }
32
+ const waveNumbers = [...waveMap.keys()].sort((a, b) => a - b);
33
+ return waveNumbers.map((n) => waveMap.get(n));
34
+ }
35
+ function getDependencies(taskId) {
36
+ const task = tasks.get(taskId);
37
+ if (!task)
38
+ return [];
39
+ const deps = [];
40
+ for (const depId of task.dependsOn) {
41
+ const dep = tasks.get(depId);
42
+ if (dep)
43
+ deps.push(dep);
44
+ }
45
+ return deps;
46
+ }
47
+ function getDependents(taskId) {
48
+ const result = [];
49
+ for (const task of tasks.values()) {
50
+ if (task.dependsOn.includes(taskId)) {
51
+ result.push(task);
52
+ }
53
+ }
54
+ return result;
55
+ }
56
+ function isReady(taskId) {
57
+ const task = tasks.get(taskId);
58
+ if (!task)
59
+ return false;
60
+ if (task.status !== 'pending')
61
+ return false;
62
+ for (const depId of task.dependsOn) {
63
+ const dep = tasks.get(depId);
64
+ if (!dep || dep.status !== 'completed')
65
+ return false;
66
+ }
67
+ return true;
68
+ }
69
+ function getReadyTasks() {
70
+ const result = [];
71
+ for (const task of tasks.values()) {
72
+ if (isReady(task.id)) {
73
+ result.push(task);
74
+ }
75
+ }
76
+ return result;
77
+ }
78
+ function kahnSort() {
79
+ // Build adjacency and in-degree from dependsOn
80
+ const inDegree = new Map();
81
+ const adjacency = new Map();
82
+ for (const task of tasks.values()) {
83
+ if (!inDegree.has(task.id))
84
+ inDegree.set(task.id, 0);
85
+ if (!adjacency.has(task.id))
86
+ adjacency.set(task.id, []);
87
+ }
88
+ for (const task of tasks.values()) {
89
+ for (const depId of task.dependsOn) {
90
+ if (tasks.has(depId)) {
91
+ // depId -> task.id (dependency must come before dependent)
92
+ const adj = adjacency.get(depId);
93
+ if (adj)
94
+ adj.push(task.id);
95
+ inDegree.set(task.id, (inDegree.get(task.id) ?? 0) + 1);
96
+ }
97
+ }
98
+ }
99
+ const queue = [];
100
+ for (const [id, degree] of inDegree) {
101
+ if (degree === 0)
102
+ queue.push(id);
103
+ }
104
+ const sorted = [];
105
+ while (queue.length > 0) {
106
+ const id = queue.shift();
107
+ const task = tasks.get(id);
108
+ if (task)
109
+ sorted.push(task);
110
+ for (const neighbor of adjacency.get(id) ?? []) {
111
+ const newDegree = (inDegree.get(neighbor) ?? 1) - 1;
112
+ inDegree.set(neighbor, newDegree);
113
+ if (newDegree === 0)
114
+ queue.push(neighbor);
115
+ }
116
+ }
117
+ return { sorted, hasCycle: sorted.length < tasks.size };
118
+ }
119
+ function topologicalSort() {
120
+ const result = kahnSort();
121
+ if (result.hasCycle) {
122
+ throw new Error('Task graph contains a cycle');
123
+ }
124
+ return result.sorted;
125
+ }
126
+ function hasCycle() {
127
+ return kahnSort().hasCycle;
128
+ }
129
+ function validateDependencies() {
130
+ const errors = [];
131
+ for (const task of tasks.values()) {
132
+ for (const depId of task.dependsOn) {
133
+ if (!tasks.has(depId)) {
134
+ errors.push(`Task '${task.id}' depends on '${depId}' which does not exist`);
135
+ }
136
+ }
137
+ }
138
+ return errors;
139
+ }
140
+ return {
141
+ addTask,
142
+ removeTask,
143
+ getTask,
144
+ getAllTasks,
145
+ getWave,
146
+ getWaves,
147
+ getDependencies,
148
+ getDependents,
149
+ isReady,
150
+ getReadyTasks,
151
+ topologicalSort,
152
+ hasCycle,
153
+ validateDependencies,
154
+ };
155
+ }
156
+ //# sourceMappingURL=task-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-graph.js","sourceRoot":"","sources":["../../src/orchestrator/task-graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { Task, TaskEvent, ProjectConfig } from '../types.js';
2
+ import type { AgentRuntime, AgentEvent } from '../agents/runtime.js';
3
+ import type { TaskGraph } from './task-graph.js';
4
+ import type { SafetyState } from './safety.js';
5
+ import type { AgentAlert, AlertResponse } from './alert-types.js';
6
+ export interface ExecutionConfig {
7
+ readonly systemPrompt: string;
8
+ readonly model: string;
9
+ readonly maxTurns: number;
10
+ }
11
+ export interface WaveExecutorParams {
12
+ readonly graph: TaskGraph;
13
+ readonly runtime: AgentRuntime;
14
+ readonly config: ProjectConfig;
15
+ readonly workingDirectory: string;
16
+ readonly buildPrompt: (task: Task) => Promise<string>;
17
+ readonly buildExecutionConfig: (task: Task) => ExecutionConfig;
18
+ readonly onTaskEvent: (event: TaskEvent) => Promise<void>;
19
+ readonly onAgentEvent: (taskId: string, event: AgentEvent) => void;
20
+ readonly onAlert?: (alert: AgentAlert) => Promise<AlertResponse>;
21
+ readonly abortSignal?: AbortSignal;
22
+ }
23
+ export interface WaveResult {
24
+ readonly wave: number;
25
+ readonly tasks: readonly TaskResult[];
26
+ readonly totalInputTokens: number;
27
+ readonly totalOutputTokens: number;
28
+ }
29
+ export interface TaskResult {
30
+ readonly taskId: string;
31
+ readonly status: 'completed' | 'failed' | 'skipped';
32
+ readonly inputTokens: number;
33
+ readonly outputTokens: number;
34
+ readonly error?: string;
35
+ readonly result?: string;
36
+ }
37
+ export declare function executeWave(wave: number, params: WaveExecutorParams, safetyState: SafetyState): Promise<WaveResult>;
@@ -0,0 +1,237 @@
1
+ import { checkAll } from './safety.js';
2
+ import { generateId } from '../utils/id.js';
3
+ function createSemaphore(max) {
4
+ let current = 0;
5
+ const queue = [];
6
+ return {
7
+ acquire() {
8
+ if (current < max) {
9
+ current++;
10
+ return Promise.resolve();
11
+ }
12
+ return new Promise((resolve) => {
13
+ queue.push(resolve);
14
+ });
15
+ },
16
+ release() {
17
+ const next = queue.shift();
18
+ if (next) {
19
+ next();
20
+ }
21
+ else {
22
+ current--;
23
+ }
24
+ },
25
+ };
26
+ }
27
+ const MAX_ALERT_RETRIES = 5;
28
+ async function executeTask(task, params, semaphore, retriesRemaining, safetyState) {
29
+ await semaphore.acquire();
30
+ try {
31
+ return await runTask(task, params, semaphore, retriesRemaining, safetyState, 0);
32
+ }
33
+ catch (err) {
34
+ // runTask manages its own semaphore release and activeAgents cleanup.
35
+ // If we reach here, the task is in an unexpected state — just return failed.
36
+ const errorMsg = err instanceof Error ? err.message : String(err);
37
+ if (task.status !== 'failed') {
38
+ task.status = 'failed';
39
+ }
40
+ return {
41
+ taskId: task.id,
42
+ status: 'failed',
43
+ inputTokens: 0,
44
+ outputTokens: 0,
45
+ error: errorMsg,
46
+ };
47
+ }
48
+ }
49
+ async function runTask(task, params, semaphore, retriesRemaining, safetyState, alertRetryCount, alertContext) {
50
+ if (params.abortSignal?.aborted) {
51
+ semaphore.release();
52
+ task.status = 'skipped';
53
+ return { taskId: task.id, status: 'skipped', inputTokens: 0, outputTokens: 0 };
54
+ }
55
+ task.status = 'running';
56
+ safetyState.totalAgentInvocations++;
57
+ safetyState.activeAgents++;
58
+ let inputTokens = 0;
59
+ let outputTokens = 0;
60
+ let result;
61
+ let error;
62
+ let retryWithContext;
63
+ let shouldSkip = false;
64
+ try {
65
+ await params.onTaskEvent({
66
+ ts: new Date().toISOString(),
67
+ type: 'task_started',
68
+ taskId: task.id,
69
+ });
70
+ const executionId = generateId();
71
+ const basePrompt = await params.buildPrompt(task);
72
+ const prompt = alertContext
73
+ ? `${basePrompt}\n\n# Additional Context from Previous Attempt\n${alertContext}`
74
+ : basePrompt;
75
+ const execConfig = params.buildExecutionConfig(task);
76
+ const stream = params.runtime.execute({
77
+ executionId,
78
+ prompt,
79
+ systemPrompt: execConfig.systemPrompt,
80
+ workingDirectory: params.workingDirectory,
81
+ model: execConfig.model,
82
+ maxTurns: execConfig.maxTurns,
83
+ outputFormat: 'stream-json',
84
+ dangerouslySkipPermissions: true,
85
+ });
86
+ for await (const event of stream) {
87
+ params.onAgentEvent(task.id, event);
88
+ if (event.type === 'cost_update') {
89
+ inputTokens = event.inputTokens;
90
+ outputTokens = event.outputTokens;
91
+ }
92
+ else if (event.type === 'complete') {
93
+ result = event.result;
94
+ }
95
+ else if (event.type === 'error') {
96
+ error = event.error;
97
+ }
98
+ else if (event.type === 'alert' && params.onAlert) {
99
+ const alert = {
100
+ taskId: task.id,
101
+ executionId,
102
+ severity: event.severity,
103
+ message: event.message,
104
+ context: event.context,
105
+ timestamp: Date.now(),
106
+ };
107
+ const response = await params.onAlert(alert);
108
+ if (response.action === 'abort') {
109
+ await params.runtime.abort(executionId).catch((err) => {
110
+ process.stderr.write(`[wave-executor] Failed to abort execution ${executionId}: ${err instanceof Error ? err.message : String(err)}\n`);
111
+ });
112
+ error = `Aborted due to alert: ${event.message}`;
113
+ break;
114
+ }
115
+ if (response.action === 'skip') {
116
+ await params.runtime.abort(executionId).catch((err) => {
117
+ process.stderr.write(`[wave-executor] Failed to abort execution ${executionId}: ${err instanceof Error ? err.message : String(err)}\n`);
118
+ });
119
+ shouldSkip = true;
120
+ break;
121
+ }
122
+ if (response.action === 'retry') {
123
+ await params.runtime.abort(executionId).catch((err) => {
124
+ process.stderr.write(`[wave-executor] Failed to abort execution ${executionId}: ${err instanceof Error ? err.message : String(err)}\n`);
125
+ });
126
+ retryWithContext = `Previous attempt raised an alert: ${event.message}`;
127
+ break;
128
+ }
129
+ if (response.action === 'answer') {
130
+ await params.runtime.abort(executionId).catch((err) => {
131
+ process.stderr.write(`[wave-executor] Failed to abort execution ${executionId}: ${err instanceof Error ? err.message : String(err)}\n`);
132
+ });
133
+ retryWithContext = response.message
134
+ ? `Previous attempt raised a question: ${event.message}\nUser provided guidance: ${response.message}`
135
+ : `Previous attempt raised a question: ${event.message}`;
136
+ break;
137
+ }
138
+ }
139
+ }
140
+ }
141
+ catch (err) {
142
+ error = err instanceof Error ? err.message : String(err);
143
+ }
144
+ finally {
145
+ semaphore.release();
146
+ safetyState.activeAgents--;
147
+ }
148
+ // Alert-triggered retry: re-run with context injected into prompt (bounded)
149
+ if (retryWithContext !== undefined) {
150
+ if (alertRetryCount >= MAX_ALERT_RETRIES) {
151
+ task.status = 'failed';
152
+ const failError = `Max alert retries (${MAX_ALERT_RETRIES}) exceeded`;
153
+ await params.onTaskEvent({
154
+ ts: new Date().toISOString(),
155
+ type: 'task_failed',
156
+ taskId: task.id,
157
+ error: failError,
158
+ }).catch((err) => {
159
+ process.stderr.write(`[wave-executor] Failed to persist task event for ${task.id}: ${err instanceof Error ? err.message : String(err)}\n`);
160
+ });
161
+ return { taskId: task.id, status: 'failed', inputTokens, outputTokens, error: failError };
162
+ }
163
+ await semaphore.acquire();
164
+ return runTask(task, params, semaphore, retriesRemaining, safetyState, alertRetryCount + 1, retryWithContext);
165
+ }
166
+ // Alert-triggered skip: mark task as skipped
167
+ if (shouldSkip) {
168
+ task.status = 'skipped';
169
+ await params.onTaskEvent({
170
+ ts: new Date().toISOString(),
171
+ type: 'task_skipped',
172
+ taskId: task.id,
173
+ }).catch((err) => {
174
+ process.stderr.write(`[wave-executor] Failed to persist task event for ${task.id}: ${err instanceof Error ? err.message : String(err)}\n`);
175
+ });
176
+ return { taskId: task.id, status: 'skipped', inputTokens, outputTokens };
177
+ }
178
+ if (error !== undefined) {
179
+ if (retriesRemaining > 0) {
180
+ await semaphore.acquire();
181
+ return runTask(task, params, semaphore, retriesRemaining - 1, safetyState, 0);
182
+ }
183
+ task.status = 'failed';
184
+ await params.onTaskEvent({
185
+ ts: new Date().toISOString(),
186
+ type: 'task_failed',
187
+ taskId: task.id,
188
+ error,
189
+ }).catch((err) => {
190
+ process.stderr.write(`[wave-executor] Failed to persist task event for ${task.id}: ${err instanceof Error ? err.message : String(err)}\n`);
191
+ });
192
+ return { taskId: task.id, status: 'failed', inputTokens, outputTokens, error };
193
+ }
194
+ task.status = 'completed';
195
+ await params.onTaskEvent({
196
+ ts: new Date().toISOString(),
197
+ type: 'task_completed',
198
+ taskId: task.id,
199
+ inputTokens,
200
+ outputTokens,
201
+ }).catch((err) => {
202
+ process.stderr.write(`[wave-executor] Failed to persist task event for ${task.id}: ${err instanceof Error ? err.message : String(err)}\n`);
203
+ });
204
+ return { taskId: task.id, status: 'completed', inputTokens, outputTokens, result };
205
+ }
206
+ export async function executeWave(wave, params, safetyState) {
207
+ // Check safety limits before starting
208
+ const failedChecks = checkAll(safetyState, params.config);
209
+ if (failedChecks.length > 0) {
210
+ const first = failedChecks[0];
211
+ throw new Error(`Safety check failed [${first.code}]: ${first.message}`);
212
+ }
213
+ const tasks = params.graph.getWave(wave);
214
+ if (tasks.length === 0) {
215
+ return { wave, tasks: [], totalInputTokens: 0, totalOutputTokens: 0 };
216
+ }
217
+ const semaphore = createSemaphore(params.config.maxConcurrentAgents);
218
+ const maxRetries = params.config.maxTaskRetries;
219
+ const promises = tasks.map((task) => executeTask(task, params, semaphore, task.maxRetries ?? maxRetries, safetyState));
220
+ const settled = await Promise.allSettled(promises);
221
+ const taskResults = settled.map((outcome) => {
222
+ if (outcome.status === 'fulfilled') {
223
+ return outcome.value;
224
+ }
225
+ return {
226
+ taskId: 'unknown',
227
+ status: 'failed',
228
+ inputTokens: 0,
229
+ outputTokens: 0,
230
+ error: outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason),
231
+ };
232
+ });
233
+ const totalInputTokens = taskResults.reduce((sum, r) => sum + r.inputTokens, 0);
234
+ const totalOutputTokens = taskResults.reduce((sum, r) => sum + r.outputTokens, 0);
235
+ return { wave, tasks: taskResults, totalInputTokens, totalOutputTokens };
236
+ }
237
+ //# sourceMappingURL=wave-executor.js.map