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,30 @@
1
+ import { clearScreen, moveCursor, write } from './screen.js';
2
+ import { stripAnsi } from './colors.js';
3
+ function writeLine(text, row, col, maxWidth) {
4
+ moveCursor(row + 1, col + 1); // moveCursor is 1-based
5
+ const visibleLen = stripAnsi(text).length;
6
+ if (visibleLen > maxWidth) {
7
+ // Truncate to fit (strip ANSI, truncate, no ANSI re-wrap for simplicity)
8
+ const stripped = stripAnsi(text);
9
+ write(stripped.slice(0, maxWidth));
10
+ }
11
+ else {
12
+ write(text);
13
+ }
14
+ }
15
+ export function renderFrame(frame, layout) {
16
+ clearScreen();
17
+ // Render header
18
+ writeLine(frame.header, layout.header.top, layout.header.left, layout.header.width);
19
+ // Render task board
20
+ for (let i = 0; i < layout.taskBoard.height && i < frame.taskBoard.length; i++) {
21
+ writeLine(frame.taskBoard[i], layout.taskBoard.top + i, layout.taskBoard.left, layout.taskBoard.width);
22
+ }
23
+ // Render agent panel
24
+ for (let i = 0; i < layout.agentPanel.height && i < frame.agentPanel.length; i++) {
25
+ writeLine(frame.agentPanel[i], layout.agentPanel.top + i, layout.agentPanel.left, layout.agentPanel.width);
26
+ }
27
+ // Render status bar
28
+ writeLine(frame.statusBar, layout.statusBar.top, layout.statusBar.left, layout.statusBar.width);
29
+ }
30
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/tui/renderer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AASxC,SAAS,SAAS,CAAC,IAAY,EAAE,GAAW,EAAE,GAAW,EAAE,QAAgB;IACzE,UAAU,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,wBAAwB;IACtD,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IAC1C,IAAI,UAAU,GAAG,QAAQ,EAAE,CAAC;QAC1B,yEAAyE;QACzE,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QACjC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IACrC,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAkB,EAAE,MAAc;IAC5D,WAAW,EAAE,CAAC;IAEd,gBAAgB;IAChB,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEpF,oBAAoB;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/E,SAAS,CACP,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAClB,MAAM,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,EACxB,MAAM,CAAC,SAAS,CAAC,IAAI,EACrB,MAAM,CAAC,SAAS,CAAC,KAAK,CACvB,CAAC;IACJ,CAAC;IAED,qBAAqB;IACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACjF,SAAS,CACP,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EACnB,MAAM,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,EACzB,MAAM,CAAC,UAAU,CAAC,IAAI,EACtB,MAAM,CAAC,UAAU,CAAC,KAAK,CACxB,CAAC;IACJ,CAAC;IAED,oBAAoB;IACpB,SAAS,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAClG,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface ScreenSize {
2
+ readonly rows: number;
3
+ readonly cols: number;
4
+ }
5
+ export declare function getScreenSize(): ScreenSize;
6
+ export declare function enterRawMode(): void;
7
+ export declare function exitRawMode(): void;
8
+ export declare function hideCursor(): void;
9
+ export declare function showCursor(): void;
10
+ export declare function clearScreen(): void;
11
+ export declare function moveCursor(row: number, col: number): void;
12
+ export declare function write(text: string): void;
@@ -0,0 +1,32 @@
1
+ export function getScreenSize() {
2
+ return {
3
+ rows: process.stdout.rows || 24,
4
+ cols: process.stdout.columns || 80,
5
+ };
6
+ }
7
+ export function enterRawMode() {
8
+ if (process.stdin.isTTY) {
9
+ process.stdin.setRawMode(true);
10
+ }
11
+ }
12
+ export function exitRawMode() {
13
+ if (process.stdin.isTTY) {
14
+ process.stdin.setRawMode(false);
15
+ }
16
+ }
17
+ export function hideCursor() {
18
+ write('\x1b[?25l');
19
+ }
20
+ export function showCursor() {
21
+ write('\x1b[?25h');
22
+ }
23
+ export function clearScreen() {
24
+ write('\x1b[2J\x1b[H');
25
+ }
26
+ export function moveCursor(row, col) {
27
+ write(`\x1b[${row};${col}H`);
28
+ }
29
+ export function write(text) {
30
+ process.stdout.write(text);
31
+ }
32
+ //# sourceMappingURL=screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen.js","sourceRoot":"","sources":["../../src/tui/screen.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE;QAC/B,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE;KACnC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,KAAK,CAAC,WAAW,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,KAAK,CAAC,WAAW,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,KAAK,CAAC,eAAe,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,GAAW;IACjD,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAY;IAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { DisplayTarget, DisplayConfig } from './display.js';
2
+ export interface StructuredDisplayConfig extends DisplayConfig {
3
+ readonly structuredLogPath: string;
4
+ }
5
+ export declare function createStructuredDisplay(config: StructuredDisplayConfig): DisplayTarget;
@@ -0,0 +1,74 @@
1
+ import { createWriteStream } from 'node:fs';
2
+ export function createStructuredDisplay(config) {
3
+ let stream = null;
4
+ function handleEvent(event) {
5
+ if (!stream)
6
+ return;
7
+ const line = {
8
+ ts: new Date().toISOString(),
9
+ type: event.type,
10
+ };
11
+ switch (event.type) {
12
+ case 'pipeline_started':
13
+ line.goal = event.goal;
14
+ line.mode = event.mode;
15
+ break;
16
+ case 'step_created':
17
+ line.stepNumber = event.stepNumber;
18
+ line.name = event.name;
19
+ if (event.phase)
20
+ line.phase = event.phase;
21
+ break;
22
+ case 'step_started':
23
+ line.stepNumber = event.stepNumber;
24
+ line.name = event.name;
25
+ line.agent = event.agent;
26
+ break;
27
+ case 'step_completed':
28
+ line.stepNumber = event.stepNumber;
29
+ line.name = event.name;
30
+ line.inputTokens = event.inputTokens;
31
+ line.outputTokens = event.outputTokens;
32
+ break;
33
+ case 'step_failed':
34
+ line.stepNumber = event.stepNumber;
35
+ line.name = event.name;
36
+ line.error = event.error;
37
+ break;
38
+ case 'agent_event':
39
+ // Skip agent_event to keep JSON log concise
40
+ return;
41
+ case 'phase_started':
42
+ line.phase = event.phase;
43
+ line.description = event.description;
44
+ break;
45
+ case 'phase_completed':
46
+ line.phase = event.phase;
47
+ break;
48
+ case 'pipeline_complete':
49
+ line.totalSteps = event.totalSteps;
50
+ line.completedSteps = event.completedSteps;
51
+ line.totalInputTokens = event.totalInputTokens;
52
+ line.totalOutputTokens = event.totalOutputTokens;
53
+ break;
54
+ case 'pipeline_error':
55
+ line.error = event.error;
56
+ break;
57
+ }
58
+ stream.write(JSON.stringify(line) + '\n');
59
+ }
60
+ return {
61
+ mode: 'structured',
62
+ handleEvent,
63
+ start() {
64
+ stream = createWriteStream(config.structuredLogPath, { flags: 'a' });
65
+ },
66
+ stop() {
67
+ if (stream) {
68
+ stream.end();
69
+ stream = null;
70
+ }
71
+ },
72
+ };
73
+ }
74
+ //# sourceMappingURL=structured-display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structured-display.js","sourceRoot":"","sources":["../../src/tui/structured-display.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { DisplayTarget, DisplayConfig } from './display.js';
2
+ import type { TmuxManager } from './tmux.js';
3
+ export interface TmuxDisplayConfig extends DisplayConfig {
4
+ readonly tmuxManager?: TmuxManager;
5
+ }
6
+ export declare function createTmuxDisplay(config: TmuxDisplayConfig): DisplayTarget;
@@ -0,0 +1,187 @@
1
+ import { formatElapsed } from './display.js';
2
+ import { createTmuxManager } from './tmux.js';
3
+ import { createPaneFormatter, createDashboardFormatter } from './pane-formatter.js';
4
+ export function createTmuxDisplay(config) {
5
+ const tmux = config.tmuxManager ?? createTmuxManager();
6
+ const stepPanes = new Map();
7
+ const dashboard = createDashboardFormatter();
8
+ const startTime = Date.now();
9
+ // Session management state
10
+ let sessionName = null;
11
+ let detachedMode = false;
12
+ let dashboardPane = null;
13
+ // Tracking for status bar
14
+ let completedSteps = 0;
15
+ let totalSteps = 0;
16
+ let totalTokens = 0;
17
+ function elapsedStr() {
18
+ return formatElapsed(Date.now() - startTime);
19
+ }
20
+ function writeDashboard(text) {
21
+ if (dashboardPane) {
22
+ tmux.writeToPane(dashboardPane, text);
23
+ }
24
+ }
25
+ function updateStatusBar() {
26
+ if (sessionName) {
27
+ tmux.setStatusBar(sessionName, dashboard.formatStatusBarText(completedSteps, totalSteps, totalTokens));
28
+ }
29
+ }
30
+ function handleEvent(event) {
31
+ switch (event.type) {
32
+ case 'pipeline_started':
33
+ writeDashboard(`\n Goal: ${event.goal}\n`);
34
+ break;
35
+ case 'step_created':
36
+ totalSteps++;
37
+ updateStatusBar();
38
+ break;
39
+ case 'step_started': {
40
+ writeDashboard(dashboard.formatStepStarted(event.stepNumber, event.name, event.agent));
41
+ // Create agent pane
42
+ try {
43
+ const pane = tmux.createPane({
44
+ session: sessionName ?? undefined,
45
+ title: `${event.agent}: ${event.name}`,
46
+ });
47
+ const formatter = createPaneFormatter();
48
+ stepPanes.set(event.stepNumber, { pane, formatter, status: 'processing', agent: event.agent });
49
+ tmux.writeToPane(pane, formatter.formatPaneHeader(event.agent, event.name, event.stepNumber));
50
+ tmux.rebalanceLayout(sessionName ?? undefined);
51
+ }
52
+ catch {
53
+ // Pane creation failed — continue without tmux pane for this step
54
+ }
55
+ break;
56
+ }
57
+ case 'step_completed': {
58
+ const tok = event.inputTokens + event.outputTokens;
59
+ completedSteps++;
60
+ totalTokens += tok;
61
+ writeDashboard(dashboard.formatStepCompleted(event.stepNumber, event.name, tok));
62
+ updateStatusBar();
63
+ const entry = stepPanes.get(event.stepNumber);
64
+ if (entry) {
65
+ entry.status = 'done';
66
+ tmux.writeToPane(entry.pane, entry.formatter.formatComplete('completed', 'Step completed'));
67
+ entry.closeTimer = setTimeout(() => {
68
+ tmux.closePane(entry.pane);
69
+ stepPanes.delete(event.stepNumber);
70
+ tmux.rebalanceLayout(sessionName ?? undefined);
71
+ }, 3000);
72
+ }
73
+ break;
74
+ }
75
+ case 'step_failed': {
76
+ writeDashboard(dashboard.formatStepFailed(event.stepNumber, event.name, event.error));
77
+ const entry = stepPanes.get(event.stepNumber);
78
+ if (entry) {
79
+ entry.status = 'error';
80
+ tmux.writeToPane(entry.pane, entry.formatter.formatComplete('failed', event.error));
81
+ entry.closeTimer = setTimeout(() => {
82
+ tmux.closePane(entry.pane);
83
+ stepPanes.delete(event.stepNumber);
84
+ tmux.rebalanceLayout(sessionName ?? undefined);
85
+ }, 5000);
86
+ }
87
+ break;
88
+ }
89
+ case 'agent_event': {
90
+ const entry = stepPanes.get(event.stepNumber);
91
+ if (!entry)
92
+ break;
93
+ switch (event.event.type) {
94
+ case 'text_delta':
95
+ tmux.writeToPane(entry.pane, entry.formatter.formatTextDelta(event.event.text));
96
+ break;
97
+ case 'tool_use':
98
+ entry.status = 'processing';
99
+ tmux.writeToPane(entry.pane, entry.formatter.formatToolUse(String(event.event.tool)));
100
+ break;
101
+ case 'tool_result':
102
+ tmux.writeToPane(entry.pane, entry.formatter.formatToolResult(String(event.event.tool), String(event.event.output ?? '')));
103
+ break;
104
+ case 'cost_update': {
105
+ const stepTokens = event.event.inputTokens + event.event.outputTokens;
106
+ tmux.setPaneTitle(entry.pane, entry.formatter.formatStatusLine(entry.agent, entry.status, stepTokens));
107
+ break;
108
+ }
109
+ case 'error':
110
+ entry.status = 'error';
111
+ tmux.writeToPane(entry.pane, entry.formatter.formatError(event.event.error));
112
+ break;
113
+ case 'complete':
114
+ // Will be handled by step_completed event
115
+ break;
116
+ }
117
+ break;
118
+ }
119
+ case 'phase_started':
120
+ writeDashboard(`\n ── Phase: ${event.phase} ──\n ${event.description}\n`);
121
+ break;
122
+ case 'phase_completed':
123
+ writeDashboard(` Phase ${event.phase} completed [${elapsedStr()}]\n`);
124
+ break;
125
+ case 'pipeline_complete': {
126
+ const totalTok = event.totalInputTokens + event.totalOutputTokens;
127
+ totalTokens = totalTok;
128
+ writeDashboard(dashboard.formatPipelineComplete(event.completedSteps, totalTok, elapsedStr()));
129
+ updateStatusBar();
130
+ break;
131
+ }
132
+ case 'pipeline_error':
133
+ writeDashboard(dashboard.formatPipelineError(event.error));
134
+ break;
135
+ }
136
+ }
137
+ function start() {
138
+ if (!tmux.hasBinary()) {
139
+ throw new Error('tmux binary not found');
140
+ }
141
+ if (tmux.isInsideSession() && !config.forceDetached) {
142
+ detachedMode = false;
143
+ sessionName = null;
144
+ dashboardPane = tmux.createPane({ title: 'slavedriver: dashboard' });
145
+ tmux.rebalanceLayout();
146
+ }
147
+ else {
148
+ detachedMode = true;
149
+ const safeName = config.projectName.replace(/[^a-zA-Z0-9_-]/g, '_');
150
+ sessionName = `sd__${safeName}`;
151
+ if (tmux.hasSession(sessionName)) {
152
+ tmux.killSession(sessionName);
153
+ }
154
+ dashboardPane = tmux.createSession(sessionName);
155
+ tmux.openTerminalAttached(sessionName);
156
+ }
157
+ writeDashboard(dashboard.formatBanner(config.projectName, config.version));
158
+ updateStatusBar();
159
+ }
160
+ function stop() {
161
+ for (const [, entry] of stepPanes) {
162
+ if (entry.closeTimer) {
163
+ clearTimeout(entry.closeTimer);
164
+ }
165
+ }
166
+ tmux.closeAllPanes();
167
+ stepPanes.clear();
168
+ if (detachedMode && sessionName) {
169
+ setTimeout(() => {
170
+ if (sessionName && tmux.hasSession(sessionName)) {
171
+ tmux.killSession(sessionName);
172
+ }
173
+ }, 10000);
174
+ }
175
+ dashboardPane = null;
176
+ }
177
+ return {
178
+ mode: 'tmux',
179
+ handleEvent,
180
+ start,
181
+ stop,
182
+ getSessionName() {
183
+ return sessionName;
184
+ },
185
+ };
186
+ }
187
+ //# sourceMappingURL=tmux-display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux-display.js","sourceRoot":"","sources":["../../src/tui/tmux-display.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export interface TmuxPane {
2
+ readonly paneId: string;
3
+ readonly ttyPath: string;
4
+ }
5
+ export interface TmuxManager {
6
+ hasBinary(): boolean;
7
+ isInsideSession(): boolean;
8
+ createSession(name: string): TmuxPane;
9
+ hasSession(name: string): boolean;
10
+ killSession(name: string): void;
11
+ openTerminalAttached(sessionName: string): void;
12
+ createPane(opts: {
13
+ session?: string;
14
+ title: string;
15
+ }): TmuxPane;
16
+ writeToPane(pane: TmuxPane, text: string): void;
17
+ setPaneTitle(pane: TmuxPane, title: string): void;
18
+ closePane(pane: TmuxPane): void;
19
+ rebalanceLayout(session?: string): void;
20
+ closeAllPanes(): void;
21
+ getActivePanes(): readonly TmuxPane[];
22
+ setStatusBar(session: string, text: string): void;
23
+ setStatusBarOff(session: string): void;
24
+ }
25
+ export type ExecFn = (cmd: string, args: readonly string[]) => string;
26
+ export declare function createTmuxManager(exec?: ExecFn): TmuxManager;
@@ -0,0 +1,265 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { createWriteStream } from 'node:fs';
3
+ function defaultExec(cmd, args) {
4
+ return execFileSync(cmd, args, { encoding: 'utf-8' }).trim();
5
+ }
6
+ export function createTmuxManager(exec) {
7
+ const run = exec ?? defaultExec;
8
+ const activePanes = [];
9
+ const streams = new Map();
10
+ // --- Binary / session detection ---
11
+ function hasBinary() {
12
+ try {
13
+ run('tmux', ['-V']);
14
+ return true;
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ function isInsideSession() {
21
+ return !!process.env.TMUX;
22
+ }
23
+ // --- Session lifecycle ---
24
+ function createSession(name) {
25
+ // Create detached session with a dashboard window
26
+ // -P -F prints the pane ID of the initial pane
27
+ // The initial pane runs `cat` to act as a passive output receiver
28
+ const paneId = run('tmux', [
29
+ 'new-session', '-d', '-s', name, '-n', 'dashboard',
30
+ '-P', '-F', '#{pane_id}',
31
+ 'cat',
32
+ ]);
33
+ // Get the TTY path for the initial pane
34
+ const ttyPath = run('tmux', [
35
+ 'display-message', '-t', paneId, '-p', '#{pane_tty}',
36
+ ]);
37
+ // Set pane title
38
+ try {
39
+ run('tmux', ['select-pane', '-t', paneId, '-T', 'dashboard']);
40
+ }
41
+ catch {
42
+ // Pane title not supported
43
+ }
44
+ // Enable pane border titles in this session
45
+ try {
46
+ run('tmux', ['set-option', '-t', name, 'pane-border-format', ' #{pane_title} ']);
47
+ run('tmux', ['set-option', '-t', name, 'pane-border-status', 'top']);
48
+ }
49
+ catch {
50
+ // Pane border title not supported on older tmux
51
+ }
52
+ const pane = { paneId, ttyPath };
53
+ activePanes.push(pane);
54
+ return pane;
55
+ }
56
+ function hasSession(name) {
57
+ try {
58
+ run('tmux', ['has-session', '-t', name]);
59
+ return true;
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ }
65
+ function killSession(name) {
66
+ try {
67
+ run('tmux', ['kill-session', '-t', name]);
68
+ }
69
+ catch {
70
+ // Session may already be gone
71
+ }
72
+ }
73
+ function openTerminalAttached(sessionName) {
74
+ // Resolve absolute path to tmux — terminal emulators (iTerm2, Terminal.app)
75
+ // don't search $PATH when running a command via osascript, so we need the
76
+ // full path or the execvp will fail.
77
+ let tmuxBin = 'tmux';
78
+ try {
79
+ tmuxBin = run('which', ['tmux']);
80
+ }
81
+ catch {
82
+ // Fall back to bare name
83
+ }
84
+ const platform = process.platform;
85
+ const attachCmd = `${tmuxBin} attach-session -t ${sessionName}`;
86
+ if (platform === 'darwin') {
87
+ try {
88
+ // Try iTerm2 via osascript
89
+ run('osascript', [
90
+ '-e', `tell application "iTerm2"
91
+ create window with default profile command "${attachCmd}"
92
+ end tell`,
93
+ ]);
94
+ return;
95
+ }
96
+ catch (err) {
97
+ process.stderr.write(`[tmux] iTerm2 open failed: ${err instanceof Error ? err.message : String(err)}\n`);
98
+ }
99
+ try {
100
+ // Fall back to Terminal.app
101
+ run('osascript', [
102
+ '-e', `tell application "Terminal"
103
+ do script "${attachCmd}"
104
+ activate
105
+ end tell`,
106
+ ]);
107
+ return;
108
+ }
109
+ catch (err) {
110
+ process.stderr.write(`[tmux] Terminal.app open failed: ${err instanceof Error ? err.message : String(err)}\n`);
111
+ }
112
+ }
113
+ if (platform === 'linux') {
114
+ // Try common Linux terminals
115
+ const terminals = ['gnome-terminal', 'xterm', 'konsole'];
116
+ for (const term of terminals) {
117
+ try {
118
+ if (term === 'gnome-terminal') {
119
+ run(term, ['--', tmuxBin, 'attach-session', '-t', sessionName]);
120
+ }
121
+ else if (term === 'konsole') {
122
+ run(term, ['-e', tmuxBin, 'attach-session', '-t', sessionName]);
123
+ }
124
+ else {
125
+ run(term, ['-e', attachCmd]);
126
+ }
127
+ return;
128
+ }
129
+ catch {
130
+ continue;
131
+ }
132
+ }
133
+ }
134
+ // If nothing worked, print instructions
135
+ process.stderr.write(`[tmux] Could not open terminal window automatically.\n`);
136
+ process.stderr.write(`[tmux] Attach with: tmux attach-session -t ${sessionName}\n`);
137
+ }
138
+ // --- Pane management ---
139
+ function createPane(opts) {
140
+ const targetArgs = [];
141
+ if (opts.session) {
142
+ targetArgs.push('-t', opts.session);
143
+ }
144
+ // Split a new pane running `cat` as a passive output receiver
145
+ // -d keeps focus on the current pane, -P prints pane info
146
+ const paneId = run('tmux', [
147
+ 'split-window', '-d', '-P', '-F', '#{pane_id}',
148
+ ...targetArgs,
149
+ 'cat',
150
+ ]);
151
+ // Get the TTY path for direct writes
152
+ const ttyPath = run('tmux', [
153
+ 'display-message', '-t', paneId, '-p', '#{pane_tty}',
154
+ ]);
155
+ // Set the pane title
156
+ try {
157
+ run('tmux', ['select-pane', '-t', paneId, '-T', opts.title]);
158
+ }
159
+ catch {
160
+ // Pane title not supported on older tmux
161
+ }
162
+ const pane = { paneId, ttyPath };
163
+ activePanes.push(pane);
164
+ return pane;
165
+ }
166
+ function writeToPane(pane, text) {
167
+ let stream = streams.get(pane.paneId);
168
+ if (!stream) {
169
+ try {
170
+ stream = createWriteStream(pane.ttyPath, { flags: 'a' });
171
+ streams.set(pane.paneId, stream);
172
+ }
173
+ catch {
174
+ // TTY not writable — fall back to send-keys
175
+ run('tmux', ['send-keys', '-t', pane.paneId, text, '']);
176
+ return;
177
+ }
178
+ }
179
+ stream.write(text);
180
+ }
181
+ function setPaneTitle(pane, title) {
182
+ try {
183
+ run('tmux', ['select-pane', '-t', pane.paneId, '-T', title]);
184
+ }
185
+ catch {
186
+ // Pane title not supported
187
+ }
188
+ }
189
+ function closePane(pane) {
190
+ const stream = streams.get(pane.paneId);
191
+ if (stream) {
192
+ stream.end();
193
+ streams.delete(pane.paneId);
194
+ }
195
+ try {
196
+ run('tmux', ['kill-pane', '-t', pane.paneId]);
197
+ }
198
+ catch {
199
+ // Pane may already be gone
200
+ }
201
+ const idx = activePanes.findIndex((p) => p.paneId === pane.paneId);
202
+ if (idx >= 0) {
203
+ activePanes.splice(idx, 1);
204
+ }
205
+ }
206
+ function rebalanceLayout(session) {
207
+ try {
208
+ const args = ['select-layout'];
209
+ if (session) {
210
+ args.push('-t', session);
211
+ }
212
+ args.push('tiled');
213
+ run('tmux', args);
214
+ }
215
+ catch {
216
+ // Layout rebalance may fail if only one pane
217
+ }
218
+ }
219
+ function closeAllPanes() {
220
+ const panesToClose = [...activePanes];
221
+ for (const pane of panesToClose) {
222
+ closePane(pane);
223
+ }
224
+ }
225
+ function getActivePanes() {
226
+ return [...activePanes];
227
+ }
228
+ // --- Tmux status bar ---
229
+ function setStatusBar(session, text) {
230
+ try {
231
+ run('tmux', ['set-option', '-t', session, 'status-left-length', '80']);
232
+ run('tmux', ['set-option', '-t', session, 'status-left', text]);
233
+ run('tmux', ['set-option', '-t', session, 'status', 'on']);
234
+ }
235
+ catch {
236
+ // Status bar not supported
237
+ }
238
+ }
239
+ function setStatusBarOff(session) {
240
+ try {
241
+ run('tmux', ['set-option', '-t', session, 'status', 'off']);
242
+ }
243
+ catch {
244
+ // Ignore
245
+ }
246
+ }
247
+ return {
248
+ hasBinary,
249
+ isInsideSession,
250
+ createSession,
251
+ hasSession,
252
+ killSession,
253
+ openTerminalAttached,
254
+ createPane,
255
+ writeToPane,
256
+ setPaneTitle,
257
+ closePane,
258
+ rebalanceLayout,
259
+ closeAllPanes,
260
+ getActivePanes,
261
+ setStatusBar,
262
+ setStatusBarOff,
263
+ };
264
+ }
265
+ //# sourceMappingURL=tmux.js.map