claude-code-swarm 0.3.3 → 0.3.5

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 (273) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +22 -1
  3. package/.claude-plugin/run-agent-inbox-mcp.sh +76 -0
  4. package/.claude-plugin/run-minimem-mcp.sh +98 -0
  5. package/.claude-plugin/run-opentasks-mcp.sh +65 -0
  6. package/CLAUDE.md +200 -36
  7. package/README.md +65 -0
  8. package/e2e/helpers/cleanup.mjs +17 -3
  9. package/e2e/helpers/map-mock-server.mjs +201 -25
  10. package/e2e/helpers/sidecar.mjs +222 -0
  11. package/e2e/helpers/workspace.mjs +2 -1
  12. package/e2e/tier5-sidecar-inbox.test.mjs +900 -0
  13. package/e2e/tier6-inbox-mcp.test.mjs +173 -0
  14. package/e2e/tier6-live-agent.test.mjs +759 -0
  15. package/e2e/vitest.config.e2e.mjs +1 -1
  16. package/hooks/hooks.json +15 -8
  17. package/package.json +13 -1
  18. package/references/agent-inbox/CLAUDE.md +151 -0
  19. package/references/agent-inbox/README.md +238 -0
  20. package/references/agent-inbox/docs/CLAUDE-CODE-SWARM-PROPOSAL.md +137 -0
  21. package/references/agent-inbox/docs/DESIGN.md +1156 -0
  22. package/references/agent-inbox/hooks/inbox-hook.mjs +119 -0
  23. package/references/agent-inbox/hooks/register-hook.mjs +69 -0
  24. package/references/agent-inbox/package-lock.json +3347 -0
  25. package/references/agent-inbox/package.json +58 -0
  26. package/references/agent-inbox/rules/agent-inbox.md +78 -0
  27. package/references/agent-inbox/src/federation/address.ts +61 -0
  28. package/references/agent-inbox/src/federation/connection-manager.ts +573 -0
  29. package/references/agent-inbox/src/federation/delivery-queue.ts +222 -0
  30. package/references/agent-inbox/src/federation/index.ts +6 -0
  31. package/references/agent-inbox/src/federation/routing-engine.ts +188 -0
  32. package/references/agent-inbox/src/federation/trust.ts +71 -0
  33. package/references/agent-inbox/src/index.ts +390 -0
  34. package/references/agent-inbox/src/ipc/ipc-server.ts +207 -0
  35. package/references/agent-inbox/src/jsonrpc/mail-server.ts +382 -0
  36. package/references/agent-inbox/src/map/map-client.ts +414 -0
  37. package/references/agent-inbox/src/mcp/mcp-server.ts +272 -0
  38. package/references/agent-inbox/src/mesh/delivery-bridge.ts +110 -0
  39. package/references/agent-inbox/src/mesh/mesh-connector.ts +41 -0
  40. package/references/agent-inbox/src/mesh/mesh-transport.ts +157 -0
  41. package/references/agent-inbox/src/mesh/type-mapper.ts +239 -0
  42. package/references/agent-inbox/src/push/notifier.ts +233 -0
  43. package/references/agent-inbox/src/registry/warm-registry.ts +255 -0
  44. package/references/agent-inbox/src/router/message-router.ts +175 -0
  45. package/references/agent-inbox/src/storage/interface.ts +48 -0
  46. package/references/agent-inbox/src/storage/memory.ts +145 -0
  47. package/references/agent-inbox/src/storage/sqlite.ts +671 -0
  48. package/references/agent-inbox/src/traceability/traceability.ts +183 -0
  49. package/references/agent-inbox/src/types.ts +303 -0
  50. package/references/agent-inbox/test/federation/address.test.ts +101 -0
  51. package/references/agent-inbox/test/federation/connection-manager.test.ts +546 -0
  52. package/references/agent-inbox/test/federation/delivery-queue.test.ts +159 -0
  53. package/references/agent-inbox/test/federation/integration.test.ts +857 -0
  54. package/references/agent-inbox/test/federation/routing-engine.test.ts +117 -0
  55. package/references/agent-inbox/test/federation/sdk-integration.test.ts +744 -0
  56. package/references/agent-inbox/test/federation/trust.test.ts +89 -0
  57. package/references/agent-inbox/test/ipc-jsonrpc.test.ts +113 -0
  58. package/references/agent-inbox/test/ipc-server.test.ts +197 -0
  59. package/references/agent-inbox/test/mail-server.test.ts +285 -0
  60. package/references/agent-inbox/test/map-client.test.ts +408 -0
  61. package/references/agent-inbox/test/mesh/delivery-bridge.test.ts +178 -0
  62. package/references/agent-inbox/test/mesh/e2e-mesh.test.ts +527 -0
  63. package/references/agent-inbox/test/mesh/e2e-real-meshpeer.test.ts +629 -0
  64. package/references/agent-inbox/test/mesh/federation-mesh.test.ts +269 -0
  65. package/references/agent-inbox/test/mesh/mesh-connector.test.ts +66 -0
  66. package/references/agent-inbox/test/mesh/mesh-transport.test.ts +191 -0
  67. package/references/agent-inbox/test/mesh/meshpeer-integration.test.ts +442 -0
  68. package/references/agent-inbox/test/mesh/mock-mesh.ts +125 -0
  69. package/references/agent-inbox/test/mesh/mock-meshpeer.ts +266 -0
  70. package/references/agent-inbox/test/mesh/type-mapper.test.ts +226 -0
  71. package/references/agent-inbox/test/message-router.test.ts +184 -0
  72. package/references/agent-inbox/test/push-notifier.test.ts +139 -0
  73. package/references/agent-inbox/test/registry/warm-registry.test.ts +171 -0
  74. package/references/agent-inbox/test/sqlite-prefix.test.ts +192 -0
  75. package/references/agent-inbox/test/sqlite-storage.test.ts +243 -0
  76. package/references/agent-inbox/test/storage.test.ts +196 -0
  77. package/references/agent-inbox/test/traceability.test.ts +123 -0
  78. package/references/agent-inbox/test/wake.test.ts +330 -0
  79. package/references/agent-inbox/tsconfig.json +20 -0
  80. package/references/agent-inbox/tsup.config.ts +10 -0
  81. package/references/agent-inbox/vitest.config.ts +8 -0
  82. package/references/minimem/.claude/settings.json +7 -0
  83. package/references/minimem/.sudocode/issues.jsonl +18 -0
  84. package/references/minimem/.sudocode/specs.jsonl +1 -0
  85. package/references/minimem/CLAUDE.md +329 -0
  86. package/references/minimem/README.md +565 -0
  87. package/references/minimem/claude-plugin/.claude-plugin/plugin.json +10 -0
  88. package/references/minimem/claude-plugin/.mcp.json +7 -0
  89. package/references/minimem/claude-plugin/README.md +158 -0
  90. package/references/minimem/claude-plugin/commands/recall.md +47 -0
  91. package/references/minimem/claude-plugin/commands/remember.md +41 -0
  92. package/references/minimem/claude-plugin/hooks/__tests__/hooks.test.ts +272 -0
  93. package/references/minimem/claude-plugin/hooks/hooks.json +27 -0
  94. package/references/minimem/claude-plugin/hooks/session-end.sh +86 -0
  95. package/references/minimem/claude-plugin/hooks/session-start.sh +85 -0
  96. package/references/minimem/claude-plugin/skills/memory/SKILL.md +108 -0
  97. package/references/minimem/media/banner.png +0 -0
  98. package/references/minimem/package-lock.json +5373 -0
  99. package/references/minimem/package.json +76 -0
  100. package/references/minimem/scripts/postbuild.js +49 -0
  101. package/references/minimem/src/__tests__/edge-cases.test.ts +371 -0
  102. package/references/minimem/src/__tests__/errors.test.ts +265 -0
  103. package/references/minimem/src/__tests__/helpers.ts +199 -0
  104. package/references/minimem/src/__tests__/internal.test.ts +407 -0
  105. package/references/minimem/src/__tests__/knowledge-frontmatter.test.ts +148 -0
  106. package/references/minimem/src/__tests__/knowledge.test.ts +148 -0
  107. package/references/minimem/src/__tests__/minimem.integration.test.ts +1127 -0
  108. package/references/minimem/src/__tests__/session.test.ts +190 -0
  109. package/references/minimem/src/cli/__tests__/commands.test.ts +760 -0
  110. package/references/minimem/src/cli/__tests__/contained-layout.test.ts +286 -0
  111. package/references/minimem/src/cli/commands/__tests__/conflicts.test.ts +141 -0
  112. package/references/minimem/src/cli/commands/append.ts +76 -0
  113. package/references/minimem/src/cli/commands/config.ts +262 -0
  114. package/references/minimem/src/cli/commands/conflicts.ts +415 -0
  115. package/references/minimem/src/cli/commands/daemon.ts +169 -0
  116. package/references/minimem/src/cli/commands/index.ts +12 -0
  117. package/references/minimem/src/cli/commands/init.ts +166 -0
  118. package/references/minimem/src/cli/commands/mcp.ts +221 -0
  119. package/references/minimem/src/cli/commands/push-pull.ts +213 -0
  120. package/references/minimem/src/cli/commands/search.ts +223 -0
  121. package/references/minimem/src/cli/commands/status.ts +84 -0
  122. package/references/minimem/src/cli/commands/store.ts +189 -0
  123. package/references/minimem/src/cli/commands/sync-init.ts +290 -0
  124. package/references/minimem/src/cli/commands/sync.ts +70 -0
  125. package/references/minimem/src/cli/commands/upsert.ts +197 -0
  126. package/references/minimem/src/cli/config.ts +611 -0
  127. package/references/minimem/src/cli/index.ts +299 -0
  128. package/references/minimem/src/cli/shared.ts +189 -0
  129. package/references/minimem/src/cli/sync/__tests__/central.test.ts +152 -0
  130. package/references/minimem/src/cli/sync/__tests__/conflicts.test.ts +209 -0
  131. package/references/minimem/src/cli/sync/__tests__/daemon.test.ts +118 -0
  132. package/references/minimem/src/cli/sync/__tests__/detection.test.ts +207 -0
  133. package/references/minimem/src/cli/sync/__tests__/integration.test.ts +476 -0
  134. package/references/minimem/src/cli/sync/__tests__/registry.test.ts +363 -0
  135. package/references/minimem/src/cli/sync/__tests__/state.test.ts +255 -0
  136. package/references/minimem/src/cli/sync/__tests__/validation.test.ts +193 -0
  137. package/references/minimem/src/cli/sync/__tests__/watcher.test.ts +178 -0
  138. package/references/minimem/src/cli/sync/central.ts +292 -0
  139. package/references/minimem/src/cli/sync/conflicts.ts +205 -0
  140. package/references/minimem/src/cli/sync/daemon.ts +407 -0
  141. package/references/minimem/src/cli/sync/detection.ts +138 -0
  142. package/references/minimem/src/cli/sync/index.ts +107 -0
  143. package/references/minimem/src/cli/sync/operations.ts +373 -0
  144. package/references/minimem/src/cli/sync/registry.ts +279 -0
  145. package/references/minimem/src/cli/sync/state.ts +358 -0
  146. package/references/minimem/src/cli/sync/validation.ts +206 -0
  147. package/references/minimem/src/cli/sync/watcher.ts +237 -0
  148. package/references/minimem/src/cli/version.ts +34 -0
  149. package/references/minimem/src/core/index.ts +9 -0
  150. package/references/minimem/src/core/indexer.ts +628 -0
  151. package/references/minimem/src/core/searcher.ts +221 -0
  152. package/references/minimem/src/db/schema.ts +183 -0
  153. package/references/minimem/src/db/sqlite-vec.ts +24 -0
  154. package/references/minimem/src/embeddings/__tests__/embeddings.test.ts +431 -0
  155. package/references/minimem/src/embeddings/batch-gemini.ts +392 -0
  156. package/references/minimem/src/embeddings/batch-openai.ts +409 -0
  157. package/references/minimem/src/embeddings/embeddings.ts +434 -0
  158. package/references/minimem/src/index.ts +132 -0
  159. package/references/minimem/src/internal.ts +299 -0
  160. package/references/minimem/src/minimem.ts +1291 -0
  161. package/references/minimem/src/search/__tests__/hybrid.test.ts +247 -0
  162. package/references/minimem/src/search/graph.ts +234 -0
  163. package/references/minimem/src/search/hybrid.ts +151 -0
  164. package/references/minimem/src/search/search.ts +256 -0
  165. package/references/minimem/src/server/__tests__/mcp.test.ts +347 -0
  166. package/references/minimem/src/server/__tests__/tools.test.ts +364 -0
  167. package/references/minimem/src/server/mcp.ts +326 -0
  168. package/references/minimem/src/server/tools.ts +720 -0
  169. package/references/minimem/src/session.ts +460 -0
  170. package/references/minimem/src/store/__tests__/manifest.test.ts +177 -0
  171. package/references/minimem/src/store/__tests__/materialize.test.ts +52 -0
  172. package/references/minimem/src/store/__tests__/store-graph.test.ts +228 -0
  173. package/references/minimem/src/store/index.ts +27 -0
  174. package/references/minimem/src/store/manifest.ts +203 -0
  175. package/references/minimem/src/store/materialize.ts +185 -0
  176. package/references/minimem/src/store/store-graph.ts +252 -0
  177. package/references/minimem/tsconfig.json +19 -0
  178. package/references/minimem/tsup.config.ts +26 -0
  179. package/references/minimem/vitest.config.ts +29 -0
  180. package/references/openteams/src/cli/generate.ts +23 -1
  181. package/references/openteams/src/generators/agent-prompt-generator.test.ts +94 -0
  182. package/references/openteams/src/generators/agent-prompt-generator.ts +42 -13
  183. package/references/openteams/src/generators/package-generator.ts +9 -1
  184. package/references/openteams/src/generators/skill-generator.test.ts +28 -0
  185. package/references/openteams/src/generators/skill-generator.ts +10 -4
  186. package/references/skill-tree/.claude/settings.json +6 -0
  187. package/references/skill-tree/.sudocode/issues.jsonl +19 -0
  188. package/references/skill-tree/.sudocode/specs.jsonl +3 -0
  189. package/references/skill-tree/CLAUDE.md +132 -0
  190. package/references/skill-tree/README.md +396 -0
  191. package/references/skill-tree/docs/GAPS_v1.md +221 -0
  192. package/references/skill-tree/docs/INTEGRATION_PLAN.md +467 -0
  193. package/references/skill-tree/docs/TODOS.md +91 -0
  194. package/references/skill-tree/docs/anthropic_skill_guide.md +1364 -0
  195. package/references/skill-tree/docs/design/federated-skill-trees.md +524 -0
  196. package/references/skill-tree/docs/design/multi-agent-sync.md +759 -0
  197. package/references/skill-tree/docs/scraper/BRAINSTORM.md +583 -0
  198. package/references/skill-tree/docs/scraper/POC_PLAN.md +420 -0
  199. package/references/skill-tree/docs/scraper/README.md +170 -0
  200. package/references/skill-tree/examples/basic-usage.ts +157 -0
  201. package/references/skill-tree/package-lock.json +1852 -0
  202. package/references/skill-tree/package.json +66 -0
  203. package/references/skill-tree/plan.md +78 -0
  204. package/references/skill-tree/scraper/README.md +123 -0
  205. package/references/skill-tree/scraper/docs/DESIGN.md +683 -0
  206. package/references/skill-tree/scraper/docs/PLAN.md +336 -0
  207. package/references/skill-tree/scraper/drizzle.config.ts +10 -0
  208. package/references/skill-tree/scraper/package-lock.json +6329 -0
  209. package/references/skill-tree/scraper/package.json +68 -0
  210. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-description.md +7 -0
  211. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-name.md +7 -0
  212. package/references/skill-tree/scraper/test/fixtures/minimal-skill/SKILL.md +27 -0
  213. package/references/skill-tree/scraper/test/fixtures/skill-json/SKILL.json +21 -0
  214. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/SKILL.md +54 -0
  215. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/_meta.json +24 -0
  216. package/references/skill-tree/scraper/test/fixtures/valid-skill/SKILL.md +93 -0
  217. package/references/skill-tree/scraper/test/fixtures/valid-skill/_meta.json +22 -0
  218. package/references/skill-tree/scraper/tsup.config.ts +14 -0
  219. package/references/skill-tree/scraper/vitest.config.ts +17 -0
  220. package/references/skill-tree/scripts/convert-to-vitest.ts +166 -0
  221. package/references/skill-tree/skills/skill-writer/SKILL.md +339 -0
  222. package/references/skill-tree/skills/skill-writer/references/examples.md +326 -0
  223. package/references/skill-tree/skills/skill-writer/references/patterns.md +210 -0
  224. package/references/skill-tree/skills/skill-writer/references/quality-checklist.md +123 -0
  225. package/references/skill-tree/test/run-all.ts +106 -0
  226. package/references/skill-tree/test/utils.ts +128 -0
  227. package/references/skill-tree/vitest.config.ts +16 -0
  228. package/references/swarmkit/src/commands/init/phases/configure.ts +0 -22
  229. package/references/swarmkit/src/commands/init/phases/global-setup.ts +5 -3
  230. package/references/swarmkit/src/commands/init/wizard.ts +2 -2
  231. package/references/swarmkit/src/packages/setup.test.ts +53 -7
  232. package/references/swarmkit/src/packages/setup.ts +37 -1
  233. package/scripts/bootstrap.mjs +26 -1
  234. package/scripts/generate-agents.mjs +5 -1
  235. package/scripts/map-hook.mjs +97 -64
  236. package/scripts/map-sidecar.mjs +179 -25
  237. package/scripts/team-loader.mjs +12 -41
  238. package/skills/swarm/SKILL.md +89 -25
  239. package/src/__tests__/agent-generator.test.mjs +6 -13
  240. package/src/__tests__/bootstrap.test.mjs +124 -1
  241. package/src/__tests__/config.test.mjs +200 -27
  242. package/src/__tests__/e2e-live-map.test.mjs +536 -0
  243. package/src/__tests__/e2e-mesh-sidecar.test.mjs +570 -0
  244. package/src/__tests__/e2e-native-task-hooks.test.mjs +376 -0
  245. package/src/__tests__/e2e-sidecar-bridge.test.mjs +477 -0
  246. package/src/__tests__/helpers.mjs +13 -0
  247. package/src/__tests__/inbox.test.mjs +22 -89
  248. package/src/__tests__/index.test.mjs +35 -9
  249. package/src/__tests__/integration.test.mjs +513 -0
  250. package/src/__tests__/map-events.test.mjs +514 -150
  251. package/src/__tests__/mesh-connection.test.mjs +308 -0
  252. package/src/__tests__/opentasks-client.test.mjs +517 -0
  253. package/src/__tests__/paths.test.mjs +185 -41
  254. package/src/__tests__/sidecar-client.test.mjs +35 -0
  255. package/src/__tests__/sidecar-server.test.mjs +124 -0
  256. package/src/__tests__/skilltree-client.test.mjs +80 -0
  257. package/src/agent-generator.mjs +104 -33
  258. package/src/bootstrap.mjs +150 -10
  259. package/src/config.mjs +81 -17
  260. package/src/context-output.mjs +58 -8
  261. package/src/inbox.mjs +9 -54
  262. package/src/index.mjs +39 -8
  263. package/src/map-connection.mjs +4 -3
  264. package/src/map-events.mjs +350 -80
  265. package/src/mesh-connection.mjs +148 -0
  266. package/src/opentasks-client.mjs +269 -0
  267. package/src/paths.mjs +182 -27
  268. package/src/sessionlog.mjs +14 -9
  269. package/src/sidecar-client.mjs +81 -27
  270. package/src/sidecar-server.mjs +175 -16
  271. package/src/skilltree-client.mjs +173 -0
  272. package/src/template.mjs +68 -4
  273. package/vitest.config.mjs +1 -0
