opencode-swarm-plugin 0.44.0 → 0.44.2

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 (215) hide show
  1. package/bin/swarm.serve.test.ts +6 -4
  2. package/bin/swarm.ts +18 -12
  3. package/dist/compaction-prompt-scoring.js +139 -0
  4. package/dist/eval-capture.js +12811 -0
  5. package/dist/hive.d.ts.map +1 -1
  6. package/dist/hive.js +14834 -0
  7. package/dist/index.d.ts +18 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +7743 -62593
  10. package/dist/plugin.js +24052 -78907
  11. package/dist/swarm-orchestrate.d.ts.map +1 -1
  12. package/dist/swarm-prompts.d.ts.map +1 -1
  13. package/dist/swarm-prompts.js +39407 -0
  14. package/dist/swarm-review.d.ts.map +1 -1
  15. package/dist/swarm-validation.d.ts +127 -0
  16. package/dist/swarm-validation.d.ts.map +1 -0
  17. package/dist/validators/index.d.ts +7 -0
  18. package/dist/validators/index.d.ts.map +1 -0
  19. package/dist/validators/schema-validator.d.ts +58 -0
  20. package/dist/validators/schema-validator.d.ts.map +1 -0
  21. package/package.json +17 -5
  22. package/.changeset/swarm-insights-data-layer.md +0 -63
  23. package/.hive/analysis/eval-failure-analysis-2025-12-25.md +0 -331
  24. package/.hive/analysis/session-data-quality-audit.md +0 -320
  25. package/.hive/eval-results.json +0 -483
  26. package/.hive/issues.jsonl +0 -138
  27. package/.hive/memories.jsonl +0 -729
  28. package/.opencode/eval-history.jsonl +0 -327
  29. package/.turbo/turbo-build.log +0 -9
  30. package/CHANGELOG.md +0 -2286
  31. package/SCORER-ANALYSIS.md +0 -598
  32. package/docs/analysis/subagent-coordination-patterns.md +0 -902
  33. package/docs/analysis-socratic-planner-pattern.md +0 -504
  34. package/docs/planning/ADR-001-monorepo-structure.md +0 -171
  35. package/docs/planning/ADR-002-package-extraction.md +0 -393
  36. package/docs/planning/ADR-003-performance-improvements.md +0 -451
  37. package/docs/planning/ADR-004-message-queue-features.md +0 -187
  38. package/docs/planning/ADR-005-devtools-observability.md +0 -202
  39. package/docs/planning/ADR-007-swarm-enhancements-worktree-review.md +0 -168
  40. package/docs/planning/ADR-008-worker-handoff-protocol.md +0 -293
  41. package/docs/planning/ADR-009-oh-my-opencode-patterns.md +0 -353
  42. package/docs/planning/ADR-010-cass-inhousing.md +0 -1215
  43. package/docs/planning/ROADMAP.md +0 -368
  44. package/docs/semantic-memory-cli-syntax.md +0 -123
  45. package/docs/swarm-mail-architecture.md +0 -1147
  46. package/docs/testing/context-recovery-test.md +0 -470
  47. package/evals/ARCHITECTURE.md +0 -1189
  48. package/evals/README.md +0 -768
  49. package/evals/compaction-prompt.eval.ts +0 -149
  50. package/evals/compaction-resumption.eval.ts +0 -289
  51. package/evals/coordinator-behavior.eval.ts +0 -307
  52. package/evals/coordinator-session.eval.ts +0 -154
  53. package/evals/evalite.config.ts.bak +0 -15
  54. package/evals/example.eval.ts +0 -31
  55. package/evals/fixtures/cass-baseline.ts +0 -217
  56. package/evals/fixtures/compaction-cases.ts +0 -350
  57. package/evals/fixtures/compaction-prompt-cases.ts +0 -311
  58. package/evals/fixtures/coordinator-sessions.ts +0 -328
  59. package/evals/fixtures/decomposition-cases.ts +0 -105
  60. package/evals/lib/compaction-loader.test.ts +0 -248
  61. package/evals/lib/compaction-loader.ts +0 -320
  62. package/evals/lib/data-loader.evalite-test.ts +0 -289
  63. package/evals/lib/data-loader.test.ts +0 -345
  64. package/evals/lib/data-loader.ts +0 -281
  65. package/evals/lib/llm.ts +0 -115
  66. package/evals/scorers/compaction-prompt-scorers.ts +0 -145
  67. package/evals/scorers/compaction-scorers.ts +0 -305
  68. package/evals/scorers/coordinator-discipline.evalite-test.ts +0 -539
  69. package/evals/scorers/coordinator-discipline.ts +0 -325
  70. package/evals/scorers/index.test.ts +0 -146
  71. package/evals/scorers/index.ts +0 -328
  72. package/evals/scorers/outcome-scorers.evalite-test.ts +0 -27
  73. package/evals/scorers/outcome-scorers.ts +0 -349
  74. package/evals/swarm-decomposition.eval.ts +0 -121
  75. package/examples/commands/swarm.md +0 -745
  76. package/examples/plugin-wrapper-template.ts +0 -2515
  77. package/examples/skills/hive-workflow/SKILL.md +0 -212
  78. package/examples/skills/skill-creator/SKILL.md +0 -223
  79. package/examples/skills/swarm-coordination/SKILL.md +0 -292
  80. package/global-skills/cli-builder/SKILL.md +0 -344
  81. package/global-skills/cli-builder/references/advanced-patterns.md +0 -244
  82. package/global-skills/learning-systems/SKILL.md +0 -644
  83. package/global-skills/skill-creator/LICENSE.txt +0 -202
  84. package/global-skills/skill-creator/SKILL.md +0 -352
  85. package/global-skills/skill-creator/references/output-patterns.md +0 -82
  86. package/global-skills/skill-creator/references/workflows.md +0 -28
  87. package/global-skills/swarm-coordination/SKILL.md +0 -995
  88. package/global-skills/swarm-coordination/references/coordinator-patterns.md +0 -235
  89. package/global-skills/swarm-coordination/references/strategies.md +0 -138
  90. package/global-skills/system-design/SKILL.md +0 -213
  91. package/global-skills/testing-patterns/SKILL.md +0 -430
  92. package/global-skills/testing-patterns/references/dependency-breaking-catalog.md +0 -586
  93. package/opencode-swarm-plugin-0.30.7.tgz +0 -0
  94. package/opencode-swarm-plugin-0.31.0.tgz +0 -0
  95. package/scripts/cleanup-test-memories.ts +0 -346
  96. package/scripts/init-skill.ts +0 -222
  97. package/scripts/migrate-unknown-sessions.ts +0 -349
  98. package/scripts/validate-skill.ts +0 -204
  99. package/src/agent-mail.ts +0 -1724
  100. package/src/anti-patterns.test.ts +0 -1167
  101. package/src/anti-patterns.ts +0 -448
  102. package/src/compaction-capture.integration.test.ts +0 -257
  103. package/src/compaction-hook.test.ts +0 -838
  104. package/src/compaction-hook.ts +0 -1204
  105. package/src/compaction-observability.integration.test.ts +0 -139
  106. package/src/compaction-observability.test.ts +0 -187
  107. package/src/compaction-observability.ts +0 -324
  108. package/src/compaction-prompt-scorers.test.ts +0 -475
  109. package/src/compaction-prompt-scoring.ts +0 -300
  110. package/src/contributor-tools.test.ts +0 -133
  111. package/src/contributor-tools.ts +0 -201
  112. package/src/dashboard.test.ts +0 -611
  113. package/src/dashboard.ts +0 -462
  114. package/src/error-enrichment.test.ts +0 -403
  115. package/src/error-enrichment.ts +0 -219
  116. package/src/eval-capture.test.ts +0 -1015
  117. package/src/eval-capture.ts +0 -929
  118. package/src/eval-gates.test.ts +0 -306
  119. package/src/eval-gates.ts +0 -218
  120. package/src/eval-history.test.ts +0 -508
  121. package/src/eval-history.ts +0 -214
  122. package/src/eval-learning.test.ts +0 -378
  123. package/src/eval-learning.ts +0 -360
  124. package/src/eval-runner.test.ts +0 -223
  125. package/src/eval-runner.ts +0 -402
  126. package/src/export-tools.test.ts +0 -476
  127. package/src/export-tools.ts +0 -257
  128. package/src/hive.integration.test.ts +0 -2241
  129. package/src/hive.ts +0 -1628
  130. package/src/index.ts +0 -940
  131. package/src/learning.integration.test.ts +0 -1815
  132. package/src/learning.ts +0 -1079
  133. package/src/logger.test.ts +0 -189
  134. package/src/logger.ts +0 -135
  135. package/src/mandate-promotion.test.ts +0 -473
  136. package/src/mandate-promotion.ts +0 -239
  137. package/src/mandate-storage.integration.test.ts +0 -601
  138. package/src/mandate-storage.test.ts +0 -578
  139. package/src/mandate-storage.ts +0 -794
  140. package/src/mandates.ts +0 -540
  141. package/src/memory-tools.test.ts +0 -195
  142. package/src/memory-tools.ts +0 -344
  143. package/src/memory.integration.test.ts +0 -334
  144. package/src/memory.test.ts +0 -158
  145. package/src/memory.ts +0 -527
  146. package/src/model-selection.test.ts +0 -188
  147. package/src/model-selection.ts +0 -68
  148. package/src/observability-tools.test.ts +0 -359
  149. package/src/observability-tools.ts +0 -871
  150. package/src/output-guardrails.test.ts +0 -438
  151. package/src/output-guardrails.ts +0 -381
  152. package/src/pattern-maturity.test.ts +0 -1160
  153. package/src/pattern-maturity.ts +0 -525
  154. package/src/planning-guardrails.test.ts +0 -491
  155. package/src/planning-guardrails.ts +0 -438
  156. package/src/plugin.ts +0 -23
  157. package/src/post-compaction-tracker.test.ts +0 -251
  158. package/src/post-compaction-tracker.ts +0 -237
  159. package/src/query-tools.test.ts +0 -636
  160. package/src/query-tools.ts +0 -324
  161. package/src/rate-limiter.integration.test.ts +0 -466
  162. package/src/rate-limiter.ts +0 -774
  163. package/src/replay-tools.test.ts +0 -496
  164. package/src/replay-tools.ts +0 -240
  165. package/src/repo-crawl.integration.test.ts +0 -441
  166. package/src/repo-crawl.ts +0 -610
  167. package/src/schemas/cell-events.test.ts +0 -347
  168. package/src/schemas/cell-events.ts +0 -807
  169. package/src/schemas/cell.ts +0 -257
  170. package/src/schemas/evaluation.ts +0 -166
  171. package/src/schemas/index.test.ts +0 -199
  172. package/src/schemas/index.ts +0 -286
  173. package/src/schemas/mandate.ts +0 -232
  174. package/src/schemas/swarm-context.ts +0 -115
  175. package/src/schemas/task.ts +0 -161
  176. package/src/schemas/worker-handoff.test.ts +0 -302
  177. package/src/schemas/worker-handoff.ts +0 -131
  178. package/src/sessions/agent-discovery.test.ts +0 -137
  179. package/src/sessions/agent-discovery.ts +0 -112
  180. package/src/sessions/index.ts +0 -15
  181. package/src/skills.integration.test.ts +0 -1192
  182. package/src/skills.test.ts +0 -643
  183. package/src/skills.ts +0 -1549
  184. package/src/storage.integration.test.ts +0 -341
  185. package/src/storage.ts +0 -884
  186. package/src/structured.integration.test.ts +0 -817
  187. package/src/structured.test.ts +0 -1046
  188. package/src/structured.ts +0 -762
  189. package/src/swarm-decompose.test.ts +0 -188
  190. package/src/swarm-decompose.ts +0 -1302
  191. package/src/swarm-deferred.integration.test.ts +0 -157
  192. package/src/swarm-deferred.test.ts +0 -38
  193. package/src/swarm-insights.test.ts +0 -214
  194. package/src/swarm-insights.ts +0 -459
  195. package/src/swarm-mail.integration.test.ts +0 -970
  196. package/src/swarm-mail.ts +0 -739
  197. package/src/swarm-orchestrate.integration.test.ts +0 -282
  198. package/src/swarm-orchestrate.test.ts +0 -548
  199. package/src/swarm-orchestrate.ts +0 -3084
  200. package/src/swarm-prompts.test.ts +0 -1270
  201. package/src/swarm-prompts.ts +0 -2077
  202. package/src/swarm-research.integration.test.ts +0 -701
  203. package/src/swarm-research.test.ts +0 -698
  204. package/src/swarm-research.ts +0 -472
  205. package/src/swarm-review.integration.test.ts +0 -285
  206. package/src/swarm-review.test.ts +0 -879
  207. package/src/swarm-review.ts +0 -709
  208. package/src/swarm-strategies.ts +0 -407
  209. package/src/swarm-worktree.test.ts +0 -501
  210. package/src/swarm-worktree.ts +0 -575
  211. package/src/swarm.integration.test.ts +0 -2377
  212. package/src/swarm.ts +0 -38
  213. package/src/tool-adapter.integration.test.ts +0 -1221
  214. package/src/tool-availability.ts +0 -461
  215. package/tsconfig.json +0 -28
