codebyplan 1.13.28 → 1.13.30
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 +728 -18
- package/package.json +1 -1
- package/templates/README.md +16 -13
- package/templates/agents/cbp-cc-executor.md +6 -9
- package/templates/agents/cbp-improve-round.md +1 -1
- package/templates/agents/cbp-round-executor.md +1 -2
- package/templates/agents/cbp-task-check.md +12 -8
- package/templates/hooks/cbp-mcp-round-sync.sh +9 -0
- package/templates/rules/README.md +13 -8
- package/templates/rules/cbp-operating-gotchas.md +64 -0
- package/templates/settings.project.base.json +3 -3
- package/templates/skills/cbp-build-cc-agent/SKILL.md +3 -4
- package/templates/skills/cbp-build-cc-agent/examples/with-skills-preload.md +2 -3
- package/templates/skills/cbp-build-cc-agent/reference/frontmatter-fields.md +0 -1
- package/templates/skills/cbp-build-cc-agent/scripts/validate-agent.sh +0 -6
- package/templates/skills/cbp-build-cc-agent/templates/agent.md +1 -2
- package/templates/skills/cbp-build-cc-claude-file/SKILL.md +16 -2
- package/templates/skills/cbp-build-cc-claude-file/reference/what-belongs.md +1 -1
- package/templates/skills/cbp-build-cc-mode/SKILL.md +5 -4
- package/templates/skills/cbp-build-cc-rule/SKILL.md +2 -2
- package/templates/skills/cbp-build-cc-settings/reference/cbp-permission-policy.md +3 -2
- package/templates/skills/cbp-build-cc-skill/reference/cbp-quality.md +1 -1
- package/templates/skills/cbp-merge-main/SKILL.md +1 -1
- package/templates/skills/cbp-round-complete/SKILL.md +164 -0
- package/templates/skills/cbp-round-end/SKILL.md +16 -14
- package/templates/skills/cbp-round-end/reference/findings-presentation.md +7 -17
- package/templates/skills/cbp-round-execute/SKILL.md +4 -0
- package/templates/skills/cbp-round-input/SKILL.md +6 -6
- package/templates/skills/cbp-round-start/SKILL.md +12 -15
- package/templates/skills/cbp-round-update/SKILL.md +31 -143
- package/templates/skills/cbp-standalone-task-check/SKILL.md +2 -2
- package/templates/skills/cbp-standalone-task-complete/SKILL.md +4 -3
- package/templates/skills/cbp-standalone-task-testing/SKILL.md +4 -4
- package/templates/skills/cbp-task-check/SKILL.md +3 -3
- package/templates/skills/cbp-task-complete/SKILL.md +7 -6
- package/templates/skills/cbp-task-testing/SKILL.md +3 -5
- package/templates/skills/cbp-todo/SKILL.md +1 -1
- package/templates/skills/cbp-build-cc-memory/SKILL.md +0 -201
- package/templates/skills/cbp-build-cc-memory/examples/feedback-memory.md +0 -11
- package/templates/skills/cbp-build-cc-memory/examples/project-memory.md +0 -11
- package/templates/skills/cbp-build-cc-memory/examples/reference-memory.md +0 -13
- package/templates/skills/cbp-build-cc-memory/examples/user-memory.md +0 -14
- package/templates/skills/cbp-build-cc-memory/reference/memory-types.md +0 -59
- package/templates/skills/cbp-build-cc-memory/reference/when-to-save.md +0 -62
- package/templates/skills/cbp-build-cc-memory/templates/MEMORY-index.md +0 -4
- package/templates/skills/cbp-build-cc-memory/templates/memory-entry.md +0 -15
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.30";
|
|
18
18
|
PACKAGE_NAME = "codebyplan";
|
|
19
19
|
}
|
|
20
20
|
});
|
|
@@ -698,7 +698,7 @@ function isRetryable(err) {
|
|
|
698
698
|
return false;
|
|
699
699
|
}
|
|
700
700
|
function delay(ms) {
|
|
701
|
-
return new Promise((
|
|
701
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
702
702
|
}
|
|
703
703
|
async function request(method, path10, options) {
|
|
704
704
|
const url = buildUrl(path10, options?.params);
|
|
@@ -1056,7 +1056,7 @@ var init_device_flow = __esm({
|
|
|
1056
1056
|
this.name = "OAuthInvalidClientError";
|
|
1057
1057
|
}
|
|
1058
1058
|
};
|
|
1059
|
-
defaultSleep = (ms) => new Promise((
|
|
1059
|
+
defaultSleep = (ms) => new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
1060
1060
|
}
|
|
1061
1061
|
});
|
|
1062
1062
|
|
|
@@ -4596,7 +4596,7 @@ function setRetryDelayMs(ms) {
|
|
|
4596
4596
|
RETRY_DELAY_MS = ms;
|
|
4597
4597
|
}
|
|
4598
4598
|
function sleep(ms) {
|
|
4599
|
-
return new Promise((
|
|
4599
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
4600
4600
|
}
|
|
4601
4601
|
function isTransientMcpError(err) {
|
|
4602
4602
|
if (!(err instanceof McpError)) return false;
|
|
@@ -8538,11 +8538,11 @@ async function ask(q, opts) {
|
|
|
8538
8538
|
try {
|
|
8539
8539
|
while (true) {
|
|
8540
8540
|
const choices = q.choices.map((c) => `[${c.key}] ${c.label}`).join(" ");
|
|
8541
|
-
const answer = await new Promise((
|
|
8541
|
+
const answer = await new Promise((resolve11) => {
|
|
8542
8542
|
rl.question(`${q.message}
|
|
8543
8543
|
${choices}
|
|
8544
8544
|
> `, (input) => {
|
|
8545
|
-
|
|
8545
|
+
resolve11(input.trim().toLowerCase());
|
|
8546
8546
|
});
|
|
8547
8547
|
});
|
|
8548
8548
|
const match = q.choices.find(
|
|
@@ -9128,14 +9128,684 @@ var init_uninstall = __esm({
|
|
|
9128
9128
|
}
|
|
9129
9129
|
});
|
|
9130
9130
|
|
|
9131
|
+
// src/lib/structure-generator.ts
|
|
9132
|
+
function renderTechStack(techStack) {
|
|
9133
|
+
const entries = Object.entries(techStack).filter(([, value]) => value.trim().length > 0).sort(([a], [b]) => a.localeCompare(b));
|
|
9134
|
+
if (entries.length === 0) return "";
|
|
9135
|
+
const lines = entries.map(([cat, names]) => `- **${cat}**: ${names}`);
|
|
9136
|
+
return `## Tech Stack
|
|
9137
|
+
|
|
9138
|
+
${lines.join("\n")}
|
|
9139
|
+
`;
|
|
9140
|
+
}
|
|
9141
|
+
function renderPackageManager(pm) {
|
|
9142
|
+
if (!pm.trim()) return "";
|
|
9143
|
+
return `## Package Manager
|
|
9144
|
+
|
|
9145
|
+
\`${pm}\`
|
|
9146
|
+
`;
|
|
9147
|
+
}
|
|
9148
|
+
function renderMonorepoStructure(packages) {
|
|
9149
|
+
if (packages.length === 0) return "";
|
|
9150
|
+
const sorted = [...packages].sort((a, b) => a.path.localeCompare(b.path));
|
|
9151
|
+
const rows = sorted.map(
|
|
9152
|
+
(p) => `| \`${p.path}\` | \`${p.name}\` | ${p.purpose ?? ""} |`
|
|
9153
|
+
);
|
|
9154
|
+
return `## Monorepo Structure
|
|
9155
|
+
|
|
9156
|
+
| Location | Package | Purpose |
|
|
9157
|
+
|----------|---------|----------|
|
|
9158
|
+
` + rows.join("\n") + "\n";
|
|
9159
|
+
}
|
|
9160
|
+
function renderPorts(ports) {
|
|
9161
|
+
if (ports.length === 0) return "";
|
|
9162
|
+
const sorted = [...ports].sort((a, b) => a.port - b.port);
|
|
9163
|
+
const rows = sorted.map(
|
|
9164
|
+
(p) => `| ${p.port} | ${p.label} | ${p.server_type} |`
|
|
9165
|
+
);
|
|
9166
|
+
return `## Ports
|
|
9167
|
+
|
|
9168
|
+
| Port | Label | Type |
|
|
9169
|
+
|------|-------|------|
|
|
9170
|
+
` + rows.join("\n") + "\n";
|
|
9171
|
+
}
|
|
9172
|
+
function renderBranchModel(model) {
|
|
9173
|
+
const lines = [];
|
|
9174
|
+
lines.push(`- **Production**: \`${model.production}\``);
|
|
9175
|
+
if (model.protected && model.protected.length > 0) {
|
|
9176
|
+
const sorted = [...model.protected].sort();
|
|
9177
|
+
lines.push(`- **Protected**: ${sorted.map((b) => `\`${b}\``).join(", ")}`);
|
|
9178
|
+
}
|
|
9179
|
+
return `## Branch Model
|
|
9180
|
+
|
|
9181
|
+
${lines.join("\n")}
|
|
9182
|
+
`;
|
|
9183
|
+
}
|
|
9184
|
+
function resolvePlatform(key, platform2) {
|
|
9185
|
+
if (platform2) return platform2;
|
|
9186
|
+
if (key.startsWith("vercel")) return "vercel";
|
|
9187
|
+
if (key.startsWith("railway")) return "railway";
|
|
9188
|
+
if (key.startsWith("supabase")) return "supabase";
|
|
9189
|
+
if (key === "npm") return "npm";
|
|
9190
|
+
return key;
|
|
9191
|
+
}
|
|
9192
|
+
function renderShipmentSurfaces(surfaces) {
|
|
9193
|
+
if (surfaces.length === 0) return "";
|
|
9194
|
+
const sorted = [...surfaces].sort((a, b) => a.key.localeCompare(b.key));
|
|
9195
|
+
const rows = sorted.map(
|
|
9196
|
+
(s) => `| \`${s.key}\` | ${resolvePlatform(s.key, s.platform)} | ${s.urlOrPath ?? ""} |`
|
|
9197
|
+
);
|
|
9198
|
+
return `## Shipment Surfaces
|
|
9199
|
+
|
|
9200
|
+
| Surface | Platform/Type | Path/URL |
|
|
9201
|
+
|---------|---------------|----------|
|
|
9202
|
+
` + rows.join("\n") + "\n";
|
|
9203
|
+
}
|
|
9204
|
+
function generateStructureMd(config) {
|
|
9205
|
+
const sections = [];
|
|
9206
|
+
if (config.techStack && Object.keys(config.techStack).length > 0) {
|
|
9207
|
+
const rendered = renderTechStack(config.techStack);
|
|
9208
|
+
if (rendered) sections.push(rendered);
|
|
9209
|
+
}
|
|
9210
|
+
if (config.packageManager) {
|
|
9211
|
+
const rendered = renderPackageManager(config.packageManager);
|
|
9212
|
+
if (rendered) sections.push(rendered);
|
|
9213
|
+
}
|
|
9214
|
+
if (config.packages && config.packages.length > 0) {
|
|
9215
|
+
const rendered = renderMonorepoStructure(config.packages);
|
|
9216
|
+
if (rendered) sections.push(rendered);
|
|
9217
|
+
}
|
|
9218
|
+
if (config.ports && config.ports.length > 0) {
|
|
9219
|
+
const rendered = renderPorts(config.ports);
|
|
9220
|
+
if (rendered) sections.push(rendered);
|
|
9221
|
+
}
|
|
9222
|
+
if (config.branchModel) {
|
|
9223
|
+
const rendered = renderBranchModel(config.branchModel);
|
|
9224
|
+
if (rendered) sections.push(rendered);
|
|
9225
|
+
}
|
|
9226
|
+
if (config.shipmentSurfaces && config.shipmentSurfaces.length > 0) {
|
|
9227
|
+
const rendered = renderShipmentSurfaces(config.shipmentSurfaces);
|
|
9228
|
+
if (rendered) sections.push(rendered);
|
|
9229
|
+
}
|
|
9230
|
+
const body = sections.join("\n");
|
|
9231
|
+
return `${SENTINEL_START}
|
|
9232
|
+
${body}${SENTINEL_END}
|
|
9233
|
+
`;
|
|
9234
|
+
}
|
|
9235
|
+
var SENTINEL_START, SENTINEL_END;
|
|
9236
|
+
var init_structure_generator = __esm({
|
|
9237
|
+
"src/lib/structure-generator.ts"() {
|
|
9238
|
+
"use strict";
|
|
9239
|
+
SENTINEL_START = "<!-- @codebyplan-generated: structure start -->";
|
|
9240
|
+
SENTINEL_END = "<!-- @codebyplan-generated: structure end -->";
|
|
9241
|
+
}
|
|
9242
|
+
});
|
|
9243
|
+
|
|
9244
|
+
// src/cli/claude/generate.ts
|
|
9245
|
+
var generate_exports = {};
|
|
9246
|
+
__export(generate_exports, {
|
|
9247
|
+
runGenerate: () => runGenerate
|
|
9248
|
+
});
|
|
9249
|
+
import { readFile as readFile21, mkdir as mkdir10, writeFile as writeFile16 } from "node:fs/promises";
|
|
9250
|
+
import { join as join30, resolve as resolve8 } from "node:path";
|
|
9251
|
+
async function readJsonFile3(filePath) {
|
|
9252
|
+
try {
|
|
9253
|
+
const raw = await readFile21(filePath, "utf-8");
|
|
9254
|
+
return JSON.parse(raw);
|
|
9255
|
+
} catch {
|
|
9256
|
+
return null;
|
|
9257
|
+
}
|
|
9258
|
+
}
|
|
9259
|
+
async function readPkgName(absPath) {
|
|
9260
|
+
try {
|
|
9261
|
+
const raw = await readFile21(join30(absPath, "package.json"), "utf-8");
|
|
9262
|
+
const pkg = JSON.parse(raw);
|
|
9263
|
+
return typeof pkg.name === "string" ? pkg.name : null;
|
|
9264
|
+
} catch {
|
|
9265
|
+
return null;
|
|
9266
|
+
}
|
|
9267
|
+
}
|
|
9268
|
+
async function runGenerate(opts) {
|
|
9269
|
+
const projectDir = opts.projectDir ?? opts["project-dir"] ?? process.cwd();
|
|
9270
|
+
const dryRun = opts.dryRun ?? opts["dryRun"] ?? false;
|
|
9271
|
+
const rootDir = resolve8(projectDir);
|
|
9272
|
+
let packageManager;
|
|
9273
|
+
try {
|
|
9274
|
+
const raw = await readFile21(join30(rootDir, "package.json"), "utf-8");
|
|
9275
|
+
const pkg = JSON.parse(raw);
|
|
9276
|
+
if (typeof pkg.packageManager === "string") {
|
|
9277
|
+
packageManager = pkg.packageManager;
|
|
9278
|
+
}
|
|
9279
|
+
} catch {
|
|
9280
|
+
}
|
|
9281
|
+
const serverJson = await readJsonFile3(
|
|
9282
|
+
join30(rootDir, ".codebyplan", "server.json")
|
|
9283
|
+
);
|
|
9284
|
+
const ports = [];
|
|
9285
|
+
for (const alloc of serverJson?.port_allocations ?? []) {
|
|
9286
|
+
if (typeof alloc.port === "number") {
|
|
9287
|
+
ports.push({
|
|
9288
|
+
port: alloc.port,
|
|
9289
|
+
label: alloc.label ?? "",
|
|
9290
|
+
server_type: alloc.server_type ?? ""
|
|
9291
|
+
});
|
|
9292
|
+
}
|
|
9293
|
+
}
|
|
9294
|
+
const gitJson = await readJsonFile3(
|
|
9295
|
+
join30(rootDir, ".codebyplan", "git.json")
|
|
9296
|
+
);
|
|
9297
|
+
const branchModel = gitJson?.branch_config?.production ? {
|
|
9298
|
+
production: gitJson.branch_config.production,
|
|
9299
|
+
protected: gitJson.branch_config.protected?.filter(
|
|
9300
|
+
(b) => typeof b === "string"
|
|
9301
|
+
)
|
|
9302
|
+
} : void 0;
|
|
9303
|
+
const shipmentJson = await readJsonFile3(
|
|
9304
|
+
join30(rootDir, ".codebyplan", "shipment.json")
|
|
9305
|
+
);
|
|
9306
|
+
const shipmentSurfaces = [];
|
|
9307
|
+
const rawSurfaces = shipmentJson?.shipment?.surfaces ?? shipmentJson?.surfaces ?? {};
|
|
9308
|
+
for (const [key, surface] of Object.entries(rawSurfaces).sort(
|
|
9309
|
+
([a], [b]) => a.localeCompare(b)
|
|
9310
|
+
)) {
|
|
9311
|
+
const urlOrPath = surface.custom_domain ?? surface.url ?? surface.app_path ?? void 0;
|
|
9312
|
+
shipmentSurfaces.push({
|
|
9313
|
+
key,
|
|
9314
|
+
platform: surface.platform,
|
|
9315
|
+
urlOrPath
|
|
9316
|
+
});
|
|
9317
|
+
}
|
|
9318
|
+
const discoveredApps = (await discoverMonorepoApps(rootDir)).sort(
|
|
9319
|
+
(a, b) => a.path.localeCompare(b.path)
|
|
9320
|
+
);
|
|
9321
|
+
const packages = [];
|
|
9322
|
+
for (const app of discoveredApps) {
|
|
9323
|
+
const pkgName = await readPkgName(app.absPath);
|
|
9324
|
+
packages.push({
|
|
9325
|
+
path: app.path,
|
|
9326
|
+
name: pkgName ?? app.name
|
|
9327
|
+
});
|
|
9328
|
+
}
|
|
9329
|
+
const techResult = await detectTechStack(rootDir);
|
|
9330
|
+
const CATEGORY_LABELS = {
|
|
9331
|
+
"component-lib": "Component Library",
|
|
9332
|
+
graphql: "GraphQL",
|
|
9333
|
+
quality: "Code Quality"
|
|
9334
|
+
};
|
|
9335
|
+
const categoryMap = {};
|
|
9336
|
+
for (const entry of techResult.flat) {
|
|
9337
|
+
if (entry.name === SYNTHETIC_CARRIER_NAME) continue;
|
|
9338
|
+
if (!categoryMap[entry.category]) {
|
|
9339
|
+
categoryMap[entry.category] = [];
|
|
9340
|
+
}
|
|
9341
|
+
categoryMap[entry.category].push(entry.name);
|
|
9342
|
+
}
|
|
9343
|
+
if ((categoryMap["mobile"]?.length ?? 0) > 0) {
|
|
9344
|
+
const frameworkEntries = categoryMap["framework"] ?? [];
|
|
9345
|
+
const filtered = frameworkEntries.filter((n) => n !== "React");
|
|
9346
|
+
if (filtered.length > 0) {
|
|
9347
|
+
categoryMap["framework"] = filtered;
|
|
9348
|
+
} else {
|
|
9349
|
+
delete categoryMap["framework"];
|
|
9350
|
+
}
|
|
9351
|
+
}
|
|
9352
|
+
const hasNextjs = (categoryMap["framework"] ?? []).some(
|
|
9353
|
+
(n) => n.toLowerCase().includes("next")
|
|
9354
|
+
);
|
|
9355
|
+
const filteredPorts = ports.filter((p) => {
|
|
9356
|
+
if (p.server_type === "nextjs" && !hasNextjs) return false;
|
|
9357
|
+
return true;
|
|
9358
|
+
});
|
|
9359
|
+
const techStack = {};
|
|
9360
|
+
for (const [cat, names] of Object.entries(categoryMap)) {
|
|
9361
|
+
const label = CATEGORY_LABELS[cat] ?? cat.charAt(0).toUpperCase() + cat.slice(1);
|
|
9362
|
+
techStack[label] = [...names].sort().join(" + ");
|
|
9363
|
+
}
|
|
9364
|
+
const config = {
|
|
9365
|
+
techStack: Object.keys(techStack).length > 0 ? techStack : void 0,
|
|
9366
|
+
packageManager,
|
|
9367
|
+
packages: packages.length > 0 ? packages : void 0,
|
|
9368
|
+
ports: filteredPorts.length > 0 ? filteredPorts : void 0,
|
|
9369
|
+
branchModel,
|
|
9370
|
+
shipmentSurfaces: shipmentSurfaces.length > 0 ? shipmentSurfaces : void 0
|
|
9371
|
+
};
|
|
9372
|
+
const content = generateStructureMd(config);
|
|
9373
|
+
if (dryRun) {
|
|
9374
|
+
process.stdout.write(
|
|
9375
|
+
`[dry-run] Would write: .claude/generated/structure.md
|
|
9376
|
+
|
|
9377
|
+
`
|
|
9378
|
+
);
|
|
9379
|
+
process.stdout.write(content);
|
|
9380
|
+
return;
|
|
9381
|
+
}
|
|
9382
|
+
const outputDir = join30(rootDir, ".claude", "generated");
|
|
9383
|
+
await mkdir10(outputDir, { recursive: true });
|
|
9384
|
+
const outputPath = join30(outputDir, "structure.md");
|
|
9385
|
+
await writeFile16(outputPath, content, "utf-8");
|
|
9386
|
+
process.stdout.write(`Wrote: .claude/generated/structure.md
|
|
9387
|
+
`);
|
|
9388
|
+
}
|
|
9389
|
+
var init_generate = __esm({
|
|
9390
|
+
"src/cli/claude/generate.ts"() {
|
|
9391
|
+
"use strict";
|
|
9392
|
+
init_tech_detect();
|
|
9393
|
+
init_structure_generator();
|
|
9394
|
+
}
|
|
9395
|
+
});
|
|
9396
|
+
|
|
9397
|
+
// src/cli/claude/migrate-memory.ts
|
|
9398
|
+
var migrate_memory_exports = {};
|
|
9399
|
+
__export(migrate_memory_exports, {
|
|
9400
|
+
applyPlan: () => applyPlan,
|
|
9401
|
+
buildPlan: () => buildPlan,
|
|
9402
|
+
encodeProjectPath: () => encodeProjectPath,
|
|
9403
|
+
flagDropCandidates: () => flagDropCandidates,
|
|
9404
|
+
inventoryFiles: () => inventoryFiles,
|
|
9405
|
+
resolveAutoMemoryDir: () => resolveAutoMemoryDir,
|
|
9406
|
+
runMigrateMemory: () => runMigrateMemory
|
|
9407
|
+
});
|
|
9408
|
+
import {
|
|
9409
|
+
readFile as readFile22,
|
|
9410
|
+
writeFile as writeFile17,
|
|
9411
|
+
mkdir as mkdir11,
|
|
9412
|
+
unlink as unlink4,
|
|
9413
|
+
rmdir,
|
|
9414
|
+
readdir as readdir4
|
|
9415
|
+
} from "node:fs/promises";
|
|
9416
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
9417
|
+
import { join as join31, resolve as resolve9, dirname as dirname11, sep as sep2 } from "node:path";
|
|
9418
|
+
import { homedir as homedir8 } from "node:os";
|
|
9419
|
+
function encodeProjectPath(absPath) {
|
|
9420
|
+
return resolve9(absPath).replace(/[/\\]/g, "-");
|
|
9421
|
+
}
|
|
9422
|
+
function resolveAutoMemoryDir(opts) {
|
|
9423
|
+
if (opts.autoMemoryDir) {
|
|
9424
|
+
return opts.autoMemoryDir;
|
|
9425
|
+
}
|
|
9426
|
+
const projectDir = opts.projectDir ?? process.cwd();
|
|
9427
|
+
const encoded = encodeProjectPath(projectDir);
|
|
9428
|
+
return join31(homedir8(), ".claude", "projects", encoded, "memory");
|
|
9429
|
+
}
|
|
9430
|
+
function parseFrontmatter(content) {
|
|
9431
|
+
content = content.replace(/\r\n/g, "\n");
|
|
9432
|
+
if (!content.startsWith("---")) {
|
|
9433
|
+
return {
|
|
9434
|
+
ok: false,
|
|
9435
|
+
error: "File does not start with a YAML frontmatter fence (---)"
|
|
9436
|
+
};
|
|
9437
|
+
}
|
|
9438
|
+
const rest = content.slice(3);
|
|
9439
|
+
const closingIdx = rest.indexOf("\n---");
|
|
9440
|
+
if (closingIdx === -1) {
|
|
9441
|
+
return { ok: false, error: "Frontmatter closing fence (---) not found" };
|
|
9442
|
+
}
|
|
9443
|
+
const fmBlock = rest.slice(0, closingIdx);
|
|
9444
|
+
const lines = fmBlock.split("\n");
|
|
9445
|
+
let name = "";
|
|
9446
|
+
let description = "";
|
|
9447
|
+
let metadataType = null;
|
|
9448
|
+
let inMetadata = false;
|
|
9449
|
+
for (const line of lines) {
|
|
9450
|
+
if (!line.trim()) continue;
|
|
9451
|
+
if (/^metadata:\s*$/.test(line)) {
|
|
9452
|
+
inMetadata = true;
|
|
9453
|
+
continue;
|
|
9454
|
+
}
|
|
9455
|
+
if (inMetadata && /^\s{2,}/.test(line)) {
|
|
9456
|
+
const match2 = line.trim().match(/^(\w+):\s*(.*)$/);
|
|
9457
|
+
if (match2) {
|
|
9458
|
+
const [, key2, val2] = match2;
|
|
9459
|
+
if (key2 === "type") {
|
|
9460
|
+
metadataType = val2?.trim() || null;
|
|
9461
|
+
}
|
|
9462
|
+
}
|
|
9463
|
+
continue;
|
|
9464
|
+
}
|
|
9465
|
+
if (inMetadata) {
|
|
9466
|
+
inMetadata = false;
|
|
9467
|
+
}
|
|
9468
|
+
const match = line.match(/^(\w+):\s*(.*)$/);
|
|
9469
|
+
if (!match) continue;
|
|
9470
|
+
const [, key, rawVal] = match;
|
|
9471
|
+
const val = (rawVal ?? "").trim().replace(/^["']|["']$/g, "");
|
|
9472
|
+
if (key === "name") name = val;
|
|
9473
|
+
if (key === "description") description = val;
|
|
9474
|
+
}
|
|
9475
|
+
return {
|
|
9476
|
+
ok: true,
|
|
9477
|
+
data: {
|
|
9478
|
+
name,
|
|
9479
|
+
description,
|
|
9480
|
+
metadata: { type: metadataType }
|
|
9481
|
+
}
|
|
9482
|
+
};
|
|
9483
|
+
}
|
|
9484
|
+
async function inventoryFiles(dir) {
|
|
9485
|
+
let filenames;
|
|
9486
|
+
try {
|
|
9487
|
+
const entries = await readdir4(dir);
|
|
9488
|
+
filenames = entries.filter((f) => f.endsWith(".md") && f !== "MEMORY.md").sort();
|
|
9489
|
+
} catch {
|
|
9490
|
+
return [];
|
|
9491
|
+
}
|
|
9492
|
+
const results = [];
|
|
9493
|
+
for (const filename of filenames) {
|
|
9494
|
+
const sourcePath = join31(dir, filename);
|
|
9495
|
+
let raw;
|
|
9496
|
+
try {
|
|
9497
|
+
raw = await readFile22(sourcePath, "utf-8");
|
|
9498
|
+
} catch (err) {
|
|
9499
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9500
|
+
results.push({
|
|
9501
|
+
filename,
|
|
9502
|
+
source_path: sourcePath,
|
|
9503
|
+
name: filename.replace(/\.md$/, ""),
|
|
9504
|
+
description: "",
|
|
9505
|
+
metadata_type: null,
|
|
9506
|
+
suggested_action: "keep",
|
|
9507
|
+
parse_error: `Could not read file: ${msg}`
|
|
9508
|
+
});
|
|
9509
|
+
continue;
|
|
9510
|
+
}
|
|
9511
|
+
const parseResult = parseFrontmatter(raw);
|
|
9512
|
+
if (!parseResult.ok) {
|
|
9513
|
+
console.error(
|
|
9514
|
+
`[migrate-memory] WARNING: could not parse frontmatter in ${filename}: ${parseResult.error}`
|
|
9515
|
+
);
|
|
9516
|
+
results.push({
|
|
9517
|
+
filename,
|
|
9518
|
+
source_path: sourcePath,
|
|
9519
|
+
name: filename.replace(/\.md$/, ""),
|
|
9520
|
+
description: "",
|
|
9521
|
+
metadata_type: null,
|
|
9522
|
+
suggested_action: "keep",
|
|
9523
|
+
parse_error: parseResult.error
|
|
9524
|
+
});
|
|
9525
|
+
continue;
|
|
9526
|
+
}
|
|
9527
|
+
const { name, description, metadata } = parseResult.data;
|
|
9528
|
+
const entry = {
|
|
9529
|
+
filename,
|
|
9530
|
+
source_path: sourcePath,
|
|
9531
|
+
name: name || filename.replace(/\.md$/, ""),
|
|
9532
|
+
description,
|
|
9533
|
+
metadata_type: metadata.type,
|
|
9534
|
+
suggested_action: "keep"
|
|
9535
|
+
};
|
|
9536
|
+
if (DROP_PATTERN.test(description)) {
|
|
9537
|
+
entry.suggested_action = "drop";
|
|
9538
|
+
const match = description.match(DROP_PATTERN);
|
|
9539
|
+
entry.drop_reason = `Description contains "${match[0]}" keyword`;
|
|
9540
|
+
}
|
|
9541
|
+
if (entry.suggested_action === "keep") {
|
|
9542
|
+
const typeSlug = metadata.type?.toLowerCase().replace(/[^a-z0-9-]/g, "-") ?? "misc";
|
|
9543
|
+
entry.suggested_target = `nested:.claude/memory/${typeSlug}`;
|
|
9544
|
+
}
|
|
9545
|
+
results.push(entry);
|
|
9546
|
+
}
|
|
9547
|
+
return results;
|
|
9548
|
+
}
|
|
9549
|
+
function flagDropCandidates(entries) {
|
|
9550
|
+
return entries.map((entry) => {
|
|
9551
|
+
if (entry.parse_error) {
|
|
9552
|
+
return entry;
|
|
9553
|
+
}
|
|
9554
|
+
if (DROP_PATTERN.test(entry.description)) {
|
|
9555
|
+
const match = entry.description.match(DROP_PATTERN);
|
|
9556
|
+
return {
|
|
9557
|
+
...entry,
|
|
9558
|
+
suggested_action: "drop",
|
|
9559
|
+
drop_reason: entry.drop_reason ?? `Description contains "${match[0]}" keyword`
|
|
9560
|
+
};
|
|
9561
|
+
}
|
|
9562
|
+
return entry;
|
|
9563
|
+
});
|
|
9564
|
+
}
|
|
9565
|
+
function buildPlan(entries, opts) {
|
|
9566
|
+
const plan = {
|
|
9567
|
+
auto_memory_dir: opts.autoMemoryDir,
|
|
9568
|
+
entries,
|
|
9569
|
+
generate_step: "After --apply, run `codebyplan claude generate` to regenerate .claude/generated/structure.md"
|
|
9570
|
+
};
|
|
9571
|
+
if (!opts.omitTimestamp) {
|
|
9572
|
+
plan.generated_at = opts.now ? opts.now() : (/* @__PURE__ */ new Date()).toISOString();
|
|
9573
|
+
}
|
|
9574
|
+
return plan;
|
|
9575
|
+
}
|
|
9576
|
+
async function applyPlan(plan, opts) {
|
|
9577
|
+
const projectDir = resolve9(opts.projectDir);
|
|
9578
|
+
const dryRun = opts.dryRun ?? false;
|
|
9579
|
+
for (const entry of plan.entries) {
|
|
9580
|
+
if (entry.suggested_action !== "keep") continue;
|
|
9581
|
+
if (!entry.suggested_target?.startsWith("nested:")) continue;
|
|
9582
|
+
const relPath = entry.suggested_target.slice("nested:".length);
|
|
9583
|
+
const targetDir = resolve9(join31(projectDir, relPath));
|
|
9584
|
+
const targetFile = join31(targetDir, "CLAUDE.md");
|
|
9585
|
+
if (!targetDir.startsWith(resolve9(projectDir) + sep2)) {
|
|
9586
|
+
process.stderr.write(
|
|
9587
|
+
`migrate-memory: skipping unsafe suggested_target "${entry.suggested_target}" \u2014 resolves outside projectDir
|
|
9588
|
+
`
|
|
9589
|
+
);
|
|
9590
|
+
continue;
|
|
9591
|
+
}
|
|
9592
|
+
const anchor = `_Source: ${entry.filename}_`;
|
|
9593
|
+
const appendContent = `
|
|
9594
|
+
## ${entry.name}
|
|
9595
|
+
|
|
9596
|
+
${entry.description}
|
|
9597
|
+
|
|
9598
|
+
${anchor}
|
|
9599
|
+
`;
|
|
9600
|
+
if (dryRun) {
|
|
9601
|
+
process.stdout.write(`[dry-run] Would create/append: ${targetFile}
|
|
9602
|
+
`);
|
|
9603
|
+
if (resolve9(entry.source_path).startsWith(
|
|
9604
|
+
resolve9(plan.auto_memory_dir) + sep2
|
|
9605
|
+
)) {
|
|
9606
|
+
process.stdout.write(
|
|
9607
|
+
`[dry-run] Would delete migrated keep source: ${entry.source_path}
|
|
9608
|
+
`
|
|
9609
|
+
);
|
|
9610
|
+
}
|
|
9611
|
+
continue;
|
|
9612
|
+
}
|
|
9613
|
+
await mkdir11(targetDir, { recursive: true });
|
|
9614
|
+
let existing = "";
|
|
9615
|
+
try {
|
|
9616
|
+
existing = await readFile22(targetFile, "utf-8");
|
|
9617
|
+
} catch {
|
|
9618
|
+
}
|
|
9619
|
+
if (!existing.includes(anchor)) {
|
|
9620
|
+
await writeFile17(targetFile, existing + appendContent, "utf-8");
|
|
9621
|
+
}
|
|
9622
|
+
if (resolve9(entry.source_path).startsWith(resolve9(plan.auto_memory_dir) + sep2)) {
|
|
9623
|
+
try {
|
|
9624
|
+
await unlink4(entry.source_path);
|
|
9625
|
+
} catch {
|
|
9626
|
+
}
|
|
9627
|
+
} else {
|
|
9628
|
+
process.stderr.write(
|
|
9629
|
+
`migrate-memory: skipping delete of migrated keep source "${entry.source_path}" \u2014 resolves outside auto_memory_dir
|
|
9630
|
+
`
|
|
9631
|
+
);
|
|
9632
|
+
}
|
|
9633
|
+
}
|
|
9634
|
+
const rootClaudeMd = join31(projectDir, ".claude", "CLAUDE.md");
|
|
9635
|
+
if (dryRun) {
|
|
9636
|
+
process.stdout.write(
|
|
9637
|
+
`[dry-run] Would ensure ${rootClaudeMd} contains: ${IMPORT_LINE}
|
|
9638
|
+
`
|
|
9639
|
+
);
|
|
9640
|
+
} else {
|
|
9641
|
+
let claudeMdContent = "";
|
|
9642
|
+
try {
|
|
9643
|
+
claudeMdContent = await readFile22(rootClaudeMd, "utf-8");
|
|
9644
|
+
} catch {
|
|
9645
|
+
await mkdir11(dirname11(rootClaudeMd), { recursive: true });
|
|
9646
|
+
}
|
|
9647
|
+
if (!claudeMdContent.includes(IMPORT_LINE)) {
|
|
9648
|
+
await writeFile17(
|
|
9649
|
+
rootClaudeMd,
|
|
9650
|
+
claudeMdContent + `
|
|
9651
|
+
${IMPORT_LINE}
|
|
9652
|
+
`,
|
|
9653
|
+
"utf-8"
|
|
9654
|
+
);
|
|
9655
|
+
}
|
|
9656
|
+
}
|
|
9657
|
+
for (const entry of plan.entries) {
|
|
9658
|
+
if (entry.suggested_action !== "drop") continue;
|
|
9659
|
+
if (!resolve9(entry.source_path).startsWith(
|
|
9660
|
+
resolve9(plan.auto_memory_dir) + sep2
|
|
9661
|
+
)) {
|
|
9662
|
+
process.stderr.write(
|
|
9663
|
+
`migrate-memory: skipping delete of "${entry.source_path}" \u2014 resolves outside auto_memory_dir
|
|
9664
|
+
`
|
|
9665
|
+
);
|
|
9666
|
+
continue;
|
|
9667
|
+
}
|
|
9668
|
+
if (dryRun) {
|
|
9669
|
+
process.stdout.write(`[dry-run] Would delete: ${entry.source_path}
|
|
9670
|
+
`);
|
|
9671
|
+
continue;
|
|
9672
|
+
}
|
|
9673
|
+
try {
|
|
9674
|
+
await unlink4(entry.source_path);
|
|
9675
|
+
} catch {
|
|
9676
|
+
}
|
|
9677
|
+
}
|
|
9678
|
+
const memoryMd = join31(plan.auto_memory_dir, "MEMORY.md");
|
|
9679
|
+
const safeRmdirBase = join31(homedir8(), ".claude", "projects");
|
|
9680
|
+
if (dryRun) {
|
|
9681
|
+
process.stdout.write(`[dry-run] Would delete MEMORY.md: ${memoryMd}
|
|
9682
|
+
`);
|
|
9683
|
+
} else {
|
|
9684
|
+
if (resolve9(plan.auto_memory_dir).startsWith(safeRmdirBase + sep2)) {
|
|
9685
|
+
try {
|
|
9686
|
+
await unlink4(memoryMd);
|
|
9687
|
+
} catch {
|
|
9688
|
+
}
|
|
9689
|
+
} else {
|
|
9690
|
+
process.stderr.write(
|
|
9691
|
+
`migrate-memory: skipping MEMORY.md deletion \u2014 auto_memory_dir not under ~/.claude/projects
|
|
9692
|
+
`
|
|
9693
|
+
);
|
|
9694
|
+
}
|
|
9695
|
+
}
|
|
9696
|
+
if (dryRun) {
|
|
9697
|
+
process.stdout.write(
|
|
9698
|
+
`[dry-run] Would rmdir (if empty): ${plan.auto_memory_dir}
|
|
9699
|
+
`
|
|
9700
|
+
);
|
|
9701
|
+
} else {
|
|
9702
|
+
if (!resolve9(plan.auto_memory_dir).startsWith(safeRmdirBase + sep2)) {
|
|
9703
|
+
process.stderr.write(
|
|
9704
|
+
`migrate-memory: skipping rmdir of "${plan.auto_memory_dir}" \u2014 not under ~/.claude/projects
|
|
9705
|
+
`
|
|
9706
|
+
);
|
|
9707
|
+
} else {
|
|
9708
|
+
try {
|
|
9709
|
+
const remaining = await readdir4(plan.auto_memory_dir);
|
|
9710
|
+
if (remaining.length === 0) {
|
|
9711
|
+
await rmdir(plan.auto_memory_dir);
|
|
9712
|
+
}
|
|
9713
|
+
} catch {
|
|
9714
|
+
}
|
|
9715
|
+
}
|
|
9716
|
+
}
|
|
9717
|
+
}
|
|
9718
|
+
async function runMigrateMemory(opts) {
|
|
9719
|
+
const rest = opts.rest ?? [];
|
|
9720
|
+
const projectDir = opts.projectDir ?? process.cwd();
|
|
9721
|
+
const filteredRest = rest.filter(
|
|
9722
|
+
(v, i) => v !== "--project-dir" && rest[i - 1] !== "--project-dir"
|
|
9723
|
+
);
|
|
9724
|
+
const isJson = filteredRest.includes("--json") || filteredRest.length === 0;
|
|
9725
|
+
const isDryRun = rest.includes("--dry-run");
|
|
9726
|
+
const applyIdx = rest.indexOf("--apply");
|
|
9727
|
+
const applyFile = applyIdx !== -1 ? rest[applyIdx + 1] : void 0;
|
|
9728
|
+
const autoMemoryDir = resolveAutoMemoryDir(opts);
|
|
9729
|
+
if (applyFile) {
|
|
9730
|
+
let planJson;
|
|
9731
|
+
try {
|
|
9732
|
+
planJson = await readFile22(resolve9(applyFile), "utf-8");
|
|
9733
|
+
} catch (err) {
|
|
9734
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9735
|
+
process.stderr.write(
|
|
9736
|
+
`migrate-memory: cannot read plan file "${applyFile}": ${msg}
|
|
9737
|
+
`
|
|
9738
|
+
);
|
|
9739
|
+
process.exitCode = 1;
|
|
9740
|
+
return;
|
|
9741
|
+
}
|
|
9742
|
+
let plan2;
|
|
9743
|
+
try {
|
|
9744
|
+
plan2 = JSON.parse(planJson);
|
|
9745
|
+
} catch (err) {
|
|
9746
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9747
|
+
process.stderr.write(
|
|
9748
|
+
`migrate-memory: plan file is not valid JSON: ${msg}
|
|
9749
|
+
`
|
|
9750
|
+
);
|
|
9751
|
+
process.exitCode = 1;
|
|
9752
|
+
return;
|
|
9753
|
+
}
|
|
9754
|
+
await applyPlan(plan2, { projectDir, dryRun: isDryRun });
|
|
9755
|
+
process.stdout.write(
|
|
9756
|
+
isDryRun ? "migrate-memory: dry-run complete (no changes written).\n" : "migrate-memory: apply complete.\n"
|
|
9757
|
+
);
|
|
9758
|
+
return;
|
|
9759
|
+
}
|
|
9760
|
+
if (!existsSync10(autoMemoryDir)) {
|
|
9761
|
+
process.stdout.write(
|
|
9762
|
+
JSON.stringify(
|
|
9763
|
+
{
|
|
9764
|
+
auto_memory_dir: autoMemoryDir,
|
|
9765
|
+
entries: [],
|
|
9766
|
+
generate_step: "After --apply, run `codebyplan claude generate` to regenerate .claude/generated/structure.md",
|
|
9767
|
+
note: "Auto-memory directory does not exist \u2014 nothing to migrate."
|
|
9768
|
+
},
|
|
9769
|
+
null,
|
|
9770
|
+
2
|
|
9771
|
+
) + "\n"
|
|
9772
|
+
);
|
|
9773
|
+
return;
|
|
9774
|
+
}
|
|
9775
|
+
const rawEntries = await inventoryFiles(autoMemoryDir);
|
|
9776
|
+
const entries = flagDropCandidates(rawEntries);
|
|
9777
|
+
const plan = buildPlan(entries, {
|
|
9778
|
+
autoMemoryDir,
|
|
9779
|
+
omitTimestamp: opts.omitTimestamp,
|
|
9780
|
+
now: opts.now
|
|
9781
|
+
});
|
|
9782
|
+
if (isDryRun) {
|
|
9783
|
+
process.stdout.write("[dry-run] Plan:\n");
|
|
9784
|
+
process.stdout.write(JSON.stringify(plan, null, 2) + "\n\n");
|
|
9785
|
+
await applyPlan(plan, { projectDir, dryRun: true });
|
|
9786
|
+
return;
|
|
9787
|
+
}
|
|
9788
|
+
if (isJson) {
|
|
9789
|
+
process.stdout.write(JSON.stringify(plan, null, 2) + "\n");
|
|
9790
|
+
}
|
|
9791
|
+
}
|
|
9792
|
+
var DROP_PATTERN, IMPORT_LINE;
|
|
9793
|
+
var init_migrate_memory = __esm({
|
|
9794
|
+
"src/cli/claude/migrate-memory.ts"() {
|
|
9795
|
+
"use strict";
|
|
9796
|
+
DROP_PATTERN = /\b(RESOLVED|SHIPPED|RETIRED|ROLLED.?BACK)\b/i;
|
|
9797
|
+
IMPORT_LINE = "@.claude/generated/structure.md";
|
|
9798
|
+
}
|
|
9799
|
+
});
|
|
9800
|
+
|
|
9131
9801
|
// src/index.ts
|
|
9132
9802
|
init_version();
|
|
9133
9803
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
9134
|
-
import { resolve as
|
|
9804
|
+
import { resolve as resolve10 } from "node:path";
|
|
9135
9805
|
void (async () => {
|
|
9136
9806
|
if (!process.env.CODEBYPLAN_API_KEY) {
|
|
9137
9807
|
try {
|
|
9138
|
-
const envPath =
|
|
9808
|
+
const envPath = resolve10(process.cwd(), ".env.local");
|
|
9139
9809
|
const content = readFileSync10(envPath, "utf-8");
|
|
9140
9810
|
for (const line of content.split("\n")) {
|
|
9141
9811
|
const trimmed = line.trim();
|
|
@@ -9336,16 +10006,40 @@ void (async () => {
|
|
|
9336
10006
|
);
|
|
9337
10007
|
process.exit(process.exitCode ?? 0);
|
|
9338
10008
|
}
|
|
10009
|
+
if (subcommand === "generate") {
|
|
10010
|
+
if (parsed === null) {
|
|
10011
|
+
process.exit(1);
|
|
10012
|
+
}
|
|
10013
|
+
const { runGenerate: runGenerate2 } = await Promise.resolve().then(() => (init_generate(), generate_exports));
|
|
10014
|
+
await runGenerate2(
|
|
10015
|
+
parsed.projectDir != null ? { ...parsed.opts, projectDir: parsed.projectDir } : parsed.opts
|
|
10016
|
+
);
|
|
10017
|
+
process.exit(process.exitCode ?? 0);
|
|
10018
|
+
}
|
|
10019
|
+
if (subcommand === "migrate-memory") {
|
|
10020
|
+
if (parsed === null) {
|
|
10021
|
+
process.exit(1);
|
|
10022
|
+
}
|
|
10023
|
+
const { runMigrateMemory: runMigrateMemory2 } = await Promise.resolve().then(() => (init_migrate_memory(), migrate_memory_exports));
|
|
10024
|
+
const rest = process.argv.slice(4);
|
|
10025
|
+
await runMigrateMemory2({
|
|
10026
|
+
rest,
|
|
10027
|
+
projectDir: parsed.projectDir ?? void 0
|
|
10028
|
+
});
|
|
10029
|
+
process.exit(process.exitCode ?? 0);
|
|
10030
|
+
}
|
|
9339
10031
|
console.log(`
|
|
9340
10032
|
CodeByPlan Claude asset management v${VERSION}
|
|
9341
10033
|
|
|
9342
10034
|
Usage:
|
|
9343
|
-
codebyplan claude install [flags]
|
|
9344
|
-
codebyplan claude update [flags]
|
|
9345
|
-
codebyplan claude uninstall [flags]
|
|
9346
|
-
codebyplan claude status
|
|
9347
|
-
|
|
9348
|
-
|
|
10035
|
+
codebyplan claude install [flags] Install skills/agents/hooks into ./.claude/
|
|
10036
|
+
codebyplan claude update [flags] Update installed assets to latest versions
|
|
10037
|
+
codebyplan claude uninstall [flags] Remove installed assets from ./.claude/
|
|
10038
|
+
codebyplan claude status Check package-sync state (drift, version skip, settings drift)
|
|
10039
|
+
--write-cache Write result to .codebyplan/claude-status.local.json
|
|
10040
|
+
--quiet Suppress stdout output
|
|
10041
|
+
codebyplan claude generate [flags] Write .claude/generated/structure.md from local config
|
|
10042
|
+
codebyplan claude migrate-memory [flags] Inventory auto-memory files and emit migration plan
|
|
9349
10043
|
|
|
9350
10044
|
Flags (apply to install/update/uninstall):
|
|
9351
10045
|
--yes, -y Auto-accept every prompt with its recommended default
|
|
@@ -9359,6 +10053,10 @@ void (async () => {
|
|
|
9359
10053
|
--bash Set statusline renderer to bash after install/update
|
|
9360
10054
|
--node Set statusline renderer to node after install/update
|
|
9361
10055
|
--python Set statusline renderer to python after install/update
|
|
10056
|
+
|
|
10057
|
+
Flags (apply to generate):
|
|
10058
|
+
--project-dir <path> Override the project root (default: cwd)
|
|
10059
|
+
--dry-run Print what would be written, write nothing
|
|
9362
10060
|
`);
|
|
9363
10061
|
process.exit(0);
|
|
9364
10062
|
}
|
|
@@ -9387,7 +10085,7 @@ void (async () => {
|
|
|
9387
10085
|
codebyplan upload-e2e-images Upload new/changed committed e2e PNGs for a checkpoint
|
|
9388
10086
|
codebyplan scaffold-publish-workflow Write the publish-on-main GitHub workflow into ./.github/workflows/
|
|
9389
10087
|
codebyplan branch migrate Rewrite branch_config from 3-branch to 2-tier model
|
|
9390
|
-
codebyplan claude Claude asset management (install/update/uninstall)
|
|
10088
|
+
codebyplan claude Claude asset management (install/update/uninstall/generate/migrate-memory)
|
|
9391
10089
|
codebyplan statusline Show or set the statusline renderer (bash/node/python)
|
|
9392
10090
|
codebyplan resolve-worktree Resolve active worktree UUID from device+path+branch tuple
|
|
9393
10091
|
codebyplan version-status Report installed vs latest version + update guard (JSON)
|
|
@@ -9419,9 +10117,11 @@ void (async () => {
|
|
|
9419
10117
|
codebyplan eslint init Detect tech stack, resolve presets, generate configs
|
|
9420
10118
|
|
|
9421
10119
|
Claude asset management:
|
|
9422
|
-
codebyplan claude install [flags]
|
|
9423
|
-
codebyplan claude update [flags]
|
|
9424
|
-
codebyplan claude uninstall [flags]
|
|
10120
|
+
codebyplan claude install [flags] Install skills/agents/hooks into ./.claude/
|
|
10121
|
+
codebyplan claude update [flags] Update installed assets to latest versions
|
|
10122
|
+
codebyplan claude uninstall [flags] Remove installed assets from ./.claude/
|
|
10123
|
+
codebyplan claude generate [flags] Write .claude/generated/structure.md from local config
|
|
10124
|
+
codebyplan claude migrate-memory [flags] Inventory auto-memory files and emit migration plan
|
|
9425
10125
|
|
|
9426
10126
|
Flags (install/update/uninstall):
|
|
9427
10127
|
--yes, -y Auto-accept prompts with recommended defaults
|
|
@@ -9433,6 +10133,16 @@ void (async () => {
|
|
|
9433
10133
|
--node Set statusline renderer to node after install/update
|
|
9434
10134
|
--python Set statusline renderer to python after install/update
|
|
9435
10135
|
|
|
10136
|
+
Flags (generate):
|
|
10137
|
+
--project-dir <path> Override the project root (default: cwd)
|
|
10138
|
+
--dry-run Print what would be written, write nothing
|
|
10139
|
+
|
|
10140
|
+
Flags (migrate-memory):
|
|
10141
|
+
--project-dir <path> Override the project root (default: cwd)
|
|
10142
|
+
--json Inventory mode: print plan JSON to stdout, write nothing (default)
|
|
10143
|
+
--dry-run Print plan + what apply would do, write nothing
|
|
10144
|
+
--apply <file> Read an approved plan JSON file and apply it
|
|
10145
|
+
|
|
9436
10146
|
Resolve-worktree options:
|
|
9437
10147
|
--json Structured JSON output instead of bare UUID
|
|
9438
10148
|
--fallback-from-branch Fallback resolver: filter by (device_id, branch) client-side
|