@beastmode-develeap/beastmode 0.1.266 → 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 +289 -291
- 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
|
@@ -95,17 +95,36 @@ var init_schemas = __esm({
|
|
|
95
95
|
});
|
|
96
96
|
DeployConfigSchema = z.object({
|
|
97
97
|
target: z.string().default("pr-only"),
|
|
98
|
+
verify_port: z.number().int().default(3001),
|
|
98
99
|
config: z.record(z.unknown()).default({})
|
|
99
100
|
});
|
|
100
101
|
ProjectConfigSchema = z.object({
|
|
101
102
|
name: z.string(),
|
|
102
|
-
repo: z.string().optional(),
|
|
103
103
|
path: z.string(),
|
|
104
|
+
github: z.object({
|
|
105
|
+
repo: z.string().default(""),
|
|
106
|
+
default_branch: z.string().default("main")
|
|
107
|
+
}).default({}),
|
|
108
|
+
board: z.object({
|
|
109
|
+
id: z.number().nullable().default(null),
|
|
110
|
+
url: z.string().default("http://127.0.0.1:8080"),
|
|
111
|
+
auto_created: z.boolean().default(false)
|
|
112
|
+
}).default({}),
|
|
104
113
|
stack: StackConfigSchema,
|
|
105
114
|
deploy: DeployConfigSchema.default({}),
|
|
106
115
|
pipeline: z.record(z.unknown()).default({}),
|
|
107
116
|
models: z.record(z.string()).default({}),
|
|
108
|
-
plugins: z.array(z.string()).default([])
|
|
117
|
+
plugins: z.array(z.string()).default([]),
|
|
118
|
+
slots: z.object({
|
|
119
|
+
max: z.number().nullable().default(null)
|
|
120
|
+
}).default({}),
|
|
121
|
+
infra: z.object({
|
|
122
|
+
credentials: z.object({
|
|
123
|
+
mode: z.string().default("factory")
|
|
124
|
+
}).default({}),
|
|
125
|
+
state_backend: z.string().default("auto")
|
|
126
|
+
}).default({}),
|
|
127
|
+
registered_at: z.string().default("")
|
|
109
128
|
});
|
|
110
129
|
FactoryIdentitySchema = z.object({
|
|
111
130
|
factory_name: z.string(),
|
|
@@ -2854,7 +2873,10 @@ function mapDaemonToFactory(daemon) {
|
|
|
2854
2873
|
const hasDeployConfig = Object.keys(deployConfig).length > 0;
|
|
2855
2874
|
const projectRaw = {
|
|
2856
2875
|
name: repoName,
|
|
2857
|
-
|
|
2876
|
+
github: {
|
|
2877
|
+
repo: daemon.github?.project_repo || "",
|
|
2878
|
+
default_branch: daemon.github?.base_branch || "main"
|
|
2879
|
+
},
|
|
2858
2880
|
path: daemon.repos?.project || "",
|
|
2859
2881
|
stack: {
|
|
2860
2882
|
detected: stack.name || "node",
|
|
@@ -3058,7 +3080,7 @@ function generateDaemonConfig(factoryConfig, projectConfig, factoryPath) {
|
|
|
3058
3080
|
taskBackendValue = backendAdapter;
|
|
3059
3081
|
}
|
|
3060
3082
|
const boardUrl = process.env.BEASTMODE_BOARD_URL || taskBackend.config?.url || "http://127.0.0.1:8080";
|
|
3061
|
-
const projectRepo = projectConfig?.repo || "";
|
|
3083
|
+
const projectRepo = projectConfig?.github?.repo || (projectConfig?.repo ?? "");
|
|
3062
3084
|
const projectPath = projectConfig?.path || "";
|
|
3063
3085
|
const projectOrg = projectRepo.split("/")[0] || "beastmode-agent";
|
|
3064
3086
|
const stack = projectConfig?.stack;
|
|
@@ -3201,8 +3223,18 @@ var init_bridge = __esm({
|
|
|
3201
3223
|
});
|
|
3202
3224
|
|
|
3203
3225
|
// src/engine/project-record.ts
|
|
3204
|
-
import { existsSync as existsSync8, writeFileSync as writeFileSync6, renameSync, readFileSync as readFileSync8, readdirSync as readdirSync3, mkdirSync as mkdirSync6 } from "fs";
|
|
3205
|
-
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
|
+
}
|
|
3206
3238
|
function detectShape(parsed) {
|
|
3207
3239
|
if (parsed.github && typeof parsed.github === "object" && parsed.slots && typeof parsed.slots === "object") {
|
|
3208
3240
|
return "canonical";
|
|
@@ -3212,10 +3244,34 @@ function detectShape(parsed) {
|
|
|
3212
3244
|
}
|
|
3213
3245
|
return "http-legacy";
|
|
3214
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
|
+
}
|
|
3215
3263
|
function normalizeToCanonical(parsed, name) {
|
|
3216
3264
|
const shape = detectShape(parsed);
|
|
3265
|
+
const existingDeploy = parsed.deploy;
|
|
3217
3266
|
if (shape === "canonical") {
|
|
3218
|
-
|
|
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
|
+
};
|
|
3219
3275
|
}
|
|
3220
3276
|
if (shape === "cli-legacy") {
|
|
3221
3277
|
const github = parsed.github;
|
|
@@ -3231,10 +3287,13 @@ function normalizeToCanonical(parsed, name) {
|
|
|
3231
3287
|
url: "http://127.0.0.1:8080",
|
|
3232
3288
|
auto_created: true
|
|
3233
3289
|
},
|
|
3234
|
-
|
|
3290
|
+
stack: parsed.stack || DEFAULT_STACK,
|
|
3291
|
+
deploy: normalizeDeploy(existingDeploy),
|
|
3235
3292
|
pipeline: parsed.pipeline || {},
|
|
3236
3293
|
models: parsed.models || {},
|
|
3294
|
+
plugins: parsed.plugins || [],
|
|
3237
3295
|
slots: { max: null },
|
|
3296
|
+
infra: parsed.infra || DEFAULT_INFRA,
|
|
3238
3297
|
registered_at: parsed.registered_at || (/* @__PURE__ */ new Date()).toISOString()
|
|
3239
3298
|
};
|
|
3240
3299
|
}
|
|
@@ -3242,34 +3301,74 @@ function normalizeToCanonical(parsed, name) {
|
|
|
3242
3301
|
name: parsed.name || name,
|
|
3243
3302
|
path: parsed.path || "",
|
|
3244
3303
|
github: {
|
|
3245
|
-
repo: parsed.repo || "",
|
|
3304
|
+
repo: parsed.repo || parsed.github?.repo || "",
|
|
3246
3305
|
default_branch: "main"
|
|
3247
3306
|
},
|
|
3248
|
-
board:
|
|
3249
|
-
|
|
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),
|
|
3250
3314
|
pipeline: parsed.pipeline || {},
|
|
3251
3315
|
models: parsed.models || {},
|
|
3252
|
-
|
|
3253
|
-
|
|
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()
|
|
3254
3320
|
};
|
|
3255
3321
|
}
|
|
3256
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);
|
|
3257
3349
|
return {
|
|
3258
|
-
name
|
|
3350
|
+
name,
|
|
3259
3351
|
path: input.resolvedPath,
|
|
3260
3352
|
github: {
|
|
3261
|
-
repo:
|
|
3353
|
+
repo: gitRemote || "",
|
|
3262
3354
|
default_branch: "main"
|
|
3263
3355
|
},
|
|
3264
3356
|
board: {
|
|
3265
|
-
id:
|
|
3357
|
+
id: boardId,
|
|
3266
3358
|
url: process.env.BEASTMODE_BOARD_URL || "http://127.0.0.1:8080",
|
|
3267
|
-
auto_created:
|
|
3359
|
+
auto_created: boardId === null
|
|
3360
|
+
},
|
|
3361
|
+
stack,
|
|
3362
|
+
deploy: {
|
|
3363
|
+
target: "pr-only",
|
|
3364
|
+
verify_port: verifyPort,
|
|
3365
|
+
config: {}
|
|
3268
3366
|
},
|
|
3269
|
-
deploy: { verify_port: input.verifyPort ?? 3001 },
|
|
3270
3367
|
pipeline: {},
|
|
3271
3368
|
models: {},
|
|
3369
|
+
plugins: [],
|
|
3272
3370
|
slots: { max: null },
|
|
3371
|
+
infra: { credentials: { mode: "factory" }, state_backend: "auto" },
|
|
3273
3372
|
registered_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3274
3373
|
};
|
|
3275
3374
|
}
|
|
@@ -3317,8 +3416,15 @@ function readProjectRecord(projectsDir, name) {
|
|
|
3317
3416
|
}
|
|
3318
3417
|
const shape = detectShape(parsed);
|
|
3319
3418
|
const record = normalizeToCanonical(parsed, name);
|
|
3320
|
-
|
|
3419
|
+
const needsWrite = shape !== "canonical" || isFlat || hasMissingCanonicalFields(parsed);
|
|
3420
|
+
if (needsWrite) {
|
|
3321
3421
|
writeProjectRecord(projectsDir, name, record);
|
|
3422
|
+
if (isFlat) {
|
|
3423
|
+
try {
|
|
3424
|
+
unlinkSync(flatPath);
|
|
3425
|
+
} catch {
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3322
3428
|
}
|
|
3323
3429
|
return record;
|
|
3324
3430
|
}
|
|
@@ -3347,9 +3453,23 @@ function listProjectRecords(projectsDir) {
|
|
|
3347
3453
|
}
|
|
3348
3454
|
return records;
|
|
3349
3455
|
}
|
|
3456
|
+
var DEFAULT_STACK, DEFAULT_INFRA;
|
|
3350
3457
|
var init_project_record = __esm({
|
|
3351
3458
|
"src/engine/project-record.ts"() {
|
|
3352
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
|
+
};
|
|
3353
3473
|
}
|
|
3354
3474
|
});
|
|
3355
3475
|
|
|
@@ -3668,7 +3788,7 @@ var init_api_routes = __esm({
|
|
|
3668
3788
|
});
|
|
3669
3789
|
|
|
3670
3790
|
// src/cli/ui/archival.ts
|
|
3671
|
-
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";
|
|
3672
3792
|
import { join as join10 } from "path";
|
|
3673
3793
|
function archiveOldRuns(runsDir, archiveAfterDays) {
|
|
3674
3794
|
if (archiveAfterDays <= 0 || !existsSync12(runsDir)) return { archived: 0 };
|
|
@@ -3709,7 +3829,7 @@ function pinRun(runsDir, runId) {
|
|
|
3709
3829
|
function unpinRun(runsDir, runId) {
|
|
3710
3830
|
const pinFile = join10(runsDir, runId, "pinned");
|
|
3711
3831
|
if (!existsSync12(pinFile)) return false;
|
|
3712
|
-
|
|
3832
|
+
unlinkSync2(pinFile);
|
|
3713
3833
|
return true;
|
|
3714
3834
|
}
|
|
3715
3835
|
function isRunPinned(runsDir, runId) {
|
|
@@ -3738,7 +3858,7 @@ __export(inception_exports, {
|
|
|
3738
3858
|
saveArtifact: () => saveArtifact,
|
|
3739
3859
|
saveInceptionState: () => saveInceptionState
|
|
3740
3860
|
});
|
|
3741
|
-
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";
|
|
3742
3862
|
import { join as join11, dirname as dirname4 } from "path";
|
|
3743
3863
|
import { fileURLToPath } from "url";
|
|
3744
3864
|
function getMethodologiesDir() {
|
|
@@ -3869,10 +3989,10 @@ function migrateInceptionToSession(factoryDir, productName) {
|
|
|
3869
3989
|
const src = join11(productDir, file);
|
|
3870
3990
|
if (existsSync13(src)) {
|
|
3871
3991
|
writeFileSync10(join11(sessionDir, file), readFileSync10(src, "utf-8"));
|
|
3872
|
-
|
|
3992
|
+
unlinkSync3(src);
|
|
3873
3993
|
}
|
|
3874
3994
|
}
|
|
3875
|
-
|
|
3995
|
+
unlinkSync3(oldInception);
|
|
3876
3996
|
return true;
|
|
3877
3997
|
}
|
|
3878
3998
|
function listProducts(factoryDir) {
|
|
@@ -5107,8 +5227,8 @@ var init_chat_handler = __esm({
|
|
|
5107
5227
|
});
|
|
5108
5228
|
|
|
5109
5229
|
// src/cli/ui/board-api-routes.ts
|
|
5110
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync13, existsSync as existsSync16, readdirSync as readdirSync8, unlinkSync as
|
|
5111
|
-
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";
|
|
5112
5232
|
import { homedir } from "os";
|
|
5113
5233
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
5114
5234
|
import { execSync as execSync3, spawnSync } from "child_process";
|
|
@@ -5373,14 +5493,6 @@ function _gitHeadSha(repoPath) {
|
|
|
5373
5493
|
return "no-git";
|
|
5374
5494
|
}
|
|
5375
5495
|
}
|
|
5376
|
-
function _hasClaudeCli() {
|
|
5377
|
-
try {
|
|
5378
|
-
execSync3("which claude", { encoding: "utf-8" });
|
|
5379
|
-
return true;
|
|
5380
|
-
} catch {
|
|
5381
|
-
return false;
|
|
5382
|
-
}
|
|
5383
|
-
}
|
|
5384
5496
|
function getBoardRoutes(factoryDir) {
|
|
5385
5497
|
return [
|
|
5386
5498
|
// ── Status ──
|
|
@@ -6096,7 +6208,7 @@ function getBoardRoutes(factoryDir) {
|
|
|
6096
6208
|
} else {
|
|
6097
6209
|
throw new Error("Missing required field: provide either `path` (local) or `github_url` (clone)");
|
|
6098
6210
|
}
|
|
6099
|
-
const projectName =
|
|
6211
|
+
const projectName = basename5(resolvedPath);
|
|
6100
6212
|
const stack = detectStack(resolvedPath);
|
|
6101
6213
|
let verifyPort = 3001;
|
|
6102
6214
|
for (const existing of listProjectRecords(projectsDir)) {
|
|
@@ -6143,11 +6255,24 @@ function getBoardRoutes(factoryDir) {
|
|
|
6143
6255
|
if (!hasSubDir && !hasFlat) throw new Error(`Project not found: ${name}`);
|
|
6144
6256
|
if (hasSubDir) rmSync3(subDir, { recursive: true, force: true });
|
|
6145
6257
|
else if (existsSync16(subDir)) rmSync3(subDir, { recursive: true, force: true });
|
|
6146
|
-
if (hasFlat)
|
|
6258
|
+
if (hasFlat) unlinkSync4(flatPath);
|
|
6147
6259
|
return { success: true };
|
|
6148
6260
|
}
|
|
6149
6261
|
},
|
|
6150
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)
|
|
6151
6276
|
method: "POST",
|
|
6152
6277
|
pattern: "/api/projects/:name/analyze",
|
|
6153
6278
|
handler: async (body, params, query) => {
|
|
@@ -6185,59 +6310,36 @@ Path: ${projectPath}
|
|
|
6185
6310
|
}
|
|
6186
6311
|
if (!force) {
|
|
6187
6312
|
const meta = _readAnalyzeMeta(projectsDir, name);
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
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
|
+
}
|
|
6191
6318
|
}
|
|
6192
6319
|
}
|
|
6193
6320
|
const existingJob = _analyzeJobs.get(name);
|
|
6194
6321
|
if (existingJob && existingJob.status === "running") {
|
|
6195
6322
|
return { analyzing: true, project: name, job_id: existingJob.job_id, status: "running" };
|
|
6196
6323
|
}
|
|
6197
|
-
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;
|
|
6198
6328
|
try {
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
const brownfieldPath = join14(subDir, "brownfield.md");
|
|
6210
|
-
if (!existsSync16(brownfieldPath)) {
|
|
6211
|
-
const { detectStack: detectStackFn } = await Promise.resolve().then(() => (init_engine(), engine_exports));
|
|
6212
|
-
let stackInfo = "Unknown stack";
|
|
6213
|
-
try {
|
|
6214
|
-
const stack = detectStackFn(projectPath);
|
|
6215
|
-
const cmds = stack.suggested_commands;
|
|
6216
|
-
stackInfo = `Framework: ${stack.framework || "unknown"}
|
|
6217
|
-
Build: ${cmds?.build || "unknown"}
|
|
6218
|
-
Dev: ${cmds?.dev || "unknown"}`;
|
|
6219
|
-
} catch {
|
|
6220
|
-
}
|
|
6221
|
-
writeFileSync13(brownfieldPath, `# Brownfield Analysis: ${name}
|
|
6222
|
-
|
|
6223
|
-
${stackInfo}
|
|
6224
|
-
|
|
6225
|
-
Path: ${projectPath}
|
|
6226
|
-
`);
|
|
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 {
|
|
6227
6339
|
}
|
|
6228
|
-
writeMeta({
|
|
6229
|
-
analyzed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6230
|
-
target_repo_head_sha: _gitHeadSha(projectPath),
|
|
6231
|
-
status: "failed",
|
|
6232
|
-
error: "Claude CLI not available",
|
|
6233
|
-
duration_seconds: 0
|
|
6234
|
-
});
|
|
6235
|
-
console.warn(`[analyze] Claude CLI unavailable for project ${name}; wrote detectStack() fallback.`);
|
|
6236
|
-
return { analyzed: true, project: name, fallback: true };
|
|
6237
6340
|
}
|
|
6238
6341
|
const jobId = randomUUID2();
|
|
6239
6342
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6240
|
-
const startMs = Date.now();
|
|
6241
6343
|
const job = {
|
|
6242
6344
|
job_id: jobId,
|
|
6243
6345
|
project: name,
|
|
@@ -6245,171 +6347,86 @@ Path: ${projectPath}
|
|
|
6245
6347
|
started_at: startedAt
|
|
6246
6348
|
};
|
|
6247
6349
|
_analyzeJobs.set(name, job);
|
|
6248
|
-
(
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
].join("\n");
|
|
6260
|
-
const isRoot = process.getuid?.() === 0;
|
|
6261
|
-
const claudeArgs = [
|
|
6262
|
-
"-p",
|
|
6263
|
-
prompt,
|
|
6264
|
-
"--agent",
|
|
6265
|
-
"brownfield-analyst",
|
|
6266
|
-
"--output-format",
|
|
6267
|
-
"stream-json",
|
|
6268
|
-
"--verbose",
|
|
6269
|
-
"--dangerously-skip-permissions"
|
|
6270
|
-
];
|
|
6271
|
-
const spawnCmd = isRoot ? "runuser" : "claude";
|
|
6272
|
-
const spawnArgs = isRoot ? ["-u", "node", "--", "claude", ...claudeArgs] : claudeArgs;
|
|
6273
|
-
const child = spawn4(spawnCmd, spawnArgs, {
|
|
6274
|
-
cwd: projectPath,
|
|
6275
|
-
env: {
|
|
6276
|
-
...process.env,
|
|
6277
|
-
BEASTMODE_PROJECT: name,
|
|
6278
|
-
BEASTMODE_OUTPUT_DIR: subDir,
|
|
6279
|
-
...isRoot ? { HOME: "/home/node" } : {}
|
|
6280
|
-
},
|
|
6281
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
6282
|
-
});
|
|
6283
|
-
child.stdout?.on("data", () => {
|
|
6284
|
-
});
|
|
6285
|
-
child.stderr?.on("data", () => {
|
|
6286
|
-
});
|
|
6287
|
-
child.on("close", (code) => {
|
|
6288
|
-
const durationSeconds = (Date.now() - startMs) / 1e3;
|
|
6289
|
-
const sha = _gitHeadSha(projectPath);
|
|
6290
|
-
const guidePath = join14(subDir, "codebase-guide.md");
|
|
6291
|
-
const ok = code === 0 && existsSync16(guidePath);
|
|
6292
|
-
if (ok) {
|
|
6293
|
-
writeMeta({
|
|
6294
|
-
analyzed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6295
|
-
analyst_version: "brownfield-analyst-v1",
|
|
6296
|
-
target_repo_head_sha: sha,
|
|
6297
|
-
project_name: name,
|
|
6298
|
-
duration_seconds: durationSeconds,
|
|
6299
|
-
status: "complete"
|
|
6300
|
-
});
|
|
6301
|
-
const legacy = join14(subDir, "brownfield.md");
|
|
6302
|
-
if (existsSync16(legacy)) {
|
|
6303
|
-
try {
|
|
6304
|
-
unlinkSync3(legacy);
|
|
6305
|
-
} catch {
|
|
6306
|
-
}
|
|
6307
|
-
}
|
|
6308
|
-
_analyzeJobs.set(name, {
|
|
6309
|
-
...job,
|
|
6310
|
-
status: "complete",
|
|
6311
|
-
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6312
|
-
duration_seconds: durationSeconds
|
|
6313
|
-
});
|
|
6314
|
-
} else {
|
|
6315
|
-
const errMsg = `claude exited with code ${code}`;
|
|
6316
|
-
writeMeta({
|
|
6317
|
-
analyzed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6318
|
-
target_repo_head_sha: sha,
|
|
6319
|
-
status: "failed",
|
|
6320
|
-
error: errMsg,
|
|
6321
|
-
duration_seconds: durationSeconds
|
|
6322
|
-
});
|
|
6323
|
-
_analyzeJobs.set(name, {
|
|
6324
|
-
...job,
|
|
6325
|
-
status: "failed",
|
|
6326
|
-
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6327
|
-
duration_seconds: durationSeconds,
|
|
6328
|
-
error: errMsg
|
|
6329
|
-
});
|
|
6330
|
-
}
|
|
6331
|
-
});
|
|
6332
|
-
child.on("error", (err) => {
|
|
6333
|
-
const durationSeconds = (Date.now() - startMs) / 1e3;
|
|
6334
|
-
const sha = _gitHeadSha(projectPath);
|
|
6335
|
-
writeMeta({
|
|
6336
|
-
analyzed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6337
|
-
target_repo_head_sha: sha,
|
|
6338
|
-
status: "failed",
|
|
6339
|
-
error: String(err),
|
|
6340
|
-
duration_seconds: durationSeconds
|
|
6341
|
-
});
|
|
6342
|
-
_analyzeJobs.set(name, {
|
|
6343
|
-
...job,
|
|
6344
|
-
status: "failed",
|
|
6345
|
-
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6346
|
-
duration_seconds: durationSeconds,
|
|
6347
|
-
error: String(err)
|
|
6348
|
-
});
|
|
6349
|
-
});
|
|
6350
|
-
} catch (err) {
|
|
6351
|
-
const durationSeconds = (Date.now() - startMs) / 1e3;
|
|
6352
|
-
const sha = _gitHeadSha(projectPath);
|
|
6353
|
-
writeMeta({
|
|
6354
|
-
analyzed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6355
|
-
target_repo_head_sha: sha,
|
|
6356
|
-
status: "failed",
|
|
6357
|
-
error: String(err),
|
|
6358
|
-
duration_seconds: durationSeconds
|
|
6359
|
-
});
|
|
6360
|
-
_analyzeJobs.set(name, {
|
|
6361
|
-
...job,
|
|
6362
|
-
status: "failed",
|
|
6363
|
-
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6364
|
-
duration_seconds: durationSeconds,
|
|
6365
|
-
error: String(err)
|
|
6366
|
-
});
|
|
6367
|
-
}
|
|
6368
|
-
})();
|
|
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
|
+
);
|
|
6369
6361
|
return { analyzing: true, project: name, job_id: jobId, status: "running" };
|
|
6370
6362
|
}
|
|
6371
6363
|
},
|
|
6372
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
|
|
6373
6373
|
method: "GET",
|
|
6374
6374
|
pattern: "/api/projects/:name/analyze/status",
|
|
6375
6375
|
handler: (_body, params) => {
|
|
6376
6376
|
const { name } = params;
|
|
6377
6377
|
assertSafeName(name);
|
|
6378
6378
|
const projectsDir = join14(factoryDir, ".beastmode", "projects");
|
|
6379
|
-
const
|
|
6380
|
-
const
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
status: "
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
completed_at: job.completed_at,
|
|
6395
|
-
duration_seconds: job.duration_seconds
|
|
6396
|
-
};
|
|
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
|
+
}
|
|
6397
6394
|
}
|
|
6395
|
+
const meta = _readAnalyzeMeta(projectsDir, name);
|
|
6398
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
|
+
}
|
|
6399
6401
|
return {
|
|
6400
|
-
status:
|
|
6402
|
+
status: "complete",
|
|
6401
6403
|
analyzed_at: meta.analyzed_at,
|
|
6402
6404
|
duration_seconds: meta.duration_seconds,
|
|
6403
6405
|
target_repo_head_sha: meta.target_repo_head_sha
|
|
6404
6406
|
};
|
|
6405
6407
|
}
|
|
6406
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
|
+
}
|
|
6407
6413
|
return {
|
|
6408
6414
|
status: "failed",
|
|
6409
6415
|
analyzed_at: meta.analyzed_at,
|
|
6410
6416
|
error: meta.error
|
|
6411
6417
|
};
|
|
6412
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
|
+
}
|
|
6413
6430
|
return { status: "idle" };
|
|
6414
6431
|
}
|
|
6415
6432
|
},
|
|
@@ -7957,7 +7974,7 @@ __export(sync_claude_creds_exports, {
|
|
|
7957
7974
|
});
|
|
7958
7975
|
import { Command as Command2 } from "commander";
|
|
7959
7976
|
import { execSync as execSync5, spawnSync as spawnSync2 } from "child_process";
|
|
7960
|
-
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";
|
|
7961
7978
|
import { join as join17 } from "path";
|
|
7962
7979
|
import { homedir as homedir2, platform } from "os";
|
|
7963
7980
|
function systemdUserDir() {
|
|
@@ -8030,7 +8047,7 @@ function removeUrgencyMarker(factoryDir) {
|
|
|
8030
8047
|
if (!factoryDir) return;
|
|
8031
8048
|
const markerPath = urgencyMarkerHostPath(factoryDir);
|
|
8032
8049
|
try {
|
|
8033
|
-
|
|
8050
|
+
unlinkSync5(markerPath);
|
|
8034
8051
|
} catch {
|
|
8035
8052
|
}
|
|
8036
8053
|
}
|
|
@@ -8136,7 +8153,7 @@ function uninstallAgent() {
|
|
|
8136
8153
|
warn(`launchctl bootout returned: ${result.stderr || result.stdout}`);
|
|
8137
8154
|
}
|
|
8138
8155
|
try {
|
|
8139
|
-
|
|
8156
|
+
unlinkSync5(plist);
|
|
8140
8157
|
} catch {
|
|
8141
8158
|
}
|
|
8142
8159
|
success(`LaunchAgent removed: ${LAUNCH_AGENT_LABEL}`);
|
|
@@ -8322,14 +8339,14 @@ function uninstallAgentLinux() {
|
|
|
8322
8339
|
let removed = false;
|
|
8323
8340
|
if (existsSync19(servicePath)) {
|
|
8324
8341
|
try {
|
|
8325
|
-
|
|
8342
|
+
unlinkSync5(servicePath);
|
|
8326
8343
|
removed = true;
|
|
8327
8344
|
} catch {
|
|
8328
8345
|
}
|
|
8329
8346
|
}
|
|
8330
8347
|
if (existsSync19(timerPath)) {
|
|
8331
8348
|
try {
|
|
8332
|
-
|
|
8349
|
+
unlinkSync5(timerPath);
|
|
8333
8350
|
removed = true;
|
|
8334
8351
|
} catch {
|
|
8335
8352
|
}
|
|
@@ -8507,7 +8524,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
8507
8524
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8508
8525
|
import { z as z2 } from "zod";
|
|
8509
8526
|
import { readFileSync as readFileSync29, writeFileSync as writeFileSync25, existsSync as existsSync32, readdirSync as readdirSync12 } from "fs";
|
|
8510
|
-
import { join as join30, resolve as resolve18, basename as
|
|
8527
|
+
import { join as join30, resolve as resolve18, basename as basename7 } from "path";
|
|
8511
8528
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
8512
8529
|
function readJsonFile2(filePath) {
|
|
8513
8530
|
if (!existsSync32(filePath)) return null;
|
|
@@ -8826,7 +8843,7 @@ function createMcpServer() {
|
|
|
8826
8843
|
if (!existsSync32(resolvedPath)) {
|
|
8827
8844
|
return { content: [{ type: "text", text: `Directory not found: ${resolvedPath}` }], isError: true };
|
|
8828
8845
|
}
|
|
8829
|
-
const projectName =
|
|
8846
|
+
const projectName = basename7(resolvedPath);
|
|
8830
8847
|
const stack = detectStack(resolvedPath);
|
|
8831
8848
|
const projectsDir = join30(factoryDir, ".beastmode", "projects");
|
|
8832
8849
|
let verifyPort = 3001;
|
|
@@ -8944,7 +8961,7 @@ init_engine();
|
|
|
8944
8961
|
init_file_writer();
|
|
8945
8962
|
import { Command as Command3 } from "commander";
|
|
8946
8963
|
import inquirer from "inquirer";
|
|
8947
|
-
import { resolve as resolve6, basename as
|
|
8964
|
+
import { resolve as resolve6, basename as basename6, join as join18 } from "path";
|
|
8948
8965
|
import { existsSync as existsSync20, writeFileSync as writeFileSync16, mkdirSync as mkdirSync15, readFileSync as readFileSync17 } from "fs";
|
|
8949
8966
|
|
|
8950
8967
|
// src/cli/utils/docker.ts
|
|
@@ -9205,7 +9222,7 @@ function isSourceRepo(dir) {
|
|
|
9205
9222
|
async function runInit(name, opts) {
|
|
9206
9223
|
if (opts.ui) {
|
|
9207
9224
|
const { startServer: startServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
9208
|
-
const factoryName2 = name ||
|
|
9225
|
+
const factoryName2 = name || basename6(resolve6("."));
|
|
9209
9226
|
const projectPath2 = opts.project ? resolve6(opts.project) : void 0;
|
|
9210
9227
|
info("Starting init wizard...");
|
|
9211
9228
|
const uiServer = await startServer2({
|
|
@@ -9238,13 +9255,13 @@ async function runInit(name, opts) {
|
|
|
9238
9255
|
const totalSteps = 5;
|
|
9239
9256
|
header("BeastMode \u2014 Dark Factory Init");
|
|
9240
9257
|
info("Creating your Custom Dark Factory\n");
|
|
9241
|
-
const factoryName = name ||
|
|
9258
|
+
const factoryName = name || basename6(resolve6("."));
|
|
9242
9259
|
if (existsSync20(factoryName) && existsSync20(resolve6(factoryName, ".beastmode"))) {
|
|
9243
9260
|
throw new Error(`Factory already exists at ./${factoryName}. Use 'beastmode config' to modify.`);
|
|
9244
9261
|
}
|
|
9245
9262
|
if (opts.from) {
|
|
9246
|
-
const { readFileSync:
|
|
9247
|
-
const templateContent =
|
|
9263
|
+
const { readFileSync: readFileSync36 } = await import("fs");
|
|
9264
|
+
const templateContent = readFileSync36(resolve6(opts.from), "utf-8");
|
|
9248
9265
|
const { parseTemplate: parseTemplate2 } = await Promise.resolve().then(() => (init_template_importer(), template_importer_exports));
|
|
9249
9266
|
const template = parseTemplate2(templateContent);
|
|
9250
9267
|
info(`Importing from template: ${opts.from}`);
|
|
@@ -9254,7 +9271,7 @@ async function runInit(name, opts) {
|
|
|
9254
9271
|
}
|
|
9255
9272
|
const templateProjectPath = resolve6(opts.project);
|
|
9256
9273
|
const templateStack = detectStack(templateProjectPath);
|
|
9257
|
-
const templateProjectName =
|
|
9274
|
+
const templateProjectName = basename6(templateProjectPath);
|
|
9258
9275
|
const actions2 = scaffoldFactory(factoryName, template.config, {
|
|
9259
9276
|
name: templateProjectName,
|
|
9260
9277
|
repo: templateStack.git_remote || void 0,
|
|
@@ -9449,7 +9466,7 @@ async function runInit(name, opts) {
|
|
|
9449
9466
|
success("Board UI password set");
|
|
9450
9467
|
}
|
|
9451
9468
|
step(5, totalSteps, "Boot");
|
|
9452
|
-
const projectName =
|
|
9469
|
+
const projectName = basename6(projectPath);
|
|
9453
9470
|
const actions = scaffoldFactory(factoryName, config, {
|
|
9454
9471
|
name: projectName,
|
|
9455
9472
|
repo: stack.git_remote || void 0,
|
|
@@ -12161,10 +12178,10 @@ async function runMigrate(opts) {
|
|
|
12161
12178
|
let runDirs = [];
|
|
12162
12179
|
const checkpoints = /* @__PURE__ */ new Map();
|
|
12163
12180
|
if (existsSync29(runsDir)) {
|
|
12164
|
-
const { readdirSync:
|
|
12165
|
-
runDirs =
|
|
12181
|
+
const { readdirSync: readdirSync13 } = await import("fs");
|
|
12182
|
+
runDirs = readdirSync13(runsDir).filter((d) => {
|
|
12166
12183
|
try {
|
|
12167
|
-
return
|
|
12184
|
+
return readdirSync13(join27(runsDir, d)).length > 0;
|
|
12168
12185
|
} catch {
|
|
12169
12186
|
return false;
|
|
12170
12187
|
}
|
|
@@ -12272,6 +12289,7 @@ init_display();
|
|
|
12272
12289
|
init_board();
|
|
12273
12290
|
init_bridge();
|
|
12274
12291
|
init_schemas();
|
|
12292
|
+
init_engine();
|
|
12275
12293
|
import { Command as Command15 } from "commander";
|
|
12276
12294
|
import { join as join28 } from "path";
|
|
12277
12295
|
import { existsSync as existsSync30, readFileSync as readFileSync27, writeFileSync as writeFileSync23, mkdirSync as mkdirSync18 } from "fs";
|
|
@@ -12305,25 +12323,16 @@ async function runPipeline(projectName, opts) {
|
|
|
12305
12323
|
);
|
|
12306
12324
|
let projectConfig = null;
|
|
12307
12325
|
const projectsDir = join28(bmDir, "projects");
|
|
12308
|
-
if (
|
|
12309
|
-
const
|
|
12310
|
-
|
|
12311
|
-
(
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
throw new Error(`Project not found: ${projectName}`);
|
|
12319
|
-
}
|
|
12320
|
-
projectConfig = ProjectConfigSchema.parse(
|
|
12321
|
-
JSON.parse(readFileSync27(join28(projectsDir, file), "utf-8"))
|
|
12322
|
-
);
|
|
12323
|
-
} else if (projectFiles.length > 0) {
|
|
12324
|
-
projectConfig = ProjectConfigSchema.parse(
|
|
12325
|
-
JSON.parse(readFileSync27(join28(projectsDir, projectFiles[0]), "utf-8"))
|
|
12326
|
-
);
|
|
12326
|
+
if (projectName) {
|
|
12327
|
+
const record = readProjectRecord(projectsDir, projectName);
|
|
12328
|
+
if (!record) {
|
|
12329
|
+
throw new Error(`Project not found: ${projectName}`);
|
|
12330
|
+
}
|
|
12331
|
+
projectConfig = record;
|
|
12332
|
+
} else {
|
|
12333
|
+
const projects = listProjectRecords(projectsDir);
|
|
12334
|
+
if (projects.length > 0) {
|
|
12335
|
+
projectConfig = projects[0];
|
|
12327
12336
|
info(`Using project: ${projectConfig.name}`);
|
|
12328
12337
|
}
|
|
12329
12338
|
}
|
|
@@ -12450,6 +12459,7 @@ init_display();
|
|
|
12450
12459
|
init_board();
|
|
12451
12460
|
init_bridge();
|
|
12452
12461
|
init_schemas();
|
|
12462
|
+
init_engine();
|
|
12453
12463
|
import { Command as Command16 } from "commander";
|
|
12454
12464
|
import { join as join29 } from "path";
|
|
12455
12465
|
import { existsSync as existsSync31, readFileSync as readFileSync28, writeFileSync as writeFileSync24, mkdirSync as mkdirSync19 } from "fs";
|
|
@@ -12483,17 +12493,10 @@ async function runDaemon(opts) {
|
|
|
12483
12493
|
);
|
|
12484
12494
|
let projectConfig = null;
|
|
12485
12495
|
const projectsDir = join29(bmDir, "projects");
|
|
12486
|
-
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
);
|
|
12491
|
-
if (projectFiles.length > 0) {
|
|
12492
|
-
projectConfig = ProjectConfigSchema.parse(
|
|
12493
|
-
JSON.parse(readFileSync28(join29(projectsDir, projectFiles[0]), "utf-8"))
|
|
12494
|
-
);
|
|
12495
|
-
info(`Using project: ${projectConfig.name}`);
|
|
12496
|
-
}
|
|
12496
|
+
const projects = listProjectRecords(projectsDir);
|
|
12497
|
+
if (projects.length > 0) {
|
|
12498
|
+
projectConfig = projects[0];
|
|
12499
|
+
info(`Using project: ${projectConfig.name}`);
|
|
12497
12500
|
}
|
|
12498
12501
|
const cacheDir = join29(bmDir, ".cache");
|
|
12499
12502
|
mkdirSync19(cacheDir, { recursive: true });
|
|
@@ -12564,8 +12567,8 @@ async function runDaemon(opts) {
|
|
|
12564
12567
|
const exitCode = await new Promise((resolvePromise) => {
|
|
12565
12568
|
child.on("exit", (code) => {
|
|
12566
12569
|
try {
|
|
12567
|
-
const { unlinkSync:
|
|
12568
|
-
|
|
12570
|
+
const { unlinkSync: unlinkSync8 } = __require("fs");
|
|
12571
|
+
unlinkSync8(pidFile);
|
|
12569
12572
|
} catch {
|
|
12570
12573
|
}
|
|
12571
12574
|
resolvePromise(code ?? 1);
|
|
@@ -13201,11 +13204,12 @@ var updateCommand = new Command22("update").description("Pull latest BeastMode i
|
|
|
13201
13204
|
});
|
|
13202
13205
|
|
|
13203
13206
|
// src/cli/commands/runner-cmd.ts
|
|
13207
|
+
init_engine();
|
|
13204
13208
|
init_display();
|
|
13205
13209
|
import { Command as Command23 } from "commander";
|
|
13206
13210
|
import { spawn as spawn3 } from "child_process";
|
|
13207
|
-
import { existsSync as existsSync38
|
|
13208
|
-
import { basename as
|
|
13211
|
+
import { existsSync as existsSync38 } from "fs";
|
|
13212
|
+
import { basename as basename8, join as join37, resolve as resolve20 } from "path";
|
|
13209
13213
|
|
|
13210
13214
|
// src/cli/runner-image-builder.ts
|
|
13211
13215
|
import { execSync as execSync10 } from "child_process";
|
|
@@ -13791,7 +13795,7 @@ import {
|
|
|
13791
13795
|
createWriteStream,
|
|
13792
13796
|
existsSync as existsSync36,
|
|
13793
13797
|
mkdirSync as mkdirSync22,
|
|
13794
|
-
unlinkSync as
|
|
13798
|
+
unlinkSync as unlinkSync6,
|
|
13795
13799
|
writeFileSync as writeFileSync29
|
|
13796
13800
|
} from "fs";
|
|
13797
13801
|
import { homedir as homedir4 } from "os";
|
|
@@ -13859,7 +13863,7 @@ async function downloadAndExtractRunner(installDir, os, arch) {
|
|
|
13859
13863
|
);
|
|
13860
13864
|
}
|
|
13861
13865
|
try {
|
|
13862
|
-
|
|
13866
|
+
unlinkSync6(tarball);
|
|
13863
13867
|
} catch {
|
|
13864
13868
|
}
|
|
13865
13869
|
if (os === "darwin") {
|
|
@@ -14097,7 +14101,7 @@ import {
|
|
|
14097
14101
|
existsSync as existsSync37,
|
|
14098
14102
|
mkdirSync as mkdirSync23,
|
|
14099
14103
|
readFileSync as readFileSync34,
|
|
14100
|
-
unlinkSync as
|
|
14104
|
+
unlinkSync as unlinkSync7,
|
|
14101
14105
|
writeFileSync as writeFileSync30
|
|
14102
14106
|
} from "fs";
|
|
14103
14107
|
import { dirname as dirname9, join as join36 } from "path";
|
|
@@ -14189,7 +14193,7 @@ async function restoreWorkflows(projectDir) {
|
|
|
14189
14193
|
jobCount: fileState.originals.length
|
|
14190
14194
|
});
|
|
14191
14195
|
}
|
|
14192
|
-
|
|
14196
|
+
unlinkSync7(statePath);
|
|
14193
14197
|
return { nothingToRestore: false, files: resultFiles };
|
|
14194
14198
|
}
|
|
14195
14199
|
|
|
@@ -14199,22 +14203,16 @@ function resolveProjectName(projectDir) {
|
|
|
14199
14203
|
const projectsDir = join37(projectDir, ".beastmode", "projects");
|
|
14200
14204
|
if (existsSync38(projectsDir)) {
|
|
14201
14205
|
try {
|
|
14202
|
-
|
|
14203
|
-
|
|
14204
|
-
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
if (typeof data.path === "string" && resolve20(data.path) === resolve20(projectDir) && typeof data.name === "string" && data.name.length > 0) {
|
|
14209
|
-
return data.name;
|
|
14210
|
-
}
|
|
14211
|
-
} catch {
|
|
14212
|
-
}
|
|
14213
|
-
}
|
|
14206
|
+
const records = listProjectRecords(projectsDir);
|
|
14207
|
+
const target = resolve20(projectDir);
|
|
14208
|
+
const match = records.find(
|
|
14209
|
+
(r) => typeof r.path === "string" && resolve20(r.path) === target
|
|
14210
|
+
);
|
|
14211
|
+
if (match && match.name) return match.name;
|
|
14214
14212
|
} catch {
|
|
14215
14213
|
}
|
|
14216
14214
|
}
|
|
14217
|
-
return
|
|
14215
|
+
return basename8(resolve20(projectDir));
|
|
14218
14216
|
}
|
|
14219
14217
|
async function runnerSetupAction(opts) {
|
|
14220
14218
|
if (opts.service !== void 0 && !opts.native) {
|
|
@@ -14589,8 +14587,8 @@ runnerCommand.command("build-image").description(
|
|
|
14589
14587
|
// src/cli/commands/project-cmd.ts
|
|
14590
14588
|
init_engine();
|
|
14591
14589
|
import { Command as Command24 } from "commander";
|
|
14592
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync24, readFileSync as
|
|
14593
|
-
import { join as join38, resolve as resolve21, basename as
|
|
14590
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync24, readFileSync as readFileSync35, renameSync as renameSync3 } from "fs";
|
|
14591
|
+
import { join as join38, resolve as resolve21, basename as basename9 } from "path";
|
|
14594
14592
|
import { execSync as execSync13 } from "child_process";
|
|
14595
14593
|
var DEFAULT_MAX_PROJECTS = 5;
|
|
14596
14594
|
var MIN_DISK_WARNING_GB = 10;
|
|
@@ -14598,7 +14596,7 @@ function getMaxProjects(factoryDir) {
|
|
|
14598
14596
|
const configPath = join38(factoryDir, ".beastmode", "config.json");
|
|
14599
14597
|
if (existsSync39(configPath)) {
|
|
14600
14598
|
try {
|
|
14601
|
-
const config = JSON.parse(
|
|
14599
|
+
const config = JSON.parse(readFileSync35(configPath, "utf-8"));
|
|
14602
14600
|
if (typeof config.max_projects === "number") return config.max_projects;
|
|
14603
14601
|
} catch {
|
|
14604
14602
|
}
|
|
@@ -14618,7 +14616,7 @@ function getFreeDiskGB() {
|
|
|
14618
14616
|
function projectAddAction(factoryDir, projectPath, opts) {
|
|
14619
14617
|
const resolvedPath = resolve21(projectPath);
|
|
14620
14618
|
if (!existsSync39(resolvedPath)) throw new Error(`Directory not found: ${resolvedPath}`);
|
|
14621
|
-
const projectName = opts.name ||
|
|
14619
|
+
const projectName = opts.name || basename9(resolvedPath);
|
|
14622
14620
|
const projectsDir = join38(factoryDir, ".beastmode", "projects");
|
|
14623
14621
|
if (existsSync39(join38(projectsDir, projectName, "project.json"))) {
|
|
14624
14622
|
throw new Error(`Project already exists: ${projectName}`);
|
|
@@ -14709,7 +14707,7 @@ var projectCommand = new Command24("project").description("Manage projects in th
|
|
|
14709
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) => {
|
|
14710
14708
|
const factoryDir = resolve21(".");
|
|
14711
14709
|
projectAddAction(factoryDir, path, opts);
|
|
14712
|
-
console.log(`Project registered: ${opts.name ||
|
|
14710
|
+
console.log(`Project registered: ${opts.name || basename9(resolve21(path))}`);
|
|
14713
14711
|
});
|
|
14714
14712
|
projectCommand.command("list").description("List registered projects").action(() => {
|
|
14715
14713
|
const projects = projectListAction(resolve21("."));
|