@os-eco/overstory-cli 0.6.1

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 (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +381 -0
  3. package/agents/builder.md +137 -0
  4. package/agents/coordinator.md +263 -0
  5. package/agents/lead.md +301 -0
  6. package/agents/merger.md +160 -0
  7. package/agents/monitor.md +214 -0
  8. package/agents/reviewer.md +140 -0
  9. package/agents/scout.md +119 -0
  10. package/agents/supervisor.md +423 -0
  11. package/package.json +47 -0
  12. package/src/agents/checkpoint.test.ts +88 -0
  13. package/src/agents/checkpoint.ts +101 -0
  14. package/src/agents/hooks-deployer.test.ts +2040 -0
  15. package/src/agents/hooks-deployer.ts +607 -0
  16. package/src/agents/identity.test.ts +603 -0
  17. package/src/agents/identity.ts +384 -0
  18. package/src/agents/lifecycle.test.ts +196 -0
  19. package/src/agents/lifecycle.ts +183 -0
  20. package/src/agents/manifest.test.ts +746 -0
  21. package/src/agents/manifest.ts +354 -0
  22. package/src/agents/overlay.test.ts +676 -0
  23. package/src/agents/overlay.ts +308 -0
  24. package/src/beads/client.test.ts +217 -0
  25. package/src/beads/client.ts +202 -0
  26. package/src/beads/molecules.test.ts +338 -0
  27. package/src/beads/molecules.ts +198 -0
  28. package/src/commands/agents.test.ts +322 -0
  29. package/src/commands/agents.ts +287 -0
  30. package/src/commands/clean.test.ts +670 -0
  31. package/src/commands/clean.ts +618 -0
  32. package/src/commands/completions.test.ts +342 -0
  33. package/src/commands/completions.ts +887 -0
  34. package/src/commands/coordinator.test.ts +1530 -0
  35. package/src/commands/coordinator.ts +733 -0
  36. package/src/commands/costs.test.ts +1119 -0
  37. package/src/commands/costs.ts +564 -0
  38. package/src/commands/dashboard.test.ts +308 -0
  39. package/src/commands/dashboard.ts +838 -0
  40. package/src/commands/doctor.test.ts +294 -0
  41. package/src/commands/doctor.ts +213 -0
  42. package/src/commands/errors.test.ts +647 -0
  43. package/src/commands/errors.ts +248 -0
  44. package/src/commands/feed.test.ts +578 -0
  45. package/src/commands/feed.ts +361 -0
  46. package/src/commands/group.test.ts +262 -0
  47. package/src/commands/group.ts +511 -0
  48. package/src/commands/hooks.test.ts +458 -0
  49. package/src/commands/hooks.ts +253 -0
  50. package/src/commands/init.test.ts +347 -0
  51. package/src/commands/init.ts +650 -0
  52. package/src/commands/inspect.test.ts +670 -0
  53. package/src/commands/inspect.ts +431 -0
  54. package/src/commands/log.test.ts +1454 -0
  55. package/src/commands/log.ts +724 -0
  56. package/src/commands/logs.test.ts +379 -0
  57. package/src/commands/logs.ts +546 -0
  58. package/src/commands/mail.test.ts +1270 -0
  59. package/src/commands/mail.ts +771 -0
  60. package/src/commands/merge.test.ts +670 -0
  61. package/src/commands/merge.ts +355 -0
  62. package/src/commands/metrics.test.ts +444 -0
  63. package/src/commands/metrics.ts +143 -0
  64. package/src/commands/monitor.test.ts +191 -0
  65. package/src/commands/monitor.ts +390 -0
  66. package/src/commands/nudge.test.ts +230 -0
  67. package/src/commands/nudge.ts +372 -0
  68. package/src/commands/prime.test.ts +470 -0
  69. package/src/commands/prime.ts +381 -0
  70. package/src/commands/replay.test.ts +741 -0
  71. package/src/commands/replay.ts +360 -0
  72. package/src/commands/run.test.ts +431 -0
  73. package/src/commands/run.ts +351 -0
  74. package/src/commands/sling.test.ts +657 -0
  75. package/src/commands/sling.ts +661 -0
  76. package/src/commands/spec.test.ts +203 -0
  77. package/src/commands/spec.ts +168 -0
  78. package/src/commands/status.test.ts +430 -0
  79. package/src/commands/status.ts +398 -0
  80. package/src/commands/stop.test.ts +420 -0
  81. package/src/commands/stop.ts +151 -0
  82. package/src/commands/supervisor.test.ts +187 -0
  83. package/src/commands/supervisor.ts +535 -0
  84. package/src/commands/trace.test.ts +745 -0
  85. package/src/commands/trace.ts +325 -0
  86. package/src/commands/watch.test.ts +145 -0
  87. package/src/commands/watch.ts +247 -0
  88. package/src/commands/worktree.test.ts +786 -0
  89. package/src/commands/worktree.ts +311 -0
  90. package/src/config.test.ts +822 -0
  91. package/src/config.ts +829 -0
  92. package/src/doctor/agents.test.ts +454 -0
  93. package/src/doctor/agents.ts +396 -0
  94. package/src/doctor/config-check.test.ts +190 -0
  95. package/src/doctor/config-check.ts +183 -0
  96. package/src/doctor/consistency.test.ts +651 -0
  97. package/src/doctor/consistency.ts +294 -0
  98. package/src/doctor/databases.test.ts +290 -0
  99. package/src/doctor/databases.ts +218 -0
  100. package/src/doctor/dependencies.test.ts +184 -0
  101. package/src/doctor/dependencies.ts +175 -0
  102. package/src/doctor/logs.test.ts +251 -0
  103. package/src/doctor/logs.ts +295 -0
  104. package/src/doctor/merge-queue.test.ts +216 -0
  105. package/src/doctor/merge-queue.ts +144 -0
  106. package/src/doctor/structure.test.ts +291 -0
  107. package/src/doctor/structure.ts +198 -0
  108. package/src/doctor/types.ts +37 -0
  109. package/src/doctor/version.test.ts +136 -0
  110. package/src/doctor/version.ts +129 -0
  111. package/src/e2e/init-sling-lifecycle.test.ts +277 -0
  112. package/src/errors.ts +217 -0
  113. package/src/events/store.test.ts +660 -0
  114. package/src/events/store.ts +369 -0
  115. package/src/events/tool-filter.test.ts +330 -0
  116. package/src/events/tool-filter.ts +126 -0
  117. package/src/index.ts +316 -0
  118. package/src/insights/analyzer.test.ts +466 -0
  119. package/src/insights/analyzer.ts +203 -0
  120. package/src/logging/color.test.ts +142 -0
  121. package/src/logging/color.ts +71 -0
  122. package/src/logging/logger.test.ts +813 -0
  123. package/src/logging/logger.ts +266 -0
  124. package/src/logging/reporter.test.ts +259 -0
  125. package/src/logging/reporter.ts +109 -0
  126. package/src/logging/sanitizer.test.ts +190 -0
  127. package/src/logging/sanitizer.ts +57 -0
  128. package/src/mail/broadcast.test.ts +203 -0
  129. package/src/mail/broadcast.ts +92 -0
  130. package/src/mail/client.test.ts +773 -0
  131. package/src/mail/client.ts +223 -0
  132. package/src/mail/store.test.ts +705 -0
  133. package/src/mail/store.ts +387 -0
  134. package/src/merge/queue.test.ts +359 -0
  135. package/src/merge/queue.ts +231 -0
  136. package/src/merge/resolver.test.ts +1345 -0
  137. package/src/merge/resolver.ts +645 -0
  138. package/src/metrics/store.test.ts +667 -0
  139. package/src/metrics/store.ts +445 -0
  140. package/src/metrics/summary.test.ts +398 -0
  141. package/src/metrics/summary.ts +178 -0
  142. package/src/metrics/transcript.test.ts +356 -0
  143. package/src/metrics/transcript.ts +175 -0
  144. package/src/mulch/client.test.ts +671 -0
  145. package/src/mulch/client.ts +332 -0
  146. package/src/sessions/compat.test.ts +280 -0
  147. package/src/sessions/compat.ts +104 -0
  148. package/src/sessions/store.test.ts +873 -0
  149. package/src/sessions/store.ts +494 -0
  150. package/src/test-helpers.test.ts +124 -0
  151. package/src/test-helpers.ts +126 -0
  152. package/src/tracker/beads.ts +56 -0
  153. package/src/tracker/factory.test.ts +80 -0
  154. package/src/tracker/factory.ts +64 -0
  155. package/src/tracker/seeds.ts +182 -0
  156. package/src/tracker/types.ts +52 -0
  157. package/src/types.ts +724 -0
  158. package/src/watchdog/daemon.test.ts +1975 -0
  159. package/src/watchdog/daemon.ts +671 -0
  160. package/src/watchdog/health.test.ts +431 -0
  161. package/src/watchdog/health.ts +264 -0
  162. package/src/watchdog/triage.test.ts +164 -0
  163. package/src/watchdog/triage.ts +179 -0
  164. package/src/worktree/manager.test.ts +439 -0
  165. package/src/worktree/manager.ts +198 -0
  166. package/src/worktree/tmux.test.ts +1009 -0
  167. package/src/worktree/tmux.ts +509 -0
  168. package/templates/CLAUDE.md.tmpl +89 -0
  169. package/templates/hooks.json.tmpl +105 -0
  170. package/templates/overlay.md.tmpl +81 -0
@@ -0,0 +1,887 @@
1
+ /**
2
+ * Shell completion generation for overstory CLI.
3
+ *
4
+ * Generates completion scripts for bash, zsh, and fish shells.
5
+ */
6
+
7
+ interface FlagDef {
8
+ name: string;
9
+ desc: string;
10
+ takesValue?: boolean;
11
+ values?: readonly string[];
12
+ }
13
+
14
+ interface SubcommandDef {
15
+ name: string;
16
+ desc: string;
17
+ flags?: readonly FlagDef[];
18
+ }
19
+
20
+ interface CommandDef {
21
+ name: string;
22
+ desc: string;
23
+ flags?: readonly FlagDef[];
24
+ subcommands?: readonly SubcommandDef[];
25
+ }
26
+
27
+ export const COMMANDS: readonly CommandDef[] = [
28
+ {
29
+ name: "agents",
30
+ desc: "Discover and query agents",
31
+ flags: [
32
+ { name: "--json", desc: "JSON output" },
33
+ { name: "--help", desc: "Show help" },
34
+ ],
35
+ subcommands: [
36
+ {
37
+ name: "discover",
38
+ desc: "Find active agents by capability",
39
+ flags: [
40
+ {
41
+ name: "--capability",
42
+ desc: "Filter by capability",
43
+ takesValue: true,
44
+ values: ["builder", "scout", "reviewer", "lead", "merger", "coordinator", "supervisor"],
45
+ },
46
+ { name: "--all", desc: "Include completed and zombie agents" },
47
+ { name: "--json", desc: "JSON output" },
48
+ { name: "--help", desc: "Show help" },
49
+ ],
50
+ },
51
+ ],
52
+ },
53
+ {
54
+ name: "init",
55
+ desc: "Initialize .overstory/ in current project",
56
+ flags: [
57
+ { name: "--force", desc: "Overwrite existing configuration" },
58
+ { name: "--help", desc: "Show help" },
59
+ ],
60
+ },
61
+ {
62
+ name: "sling",
63
+ desc: "Spawn a worker agent",
64
+ flags: [
65
+ {
66
+ name: "--capability",
67
+ desc: "Agent capability type",
68
+ takesValue: true,
69
+ values: ["builder", "scout", "reviewer", "lead", "merger"],
70
+ },
71
+ { name: "--name", desc: "Unique agent name", takesValue: true },
72
+ { name: "--spec", desc: "Path to task spec file", takesValue: true },
73
+ { name: "--files", desc: "Exclusive file scope (comma-separated)", takesValue: true },
74
+ { name: "--parent", desc: "Parent agent name", takesValue: true },
75
+ { name: "--depth", desc: "Current hierarchy depth", takesValue: true },
76
+ { name: "--force-hierarchy", desc: "Bypass hierarchy validation" },
77
+ { name: "--json", desc: "JSON output" },
78
+ { name: "--help", desc: "Show help" },
79
+ ],
80
+ },
81
+ {
82
+ name: "prime",
83
+ desc: "Load context for orchestrator/agent",
84
+ flags: [
85
+ { name: "--agent", desc: "Per-agent priming", takesValue: true },
86
+ { name: "--compact", desc: "Less context (for PreCompact hook)" },
87
+ { name: "--help", desc: "Show help" },
88
+ ],
89
+ },
90
+ {
91
+ name: "stop",
92
+ desc: "Terminate a running agent",
93
+ flags: [
94
+ { name: "--force", desc: "Force kill and force-delete branch" },
95
+ { name: "--clean-worktree", desc: "Remove the agent's worktree after stopping" },
96
+ { name: "--json", desc: "JSON output" },
97
+ { name: "--help", desc: "Show help" },
98
+ ],
99
+ },
100
+ {
101
+ name: "status",
102
+ desc: "Show all active agents and project state",
103
+ flags: [
104
+ { name: "--json", desc: "JSON output" },
105
+ { name: "--verbose", desc: "Extra per-agent detail" },
106
+ { name: "--agent", desc: "Filter by agent", takesValue: true },
107
+ { name: "--watch", desc: "Watch mode" },
108
+ { name: "--interval", desc: "Poll interval in ms", takesValue: true },
109
+ { name: "--help", desc: "Show help" },
110
+ ],
111
+ },
112
+ {
113
+ name: "dashboard",
114
+ desc: "Live TUI dashboard for agent monitoring",
115
+ flags: [
116
+ { name: "--interval", desc: "Poll interval in ms (default 2000)", takesValue: true },
117
+ { name: "--help", desc: "Show help" },
118
+ ],
119
+ },
120
+ {
121
+ name: "inspect",
122
+ desc: "Deep inspection of a single agent",
123
+ flags: [
124
+ { name: "--json", desc: "JSON output" },
125
+ { name: "--follow", desc: "Poll and refresh continuously" },
126
+ { name: "--interval", desc: "Polling interval in ms", takesValue: true },
127
+ { name: "--limit", desc: "Recent tool calls to show", takesValue: true },
128
+ { name: "--no-tmux", desc: "Skip tmux capture-pane" },
129
+ { name: "--help", desc: "Show help" },
130
+ ],
131
+ },
132
+ {
133
+ name: "merge",
134
+ desc: "Merge agent branches into canonical",
135
+ flags: [
136
+ { name: "--branch", desc: "Specific branch to merge", takesValue: true },
137
+ { name: "--all", desc: "All completed branches" },
138
+ { name: "--dry-run", desc: "Check for conflicts only" },
139
+ { name: "--json", desc: "JSON output" },
140
+ { name: "--help", desc: "Show help" },
141
+ ],
142
+ },
143
+ {
144
+ name: "nudge",
145
+ desc: "Send a text nudge to an agent",
146
+ flags: [
147
+ { name: "--from", desc: "Sender name", takesValue: true },
148
+ { name: "--force", desc: "Skip debounce check" },
149
+ { name: "--json", desc: "JSON output" },
150
+ { name: "--help", desc: "Show help" },
151
+ ],
152
+ },
153
+ {
154
+ name: "clean",
155
+ desc: "Wipe runtime state (nuclear cleanup)",
156
+ flags: [
157
+ { name: "--all", desc: "Wipe everything" },
158
+ { name: "--mail", desc: "Clean mail database" },
159
+ { name: "--sessions", desc: "Clean sessions database" },
160
+ { name: "--metrics", desc: "Clean metrics database" },
161
+ { name: "--logs", desc: "Clean log files" },
162
+ { name: "--worktrees", desc: "Clean worktrees" },
163
+ { name: "--branches", desc: "Clean branches" },
164
+ { name: "--agents", desc: "Clean agent state" },
165
+ { name: "--specs", desc: "Clean specs" },
166
+ { name: "--json", desc: "JSON output" },
167
+ { name: "--help", desc: "Show help" },
168
+ ],
169
+ },
170
+ {
171
+ name: "doctor",
172
+ desc: "Run health checks on overstory setup",
173
+ flags: [
174
+ { name: "--json", desc: "JSON output" },
175
+ { name: "--verbose", desc: "Show passing checks too" },
176
+ {
177
+ name: "--category",
178
+ desc: "Run one category only",
179
+ takesValue: true,
180
+ values: [
181
+ "dependencies",
182
+ "structure",
183
+ "config",
184
+ "databases",
185
+ "consistency",
186
+ "agents",
187
+ "merge",
188
+ "logs",
189
+ "version",
190
+ ],
191
+ },
192
+ { name: "--help", desc: "Show help" },
193
+ ],
194
+ },
195
+ {
196
+ name: "log",
197
+ desc: "Log a hook event",
198
+ flags: [
199
+ { name: "--agent", desc: "Agent name", takesValue: true },
200
+ { name: "--tool-name", desc: "Tool name", takesValue: true },
201
+ { name: "--transcript", desc: "Transcript path", takesValue: true },
202
+ { name: "--stdin", desc: "Read from stdin" },
203
+ { name: "--help", desc: "Show help" },
204
+ ],
205
+ },
206
+ {
207
+ name: "logs",
208
+ desc: "Query NDJSON logs across agents",
209
+ flags: [
210
+ { name: "--agent", desc: "Filter by agent", takesValue: true },
211
+ {
212
+ name: "--level",
213
+ desc: "Filter by log level",
214
+ takesValue: true,
215
+ values: ["debug", "info", "warn", "error"],
216
+ },
217
+ { name: "--since", desc: "Time filter (ISO 8601 or relative)", takesValue: true },
218
+ { name: "--until", desc: "Time filter (ISO 8601)", takesValue: true },
219
+ { name: "--limit", desc: "Max entries", takesValue: true },
220
+ { name: "--follow", desc: "Tail logs in real time" },
221
+ { name: "--json", desc: "JSON output" },
222
+ { name: "--help", desc: "Show help" },
223
+ ],
224
+ },
225
+ {
226
+ name: "watch",
227
+ desc: "Start watchdog daemon",
228
+ flags: [
229
+ { name: "--interval", desc: "Check interval in ms", takesValue: true },
230
+ { name: "--background", desc: "Run in background" },
231
+ { name: "--help", desc: "Show help" },
232
+ ],
233
+ },
234
+ {
235
+ name: "trace",
236
+ desc: "Chronological event timeline for agent/bead",
237
+ flags: [
238
+ { name: "--json", desc: "JSON output" },
239
+ { name: "--since", desc: "Time range filter (ISO 8601)", takesValue: true },
240
+ { name: "--until", desc: "Time range filter (ISO 8601)", takesValue: true },
241
+ { name: "--limit", desc: "Max events", takesValue: true },
242
+ { name: "--help", desc: "Show help" },
243
+ ],
244
+ },
245
+ {
246
+ name: "errors",
247
+ desc: "Aggregated error view across agents",
248
+ flags: [
249
+ { name: "--agent", desc: "Filter by agent", takesValue: true },
250
+ { name: "--run", desc: "Filter by run", takesValue: true },
251
+ { name: "--since", desc: "Time range filter (ISO 8601)", takesValue: true },
252
+ { name: "--until", desc: "Time range filter (ISO 8601)", takesValue: true },
253
+ { name: "--limit", desc: "Max errors", takesValue: true },
254
+ { name: "--json", desc: "JSON output" },
255
+ { name: "--help", desc: "Show help" },
256
+ ],
257
+ },
258
+ {
259
+ name: "feed",
260
+ desc: "Unified real-time event stream across all agents",
261
+ flags: [
262
+ { name: "--follow", desc: "Continuously poll for new events" },
263
+ { name: "-f", desc: "Alias for --follow" },
264
+ { name: "--interval", desc: "Polling interval in ms", takesValue: true },
265
+ { name: "--agent", desc: "Filter by agent", takesValue: true },
266
+ { name: "--run", desc: "Filter by run", takesValue: true },
267
+ { name: "--since", desc: "Start time (ISO 8601)", takesValue: true },
268
+ { name: "--limit", desc: "Max initial events", takesValue: true },
269
+ { name: "--json", desc: "JSON output" },
270
+ { name: "--help", desc: "Show help" },
271
+ ],
272
+ },
273
+ {
274
+ name: "replay",
275
+ desc: "Interleaved chronological replay across agents",
276
+ flags: [
277
+ { name: "--run", desc: "Filter by run", takesValue: true },
278
+ { name: "--agent", desc: "Filter by agent", takesValue: true },
279
+ { name: "--since", desc: "Time range filter (ISO 8601)", takesValue: true },
280
+ { name: "--until", desc: "Time range filter (ISO 8601)", takesValue: true },
281
+ { name: "--limit", desc: "Max events", takesValue: true },
282
+ { name: "--json", desc: "JSON output" },
283
+ { name: "--help", desc: "Show help" },
284
+ ],
285
+ },
286
+ {
287
+ name: "costs",
288
+ desc: "Token/cost analysis and breakdown",
289
+ flags: [
290
+ { name: "--live", desc: "Show real-time token usage for active agents" },
291
+ { name: "--agent", desc: "Filter by agent", takesValue: true },
292
+ { name: "--run", desc: "Filter by run", takesValue: true },
293
+ { name: "--by-capability", desc: "Group by capability with subtotals" },
294
+ { name: "--last", desc: "Recent sessions", takesValue: true },
295
+ { name: "--json", desc: "JSON output" },
296
+ { name: "--help", desc: "Show help" },
297
+ ],
298
+ },
299
+ {
300
+ name: "metrics",
301
+ desc: "Show session metrics",
302
+ flags: [
303
+ { name: "--last", desc: "Recent sessions", takesValue: true },
304
+ { name: "--json", desc: "JSON output" },
305
+ { name: "--help", desc: "Show help" },
306
+ ],
307
+ },
308
+ {
309
+ name: "spec",
310
+ desc: "Manage task specs",
311
+ flags: [{ name: "--help", desc: "Show help" }],
312
+ subcommands: [
313
+ {
314
+ name: "write",
315
+ desc: "Write a spec file",
316
+ flags: [
317
+ { name: "--body", desc: "Spec content", takesValue: true },
318
+ { name: "--agent", desc: "Agent attribution", takesValue: true },
319
+ { name: "--help", desc: "Show help" },
320
+ ],
321
+ },
322
+ ],
323
+ },
324
+ {
325
+ name: "coordinator",
326
+ desc: "Persistent coordinator agent",
327
+ flags: [
328
+ { name: "--json", desc: "JSON output" },
329
+ { name: "--help", desc: "Show help" },
330
+ ],
331
+ subcommands: [
332
+ {
333
+ name: "start",
334
+ desc: "Start coordinator",
335
+ flags: [
336
+ { name: "--attach", desc: "Attach to tmux session" },
337
+ { name: "--no-attach", desc: "Do not attach to tmux session" },
338
+ { name: "--watchdog", desc: "Auto-start watchdog daemon" },
339
+ { name: "--json", desc: "JSON output" },
340
+ ],
341
+ },
342
+ {
343
+ name: "stop",
344
+ desc: "Stop coordinator",
345
+ flags: [{ name: "--json", desc: "JSON output" }],
346
+ },
347
+ {
348
+ name: "status",
349
+ desc: "Show coordinator state",
350
+ flags: [{ name: "--json", desc: "JSON output" }],
351
+ },
352
+ ],
353
+ },
354
+ {
355
+ name: "supervisor",
356
+ desc: "Per-project supervisor agent",
357
+ flags: [
358
+ { name: "--json", desc: "JSON output" },
359
+ { name: "--help", desc: "Show help" },
360
+ ],
361
+ subcommands: [
362
+ {
363
+ name: "start",
364
+ desc: "Start supervisor",
365
+ flags: [
366
+ { name: "--task", desc: "Bead task ID", takesValue: true },
367
+ { name: "--name", desc: "Unique name", takesValue: true },
368
+ { name: "--parent", desc: "Parent agent", takesValue: true },
369
+ { name: "--depth", desc: "Hierarchy depth", takesValue: true },
370
+ { name: "--json", desc: "JSON output" },
371
+ ],
372
+ },
373
+ {
374
+ name: "stop",
375
+ desc: "Stop supervisor",
376
+ flags: [
377
+ { name: "--name", desc: "Supervisor name", takesValue: true },
378
+ { name: "--json", desc: "JSON output" },
379
+ ],
380
+ },
381
+ {
382
+ name: "status",
383
+ desc: "Show supervisor state",
384
+ flags: [
385
+ { name: "--name", desc: "Supervisor name", takesValue: true },
386
+ { name: "--json", desc: "JSON output" },
387
+ ],
388
+ },
389
+ ],
390
+ },
391
+ {
392
+ name: "hooks",
393
+ desc: "Manage orchestrator hooks",
394
+ flags: [
395
+ { name: "--json", desc: "JSON output" },
396
+ { name: "--help", desc: "Show help" },
397
+ ],
398
+ subcommands: [
399
+ {
400
+ name: "install",
401
+ desc: "Install hooks",
402
+ flags: [
403
+ { name: "--force", desc: "Overwrite existing hooks" },
404
+ { name: "--json", desc: "JSON output" },
405
+ ],
406
+ },
407
+ {
408
+ name: "uninstall",
409
+ desc: "Uninstall hooks",
410
+ flags: [{ name: "--json", desc: "JSON output" }],
411
+ },
412
+ {
413
+ name: "status",
414
+ desc: "Check if hooks are installed",
415
+ flags: [{ name: "--json", desc: "JSON output" }],
416
+ },
417
+ ],
418
+ },
419
+ {
420
+ name: "monitor",
421
+ desc: "Tier 2 monitor agent",
422
+ flags: [
423
+ { name: "--json", desc: "JSON output" },
424
+ { name: "--help", desc: "Show help" },
425
+ ],
426
+ subcommands: [
427
+ {
428
+ name: "start",
429
+ desc: "Start monitor",
430
+ flags: [
431
+ { name: "--attach", desc: "Attach to tmux session" },
432
+ { name: "--no-attach", desc: "Do not attach to tmux session" },
433
+ { name: "--json", desc: "JSON output" },
434
+ ],
435
+ },
436
+ {
437
+ name: "stop",
438
+ desc: "Stop monitor",
439
+ flags: [{ name: "--json", desc: "JSON output" }],
440
+ },
441
+ {
442
+ name: "status",
443
+ desc: "Show monitor state",
444
+ flags: [{ name: "--json", desc: "JSON output" }],
445
+ },
446
+ ],
447
+ },
448
+ {
449
+ name: "mail",
450
+ desc: "Mail system",
451
+ flags: [{ name: "--help", desc: "Show help" }],
452
+ subcommands: [
453
+ {
454
+ name: "send",
455
+ desc: "Send a message",
456
+ flags: [
457
+ { name: "--to", desc: "Recipient agent", takesValue: true },
458
+ { name: "--subject", desc: "Message subject", takesValue: true },
459
+ { name: "--body", desc: "Message body", takesValue: true },
460
+ { name: "--from", desc: "Sender name", takesValue: true },
461
+ { name: "--agent", desc: "Agent name", takesValue: true },
462
+ {
463
+ name: "--type",
464
+ desc: "Message type",
465
+ takesValue: true,
466
+ values: [
467
+ "status",
468
+ "question",
469
+ "result",
470
+ "error",
471
+ "worker_done",
472
+ "merge_ready",
473
+ "merged",
474
+ "merge_failed",
475
+ "escalation",
476
+ "health_check",
477
+ "dispatch",
478
+ "assign",
479
+ ],
480
+ },
481
+ {
482
+ name: "--priority",
483
+ desc: "Message priority",
484
+ takesValue: true,
485
+ values: ["low", "normal", "high", "urgent"],
486
+ },
487
+ { name: "--payload", desc: "Structured JSON payload", takesValue: true },
488
+ { name: "--json", desc: "JSON output" },
489
+ ],
490
+ },
491
+ {
492
+ name: "check",
493
+ desc: "Check inbox (unread messages)",
494
+ flags: [
495
+ { name: "--agent", desc: "Agent name", takesValue: true },
496
+ { name: "--inject", desc: "Inject messages" },
497
+ { name: "--debounce", desc: "Debounce interval in ms", takesValue: true },
498
+ { name: "--json", desc: "JSON output" },
499
+ ],
500
+ },
501
+ {
502
+ name: "list",
503
+ desc: "List messages with filters",
504
+ flags: [
505
+ { name: "--from", desc: "Filter by sender", takesValue: true },
506
+ { name: "--to", desc: "Filter by recipient", takesValue: true },
507
+ { name: "--agent", desc: "Agent name", takesValue: true },
508
+ { name: "--unread", desc: "Show only unread messages" },
509
+ { name: "--json", desc: "JSON output" },
510
+ ],
511
+ },
512
+ {
513
+ name: "read",
514
+ desc: "Mark message as read",
515
+ },
516
+ {
517
+ name: "reply",
518
+ desc: "Reply to a message",
519
+ flags: [
520
+ { name: "--body", desc: "Reply body", takesValue: true },
521
+ { name: "--from", desc: "Sender name", takesValue: true },
522
+ { name: "--agent", desc: "Agent name", takesValue: true },
523
+ { name: "--json", desc: "JSON output" },
524
+ ],
525
+ },
526
+ {
527
+ name: "purge",
528
+ desc: "Delete old messages",
529
+ flags: [
530
+ { name: "--all", desc: "Delete all messages" },
531
+ { name: "--days", desc: "Delete messages older than N days", takesValue: true },
532
+ { name: "--agent", desc: "Agent name", takesValue: true },
533
+ { name: "--json", desc: "JSON output" },
534
+ ],
535
+ },
536
+ ],
537
+ },
538
+ {
539
+ name: "group",
540
+ desc: "Task groups",
541
+ flags: [
542
+ { name: "--json", desc: "JSON output" },
543
+ { name: "--skip-validation", desc: "Skip beads checks" },
544
+ { name: "--help", desc: "Show help" },
545
+ ],
546
+ subcommands: [
547
+ { name: "create", desc: "Create a new task group" },
548
+ { name: "status", desc: "Show progress for one or all groups" },
549
+ { name: "add", desc: "Add issues to a group" },
550
+ { name: "remove", desc: "Remove issues from a group" },
551
+ { name: "list", desc: "List all groups (summary)" },
552
+ ],
553
+ },
554
+ {
555
+ name: "worktree",
556
+ desc: "Manage worktrees",
557
+ flags: [
558
+ { name: "--json", desc: "JSON output" },
559
+ { name: "--help", desc: "Show help" },
560
+ ],
561
+ subcommands: [
562
+ {
563
+ name: "list",
564
+ desc: "List worktrees with status",
565
+ flags: [{ name: "--json", desc: "JSON output" }],
566
+ },
567
+ {
568
+ name: "clean",
569
+ desc: "Remove completed worktrees",
570
+ flags: [
571
+ { name: "--completed", desc: "Only finished agents" },
572
+ { name: "--all", desc: "Force remove all" },
573
+ { name: "--json", desc: "JSON output" },
574
+ ],
575
+ },
576
+ ],
577
+ },
578
+ {
579
+ name: "run",
580
+ desc: "Manage runs",
581
+ flags: [
582
+ { name: "--json", desc: "JSON output" },
583
+ { name: "--help", desc: "Show help" },
584
+ ],
585
+ subcommands: [
586
+ {
587
+ name: "list",
588
+ desc: "List recent runs",
589
+ flags: [
590
+ { name: "--last", desc: "Number of runs to show", takesValue: true },
591
+ { name: "--json", desc: "JSON output" },
592
+ ],
593
+ },
594
+ {
595
+ name: "show",
596
+ desc: "Show run details",
597
+ flags: [{ name: "--json", desc: "JSON output" }],
598
+ },
599
+ {
600
+ name: "complete",
601
+ desc: "Mark current run as completed",
602
+ flags: [{ name: "--json", desc: "JSON output" }],
603
+ },
604
+ ],
605
+ },
606
+ ] as const;
607
+
608
+ export function generateBash(): string {
609
+ const lines: string[] = [
610
+ "# Bash completion for overstory",
611
+ "# Source this file to enable completions:",
612
+ "# source <(overstory --completions bash)",
613
+ "",
614
+ "_overstory() {",
615
+ " local cur prev words cword",
616
+ " _init_completion || return",
617
+ "",
618
+ " local commands='init sling prime stop status dashboard inspect merge nudge clean doctor log logs watch trace errors feed replay costs metrics spec coordinator supervisor hooks monitor mail group worktree run'",
619
+ "",
620
+ " # Top-level completion",
621
+ " if [[ $cword -eq 1 ]]; then",
622
+ ' COMPREPLY=($(compgen -W "$commands --help --version --completions" -- "$cur"))',
623
+ " return",
624
+ " fi",
625
+ "",
626
+ // Shell variable expansion - not a template string placeholder
627
+ ` local command="\${words[1]}"`,
628
+ "",
629
+ ];
630
+
631
+ // Generate command-specific completions
632
+ for (const cmd of COMMANDS) {
633
+ lines.push(` if [[ $command == "${cmd.name}" ]]; then`);
634
+
635
+ if (cmd.subcommands && cmd.subcommands.length > 0) {
636
+ // Command with subcommands
637
+ const subcmdNames = cmd.subcommands.map((s) => s.name).join(" ");
638
+ lines.push(" if [[ $cword -eq 2 ]]; then");
639
+ lines.push(` COMPREPLY=($(compgen -W "${subcmdNames}" -- "$cur"))`);
640
+ lines.push(" return");
641
+ lines.push(" fi");
642
+
643
+ // Subcommand flags
644
+ for (const subcmd of cmd.subcommands) {
645
+ if (subcmd.flags && subcmd.flags.length > 0) {
646
+ const subcmdFlags = subcmd.flags.map((f) => f.name).join(" ");
647
+ lines.push(` if [[ \${words[2]} == "${subcmd.name}" ]]; then`);
648
+ lines.push(` COMPREPLY=($(compgen -W "${subcmdFlags}" -- "$cur"))`);
649
+ lines.push(" return");
650
+ lines.push(" fi");
651
+ }
652
+ }
653
+ }
654
+
655
+ // Command-level flags
656
+ if (cmd.flags && cmd.flags.length > 0) {
657
+ const cmdFlags = cmd.flags.map((f) => f.name).join(" ");
658
+ lines.push(` COMPREPLY=($(compgen -W "${cmdFlags}" -- "$cur"))`);
659
+ lines.push(" return");
660
+ }
661
+
662
+ lines.push(" fi");
663
+ lines.push("");
664
+ }
665
+
666
+ lines.push(" return 0");
667
+ lines.push("}");
668
+ lines.push("");
669
+ lines.push("complete -F _overstory overstory");
670
+
671
+ return lines.join("\n");
672
+ }
673
+
674
+ export function generateZsh(): string {
675
+ const lines: string[] = [
676
+ "#compdef overstory",
677
+ "# Zsh completion for overstory",
678
+ "# Place this file in your fpath or source it:",
679
+ "# source <(overstory --completions zsh)",
680
+ "",
681
+ "_overstory() {",
682
+ " local -a commands",
683
+ " commands=(",
684
+ ];
685
+
686
+ // List all commands
687
+ for (const cmd of COMMANDS) {
688
+ lines.push(` '${cmd.name}:${cmd.desc}'`);
689
+ }
690
+ lines.push(" )");
691
+ lines.push("");
692
+
693
+ lines.push(" local -a global_opts");
694
+ lines.push(" global_opts=(");
695
+ lines.push(" '--help[Show help]'");
696
+ lines.push(" '--version[Show version]'");
697
+ lines.push(" '--completions[Generate shell completions]:shell:(bash zsh fish)'");
698
+ lines.push(" )");
699
+ lines.push("");
700
+
701
+ lines.push(" if (( CURRENT == 2 )); then");
702
+ lines.push(" _describe 'command' commands");
703
+ lines.push(" _arguments $global_opts");
704
+ lines.push(" return");
705
+ lines.push(" fi");
706
+ lines.push("");
707
+
708
+ lines.push(' local command="$words[2]"');
709
+ lines.push("");
710
+ lines.push(' case "$command" in');
711
+
712
+ // Generate completions for each command
713
+ for (const cmd of COMMANDS) {
714
+ lines.push(` ${cmd.name})`);
715
+
716
+ if (cmd.subcommands && cmd.subcommands.length > 0) {
717
+ lines.push(" local -a subcommands");
718
+ lines.push(" subcommands=(");
719
+ for (const subcmd of cmd.subcommands) {
720
+ lines.push(` '${subcmd.name}:${subcmd.desc}'`);
721
+ }
722
+ lines.push(" )");
723
+ lines.push("");
724
+ lines.push(" if (( CURRENT == 3 )); then");
725
+ lines.push(" _describe 'subcommand' subcommands");
726
+ lines.push(" return");
727
+ lines.push(" fi");
728
+
729
+ // Subcommand-specific flags
730
+ for (const subcmd of cmd.subcommands) {
731
+ if (subcmd.flags && subcmd.flags.length > 0) {
732
+ lines.push(` if [[ $words[3] == "${subcmd.name}" ]]; then`);
733
+ lines.push(" _arguments \\");
734
+ for (const flag of subcmd.flags) {
735
+ if (flag.values) {
736
+ const vals = flag.values.join(" ");
737
+ lines.push(` '${flag.name}[${flag.desc}]:value:(${vals})' \\`);
738
+ } else if (flag.takesValue) {
739
+ lines.push(` '${flag.name}[${flag.desc}]:value:' \\`);
740
+ } else {
741
+ lines.push(` '${flag.name}[${flag.desc}]' \\`);
742
+ }
743
+ }
744
+ const lastLine = lines[lines.length - 1];
745
+ if (lastLine) {
746
+ lines[lines.length - 1] = lastLine.replace(" \\", "");
747
+ }
748
+ lines.push(" return");
749
+ lines.push(" fi");
750
+ }
751
+ }
752
+ }
753
+
754
+ // Command-level flags
755
+ if (cmd.flags && cmd.flags.length > 0) {
756
+ lines.push(" _arguments \\");
757
+ for (const flag of cmd.flags) {
758
+ if (flag.values) {
759
+ const vals = flag.values.join(" ");
760
+ lines.push(` '${flag.name}[${flag.desc}]:value:(${vals})' \\`);
761
+ } else if (flag.takesValue) {
762
+ lines.push(` '${flag.name}[${flag.desc}]:value:' \\`);
763
+ } else {
764
+ lines.push(` '${flag.name}[${flag.desc}]' \\`);
765
+ }
766
+ }
767
+ const lastLine = lines[lines.length - 1];
768
+ if (lastLine) {
769
+ lines[lines.length - 1] = lastLine.replace(" \\", "");
770
+ }
771
+ }
772
+
773
+ lines.push(" ;;");
774
+ }
775
+
776
+ lines.push(" esac");
777
+ lines.push("}");
778
+ lines.push("");
779
+ lines.push('_overstory "$@"');
780
+
781
+ return lines.join("\n");
782
+ }
783
+
784
+ export function generateFish(): string {
785
+ const lines: string[] = [
786
+ "# Fish completion for overstory",
787
+ "# Place this file in ~/.config/fish/completions/overstory.fish or source it:",
788
+ "# overstory --completions fish | source",
789
+ "",
790
+ "# Remove all existing completions for overstory",
791
+ "complete -c overstory -e",
792
+ "",
793
+ "# Global options",
794
+ "complete -c overstory -l help -d 'Show help'",
795
+ "complete -c overstory -l version -d 'Show version'",
796
+ "complete -c overstory -l completions -d 'Generate shell completions' -xa 'bash zsh fish'",
797
+ "",
798
+ ];
799
+
800
+ // Generate completions for each command
801
+ for (const cmd of COMMANDS) {
802
+ // Command name
803
+ lines.push(`# ${cmd.desc}`);
804
+ lines.push(
805
+ `complete -c overstory -f -n '__fish_use_subcommand' -a '${cmd.name}' -d '${cmd.desc}'`,
806
+ );
807
+
808
+ if (cmd.subcommands && cmd.subcommands.length > 0) {
809
+ // Subcommand names
810
+ for (const subcmd of cmd.subcommands) {
811
+ lines.push(
812
+ `complete -c overstory -f -n '__fish_seen_subcommand_from ${cmd.name}; and not __fish_seen_subcommand_from ${cmd.subcommands.map((s) => s.name).join(" ")}' -a '${subcmd.name}' -d '${subcmd.desc}'`,
813
+ );
814
+
815
+ // Subcommand flags
816
+ if (subcmd.flags && subcmd.flags.length > 0) {
817
+ for (const flag of subcmd.flags) {
818
+ const flagName = flag.name.replace(/^--/, "");
819
+ const cond = `'__fish_seen_subcommand_from ${cmd.name}; and __fish_seen_subcommand_from ${subcmd.name}'`;
820
+
821
+ if (flag.values) {
822
+ lines.push(
823
+ `complete -c overstory -f -n ${cond} -l '${flagName}' -d '${flag.desc}' -xa '${flag.values.join(" ")}'`,
824
+ );
825
+ } else if (flag.takesValue) {
826
+ lines.push(`complete -c overstory -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
827
+ } else {
828
+ lines.push(`complete -c overstory -f -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
829
+ }
830
+ }
831
+ }
832
+ }
833
+ }
834
+
835
+ // Command-level flags
836
+ if (cmd.flags && cmd.flags.length > 0) {
837
+ for (const flag of cmd.flags) {
838
+ const flagName = flag.name.replace(/^--/, "");
839
+ const cond = `'__fish_seen_subcommand_from ${cmd.name}'`;
840
+
841
+ if (flag.values) {
842
+ lines.push(
843
+ `complete -c overstory -f -n ${cond} -l '${flagName}' -d '${flag.desc}' -xa '${flag.values.join(" ")}'`,
844
+ );
845
+ } else if (flag.takesValue) {
846
+ lines.push(`complete -c overstory -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
847
+ } else {
848
+ lines.push(`complete -c overstory -f -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
849
+ }
850
+ }
851
+ }
852
+
853
+ lines.push("");
854
+ }
855
+
856
+ return lines.join("\n");
857
+ }
858
+
859
+ export function completionsCommand(args: string[]): void {
860
+ const shell = args[0];
861
+
862
+ if (!shell) {
863
+ process.stderr.write("Error: missing shell argument\n");
864
+ process.stderr.write("Usage: overstory --completions <bash|zsh|fish>\n");
865
+ process.exit(1);
866
+ }
867
+
868
+ let script: string;
869
+ switch (shell.toLowerCase()) {
870
+ case "bash":
871
+ script = generateBash();
872
+ break;
873
+ case "zsh":
874
+ script = generateZsh();
875
+ break;
876
+ case "fish":
877
+ script = generateFish();
878
+ break;
879
+ default:
880
+ process.stderr.write(`Error: unknown shell '${shell}'\n`);
881
+ process.stderr.write("Supported shells: bash, zsh, fish\n");
882
+ process.exit(1);
883
+ }
884
+
885
+ process.stdout.write(script);
886
+ process.stdout.write("\n");
887
+ }