@beastmode-develeap/beastmode 0.1.267 → 0.1.268
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/dist/index.js +233 -238
- package/dist/index.js.map +1 -1
- package/dist/web/board.html +1 -1
- package/dist/web/build-commit.txt +1 -1
- package/dist/web/build-stamp.txt +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3223,8 +3223,18 @@ var init_bridge = __esm({
|
|
|
3223
3223
|
});
|
|
3224
3224
|
|
|
3225
3225
|
// src/engine/project-record.ts
|
|
3226
|
-
import { existsSync as existsSync8, writeFileSync as writeFileSync6, renameSync, readFileSync as readFileSync8, readdirSync as readdirSync3, mkdirSync as mkdirSync6 } from "fs";
|
|
3227
|
-
import { join as join8 } from "path";
|
|
3226
|
+
import { existsSync as existsSync8, writeFileSync as writeFileSync6, renameSync, readFileSync as readFileSync8, readdirSync as readdirSync3, mkdirSync as mkdirSync6, unlinkSync } from "fs";
|
|
3227
|
+
import { join as join8, basename as basename3 } from "path";
|
|
3228
|
+
function computeVerifyPort(existingProjects) {
|
|
3229
|
+
let port = 3001;
|
|
3230
|
+
if (existingProjects) {
|
|
3231
|
+
for (const p of existingProjects) {
|
|
3232
|
+
const v = p.deploy?.verify_port;
|
|
3233
|
+
if (typeof v === "number" && v >= port) port = v + 1;
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
return port;
|
|
3237
|
+
}
|
|
3228
3238
|
function detectShape(parsed) {
|
|
3229
3239
|
if (parsed.github && typeof parsed.github === "object" && parsed.slots && typeof parsed.slots === "object") {
|
|
3230
3240
|
return "canonical";
|
|
@@ -3234,10 +3244,34 @@ function detectShape(parsed) {
|
|
|
3234
3244
|
}
|
|
3235
3245
|
return "http-legacy";
|
|
3236
3246
|
}
|
|
3247
|
+
function hasMissingCanonicalFields(parsed) {
|
|
3248
|
+
if (!parsed.stack) return true;
|
|
3249
|
+
if (!parsed.plugins) return true;
|
|
3250
|
+
if (!parsed.infra) return true;
|
|
3251
|
+
const deploy = parsed.deploy;
|
|
3252
|
+
if (!deploy?.target) return true;
|
|
3253
|
+
return false;
|
|
3254
|
+
}
|
|
3255
|
+
function normalizeDeploy(existing) {
|
|
3256
|
+
return {
|
|
3257
|
+
...existing,
|
|
3258
|
+
target: existing?.target || "pr-only",
|
|
3259
|
+
verify_port: existing?.verify_port || 3001,
|
|
3260
|
+
config: existing?.config || {}
|
|
3261
|
+
};
|
|
3262
|
+
}
|
|
3237
3263
|
function normalizeToCanonical(parsed, name) {
|
|
3238
3264
|
const shape = detectShape(parsed);
|
|
3265
|
+
const existingDeploy = parsed.deploy;
|
|
3239
3266
|
if (shape === "canonical") {
|
|
3240
|
-
|
|
3267
|
+
const record = parsed;
|
|
3268
|
+
return {
|
|
3269
|
+
...record,
|
|
3270
|
+
stack: record.stack || DEFAULT_STACK,
|
|
3271
|
+
plugins: record.plugins || [],
|
|
3272
|
+
infra: record.infra || DEFAULT_INFRA,
|
|
3273
|
+
deploy: normalizeDeploy(existingDeploy)
|
|
3274
|
+
};
|
|
3241
3275
|
}
|
|
3242
3276
|
if (shape === "cli-legacy") {
|
|
3243
3277
|
const github = parsed.github;
|
|
@@ -3253,10 +3287,13 @@ function normalizeToCanonical(parsed, name) {
|
|
|
3253
3287
|
url: "http://127.0.0.1:8080",
|
|
3254
3288
|
auto_created: true
|
|
3255
3289
|
},
|
|
3256
|
-
|
|
3290
|
+
stack: parsed.stack || DEFAULT_STACK,
|
|
3291
|
+
deploy: normalizeDeploy(existingDeploy),
|
|
3257
3292
|
pipeline: parsed.pipeline || {},
|
|
3258
3293
|
models: parsed.models || {},
|
|
3294
|
+
plugins: parsed.plugins || [],
|
|
3259
3295
|
slots: { max: null },
|
|
3296
|
+
infra: parsed.infra || DEFAULT_INFRA,
|
|
3260
3297
|
registered_at: parsed.registered_at || (/* @__PURE__ */ new Date()).toISOString()
|
|
3261
3298
|
};
|
|
3262
3299
|
}
|
|
@@ -3264,34 +3301,74 @@ function normalizeToCanonical(parsed, name) {
|
|
|
3264
3301
|
name: parsed.name || name,
|
|
3265
3302
|
path: parsed.path || "",
|
|
3266
3303
|
github: {
|
|
3267
|
-
repo: parsed.repo || "",
|
|
3304
|
+
repo: parsed.repo || parsed.github?.repo || "",
|
|
3268
3305
|
default_branch: "main"
|
|
3269
3306
|
},
|
|
3270
|
-
board:
|
|
3271
|
-
|
|
3307
|
+
board: parsed.board || {
|
|
3308
|
+
id: null,
|
|
3309
|
+
url: "http://127.0.0.1:8080",
|
|
3310
|
+
auto_created: true
|
|
3311
|
+
},
|
|
3312
|
+
stack: parsed.stack || DEFAULT_STACK,
|
|
3313
|
+
deploy: normalizeDeploy(existingDeploy),
|
|
3272
3314
|
pipeline: parsed.pipeline || {},
|
|
3273
3315
|
models: parsed.models || {},
|
|
3274
|
-
|
|
3275
|
-
|
|
3316
|
+
plugins: parsed.plugins || [],
|
|
3317
|
+
slots: parsed.slots || { max: null },
|
|
3318
|
+
infra: parsed.infra || DEFAULT_INFRA,
|
|
3319
|
+
registered_at: parsed.registered_at || (/* @__PURE__ */ new Date()).toISOString()
|
|
3276
3320
|
};
|
|
3277
3321
|
}
|
|
3278
3322
|
function createProjectRecord(input) {
|
|
3323
|
+
const name = input.name || basename3(input.resolvedPath);
|
|
3324
|
+
let boardId = null;
|
|
3325
|
+
if (input.boardId !== void 0 && input.boardId !== null) {
|
|
3326
|
+
const parsed = typeof input.boardId === "string" ? parseInt(input.boardId, 10) : input.boardId;
|
|
3327
|
+
boardId = isNaN(parsed) ? null : parsed;
|
|
3328
|
+
}
|
|
3329
|
+
let stack = { ...DEFAULT_STACK };
|
|
3330
|
+
let gitRemote = input.gitRemote;
|
|
3331
|
+
try {
|
|
3332
|
+
const detected = detectStack(input.resolvedPath);
|
|
3333
|
+
stack = {
|
|
3334
|
+
detected: detected.framework,
|
|
3335
|
+
build_command: detected.suggested_commands.build,
|
|
3336
|
+
dev_command: detected.suggested_commands.dev,
|
|
3337
|
+
test_command: detected.suggested_commands.test,
|
|
3338
|
+
install_command: detected.suggested_commands.install,
|
|
3339
|
+
dev_port: detected.dev_port,
|
|
3340
|
+
is_monorepo: detected.is_monorepo,
|
|
3341
|
+
total_packages: detected.total_packages,
|
|
3342
|
+
primary_languages: detected.primary_languages,
|
|
3343
|
+
...detected.packages ? { packages: detected.packages } : {}
|
|
3344
|
+
};
|
|
3345
|
+
if (!gitRemote && detected.git_remote) gitRemote = detected.git_remote;
|
|
3346
|
+
} catch {
|
|
3347
|
+
}
|
|
3348
|
+
const verifyPort = input.verifyPort ?? computeVerifyPort(input.existingProjects);
|
|
3279
3349
|
return {
|
|
3280
|
-
name
|
|
3350
|
+
name,
|
|
3281
3351
|
path: input.resolvedPath,
|
|
3282
3352
|
github: {
|
|
3283
|
-
repo:
|
|
3353
|
+
repo: gitRemote || "",
|
|
3284
3354
|
default_branch: "main"
|
|
3285
3355
|
},
|
|
3286
3356
|
board: {
|
|
3287
|
-
id:
|
|
3357
|
+
id: boardId,
|
|
3288
3358
|
url: process.env.BEASTMODE_BOARD_URL || "http://127.0.0.1:8080",
|
|
3289
|
-
auto_created:
|
|
3359
|
+
auto_created: boardId === null
|
|
3360
|
+
},
|
|
3361
|
+
stack,
|
|
3362
|
+
deploy: {
|
|
3363
|
+
target: "pr-only",
|
|
3364
|
+
verify_port: verifyPort,
|
|
3365
|
+
config: {}
|
|
3290
3366
|
},
|
|
3291
|
-
deploy: { verify_port: input.verifyPort ?? 3001 },
|
|
3292
3367
|
pipeline: {},
|
|
3293
3368
|
models: {},
|
|
3369
|
+
plugins: [],
|
|
3294
3370
|
slots: { max: null },
|
|
3371
|
+
infra: { credentials: { mode: "factory" }, state_backend: "auto" },
|
|
3295
3372
|
registered_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3296
3373
|
};
|
|
3297
3374
|
}
|
|
@@ -3339,8 +3416,15 @@ function readProjectRecord(projectsDir, name) {
|
|
|
3339
3416
|
}
|
|
3340
3417
|
const shape = detectShape(parsed);
|
|
3341
3418
|
const record = normalizeToCanonical(parsed, name);
|
|
3342
|
-
|
|
3419
|
+
const needsWrite = shape !== "canonical" || isFlat || hasMissingCanonicalFields(parsed);
|
|
3420
|
+
if (needsWrite) {
|
|
3343
3421
|
writeProjectRecord(projectsDir, name, record);
|
|
3422
|
+
if (isFlat) {
|
|
3423
|
+
try {
|
|
3424
|
+
unlinkSync(flatPath);
|
|
3425
|
+
} catch {
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3344
3428
|
}
|
|
3345
3429
|
return record;
|
|
3346
3430
|
}
|
|
@@ -3369,9 +3453,23 @@ function listProjectRecords(projectsDir) {
|
|
|
3369
3453
|
}
|
|
3370
3454
|
return records;
|
|
3371
3455
|
}
|
|
3456
|
+
var DEFAULT_STACK, DEFAULT_INFRA;
|
|
3372
3457
|
var init_project_record = __esm({
|
|
3373
3458
|
"src/engine/project-record.ts"() {
|
|
3374
3459
|
"use strict";
|
|
3460
|
+
init_stack_detector();
|
|
3461
|
+
DEFAULT_STACK = {
|
|
3462
|
+
detected: "unknown",
|
|
3463
|
+
build_command: "",
|
|
3464
|
+
dev_command: "",
|
|
3465
|
+
test_command: "",
|
|
3466
|
+
install_command: "",
|
|
3467
|
+
dev_port: 3e3
|
|
3468
|
+
};
|
|
3469
|
+
DEFAULT_INFRA = {
|
|
3470
|
+
credentials: { mode: "factory" },
|
|
3471
|
+
state_backend: "auto"
|
|
3472
|
+
};
|
|
3375
3473
|
}
|
|
3376
3474
|
});
|
|
3377
3475
|
|
|
@@ -3690,7 +3788,7 @@ var init_api_routes = __esm({
|
|
|
3690
3788
|
});
|
|
3691
3789
|
|
|
3692
3790
|
// src/cli/ui/archival.ts
|
|
3693
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readdirSync as readdirSync4, renameSync as renameSync2, readFileSync as readFileSync9, statSync as statSync3, writeFileSync as writeFileSync9, unlinkSync } from "fs";
|
|
3791
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readdirSync as readdirSync4, renameSync as renameSync2, readFileSync as readFileSync9, statSync as statSync3, writeFileSync as writeFileSync9, unlinkSync as unlinkSync2 } from "fs";
|
|
3694
3792
|
import { join as join10 } from "path";
|
|
3695
3793
|
function archiveOldRuns(runsDir, archiveAfterDays) {
|
|
3696
3794
|
if (archiveAfterDays <= 0 || !existsSync12(runsDir)) return { archived: 0 };
|
|
@@ -3731,7 +3829,7 @@ function pinRun(runsDir, runId) {
|
|
|
3731
3829
|
function unpinRun(runsDir, runId) {
|
|
3732
3830
|
const pinFile = join10(runsDir, runId, "pinned");
|
|
3733
3831
|
if (!existsSync12(pinFile)) return false;
|
|
3734
|
-
|
|
3832
|
+
unlinkSync2(pinFile);
|
|
3735
3833
|
return true;
|
|
3736
3834
|
}
|
|
3737
3835
|
function isRunPinned(runsDir, runId) {
|
|
@@ -3760,7 +3858,7 @@ __export(inception_exports, {
|
|
|
3760
3858
|
saveArtifact: () => saveArtifact,
|
|
3761
3859
|
saveInceptionState: () => saveInceptionState
|
|
3762
3860
|
});
|
|
3763
|
-
import { existsSync as existsSync13, mkdirSync as mkdirSync9, writeFileSync as writeFileSync10, readFileSync as readFileSync10, readdirSync as readdirSync5, unlinkSync as
|
|
3861
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync9, writeFileSync as writeFileSync10, readFileSync as readFileSync10, readdirSync as readdirSync5, unlinkSync as unlinkSync3 } from "fs";
|
|
3764
3862
|
import { join as join11, dirname as dirname4 } from "path";
|
|
3765
3863
|
import { fileURLToPath } from "url";
|
|
3766
3864
|
function getMethodologiesDir() {
|
|
@@ -3891,10 +3989,10 @@ function migrateInceptionToSession(factoryDir, productName) {
|
|
|
3891
3989
|
const src = join11(productDir, file);
|
|
3892
3990
|
if (existsSync13(src)) {
|
|
3893
3991
|
writeFileSync10(join11(sessionDir, file), readFileSync10(src, "utf-8"));
|
|
3894
|
-
|
|
3992
|
+
unlinkSync3(src);
|
|
3895
3993
|
}
|
|
3896
3994
|
}
|
|
3897
|
-
|
|
3995
|
+
unlinkSync3(oldInception);
|
|
3898
3996
|
return true;
|
|
3899
3997
|
}
|
|
3900
3998
|
function listProducts(factoryDir) {
|
|
@@ -5129,8 +5227,8 @@ var init_chat_handler = __esm({
|
|
|
5129
5227
|
});
|
|
5130
5228
|
|
|
5131
5229
|
// src/cli/ui/board-api-routes.ts
|
|
5132
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync13, existsSync as existsSync16, readdirSync as readdirSync8, unlinkSync as
|
|
5133
|
-
import { join as join14, basename as
|
|
5230
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync13, existsSync as existsSync16, readdirSync as readdirSync8, unlinkSync as unlinkSync4, mkdirSync as mkdirSync12, statSync as statSync6, rmSync as rmSync3 } from "fs";
|
|
5231
|
+
import { join as join14, basename as basename5, resolve as resolve4, dirname as dirname5 } from "path";
|
|
5134
5232
|
import { homedir } from "os";
|
|
5135
5233
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
5136
5234
|
import { execSync as execSync3, spawnSync } from "child_process";
|
|
@@ -5395,14 +5493,6 @@ function _gitHeadSha(repoPath) {
|
|
|
5395
5493
|
return "no-git";
|
|
5396
5494
|
}
|
|
5397
5495
|
}
|
|
5398
|
-
function _hasClaudeCli() {
|
|
5399
|
-
try {
|
|
5400
|
-
execSync3("which claude", { encoding: "utf-8" });
|
|
5401
|
-
return true;
|
|
5402
|
-
} catch {
|
|
5403
|
-
return false;
|
|
5404
|
-
}
|
|
5405
|
-
}
|
|
5406
5496
|
function getBoardRoutes(factoryDir) {
|
|
5407
5497
|
return [
|
|
5408
5498
|
// ── Status ──
|
|
@@ -6118,7 +6208,7 @@ function getBoardRoutes(factoryDir) {
|
|
|
6118
6208
|
} else {
|
|
6119
6209
|
throw new Error("Missing required field: provide either `path` (local) or `github_url` (clone)");
|
|
6120
6210
|
}
|
|
6121
|
-
const projectName =
|
|
6211
|
+
const projectName = basename5(resolvedPath);
|
|
6122
6212
|
const stack = detectStack(resolvedPath);
|
|
6123
6213
|
let verifyPort = 3001;
|
|
6124
6214
|
for (const existing of listProjectRecords(projectsDir)) {
|
|
@@ -6165,11 +6255,24 @@ function getBoardRoutes(factoryDir) {
|
|
|
6165
6255
|
if (!hasSubDir && !hasFlat) throw new Error(`Project not found: ${name}`);
|
|
6166
6256
|
if (hasSubDir) rmSync3(subDir, { recursive: true, force: true });
|
|
6167
6257
|
else if (existsSync16(subDir)) rmSync3(subDir, { recursive: true, force: true });
|
|
6168
|
-
if (hasFlat)
|
|
6258
|
+
if (hasFlat) unlinkSync4(flatPath);
|
|
6169
6259
|
return { success: true };
|
|
6170
6260
|
}
|
|
6171
6261
|
},
|
|
6172
6262
|
{
|
|
6263
|
+
// Trigger brownfield analysis for a project.
|
|
6264
|
+
//
|
|
6265
|
+
// POST body: { tier?: "quick" | "standard" | "full" }
|
|
6266
|
+
// tier "quick" — writes a lightweight detectStack() placeholder, no Claude invocation.
|
|
6267
|
+
// tier "standard" / "full" (default) — delegates real analysis to the daemon via
|
|
6268
|
+
// a trigger file in the shared .beastmode volume. The daemon has access to the
|
|
6269
|
+
// project source files (/app/project) which the UI container does NOT have.
|
|
6270
|
+
// Query params: force=true — bypass cache and re-run even if HEAD hasn't changed.
|
|
6271
|
+
//
|
|
6272
|
+
// Returns immediately (analysis runs in daemon background):
|
|
6273
|
+
// { analyzing: true, project: string, job_id: string, status: "running" }
|
|
6274
|
+
// { analyzed: true, project: string, cached: true, analyzed_at: string } (cache hit)
|
|
6275
|
+
// { analyzed: true, project: string, tier: "quick" } (quick tier)
|
|
6173
6276
|
method: "POST",
|
|
6174
6277
|
pattern: "/api/projects/:name/analyze",
|
|
6175
6278
|
handler: async (body, params, query) => {
|
|
@@ -6207,59 +6310,36 @@ Path: ${projectPath}
|
|
|
6207
6310
|
}
|
|
6208
6311
|
if (!force) {
|
|
6209
6312
|
const meta = _readAnalyzeMeta(projectsDir, name);
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6313
|
+
if (meta && meta.status === "complete") {
|
|
6314
|
+
const currentSha = _gitHeadSha(projectPath);
|
|
6315
|
+
if (currentSha === "no-git" || meta.target_repo_head_sha === currentSha) {
|
|
6316
|
+
return { analyzed: true, project: name, cached: true, analyzed_at: meta.analyzed_at };
|
|
6317
|
+
}
|
|
6213
6318
|
}
|
|
6214
6319
|
}
|
|
6215
6320
|
const existingJob = _analyzeJobs.get(name);
|
|
6216
6321
|
if (existingJob && existingJob.status === "running") {
|
|
6217
6322
|
return { analyzing: true, project: name, job_id: existingJob.job_id, status: "running" };
|
|
6218
6323
|
}
|
|
6219
|
-
const
|
|
6324
|
+
const triggerPath = join14(subDir, ".analyze-request.json");
|
|
6325
|
+
const inProgressPath = join14(subDir, ".analyze-in-progress.json");
|
|
6326
|
+
if (existsSync16(triggerPath) || existsSync16(inProgressPath)) {
|
|
6327
|
+
const existingTrigger = existsSync16(triggerPath) ? triggerPath : inProgressPath;
|
|
6220
6328
|
try {
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
const brownfieldPath = join14(subDir, "brownfield.md");
|
|
6232
|
-
if (!existsSync16(brownfieldPath)) {
|
|
6233
|
-
const { detectStack: detectStackFn } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
6234
|
-
let stackInfo = "Unknown stack";
|
|
6235
|
-
try {
|
|
6236
|
-
const stack = detectStackFn(projectPath);
|
|
6237
|
-
const cmds = stack.suggested_commands;
|
|
6238
|
-
stackInfo = `Framework: ${stack.framework || "unknown"}
|
|
6239
|
-
Build: ${cmds?.build || "unknown"}
|
|
6240
|
-
Dev: ${cmds?.dev || "unknown"}`;
|
|
6241
|
-
} catch {
|
|
6242
|
-
}
|
|
6243
|
-
writeFileSync13(brownfieldPath, `# Brownfield Analysis: ${name}
|
|
6244
|
-
|
|
6245
|
-
${stackInfo}
|
|
6246
|
-
|
|
6247
|
-
Path: ${projectPath}
|
|
6248
|
-
`);
|
|
6329
|
+
const t = JSON.parse(readFileSync13(existingTrigger, "utf-8"));
|
|
6330
|
+
const job2 = {
|
|
6331
|
+
job_id: t.job_id,
|
|
6332
|
+
project: name,
|
|
6333
|
+
status: "running",
|
|
6334
|
+
started_at: t.requested_at
|
|
6335
|
+
};
|
|
6336
|
+
_analyzeJobs.set(name, job2);
|
|
6337
|
+
return { analyzing: true, project: name, job_id: t.job_id, status: "running" };
|
|
6338
|
+
} catch {
|
|
6249
6339
|
}
|
|
6250
|
-
writeMeta({
|
|
6251
|
-
analyzed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6252
|
-
target_repo_head_sha: _gitHeadSha(projectPath),
|
|
6253
|
-
status: "failed",
|
|
6254
|
-
error: "Claude CLI not available",
|
|
6255
|
-
duration_seconds: 0
|
|
6256
|
-
});
|
|
6257
|
-
console.warn(`[analyze] Claude CLI unavailable for project ${name}; wrote detectStack() fallback.`);
|
|
6258
|
-
return { analyzed: true, project: name, fallback: true };
|
|
6259
6340
|
}
|
|
6260
6341
|
const jobId = randomUUID2();
|
|
6261
6342
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6262
|
-
const startMs = Date.now();
|
|
6263
6343
|
const job = {
|
|
6264
6344
|
job_id: jobId,
|
|
6265
6345
|
project: name,
|
|
@@ -6267,171 +6347,86 @@ Path: ${projectPath}
|
|
|
6267
6347
|
started_at: startedAt
|
|
6268
6348
|
};
|
|
6269
6349
|
_analyzeJobs.set(name, job);
|
|
6270
|
-
(
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
].join("\n");
|
|
6282
|
-
const isRoot = process.getuid?.() === 0;
|
|
6283
|
-
const claudeArgs = [
|
|
6284
|
-
"-p",
|
|
6285
|
-
prompt,
|
|
6286
|
-
"--agent",
|
|
6287
|
-
"brownfield-analyst",
|
|
6288
|
-
"--output-format",
|
|
6289
|
-
"stream-json",
|
|
6290
|
-
"--verbose",
|
|
6291
|
-
"--dangerously-skip-permissions"
|
|
6292
|
-
];
|
|
6293
|
-
const spawnCmd = isRoot ? "runuser" : "claude";
|
|
6294
|
-
const spawnArgs = isRoot ? ["-u", "node", "--", "claude", ...claudeArgs] : claudeArgs;
|
|
6295
|
-
const child = spawn4(spawnCmd, spawnArgs, {
|
|
6296
|
-
cwd: projectPath,
|
|
6297
|
-
env: {
|
|
6298
|
-
...process.env,
|
|
6299
|
-
BEASTMODE_PROJECT: name,
|
|
6300
|
-
BEASTMODE_OUTPUT_DIR: subDir,
|
|
6301
|
-
...isRoot ? { HOME: "/home/node" } : {}
|
|
6302
|
-
},
|
|
6303
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
6304
|
-
});
|
|
6305
|
-
child.stdout?.on("data", () => {
|
|
6306
|
-
});
|
|
6307
|
-
child.stderr?.on("data", () => {
|
|
6308
|
-
});
|
|
6309
|
-
child.on("close", (code) => {
|
|
6310
|
-
const durationSeconds = (Date.now() - startMs) / 1e3;
|
|
6311
|
-
const sha = _gitHeadSha(projectPath);
|
|
6312
|
-
const guidePath = join14(subDir, "codebase-guide.md");
|
|
6313
|
-
const ok = code === 0 && existsSync16(guidePath);
|
|
6314
|
-
if (ok) {
|
|
6315
|
-
writeMeta({
|
|
6316
|
-
analyzed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6317
|
-
analyst_version: "brownfield-analyst-v1",
|
|
6318
|
-
target_repo_head_sha: sha,
|
|
6319
|
-
project_name: name,
|
|
6320
|
-
duration_seconds: durationSeconds,
|
|
6321
|
-
status: "complete"
|
|
6322
|
-
});
|
|
6323
|
-
const legacy = join14(subDir, "brownfield.md");
|
|
6324
|
-
if (existsSync16(legacy)) {
|
|
6325
|
-
try {
|
|
6326
|
-
unlinkSync3(legacy);
|
|
6327
|
-
} catch {
|
|
6328
|
-
}
|
|
6329
|
-
}
|
|
6330
|
-
_analyzeJobs.set(name, {
|
|
6331
|
-
...job,
|
|
6332
|
-
status: "complete",
|
|
6333
|
-
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6334
|
-
duration_seconds: durationSeconds
|
|
6335
|
-
});
|
|
6336
|
-
} else {
|
|
6337
|
-
const errMsg = `claude exited with code ${code}`;
|
|
6338
|
-
writeMeta({
|
|
6339
|
-
analyzed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6340
|
-
target_repo_head_sha: sha,
|
|
6341
|
-
status: "failed",
|
|
6342
|
-
error: errMsg,
|
|
6343
|
-
duration_seconds: durationSeconds
|
|
6344
|
-
});
|
|
6345
|
-
_analyzeJobs.set(name, {
|
|
6346
|
-
...job,
|
|
6347
|
-
status: "failed",
|
|
6348
|
-
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6349
|
-
duration_seconds: durationSeconds,
|
|
6350
|
-
error: errMsg
|
|
6351
|
-
});
|
|
6352
|
-
}
|
|
6353
|
-
});
|
|
6354
|
-
child.on("error", (err) => {
|
|
6355
|
-
const durationSeconds = (Date.now() - startMs) / 1e3;
|
|
6356
|
-
const sha = _gitHeadSha(projectPath);
|
|
6357
|
-
writeMeta({
|
|
6358
|
-
analyzed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6359
|
-
target_repo_head_sha: sha,
|
|
6360
|
-
status: "failed",
|
|
6361
|
-
error: String(err),
|
|
6362
|
-
duration_seconds: durationSeconds
|
|
6363
|
-
});
|
|
6364
|
-
_analyzeJobs.set(name, {
|
|
6365
|
-
...job,
|
|
6366
|
-
status: "failed",
|
|
6367
|
-
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6368
|
-
duration_seconds: durationSeconds,
|
|
6369
|
-
error: String(err)
|
|
6370
|
-
});
|
|
6371
|
-
});
|
|
6372
|
-
} catch (err) {
|
|
6373
|
-
const durationSeconds = (Date.now() - startMs) / 1e3;
|
|
6374
|
-
const sha = _gitHeadSha(projectPath);
|
|
6375
|
-
writeMeta({
|
|
6376
|
-
analyzed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6377
|
-
target_repo_head_sha: sha,
|
|
6378
|
-
status: "failed",
|
|
6379
|
-
error: String(err),
|
|
6380
|
-
duration_seconds: durationSeconds
|
|
6381
|
-
});
|
|
6382
|
-
_analyzeJobs.set(name, {
|
|
6383
|
-
...job,
|
|
6384
|
-
status: "failed",
|
|
6385
|
-
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6386
|
-
duration_seconds: durationSeconds,
|
|
6387
|
-
error: String(err)
|
|
6388
|
-
});
|
|
6389
|
-
}
|
|
6390
|
-
})();
|
|
6350
|
+
writeFileSync13(
|
|
6351
|
+
triggerPath,
|
|
6352
|
+
JSON.stringify({
|
|
6353
|
+
job_id: jobId,
|
|
6354
|
+
project_name: name,
|
|
6355
|
+
project_path: projectPath,
|
|
6356
|
+
requested_at: startedAt,
|
|
6357
|
+
force
|
|
6358
|
+
}, null, 2) + "\n",
|
|
6359
|
+
"utf-8"
|
|
6360
|
+
);
|
|
6391
6361
|
return { analyzing: true, project: name, job_id: jobId, status: "running" };
|
|
6392
6362
|
}
|
|
6393
6363
|
},
|
|
6394
6364
|
{
|
|
6365
|
+
// Poll the status of a background brownfield analysis job.
|
|
6366
|
+
//
|
|
6367
|
+
// Returns one of:
|
|
6368
|
+
// { status: "running", job_id: string, started_at: string }
|
|
6369
|
+
// { status: "complete", analyzed_at: string, duration_seconds: number, target_repo_head_sha: string }
|
|
6370
|
+
// { status: "cached", analyzed_at: string, duration_seconds: number, target_repo_head_sha: string }
|
|
6371
|
+
// { status: "failed", job_id?: string, error: string, started_at?: string, completed_at?: string }
|
|
6372
|
+
// { status: "idle" } — no analysis has been requested for this project
|
|
6395
6373
|
method: "GET",
|
|
6396
6374
|
pattern: "/api/projects/:name/analyze/status",
|
|
6397
6375
|
handler: (_body, params) => {
|
|
6398
6376
|
const { name } = params;
|
|
6399
6377
|
assertSafeName(name);
|
|
6400
6378
|
const projectsDir = join14(factoryDir, ".beastmode", "projects");
|
|
6401
|
-
const
|
|
6402
|
-
const
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
status: "
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
|
|
6416
|
-
completed_at: job.completed_at,
|
|
6417
|
-
duration_seconds: job.duration_seconds
|
|
6418
|
-
};
|
|
6379
|
+
const subDir = join14(projectsDir, name);
|
|
6380
|
+
const triggerPath = join14(subDir, ".analyze-request.json");
|
|
6381
|
+
const inProgressPath = join14(subDir, ".analyze-in-progress.json");
|
|
6382
|
+
if (existsSync16(triggerPath) || existsSync16(inProgressPath)) {
|
|
6383
|
+
const job2 = _analyzeJobs.get(name);
|
|
6384
|
+
try {
|
|
6385
|
+
const p = existsSync16(triggerPath) ? triggerPath : inProgressPath;
|
|
6386
|
+
const t = JSON.parse(readFileSync13(p, "utf-8"));
|
|
6387
|
+
if (!job2 || job2.status !== "running") {
|
|
6388
|
+
_analyzeJobs.set(name, { job_id: t.job_id, project: name, status: "running", started_at: t.requested_at });
|
|
6389
|
+
}
|
|
6390
|
+
return { status: "running", job_id: t.job_id, started_at: t.requested_at };
|
|
6391
|
+
} catch {
|
|
6392
|
+
return { status: "running", job_id: job2?.job_id, started_at: job2?.started_at };
|
|
6393
|
+
}
|
|
6419
6394
|
}
|
|
6395
|
+
const meta = _readAnalyzeMeta(projectsDir, name);
|
|
6420
6396
|
if (meta && meta.status === "complete") {
|
|
6397
|
+
const job2 = _analyzeJobs.get(name);
|
|
6398
|
+
if (job2?.status === "running") {
|
|
6399
|
+
_analyzeJobs.set(name, { ...job2, status: "complete" });
|
|
6400
|
+
}
|
|
6421
6401
|
return {
|
|
6422
|
-
status:
|
|
6402
|
+
status: "complete",
|
|
6423
6403
|
analyzed_at: meta.analyzed_at,
|
|
6424
6404
|
duration_seconds: meta.duration_seconds,
|
|
6425
6405
|
target_repo_head_sha: meta.target_repo_head_sha
|
|
6426
6406
|
};
|
|
6427
6407
|
}
|
|
6428
6408
|
if (meta && meta.status === "failed") {
|
|
6409
|
+
const job2 = _analyzeJobs.get(name);
|
|
6410
|
+
if (job2?.status === "running") {
|
|
6411
|
+
_analyzeJobs.set(name, { ...job2, status: "failed", error: meta.error });
|
|
6412
|
+
}
|
|
6429
6413
|
return {
|
|
6430
6414
|
status: "failed",
|
|
6431
6415
|
analyzed_at: meta.analyzed_at,
|
|
6432
6416
|
error: meta.error
|
|
6433
6417
|
};
|
|
6434
6418
|
}
|
|
6419
|
+
const job = _analyzeJobs.get(name);
|
|
6420
|
+
if (job && job.status === "failed") {
|
|
6421
|
+
return {
|
|
6422
|
+
status: "failed",
|
|
6423
|
+
job_id: job.job_id,
|
|
6424
|
+
error: job.error,
|
|
6425
|
+
started_at: job.started_at,
|
|
6426
|
+
completed_at: job.completed_at,
|
|
6427
|
+
duration_seconds: job.duration_seconds
|
|
6428
|
+
};
|
|
6429
|
+
}
|
|
6435
6430
|
return { status: "idle" };
|
|
6436
6431
|
}
|
|
6437
6432
|
},
|
|
@@ -7979,7 +7974,7 @@ __export(sync_claude_creds_exports, {
|
|
|
7979
7974
|
});
|
|
7980
7975
|
import { Command as Command2 } from "commander";
|
|
7981
7976
|
import { execSync as execSync5, spawnSync as spawnSync2 } from "child_process";
|
|
7982
|
-
import { writeFileSync as writeFileSync15, readFileSync as readFileSync16, chmodSync, mkdirSync as mkdirSync14, existsSync as existsSync19, unlinkSync as
|
|
7977
|
+
import { writeFileSync as writeFileSync15, readFileSync as readFileSync16, chmodSync, mkdirSync as mkdirSync14, existsSync as existsSync19, unlinkSync as unlinkSync5 } from "fs";
|
|
7983
7978
|
import { join as join17 } from "path";
|
|
7984
7979
|
import { homedir as homedir2, platform } from "os";
|
|
7985
7980
|
function systemdUserDir() {
|
|
@@ -8052,7 +8047,7 @@ function removeUrgencyMarker(factoryDir) {
|
|
|
8052
8047
|
if (!factoryDir) return;
|
|
8053
8048
|
const markerPath = urgencyMarkerHostPath(factoryDir);
|
|
8054
8049
|
try {
|
|
8055
|
-
|
|
8050
|
+
unlinkSync5(markerPath);
|
|
8056
8051
|
} catch {
|
|
8057
8052
|
}
|
|
8058
8053
|
}
|
|
@@ -8158,7 +8153,7 @@ function uninstallAgent() {
|
|
|
8158
8153
|
warn(`launchctl bootout returned: ${result.stderr || result.stdout}`);
|
|
8159
8154
|
}
|
|
8160
8155
|
try {
|
|
8161
|
-
|
|
8156
|
+
unlinkSync5(plist);
|
|
8162
8157
|
} catch {
|
|
8163
8158
|
}
|
|
8164
8159
|
success(`LaunchAgent removed: ${LAUNCH_AGENT_LABEL}`);
|
|
@@ -8344,14 +8339,14 @@ function uninstallAgentLinux() {
|
|
|
8344
8339
|
let removed = false;
|
|
8345
8340
|
if (existsSync19(servicePath)) {
|
|
8346
8341
|
try {
|
|
8347
|
-
|
|
8342
|
+
unlinkSync5(servicePath);
|
|
8348
8343
|
removed = true;
|
|
8349
8344
|
} catch {
|
|
8350
8345
|
}
|
|
8351
8346
|
}
|
|
8352
8347
|
if (existsSync19(timerPath)) {
|
|
8353
8348
|
try {
|
|
8354
|
-
|
|
8349
|
+
unlinkSync5(timerPath);
|
|
8355
8350
|
removed = true;
|
|
8356
8351
|
} catch {
|
|
8357
8352
|
}
|
|
@@ -8529,7 +8524,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
8529
8524
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8530
8525
|
import { z as z2 } from "zod";
|
|
8531
8526
|
import { readFileSync as readFileSync29, writeFileSync as writeFileSync25, existsSync as existsSync32, readdirSync as readdirSync12 } from "fs";
|
|
8532
|
-
import { join as join30, resolve as resolve18, basename as
|
|
8527
|
+
import { join as join30, resolve as resolve18, basename as basename7 } from "path";
|
|
8533
8528
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
8534
8529
|
function readJsonFile2(filePath) {
|
|
8535
8530
|
if (!existsSync32(filePath)) return null;
|
|
@@ -8848,7 +8843,7 @@ function createMcpServer() {
|
|
|
8848
8843
|
if (!existsSync32(resolvedPath)) {
|
|
8849
8844
|
return { content: [{ type: "text", text: `Directory not found: ${resolvedPath}` }], isError: true };
|
|
8850
8845
|
}
|
|
8851
|
-
const projectName =
|
|
8846
|
+
const projectName = basename7(resolvedPath);
|
|
8852
8847
|
const stack = detectStack(resolvedPath);
|
|
8853
8848
|
const projectsDir = join30(factoryDir, ".beastmode", "projects");
|
|
8854
8849
|
let verifyPort = 3001;
|
|
@@ -8966,7 +8961,7 @@ init_engine();
|
|
|
8966
8961
|
init_file_writer();
|
|
8967
8962
|
import { Command as Command3 } from "commander";
|
|
8968
8963
|
import inquirer from "inquirer";
|
|
8969
|
-
import { resolve as resolve6, basename as
|
|
8964
|
+
import { resolve as resolve6, basename as basename6, join as join18 } from "path";
|
|
8970
8965
|
import { existsSync as existsSync20, writeFileSync as writeFileSync16, mkdirSync as mkdirSync15, readFileSync as readFileSync17 } from "fs";
|
|
8971
8966
|
|
|
8972
8967
|
// src/cli/utils/docker.ts
|
|
@@ -9227,7 +9222,7 @@ function isSourceRepo(dir) {
|
|
|
9227
9222
|
async function runInit(name, opts) {
|
|
9228
9223
|
if (opts.ui) {
|
|
9229
9224
|
const { startServer: startServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
9230
|
-
const factoryName2 = name ||
|
|
9225
|
+
const factoryName2 = name || basename6(resolve6("."));
|
|
9231
9226
|
const projectPath2 = opts.project ? resolve6(opts.project) : void 0;
|
|
9232
9227
|
info("Starting init wizard...");
|
|
9233
9228
|
const uiServer = await startServer2({
|
|
@@ -9260,7 +9255,7 @@ async function runInit(name, opts) {
|
|
|
9260
9255
|
const totalSteps = 5;
|
|
9261
9256
|
header("BeastMode \u2014 Dark Factory Init");
|
|
9262
9257
|
info("Creating your Custom Dark Factory\n");
|
|
9263
|
-
const factoryName = name ||
|
|
9258
|
+
const factoryName = name || basename6(resolve6("."));
|
|
9264
9259
|
if (existsSync20(factoryName) && existsSync20(resolve6(factoryName, ".beastmode"))) {
|
|
9265
9260
|
throw new Error(`Factory already exists at ./${factoryName}. Use 'beastmode config' to modify.`);
|
|
9266
9261
|
}
|
|
@@ -9276,7 +9271,7 @@ async function runInit(name, opts) {
|
|
|
9276
9271
|
}
|
|
9277
9272
|
const templateProjectPath = resolve6(opts.project);
|
|
9278
9273
|
const templateStack = detectStack(templateProjectPath);
|
|
9279
|
-
const templateProjectName =
|
|
9274
|
+
const templateProjectName = basename6(templateProjectPath);
|
|
9280
9275
|
const actions2 = scaffoldFactory(factoryName, template.config, {
|
|
9281
9276
|
name: templateProjectName,
|
|
9282
9277
|
repo: templateStack.git_remote || void 0,
|
|
@@ -9471,7 +9466,7 @@ async function runInit(name, opts) {
|
|
|
9471
9466
|
success("Board UI password set");
|
|
9472
9467
|
}
|
|
9473
9468
|
step(5, totalSteps, "Boot");
|
|
9474
|
-
const projectName =
|
|
9469
|
+
const projectName = basename6(projectPath);
|
|
9475
9470
|
const actions = scaffoldFactory(factoryName, config, {
|
|
9476
9471
|
name: projectName,
|
|
9477
9472
|
repo: stack.git_remote || void 0,
|
|
@@ -10250,8 +10245,8 @@ for (const artifact of VALID_ARTIFACTS) {
|
|
|
10250
10245
|
|
|
10251
10246
|
// src/cli/commands/status.ts
|
|
10252
10247
|
init_status_checker();
|
|
10248
|
+
init_engine();
|
|
10253
10249
|
init_schemas();
|
|
10254
|
-
init_project_record();
|
|
10255
10250
|
init_display();
|
|
10256
10251
|
import { Command as Command10 } from "commander";
|
|
10257
10252
|
import { existsSync as existsSync24, readFileSync as readFileSync21, readdirSync as readdirSync10 } from "fs";
|
|
@@ -12572,8 +12567,8 @@ async function runDaemon(opts) {
|
|
|
12572
12567
|
const exitCode = await new Promise((resolvePromise) => {
|
|
12573
12568
|
child.on("exit", (code) => {
|
|
12574
12569
|
try {
|
|
12575
|
-
const { unlinkSync:
|
|
12576
|
-
|
|
12570
|
+
const { unlinkSync: unlinkSync8 } = __require("fs");
|
|
12571
|
+
unlinkSync8(pidFile);
|
|
12577
12572
|
} catch {
|
|
12578
12573
|
}
|
|
12579
12574
|
resolvePromise(code ?? 1);
|
|
@@ -13214,7 +13209,7 @@ init_display();
|
|
|
13214
13209
|
import { Command as Command23 } from "commander";
|
|
13215
13210
|
import { spawn as spawn3 } from "child_process";
|
|
13216
13211
|
import { existsSync as existsSync38 } from "fs";
|
|
13217
|
-
import { basename as
|
|
13212
|
+
import { basename as basename8, join as join37, resolve as resolve20 } from "path";
|
|
13218
13213
|
|
|
13219
13214
|
// src/cli/runner-image-builder.ts
|
|
13220
13215
|
import { execSync as execSync10 } from "child_process";
|
|
@@ -13800,7 +13795,7 @@ import {
|
|
|
13800
13795
|
createWriteStream,
|
|
13801
13796
|
existsSync as existsSync36,
|
|
13802
13797
|
mkdirSync as mkdirSync22,
|
|
13803
|
-
unlinkSync as
|
|
13798
|
+
unlinkSync as unlinkSync6,
|
|
13804
13799
|
writeFileSync as writeFileSync29
|
|
13805
13800
|
} from "fs";
|
|
13806
13801
|
import { homedir as homedir4 } from "os";
|
|
@@ -13868,7 +13863,7 @@ async function downloadAndExtractRunner(installDir, os, arch) {
|
|
|
13868
13863
|
);
|
|
13869
13864
|
}
|
|
13870
13865
|
try {
|
|
13871
|
-
|
|
13866
|
+
unlinkSync6(tarball);
|
|
13872
13867
|
} catch {
|
|
13873
13868
|
}
|
|
13874
13869
|
if (os === "darwin") {
|
|
@@ -14106,7 +14101,7 @@ import {
|
|
|
14106
14101
|
existsSync as existsSync37,
|
|
14107
14102
|
mkdirSync as mkdirSync23,
|
|
14108
14103
|
readFileSync as readFileSync34,
|
|
14109
|
-
unlinkSync as
|
|
14104
|
+
unlinkSync as unlinkSync7,
|
|
14110
14105
|
writeFileSync as writeFileSync30
|
|
14111
14106
|
} from "fs";
|
|
14112
14107
|
import { dirname as dirname9, join as join36 } from "path";
|
|
@@ -14198,7 +14193,7 @@ async function restoreWorkflows(projectDir) {
|
|
|
14198
14193
|
jobCount: fileState.originals.length
|
|
14199
14194
|
});
|
|
14200
14195
|
}
|
|
14201
|
-
|
|
14196
|
+
unlinkSync7(statePath);
|
|
14202
14197
|
return { nothingToRestore: false, files: resultFiles };
|
|
14203
14198
|
}
|
|
14204
14199
|
|
|
@@ -14217,7 +14212,7 @@ function resolveProjectName(projectDir) {
|
|
|
14217
14212
|
} catch {
|
|
14218
14213
|
}
|
|
14219
14214
|
}
|
|
14220
|
-
return
|
|
14215
|
+
return basename8(resolve20(projectDir));
|
|
14221
14216
|
}
|
|
14222
14217
|
async function runnerSetupAction(opts) {
|
|
14223
14218
|
if (opts.service !== void 0 && !opts.native) {
|
|
@@ -14593,7 +14588,7 @@ runnerCommand.command("build-image").description(
|
|
|
14593
14588
|
init_engine();
|
|
14594
14589
|
import { Command as Command24 } from "commander";
|
|
14595
14590
|
import { existsSync as existsSync39, mkdirSync as mkdirSync24, readFileSync as readFileSync35, renameSync as renameSync3 } from "fs";
|
|
14596
|
-
import { join as join38, resolve as resolve21, basename as
|
|
14591
|
+
import { join as join38, resolve as resolve21, basename as basename9 } from "path";
|
|
14597
14592
|
import { execSync as execSync13 } from "child_process";
|
|
14598
14593
|
var DEFAULT_MAX_PROJECTS = 5;
|
|
14599
14594
|
var MIN_DISK_WARNING_GB = 10;
|
|
@@ -14621,7 +14616,7 @@ function getFreeDiskGB() {
|
|
|
14621
14616
|
function projectAddAction(factoryDir, projectPath, opts) {
|
|
14622
14617
|
const resolvedPath = resolve21(projectPath);
|
|
14623
14618
|
if (!existsSync39(resolvedPath)) throw new Error(`Directory not found: ${resolvedPath}`);
|
|
14624
|
-
const projectName = opts.name ||
|
|
14619
|
+
const projectName = opts.name || basename9(resolvedPath);
|
|
14625
14620
|
const projectsDir = join38(factoryDir, ".beastmode", "projects");
|
|
14626
14621
|
if (existsSync39(join38(projectsDir, projectName, "project.json"))) {
|
|
14627
14622
|
throw new Error(`Project already exists: ${projectName}`);
|
|
@@ -14712,7 +14707,7 @@ var projectCommand = new Command24("project").description("Manage projects in th
|
|
|
14712
14707
|
projectCommand.command("add <path>").description("Register a project").option("--name <name>", "Override project name").option("--board-id <id>", "Link to existing board ID").action((path, opts) => {
|
|
14713
14708
|
const factoryDir = resolve21(".");
|
|
14714
14709
|
projectAddAction(factoryDir, path, opts);
|
|
14715
|
-
console.log(`Project registered: ${opts.name ||
|
|
14710
|
+
console.log(`Project registered: ${opts.name || basename9(resolve21(path))}`);
|
|
14716
14711
|
});
|
|
14717
14712
|
projectCommand.command("list").description("List registered projects").action(() => {
|
|
14718
14713
|
const projects = projectListAction(resolve21("."));
|