swarmkit 0.0.2 → 0.0.4

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.
@@ -1,48 +1,146 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { promisify } from "node:util";
3
- import { existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
3
+ import { existsSync, lstatSync, mkdirSync, readFileSync, renameSync, symlinkSync, writeFileSync, } from "node:fs";
4
4
  import { basename, join } from "node:path";
5
5
  import { homedir } from "node:os";
6
6
  const execFileAsync = promisify(execFile);
7
7
  // ─── Project-level setup ─────────────────────────────────────────────────────
8
- /** Config directories each package creates at the project level */
8
+ /** Root directory for all swarmkit project-level config */
9
+ export const PROJECT_ROOT = ".swarm";
10
+ /** Config directories with .swarm/ prefix (default layout) */
9
11
  export const PROJECT_CONFIG_DIRS = {
12
+ opentasks: ".swarm/opentasks",
13
+ minimem: ".swarm/minimem",
14
+ "cognitive-core": ".swarm/cognitive-core",
15
+ "skill-tree": ".swarm/skilltree",
16
+ "self-driving-repo": ".swarm/self-driving",
17
+ openteams: ".swarm/openteams",
18
+ sessionlog: ".swarm/sessionlog",
19
+ "claude-code-swarm": ".swarm/claude-swarm",
20
+ };
21
+ /** Config directories without prefix (flat layout, --no-prefix) */
22
+ export const FLAT_PROJECT_CONFIG_DIRS = {
10
23
  opentasks: ".opentasks",
11
24
  minimem: ".minimem",
12
25
  "cognitive-core": ".cognitive-core",
13
- "macro-agent": ".multiagent",
26
+ "skill-tree": ".skilltree",
14
27
  "self-driving-repo": ".self-driving",
28
+ openteams: ".openteams",
29
+ sessionlog: ".sessionlog",
30
+ "claude-code-swarm": ".claude-swarm",
15
31
  };
32
+ /** Get config dirs for the given mode */
33
+ export function projectConfigDirs(usePrefix) {
34
+ return usePrefix ? PROJECT_CONFIG_DIRS : FLAT_PROJECT_CONFIG_DIRS;
35
+ }
16
36
  /**
17
37
  * Project-level packages in correct init order.
18
- * Order matters: minimem before cognitive-core (runtime detection),
19
- * opentasks before macro-agent (task backend wiring).
38
+ * Order matters: minimem before cognitive-core (runtime detection).
20
39
  */
21
40
  export const PROJECT_INIT_ORDER = [
22
41
  "opentasks",
23
42
  "minimem",
24
43
  "cognitive-core",
25
- "macro-agent",
44
+ "skill-tree",
26
45
  "self-driving-repo",
46
+ "openteams",
47
+ "sessionlog",
48
+ "claude-code-swarm",
27
49
  ];
28
- /** Check whether a package is already initialized in a project */
50
+ /** Check whether a package is already initialized in a project (checks both layouts) */
29
51
  export function isProjectInit(cwd, pkg) {
30
- const dir = PROJECT_CONFIG_DIRS[pkg];
31
- return dir ? existsSync(join(cwd, dir)) : false;
52
+ const prefixed = PROJECT_CONFIG_DIRS[pkg];
53
+ const flat = FLAT_PROJECT_CONFIG_DIRS[pkg];
54
+ return (prefixed ? existsSync(join(cwd, prefixed)) : false) ||
55
+ (flat ? existsSync(join(cwd, flat)) : false);
56
+ }
57
+ /** Ensure the .swarm/ project root directory exists */
58
+ function ensureProjectRoot(cwd) {
59
+ const root = join(cwd, PROJECT_ROOT);
60
+ if (!existsSync(root)) {
61
+ mkdirSync(root, { recursive: true });
62
+ }
63
+ }
64
+ /**
65
+ * After init, relocate a package's config dir into .swarm/ if the CLI
66
+ * created it at the legacy top-level location, then leave a symlink at
67
+ * the old path so the package can still find its data at runtime.
68
+ * This is a no-op when the package already respects its env-var override.
69
+ */
70
+ function relocate(cwd, legacyName, targetName) {
71
+ const src = join(cwd, legacyName);
72
+ const dest = join(cwd, PROJECT_ROOT, targetName);
73
+ // Move the directory if it was created at the legacy location
74
+ if (existsSync(src) && !isSymlink(src) && !existsSync(dest)) {
75
+ try {
76
+ renameSync(src, dest);
77
+ }
78
+ catch {
79
+ return; // Non-fatal — leave in legacy location
80
+ }
81
+ }
82
+ // Create a symlink at the legacy location so packages find their data
83
+ ensureSymlink(cwd, legacyName, targetName);
84
+ }
85
+ /** Create a relative symlink: cwd/<legacyName> → .swarm/<targetName> */
86
+ function ensureSymlink(cwd, legacyName, targetName) {
87
+ const link = join(cwd, legacyName);
88
+ const target = join(PROJECT_ROOT, targetName); // relative path
89
+ if (isSymlink(link))
90
+ return; // Already symlinked
91
+ if (existsSync(link))
92
+ return; // Real directory exists — don't overwrite
93
+ try {
94
+ symlinkSync(target, link);
95
+ }
96
+ catch {
97
+ // Non-fatal — package can still be configured via env var
98
+ }
99
+ }
100
+ function isSymlink(path) {
101
+ try {
102
+ return lstatSync(path).isSymbolicLink();
103
+ }
104
+ catch {
105
+ return false;
106
+ }
32
107
  }
33
108
  /** Initialize a single project-level package */
34
109
  export async function initProjectPackage(pkg, ctx) {
110
+ if (ctx.usePrefix) {
111
+ ensureProjectRoot(ctx.cwd);
112
+ }
35
113
  switch (pkg) {
36
- case "opentasks":
37
- return shellInit("opentasks", ["init", "--name", getProjectName(ctx.cwd)], ctx.cwd);
114
+ case "opentasks": {
115
+ const result = await shellInit("opentasks", ["init", "--name", getProjectName(ctx.cwd)], ctx.cwd, ctx.usePrefix
116
+ ? { OPENTASKS_PROJECT_DIR: join(PROJECT_ROOT, "opentasks") }
117
+ : undefined);
118
+ // relocate handles packages that don't yet respect the env var;
119
+ // for packages that create directly in .swarm/, this is a no-op.
120
+ if (ctx.usePrefix)
121
+ relocate(ctx.cwd, ".opentasks", "opentasks");
122
+ return result;
123
+ }
38
124
  case "minimem":
39
125
  return initMinimem(ctx);
40
- case "cognitive-core":
41
- return shellInit("cognitive-core", ["init"], ctx.cwd);
42
- case "macro-agent":
43
- return initMacroAgent(ctx);
126
+ case "cognitive-core": {
127
+ const result = await shellInit("cognitive-core", ["init"], ctx.cwd, ctx.usePrefix
128
+ ? { COGNITIVE_CORE_HOME: join(ctx.cwd, PROJECT_ROOT, "cognitive-core") }
129
+ : undefined);
130
+ if (ctx.usePrefix)
131
+ relocate(ctx.cwd, ".cognitive-core", "cognitive-core");
132
+ return result;
133
+ }
134
+ case "skill-tree":
135
+ return initSkillTreeProject(ctx);
44
136
  case "self-driving-repo":
45
- return shellInit("sdr", ["init", "-t", "triage-only"], ctx.cwd);
137
+ return initSdr(ctx);
138
+ case "openteams":
139
+ return initOpenteamsProject(ctx);
140
+ case "sessionlog":
141
+ return initSessionlogProject(ctx);
142
+ case "claude-code-swarm":
143
+ return initClaudeSwarmProject(ctx);
46
144
  default:
47
145
  return { package: pkg, success: false, message: "Unknown package" };
48
146
  }
@@ -50,9 +148,7 @@ export async function initProjectPackage(pkg, ctx) {
50
148
  // ─── Global-level setup ──────────────────────────────────────────────────────
51
149
  /** Config directories for global packages (relative to homedir) */
52
150
  export const GLOBAL_CONFIG_DIRS = {
53
- "agent-iam": ".agent-credentials",
54
151
  "skill-tree": ".skill-tree",
55
- openswarm: ".openswarm",
56
152
  openhive: ".openhive",
57
153
  };
58
154
  /** Check whether a global package is already configured */
@@ -65,12 +161,8 @@ export function isGlobalInit(pkg) {
65
161
  /** Initialize a single global package */
66
162
  export async function initGlobalPackage(pkg, ctx, openhiveOpts) {
67
163
  switch (pkg) {
68
- case "agent-iam":
69
- return initAgentIam(ctx);
70
164
  case "skill-tree":
71
165
  return initSkillTree();
72
- case "openswarm":
73
- return initOpenswarm(ctx);
74
166
  case "openhive":
75
167
  return openhiveOpts
76
168
  ? initOpenhive(openhiveOpts)
@@ -83,6 +175,8 @@ export async function initGlobalPackage(pkg, ctx, openhiveOpts) {
83
175
  return { package: "openteams", success: true, message: "no setup required" };
84
176
  case "sessionlog":
85
177
  return { package: "sessionlog", success: true, message: "no setup required" };
178
+ case "claude-code-swarm":
179
+ return { package: "claude-code-swarm", success: true, message: "no setup required" };
86
180
  default:
87
181
  return { package: pkg, success: false, message: "Unknown package" };
88
182
  }
@@ -97,10 +191,13 @@ function cleanEnv() {
97
191
  return env;
98
192
  }
99
193
  /** Shell out to a package's CLI init command */
100
- async function shellInit(command, args, cwd) {
194
+ async function shellInit(command, args, cwd, envOverrides) {
101
195
  const pkg = command === "sdr" ? "self-driving-repo" : command;
102
196
  try {
103
- await execFileAsync(command, args, { cwd, timeout: 30_000, env: cleanEnv() });
197
+ const env = envOverrides
198
+ ? { ...cleanEnv(), ...envOverrides }
199
+ : cleanEnv();
200
+ await execFileAsync(command, args, { cwd, timeout: 30_000, env });
104
201
  return { package: pkg, success: true };
105
202
  }
106
203
  catch (err) {
@@ -108,15 +205,25 @@ async function shellInit(command, args, cwd) {
108
205
  }
109
206
  }
110
207
  async function initMinimem(ctx) {
208
+ const targetDir = ctx.usePrefix
209
+ ? join(ctx.cwd, PROJECT_ROOT, "minimem")
210
+ : join(ctx.cwd, ".minimem");
111
211
  try {
112
212
  await execFileAsync("minimem", ["init"], {
113
213
  cwd: ctx.cwd,
114
214
  timeout: 30_000,
115
- env: cleanEnv(),
215
+ env: ctx.usePrefix
216
+ ? { ...cleanEnv(), MINIMEM_CONFIG_DIR: join(PROJECT_ROOT, "minimem") }
217
+ : cleanEnv(),
116
218
  });
219
+ // relocate handles packages that don't yet respect the env var;
220
+ // for packages that create directly in .swarm/, this is a no-op.
221
+ if (ctx.usePrefix) {
222
+ relocate(ctx.cwd, ".minimem", "minimem");
223
+ }
117
224
  // Patch embedding provider if configured
118
225
  if (ctx.embeddingProvider && ctx.embeddingProvider !== "local") {
119
- const configPath = join(ctx.cwd, ".minimem", "config.json");
226
+ const configPath = join(targetDir, "config.json");
120
227
  if (existsSync(configPath)) {
121
228
  try {
122
229
  const config = JSON.parse(readFileSync(configPath, "utf-8"));
@@ -135,65 +242,71 @@ async function initMinimem(ctx) {
135
242
  return { package: "minimem", success: false, message: formatError(err) };
136
243
  }
137
244
  }
138
- async function initMacroAgent(ctx) {
245
+ async function initSdr(ctx) {
246
+ const result = await shellInit("sdr", ["init", "-t", "triage-only"], ctx.cwd, ctx.usePrefix
247
+ ? { SDR_CONFIG_DIR: join(PROJECT_ROOT, "self-driving") }
248
+ : undefined);
249
+ // relocate handles packages that don't yet respect the env var;
250
+ // for packages that create directly in .swarm/, this is a no-op.
251
+ if (ctx.usePrefix) {
252
+ relocate(ctx.cwd, ".self-driving", "self-driving");
253
+ }
254
+ return result;
255
+ }
256
+ async function initSkillTreeProject(ctx) {
139
257
  try {
140
- const configDir = join(ctx.cwd, ".multiagent");
141
- mkdirSync(configDir, { recursive: true });
142
- const config = {
143
- team: "default",
144
- port: 3001,
145
- host: "localhost",
258
+ const targetDir = ctx.usePrefix
259
+ ? join(ctx.cwd, PROJECT_ROOT, "skilltree")
260
+ : join(ctx.cwd, ".skilltree");
261
+ mkdirSync(targetDir, { recursive: true });
262
+ mkdirSync(join(targetDir, "skills"), { recursive: true });
263
+ return { package: "skill-tree", success: true };
264
+ }
265
+ catch (err) {
266
+ return {
267
+ package: "skill-tree",
268
+ success: false,
269
+ message: formatError(err),
146
270
  };
147
- // Wire up opentasks if selected
148
- if (ctx.packages.includes("opentasks")) {
149
- config.task = {
150
- backend: "opentasks",
151
- opentasks: { auto_start: true },
152
- };
271
+ }
272
+ }
273
+ async function initOpenteamsProject(ctx) {
274
+ try {
275
+ const targetDir = ctx.usePrefix
276
+ ? join(ctx.cwd, PROJECT_ROOT, "openteams")
277
+ : join(ctx.cwd, ".openteams");
278
+ mkdirSync(targetDir, { recursive: true });
279
+ // Write default config.json (matches `openteams template init` with no options)
280
+ const configPath = join(targetDir, "config.json");
281
+ if (!existsSync(configPath)) {
282
+ writeFileSync(configPath, JSON.stringify({}, null, 2) + "\n");
153
283
  }
154
- writeFileSync(join(configDir, "config.json"), JSON.stringify(config, null, 2) + "\n");
155
- return { package: "macro-agent", success: true };
284
+ return { package: "openteams", success: true };
156
285
  }
157
286
  catch (err) {
158
287
  return {
159
- package: "macro-agent",
288
+ package: "openteams",
160
289
  success: false,
161
290
  message: formatError(err),
162
291
  };
163
292
  }
164
293
  }
165
- async function initAgentIam(ctx) {
294
+ async function initSessionlogProject(ctx) {
166
295
  try {
167
- const credDir = join(homedir(), ".agent-credentials");
168
- if (!existsSync(credDir)) {
169
- mkdirSync(credDir, { recursive: true, mode: 0o700 });
170
- }
171
- // Register stored API keys with agent-iam
172
- const env = { ...cleanEnv(), HOME: homedir() };
173
- for (const [provider, key] of Object.entries(ctx.apiKeys)) {
174
- if (["anthropic", "openai", "gemini"].includes(provider)) {
175
- try {
176
- await execFileAsync("agent-iam", [
177
- "apikey",
178
- "add",
179
- "--name",
180
- provider,
181
- "--provider",
182
- provider,
183
- "--key",
184
- key,
185
- ], { timeout: 15_000, env });
186
- }
187
- catch {
188
- // Non-fatal — agent-iam CLI may not be fully installed yet
189
- }
190
- }
296
+ const targetDir = ctx.usePrefix
297
+ ? join(ctx.cwd, PROJECT_ROOT, "sessionlog")
298
+ : join(ctx.cwd, ".sessionlog");
299
+ mkdirSync(targetDir, { recursive: true });
300
+ // Write default settings.json
301
+ const settingsPath = join(targetDir, "settings.json");
302
+ if (!existsSync(settingsPath)) {
303
+ writeFileSync(settingsPath, JSON.stringify({ enabled: false, strategy: "manual-commit" }, null, 2) + "\n");
191
304
  }
192
- return { package: "agent-iam", success: true };
305
+ return { package: "sessionlog", success: true };
193
306
  }
194
307
  catch (err) {
195
308
  return {
196
- package: "agent-iam",
309
+ package: "sessionlog",
197
310
  success: false,
198
311
  message: formatError(err),
199
312
  };
@@ -224,40 +337,6 @@ async function initSkillTree() {
224
337
  };
225
338
  }
226
339
  }
227
- async function initOpenswarm(ctx) {
228
- const configDir = join(homedir(), ".openswarm");
229
- const configPath = join(configDir, "server.json");
230
- if (existsSync(configPath)) {
231
- return {
232
- package: "openswarm",
233
- success: true,
234
- message: "already configured",
235
- };
236
- }
237
- try {
238
- mkdirSync(configDir, { recursive: true });
239
- const config = {
240
- host: "localhost",
241
- port: 3000,
242
- auth: { mode: "none" },
243
- storage: { type: "memory" },
244
- logging: { level: "info" },
245
- };
246
- // Configure macro-agent adapter if installed
247
- if (ctx.packages.includes("macro-agent")) {
248
- config.adapter = { id: "macro-agent" };
249
- }
250
- writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
251
- return { package: "openswarm", success: true };
252
- }
253
- catch (err) {
254
- return {
255
- package: "openswarm",
256
- success: false,
257
- message: formatError(err),
258
- };
259
- }
260
- }
261
340
  async function initOpenhive(opts) {
262
341
  try {
263
342
  const args = [
@@ -286,6 +365,32 @@ async function initOpenhive(opts) {
286
365
  };
287
366
  }
288
367
  }
368
+ async function initClaudeSwarmProject(ctx) {
369
+ try {
370
+ const targetDir = ctx.usePrefix
371
+ ? join(ctx.cwd, PROJECT_ROOT, "claude-swarm")
372
+ : join(ctx.cwd, ".claude-swarm");
373
+ mkdirSync(targetDir, { recursive: true });
374
+ // Write default config.json
375
+ const configPath = join(targetDir, "config.json");
376
+ if (!existsSync(configPath)) {
377
+ writeFileSync(configPath, JSON.stringify({}, null, 2) + "\n");
378
+ }
379
+ // Write .gitignore for tmp/
380
+ const gitignorePath = join(targetDir, ".gitignore");
381
+ if (!existsSync(gitignorePath)) {
382
+ writeFileSync(gitignorePath, "tmp/\n");
383
+ }
384
+ return { package: "claude-code-swarm", success: true };
385
+ }
386
+ catch (err) {
387
+ return {
388
+ package: "claude-code-swarm",
389
+ success: false,
390
+ message: formatError(err),
391
+ };
392
+ }
393
+ }
289
394
  // ─── Helpers ─────────────────────────────────────────────────────────────────
290
395
  function getProjectName(cwd) {
291
396
  const pkgPath = join(cwd, "package.json");