swarmkit 0.0.1 → 0.0.3
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.
- package/LICENSE +21 -0
- package/README.md +130 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +33 -0
- package/dist/commands/add.d.ts +2 -0
- package/dist/commands/add.js +98 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +100 -0
- package/dist/commands/hive.d.ts +2 -0
- package/dist/commands/hive.js +248 -0
- package/dist/commands/init/phases/configure.d.ts +2 -0
- package/dist/commands/init/phases/configure.js +85 -0
- package/dist/commands/init/phases/global-setup.d.ts +2 -0
- package/dist/commands/init/phases/global-setup.js +81 -0
- package/dist/commands/init/phases/packages.d.ts +2 -0
- package/dist/commands/init/phases/packages.js +30 -0
- package/dist/commands/init/phases/project.d.ts +2 -0
- package/dist/commands/init/phases/project.js +56 -0
- package/dist/commands/init/phases/use-case.d.ts +2 -0
- package/dist/commands/init/phases/use-case.js +41 -0
- package/dist/commands/init/state.d.ts +13 -0
- package/dist/commands/init/state.js +9 -0
- package/dist/commands/init/state.test.d.ts +1 -0
- package/dist/commands/init/state.test.js +21 -0
- package/dist/commands/init/wizard.d.ts +4 -0
- package/dist/commands/init/wizard.js +108 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +11 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +91 -0
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.js +19 -0
- package/dist/commands/remove.d.ts +2 -0
- package/dist/commands/remove.js +55 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +87 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +54 -0
- package/dist/commands/whoami.d.ts +2 -0
- package/dist/commands/whoami.js +40 -0
- package/dist/config/global.d.ts +26 -0
- package/dist/config/global.js +71 -0
- package/dist/config/global.test.d.ts +1 -0
- package/dist/config/global.test.js +167 -0
- package/dist/config/keys.d.ts +10 -0
- package/dist/config/keys.js +47 -0
- package/dist/config/keys.test.d.ts +1 -0
- package/dist/config/keys.test.js +87 -0
- package/dist/doctor/checks.d.ts +31 -0
- package/dist/doctor/checks.js +226 -0
- package/dist/doctor/checks.test.d.ts +1 -0
- package/dist/doctor/checks.test.js +301 -0
- package/dist/doctor/types.d.ts +29 -0
- package/dist/doctor/types.js +1 -0
- package/dist/hub/auth-flow.d.ts +16 -0
- package/dist/hub/auth-flow.js +118 -0
- package/dist/hub/auth-flow.test.d.ts +1 -0
- package/dist/hub/auth-flow.test.js +98 -0
- package/dist/hub/client.d.ts +51 -0
- package/dist/hub/client.js +107 -0
- package/dist/hub/client.test.d.ts +1 -0
- package/dist/hub/client.test.js +177 -0
- package/dist/hub/credentials.d.ts +14 -0
- package/dist/hub/credentials.js +41 -0
- package/dist/hub/credentials.test.d.ts +1 -0
- package/dist/hub/credentials.test.js +102 -0
- package/dist/index.d.ts +17 -1
- package/dist/index.js +10 -2
- package/dist/packages/installer.d.ts +42 -0
- package/dist/packages/installer.js +158 -0
- package/dist/packages/installer.test.d.ts +1 -0
- package/dist/packages/installer.test.js +283 -0
- package/dist/packages/plugin.d.ts +13 -0
- package/dist/packages/plugin.js +33 -0
- package/dist/packages/plugin.test.d.ts +1 -0
- package/dist/packages/plugin.test.js +99 -0
- package/dist/packages/registry.d.ts +37 -0
- package/dist/packages/registry.js +154 -0
- package/dist/packages/registry.test.d.ts +1 -0
- package/dist/packages/registry.test.js +188 -0
- package/dist/packages/setup.d.ts +55 -0
- package/dist/packages/setup.js +414 -0
- package/dist/packages/setup.test.d.ts +1 -0
- package/dist/packages/setup.test.js +808 -0
- package/dist/utils/ui.d.ts +10 -0
- package/dist/utils/ui.js +47 -0
- package/dist/utils/ui.test.d.ts +1 -0
- package/dist/utils/ui.test.js +102 -0
- package/package.json +29 -6
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, renameSync, symlinkSync, writeFileSync, } from "node:fs";
|
|
4
|
+
import { basename, join } from "node:path";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
// ─── Project-level setup ─────────────────────────────────────────────────────
|
|
8
|
+
/** Root directory for all swarmkit project-level config */
|
|
9
|
+
export const PROJECT_ROOT = ".swarm";
|
|
10
|
+
/** Config directories with .swarm/ prefix (default layout) */
|
|
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 = {
|
|
23
|
+
opentasks: ".opentasks",
|
|
24
|
+
minimem: ".minimem",
|
|
25
|
+
"cognitive-core": ".cognitive-core",
|
|
26
|
+
"skill-tree": ".skilltree",
|
|
27
|
+
"self-driving-repo": ".self-driving",
|
|
28
|
+
openteams: ".openteams",
|
|
29
|
+
sessionlog: ".sessionlog",
|
|
30
|
+
"claude-code-swarm": ".claude-swarm",
|
|
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
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Project-level packages in correct init order.
|
|
38
|
+
* Order matters: minimem before cognitive-core (runtime detection).
|
|
39
|
+
*/
|
|
40
|
+
export const PROJECT_INIT_ORDER = [
|
|
41
|
+
"opentasks",
|
|
42
|
+
"minimem",
|
|
43
|
+
"cognitive-core",
|
|
44
|
+
"skill-tree",
|
|
45
|
+
"self-driving-repo",
|
|
46
|
+
"openteams",
|
|
47
|
+
"sessionlog",
|
|
48
|
+
"claude-code-swarm",
|
|
49
|
+
];
|
|
50
|
+
/** Check whether a package is already initialized in a project (checks both layouts) */
|
|
51
|
+
export function isProjectInit(cwd, pkg) {
|
|
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
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/** Initialize a single project-level package */
|
|
109
|
+
export async function initProjectPackage(pkg, ctx) {
|
|
110
|
+
if (ctx.usePrefix) {
|
|
111
|
+
ensureProjectRoot(ctx.cwd);
|
|
112
|
+
}
|
|
113
|
+
switch (pkg) {
|
|
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
|
+
}
|
|
124
|
+
case "minimem":
|
|
125
|
+
return initMinimem(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);
|
|
136
|
+
case "self-driving-repo":
|
|
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);
|
|
144
|
+
default:
|
|
145
|
+
return { package: pkg, success: false, message: "Unknown package" };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// ─── Global-level setup ──────────────────────────────────────────────────────
|
|
149
|
+
/** Config directories for global packages (relative to homedir) */
|
|
150
|
+
export const GLOBAL_CONFIG_DIRS = {
|
|
151
|
+
"skill-tree": ".skill-tree",
|
|
152
|
+
openhive: ".openhive",
|
|
153
|
+
};
|
|
154
|
+
/** Check whether a global package is already configured */
|
|
155
|
+
export function isGlobalInit(pkg) {
|
|
156
|
+
const dir = GLOBAL_CONFIG_DIRS[pkg];
|
|
157
|
+
if (!dir)
|
|
158
|
+
return false;
|
|
159
|
+
return existsSync(join(homedir(), dir));
|
|
160
|
+
}
|
|
161
|
+
/** Initialize a single global package */
|
|
162
|
+
export async function initGlobalPackage(pkg, ctx, openhiveOpts) {
|
|
163
|
+
switch (pkg) {
|
|
164
|
+
case "skill-tree":
|
|
165
|
+
return initSkillTree();
|
|
166
|
+
case "openhive":
|
|
167
|
+
return openhiveOpts
|
|
168
|
+
? initOpenhive(openhiveOpts)
|
|
169
|
+
: {
|
|
170
|
+
package: "openhive",
|
|
171
|
+
success: false,
|
|
172
|
+
message: "No openhive options provided",
|
|
173
|
+
};
|
|
174
|
+
case "openteams":
|
|
175
|
+
return { package: "openteams", success: true, message: "no setup required" };
|
|
176
|
+
case "sessionlog":
|
|
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" };
|
|
180
|
+
default:
|
|
181
|
+
return { package: pkg, success: false, message: "Unknown package" };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// ─── Package-specific init functions ─────────────────────────────────────────
|
|
185
|
+
/** Build a clean env for child processes (strips test-runner vars like VITEST) */
|
|
186
|
+
function cleanEnv() {
|
|
187
|
+
const env = { ...process.env };
|
|
188
|
+
delete env.VITEST;
|
|
189
|
+
delete env.VITEST_POOL_ID;
|
|
190
|
+
delete env.VITEST_WORKER_ID;
|
|
191
|
+
return env;
|
|
192
|
+
}
|
|
193
|
+
/** Shell out to a package's CLI init command */
|
|
194
|
+
async function shellInit(command, args, cwd, envOverrides) {
|
|
195
|
+
const pkg = command === "sdr" ? "self-driving-repo" : command;
|
|
196
|
+
try {
|
|
197
|
+
const env = envOverrides
|
|
198
|
+
? { ...cleanEnv(), ...envOverrides }
|
|
199
|
+
: cleanEnv();
|
|
200
|
+
await execFileAsync(command, args, { cwd, timeout: 30_000, env });
|
|
201
|
+
return { package: pkg, success: true };
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
return { package: pkg, success: false, message: formatError(err) };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async function initMinimem(ctx) {
|
|
208
|
+
const targetDir = ctx.usePrefix
|
|
209
|
+
? join(ctx.cwd, PROJECT_ROOT, "minimem")
|
|
210
|
+
: join(ctx.cwd, ".minimem");
|
|
211
|
+
try {
|
|
212
|
+
await execFileAsync("minimem", ["init"], {
|
|
213
|
+
cwd: ctx.cwd,
|
|
214
|
+
timeout: 30_000,
|
|
215
|
+
env: ctx.usePrefix
|
|
216
|
+
? { ...cleanEnv(), MINIMEM_CONFIG_DIR: join(PROJECT_ROOT, "minimem") }
|
|
217
|
+
: cleanEnv(),
|
|
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
|
+
}
|
|
224
|
+
// Patch embedding provider if configured
|
|
225
|
+
if (ctx.embeddingProvider && ctx.embeddingProvider !== "local") {
|
|
226
|
+
const configPath = join(targetDir, "config.json");
|
|
227
|
+
if (existsSync(configPath)) {
|
|
228
|
+
try {
|
|
229
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
230
|
+
config.embedding = config.embedding || {};
|
|
231
|
+
config.embedding.provider = ctx.embeddingProvider;
|
|
232
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// Non-fatal — user can configure manually
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return { package: "minimem", success: true };
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
return { package: "minimem", success: false, message: formatError(err) };
|
|
243
|
+
}
|
|
244
|
+
}
|
|
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) {
|
|
257
|
+
try {
|
|
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),
|
|
270
|
+
};
|
|
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");
|
|
283
|
+
}
|
|
284
|
+
return { package: "openteams", success: true };
|
|
285
|
+
}
|
|
286
|
+
catch (err) {
|
|
287
|
+
return {
|
|
288
|
+
package: "openteams",
|
|
289
|
+
success: false,
|
|
290
|
+
message: formatError(err),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
async function initSessionlogProject(ctx) {
|
|
295
|
+
try {
|
|
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");
|
|
304
|
+
}
|
|
305
|
+
return { package: "sessionlog", success: true };
|
|
306
|
+
}
|
|
307
|
+
catch (err) {
|
|
308
|
+
return {
|
|
309
|
+
package: "sessionlog",
|
|
310
|
+
success: false,
|
|
311
|
+
message: formatError(err),
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async function initSkillTree() {
|
|
316
|
+
const configPath = join(homedir(), ".skill-tree", "config.yaml");
|
|
317
|
+
if (existsSync(configPath)) {
|
|
318
|
+
return {
|
|
319
|
+
package: "skill-tree",
|
|
320
|
+
success: true,
|
|
321
|
+
message: "already configured",
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
const env = { ...cleanEnv(), HOME: homedir() };
|
|
326
|
+
await execFileAsync("skill-tree", ["config", "init"], {
|
|
327
|
+
timeout: 15_000,
|
|
328
|
+
env,
|
|
329
|
+
});
|
|
330
|
+
return { package: "skill-tree", success: true };
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
return {
|
|
334
|
+
package: "skill-tree",
|
|
335
|
+
success: false,
|
|
336
|
+
message: formatError(err),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async function initOpenhive(opts) {
|
|
341
|
+
try {
|
|
342
|
+
const args = [
|
|
343
|
+
"init",
|
|
344
|
+
"--name",
|
|
345
|
+
opts.name,
|
|
346
|
+
"--port",
|
|
347
|
+
String(opts.port),
|
|
348
|
+
"--auth-mode",
|
|
349
|
+
opts.authMode,
|
|
350
|
+
"--verification",
|
|
351
|
+
opts.verification,
|
|
352
|
+
];
|
|
353
|
+
if (opts.dataDir) {
|
|
354
|
+
args.unshift("--data-dir", opts.dataDir);
|
|
355
|
+
}
|
|
356
|
+
const env = { ...cleanEnv(), HOME: homedir() };
|
|
357
|
+
await execFileAsync("openhive", args, { timeout: 60_000, env });
|
|
358
|
+
return { package: "openhive", success: true };
|
|
359
|
+
}
|
|
360
|
+
catch (err) {
|
|
361
|
+
return {
|
|
362
|
+
package: "openhive",
|
|
363
|
+
success: false,
|
|
364
|
+
message: formatError(err),
|
|
365
|
+
};
|
|
366
|
+
}
|
|
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
|
+
}
|
|
394
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
395
|
+
function getProjectName(cwd) {
|
|
396
|
+
const pkgPath = join(cwd, "package.json");
|
|
397
|
+
if (existsSync(pkgPath)) {
|
|
398
|
+
try {
|
|
399
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
400
|
+
if (typeof pkg.name === "string" && pkg.name)
|
|
401
|
+
return pkg.name;
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
// Fall through
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return basename(cwd) || "project";
|
|
408
|
+
}
|
|
409
|
+
function formatError(err) {
|
|
410
|
+
if (err instanceof Error) {
|
|
411
|
+
return err.message.split("\n")[0];
|
|
412
|
+
}
|
|
413
|
+
return String(err);
|
|
414
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|