codebyplan 1.13.38 → 1.13.39
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/cli.js +557 -117
- package/package.json +1 -1
- package/templates/agents/cbp-map-architecture.md +90 -0
- package/templates/agents/cbp-round-executor.md +10 -0
- package/templates/agents/cbp-task-planner.md +5 -0
- package/templates/context/architecture/arch-map-spec.md +204 -0
- package/templates/context/architecture-map.md +117 -0
- package/templates/hooks/validate-structure.sh +3 -2
- package/templates/rules/architecture-map.md +30 -0
- package/templates/rules/context-file-loading.md +3 -0
- package/templates/rules/supabase-branch-lifecycle.md +1 -1
- package/templates/settings.project.base.json +5 -1
- package/templates/skills/cbp-checkpoint-end/SKILL.md +6 -3
- package/templates/skills/cbp-git-worktree-remove/SKILL.md +3 -2
- package/templates/skills/cbp-map-architecture/SKILL.md +170 -0
- package/templates/skills/cbp-refresh-arch-map/SKILL.md +191 -0
- package/templates/skills/cbp-session-start/SKILL.md +33 -2
- package/templates/skills/cbp-ship/reference/surface-supabase.md +3 -3
- package/templates/skills/cbp-ship-configure/SKILL.md +1 -1
- package/templates/skills/cbp-ship-configure/reference/railway-backend.md +2 -2
- package/templates/skills/cbp-ship-configure/reference/vercel.md +1 -1
- package/templates/skills/cbp-ship-main/SKILL.md +3 -2
- package/templates/skills/cbp-standalone-task-complete/SKILL.md +3 -2
- package/templates/skills/cbp-supabase-migrate/SKILL.md +2 -6
package/dist/cli.js
CHANGED
|
@@ -14,7 +14,7 @@ var VERSION, PACKAGE_NAME;
|
|
|
14
14
|
var init_version = __esm({
|
|
15
15
|
"src/lib/version.ts"() {
|
|
16
16
|
"use strict";
|
|
17
|
-
VERSION = "1.13.
|
|
17
|
+
VERSION = "1.13.39";
|
|
18
18
|
PACKAGE_NAME = "codebyplan";
|
|
19
19
|
}
|
|
20
20
|
});
|
|
@@ -3134,6 +3134,11 @@ async function writeCodebyplanDirectory(projectPath, selectedRepo, deviceId) {
|
|
|
3134
3134
|
JSON.stringify({}, null, 2) + "\n",
|
|
3135
3135
|
"utf-8"
|
|
3136
3136
|
);
|
|
3137
|
+
await writeFile7(
|
|
3138
|
+
join12(codebyplanDir, "architecture.json"),
|
|
3139
|
+
JSON.stringify({ version: 1, modules: [] }, null, 2) + "\n",
|
|
3140
|
+
"utf-8"
|
|
3141
|
+
);
|
|
3137
3142
|
const statuslinePath = join12(codebyplanDir, "statusline.json");
|
|
3138
3143
|
let statuslineExists = false;
|
|
3139
3144
|
try {
|
|
@@ -3151,7 +3156,7 @@ async function writeCodebyplanDirectory(projectPath, selectedRepo, deviceId) {
|
|
|
3151
3156
|
await writeLocalConfig(projectPath, { device_id: deviceId });
|
|
3152
3157
|
console.log(` Created ${codebyplanDir}/`);
|
|
3153
3158
|
console.log(
|
|
3154
|
-
` repo.json, server.json, git.json, shipment.json, vendor.json, e2e.json, eslint.json, statusline.json`
|
|
3159
|
+
` repo.json, server.json, git.json, shipment.json, vendor.json, e2e.json, eslint.json, architecture.json, statusline.json`
|
|
3155
3160
|
);
|
|
3156
3161
|
console.log(` device.local.json (gitignored)`);
|
|
3157
3162
|
const gitignoreAction = await ensureManagedGitignoreBlock(projectPath);
|
|
@@ -7142,6 +7147,425 @@ var init_upload_e2e_images = __esm({
|
|
|
7142
7147
|
}
|
|
7143
7148
|
});
|
|
7144
7149
|
|
|
7150
|
+
// src/cli/arch-map.ts
|
|
7151
|
+
var arch_map_exports = {};
|
|
7152
|
+
__export(arch_map_exports, {
|
|
7153
|
+
mapFileSlug: () => mapFileSlug,
|
|
7154
|
+
runArchMapCommand: () => runArchMapCommand,
|
|
7155
|
+
updateFrontmatterFields: () => updateFrontmatterFields
|
|
7156
|
+
});
|
|
7157
|
+
import { readFile as readFile17, writeFile as writeFile13 } from "node:fs/promises";
|
|
7158
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2 } from "node:fs";
|
|
7159
|
+
import { join as join23 } from "node:path";
|
|
7160
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
7161
|
+
function normalizeModulePath(modulePath) {
|
|
7162
|
+
return modulePath.replace(/\/+$/, "");
|
|
7163
|
+
}
|
|
7164
|
+
function repoRootFromCodebyplanDir(codebyplanDir) {
|
|
7165
|
+
return codebyplanDir.endsWith("/.codebyplan") ? codebyplanDir.slice(0, codebyplanDir.lastIndexOf("/")) : codebyplanDir;
|
|
7166
|
+
}
|
|
7167
|
+
function mapFileSlug(modulePath) {
|
|
7168
|
+
const slug = modulePath.replace(/\//g, "-").replace(/^\./, "dot-");
|
|
7169
|
+
return `${slug}.md`;
|
|
7170
|
+
}
|
|
7171
|
+
async function resolveCodebyplanDir(startDir) {
|
|
7172
|
+
try {
|
|
7173
|
+
const found = await findCodebyplanConfig(startDir);
|
|
7174
|
+
if (!found) return null;
|
|
7175
|
+
if (found.path.endsWith("/repo.json")) {
|
|
7176
|
+
return found.path.slice(0, found.path.lastIndexOf("/"));
|
|
7177
|
+
}
|
|
7178
|
+
return found.path.slice(0, found.path.lastIndexOf("/"));
|
|
7179
|
+
} catch {
|
|
7180
|
+
return null;
|
|
7181
|
+
}
|
|
7182
|
+
}
|
|
7183
|
+
async function readArchitectureConfig(codebyplanDir) {
|
|
7184
|
+
const filePath = join23(codebyplanDir, "architecture.json");
|
|
7185
|
+
try {
|
|
7186
|
+
const raw = await readFile17(filePath, "utf-8");
|
|
7187
|
+
const parsed = JSON.parse(raw);
|
|
7188
|
+
if (typeof parsed !== "object" || parsed === null || !Array.isArray(parsed.modules)) {
|
|
7189
|
+
return { version: 1, modules: [] };
|
|
7190
|
+
}
|
|
7191
|
+
return parsed;
|
|
7192
|
+
} catch {
|
|
7193
|
+
return { version: 1, modules: [] };
|
|
7194
|
+
}
|
|
7195
|
+
}
|
|
7196
|
+
async function writeArchitectureConfig(codebyplanDir, config) {
|
|
7197
|
+
const filePath = join23(codebyplanDir, "architecture.json");
|
|
7198
|
+
await writeFile13(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
7199
|
+
}
|
|
7200
|
+
function resolveGitSha(modulePath, cwd) {
|
|
7201
|
+
try {
|
|
7202
|
+
const result = spawnSync7(
|
|
7203
|
+
"git",
|
|
7204
|
+
["log", "--format=%H", "-1", "--", modulePath],
|
|
7205
|
+
{ cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
7206
|
+
);
|
|
7207
|
+
if (result.status !== 0 || result.error) return null;
|
|
7208
|
+
const sha = (result.stdout ?? "").trim();
|
|
7209
|
+
return sha.length > 0 ? sha : null;
|
|
7210
|
+
} catch {
|
|
7211
|
+
return null;
|
|
7212
|
+
}
|
|
7213
|
+
}
|
|
7214
|
+
async function discoverModulePaths(projectRoot) {
|
|
7215
|
+
const paths = [];
|
|
7216
|
+
const workspacePath = join23(projectRoot, "pnpm-workspace.yaml");
|
|
7217
|
+
let patterns = [];
|
|
7218
|
+
try {
|
|
7219
|
+
const raw = await readFile17(workspacePath, "utf-8");
|
|
7220
|
+
const lines = raw.split("\n");
|
|
7221
|
+
let inPackages = false;
|
|
7222
|
+
for (const line of lines) {
|
|
7223
|
+
const trimmed = line.trim();
|
|
7224
|
+
if (trimmed.split("#")[0].trim() === "packages:") {
|
|
7225
|
+
inPackages = true;
|
|
7226
|
+
continue;
|
|
7227
|
+
}
|
|
7228
|
+
if (inPackages) {
|
|
7229
|
+
if (trimmed.startsWith("-")) {
|
|
7230
|
+
const pat = trimmed.slice(1).trim().replace(/['"]/g, "");
|
|
7231
|
+
patterns.push(pat);
|
|
7232
|
+
} else if (trimmed && !trimmed.startsWith("#")) {
|
|
7233
|
+
break;
|
|
7234
|
+
}
|
|
7235
|
+
}
|
|
7236
|
+
}
|
|
7237
|
+
} catch {
|
|
7238
|
+
patterns = ["apps/*", "packages/*"];
|
|
7239
|
+
}
|
|
7240
|
+
for (const pattern of patterns) {
|
|
7241
|
+
if (pattern.endsWith("/*")) {
|
|
7242
|
+
const dir = pattern.slice(0, -2);
|
|
7243
|
+
const absDir = join23(projectRoot, dir);
|
|
7244
|
+
try {
|
|
7245
|
+
if (existsSync5(absDir)) {
|
|
7246
|
+
const entries = readdirSync2(absDir, { withFileTypes: true });
|
|
7247
|
+
for (const entry of entries) {
|
|
7248
|
+
if (entry.isDirectory()) {
|
|
7249
|
+
paths.push(`${dir}/${entry.name}`);
|
|
7250
|
+
}
|
|
7251
|
+
}
|
|
7252
|
+
}
|
|
7253
|
+
} catch {
|
|
7254
|
+
}
|
|
7255
|
+
} else if (!pattern.includes("*")) {
|
|
7256
|
+
const absPath = join23(projectRoot, pattern);
|
|
7257
|
+
if (existsSync5(absPath)) {
|
|
7258
|
+
paths.push(pattern);
|
|
7259
|
+
}
|
|
7260
|
+
}
|
|
7261
|
+
}
|
|
7262
|
+
const crossCutting = ["supabase", ".github", "scripts"];
|
|
7263
|
+
for (const dir of crossCutting) {
|
|
7264
|
+
const absPath = join23(projectRoot, dir);
|
|
7265
|
+
try {
|
|
7266
|
+
if (existsSync5(absPath)) {
|
|
7267
|
+
paths.push(dir);
|
|
7268
|
+
}
|
|
7269
|
+
} catch {
|
|
7270
|
+
}
|
|
7271
|
+
}
|
|
7272
|
+
return paths;
|
|
7273
|
+
}
|
|
7274
|
+
async function runStatus(projectRoot) {
|
|
7275
|
+
console.log("\n CodeByPlan arch-map status\n");
|
|
7276
|
+
try {
|
|
7277
|
+
const codebyplanDir = await resolveCodebyplanDir(projectRoot);
|
|
7278
|
+
const repoRoot = codebyplanDir ? repoRootFromCodebyplanDir(codebyplanDir) : projectRoot;
|
|
7279
|
+
const config = codebyplanDir ? await readArchitectureConfig(codebyplanDir) : { version: 1, modules: [] };
|
|
7280
|
+
const manifestByPath = /* @__PURE__ */ new Map();
|
|
7281
|
+
for (const entry of config.modules) {
|
|
7282
|
+
manifestByPath.set(normalizeModulePath(entry.path), entry);
|
|
7283
|
+
}
|
|
7284
|
+
let modulePaths = [];
|
|
7285
|
+
try {
|
|
7286
|
+
modulePaths = await discoverModulePaths(repoRoot);
|
|
7287
|
+
} catch {
|
|
7288
|
+
console.warn(" Warning: could not discover modules from workspace");
|
|
7289
|
+
}
|
|
7290
|
+
if (modulePaths.length === 0 && config.modules.length === 0) {
|
|
7291
|
+
console.log(" No modules found.\n");
|
|
7292
|
+
return;
|
|
7293
|
+
}
|
|
7294
|
+
const allPaths = /* @__PURE__ */ new Set([
|
|
7295
|
+
...modulePaths.map(normalizeModulePath),
|
|
7296
|
+
...config.modules.map((e) => normalizeModulePath(e.path))
|
|
7297
|
+
]);
|
|
7298
|
+
console.log(
|
|
7299
|
+
" Module".padEnd(40) + "Map".padEnd(8) + "Stamped".padEnd(12) + "Status"
|
|
7300
|
+
);
|
|
7301
|
+
console.log(" " + "-".repeat(70));
|
|
7302
|
+
for (const modPath of allPaths) {
|
|
7303
|
+
const entry = manifestByPath.get(modPath);
|
|
7304
|
+
const hasMap = !!entry;
|
|
7305
|
+
const stamped = entry?.generated_from_sha != null;
|
|
7306
|
+
let freshness = "-";
|
|
7307
|
+
if (stamped && entry) {
|
|
7308
|
+
const currentSha = resolveGitSha(modPath, repoRoot);
|
|
7309
|
+
if (currentSha == null) {
|
|
7310
|
+
freshness = "unknown";
|
|
7311
|
+
} else if (currentSha === entry.generated_from_sha) {
|
|
7312
|
+
freshness = "fresh";
|
|
7313
|
+
} else {
|
|
7314
|
+
freshness = "stale";
|
|
7315
|
+
}
|
|
7316
|
+
}
|
|
7317
|
+
console.log(
|
|
7318
|
+
" " + modPath.padEnd(38) + (hasMap ? "yes" : "no").padEnd(8) + (stamped ? "yes" : "no").padEnd(12) + freshness
|
|
7319
|
+
);
|
|
7320
|
+
}
|
|
7321
|
+
console.log();
|
|
7322
|
+
} catch (err) {
|
|
7323
|
+
console.warn(
|
|
7324
|
+
` Warning: arch-map status error: ${err instanceof Error ? err.message : String(err)}`
|
|
7325
|
+
);
|
|
7326
|
+
}
|
|
7327
|
+
}
|
|
7328
|
+
async function runDrift(projectRoot) {
|
|
7329
|
+
console.log("\n CodeByPlan arch-map drift\n");
|
|
7330
|
+
try {
|
|
7331
|
+
const codebyplanDir = await resolveCodebyplanDir(projectRoot);
|
|
7332
|
+
if (!codebyplanDir) {
|
|
7333
|
+
console.log(" No .codebyplan/ directory found \u2014 no manifest to check.");
|
|
7334
|
+
console.log();
|
|
7335
|
+
return;
|
|
7336
|
+
}
|
|
7337
|
+
const repoRoot = repoRootFromCodebyplanDir(codebyplanDir);
|
|
7338
|
+
const config = await readArchitectureConfig(codebyplanDir);
|
|
7339
|
+
const stamped = config.modules.filter((e) => e.generated_from_sha != null);
|
|
7340
|
+
if (stamped.length === 0) {
|
|
7341
|
+
console.log(" No stamped modules found \u2014 run arch-map stamp first.");
|
|
7342
|
+
console.log();
|
|
7343
|
+
return;
|
|
7344
|
+
}
|
|
7345
|
+
let driftCount = 0;
|
|
7346
|
+
for (const entry of stamped) {
|
|
7347
|
+
const currentSha = resolveGitSha(entry.path, repoRoot);
|
|
7348
|
+
if (currentSha == null) {
|
|
7349
|
+
console.log(
|
|
7350
|
+
` ? ${entry.path} \u2014 could not resolve current SHA (git unavailable or path not tracked)`
|
|
7351
|
+
);
|
|
7352
|
+
continue;
|
|
7353
|
+
}
|
|
7354
|
+
if (currentSha !== entry.generated_from_sha) {
|
|
7355
|
+
console.log(` DRIFTED ${entry.path}`);
|
|
7356
|
+
console.log(` stamped: ${entry.generated_from_sha}`);
|
|
7357
|
+
console.log(` current: ${currentSha}`);
|
|
7358
|
+
driftCount++;
|
|
7359
|
+
}
|
|
7360
|
+
}
|
|
7361
|
+
if (driftCount === 0) {
|
|
7362
|
+
console.log(" All stamped modules are fresh.");
|
|
7363
|
+
} else {
|
|
7364
|
+
console.log(`
|
|
7365
|
+
${driftCount} module(s) have drifted since last stamp.`);
|
|
7366
|
+
}
|
|
7367
|
+
console.log();
|
|
7368
|
+
} catch (err) {
|
|
7369
|
+
console.warn(
|
|
7370
|
+
` Warning: arch-map drift error: ${err instanceof Error ? err.message : String(err)}`
|
|
7371
|
+
);
|
|
7372
|
+
}
|
|
7373
|
+
}
|
|
7374
|
+
function updateFrontmatterFields(content, fields) {
|
|
7375
|
+
const lines = content.split("\n");
|
|
7376
|
+
if (lines.length === 0 || lines[0] !== "---") {
|
|
7377
|
+
return null;
|
|
7378
|
+
}
|
|
7379
|
+
let closeIndex = -1;
|
|
7380
|
+
for (let i = 1; i < lines.length; i++) {
|
|
7381
|
+
if (lines[i] === "---") {
|
|
7382
|
+
closeIndex = i;
|
|
7383
|
+
break;
|
|
7384
|
+
}
|
|
7385
|
+
}
|
|
7386
|
+
if (closeIndex === -1) {
|
|
7387
|
+
return null;
|
|
7388
|
+
}
|
|
7389
|
+
const result = lines.map((line, idx) => {
|
|
7390
|
+
if (idx === 0 || idx >= closeIndex) {
|
|
7391
|
+
return line;
|
|
7392
|
+
}
|
|
7393
|
+
if (/^generated_from_sha:\s*/.test(line)) {
|
|
7394
|
+
return `generated_from_sha: ${fields.generated_from_sha}`;
|
|
7395
|
+
}
|
|
7396
|
+
if (/^generated_at:\s*/.test(line)) {
|
|
7397
|
+
return `generated_at: ${fields.generated_at}`;
|
|
7398
|
+
}
|
|
7399
|
+
if (fields.depth !== void 0 && /^depth:\s*/.test(line)) {
|
|
7400
|
+
return `depth: ${fields.depth}`;
|
|
7401
|
+
}
|
|
7402
|
+
return line;
|
|
7403
|
+
});
|
|
7404
|
+
return result.join("\n");
|
|
7405
|
+
}
|
|
7406
|
+
async function runStamp(modulePath, sha, depthArg, projectRoot) {
|
|
7407
|
+
const codebyplanDir = await resolveCodebyplanDir(projectRoot);
|
|
7408
|
+
if (!codebyplanDir) {
|
|
7409
|
+
process.stderr.write(
|
|
7410
|
+
" Error: no .codebyplan/ directory found. Run `codebyplan setup` first.\n"
|
|
7411
|
+
);
|
|
7412
|
+
process.exit(1);
|
|
7413
|
+
}
|
|
7414
|
+
const repoRoot = repoRootFromCodebyplanDir(codebyplanDir);
|
|
7415
|
+
let resolvedSha = sha;
|
|
7416
|
+
if (!resolvedSha) {
|
|
7417
|
+
resolvedSha = resolveGitSha(modulePath, repoRoot);
|
|
7418
|
+
if (!resolvedSha) {
|
|
7419
|
+
process.stderr.write(
|
|
7420
|
+
` Error: could not resolve SHA for ${modulePath}. Provide --sha <value>.
|
|
7421
|
+
`
|
|
7422
|
+
);
|
|
7423
|
+
process.exit(1);
|
|
7424
|
+
}
|
|
7425
|
+
}
|
|
7426
|
+
const config = await readArchitectureConfig(codebyplanDir);
|
|
7427
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7428
|
+
const mapFile = mapFileSlug(modulePath);
|
|
7429
|
+
const mapFilePath = `.claude/architecture/${mapFile}`;
|
|
7430
|
+
const existingIndex = config.modules.findIndex((e) => e.path === modulePath);
|
|
7431
|
+
if (existingIndex >= 0) {
|
|
7432
|
+
config.modules[existingIndex] = {
|
|
7433
|
+
...config.modules[existingIndex],
|
|
7434
|
+
map_file: mapFilePath,
|
|
7435
|
+
generated_from_sha: resolvedSha,
|
|
7436
|
+
generated_at: now,
|
|
7437
|
+
...depthArg !== null ? { depth: depthArg } : {}
|
|
7438
|
+
};
|
|
7439
|
+
} else {
|
|
7440
|
+
config.modules.push({
|
|
7441
|
+
path: modulePath,
|
|
7442
|
+
map_file: mapFilePath,
|
|
7443
|
+
generated_from_sha: resolvedSha,
|
|
7444
|
+
depth: depthArg ?? "skeleton",
|
|
7445
|
+
generated_at: now
|
|
7446
|
+
});
|
|
7447
|
+
}
|
|
7448
|
+
await writeArchitectureConfig(codebyplanDir, config);
|
|
7449
|
+
const stampedEntry = existingIndex >= 0 ? config.modules[existingIndex] : config.modules[config.modules.length - 1];
|
|
7450
|
+
const mapAbsPath = join23(repoRoot, stampedEntry.map_file);
|
|
7451
|
+
let mapContent = null;
|
|
7452
|
+
try {
|
|
7453
|
+
mapContent = await readFile17(mapAbsPath, "utf-8");
|
|
7454
|
+
} catch {
|
|
7455
|
+
console.warn(
|
|
7456
|
+
" Warning: map file " + stampedEntry.map_file + " not found \u2014 stamped manifest only"
|
|
7457
|
+
);
|
|
7458
|
+
}
|
|
7459
|
+
if (mapContent !== null) {
|
|
7460
|
+
const updated = updateFrontmatterFields(mapContent, {
|
|
7461
|
+
generated_from_sha: resolvedSha,
|
|
7462
|
+
generated_at: now,
|
|
7463
|
+
...depthArg !== null ? { depth: depthArg } : {}
|
|
7464
|
+
});
|
|
7465
|
+
if (updated === null) {
|
|
7466
|
+
console.warn(
|
|
7467
|
+
" Warning: no frontmatter block in " + stampedEntry.map_file + " \u2014 stamped manifest only"
|
|
7468
|
+
);
|
|
7469
|
+
} else if (!updated.includes(`generated_from_sha: ${resolvedSha}`) || !updated.includes(`generated_at: ${now}`)) {
|
|
7470
|
+
console.warn(
|
|
7471
|
+
" Warning: " + stampedEntry.map_file + " frontmatter missing generated_from_sha/generated_at \u2014 not mirrored (manifest stamped)"
|
|
7472
|
+
);
|
|
7473
|
+
} else {
|
|
7474
|
+
try {
|
|
7475
|
+
await writeFile13(mapAbsPath, updated, "utf-8");
|
|
7476
|
+
} catch (writeErr) {
|
|
7477
|
+
console.warn(
|
|
7478
|
+
" Warning: could not write map file " + stampedEntry.map_file + " \u2014 " + (writeErr instanceof Error ? writeErr.message : String(writeErr)) + " \u2014 stamped manifest only"
|
|
7479
|
+
);
|
|
7480
|
+
}
|
|
7481
|
+
}
|
|
7482
|
+
}
|
|
7483
|
+
console.log(` Stamped ${modulePath} @ ${resolvedSha.slice(0, 8)} (${now})`);
|
|
7484
|
+
}
|
|
7485
|
+
async function runArchMapCommand(rest) {
|
|
7486
|
+
const subcommand = rest[0];
|
|
7487
|
+
const projectRoot = process.cwd();
|
|
7488
|
+
if (subcommand === "status") {
|
|
7489
|
+
await runStatus(projectRoot);
|
|
7490
|
+
return;
|
|
7491
|
+
}
|
|
7492
|
+
if (subcommand === "drift") {
|
|
7493
|
+
await runDrift(projectRoot);
|
|
7494
|
+
return;
|
|
7495
|
+
}
|
|
7496
|
+
if (subcommand === "stamp") {
|
|
7497
|
+
const rawModulePath = rest[1];
|
|
7498
|
+
if (!rawModulePath) {
|
|
7499
|
+
process.stderr.write(
|
|
7500
|
+
" Usage: codebyplan arch-map stamp <module> [--sha <value>]\n"
|
|
7501
|
+
);
|
|
7502
|
+
process.exit(1);
|
|
7503
|
+
}
|
|
7504
|
+
if (rawModulePath.startsWith("/")) {
|
|
7505
|
+
process.stderr.write(
|
|
7506
|
+
" Error: module path must be relative to the repo root (e.g. apps/web), not absolute.\n"
|
|
7507
|
+
);
|
|
7508
|
+
process.exit(1);
|
|
7509
|
+
}
|
|
7510
|
+
const modulePath = normalizeModulePath(rawModulePath);
|
|
7511
|
+
if (modulePath.split("/").length > 2) {
|
|
7512
|
+
console.warn(
|
|
7513
|
+
` Warning: ${modulePath} has more than 2 path segments; expected a top-level module path (e.g. apps/web).`
|
|
7514
|
+
);
|
|
7515
|
+
}
|
|
7516
|
+
let sha = null;
|
|
7517
|
+
const shaIdx = rest.indexOf("--sha");
|
|
7518
|
+
if (shaIdx !== -1) {
|
|
7519
|
+
const shaVal = rest[shaIdx + 1];
|
|
7520
|
+
if (!shaVal || shaVal.startsWith("--")) {
|
|
7521
|
+
process.stderr.write(" Error: --sha requires a value.\n");
|
|
7522
|
+
process.exit(1);
|
|
7523
|
+
}
|
|
7524
|
+
if (!/^[0-9a-f]{40}$/i.test(shaVal)) {
|
|
7525
|
+
process.stderr.write(
|
|
7526
|
+
" Error: --sha value does not look like a git SHA (expected 40 hex chars).\n"
|
|
7527
|
+
);
|
|
7528
|
+
process.exit(1);
|
|
7529
|
+
}
|
|
7530
|
+
sha = shaVal;
|
|
7531
|
+
}
|
|
7532
|
+
let depthArg = null;
|
|
7533
|
+
const depthIdx = rest.indexOf("--depth");
|
|
7534
|
+
if (depthIdx !== -1) {
|
|
7535
|
+
const depthVal = rest[depthIdx + 1];
|
|
7536
|
+
if (!depthVal || depthVal.startsWith("--")) {
|
|
7537
|
+
process.stderr.write(" Error: --depth requires a value.\n");
|
|
7538
|
+
process.exit(1);
|
|
7539
|
+
}
|
|
7540
|
+
if (depthVal !== "skeleton" && depthVal !== "deep") {
|
|
7541
|
+
process.stderr.write(" Error: --depth must be skeleton or deep.\n");
|
|
7542
|
+
process.exit(1);
|
|
7543
|
+
}
|
|
7544
|
+
depthArg = depthVal;
|
|
7545
|
+
}
|
|
7546
|
+
await runStamp(modulePath, sha, depthArg, projectRoot);
|
|
7547
|
+
return;
|
|
7548
|
+
}
|
|
7549
|
+
console.log(`
|
|
7550
|
+
codebyplan arch-map \u2014 Architecture map pipeline
|
|
7551
|
+
|
|
7552
|
+
Note: arch-map commands are intended to run from the repo root.
|
|
7553
|
+
|
|
7554
|
+
Usage:
|
|
7555
|
+
codebyplan arch-map status List all modules and map freshness
|
|
7556
|
+
codebyplan arch-map drift Report modules drifted since last stamp
|
|
7557
|
+
codebyplan arch-map stamp <module> Stamp a module with its current git SHA
|
|
7558
|
+
codebyplan arch-map stamp <module> --sha <sha> Stamp with an explicit SHA
|
|
7559
|
+
codebyplan arch-map stamp <module> --depth <skeleton|deep> Stamp with an explicit depth
|
|
7560
|
+
`);
|
|
7561
|
+
}
|
|
7562
|
+
var init_arch_map = __esm({
|
|
7563
|
+
"src/cli/arch-map.ts"() {
|
|
7564
|
+
"use strict";
|
|
7565
|
+
init_flags();
|
|
7566
|
+
}
|
|
7567
|
+
});
|
|
7568
|
+
|
|
7145
7569
|
// src/lib/worktree-port-resolver.ts
|
|
7146
7570
|
async function resolveWorktreePortAllocations(repoId, projectPath) {
|
|
7147
7571
|
let resolvedWorktreeId;
|
|
@@ -7231,19 +7655,19 @@ var init_worktree_port_resolver = __esm({
|
|
|
7231
7655
|
});
|
|
7232
7656
|
|
|
7233
7657
|
// src/lib/migrate-local-config.ts
|
|
7234
|
-
import { mkdir as mkdir7, readFile as
|
|
7235
|
-
import { join as
|
|
7658
|
+
import { mkdir as mkdir7, readFile as readFile18, unlink as unlink3, writeFile as writeFile14 } from "node:fs/promises";
|
|
7659
|
+
import { join as join24 } from "node:path";
|
|
7236
7660
|
function legacySharedPath(projectPath) {
|
|
7237
|
-
return
|
|
7661
|
+
return join24(projectPath, ".codebyplan.json");
|
|
7238
7662
|
}
|
|
7239
7663
|
function legacyLocalPath(projectPath) {
|
|
7240
|
-
return
|
|
7664
|
+
return join24(projectPath, ".codebyplan.local.json");
|
|
7241
7665
|
}
|
|
7242
7666
|
function newDirPath(projectPath) {
|
|
7243
|
-
return
|
|
7667
|
+
return join24(projectPath, ".codebyplan");
|
|
7244
7668
|
}
|
|
7245
7669
|
function sentinelPath(projectPath) {
|
|
7246
|
-
return
|
|
7670
|
+
return join24(projectPath, ".codebyplan", "repo.json");
|
|
7247
7671
|
}
|
|
7248
7672
|
async function statSafe(p) {
|
|
7249
7673
|
const { stat: stat2 } = await import("node:fs/promises");
|
|
@@ -7282,7 +7706,7 @@ async function runLocalMigration(projectPath) {
|
|
|
7282
7706
|
}
|
|
7283
7707
|
let legacyRaw;
|
|
7284
7708
|
try {
|
|
7285
|
-
legacyRaw = await
|
|
7709
|
+
legacyRaw = await readFile18(legacySharedPath(projectPath), "utf-8");
|
|
7286
7710
|
} catch {
|
|
7287
7711
|
return {
|
|
7288
7712
|
migrated: true,
|
|
@@ -7309,7 +7733,7 @@ async function runLocalMigration(projectPath) {
|
|
|
7309
7733
|
let deviceId;
|
|
7310
7734
|
let deviceWrittenByHelper = false;
|
|
7311
7735
|
try {
|
|
7312
|
-
const localRaw = await
|
|
7736
|
+
const localRaw = await readFile18(legacyLocalPath(projectPath), "utf-8");
|
|
7313
7737
|
const localParsed = JSON.parse(localRaw);
|
|
7314
7738
|
if (typeof localParsed.device_id === "string") {
|
|
7315
7739
|
deviceId = localParsed.device_id;
|
|
@@ -7336,8 +7760,8 @@ async function runLocalMigration(projectPath) {
|
|
|
7336
7760
|
if ("repo_id" in cfg) repoJson.repo_id = cfg.repo_id;
|
|
7337
7761
|
if ("organization_id" in cfg) repoJson.organization_id = cfg.organization_id;
|
|
7338
7762
|
if ("project_id" in cfg) repoJson.project_id = cfg.project_id;
|
|
7339
|
-
await
|
|
7340
|
-
|
|
7763
|
+
await writeFile14(
|
|
7764
|
+
join24(projectPath, ".codebyplan", "repo.json"),
|
|
7341
7765
|
JSON.stringify(repoJson, null, 2) + "\n",
|
|
7342
7766
|
"utf-8"
|
|
7343
7767
|
);
|
|
@@ -7349,8 +7773,8 @@ async function runLocalMigration(projectPath) {
|
|
|
7349
7773
|
serverJson.auto_push_enabled = cfg.auto_push_enabled;
|
|
7350
7774
|
if ("port_allocations" in cfg)
|
|
7351
7775
|
serverJson.port_allocations = cfg.port_allocations;
|
|
7352
|
-
await
|
|
7353
|
-
|
|
7776
|
+
await writeFile14(
|
|
7777
|
+
join24(projectPath, ".codebyplan", "server.json"),
|
|
7354
7778
|
JSON.stringify(serverJson, null, 2) + "\n",
|
|
7355
7779
|
"utf-8"
|
|
7356
7780
|
);
|
|
@@ -7358,44 +7782,44 @@ async function runLocalMigration(projectPath) {
|
|
|
7358
7782
|
const gitJson = {};
|
|
7359
7783
|
if ("git_branch" in cfg) gitJson.git_branch = cfg.git_branch;
|
|
7360
7784
|
if ("branch_config" in cfg) gitJson.branch_config = cfg.branch_config;
|
|
7361
|
-
await
|
|
7362
|
-
|
|
7785
|
+
await writeFile14(
|
|
7786
|
+
join24(projectPath, ".codebyplan", "git.json"),
|
|
7363
7787
|
JSON.stringify(gitJson, null, 2) + "\n",
|
|
7364
7788
|
"utf-8"
|
|
7365
7789
|
);
|
|
7366
7790
|
filesChanged.push(".codebyplan/git.json");
|
|
7367
7791
|
const shipmentJson = {};
|
|
7368
7792
|
if ("shipment" in cfg) shipmentJson.shipment = cfg.shipment;
|
|
7369
|
-
await
|
|
7370
|
-
|
|
7793
|
+
await writeFile14(
|
|
7794
|
+
join24(projectPath, ".codebyplan", "shipment.json"),
|
|
7371
7795
|
JSON.stringify(shipmentJson, null, 2) + "\n",
|
|
7372
7796
|
"utf-8"
|
|
7373
7797
|
);
|
|
7374
7798
|
filesChanged.push(".codebyplan/shipment.json");
|
|
7375
7799
|
const vendorJson = {};
|
|
7376
|
-
await
|
|
7377
|
-
|
|
7800
|
+
await writeFile14(
|
|
7801
|
+
join24(projectPath, ".codebyplan", "vendor.json"),
|
|
7378
7802
|
JSON.stringify(vendorJson, null, 2) + "\n",
|
|
7379
7803
|
"utf-8"
|
|
7380
7804
|
);
|
|
7381
7805
|
filesChanged.push(".codebyplan/vendor.json");
|
|
7382
7806
|
const e2eJson = {};
|
|
7383
|
-
await
|
|
7384
|
-
|
|
7807
|
+
await writeFile14(
|
|
7808
|
+
join24(projectPath, ".codebyplan", "e2e.json"),
|
|
7385
7809
|
JSON.stringify(e2eJson, null, 2) + "\n",
|
|
7386
7810
|
"utf-8"
|
|
7387
7811
|
);
|
|
7388
7812
|
filesChanged.push(".codebyplan/e2e.json");
|
|
7389
7813
|
const eslintJson = {};
|
|
7390
|
-
await
|
|
7391
|
-
|
|
7814
|
+
await writeFile14(
|
|
7815
|
+
join24(projectPath, ".codebyplan", "eslint.json"),
|
|
7392
7816
|
JSON.stringify(eslintJson, null, 2) + "\n",
|
|
7393
7817
|
"utf-8"
|
|
7394
7818
|
);
|
|
7395
7819
|
filesChanged.push(".codebyplan/eslint.json");
|
|
7396
7820
|
if (!deviceWrittenByHelper) {
|
|
7397
|
-
await
|
|
7398
|
-
|
|
7821
|
+
await writeFile14(
|
|
7822
|
+
join24(projectPath, ".codebyplan", "device.local.json"),
|
|
7399
7823
|
JSON.stringify({ device_id: deviceId }, null, 2) + "\n",
|
|
7400
7824
|
"utf-8"
|
|
7401
7825
|
);
|
|
@@ -7407,9 +7831,9 @@ async function runLocalMigration(projectPath) {
|
|
|
7407
7831
|
"Migration write incomplete: .codebyplan/repo.json was not persisted. Re-run migration to retry from a clean state."
|
|
7408
7832
|
);
|
|
7409
7833
|
}
|
|
7410
|
-
const gitignorePath =
|
|
7834
|
+
const gitignorePath = join24(projectPath, ".gitignore");
|
|
7411
7835
|
try {
|
|
7412
|
-
const gitignoreContent = await
|
|
7836
|
+
const gitignoreContent = await readFile18(gitignorePath, "utf-8");
|
|
7413
7837
|
const legacyLine = ".codebyplan.local.json";
|
|
7414
7838
|
const newLine = ".codebyplan/device.local.json";
|
|
7415
7839
|
const hasLegacy = gitignoreContent.split("\n").some((l) => l.trimEnd() === legacyLine);
|
|
@@ -7428,7 +7852,7 @@ async function runLocalMigration(projectPath) {
|
|
|
7428
7852
|
updated = gitignoreContent;
|
|
7429
7853
|
}
|
|
7430
7854
|
if (updated !== gitignoreContent) {
|
|
7431
|
-
await
|
|
7855
|
+
await writeFile14(gitignorePath, updated, "utf-8");
|
|
7432
7856
|
filesChanged.push(".gitignore");
|
|
7433
7857
|
}
|
|
7434
7858
|
} catch {
|
|
@@ -7469,8 +7893,8 @@ __export(config_exports, {
|
|
|
7469
7893
|
readVendorConfig: () => readVendorConfig,
|
|
7470
7894
|
runConfig: () => runConfig
|
|
7471
7895
|
});
|
|
7472
|
-
import { mkdir as mkdir8, readFile as
|
|
7473
|
-
import { join as
|
|
7896
|
+
import { mkdir as mkdir8, readFile as readFile19, writeFile as writeFile15 } from "node:fs/promises";
|
|
7897
|
+
import { join as join25 } from "node:path";
|
|
7474
7898
|
async function runConfig() {
|
|
7475
7899
|
const flags = parseFlags(3);
|
|
7476
7900
|
const dryRun = hasFlag("dry-run", 3);
|
|
@@ -7503,7 +7927,7 @@ async function runConfig() {
|
|
|
7503
7927
|
console.log("\n Config complete.\n");
|
|
7504
7928
|
}
|
|
7505
7929
|
async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
7506
|
-
const codebyplanDir =
|
|
7930
|
+
const codebyplanDir = join25(projectPath, ".codebyplan");
|
|
7507
7931
|
const {
|
|
7508
7932
|
resolvedWorktreeId,
|
|
7509
7933
|
portAllocations,
|
|
@@ -7571,6 +7995,10 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
7571
7995
|
const vendorPayload = {};
|
|
7572
7996
|
const e2ePayload = {};
|
|
7573
7997
|
const eslintPayload = {};
|
|
7998
|
+
const architecturePayload = {
|
|
7999
|
+
version: 1,
|
|
8000
|
+
modules: []
|
|
8001
|
+
};
|
|
7574
8002
|
if (dryRun) {
|
|
7575
8003
|
console.log(" Config would be updated (dry-run).");
|
|
7576
8004
|
return;
|
|
@@ -7583,20 +8011,25 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
7583
8011
|
{ name: "shipment.json", payload: shipmentPayload },
|
|
7584
8012
|
{ name: "vendor.json", payload: vendorPayload },
|
|
7585
8013
|
{ name: "e2e.json", payload: e2ePayload, createOnly: true },
|
|
7586
|
-
{ name: "eslint.json", payload: eslintPayload, createOnly: true }
|
|
8014
|
+
{ name: "eslint.json", payload: eslintPayload, createOnly: true },
|
|
8015
|
+
{
|
|
8016
|
+
name: "architecture.json",
|
|
8017
|
+
payload: architecturePayload,
|
|
8018
|
+
createOnly: true
|
|
8019
|
+
}
|
|
7587
8020
|
];
|
|
7588
8021
|
let anyUpdated = false;
|
|
7589
8022
|
for (const { name, payload, createOnly } of files) {
|
|
7590
|
-
const filePath =
|
|
8023
|
+
const filePath = join25(codebyplanDir, name);
|
|
7591
8024
|
const newJson = JSON.stringify(payload, null, 2) + "\n";
|
|
7592
8025
|
let currentJson = "";
|
|
7593
8026
|
try {
|
|
7594
|
-
currentJson = await
|
|
8027
|
+
currentJson = await readFile19(filePath, "utf-8");
|
|
7595
8028
|
} catch {
|
|
7596
8029
|
}
|
|
7597
8030
|
if (createOnly && currentJson !== "") continue;
|
|
7598
8031
|
if (currentJson === newJson) continue;
|
|
7599
|
-
await
|
|
8032
|
+
await writeFile15(filePath, newJson, "utf-8");
|
|
7600
8033
|
console.log(` Updated .codebyplan/${name}`);
|
|
7601
8034
|
anyUpdated = true;
|
|
7602
8035
|
}
|
|
@@ -7606,8 +8039,8 @@ async function syncConfigToFile(repoId, projectPath, dryRun) {
|
|
|
7606
8039
|
}
|
|
7607
8040
|
async function readRepoConfig(projectPath) {
|
|
7608
8041
|
try {
|
|
7609
|
-
const raw = await
|
|
7610
|
-
|
|
8042
|
+
const raw = await readFile19(
|
|
8043
|
+
join25(projectPath, ".codebyplan", "repo.json"),
|
|
7611
8044
|
"utf-8"
|
|
7612
8045
|
);
|
|
7613
8046
|
return JSON.parse(raw);
|
|
@@ -7617,8 +8050,8 @@ async function readRepoConfig(projectPath) {
|
|
|
7617
8050
|
}
|
|
7618
8051
|
async function readServerConfig(projectPath) {
|
|
7619
8052
|
try {
|
|
7620
|
-
const raw = await
|
|
7621
|
-
|
|
8053
|
+
const raw = await readFile19(
|
|
8054
|
+
join25(projectPath, ".codebyplan", "server.json"),
|
|
7622
8055
|
"utf-8"
|
|
7623
8056
|
);
|
|
7624
8057
|
return JSON.parse(raw);
|
|
@@ -7628,8 +8061,8 @@ async function readServerConfig(projectPath) {
|
|
|
7628
8061
|
}
|
|
7629
8062
|
async function readGitConfig(projectPath) {
|
|
7630
8063
|
try {
|
|
7631
|
-
const raw = await
|
|
7632
|
-
|
|
8064
|
+
const raw = await readFile19(
|
|
8065
|
+
join25(projectPath, ".codebyplan", "git.json"),
|
|
7633
8066
|
"utf-8"
|
|
7634
8067
|
);
|
|
7635
8068
|
return JSON.parse(raw);
|
|
@@ -7639,8 +8072,8 @@ async function readGitConfig(projectPath) {
|
|
|
7639
8072
|
}
|
|
7640
8073
|
async function readShipmentConfig(projectPath) {
|
|
7641
8074
|
try {
|
|
7642
|
-
const raw = await
|
|
7643
|
-
|
|
8075
|
+
const raw = await readFile19(
|
|
8076
|
+
join25(projectPath, ".codebyplan", "shipment.json"),
|
|
7644
8077
|
"utf-8"
|
|
7645
8078
|
);
|
|
7646
8079
|
return JSON.parse(raw);
|
|
@@ -7650,8 +8083,8 @@ async function readShipmentConfig(projectPath) {
|
|
|
7650
8083
|
}
|
|
7651
8084
|
async function readVendorConfig(projectPath) {
|
|
7652
8085
|
try {
|
|
7653
|
-
const raw = await
|
|
7654
|
-
|
|
8086
|
+
const raw = await readFile19(
|
|
8087
|
+
join25(projectPath, ".codebyplan", "vendor.json"),
|
|
7655
8088
|
"utf-8"
|
|
7656
8089
|
);
|
|
7657
8090
|
return JSON.parse(raw);
|
|
@@ -7661,8 +8094,8 @@ async function readVendorConfig(projectPath) {
|
|
|
7661
8094
|
}
|
|
7662
8095
|
async function readE2eConfig2(projectPath) {
|
|
7663
8096
|
try {
|
|
7664
|
-
const raw = await
|
|
7665
|
-
|
|
8097
|
+
const raw = await readFile19(
|
|
8098
|
+
join25(projectPath, ".codebyplan", "e2e.json"),
|
|
7666
8099
|
"utf-8"
|
|
7667
8100
|
);
|
|
7668
8101
|
return JSON.parse(raw);
|
|
@@ -7672,8 +8105,8 @@ async function readE2eConfig2(projectPath) {
|
|
|
7672
8105
|
}
|
|
7673
8106
|
async function readServerLocalConfig(projectPath) {
|
|
7674
8107
|
try {
|
|
7675
|
-
const raw = await
|
|
7676
|
-
|
|
8108
|
+
const raw = await readFile19(
|
|
8109
|
+
join25(projectPath, ".codebyplan", "server.local.json"),
|
|
7677
8110
|
"utf-8"
|
|
7678
8111
|
);
|
|
7679
8112
|
return JSON.parse(raw);
|
|
@@ -7728,14 +8161,14 @@ var init_server_detect = __esm({
|
|
|
7728
8161
|
});
|
|
7729
8162
|
|
|
7730
8163
|
// src/lib/port-verify.ts
|
|
7731
|
-
import { readFile as
|
|
8164
|
+
import { readFile as readFile20 } from "node:fs/promises";
|
|
7732
8165
|
async function verifyPorts(projectPath, portAllocations) {
|
|
7733
8166
|
const mismatches = [];
|
|
7734
8167
|
const allocatedPorts = new Set(portAllocations.map((a) => a.port));
|
|
7735
8168
|
const packageJsonPaths = await findPackageJsonFiles(projectPath, projectPath);
|
|
7736
8169
|
for (const pkgPath of packageJsonPaths) {
|
|
7737
8170
|
try {
|
|
7738
|
-
const raw = await
|
|
8171
|
+
const raw = await readFile20(pkgPath, "utf-8");
|
|
7739
8172
|
const pkg = JSON.parse(raw);
|
|
7740
8173
|
const scriptPort = detectPortFromScripts(pkg);
|
|
7741
8174
|
if (scriptPort !== null && !allocatedPorts.has(scriptPort)) {
|
|
@@ -7798,7 +8231,7 @@ async function findUnallocatedApps(projectPath, portAllocations) {
|
|
|
7798
8231
|
}
|
|
7799
8232
|
let pkg;
|
|
7800
8233
|
try {
|
|
7801
|
-
const raw = await
|
|
8234
|
+
const raw = await readFile20(`${app.absPath}/package.json`, "utf-8");
|
|
7802
8235
|
pkg = JSON.parse(raw);
|
|
7803
8236
|
} catch {
|
|
7804
8237
|
continue;
|
|
@@ -7848,8 +8281,8 @@ __export(ports_exports, {
|
|
|
7848
8281
|
parseEnvFile: () => parseEnvFile,
|
|
7849
8282
|
runPorts: () => runPorts
|
|
7850
8283
|
});
|
|
7851
|
-
import { mkdir as mkdir9, readFile as
|
|
7852
|
-
import { join as
|
|
8284
|
+
import { mkdir as mkdir9, readFile as readFile21, writeFile as writeFile16 } from "node:fs/promises";
|
|
8285
|
+
import { join as join26 } from "node:path";
|
|
7853
8286
|
async function runPorts() {
|
|
7854
8287
|
const flags = parseFlags(3);
|
|
7855
8288
|
const dryRun = hasFlag("dry-run", 3);
|
|
@@ -7970,12 +8403,12 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
|
|
|
7970
8403
|
// and ServerLocalConfig.port_allocations is typed the same — honest end-to-end.
|
|
7971
8404
|
port_allocations: portAllocations
|
|
7972
8405
|
};
|
|
7973
|
-
const codebyplanDir =
|
|
7974
|
-
const filePath =
|
|
8406
|
+
const codebyplanDir = join26(projectPath, ".codebyplan");
|
|
8407
|
+
const filePath = join26(codebyplanDir, "server.local.json");
|
|
7975
8408
|
const newJson = JSON.stringify(payload, null, 2) + "\n";
|
|
7976
8409
|
let currentJson = "";
|
|
7977
8410
|
try {
|
|
7978
|
-
currentJson = await
|
|
8411
|
+
currentJson = await readFile21(filePath, "utf-8");
|
|
7979
8412
|
} catch {
|
|
7980
8413
|
}
|
|
7981
8414
|
if (currentJson === newJson) {
|
|
@@ -7987,17 +8420,17 @@ async function writeServerLocalConfig(repoId, projectPath, dryRun) {
|
|
|
7987
8420
|
return;
|
|
7988
8421
|
}
|
|
7989
8422
|
await mkdir9(codebyplanDir, { recursive: true });
|
|
7990
|
-
await
|
|
8423
|
+
await writeFile16(filePath, newJson, "utf-8");
|
|
7991
8424
|
console.log(
|
|
7992
8425
|
` Updated .codebyplan/server.local.json (worktree ${resolvedWorktreeId ?? "\u2014"}, ${portAllocations.length} allocation${portAllocations.length === 1 ? "" : "s"}).`
|
|
7993
8426
|
);
|
|
7994
8427
|
}
|
|
7995
8428
|
async function provisionE2eEnv(projectPath, dryRun) {
|
|
7996
|
-
const relSource =
|
|
7997
|
-
const sourcePath =
|
|
8429
|
+
const relSource = join26("apps", "web", ".env.local");
|
|
8430
|
+
const sourcePath = join26(projectPath, relSource);
|
|
7998
8431
|
let sourceRaw;
|
|
7999
8432
|
try {
|
|
8000
|
-
sourceRaw = await
|
|
8433
|
+
sourceRaw = await readFile21(sourcePath, "utf-8");
|
|
8001
8434
|
} catch {
|
|
8002
8435
|
console.warn(
|
|
8003
8436
|
` Skipped .codebyplan/e2e.env \u2014 source ${relSource} not found.`
|
|
@@ -8026,12 +8459,12 @@ async function provisionE2eEnv(projectPath, dryRun) {
|
|
|
8026
8459
|
);
|
|
8027
8460
|
return;
|
|
8028
8461
|
}
|
|
8029
|
-
const codebyplanDir =
|
|
8030
|
-
const filePath =
|
|
8462
|
+
const codebyplanDir = join26(projectPath, ".codebyplan");
|
|
8463
|
+
const filePath = join26(codebyplanDir, "e2e.env");
|
|
8031
8464
|
const newContent = lines.join("\n") + "\n";
|
|
8032
8465
|
let currentContent = "";
|
|
8033
8466
|
try {
|
|
8034
|
-
currentContent = await
|
|
8467
|
+
currentContent = await readFile21(filePath, "utf-8");
|
|
8035
8468
|
} catch {
|
|
8036
8469
|
}
|
|
8037
8470
|
if (currentContent === newContent) {
|
|
@@ -8043,7 +8476,7 @@ async function provisionE2eEnv(projectPath, dryRun) {
|
|
|
8043
8476
|
return;
|
|
8044
8477
|
}
|
|
8045
8478
|
await mkdir9(codebyplanDir, { recursive: true });
|
|
8046
|
-
await
|
|
8479
|
+
await writeFile16(filePath, newContent, "utf-8");
|
|
8047
8480
|
console.log(
|
|
8048
8481
|
` Provisioned .codebyplan/e2e.env (${lines.length} var${lines.length === 1 ? "" : "s"}).`
|
|
8049
8482
|
);
|
|
@@ -8093,7 +8526,7 @@ __export(tech_stack_exports, {
|
|
|
8093
8526
|
runFullTechStack: () => runFullTechStack,
|
|
8094
8527
|
runTechStack: () => runTechStack
|
|
8095
8528
|
});
|
|
8096
|
-
import { existsSync as
|
|
8529
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
8097
8530
|
async function runTechStack() {
|
|
8098
8531
|
const flags = parseFlags(3);
|
|
8099
8532
|
const dryRun = hasFlag("dry-run", 3);
|
|
@@ -8266,7 +8699,7 @@ async function runFullTechStack(dryRun) {
|
|
|
8266
8699
|
continue;
|
|
8267
8700
|
}
|
|
8268
8701
|
const localWorktrees = worktrees.filter(
|
|
8269
|
-
(wt) => wt.path ?
|
|
8702
|
+
(wt) => wt.path ? existsSync6(wt.path) : false
|
|
8270
8703
|
);
|
|
8271
8704
|
if (localWorktrees.length === 0) {
|
|
8272
8705
|
console.log(` skipping ${repo.name} \u2014 no local worktree on this device`);
|
|
@@ -8366,7 +8799,7 @@ var init_claude_plan = __esm({
|
|
|
8366
8799
|
// src/cli/claude/status.ts
|
|
8367
8800
|
var status_exports = {};
|
|
8368
8801
|
__export(status_exports, {
|
|
8369
|
-
runStatus: () =>
|
|
8802
|
+
runStatus: () => runStatus2
|
|
8370
8803
|
});
|
|
8371
8804
|
import * as fs6 from "node:fs";
|
|
8372
8805
|
import * as path7 from "node:path";
|
|
@@ -8433,7 +8866,7 @@ function resolveCurrentBranch2() {
|
|
|
8433
8866
|
}
|
|
8434
8867
|
}
|
|
8435
8868
|
}
|
|
8436
|
-
async function
|
|
8869
|
+
async function runStatus2(argv) {
|
|
8437
8870
|
const checked_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
8438
8871
|
const writeCache = argv.includes("--write-cache");
|
|
8439
8872
|
const quiet = argv.includes("--quiet");
|
|
@@ -9618,11 +10051,11 @@ var generate_exports = {};
|
|
|
9618
10051
|
__export(generate_exports, {
|
|
9619
10052
|
runGenerate: () => runGenerate
|
|
9620
10053
|
});
|
|
9621
|
-
import { readFile as
|
|
9622
|
-
import { join as
|
|
10054
|
+
import { readFile as readFile22, mkdir as mkdir10, writeFile as writeFile17 } from "node:fs/promises";
|
|
10055
|
+
import { join as join31, resolve as resolve8 } from "node:path";
|
|
9623
10056
|
async function readJsonFile3(filePath) {
|
|
9624
10057
|
try {
|
|
9625
|
-
const raw = await
|
|
10058
|
+
const raw = await readFile22(filePath, "utf-8");
|
|
9626
10059
|
return JSON.parse(raw);
|
|
9627
10060
|
} catch {
|
|
9628
10061
|
return null;
|
|
@@ -9630,7 +10063,7 @@ async function readJsonFile3(filePath) {
|
|
|
9630
10063
|
}
|
|
9631
10064
|
async function readPkgName(absPath) {
|
|
9632
10065
|
try {
|
|
9633
|
-
const raw = await
|
|
10066
|
+
const raw = await readFile22(join31(absPath, "package.json"), "utf-8");
|
|
9634
10067
|
const pkg = JSON.parse(raw);
|
|
9635
10068
|
return typeof pkg.name === "string" ? pkg.name : null;
|
|
9636
10069
|
} catch {
|
|
@@ -9644,7 +10077,7 @@ async function runGenerate(opts) {
|
|
|
9644
10077
|
const rootDir = resolve8(projectDir);
|
|
9645
10078
|
let packageManager;
|
|
9646
10079
|
try {
|
|
9647
|
-
const raw = await
|
|
10080
|
+
const raw = await readFile22(join31(rootDir, "package.json"), "utf-8");
|
|
9648
10081
|
const pkg = JSON.parse(raw);
|
|
9649
10082
|
if (typeof pkg.packageManager === "string") {
|
|
9650
10083
|
packageManager = pkg.packageManager;
|
|
@@ -9652,7 +10085,7 @@ async function runGenerate(opts) {
|
|
|
9652
10085
|
} catch {
|
|
9653
10086
|
}
|
|
9654
10087
|
const serverJson = await readJsonFile3(
|
|
9655
|
-
|
|
10088
|
+
join31(rootDir, ".codebyplan", "server.json")
|
|
9656
10089
|
);
|
|
9657
10090
|
const ports = [];
|
|
9658
10091
|
for (const alloc of serverJson?.port_allocations ?? []) {
|
|
@@ -9665,7 +10098,7 @@ async function runGenerate(opts) {
|
|
|
9665
10098
|
}
|
|
9666
10099
|
}
|
|
9667
10100
|
const gitJson = await readJsonFile3(
|
|
9668
|
-
|
|
10101
|
+
join31(rootDir, ".codebyplan", "git.json")
|
|
9669
10102
|
);
|
|
9670
10103
|
const branchModel = gitJson?.branch_config?.production ? {
|
|
9671
10104
|
production: gitJson.branch_config.production,
|
|
@@ -9674,7 +10107,7 @@ async function runGenerate(opts) {
|
|
|
9674
10107
|
)
|
|
9675
10108
|
} : void 0;
|
|
9676
10109
|
const shipmentJson = await readJsonFile3(
|
|
9677
|
-
|
|
10110
|
+
join31(rootDir, ".codebyplan", "shipment.json")
|
|
9678
10111
|
);
|
|
9679
10112
|
const shipmentSurfaces = [];
|
|
9680
10113
|
const rawSurfaces = shipmentJson?.shipment?.surfaces ?? shipmentJson?.surfaces ?? {};
|
|
@@ -9745,10 +10178,10 @@ async function runGenerate(opts) {
|
|
|
9745
10178
|
const structureMdContent = generateStructureMd(config);
|
|
9746
10179
|
const agentsContent = generateAgentsMd(structureMdContent);
|
|
9747
10180
|
if (check) {
|
|
9748
|
-
const agentsMdPath2 =
|
|
10181
|
+
const agentsMdPath2 = join31(rootDir, "AGENTS.md");
|
|
9749
10182
|
let existingAgents = null;
|
|
9750
10183
|
try {
|
|
9751
|
-
existingAgents = await
|
|
10184
|
+
existingAgents = await readFile22(agentsMdPath2, "utf-8");
|
|
9752
10185
|
} catch {
|
|
9753
10186
|
existingAgents = null;
|
|
9754
10187
|
}
|
|
@@ -9784,16 +10217,16 @@ async function runGenerate(opts) {
|
|
|
9784
10217
|
process.stdout.write(agentsContent);
|
|
9785
10218
|
return;
|
|
9786
10219
|
}
|
|
9787
|
-
const outputDir =
|
|
10220
|
+
const outputDir = join31(rootDir, ".claude", "generated");
|
|
9788
10221
|
await mkdir10(outputDir, { recursive: true });
|
|
9789
|
-
const outputPath =
|
|
9790
|
-
await
|
|
10222
|
+
const outputPath = join31(outputDir, "structure.md");
|
|
10223
|
+
await writeFile17(outputPath, structureMdContent, "utf-8");
|
|
9791
10224
|
process.stdout.write(`Wrote: .claude/generated/structure.md
|
|
9792
10225
|
`);
|
|
9793
|
-
const agentsMdPath =
|
|
10226
|
+
const agentsMdPath = join31(rootDir, "AGENTS.md");
|
|
9794
10227
|
let existingAgentsContent = null;
|
|
9795
10228
|
try {
|
|
9796
|
-
existingAgentsContent = await
|
|
10229
|
+
existingAgentsContent = await readFile22(agentsMdPath, "utf-8");
|
|
9797
10230
|
} catch {
|
|
9798
10231
|
existingAgentsContent = null;
|
|
9799
10232
|
}
|
|
@@ -9801,7 +10234,7 @@ async function runGenerate(opts) {
|
|
|
9801
10234
|
process.stdout.write(`Up to date: AGENTS.md
|
|
9802
10235
|
`);
|
|
9803
10236
|
} else {
|
|
9804
|
-
await
|
|
10237
|
+
await writeFile17(agentsMdPath, agentsContent, "utf-8");
|
|
9805
10238
|
process.stdout.write(`Wrote: AGENTS.md
|
|
9806
10239
|
`);
|
|
9807
10240
|
}
|
|
@@ -9821,11 +10254,11 @@ __export(readme_exports, {
|
|
|
9821
10254
|
runReadme: () => runReadme,
|
|
9822
10255
|
runReadmeCommand: () => runReadmeCommand
|
|
9823
10256
|
});
|
|
9824
|
-
import { readFile as
|
|
9825
|
-
import { join as
|
|
10257
|
+
import { readFile as readFile23, writeFile as writeFile18 } from "node:fs/promises";
|
|
10258
|
+
import { join as join32, resolve as resolve9, relative as relative8 } from "node:path";
|
|
9826
10259
|
async function readJsonFile4(filePath) {
|
|
9827
10260
|
try {
|
|
9828
|
-
const raw = await
|
|
10261
|
+
const raw = await readFile23(filePath, "utf-8");
|
|
9829
10262
|
return JSON.parse(raw);
|
|
9830
10263
|
} catch {
|
|
9831
10264
|
return null;
|
|
@@ -9894,7 +10327,7 @@ async function discoverUnits(rootDir, rootPkgJson) {
|
|
|
9894
10327
|
const discovered = await discoverMonorepoApps(rootDir);
|
|
9895
10328
|
for (const app of discovered) {
|
|
9896
10329
|
const pkgJson = await readJsonFile4(
|
|
9897
|
-
|
|
10330
|
+
join32(app.absPath, "package.json")
|
|
9898
10331
|
);
|
|
9899
10332
|
pkgJsonByPath.set(app.absPath, pkgJson);
|
|
9900
10333
|
allPackages.push({
|
|
@@ -9920,7 +10353,7 @@ async function runReadme(opts) {
|
|
|
9920
10353
|
const init = opts.init ?? opts["init"] ?? false;
|
|
9921
10354
|
const rootDir = resolve9(projectDir);
|
|
9922
10355
|
const rootPkgJson = await readJsonFile4(
|
|
9923
|
-
|
|
10356
|
+
join32(rootDir, "package.json")
|
|
9924
10357
|
);
|
|
9925
10358
|
const { units, allPackages, pkgJsonByPath } = await discoverUnits(
|
|
9926
10359
|
rootDir,
|
|
@@ -9929,11 +10362,11 @@ async function runReadme(opts) {
|
|
|
9929
10362
|
const driftUnits = [];
|
|
9930
10363
|
const missingUnits = [];
|
|
9931
10364
|
for (const unit of units) {
|
|
9932
|
-
const readmePath =
|
|
9933
|
-
const relPath = unit.isRoot ? "README.md" :
|
|
10365
|
+
const readmePath = join32(unit.absPath, "README.md");
|
|
10366
|
+
const relPath = unit.isRoot ? "README.md" : join32(relative8(rootDir, unit.absPath), "README.md");
|
|
9934
10367
|
let existingContent = null;
|
|
9935
10368
|
try {
|
|
9936
|
-
existingContent = await
|
|
10369
|
+
existingContent = await readFile23(readmePath, "utf-8");
|
|
9937
10370
|
} catch {
|
|
9938
10371
|
existingContent = null;
|
|
9939
10372
|
}
|
|
@@ -9968,7 +10401,7 @@ ${newContent}
|
|
|
9968
10401
|
`
|
|
9969
10402
|
);
|
|
9970
10403
|
} else {
|
|
9971
|
-
await
|
|
10404
|
+
await writeFile18(readmePath, newContent, "utf-8");
|
|
9972
10405
|
process.stdout.write(`Wrote (scaffold): ${relPath}
|
|
9973
10406
|
`);
|
|
9974
10407
|
}
|
|
@@ -10006,7 +10439,7 @@ ${newContent}
|
|
|
10006
10439
|
`
|
|
10007
10440
|
);
|
|
10008
10441
|
} else {
|
|
10009
|
-
await
|
|
10442
|
+
await writeFile18(readmePath, newContent, "utf-8");
|
|
10010
10443
|
process.stdout.write(`Wrote (refresh): ${relPath}
|
|
10011
10444
|
`);
|
|
10012
10445
|
}
|
|
@@ -10025,7 +10458,7 @@ ${newContent}
|
|
|
10025
10458
|
`
|
|
10026
10459
|
);
|
|
10027
10460
|
} else {
|
|
10028
|
-
await
|
|
10461
|
+
await writeFile18(readmePath, newContent, "utf-8");
|
|
10029
10462
|
process.stdout.write(`Wrote (init): ${relPath}
|
|
10030
10463
|
`);
|
|
10031
10464
|
}
|
|
@@ -10113,15 +10546,15 @@ __export(migrate_memory_exports, {
|
|
|
10113
10546
|
runMigrateMemory: () => runMigrateMemory
|
|
10114
10547
|
});
|
|
10115
10548
|
import {
|
|
10116
|
-
readFile as
|
|
10117
|
-
writeFile as
|
|
10549
|
+
readFile as readFile24,
|
|
10550
|
+
writeFile as writeFile19,
|
|
10118
10551
|
mkdir as mkdir11,
|
|
10119
10552
|
unlink as unlink4,
|
|
10120
10553
|
rmdir,
|
|
10121
10554
|
readdir as readdir4
|
|
10122
10555
|
} from "node:fs/promises";
|
|
10123
|
-
import { existsSync as
|
|
10124
|
-
import { join as
|
|
10556
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
10557
|
+
import { join as join33, resolve as resolve10, dirname as dirname11, sep as sep2 } from "node:path";
|
|
10125
10558
|
import { homedir as homedir8 } from "node:os";
|
|
10126
10559
|
function encodeProjectPath(absPath) {
|
|
10127
10560
|
return resolve10(absPath).replace(/[/\\]/g, "-");
|
|
@@ -10132,7 +10565,7 @@ function resolveAutoMemoryDir(opts) {
|
|
|
10132
10565
|
}
|
|
10133
10566
|
const projectDir = opts.projectDir ?? process.cwd();
|
|
10134
10567
|
const encoded = encodeProjectPath(projectDir);
|
|
10135
|
-
return
|
|
10568
|
+
return join33(homedir8(), ".claude", "projects", encoded, "memory");
|
|
10136
10569
|
}
|
|
10137
10570
|
function parseFrontmatter(content) {
|
|
10138
10571
|
content = content.replace(/\r\n/g, "\n");
|
|
@@ -10198,10 +10631,10 @@ async function inventoryFiles(dir) {
|
|
|
10198
10631
|
}
|
|
10199
10632
|
const results = [];
|
|
10200
10633
|
for (const filename of filenames) {
|
|
10201
|
-
const sourcePath =
|
|
10634
|
+
const sourcePath = join33(dir, filename);
|
|
10202
10635
|
let raw;
|
|
10203
10636
|
try {
|
|
10204
|
-
raw = await
|
|
10637
|
+
raw = await readFile24(sourcePath, "utf-8");
|
|
10205
10638
|
} catch (err) {
|
|
10206
10639
|
const msg = err instanceof Error ? err.message : String(err);
|
|
10207
10640
|
results.push({
|
|
@@ -10287,8 +10720,8 @@ async function applyPlan(plan, opts) {
|
|
|
10287
10720
|
if (entry.suggested_action !== "keep") continue;
|
|
10288
10721
|
if (!entry.suggested_target?.startsWith("nested:")) continue;
|
|
10289
10722
|
const relPath = entry.suggested_target.slice("nested:".length);
|
|
10290
|
-
const targetDir = resolve10(
|
|
10291
|
-
const targetFile =
|
|
10723
|
+
const targetDir = resolve10(join33(projectDir, relPath));
|
|
10724
|
+
const targetFile = join33(targetDir, "CLAUDE.md");
|
|
10292
10725
|
if (!targetDir.startsWith(resolve10(projectDir) + sep2)) {
|
|
10293
10726
|
process.stderr.write(
|
|
10294
10727
|
`migrate-memory: skipping unsafe suggested_target "${entry.suggested_target}" \u2014 resolves outside projectDir
|
|
@@ -10320,11 +10753,11 @@ ${anchor}
|
|
|
10320
10753
|
await mkdir11(targetDir, { recursive: true });
|
|
10321
10754
|
let existing = "";
|
|
10322
10755
|
try {
|
|
10323
|
-
existing = await
|
|
10756
|
+
existing = await readFile24(targetFile, "utf-8");
|
|
10324
10757
|
} catch {
|
|
10325
10758
|
}
|
|
10326
10759
|
if (!existing.includes(anchor)) {
|
|
10327
|
-
await
|
|
10760
|
+
await writeFile19(targetFile, existing + appendContent, "utf-8");
|
|
10328
10761
|
}
|
|
10329
10762
|
if (resolve10(entry.source_path).startsWith(resolve10(plan.auto_memory_dir) + sep2)) {
|
|
10330
10763
|
try {
|
|
@@ -10338,7 +10771,7 @@ ${anchor}
|
|
|
10338
10771
|
);
|
|
10339
10772
|
}
|
|
10340
10773
|
}
|
|
10341
|
-
const rootClaudeMd =
|
|
10774
|
+
const rootClaudeMd = join33(projectDir, ".claude", "CLAUDE.md");
|
|
10342
10775
|
if (dryRun) {
|
|
10343
10776
|
process.stdout.write(
|
|
10344
10777
|
`[dry-run] Would ensure ${rootClaudeMd} contains: ${IMPORT_LINE}
|
|
@@ -10347,12 +10780,12 @@ ${anchor}
|
|
|
10347
10780
|
} else {
|
|
10348
10781
|
let claudeMdContent = "";
|
|
10349
10782
|
try {
|
|
10350
|
-
claudeMdContent = await
|
|
10783
|
+
claudeMdContent = await readFile24(rootClaudeMd, "utf-8");
|
|
10351
10784
|
} catch {
|
|
10352
10785
|
await mkdir11(dirname11(rootClaudeMd), { recursive: true });
|
|
10353
10786
|
}
|
|
10354
10787
|
if (!claudeMdContent.includes(IMPORT_LINE)) {
|
|
10355
|
-
await
|
|
10788
|
+
await writeFile19(
|
|
10356
10789
|
rootClaudeMd,
|
|
10357
10790
|
claudeMdContent + `
|
|
10358
10791
|
${IMPORT_LINE}
|
|
@@ -10382,8 +10815,8 @@ ${IMPORT_LINE}
|
|
|
10382
10815
|
} catch {
|
|
10383
10816
|
}
|
|
10384
10817
|
}
|
|
10385
|
-
const memoryMd =
|
|
10386
|
-
const safeRmdirBase =
|
|
10818
|
+
const memoryMd = join33(plan.auto_memory_dir, "MEMORY.md");
|
|
10819
|
+
const safeRmdirBase = join33(homedir8(), ".claude", "projects");
|
|
10387
10820
|
if (dryRun) {
|
|
10388
10821
|
process.stdout.write(`[dry-run] Would delete MEMORY.md: ${memoryMd}
|
|
10389
10822
|
`);
|
|
@@ -10436,7 +10869,7 @@ async function runMigrateMemory(opts) {
|
|
|
10436
10869
|
if (applyFile) {
|
|
10437
10870
|
let planJson;
|
|
10438
10871
|
try {
|
|
10439
|
-
planJson = await
|
|
10872
|
+
planJson = await readFile24(resolve10(applyFile), "utf-8");
|
|
10440
10873
|
} catch (err) {
|
|
10441
10874
|
const msg = err instanceof Error ? err.message : String(err);
|
|
10442
10875
|
process.stderr.write(
|
|
@@ -10464,7 +10897,7 @@ async function runMigrateMemory(opts) {
|
|
|
10464
10897
|
);
|
|
10465
10898
|
return;
|
|
10466
10899
|
}
|
|
10467
|
-
if (!
|
|
10900
|
+
if (!existsSync11(autoMemoryDir)) {
|
|
10468
10901
|
process.stdout.write(
|
|
10469
10902
|
JSON.stringify(
|
|
10470
10903
|
{
|
|
@@ -10651,6 +11084,12 @@ void (async () => {
|
|
|
10651
11084
|
await runUploadE2eImagesCommand2(rest);
|
|
10652
11085
|
process.exit(0);
|
|
10653
11086
|
}
|
|
11087
|
+
if (arg === "arch-map") {
|
|
11088
|
+
const { runArchMapCommand: runArchMapCommand2 } = await Promise.resolve().then(() => (init_arch_map(), arch_map_exports));
|
|
11089
|
+
const rest = process.argv.slice(3);
|
|
11090
|
+
await runArchMapCommand2(rest);
|
|
11091
|
+
process.exit(0);
|
|
11092
|
+
}
|
|
10654
11093
|
if (arg === "config") {
|
|
10655
11094
|
const { runConfig: runConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
10656
11095
|
await runConfig2();
|
|
@@ -10676,8 +11115,8 @@ void (async () => {
|
|
|
10676
11115
|
const flagArgs = process.argv.slice(3);
|
|
10677
11116
|
const parsed = parseClaudeFlags(flagArgs);
|
|
10678
11117
|
if (subcommand === "status") {
|
|
10679
|
-
const { runStatus:
|
|
10680
|
-
await
|
|
11118
|
+
const { runStatus: runStatus3 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
11119
|
+
await runStatus3(process.argv.slice(4));
|
|
10681
11120
|
return;
|
|
10682
11121
|
}
|
|
10683
11122
|
if (subcommand === "install") {
|
|
@@ -10795,6 +11234,7 @@ void (async () => {
|
|
|
10795
11234
|
codebyplan create-project Create a new project within an organization (interactive prompt)
|
|
10796
11235
|
codebyplan create-repo Create a new repository within a project (interactive prompt)
|
|
10797
11236
|
codebyplan config Sync repo config from DB to .codebyplan/ files
|
|
11237
|
+
codebyplan arch-map Map architecture modules (status/drift/stamp)
|
|
10798
11238
|
codebyplan ports Verify port allocations against local package.json scripts
|
|
10799
11239
|
codebyplan tech-stack Detect and sync tech stack dependencies
|
|
10800
11240
|
(--full-tech-stack: sync every local worktree on this device)
|