@@ -1,161 +0,0 @@
1
- /**
2
- * Task decomposition schemas
3
- *
4
- * These schemas define the structure for breaking down tasks
5
- * into parallelizable subtasks for swarm execution.
6
- */
7
- import { z } from "zod";
8
-
9
- /**
10
- * Effort estimation for subtasks.
11
- *
12
- * Time ranges:
13
- * - `trivial`: < 5 minutes (simple rename, typo fix)
14
- * - `small`: 5-30 minutes (single function, simple feature)
15
- * - `medium`: 30 min - 2 hours (multi-file change, moderate complexity)
16
- * - `large`: 2+ hours (significant feature, refactoring)
17
- */
18
- export const EffortLevelSchema = z.enum([
19
- "trivial",
20
- "small",
21
- "medium",
22
- "large",
23
- ]);
24
- export type EffortLevel = z.infer<typeof EffortLevelSchema>;
25
-
26
- /**
27
- * Dependency type between subtasks
28
- */
29
- export const DependencyTypeSchema = z.enum([
30
- "blocks", // Must complete before dependent can start
31
- "requires", // Needs output from another task
32
- "related", // Informational relationship
33
- ]);
34
- export type DependencyType = z.infer<typeof DependencyTypeSchema>;
35
-
36
- /**
37
- * Subtask in a decomposition
38
- */
39
- export const DecomposedSubtaskSchema = z.object({
40
- title: z.string().min(1),
41
- description: z.string(),
42
- files: z.array(z.string()), // File paths this subtask will modify
43
- estimated_effort: EffortLevelSchema,
44
- /** Potential risks or complications (e.g., 'tight coupling', 'data migration required', 'breaking change') */
45
- risks: z.array(z.string()).optional().default([]),
46
- /**
47
- * Optional explicit model override for this subtask.
48
- * If not specified, model will be selected based on file types.
49
- */
50
- model: z.string().optional(),
51
- });
52
- export type DecomposedSubtask = z.infer<typeof DecomposedSubtaskSchema>;
53
-
54
- /**
55
- * Dependency between subtasks
56
- */
57
- export const SubtaskDependencySchema = z.object({
58
- /** Zero-based index of the dependency source subtask */
59
- from: z.number().int().min(0),
60
- /** Zero-based index of the dependency target subtask */
61
- to: z.number().int().min(0),
62
- type: DependencyTypeSchema,
63
- });
64
- export type SubtaskDependency = z.infer<typeof SubtaskDependencySchema>;
65
-
66
- /**
67
- * Full task decomposition result
68
- *
69
- * Returned by the decomposition agent, validated before spawning.
70
- */
71
- export const TaskDecompositionSchema = z.object({
72
- task: z.string(), // Original task description
73
- /** Rationale for this decomposition strategy (why these subtasks, why this order) */
74
- reasoning: z.string().optional(),
75
- subtasks: z.array(DecomposedSubtaskSchema).min(1),
76
- dependencies: z.array(SubtaskDependencySchema).optional().default([]),
77
- /**
78
- * Context shared with all spawned agents.
79
- * Examples: API contracts, shared types, project conventions, architectural decisions.
80
- */
81
- shared_context: z.string().optional(),
82
- });
83
- export type TaskDecomposition = z.infer<typeof TaskDecompositionSchema>;
84
-
85
- /**
86
- * Arguments for task decomposition
87
- */
88
- export const DecomposeArgsSchema = z.object({
89
- task: z.string().min(1),
90
- context: z.string().optional(),
91
- });
92
- export type DecomposeArgs = z.infer<typeof DecomposeArgsSchema>;
93
-
94
- /**
95
- * Spawn result for a single agent
96
- */
97
- export const SpawnedAgentSchema = z.object({
98
- bead_id: z.string(),
99
- /**
100
- * Agent Mail assigned name (e.g., 'BlueLake', 'CrimsonRiver').
101
- * Generated by Agent Mail on session init.
102
- */
103
- agent_name: z.string(),
104
- task_id: z.string().optional(), // OpenCode task ID
105
- status: z.enum(["pending", "running", "completed", "failed"]),
106
- files: z.array(z.string()), // Reserved files
107
- /**
108
- * Agent Mail reservation IDs for file locking.
109
- * Used to release locks on task completion via agentmail_release.
110
- */
111
- reservation_ids: z.array(z.number()).optional(),
112
- });
113
- export type SpawnedAgent = z.infer<typeof SpawnedAgentSchema>;
114
-
115
- /**
116
- * Result of spawning a swarm
117
- */
118
- export const SwarmSpawnResultSchema = z.object({
119
- epic_id: z.string(),
120
- coordinator_name: z.string(), // Agent Mail name of coordinator
121
- thread_id: z.string(), // Agent Mail thread for this swarm
122
- agents: z.array(SpawnedAgentSchema),
123
- started_at: z.string().datetime({ offset: true }), // ISO-8601 with timezone
124
- });
125
- export type SwarmSpawnResult = z.infer<typeof SwarmSpawnResultSchema>;
126
-
127
- /**
128
- * Progress update from an agent
129
- */
130
- export const AgentProgressSchema = z
131
- .object({
132
- bead_id: z.string(),
133
- agent_name: z.string(),
134
- status: z.enum(["in_progress", "blocked", "completed", "failed"]),
135
- progress_percent: z.number().min(0).max(100).optional(),
136
- message: z.string().optional(),
137
- files_touched: z.array(z.string()).optional(),
138
- blockers: z.array(z.string()).optional(),
139
- timestamp: z.string().datetime({ offset: true }), // ISO-8601 with timezone
140
- })
141
- .refine(
142
- (data) =>
143
- data.status !== "blocked" || (data.blockers && data.blockers.length > 0),
144
- { message: "blockers array required when status is 'blocked'" },
145
- );
146
- export type AgentProgress = z.infer<typeof AgentProgressSchema>;
147
-
148
- /**
149
- * Swarm status summary
150
- */
151
- export const SwarmStatusSchema = z.object({
152
- epic_id: z.string(),
153
- total_agents: z.number().int().min(0),
154
- running: z.number().int().min(0),
155
- completed: z.number().int().min(0),
156
- failed: z.number().int().min(0),
157
- blocked: z.number().int().min(0),
158
- agents: z.array(SpawnedAgentSchema),
159
- last_update: z.string().datetime({ offset: true }), // ISO-8601 with timezone
160
- });
161
- export type SwarmStatus = z.infer<typeof SwarmStatusSchema>;
@@ -1,302 +0,0 @@
1
- /**
2
- * Tests for WorkerHandoff schema validation
3
- *
4
- * WorkerHandoff replaces prose instructions with structured contracts.
5
- * These tests ensure runtime validation catches malformed handoffs.
6
- */
7
- import { describe, expect, test } from "bun:test";
8
- import {
9
- WorkerHandoffContractSchema,
10
- WorkerHandoffContextSchema,
11
- WorkerHandoffEscalationSchema,
12
- WorkerHandoffSchema,
13
- type WorkerHandoff,
14
- type WorkerHandoffContract,
15
- type WorkerHandoffContext,
16
- type WorkerHandoffEscalation,
17
- } from "./worker-handoff";
18
-
19
- describe("WorkerHandoffContractSchema", () => {
20
- test("valid contract parses correctly", () => {
21
- const validContract = {
22
- task_id: "opencode-swarm-monorepo-lf2p4u-abc123",
23
- files_owned: ["src/auth/service.ts", "src/auth/schema.ts"],
24
- files_readonly: ["src/lib/jwt.ts"],
25
- dependencies_completed: ["opencode-swarm-monorepo-lf2p4u-abc122"],
26
- success_criteria: [
27
- "Auth service implements JWT strategy",
28
- "All tests pass",
29
- ],
30
- };
31
-
32
- const result = WorkerHandoffContractSchema.safeParse(validContract);
33
- expect(result.success).toBe(true);
34
- if (result.success) {
35
- expect(result.data.task_id).toBe("opencode-swarm-monorepo-lf2p4u-abc123");
36
- expect(result.data.files_owned).toHaveLength(2);
37
- expect(result.data.success_criteria).toHaveLength(2);
38
- }
39
- });
40
-
41
- test("missing task_id fails", () => {
42
- const invalidContract = {
43
- files_owned: ["src/auth.ts"],
44
- files_readonly: [],
45
- dependencies_completed: [],
46
- success_criteria: ["Auth works"],
47
- };
48
-
49
- const result = WorkerHandoffContractSchema.safeParse(invalidContract);
50
- expect(result.success).toBe(false);
51
- });
52
-
53
- test("empty files_owned is valid (read-only tasks)", () => {
54
- const readOnlyContract = {
55
- task_id: "opencode-swarm-monorepo-lf2p4u-abc123",
56
- files_owned: [], // Read-only task
57
- files_readonly: ["src/types.ts"],
58
- dependencies_completed: [],
59
- success_criteria: ["Documentation updated"],
60
- };
61
-
62
- const result = WorkerHandoffContractSchema.safeParse(readOnlyContract);
63
- expect(result.success).toBe(true);
64
- });
65
-
66
- test("empty success_criteria fails", () => {
67
- const invalidContract = {
68
- task_id: "opencode-swarm-monorepo-lf2p4u-abc123",
69
- files_owned: ["src/auth.ts"],
70
- files_readonly: [],
71
- dependencies_completed: [],
72
- success_criteria: [], // Must have at least one
73
- };
74
-
75
- const result = WorkerHandoffContractSchema.safeParse(invalidContract);
76
- expect(result.success).toBe(false);
77
- if (!result.success) {
78
- expect(result.error.issues[0].message).toContain(
79
- "at least one success criterion",
80
- );
81
- }
82
- });
83
-
84
- test("empty task_id fails", () => {
85
- const invalidContract = {
86
- task_id: "", // Empty string not allowed
87
- files_owned: ["src/auth.ts"],
88
- files_readonly: [],
89
- dependencies_completed: [],
90
- success_criteria: ["Auth works"],
91
- };
92
-
93
- const result = WorkerHandoffContractSchema.safeParse(invalidContract);
94
- expect(result.success).toBe(false);
95
- if (!result.success) {
96
- expect(result.error.issues[0].message).toContain("cannot be empty");
97
- }
98
- });
99
-
100
- test("short project name with hash is valid", () => {
101
- // Regression test: single-word project names like "swarm-lf2p4u-abc123" should work
102
- const shortProjectContract = {
103
- task_id: "swarm-lf2p4u-abc123", // Only 2 segments before timestamp
104
- files_owned: ["src/auth.ts"],
105
- files_readonly: [],
106
- dependencies_completed: [],
107
- success_criteria: ["Auth works"],
108
- };
109
-
110
- const result = WorkerHandoffContractSchema.safeParse(shortProjectContract);
111
- expect(result.success).toBe(true);
112
- });
113
-
114
- test("partial hash is valid (resolvePartialId will expand it)", () => {
115
- // Partial hashes should be accepted - resolvePartialId will expand them
116
- const partialHashContract = {
117
- task_id: "mjd4pjuj", // Short hash only
118
- files_owned: ["src/auth.ts"],
119
- files_readonly: [],
120
- dependencies_completed: [],
121
- success_criteria: ["Auth works"],
122
- };
123
-
124
- const result = WorkerHandoffContractSchema.safeParse(partialHashContract);
125
- expect(result.success).toBe(true);
126
- });
127
- });
128
-
129
- describe("WorkerHandoffContextSchema", () => {
130
- test("valid context parses correctly", () => {
131
- const validContext = {
132
- epic_summary: "Add authentication system",
133
- your_role: "Implement JWT auth service",
134
- what_others_did: "Schema defined by agent-1",
135
- what_comes_next: "Integration tests in next subtask",
136
- };
137
-
138
- const result = WorkerHandoffContextSchema.safeParse(validContext);
139
- expect(result.success).toBe(true);
140
- });
141
-
142
- test("missing required fields fails", () => {
143
- const invalidContext = {
144
- epic_summary: "Add auth",
145
- your_role: "Implement service",
146
- // Missing what_others_did and what_comes_next
147
- };
148
-
149
- const result = WorkerHandoffContextSchema.safeParse(invalidContext);
150
- expect(result.success).toBe(false);
151
- });
152
-
153
- test("empty strings are valid", () => {
154
- const contextWithEmptyStrings = {
155
- epic_summary: "Add auth",
156
- your_role: "Implement service",
157
- what_others_did: "", // Valid for first subtask
158
- what_comes_next: "", // Valid for last subtask
159
- };
160
-
161
- const result = WorkerHandoffContextSchema.safeParse(
162
- contextWithEmptyStrings,
163
- );
164
- expect(result.success).toBe(true);
165
- });
166
- });
167
-
168
- describe("WorkerHandoffEscalationSchema", () => {
169
- test("valid escalation parses correctly", () => {
170
- const validEscalation = {
171
- blocked_contact: "Message coordinator via swarmmail_send(importance='high')",
172
- scope_change_protocol:
173
- "Request approval before expanding scope beyond files_owned",
174
- };
175
-
176
- const result = WorkerHandoffEscalationSchema.safeParse(validEscalation);
177
- expect(result.success).toBe(true);
178
- });
179
-
180
- test("missing required fields fails", () => {
181
- const invalidEscalation = {
182
- blocked_contact: "Message coordinator",
183
- // Missing scope_change_protocol
184
- };
185
-
186
- const result = WorkerHandoffEscalationSchema.safeParse(invalidEscalation);
187
- expect(result.success).toBe(false);
188
- });
189
- });
190
-
191
- describe("WorkerHandoffSchema", () => {
192
- test("complete valid handoff parses correctly", () => {
193
- const validHandoff = {
194
- contract: {
195
- task_id: "opencode-swarm-monorepo-lf2p4u-abc123",
196
- files_owned: ["src/auth/service.ts"],
197
- files_readonly: ["src/lib/jwt.ts"],
198
- dependencies_completed: [],
199
- success_criteria: ["Service implemented", "Tests pass"],
200
- },
201
- context: {
202
- epic_summary: "Add authentication",
203
- your_role: "Implement auth service",
204
- what_others_did: "Schema defined",
205
- what_comes_next: "Integration tests",
206
- },
207
- escalation: {
208
- blocked_contact: "Message coordinator",
209
- scope_change_protocol: "Request approval first",
210
- },
211
- };
212
-
213
- const result = WorkerHandoffSchema.safeParse(validHandoff);
214
- expect(result.success).toBe(true);
215
- if (result.success) {
216
- const handoff: WorkerHandoff = result.data;
217
- expect(handoff.contract.task_id).toBe(
218
- "opencode-swarm-monorepo-lf2p4u-abc123",
219
- );
220
- expect(handoff.context.your_role).toBe("Implement auth service");
221
- expect(handoff.escalation.blocked_contact).toBe("Message coordinator");
222
- }
223
- });
224
-
225
- test("missing contract section fails", () => {
226
- const invalidHandoff = {
227
- context: {
228
- epic_summary: "Add auth",
229
- your_role: "Implement",
230
- what_others_did: "Schema",
231
- what_comes_next: "Tests",
232
- },
233
- escalation: {
234
- blocked_contact: "Message coordinator",
235
- scope_change_protocol: "Request approval",
236
- },
237
- };
238
-
239
- const result = WorkerHandoffSchema.safeParse(invalidHandoff);
240
- expect(result.success).toBe(false);
241
- });
242
-
243
- test("nested validation catches contract errors", () => {
244
- const handoffWithInvalidContract = {
245
- contract: {
246
- task_id: "opencode-swarm-monorepo-lf2p4u-abc123",
247
- files_owned: ["src/auth.ts"],
248
- files_readonly: [],
249
- dependencies_completed: [],
250
- success_criteria: [], // Invalid: empty
251
- },
252
- context: {
253
- epic_summary: "Add auth",
254
- your_role: "Implement",
255
- what_others_did: "Schema",
256
- what_comes_next: "Tests",
257
- },
258
- escalation: {
259
- blocked_contact: "Message coordinator",
260
- scope_change_protocol: "Request approval",
261
- },
262
- };
263
-
264
- const result = WorkerHandoffSchema.safeParse(handoffWithInvalidContract);
265
- expect(result.success).toBe(false);
266
- if (!result.success) {
267
- const errorMessage = result.error.issues[0].message;
268
- expect(errorMessage).toContain("at least one success criterion");
269
- }
270
- });
271
-
272
- test("type inference works correctly", () => {
273
- const handoff: WorkerHandoff = {
274
- contract: {
275
- task_id: "opencode-swarm-monorepo-lf2p4u-abc123",
276
- files_owned: [],
277
- files_readonly: [],
278
- dependencies_completed: [],
279
- success_criteria: ["Done"],
280
- },
281
- context: {
282
- epic_summary: "Summary",
283
- your_role: "Role",
284
- what_others_did: "Nothing",
285
- what_comes_next: "More work",
286
- },
287
- escalation: {
288
- blocked_contact: "Coordinator",
289
- scope_change_protocol: "Ask first",
290
- },
291
- };
292
-
293
- // Type check only - verify TypeScript inference
294
- const contract: WorkerHandoffContract = handoff.contract;
295
- const context: WorkerHandoffContext = handoff.context;
296
- const escalation: WorkerHandoffEscalation = handoff.escalation;
297
-
298
- expect(contract.task_id).toBeDefined();
299
- expect(context.your_role).toBeDefined();
300
- expect(escalation.blocked_contact).toBeDefined();
301
- });
302
- });
@@ -1,131 +0,0 @@
1
- /**
2
- * WorkerHandoff schemas - structured contracts replacing prose instructions
3
- *
4
- * Replaces the 400-line SUBTASK_PROMPT_V2 with machine-readable contracts.
5
- * Workers receive typed handoffs with explicit files, criteria, and escalation paths.
6
- */
7
- import { z } from "zod";
8
-
9
- /**
10
- * Contract section - the binding agreement between coordinator and worker
11
- *
12
- * Defines:
13
- * - What task to complete (task_id)
14
- * - What files to modify (files_owned) vs read (files_readonly)
15
- * - What's already done (dependencies_completed)
16
- * - How to know you're done (success_criteria)
17
- */
18
- export const WorkerHandoffContractSchema = z.object({
19
- /**
20
- * Cell ID for this subtask.
21
- * Can be a full cell ID, hash, or partial hash.
22
- * Examples:
23
- * - Full ID: `opencode-swarm-monorepo-lf2p4u-abc123`
24
- * - Hash only: `lf2p4u`
25
- * - Partial hash: `mjd4pjuj`
26
- *
27
- * The hive tools use resolvePartialId() to expand short IDs before lookup.
28
- */
29
- task_id: z
30
- .string()
31
- .min(1, "Task ID cannot be empty"),
32
-
33
- /**
34
- * Files this worker owns (exclusive write access).
35
- * Empty array is valid for read-only tasks (e.g., documentation review).
36
- */
37
- files_owned: z.array(z.string()).default([]),
38
-
39
- /**
40
- * Files this worker can read but must not modify.
41
- * Coordinator reserves these for other workers.
42
- */
43
- files_readonly: z.array(z.string()).default([]),
44
-
45
- /**
46
- * Subtask IDs that must complete before this one.
47
- * Empty if no dependencies (can start immediately).
48
- */
49
- dependencies_completed: z.array(z.string()).default([]),
50
-
51
- /**
52
- * Success criteria - how to know the task is complete.
53
- * Must have at least one criterion to prevent ambiguous completion.
54
- */
55
- success_criteria: z
56
- .array(z.string())
57
- .min(1, "Must have at least one success criterion"),
58
- });
59
- export type WorkerHandoffContract = z.infer<typeof WorkerHandoffContractSchema>;
60
-
61
- /**
62
- * Context section - the narrative explaining the "why"
63
- *
64
- * Provides:
65
- * - Big picture (epic_summary)
66
- * - This worker's specific role
67
- * - What's already been done
68
- * - What comes after
69
- */
70
- export const WorkerHandoffContextSchema = z.object({
71
- /**
72
- * High-level summary of the entire epic.
73
- * Helps worker understand how their piece fits.
74
- */
75
- epic_summary: z.string(),
76
-
77
- /**
78
- * This worker's specific role/responsibility.
79
- * Should align with files_owned in contract.
80
- */
81
- your_role: z.string(),
82
-
83
- /**
84
- * What previous subtasks accomplished.
85
- * Empty string is valid for first subtask.
86
- */
87
- what_others_did: z.string(),
88
-
89
- /**
90
- * What happens after this subtask completes.
91
- * Empty string is valid for last subtask.
92
- */
93
- what_comes_next: z.string(),
94
- });
95
- export type WorkerHandoffContext = z.infer<typeof WorkerHandoffContextSchema>;
96
-
97
- /**
98
- * Escalation section - what to do when things go wrong
99
- *
100
- * Defines:
101
- * - How to report blockers
102
- * - Protocol for scope changes
103
- */
104
- export const WorkerHandoffEscalationSchema = z.object({
105
- /**
106
- * Instructions for reporting blockers.
107
- * Typically: "Message coordinator via swarmmail_send(importance='high')"
108
- */
109
- blocked_contact: z.string(),
110
-
111
- /**
112
- * Protocol for requesting scope changes.
113
- * Typically: "Request approval before expanding scope beyond files_owned"
114
- */
115
- scope_change_protocol: z.string(),
116
- });
117
- export type WorkerHandoffEscalation = z.infer<
118
- typeof WorkerHandoffEscalationSchema
119
- >;
120
-
121
- /**
122
- * Complete WorkerHandoff - combines all three sections
123
- *
124
- * This is the full structured contract that replaces prose instructions.
125
- */
126
- export const WorkerHandoffSchema = z.object({
127
- contract: WorkerHandoffContractSchema,
128
- context: WorkerHandoffContextSchema,
129
- escalation: WorkerHandoffEscalationSchema,
130
- });
131
- export type WorkerHandoff = z.infer<typeof WorkerHandoffSchema>;