@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,342 @@
1
+ /**
2
+ * Tests for shell completion generation.
3
+ */
4
+
5
+ import { describe, expect, it, mock } from "bun:test";
6
+ import {
7
+ COMMANDS,
8
+ completionsCommand,
9
+ generateBash,
10
+ generateFish,
11
+ generateZsh,
12
+ } from "./completions.ts";
13
+
14
+ describe("COMMANDS array", () => {
15
+ it("should have exactly 30 commands", () => {
16
+ expect(COMMANDS).toHaveLength(30);
17
+ });
18
+
19
+ it("should include all expected command names", () => {
20
+ const names = COMMANDS.map((c) => c.name);
21
+ expect(names).toContain("agents");
22
+ expect(names).toContain("init");
23
+ expect(names).toContain("sling");
24
+ expect(names).toContain("prime");
25
+ expect(names).toContain("status");
26
+ expect(names).toContain("dashboard");
27
+ expect(names).toContain("inspect");
28
+ expect(names).toContain("merge");
29
+ expect(names).toContain("nudge");
30
+ expect(names).toContain("clean");
31
+ expect(names).toContain("doctor");
32
+ expect(names).toContain("log");
33
+ expect(names).toContain("watch");
34
+ expect(names).toContain("trace");
35
+ expect(names).toContain("errors");
36
+ expect(names).toContain("replay");
37
+ expect(names).toContain("costs");
38
+ expect(names).toContain("metrics");
39
+ expect(names).toContain("spec");
40
+ expect(names).toContain("coordinator");
41
+ expect(names).toContain("supervisor");
42
+ expect(names).toContain("hooks");
43
+ expect(names).toContain("monitor");
44
+ expect(names).toContain("mail");
45
+ expect(names).toContain("group");
46
+ expect(names).toContain("worktree");
47
+ expect(names).toContain("run");
48
+ expect(names).toContain("feed");
49
+ expect(names).toContain("logs");
50
+ expect(names).toContain("stop");
51
+ });
52
+ });
53
+
54
+ describe("generateBash", () => {
55
+ it("should return a bash completion script", () => {
56
+ const script = generateBash();
57
+ expect(script).toContain("_overstory()");
58
+ expect(script).toContain("complete -F _overstory overstory");
59
+ expect(script).toContain("_init_completion");
60
+ });
61
+
62
+ it("should include all 27 command names", () => {
63
+ const script = generateBash();
64
+ for (const cmd of COMMANDS) {
65
+ expect(script).toContain(cmd.name);
66
+ }
67
+ });
68
+
69
+ it("should include sling command", () => {
70
+ const script = generateBash();
71
+ expect(script).toContain("sling");
72
+ // The flag names are in the script
73
+ expect(script).toContain("--capability");
74
+ });
75
+
76
+ it("should include mail subcommands", () => {
77
+ const script = generateBash();
78
+ expect(script).toContain("send");
79
+ expect(script).toContain("check");
80
+ expect(script).toContain("list");
81
+ expect(script).toContain("read");
82
+ expect(script).toContain("reply");
83
+ expect(script).toContain("purge");
84
+ });
85
+ });
86
+
87
+ describe("generateZsh", () => {
88
+ it("should return a zsh completion script", () => {
89
+ const script = generateZsh();
90
+ expect(script).toContain("#compdef overstory");
91
+ expect(script).toContain("_overstory()");
92
+ expect(script).toContain("_describe");
93
+ expect(script).toContain("_arguments");
94
+ });
95
+
96
+ it("should include all 27 command names", () => {
97
+ const script = generateZsh();
98
+ for (const cmd of COMMANDS) {
99
+ expect(script).toContain(cmd.name);
100
+ }
101
+ });
102
+
103
+ it("should include sling command with capability flag", () => {
104
+ const script = generateZsh();
105
+ expect(script).toContain("sling");
106
+ expect(script).toContain("--capability");
107
+ expect(script).toContain("builder");
108
+ expect(script).toContain("scout");
109
+ });
110
+
111
+ it("should include global options", () => {
112
+ const script = generateZsh();
113
+ expect(script).toContain("--help");
114
+ expect(script).toContain("--version");
115
+ expect(script).toContain("--completions");
116
+ });
117
+ });
118
+
119
+ describe("generateFish", () => {
120
+ it("should return a fish completion script", () => {
121
+ const script = generateFish();
122
+ expect(script).toContain("complete -c overstory");
123
+ expect(script).toContain("__fish_use_subcommand");
124
+ });
125
+
126
+ it("should include all 27 command names", () => {
127
+ const script = generateFish();
128
+ for (const cmd of COMMANDS) {
129
+ expect(script).toContain(cmd.name);
130
+ }
131
+ });
132
+
133
+ it("should include capability values for sling command", () => {
134
+ const slingCmd = COMMANDS.find((c) => c.name === "sling");
135
+ expect(slingCmd).toBeDefined();
136
+ const capabilityFlag = slingCmd?.flags?.find((f) => f.name === "--capability");
137
+ expect(capabilityFlag?.values).toContain("builder");
138
+ });
139
+
140
+ it("should include message type values for mail send", () => {
141
+ const script = generateFish();
142
+ expect(script).toContain("status");
143
+ expect(script).toContain("question");
144
+ expect(script).toContain("result");
145
+ expect(script).toContain("error");
146
+ expect(script).toContain("worker_done");
147
+ });
148
+ });
149
+
150
+ describe("completionsCommand", () => {
151
+ it("should write bash completion to stdout", () => {
152
+ const originalWrite = process.stdout.write;
153
+ let output = "";
154
+
155
+ // Mock stdout.write to capture output
156
+ process.stdout.write = mock((chunk: unknown) => {
157
+ output += String(chunk);
158
+ return true;
159
+ });
160
+
161
+ try {
162
+ completionsCommand(["bash"]);
163
+ expect(output).toContain("_overstory()");
164
+ expect(output).toContain("complete -F _overstory overstory");
165
+ } finally {
166
+ process.stdout.write = originalWrite;
167
+ }
168
+ });
169
+
170
+ it("should write zsh completion to stdout", () => {
171
+ const originalWrite = process.stdout.write;
172
+ let output = "";
173
+
174
+ process.stdout.write = mock((chunk: unknown) => {
175
+ output += String(chunk);
176
+ return true;
177
+ });
178
+
179
+ try {
180
+ completionsCommand(["zsh"]);
181
+ expect(output).toContain("#compdef overstory");
182
+ expect(output).toContain("_overstory()");
183
+ } finally {
184
+ process.stdout.write = originalWrite;
185
+ }
186
+ });
187
+
188
+ it("should write fish completion to stdout", () => {
189
+ const originalWrite = process.stdout.write;
190
+ let output = "";
191
+
192
+ process.stdout.write = mock((chunk: unknown) => {
193
+ output += String(chunk);
194
+ return true;
195
+ });
196
+
197
+ try {
198
+ completionsCommand(["fish"]);
199
+ expect(output).toContain("complete -c overstory");
200
+ } finally {
201
+ process.stdout.write = originalWrite;
202
+ }
203
+ });
204
+
205
+ it("should exit with error for missing shell argument", () => {
206
+ const originalExit = process.exit;
207
+ const originalStderr = process.stderr.write;
208
+ let exitCode: number | undefined;
209
+ let stderrOutput = "";
210
+
211
+ process.exit = mock((code?: string | number | null | undefined) => {
212
+ exitCode = typeof code === "number" ? code : 1;
213
+ throw new Error("process.exit called");
214
+ }) as never;
215
+
216
+ process.stderr.write = mock((chunk: unknown) => {
217
+ stderrOutput += String(chunk);
218
+ return true;
219
+ });
220
+
221
+ try {
222
+ expect(() => completionsCommand([])).toThrow("process.exit called");
223
+ expect(exitCode).toBe(1);
224
+ expect(stderrOutput).toContain("missing shell argument");
225
+ } finally {
226
+ process.exit = originalExit;
227
+ process.stderr.write = originalStderr;
228
+ }
229
+ });
230
+
231
+ it("should exit with error for unknown shell", () => {
232
+ const originalExit = process.exit;
233
+ const originalStderr = process.stderr.write;
234
+ let exitCode: number | undefined;
235
+ let stderrOutput = "";
236
+
237
+ process.exit = mock((code?: string | number | null | undefined) => {
238
+ exitCode = typeof code === "number" ? code : 1;
239
+ throw new Error("process.exit called");
240
+ }) as never;
241
+
242
+ process.stderr.write = mock((chunk: unknown) => {
243
+ stderrOutput += String(chunk);
244
+ return true;
245
+ });
246
+
247
+ try {
248
+ expect(() => completionsCommand(["powershell"])).toThrow("process.exit called");
249
+ expect(exitCode).toBe(1);
250
+ expect(stderrOutput).toContain("unknown shell");
251
+ expect(stderrOutput).toContain("powershell");
252
+ } finally {
253
+ process.exit = originalExit;
254
+ process.stderr.write = originalStderr;
255
+ }
256
+ });
257
+ });
258
+
259
+ describe("Flag completions", () => {
260
+ it("should have fixed values for --capability flag", () => {
261
+ const sling = COMMANDS.find((c) => c.name === "sling");
262
+ expect(sling).toBeDefined();
263
+
264
+ const capFlag = sling?.flags?.find((f) => f.name === "--capability");
265
+ expect(capFlag).toBeDefined();
266
+ expect(capFlag?.takesValue).toBe(true);
267
+ expect(capFlag?.values).toEqual(["builder", "scout", "reviewer", "lead", "merger"]);
268
+ });
269
+
270
+ it("should have fixed values for --type flag in mail send", () => {
271
+ const mail = COMMANDS.find((c) => c.name === "mail");
272
+ expect(mail).toBeDefined();
273
+
274
+ const sendSub = mail?.subcommands?.find((s) => s.name === "send");
275
+ expect(sendSub).toBeDefined();
276
+
277
+ const typeFlag = sendSub?.flags?.find((f) => f.name === "--type");
278
+ expect(typeFlag).toBeDefined();
279
+ expect(typeFlag?.takesValue).toBe(true);
280
+ expect(typeFlag?.values).toContain("status");
281
+ expect(typeFlag?.values).toContain("question");
282
+ expect(typeFlag?.values).toContain("result");
283
+ expect(typeFlag?.values).toContain("error");
284
+ expect(typeFlag?.values).toContain("worker_done");
285
+ });
286
+
287
+ it("should have fixed values for --priority flag in mail send", () => {
288
+ const mail = COMMANDS.find((c) => c.name === "mail");
289
+ const sendSub = mail?.subcommands?.find((s) => s.name === "send");
290
+ const priorityFlag = sendSub?.flags?.find((f) => f.name === "--priority");
291
+
292
+ expect(priorityFlag).toBeDefined();
293
+ expect(priorityFlag?.takesValue).toBe(true);
294
+ expect(priorityFlag?.values).toEqual(["low", "normal", "high", "urgent"]);
295
+ });
296
+
297
+ it("should have fixed values for --category flag in doctor", () => {
298
+ const doctor = COMMANDS.find((c) => c.name === "doctor");
299
+ const catFlag = doctor?.flags?.find((f) => f.name === "--category");
300
+
301
+ expect(catFlag).toBeDefined();
302
+ expect(catFlag?.takesValue).toBe(true);
303
+ expect(catFlag?.values).toContain("dependencies");
304
+ expect(catFlag?.values).toContain("config");
305
+ expect(catFlag?.values).toContain("databases");
306
+ });
307
+ });
308
+
309
+ describe("Subcommands", () => {
310
+ it("should have correct subcommands for mail command", () => {
311
+ const mail = COMMANDS.find((c) => c.name === "mail");
312
+ expect(mail?.subcommands).toBeDefined();
313
+
314
+ const subNames = mail?.subcommands?.map((s) => s.name);
315
+ expect(subNames).toContain("send");
316
+ expect(subNames).toContain("check");
317
+ expect(subNames).toContain("list");
318
+ expect(subNames).toContain("read");
319
+ expect(subNames).toContain("reply");
320
+ expect(subNames).toContain("purge");
321
+ });
322
+
323
+ it("should have correct subcommands for coordinator command", () => {
324
+ const coordinator = COMMANDS.find((c) => c.name === "coordinator");
325
+ expect(coordinator?.subcommands).toBeDefined();
326
+
327
+ const subNames = coordinator?.subcommands?.map((s) => s.name);
328
+ expect(subNames).toContain("start");
329
+ expect(subNames).toContain("stop");
330
+ expect(subNames).toContain("status");
331
+ });
332
+
333
+ it("should have correct subcommands for run command", () => {
334
+ const run = COMMANDS.find((c) => c.name === "run");
335
+ expect(run?.subcommands).toBeDefined();
336
+
337
+ const subNames = run?.subcommands?.map((s) => s.name);
338
+ expect(subNames).toContain("list");
339
+ expect(subNames).toContain("show");
340
+ expect(subNames).toContain("complete");
341
+ });
342
+ });