@@ -0,0 +1,252 @@
1
+ /**
2
+ * StoreGraph: meta-layer above Minimem for managing linked stores.
3
+ *
4
+ * A StoreGraph resolves a store and its dependencies (depth 1),
5
+ * materializes them as needed, and produces an array of MemoryInstance
6
+ * objects that can be passed to MemoryToolExecutor or used directly.
7
+ *
8
+ * The Minimem class is unchanged — StoreGraph just orchestrates
9
+ * multiple independent Minimem instances.
10
+ */
11
+
12
+ import path from "node:path";
13
+
14
+ import { Minimem, type MinimemConfig } from "../minimem.js";
15
+ import type { MemoryInstance } from "../server/tools.js";
16
+ import {
17
+ loadManifest,
18
+ getLinkedStoreNames,
19
+ resolveStore,
20
+ resolveStoreName,
21
+ type StoreManifest,
22
+ type StoreDefinition,
23
+ } from "./manifest.js";
24
+ import { materializeStore, type MaterializeResult } from "./materialize.js";
25
+
26
+ export type StoreGraphOptions = {
27
+ /** Path to the global manifest file (default: ~/.config/minimem/stores.json) */
28
+ manifestPath?: string;
29
+ /** Factory to create a MinimemConfig for a given store directory */
30
+ configFactory?: (memoryDir: string, storeName: string) => Promise<MinimemConfig>;
31
+ /** Debug logging */
32
+ debug?: (message: string) => void;
33
+ };
34
+
35
+ export type ResolvedStore = {
36
+ name: string;
37
+ definition: StoreDefinition;
38
+ materialization: MaterializeResult;
39
+ instance: Minimem;
40
+ };
41
+
42
+ export class StoreGraph {
43
+ private manifest: StoreManifest;
44
+ private resolved: Map<string, ResolvedStore> = new Map();
45
+ private configFactory: (memoryDir: string, storeName: string) => Promise<MinimemConfig>;
46
+ private debug?: (message: string) => void;
47
+
48
+ private constructor(
49
+ manifest: StoreManifest,
50
+ opts?: StoreGraphOptions,
51
+ ) {
52
+ this.manifest = manifest;
53
+ this.debug = opts?.debug;
54
+ this.configFactory = opts?.configFactory ?? defaultConfigFactory;
55
+ }
56
+
57
+ /**
58
+ * Create a StoreGraph from the global manifest.
59
+ */
60
+ static async create(opts?: StoreGraphOptions): Promise<StoreGraph> {
61
+ const manifest = await loadManifest(opts?.manifestPath);
62
+ return new StoreGraph(manifest, opts);
63
+ }
64
+
65
+ /**
66
+ * Create a StoreGraph from an explicit manifest object (useful for testing).
67
+ */
68
+ static fromManifest(
69
+ manifest: StoreManifest,
70
+ opts?: StoreGraphOptions,
71
+ ): StoreGraph {
72
+ return new StoreGraph(manifest, opts);
73
+ }
74
+
75
+ /**
76
+ * Get the loaded manifest.
77
+ */
78
+ getManifest(): StoreManifest {
79
+ return this.manifest;
80
+ }
81
+
82
+ /**
83
+ * Resolve a store by name: materialize it and all its linked stores (depth 1).
84
+ * Returns an array of MemoryInstance objects ready for search.
85
+ *
86
+ * Linked stores that fail to materialize are skipped with a warning.
87
+ */
88
+ async resolve(storeName: string): Promise<MemoryInstance[]> {
89
+ const instances: MemoryInstance[] = [];
90
+
91
+ // Resolve the primary store
92
+ const primary = await this.resolveOne(storeName);
93
+ if (!primary) {
94
+ throw new Error(`Store "${storeName}" not found or unavailable`);
95
+ }
96
+ instances.push({
97
+ minimem: primary.instance,
98
+ memoryDir: primary.materialization.path,
99
+ name: storeName,
100
+ });
101
+
102
+ // Resolve linked stores (depth 1)
103
+ const linkedNames = await getLinkedStoreNames(this.manifest, storeName);
104
+ for (const linkedName of linkedNames) {
105
+ if (linkedName === storeName) continue; // skip self-links
106
+
107
+ try {
108
+ const linked = await this.resolveOne(linkedName);
109
+ if (linked) {
110
+ instances.push({
111
+ minimem: linked.instance,
112
+ memoryDir: linked.materialization.path,
113
+ name: linkedName,
114
+ });
115
+ } else {
116
+ this.debug?.(`Linked store "${linkedName}" unavailable, skipping`);
117
+ }
118
+ } catch (err) {
119
+ this.debug?.(
120
+ `Failed to resolve linked store "${linkedName}": ${String(err)}`,
121
+ );
122
+ }
123
+ }
124
+
125
+ return instances;
126
+ }
127
+
128
+ /**
129
+ * Resolve a store by directory path (looks up the store name in the manifest).
130
+ * Falls back to creating a standalone instance if the directory isn't in the manifest.
131
+ */
132
+ async resolveByPath(dirPath: string): Promise<MemoryInstance[]> {
133
+ const storeName = resolveStoreName(this.manifest, dirPath);
134
+ if (storeName) {
135
+ return this.resolve(storeName);
136
+ }
137
+
138
+ // Not in manifest — return standalone instance with no links
139
+ this.debug?.(`Directory "${dirPath}" not in manifest, using standalone`);
140
+ const config = await this.configFactory(dirPath, path.basename(dirPath));
141
+ const instance = await Minimem.create(config);
142
+ return [
143
+ {
144
+ minimem: instance,
145
+ memoryDir: dirPath,
146
+ name: path.basename(dirPath),
147
+ },
148
+ ];
149
+ }
150
+
151
+ /**
152
+ * List all known stores from the manifest with their link info.
153
+ */
154
+ async listStores(): Promise<
155
+ Array<{
156
+ name: string;
157
+ path: string;
158
+ remote?: string;
159
+ links: string[];
160
+ available: boolean;
161
+ }>
162
+ > {
163
+ const result: Array<{
164
+ name: string;
165
+ path: string;
166
+ remote?: string;
167
+ links: string[];
168
+ available: boolean;
169
+ }> = [];
170
+
171
+ for (const [name, def] of Object.entries(this.manifest.stores)) {
172
+ const links = await getLinkedStoreNames(this.manifest, name);
173
+ const { existsSync } = await import("node:fs");
174
+ const available = existsSync(def.path) || !!def.remote;
175
+
176
+ result.push({
177
+ name,
178
+ path: def.path,
179
+ remote: def.remote,
180
+ links,
181
+ available,
182
+ });
183
+ }
184
+
185
+ return result;
186
+ }
187
+
188
+ /**
189
+ * Close all resolved Minimem instances and clean up materializations.
190
+ */
191
+ async close(): Promise<void> {
192
+ for (const [, store] of this.resolved) {
193
+ try {
194
+ store.instance.close();
195
+ } catch {
196
+ // best effort
197
+ }
198
+ try {
199
+ await store.materialization.cleanup();
200
+ } catch {
201
+ // best effort
202
+ }
203
+ }
204
+ this.resolved.clear();
205
+ }
206
+
207
+ /**
208
+ * Resolve a single store by name.
209
+ * Returns cached instance if already resolved.
210
+ */
211
+ private async resolveOne(storeName: string): Promise<ResolvedStore | null> {
212
+ // Return cached if available
213
+ const cached = this.resolved.get(storeName);
214
+ if (cached) return cached;
215
+
216
+ const def = resolveStore(this.manifest, storeName);
217
+ if (!def) return null;
218
+
219
+ // Materialize
220
+ const materialization = await materializeStore(storeName, def);
221
+ if (!materialization) return null;
222
+
223
+ // Create Minimem instance
224
+ const config = await this.configFactory(materialization.path, storeName);
225
+ const instance = await Minimem.create(config);
226
+
227
+ const resolved: ResolvedStore = {
228
+ name: storeName,
229
+ definition: def,
230
+ materialization,
231
+ instance,
232
+ };
233
+
234
+ this.resolved.set(storeName, resolved);
235
+ return resolved;
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Default config factory: creates a minimal config with auto embedding.
241
+ * In practice, the CLI will provide a factory that respects per-store configs.
242
+ */
243
+ async function defaultConfigFactory(
244
+ memoryDir: string,
245
+ _storeName: string,
246
+ ): Promise<MinimemConfig> {
247
+ return {
248
+ memoryDir,
249
+ embedding: { provider: "auto" },
250
+ watch: { enabled: false },
251
+ };
252
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2023",
4
+ "lib": ["ES2023"],
5
+ "module": "NodeNext",
6
+ "moduleResolution": "NodeNext",
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "outDir": "dist",
14
+ "rootDir": "src",
15
+ "types": ["node"]
16
+ },
17
+ "include": ["src"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }
@@ -0,0 +1,26 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig([
4
+ // Library build
5
+ {
6
+ entry: ["src/index.ts", "src/session.ts", "src/internal.ts"],
7
+ format: ["esm", "cjs"],
8
+ dts: true,
9
+ clean: true,
10
+ sourcemap: true,
11
+ target: "node22",
12
+ external: ["node-llama-cpp"],
13
+ },
14
+ // CLI build - bundle everything into single file
15
+ {
16
+ entry: ["src/cli/index.ts"],
17
+ format: ["esm"],
18
+ outDir: "dist/cli",
19
+ sourcemap: true,
20
+ target: "node22",
21
+ external: ["node-llama-cpp", "commander"],
22
+ banner: {
23
+ js: "#!/usr/bin/env node",
24
+ },
25
+ },
26
+ ]);
@@ -0,0 +1,29 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ watch: false,
6
+ include: ["src/**/*.test.ts"],
7
+ exclude: [
8
+ "**/node_modules/**",
9
+ "**/clawdbot/**",
10
+ "**/dist/**",
11
+ // These tests use node:sqlite which Vite can't handle
12
+ // Run with: npm run test:integration or npm run test:cli
13
+ "**/*.integration.test.ts",
14
+ "**/cli/__tests__/commands.test.ts",
15
+ // knowledge.test.ts uses node:sqlite for graph tests — run via test:knowledge
16
+ // Frontmatter tests are in knowledge-frontmatter.test.ts (vitest-compatible)
17
+ "src/__tests__/knowledge.test.ts",
18
+ // store-graph tests use Minimem (node:sqlite) — run via test:integration
19
+ "src/store/__tests__/store-graph.test.ts",
20
+ ],
21
+ // Run tests sequentially to avoid XDG_CONFIG_HOME conflicts
22
+ pool: "forks",
23
+ poolOptions: {
24
+ forks: {
25
+ singleFork: true,
26
+ },
27
+ },
28
+ },
29
+ });
@@ -26,6 +26,7 @@ export function createGenerateCommands(): Command {
26
26
  "Output path (default: <dir>/SKILL.md)"
27
27
  )
28
28
  .option("--no-cli-examples", "Omit CLI usage examples")
29
+ .option("--no-spawn-rules", "Omit spawn rules section")
29
30
  .action((dir: string, opts) => {
30
31
  try {
31
32
  const template = TemplateLoader.load(dir);
@@ -33,6 +34,7 @@ export function createGenerateCommands(): Command {
33
34
  const content = generateSkillMd(template, {
34
35
  teamName,
35
36
  includeCliExamples: opts.cliExamples !== false,
37
+ includeSpawnRules: opts.spawnRules !== false,
36
38
  });
37
39
 
38
40
  const outputPath = opts.output ?? path.join(dir, "SKILL.md");
@@ -55,6 +57,8 @@ export function createGenerateCommands(): Command {
55
57
  "Output directory for prompt files (default: <dir>/agents/)"
56
58
  )
57
59
  .option("--preamble <text>", "Additional context to prepend to every prompt")
60
+ .option("--no-spawn-section", "Omit spawn permissions from agent prompts")
61
+ .option("--no-cli-section", "Omit CLI quick reference from agent prompts")
58
62
  .action((dir: string, opts) => {
59
63
  try {
60
64
  const template = TemplateLoader.load(dir);
@@ -62,6 +66,8 @@ export function createGenerateCommands(): Command {
62
66
  const prompts = generateAgentPrompts(template, {
63
67
  teamName,
64
68
  preamble: opts.preamble,
69
+ includeSpawnSection: opts.spawnSection !== false,
70
+ includeCliSection: opts.cliSection !== false,
65
71
  });
66
72
 
67
73
  const outputDir = opts.output ?? path.join(dir, "agents");
@@ -92,6 +98,9 @@ export function createGenerateCommands(): Command {
92
98
  "Output base directory (default: <dir>)"
93
99
  )
94
100
  .option("--preamble <text>", "Additional context for agent prompts")
101
+ .option("--no-spawn-rules", "Omit spawn rules from SKILL.md")
102
+ .option("--no-spawn-section", "Omit spawn permissions from agent prompts")
103
+ .option("--no-cli-section", "Omit CLI quick reference from agent prompts")
95
104
  .action((dir: string, opts) => {
96
105
  try {
97
106
  const template = TemplateLoader.load(dir);
@@ -99,7 +108,10 @@ export function createGenerateCommands(): Command {
99
108
  const baseDir = opts.output ?? dir;
100
109
 
101
110
  // Generate SKILL.md
102
- const skillContent = generateSkillMd(template, { teamName });
111
+ const skillContent = generateSkillMd(template, {
112
+ teamName,
113
+ includeSpawnRules: opts.spawnRules !== false,
114
+ });
103
115
  const skillPath = path.join(baseDir, "SKILL.md");
104
116
  fs.writeFileSync(skillPath, skillContent, "utf-8");
105
117
  console.log(`Generated ${skillPath}`);
@@ -108,6 +120,8 @@ export function createGenerateCommands(): Command {
108
120
  const prompts = generateAgentPrompts(template, {
109
121
  teamName,
110
122
  preamble: opts.preamble,
123
+ includeSpawnSection: opts.spawnSection !== false,
124
+ includeCliSection: opts.cliSection !== false,
111
125
  });
112
126
  const agentsDir = path.join(baseDir, "agents");
113
127
  fs.mkdirSync(agentsDir, { recursive: true });
@@ -136,6 +150,8 @@ export function createGenerateCommands(): Command {
136
150
  "-o, --output <path>",
137
151
  "Output directory (default: <dir>/package/)"
138
152
  )
153
+ .option("--no-spawn-section", "Omit spawn permissions from role SKILL.md files")
154
+ .option("--no-cli-section", "Omit CLI quick reference from role SKILL.md files")
139
155
  .action((dir: string, opts) => {
140
156
  try {
141
157
  const template = TemplateLoader.load(dir);
@@ -145,6 +161,8 @@ export function createGenerateCommands(): Command {
145
161
  const result = generatePackage(template, {
146
162
  teamName,
147
163
  outputDir,
164
+ includeSpawnSection: opts.spawnSection !== false,
165
+ includeCliSection: opts.cliSection !== false,
148
166
  });
149
167
 
150
168
  console.log(`Generated skill package in ${outputDir}`);
@@ -194,12 +212,16 @@ export function createGenerateCommands(): Command {
194
212
  .requiredOption("-r, --role <role>", "Role name")
195
213
  .option("-n, --name <name>", "Override the team name")
196
214
  .option("-o, --output <path>", "Output path (default: stdout)")
215
+ .option("--no-spawn-section", "Omit spawn permissions section")
216
+ .option("--no-cli-section", "Omit CLI quick reference section")
197
217
  .action((dir: string, opts) => {
198
218
  try {
199
219
  const template = TemplateLoader.load(dir);
200
220
  const teamName = opts.name ?? template.manifest.name;
201
221
  const result = generateRoleSkillMd(template, opts.role, {
202
222
  teamName,
223
+ includeSpawnSection: opts.spawnSection !== false,
224
+ includeCliSection: opts.cliSection !== false,
203
225
  });
204
226
 
205
227
  if (opts.output) {
@@ -311,6 +311,100 @@ describe("generateRoleSkillMd", () => {
311
311
  });
312
312
  });
313
313
 
314
+ describe("section exclusion options (generateAgentPrompts)", () => {
315
+ it("includes spawn and CLI sections by default", () => {
316
+ const prompts = generateAgentPrompts(makeFullTemplate());
317
+ const planner = prompts.find((p) => p.role === "planner")!;
318
+ expect(planner.prompt).toContain("## Spawn Permissions");
319
+ expect(planner.prompt).toContain("## CLI Quick Reference");
320
+ });
321
+
322
+ it("excludes spawn section when includeSpawnSection is false", () => {
323
+ const prompts = generateAgentPrompts(makeFullTemplate(), {
324
+ includeSpawnSection: false,
325
+ });
326
+ for (const prompt of prompts) {
327
+ expect(prompt.prompt).not.toContain("## Spawn Permissions");
328
+ }
329
+ });
330
+
331
+ it("excludes CLI section when includeCliSection is false", () => {
332
+ const prompts = generateAgentPrompts(makeFullTemplate(), {
333
+ includeCliSection: false,
334
+ });
335
+ for (const prompt of prompts) {
336
+ expect(prompt.prompt).not.toContain("## CLI Quick Reference");
337
+ }
338
+ });
339
+
340
+ it("excludes both sections when both are false", () => {
341
+ const prompts = generateAgentPrompts(makeFullTemplate(), {
342
+ includeSpawnSection: false,
343
+ includeCliSection: false,
344
+ });
345
+ for (const prompt of prompts) {
346
+ expect(prompt.prompt).not.toContain("## Spawn Permissions");
347
+ expect(prompt.prompt).not.toContain("## CLI Quick Reference");
348
+ }
349
+ });
350
+ });
351
+
352
+ describe("section exclusion options (generateAgentPrompt single)", () => {
353
+ it("excludes spawn section when includeSpawnSection is false", () => {
354
+ const prompt = generateAgentPrompt(makeFullTemplate(), "planner", {
355
+ includeSpawnSection: false,
356
+ });
357
+ expect(prompt.prompt).not.toContain("## Spawn Permissions");
358
+ expect(prompt.prompt).toContain("## CLI Quick Reference");
359
+ });
360
+
361
+ it("excludes CLI section when includeCliSection is false", () => {
362
+ const prompt = generateAgentPrompt(makeFullTemplate(), "planner", {
363
+ includeCliSection: false,
364
+ });
365
+ expect(prompt.prompt).toContain("## Spawn Permissions");
366
+ expect(prompt.prompt).not.toContain("## CLI Quick Reference");
367
+ });
368
+ });
369
+
370
+ describe("section exclusion options (generateRoleSkillMd)", () => {
371
+ it("includes spawn and CLI sections by default", () => {
372
+ const result = generateRoleSkillMd(makeFullTemplate(), "planner");
373
+ expect(result.content).toContain("## Spawn Permissions");
374
+ expect(result.content).toContain("## CLI Quick Reference");
375
+ expect(result.content).toContain("can_spawn: [grinder, planner]");
376
+ });
377
+
378
+ it("excludes spawn section and can_spawn frontmatter when includeSpawnSection is false", () => {
379
+ const result = generateRoleSkillMd(makeFullTemplate(), "planner", {
380
+ includeSpawnSection: false,
381
+ });
382
+ expect(result.content).not.toContain("## Spawn Permissions");
383
+ expect(result.content).not.toContain("can_spawn:");
384
+ // CLI should still be included
385
+ expect(result.content).toContain("## CLI Quick Reference");
386
+ });
387
+
388
+ it("excludes CLI section when includeCliSection is false", () => {
389
+ const result = generateRoleSkillMd(makeFullTemplate(), "planner", {
390
+ includeCliSection: false,
391
+ });
392
+ expect(result.content).not.toContain("## CLI Quick Reference");
393
+ // Spawn should still be included
394
+ expect(result.content).toContain("## Spawn Permissions");
395
+ });
396
+
397
+ it("excludes both sections when both are false", () => {
398
+ const result = generateRoleSkillMd(makeFullTemplate(), "planner", {
399
+ includeSpawnSection: false,
400
+ includeCliSection: false,
401
+ });
402
+ expect(result.content).not.toContain("## Spawn Permissions");
403
+ expect(result.content).not.toContain("## CLI Quick Reference");
404
+ expect(result.content).not.toContain("can_spawn:");
405
+ });
406
+ });
407
+
314
408
  describe("generateAllRoleSkillMds", () => {
315
409
  it("generates a skill md for each role", () => {
316
410
  const results = generateAllRoleSkillMds(makeFullTemplate());
@@ -16,6 +16,10 @@ export interface AgentPromptGeneratorOptions {
16
16
  teamName?: string;
17
17
  /** Additional context to prepend to every agent prompt */
18
18
  preamble?: string;
19
+ /** Whether to include the "Spawn Permissions" section. Defaults to true. */
20
+ includeSpawnSection?: boolean;
21
+ /** Whether to include the "CLI Quick Reference" section. Defaults to true. */
22
+ includeCliSection?: boolean;
19
23
  }
20
24
 
21
25
  export interface RoleSkillMd {
@@ -26,6 +30,10 @@ export interface RoleSkillMd {
26
30
  export interface RoleSkillMdOptions {
27
31
  /** Team name override */
28
32
  teamName?: string;
33
+ /** Whether to include the "Spawn Permissions" section. Defaults to true. */
34
+ includeSpawnSection?: boolean;
35
+ /** Whether to include the "CLI Quick Reference" section. Defaults to true. */
36
+ includeCliSection?: boolean;
29
37
  }
30
38
 
31
39
  /**
@@ -46,8 +54,10 @@ export function generateAgentPrompts(
46
54
  options: AgentPromptGeneratorOptions = {}
47
55
  ): AgentPrompt[] {
48
56
  const teamName = options.teamName ?? template.manifest.name;
57
+ const includeSpawn = options.includeSpawnSection ?? true;
58
+ const includeCli = options.includeCliSection ?? true;
49
59
  return template.manifest.roles.map((roleName) =>
50
- generateSingleAgentPrompt(template, roleName, teamName, options.preamble)
60
+ generateSingleAgentPrompt(template, roleName, teamName, options.preamble, includeSpawn, includeCli)
51
61
  );
52
62
  }
53
63
 
@@ -60,11 +70,15 @@ export function generateAgentPrompt(
60
70
  options: AgentPromptGeneratorOptions = {}
61
71
  ): AgentPrompt {
62
72
  const teamName = options.teamName ?? template.manifest.name;
73
+ const includeSpawn = options.includeSpawnSection ?? true;
74
+ const includeCli = options.includeCliSection ?? true;
63
75
  return generateSingleAgentPrompt(
64
76
  template,
65
77
  roleName,
66
78
  teamName,
67
- options.preamble
79
+ options.preamble,
80
+ includeSpawn,
81
+ includeCli,
68
82
  );
69
83
  }
70
84
 
@@ -81,6 +95,8 @@ export function generateRoleSkillMd(
81
95
  options: RoleSkillMdOptions = {}
82
96
  ): RoleSkillMd {
83
97
  const teamName = options.teamName ?? template.manifest.name;
98
+ const includeSpawn = options.includeSpawnSection ?? true;
99
+ const includeCli = options.includeCliSection ?? true;
84
100
  const m = template.manifest;
85
101
  const role = template.roles.get(roleName);
86
102
  const rolePrompts = template.prompts.get(roleName);
@@ -88,7 +104,7 @@ export function generateRoleSkillMd(
88
104
  const sections: string[] = [];
89
105
 
90
106
  // YAML frontmatter
91
- sections.push(generateRoleFrontmatter(template, roleName, teamName));
107
+ sections.push(generateRoleFrontmatter(template, roleName, teamName, includeSpawn));
92
108
 
93
109
  // Identity header
94
110
  sections.push(`# Role: ${roleName}`);
@@ -133,10 +149,14 @@ export function generateRoleSkillMd(
133
149
  }
134
150
 
135
151
  // Spawn permissions
136
- sections.push(generateRoleSpawnSection(template, roleName));
152
+ if (includeSpawn) {
153
+ sections.push(generateRoleSpawnSection(template, roleName));
154
+ }
137
155
 
138
156
  // CLI reference
139
- sections.push(generateRoleCliSection(roleName, teamName, template));
157
+ if (includeCli) {
158
+ sections.push(generateRoleCliSection(roleName, teamName, template));
159
+ }
140
160
 
141
161
  return {
142
162
  role: roleName,
@@ -159,7 +179,8 @@ export function generateAllRoleSkillMds(
159
179
  function generateRoleFrontmatter(
160
180
  template: ResolvedTemplate,
161
181
  roleName: string,
162
- teamName: string
182
+ teamName: string,
183
+ includeSpawn: boolean = true,
163
184
  ): string {
164
185
  const m = template.manifest;
165
186
  const role = template.roles.get(roleName);
@@ -198,10 +219,12 @@ function generateRoleFrontmatter(
198
219
  lines.push(`emits: [${emissions.join(", ")}]`);
199
220
  }
200
221
 
201
- const spawnRules = m.topology.spawn_rules?.[roleName];
202
- if (spawnRules && spawnRules.length > 0) {
203
- const names = spawnRules.map((e) => typeof e === "string" ? e : e.role);
204
- lines.push(`can_spawn: [${names.join(", ")}]`);
222
+ if (includeSpawn) {
223
+ const spawnRules = m.topology.spawn_rules?.[roleName];
224
+ if (spawnRules && spawnRules.length > 0) {
225
+ const names = spawnRules.map((e) => typeof e === "string" ? e : e.role);
226
+ lines.push(`can_spawn: [${names.join(", ")}]`);
227
+ }
205
228
  }
206
229
 
207
230
  lines.push("---");
@@ -275,7 +298,9 @@ function generateSingleAgentPrompt(
275
298
  template: ResolvedTemplate,
276
299
  roleName: string,
277
300
  teamName: string,
278
- preamble?: string
301
+ preamble?: string,
302
+ includeSpawn: boolean = true,
303
+ includeCli: boolean = true,
279
304
  ): AgentPrompt {
280
305
  const m = template.manifest;
281
306
  const role = template.roles.get(roleName);
@@ -318,10 +343,14 @@ function generateSingleAgentPrompt(
318
343
  }
319
344
 
320
345
  // Spawn permissions
321
- sections.push(generateRoleSpawnSection(template, roleName));
346
+ if (includeSpawn) {
347
+ sections.push(generateRoleSpawnSection(template, roleName));
348
+ }
322
349
 
323
350
  // CLI reference
324
- sections.push(generateRoleCliSection(roleName, teamName, template));
351
+ if (includeCli) {
352
+ sections.push(generateRoleCliSection(roleName, teamName, template));
353
+ }
325
354
 
326
355
  return {
327
356
  role: roleName,
@@ -10,6 +10,10 @@ export interface PackageGeneratorOptions {
10
10
  teamName?: string;
11
11
  /** Output directory for the package */
12
12
  outputDir: string;
13
+ /** Whether to include spawn permissions in per-role SKILL.md. Defaults to true. */
14
+ includeSpawnSection?: boolean;
15
+ /** Whether to include CLI quick reference in per-role SKILL.md. Defaults to true. */
16
+ includeCliSection?: boolean;
13
17
  }
14
18
 
15
19
  export interface PackageResult {
@@ -51,7 +55,11 @@ export function generatePackage(
51
55
  fs.writeFileSync(catalogPath, catalogContent, "utf-8");
52
56
 
53
57
  // 2. Generate per-role SKILL.md files
54
- const roleSkills = generateAllRoleSkillMds(template, { teamName });
58
+ const roleSkills = generateAllRoleSkillMds(template, {
59
+ teamName,
60
+ includeSpawnSection: options.includeSpawnSection,
61
+ includeCliSection: options.includeCliSection,
62
+ });
55
63
  const rolePaths: { role: string; path: string }[] = [];
56
64
 
57
65
  for (const roleSkill of roleSkills) {