codebyplan 1.13.36 → 1.13.38
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 +682 -38
- package/package.json +1 -1
- package/templates/context/mcp-docs.md +2 -2
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.38";
|
|
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((resolve12) => setTimeout(resolve12, 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((resolve12) => setTimeout(resolve12, ms));
|
|
1060
1060
|
}
|
|
1061
1061
|
});
|
|
1062
1062
|
|
|
@@ -4670,7 +4670,7 @@ function setRetryDelayMs(ms) {
|
|
|
4670
4670
|
RETRY_DELAY_MS = ms;
|
|
4671
4671
|
}
|
|
4672
4672
|
function sleep(ms) {
|
|
4673
|
-
return new Promise((
|
|
4673
|
+
return new Promise((resolve12) => setTimeout(resolve12, ms));
|
|
4674
4674
|
}
|
|
4675
4675
|
function isTransientMcpError(err) {
|
|
4676
4676
|
if (!(err instanceof McpError)) return false;
|
|
@@ -8616,11 +8616,11 @@ async function ask(q, opts) {
|
|
|
8616
8616
|
try {
|
|
8617
8617
|
while (true) {
|
|
8618
8618
|
const choices = q.choices.map((c) => `[${c.key}] ${c.label}`).join(" ");
|
|
8619
|
-
const answer = await new Promise((
|
|
8619
|
+
const answer = await new Promise((resolve12) => {
|
|
8620
8620
|
rl.question(`${q.message}
|
|
8621
8621
|
${choices}
|
|
8622
8622
|
> `, (input) => {
|
|
8623
|
-
|
|
8623
|
+
resolve12(input.trim().toLowerCase());
|
|
8624
8624
|
});
|
|
8625
8625
|
});
|
|
8626
8626
|
const match = q.choices.find(
|
|
@@ -9326,6 +9326,293 @@ var init_structure_generator = __esm({
|
|
|
9326
9326
|
}
|
|
9327
9327
|
});
|
|
9328
9328
|
|
|
9329
|
+
// src/lib/readme-generator.ts
|
|
9330
|
+
function managedStartMarker(section) {
|
|
9331
|
+
return `${MANAGED_START_PREFIX}${section}${MANAGED_MARKER_SUFFIX}`;
|
|
9332
|
+
}
|
|
9333
|
+
function managedEndMarker(section) {
|
|
9334
|
+
return `${MANAGED_END_PREFIX}${section}${MANAGED_MARKER_SUFFIX}`;
|
|
9335
|
+
}
|
|
9336
|
+
function hasManagedMarkers(content) {
|
|
9337
|
+
return content.includes(MANAGED_START_PREFIX) || content.includes(MANAGED_END_PREFIX);
|
|
9338
|
+
}
|
|
9339
|
+
function validateManagedMarkers(content) {
|
|
9340
|
+
const errors = [];
|
|
9341
|
+
const startRe = /<!-- codebyplan:managed:start:([a-z0-9][a-z0-9-]*) -->/g;
|
|
9342
|
+
const endRe = /<!-- codebyplan:managed:end:([a-z0-9][a-z0-9-]*) -->/g;
|
|
9343
|
+
const starts = [...content.matchAll(startRe)].map((m) => m[1]);
|
|
9344
|
+
const ends = [...content.matchAll(endRe)].map((m) => m[1]);
|
|
9345
|
+
const seenStarts = /* @__PURE__ */ new Set();
|
|
9346
|
+
for (const s of starts) {
|
|
9347
|
+
if (seenStarts.has(s)) {
|
|
9348
|
+
errors.push(`duplicate managed section '${s}'`);
|
|
9349
|
+
}
|
|
9350
|
+
seenStarts.add(s);
|
|
9351
|
+
if (!ends.includes(s)) {
|
|
9352
|
+
errors.push(`missing end marker for section '${s}'`);
|
|
9353
|
+
}
|
|
9354
|
+
}
|
|
9355
|
+
for (const e of ends) {
|
|
9356
|
+
if (!starts.includes(e)) {
|
|
9357
|
+
errors.push(`end marker without start marker for section '${e}'`);
|
|
9358
|
+
}
|
|
9359
|
+
}
|
|
9360
|
+
return errors;
|
|
9361
|
+
}
|
|
9362
|
+
function renderTechStackSection(techStack) {
|
|
9363
|
+
const entries = Object.entries(techStack).filter(([, value]) => value.trim().length > 0).sort(([a], [b]) => a.localeCompare(b));
|
|
9364
|
+
if (entries.length === 0) return "";
|
|
9365
|
+
const lines = entries.map(([cat, names]) => `- **${cat}**: ${names}`);
|
|
9366
|
+
return `## Tech Stack
|
|
9367
|
+
|
|
9368
|
+
${lines.join("\n")}
|
|
9369
|
+
`;
|
|
9370
|
+
}
|
|
9371
|
+
function renderStructureSection(packages) {
|
|
9372
|
+
if (packages.length === 0) return "";
|
|
9373
|
+
const sorted = [...packages].sort((a, b) => a.path.localeCompare(b.path));
|
|
9374
|
+
const rows = sorted.map(
|
|
9375
|
+
(p) => `| \`${p.path}\` | \`${p.name}\` | ${p.purpose ?? ""} |`
|
|
9376
|
+
);
|
|
9377
|
+
return `## Structure
|
|
9378
|
+
|
|
9379
|
+
| Location | Package | Purpose |
|
|
9380
|
+
|----------|---------|----------|
|
|
9381
|
+
` + rows.join("\n") + "\n";
|
|
9382
|
+
}
|
|
9383
|
+
function renderScriptsSection(scripts, installCommand) {
|
|
9384
|
+
const sortedEntries = Object.entries(scripts).filter(([, cmd]) => typeof cmd === "string" && cmd.trim().length > 0).sort(([a], [b]) => a.localeCompare(b));
|
|
9385
|
+
const lines = [];
|
|
9386
|
+
lines.push(`\`\`\`bash`);
|
|
9387
|
+
lines.push(`# Install`);
|
|
9388
|
+
lines.push(installCommand);
|
|
9389
|
+
lines.push(``);
|
|
9390
|
+
if (sortedEntries.length > 0) {
|
|
9391
|
+
lines.push(`# Available scripts`);
|
|
9392
|
+
for (const [name, cmd] of sortedEntries) {
|
|
9393
|
+
lines.push(`# ${name}`);
|
|
9394
|
+
lines.push(cmd);
|
|
9395
|
+
}
|
|
9396
|
+
}
|
|
9397
|
+
lines.push(`\`\`\``);
|
|
9398
|
+
return `## Scripts
|
|
9399
|
+
|
|
9400
|
+
${lines.join("\n")}
|
|
9401
|
+
`;
|
|
9402
|
+
}
|
|
9403
|
+
function buildManagedSections(config) {
|
|
9404
|
+
const sections = {};
|
|
9405
|
+
if (config.techStack && Object.keys(config.techStack).length > 0) {
|
|
9406
|
+
const rendered = renderTechStackSection(config.techStack);
|
|
9407
|
+
if (rendered) {
|
|
9408
|
+
sections["tech-stack"] = rendered;
|
|
9409
|
+
}
|
|
9410
|
+
}
|
|
9411
|
+
if (config.packages && config.packages.length > 0) {
|
|
9412
|
+
const rendered = renderStructureSection(config.packages);
|
|
9413
|
+
if (rendered) {
|
|
9414
|
+
sections["structure"] = rendered;
|
|
9415
|
+
}
|
|
9416
|
+
}
|
|
9417
|
+
if (config.scripts && Object.keys(config.scripts).length > 0) {
|
|
9418
|
+
const pm = config.packageManager ?? "pnpm";
|
|
9419
|
+
const pmBase = pm.split("@")[0] ?? "pnpm";
|
|
9420
|
+
const installCmd = config.installCommand ?? `${pmBase} install`;
|
|
9421
|
+
const rendered = renderScriptsSection(config.scripts, installCmd);
|
|
9422
|
+
if (rendered) {
|
|
9423
|
+
sections["scripts"] = rendered;
|
|
9424
|
+
}
|
|
9425
|
+
}
|
|
9426
|
+
return sections;
|
|
9427
|
+
}
|
|
9428
|
+
function hashManagedContent(sections) {
|
|
9429
|
+
const sortedKeys = Object.keys(sections).sort();
|
|
9430
|
+
const payload = {};
|
|
9431
|
+
for (const k of sortedKeys) {
|
|
9432
|
+
payload[k] = sections[k];
|
|
9433
|
+
}
|
|
9434
|
+
return sha256(JSON.stringify(payload));
|
|
9435
|
+
}
|
|
9436
|
+
function scaffoldReadme(config) {
|
|
9437
|
+
const title = config.name ?? "Project";
|
|
9438
|
+
const description = config.description ?? "";
|
|
9439
|
+
const sections = buildManagedSections(config);
|
|
9440
|
+
const hash = hashManagedContent(sections);
|
|
9441
|
+
const lines = [];
|
|
9442
|
+
lines.push(`# ${title}`);
|
|
9443
|
+
lines.push(``);
|
|
9444
|
+
if (description) {
|
|
9445
|
+
lines.push(description);
|
|
9446
|
+
lines.push(``);
|
|
9447
|
+
}
|
|
9448
|
+
const sectionKeys = Object.keys(sections).sort();
|
|
9449
|
+
for (const key of sectionKeys) {
|
|
9450
|
+
lines.push(managedStartMarker(key));
|
|
9451
|
+
lines.push(sections[key].trimEnd());
|
|
9452
|
+
lines.push(managedEndMarker(key));
|
|
9453
|
+
lines.push(``);
|
|
9454
|
+
}
|
|
9455
|
+
lines.push(`${HASH_MARKER_PREFIX}${hash}${MANAGED_MARKER_SUFFIX}`);
|
|
9456
|
+
lines.push(``);
|
|
9457
|
+
return lines.join("\n");
|
|
9458
|
+
}
|
|
9459
|
+
function refreshManagedSections(existing, sections) {
|
|
9460
|
+
let content = existing;
|
|
9461
|
+
const startPattern = new RegExp(
|
|
9462
|
+
`${escapeRegex(MANAGED_START_PREFIX)}([a-z0-9][a-z0-9-]*)${escapeRegex(MANAGED_MARKER_SUFFIX)}[\\s\\S]*?${escapeRegex(MANAGED_END_PREFIX)}\\1${escapeRegex(MANAGED_MARKER_SUFFIX)}`,
|
|
9463
|
+
"g"
|
|
9464
|
+
);
|
|
9465
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9466
|
+
content = content.replace(startPattern, (_, sectionName) => {
|
|
9467
|
+
const key = sectionName.trim();
|
|
9468
|
+
seen.add(key);
|
|
9469
|
+
if (Object.prototype.hasOwnProperty.call(sections, key)) {
|
|
9470
|
+
const newBody = sections[key].trimEnd();
|
|
9471
|
+
return managedStartMarker(key) + "\n" + newBody + "\n" + managedEndMarker(key);
|
|
9472
|
+
} else {
|
|
9473
|
+
return "";
|
|
9474
|
+
}
|
|
9475
|
+
});
|
|
9476
|
+
content = content.replace(/\n{3,}/g, "\n\n");
|
|
9477
|
+
const newSectionKeys = Object.keys(sections).sort().filter((k) => !seen.has(k));
|
|
9478
|
+
if (newSectionKeys.length > 0) {
|
|
9479
|
+
const hashCommentPattern = new RegExp(
|
|
9480
|
+
`
|
|
9481
|
+
${escapeRegex(HASH_MARKER_PREFIX)}[^
|
|
9482
|
+
]*${escapeRegex(MANAGED_MARKER_SUFFIX)}(
|
|
9483
|
+
|$)`
|
|
9484
|
+
);
|
|
9485
|
+
content = content.replace(hashCommentPattern, "\n");
|
|
9486
|
+
if (!content.endsWith("\n")) content += "\n";
|
|
9487
|
+
for (const key of newSectionKeys) {
|
|
9488
|
+
content += "\n" + managedStartMarker(key) + "\n" + sections[key].trimEnd() + "\n" + managedEndMarker(key) + "\n";
|
|
9489
|
+
}
|
|
9490
|
+
}
|
|
9491
|
+
const newHash = hashManagedContent(sections);
|
|
9492
|
+
const hashLine = `${HASH_MARKER_PREFIX}${newHash}${MANAGED_MARKER_SUFFIX}`;
|
|
9493
|
+
const existingHashPattern = new RegExp(
|
|
9494
|
+
`${escapeRegex(HASH_MARKER_PREFIX)}[^
|
|
9495
|
+
]*${escapeRegex(MANAGED_MARKER_SUFFIX)}`
|
|
9496
|
+
);
|
|
9497
|
+
if (existingHashPattern.test(content)) {
|
|
9498
|
+
content = content.replace(existingHashPattern, hashLine);
|
|
9499
|
+
} else {
|
|
9500
|
+
if (!content.endsWith("\n")) content += "\n";
|
|
9501
|
+
content += `${hashLine}
|
|
9502
|
+
`;
|
|
9503
|
+
}
|
|
9504
|
+
content = content.trimEnd() + "\n";
|
|
9505
|
+
return content;
|
|
9506
|
+
}
|
|
9507
|
+
function escapeRegex(str) {
|
|
9508
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9509
|
+
}
|
|
9510
|
+
function extractManagedHash(content) {
|
|
9511
|
+
const hashPattern = new RegExp(
|
|
9512
|
+
`${escapeRegex(HASH_MARKER_PREFIX)}(sha256:[0-9a-f]{64})${escapeRegex(MANAGED_MARKER_SUFFIX)}`
|
|
9513
|
+
);
|
|
9514
|
+
const m = hashPattern.exec(content);
|
|
9515
|
+
return m?.[1] ?? null;
|
|
9516
|
+
}
|
|
9517
|
+
var MANAGED_START_PREFIX, MANAGED_END_PREFIX, MANAGED_MARKER_SUFFIX, HASH_MARKER_PREFIX;
|
|
9518
|
+
var init_readme_generator = __esm({
|
|
9519
|
+
"src/lib/readme-generator.ts"() {
|
|
9520
|
+
"use strict";
|
|
9521
|
+
init_hash();
|
|
9522
|
+
MANAGED_START_PREFIX = "<!-- codebyplan:managed:start:";
|
|
9523
|
+
MANAGED_END_PREFIX = "<!-- codebyplan:managed:end:";
|
|
9524
|
+
MANAGED_MARKER_SUFFIX = " -->";
|
|
9525
|
+
HASH_MARKER_PREFIX = "<!-- codebyplan:hash:";
|
|
9526
|
+
}
|
|
9527
|
+
});
|
|
9528
|
+
|
|
9529
|
+
// src/lib/agents-generator.ts
|
|
9530
|
+
function stripStructureSentinels(structureContent) {
|
|
9531
|
+
const lines = structureContent.split("\n");
|
|
9532
|
+
const filtered = lines.filter((line) => {
|
|
9533
|
+
const trimmed = line.trim();
|
|
9534
|
+
return !trimmed.startsWith("<!-- @codebyplan-generated:");
|
|
9535
|
+
});
|
|
9536
|
+
let result = filtered.join("\n");
|
|
9537
|
+
result = result.replace(/^\n+/, "").replace(/\n+$/, "");
|
|
9538
|
+
return result;
|
|
9539
|
+
}
|
|
9540
|
+
function buildCuratedGuidance(cleanStructureContent) {
|
|
9541
|
+
const lines = [];
|
|
9542
|
+
lines.push(`## Project Context`);
|
|
9543
|
+
lines.push(``);
|
|
9544
|
+
lines.push(
|
|
9545
|
+
`This file is auto-generated for cross-tool compatibility. The canonical source of truth for project instructions is \`.claude/CLAUDE.md\`. If your tool supports Claude Code's \`@\` import syntax, read \`.claude/CLAUDE.md\` directly.`
|
|
9546
|
+
);
|
|
9547
|
+
lines.push(``);
|
|
9548
|
+
if (cleanStructureContent.trim().length > 0) {
|
|
9549
|
+
lines.push(cleanStructureContent.trim());
|
|
9550
|
+
} else {
|
|
9551
|
+
lines.push(
|
|
9552
|
+
`_Structure not yet generated. Run \`codebyplan claude generate\` to populate._`
|
|
9553
|
+
);
|
|
9554
|
+
}
|
|
9555
|
+
lines.push(``);
|
|
9556
|
+
lines.push(`## Source of Truth`);
|
|
9557
|
+
lines.push(``);
|
|
9558
|
+
lines.push(
|
|
9559
|
+
`The database is the sole source of truth for all development data. No local markdown files for tracking \u2014 everything is in the DB, accessed via MCP tools or the Web UI.`
|
|
9560
|
+
);
|
|
9561
|
+
lines.push(``);
|
|
9562
|
+
lines.push(`## \`.claude/\` Layout`);
|
|
9563
|
+
lines.push(``);
|
|
9564
|
+
lines.push(`| Directory | Purpose |`);
|
|
9565
|
+
lines.push(`|-----------|---------|`);
|
|
9566
|
+
lines.push(`| \`rules/\` | Auto-loaded behavioral constraints |`);
|
|
9567
|
+
lines.push(`| \`skills/\` | User-invocable \`/cbp-*\` commands |`);
|
|
9568
|
+
lines.push(`| \`agents/\` | Spawned sub-agents |`);
|
|
9569
|
+
lines.push(`| \`context/\` | Agent/skill input data |`);
|
|
9570
|
+
lines.push(
|
|
9571
|
+
`| \`CLAUDE.md\` | Canonical project context (always loaded by Claude Code) |`
|
|
9572
|
+
);
|
|
9573
|
+
lines.push(``);
|
|
9574
|
+
lines.push(`## Port Rule`);
|
|
9575
|
+
lines.push(``);
|
|
9576
|
+
lines.push(
|
|
9577
|
+
`Never hardcode port numbers. Resolve from \`.codebyplan/server.json\` \`port_allocations[]\`. Each entry carries \`port\`, \`label\`, and \`server_type\`.`
|
|
9578
|
+
);
|
|
9579
|
+
lines.push(``);
|
|
9580
|
+
lines.push(`## Git`);
|
|
9581
|
+
lines.push(``);
|
|
9582
|
+
lines.push(
|
|
9583
|
+
`Do not include any mention of AI tools or code-assistant products in git commit messages.`
|
|
9584
|
+
);
|
|
9585
|
+
lines.push(``);
|
|
9586
|
+
return lines.join("\n");
|
|
9587
|
+
}
|
|
9588
|
+
function generateAgentsMd(structureContent) {
|
|
9589
|
+
const cleanStructure = stripStructureSentinels(structureContent);
|
|
9590
|
+
const bodyContent = buildCuratedGuidance(cleanStructure);
|
|
9591
|
+
const managedBody = [
|
|
9592
|
+
managedStartMarker(AGENTS_SECTION_NAME),
|
|
9593
|
+
bodyContent.trimEnd(),
|
|
9594
|
+
managedEndMarker(AGENTS_SECTION_NAME)
|
|
9595
|
+
].join("\n");
|
|
9596
|
+
const hash = hashManagedContent({ [AGENTS_SECTION_NAME]: bodyContent });
|
|
9597
|
+
const hashLine = `${HASH_MARKER_PREFIX}${hash}${MANAGED_MARKER_SUFFIX}`;
|
|
9598
|
+
const header = [
|
|
9599
|
+
`<!-- GENERATED \u2014 do not hand-edit. Canonical source: .claude/CLAUDE.md -->`,
|
|
9600
|
+
`<!-- Regenerate: codebyplan claude generate -->`
|
|
9601
|
+
].join("\n");
|
|
9602
|
+
return [header, ``, managedBody, ``, hashLine, ``].join("\n");
|
|
9603
|
+
}
|
|
9604
|
+
function extractAgentsHash(content) {
|
|
9605
|
+
return extractManagedHash(content);
|
|
9606
|
+
}
|
|
9607
|
+
var AGENTS_SECTION_NAME;
|
|
9608
|
+
var init_agents_generator = __esm({
|
|
9609
|
+
"src/lib/agents-generator.ts"() {
|
|
9610
|
+
"use strict";
|
|
9611
|
+
init_readme_generator();
|
|
9612
|
+
AGENTS_SECTION_NAME = "agents-context";
|
|
9613
|
+
}
|
|
9614
|
+
});
|
|
9615
|
+
|
|
9329
9616
|
// src/cli/claude/generate.ts
|
|
9330
9617
|
var generate_exports = {};
|
|
9331
9618
|
__export(generate_exports, {
|
|
@@ -9353,6 +9640,7 @@ async function readPkgName(absPath) {
|
|
|
9353
9640
|
async function runGenerate(opts) {
|
|
9354
9641
|
const projectDir = opts.projectDir ?? opts["project-dir"] ?? process.cwd();
|
|
9355
9642
|
const dryRun = opts.dryRun ?? opts["dryRun"] ?? false;
|
|
9643
|
+
const check = opts.check ?? opts["check"] ?? false;
|
|
9356
9644
|
const rootDir = resolve8(projectDir);
|
|
9357
9645
|
let packageManager;
|
|
9358
9646
|
try {
|
|
@@ -9454,28 +9742,362 @@ async function runGenerate(opts) {
|
|
|
9454
9742
|
branchModel,
|
|
9455
9743
|
shipmentSurfaces: shipmentSurfaces.length > 0 ? shipmentSurfaces : void 0
|
|
9456
9744
|
};
|
|
9457
|
-
const
|
|
9745
|
+
const structureMdContent = generateStructureMd(config);
|
|
9746
|
+
const agentsContent = generateAgentsMd(structureMdContent);
|
|
9747
|
+
if (check) {
|
|
9748
|
+
const agentsMdPath2 = join30(rootDir, "AGENTS.md");
|
|
9749
|
+
let existingAgents = null;
|
|
9750
|
+
try {
|
|
9751
|
+
existingAgents = await readFile21(agentsMdPath2, "utf-8");
|
|
9752
|
+
} catch {
|
|
9753
|
+
existingAgents = null;
|
|
9754
|
+
}
|
|
9755
|
+
if (existingAgents === null) {
|
|
9756
|
+
process.stdout.write(`AGENTS.md missing
|
|
9757
|
+
`);
|
|
9758
|
+
process.exitCode = 1;
|
|
9759
|
+
} else {
|
|
9760
|
+
const existingHash = extractAgentsHash(existingAgents);
|
|
9761
|
+
const freshEmbeddedHash = extractAgentsHash(agentsContent);
|
|
9762
|
+
if (existingHash !== freshEmbeddedHash) {
|
|
9763
|
+
process.stdout.write(`AGENTS.md drifted
|
|
9764
|
+
`);
|
|
9765
|
+
process.exitCode = 1;
|
|
9766
|
+
} else {
|
|
9767
|
+
process.stdout.write(`AGENTS.md up to date
|
|
9768
|
+
`);
|
|
9769
|
+
}
|
|
9770
|
+
}
|
|
9771
|
+
return;
|
|
9772
|
+
}
|
|
9458
9773
|
if (dryRun) {
|
|
9459
9774
|
process.stdout.write(
|
|
9460
9775
|
`[dry-run] Would write: .claude/generated/structure.md
|
|
9461
9776
|
|
|
9462
9777
|
`
|
|
9463
9778
|
);
|
|
9464
|
-
process.stdout.write(
|
|
9779
|
+
process.stdout.write(structureMdContent);
|
|
9780
|
+
process.stdout.write(`
|
|
9781
|
+
[dry-run] Would write: AGENTS.md
|
|
9782
|
+
|
|
9783
|
+
`);
|
|
9784
|
+
process.stdout.write(agentsContent);
|
|
9465
9785
|
return;
|
|
9466
9786
|
}
|
|
9467
9787
|
const outputDir = join30(rootDir, ".claude", "generated");
|
|
9468
9788
|
await mkdir10(outputDir, { recursive: true });
|
|
9469
9789
|
const outputPath = join30(outputDir, "structure.md");
|
|
9470
|
-
await writeFile16(outputPath,
|
|
9790
|
+
await writeFile16(outputPath, structureMdContent, "utf-8");
|
|
9471
9791
|
process.stdout.write(`Wrote: .claude/generated/structure.md
|
|
9472
9792
|
`);
|
|
9793
|
+
const agentsMdPath = join30(rootDir, "AGENTS.md");
|
|
9794
|
+
let existingAgentsContent = null;
|
|
9795
|
+
try {
|
|
9796
|
+
existingAgentsContent = await readFile21(agentsMdPath, "utf-8");
|
|
9797
|
+
} catch {
|
|
9798
|
+
existingAgentsContent = null;
|
|
9799
|
+
}
|
|
9800
|
+
if (existingAgentsContent !== null && existingAgentsContent === agentsContent) {
|
|
9801
|
+
process.stdout.write(`Up to date: AGENTS.md
|
|
9802
|
+
`);
|
|
9803
|
+
} else {
|
|
9804
|
+
await writeFile16(agentsMdPath, agentsContent, "utf-8");
|
|
9805
|
+
process.stdout.write(`Wrote: AGENTS.md
|
|
9806
|
+
`);
|
|
9807
|
+
}
|
|
9473
9808
|
}
|
|
9474
9809
|
var init_generate = __esm({
|
|
9475
9810
|
"src/cli/claude/generate.ts"() {
|
|
9476
9811
|
"use strict";
|
|
9477
9812
|
init_tech_detect();
|
|
9478
9813
|
init_structure_generator();
|
|
9814
|
+
init_agents_generator();
|
|
9815
|
+
}
|
|
9816
|
+
});
|
|
9817
|
+
|
|
9818
|
+
// src/cli/claude/readme.ts
|
|
9819
|
+
var readme_exports = {};
|
|
9820
|
+
__export(readme_exports, {
|
|
9821
|
+
runReadme: () => runReadme,
|
|
9822
|
+
runReadmeCommand: () => runReadmeCommand
|
|
9823
|
+
});
|
|
9824
|
+
import { readFile as readFile22, writeFile as writeFile17 } from "node:fs/promises";
|
|
9825
|
+
import { join as join31, resolve as resolve9, relative as relative8 } from "node:path";
|
|
9826
|
+
async function readJsonFile4(filePath) {
|
|
9827
|
+
try {
|
|
9828
|
+
const raw = await readFile22(filePath, "utf-8");
|
|
9829
|
+
return JSON.parse(raw);
|
|
9830
|
+
} catch {
|
|
9831
|
+
return null;
|
|
9832
|
+
}
|
|
9833
|
+
}
|
|
9834
|
+
async function buildConfig(absPath, isRoot, allPackages, rootPkgJson, pkgJson) {
|
|
9835
|
+
let techStack;
|
|
9836
|
+
try {
|
|
9837
|
+
const techResult = await detectTechStack(absPath);
|
|
9838
|
+
const CATEGORY_LABELS = {
|
|
9839
|
+
"component-lib": "Component Library",
|
|
9840
|
+
graphql: "GraphQL",
|
|
9841
|
+
quality: "Code Quality"
|
|
9842
|
+
};
|
|
9843
|
+
const categoryMap = {};
|
|
9844
|
+
for (const entry of techResult.flat) {
|
|
9845
|
+
if (entry.name === SYNTHETIC_CARRIER_NAME) continue;
|
|
9846
|
+
if (!categoryMap[entry.category]) {
|
|
9847
|
+
categoryMap[entry.category] = [];
|
|
9848
|
+
}
|
|
9849
|
+
categoryMap[entry.category].push(entry.name);
|
|
9850
|
+
}
|
|
9851
|
+
if ((categoryMap["mobile"]?.length ?? 0) > 0) {
|
|
9852
|
+
const frameworkEntries = categoryMap["framework"] ?? [];
|
|
9853
|
+
const filtered = frameworkEntries.filter((n) => n !== "React");
|
|
9854
|
+
if (filtered.length > 0) {
|
|
9855
|
+
categoryMap["framework"] = filtered;
|
|
9856
|
+
} else {
|
|
9857
|
+
delete categoryMap["framework"];
|
|
9858
|
+
}
|
|
9859
|
+
}
|
|
9860
|
+
if (Object.keys(categoryMap).length > 0) {
|
|
9861
|
+
techStack = {};
|
|
9862
|
+
for (const [cat, names] of Object.entries(categoryMap)) {
|
|
9863
|
+
const label = CATEGORY_LABELS[cat] ?? cat.charAt(0).toUpperCase() + cat.slice(1);
|
|
9864
|
+
techStack[label] = [...names].sort().join(" + ");
|
|
9865
|
+
}
|
|
9866
|
+
}
|
|
9867
|
+
} catch {
|
|
9868
|
+
}
|
|
9869
|
+
const packages = isRoot ? allPackages : void 0;
|
|
9870
|
+
const packageManager = typeof rootPkgJson?.packageManager === "string" ? rootPkgJson.packageManager : void 0;
|
|
9871
|
+
const pmBase = packageManager?.split("@")[0] ?? "pnpm";
|
|
9872
|
+
const installCommand = `${pmBase} install`;
|
|
9873
|
+
return {
|
|
9874
|
+
name: pkgJson?.name ?? void 0,
|
|
9875
|
+
description: pkgJson?.description ?? void 0,
|
|
9876
|
+
scripts: pkgJson?.scripts && Object.keys(pkgJson.scripts).length > 0 ? pkgJson.scripts : void 0,
|
|
9877
|
+
packageManager,
|
|
9878
|
+
techStack,
|
|
9879
|
+
packages: packages && packages.length > 0 ? packages : void 0,
|
|
9880
|
+
installCommand
|
|
9881
|
+
};
|
|
9882
|
+
}
|
|
9883
|
+
async function discoverUnits(rootDir, rootPkgJson) {
|
|
9884
|
+
const units = [];
|
|
9885
|
+
const allPackages = [];
|
|
9886
|
+
const pkgJsonByPath = /* @__PURE__ */ new Map();
|
|
9887
|
+
units.push({
|
|
9888
|
+
name: "root",
|
|
9889
|
+
path: ".",
|
|
9890
|
+
absPath: rootDir,
|
|
9891
|
+
isRoot: true
|
|
9892
|
+
});
|
|
9893
|
+
pkgJsonByPath.set(rootDir, rootPkgJson);
|
|
9894
|
+
const discovered = await discoverMonorepoApps(rootDir);
|
|
9895
|
+
for (const app of discovered) {
|
|
9896
|
+
const pkgJson = await readJsonFile4(
|
|
9897
|
+
join31(app.absPath, "package.json")
|
|
9898
|
+
);
|
|
9899
|
+
pkgJsonByPath.set(app.absPath, pkgJson);
|
|
9900
|
+
allPackages.push({
|
|
9901
|
+
path: app.path,
|
|
9902
|
+
name: pkgJson?.name ?? app.name,
|
|
9903
|
+
purpose: pkgJson?.description ?? void 0
|
|
9904
|
+
});
|
|
9905
|
+
const isApp = app.path === "apps" || app.path.startsWith("apps/");
|
|
9906
|
+
if (!isApp && pkgJson?.private === true) continue;
|
|
9907
|
+
units.push({
|
|
9908
|
+
name: app.name,
|
|
9909
|
+
path: app.path,
|
|
9910
|
+
absPath: app.absPath,
|
|
9911
|
+
isRoot: false
|
|
9912
|
+
});
|
|
9913
|
+
}
|
|
9914
|
+
return { units, allPackages, pkgJsonByPath };
|
|
9915
|
+
}
|
|
9916
|
+
async function runReadme(opts) {
|
|
9917
|
+
const projectDir = opts.projectDir ?? opts["project-dir"] ?? process.cwd();
|
|
9918
|
+
const dryRun = opts.dryRun ?? opts["dryRun"] ?? false;
|
|
9919
|
+
const check = opts.check ?? opts["check"] ?? false;
|
|
9920
|
+
const init = opts.init ?? opts["init"] ?? false;
|
|
9921
|
+
const rootDir = resolve9(projectDir);
|
|
9922
|
+
const rootPkgJson = await readJsonFile4(
|
|
9923
|
+
join31(rootDir, "package.json")
|
|
9924
|
+
);
|
|
9925
|
+
const { units, allPackages, pkgJsonByPath } = await discoverUnits(
|
|
9926
|
+
rootDir,
|
|
9927
|
+
rootPkgJson
|
|
9928
|
+
);
|
|
9929
|
+
const driftUnits = [];
|
|
9930
|
+
const missingUnits = [];
|
|
9931
|
+
for (const unit of units) {
|
|
9932
|
+
const readmePath = join31(unit.absPath, "README.md");
|
|
9933
|
+
const relPath = unit.isRoot ? "README.md" : join31(relative8(rootDir, unit.absPath), "README.md");
|
|
9934
|
+
let existingContent = null;
|
|
9935
|
+
try {
|
|
9936
|
+
existingContent = await readFile22(readmePath, "utf-8");
|
|
9937
|
+
} catch {
|
|
9938
|
+
existingContent = null;
|
|
9939
|
+
}
|
|
9940
|
+
let config;
|
|
9941
|
+
try {
|
|
9942
|
+
config = await buildConfig(
|
|
9943
|
+
unit.absPath,
|
|
9944
|
+
unit.isRoot,
|
|
9945
|
+
allPackages,
|
|
9946
|
+
rootPkgJson,
|
|
9947
|
+
pkgJsonByPath.get(unit.absPath) ?? null
|
|
9948
|
+
);
|
|
9949
|
+
} catch (err) {
|
|
9950
|
+
process.stderr.write(
|
|
9951
|
+
`readme: error building config for ${relPath}: ${err instanceof Error ? err.message : String(err)}
|
|
9952
|
+
`
|
|
9953
|
+
);
|
|
9954
|
+
continue;
|
|
9955
|
+
}
|
|
9956
|
+
const sections = buildManagedSections(config);
|
|
9957
|
+
if (existingContent === null) {
|
|
9958
|
+
if (check) {
|
|
9959
|
+
missingUnits.push(relPath);
|
|
9960
|
+
continue;
|
|
9961
|
+
}
|
|
9962
|
+
const newContent = scaffoldReadme(config);
|
|
9963
|
+
if (dryRun) {
|
|
9964
|
+
process.stdout.write(
|
|
9965
|
+
`[dry-run] Would write (scaffold): ${relPath}
|
|
9966
|
+
|
|
9967
|
+
${newContent}
|
|
9968
|
+
`
|
|
9969
|
+
);
|
|
9970
|
+
} else {
|
|
9971
|
+
await writeFile17(readmePath, newContent, "utf-8");
|
|
9972
|
+
process.stdout.write(`Wrote (scaffold): ${relPath}
|
|
9973
|
+
`);
|
|
9974
|
+
}
|
|
9975
|
+
} else if (hasManagedMarkers(existingContent)) {
|
|
9976
|
+
const markerErrors = validateManagedMarkers(existingContent);
|
|
9977
|
+
if (markerErrors.length > 0) {
|
|
9978
|
+
process.stderr.write(
|
|
9979
|
+
`readme: skipping ${relPath} \u2014 malformed managed markers: ${markerErrors.join("; ")}
|
|
9980
|
+
`
|
|
9981
|
+
);
|
|
9982
|
+
if (check) {
|
|
9983
|
+
driftUnits.push(`${relPath} (malformed markers)`);
|
|
9984
|
+
}
|
|
9985
|
+
continue;
|
|
9986
|
+
}
|
|
9987
|
+
const existingHash = extractManagedHash(existingContent);
|
|
9988
|
+
const newHash = hashManagedContent(sections);
|
|
9989
|
+
if (existingHash === newHash) {
|
|
9990
|
+
if (!check) {
|
|
9991
|
+
process.stdout.write(`Up to date: ${relPath}
|
|
9992
|
+
`);
|
|
9993
|
+
}
|
|
9994
|
+
continue;
|
|
9995
|
+
}
|
|
9996
|
+
if (check) {
|
|
9997
|
+
driftUnits.push(relPath);
|
|
9998
|
+
continue;
|
|
9999
|
+
}
|
|
10000
|
+
const newContent = refreshManagedSections(existingContent, sections);
|
|
10001
|
+
if (dryRun) {
|
|
10002
|
+
process.stdout.write(
|
|
10003
|
+
`[dry-run] Would write (refresh): ${relPath}
|
|
10004
|
+
|
|
10005
|
+
${newContent}
|
|
10006
|
+
`
|
|
10007
|
+
);
|
|
10008
|
+
} else {
|
|
10009
|
+
await writeFile17(readmePath, newContent, "utf-8");
|
|
10010
|
+
process.stdout.write(`Wrote (refresh): ${relPath}
|
|
10011
|
+
`);
|
|
10012
|
+
}
|
|
10013
|
+
} else {
|
|
10014
|
+
if (init) {
|
|
10015
|
+
if (check) {
|
|
10016
|
+
driftUnits.push(`${relPath} (no markers, needs --init)`);
|
|
10017
|
+
continue;
|
|
10018
|
+
}
|
|
10019
|
+
const newContent = appendManagedBlock(existingContent, sections);
|
|
10020
|
+
if (dryRun) {
|
|
10021
|
+
process.stdout.write(
|
|
10022
|
+
`[dry-run] Would write (init): ${relPath}
|
|
10023
|
+
|
|
10024
|
+
${newContent}
|
|
10025
|
+
`
|
|
10026
|
+
);
|
|
10027
|
+
} else {
|
|
10028
|
+
await writeFile17(readmePath, newContent, "utf-8");
|
|
10029
|
+
process.stdout.write(`Wrote (init): ${relPath}
|
|
10030
|
+
`);
|
|
10031
|
+
}
|
|
10032
|
+
} else {
|
|
10033
|
+
process.stdout.write(`Skipped (no markers, use --init): ${relPath}
|
|
10034
|
+
`);
|
|
10035
|
+
}
|
|
10036
|
+
}
|
|
10037
|
+
}
|
|
10038
|
+
if (check) {
|
|
10039
|
+
if (driftUnits.length > 0 || missingUnits.length > 0) {
|
|
10040
|
+
if (driftUnits.length > 0) {
|
|
10041
|
+
process.stdout.write(
|
|
10042
|
+
`
|
|
10043
|
+
README drift detected:
|
|
10044
|
+
${driftUnits.map((f) => ` - ${f}`).join("\n")}
|
|
10045
|
+
`
|
|
10046
|
+
);
|
|
10047
|
+
}
|
|
10048
|
+
if (missingUnits.length > 0) {
|
|
10049
|
+
process.stdout.write(
|
|
10050
|
+
`
|
|
10051
|
+
README missing:
|
|
10052
|
+
${missingUnits.map((f) => ` - ${f}`).join("\n")}
|
|
10053
|
+
`
|
|
10054
|
+
);
|
|
10055
|
+
}
|
|
10056
|
+
process.exitCode = 1;
|
|
10057
|
+
} else {
|
|
10058
|
+
process.stdout.write(
|
|
10059
|
+
`README check passed \u2014 all managed sections current.
|
|
10060
|
+
`
|
|
10061
|
+
);
|
|
10062
|
+
}
|
|
10063
|
+
}
|
|
10064
|
+
}
|
|
10065
|
+
function appendManagedBlock(existing, sections) {
|
|
10066
|
+
let content = existing.trimEnd();
|
|
10067
|
+
const sectionKeys = Object.keys(sections).sort();
|
|
10068
|
+
for (const key of sectionKeys) {
|
|
10069
|
+
content += "\n\n" + managedStartMarker(key) + "\n" + sections[key].trimEnd() + "\n" + managedEndMarker(key);
|
|
10070
|
+
}
|
|
10071
|
+
const newHash = hashManagedContent(sections);
|
|
10072
|
+
content += `
|
|
10073
|
+
|
|
10074
|
+
${HASH_MARKER_PREFIX}${newHash}${MANAGED_MARKER_SUFFIX}`;
|
|
10075
|
+
content += "\n";
|
|
10076
|
+
return content;
|
|
10077
|
+
}
|
|
10078
|
+
async function runReadmeCommand(args) {
|
|
10079
|
+
const dryRun = args.includes("--dry-run");
|
|
10080
|
+
const check = args.includes("--check");
|
|
10081
|
+
const init = args.includes("--init");
|
|
10082
|
+
let projectDir;
|
|
10083
|
+
const pdIdx = args.indexOf("--project-dir");
|
|
10084
|
+
if (pdIdx !== -1) {
|
|
10085
|
+
const pdVal = args[pdIdx + 1];
|
|
10086
|
+
if (pdVal && !pdVal.startsWith("--")) {
|
|
10087
|
+
projectDir = pdVal;
|
|
10088
|
+
} else {
|
|
10089
|
+
process.stderr.write("error: --project-dir requires a path argument.\n");
|
|
10090
|
+
process.exitCode = 1;
|
|
10091
|
+
return;
|
|
10092
|
+
}
|
|
10093
|
+
}
|
|
10094
|
+
await runReadme({ dryRun, check, init, projectDir });
|
|
10095
|
+
}
|
|
10096
|
+
var init_readme = __esm({
|
|
10097
|
+
"src/cli/claude/readme.ts"() {
|
|
10098
|
+
"use strict";
|
|
10099
|
+
init_tech_detect();
|
|
10100
|
+
init_readme_generator();
|
|
9479
10101
|
}
|
|
9480
10102
|
});
|
|
9481
10103
|
|
|
@@ -9491,18 +10113,18 @@ __export(migrate_memory_exports, {
|
|
|
9491
10113
|
runMigrateMemory: () => runMigrateMemory
|
|
9492
10114
|
});
|
|
9493
10115
|
import {
|
|
9494
|
-
readFile as
|
|
9495
|
-
writeFile as
|
|
10116
|
+
readFile as readFile23,
|
|
10117
|
+
writeFile as writeFile18,
|
|
9496
10118
|
mkdir as mkdir11,
|
|
9497
10119
|
unlink as unlink4,
|
|
9498
10120
|
rmdir,
|
|
9499
10121
|
readdir as readdir4
|
|
9500
10122
|
} from "node:fs/promises";
|
|
9501
10123
|
import { existsSync as existsSync10 } from "node:fs";
|
|
9502
|
-
import { join as
|
|
10124
|
+
import { join as join32, resolve as resolve10, dirname as dirname11, sep as sep2 } from "node:path";
|
|
9503
10125
|
import { homedir as homedir8 } from "node:os";
|
|
9504
10126
|
function encodeProjectPath(absPath) {
|
|
9505
|
-
return
|
|
10127
|
+
return resolve10(absPath).replace(/[/\\]/g, "-");
|
|
9506
10128
|
}
|
|
9507
10129
|
function resolveAutoMemoryDir(opts) {
|
|
9508
10130
|
if (opts.autoMemoryDir) {
|
|
@@ -9510,7 +10132,7 @@ function resolveAutoMemoryDir(opts) {
|
|
|
9510
10132
|
}
|
|
9511
10133
|
const projectDir = opts.projectDir ?? process.cwd();
|
|
9512
10134
|
const encoded = encodeProjectPath(projectDir);
|
|
9513
|
-
return
|
|
10135
|
+
return join32(homedir8(), ".claude", "projects", encoded, "memory");
|
|
9514
10136
|
}
|
|
9515
10137
|
function parseFrontmatter(content) {
|
|
9516
10138
|
content = content.replace(/\r\n/g, "\n");
|
|
@@ -9576,10 +10198,10 @@ async function inventoryFiles(dir) {
|
|
|
9576
10198
|
}
|
|
9577
10199
|
const results = [];
|
|
9578
10200
|
for (const filename of filenames) {
|
|
9579
|
-
const sourcePath =
|
|
10201
|
+
const sourcePath = join32(dir, filename);
|
|
9580
10202
|
let raw;
|
|
9581
10203
|
try {
|
|
9582
|
-
raw = await
|
|
10204
|
+
raw = await readFile23(sourcePath, "utf-8");
|
|
9583
10205
|
} catch (err) {
|
|
9584
10206
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9585
10207
|
results.push({
|
|
@@ -9659,15 +10281,15 @@ function buildPlan(entries, opts) {
|
|
|
9659
10281
|
return plan;
|
|
9660
10282
|
}
|
|
9661
10283
|
async function applyPlan(plan, opts) {
|
|
9662
|
-
const projectDir =
|
|
10284
|
+
const projectDir = resolve10(opts.projectDir);
|
|
9663
10285
|
const dryRun = opts.dryRun ?? false;
|
|
9664
10286
|
for (const entry of plan.entries) {
|
|
9665
10287
|
if (entry.suggested_action !== "keep") continue;
|
|
9666
10288
|
if (!entry.suggested_target?.startsWith("nested:")) continue;
|
|
9667
10289
|
const relPath = entry.suggested_target.slice("nested:".length);
|
|
9668
|
-
const targetDir =
|
|
9669
|
-
const targetFile =
|
|
9670
|
-
if (!targetDir.startsWith(
|
|
10290
|
+
const targetDir = resolve10(join32(projectDir, relPath));
|
|
10291
|
+
const targetFile = join32(targetDir, "CLAUDE.md");
|
|
10292
|
+
if (!targetDir.startsWith(resolve10(projectDir) + sep2)) {
|
|
9671
10293
|
process.stderr.write(
|
|
9672
10294
|
`migrate-memory: skipping unsafe suggested_target "${entry.suggested_target}" \u2014 resolves outside projectDir
|
|
9673
10295
|
`
|
|
@@ -9685,8 +10307,8 @@ ${anchor}
|
|
|
9685
10307
|
if (dryRun) {
|
|
9686
10308
|
process.stdout.write(`[dry-run] Would create/append: ${targetFile}
|
|
9687
10309
|
`);
|
|
9688
|
-
if (
|
|
9689
|
-
|
|
10310
|
+
if (resolve10(entry.source_path).startsWith(
|
|
10311
|
+
resolve10(plan.auto_memory_dir) + sep2
|
|
9690
10312
|
)) {
|
|
9691
10313
|
process.stdout.write(
|
|
9692
10314
|
`[dry-run] Would delete migrated keep source: ${entry.source_path}
|
|
@@ -9698,13 +10320,13 @@ ${anchor}
|
|
|
9698
10320
|
await mkdir11(targetDir, { recursive: true });
|
|
9699
10321
|
let existing = "";
|
|
9700
10322
|
try {
|
|
9701
|
-
existing = await
|
|
10323
|
+
existing = await readFile23(targetFile, "utf-8");
|
|
9702
10324
|
} catch {
|
|
9703
10325
|
}
|
|
9704
10326
|
if (!existing.includes(anchor)) {
|
|
9705
|
-
await
|
|
10327
|
+
await writeFile18(targetFile, existing + appendContent, "utf-8");
|
|
9706
10328
|
}
|
|
9707
|
-
if (
|
|
10329
|
+
if (resolve10(entry.source_path).startsWith(resolve10(plan.auto_memory_dir) + sep2)) {
|
|
9708
10330
|
try {
|
|
9709
10331
|
await unlink4(entry.source_path);
|
|
9710
10332
|
} catch {
|
|
@@ -9716,7 +10338,7 @@ ${anchor}
|
|
|
9716
10338
|
);
|
|
9717
10339
|
}
|
|
9718
10340
|
}
|
|
9719
|
-
const rootClaudeMd =
|
|
10341
|
+
const rootClaudeMd = join32(projectDir, ".claude", "CLAUDE.md");
|
|
9720
10342
|
if (dryRun) {
|
|
9721
10343
|
process.stdout.write(
|
|
9722
10344
|
`[dry-run] Would ensure ${rootClaudeMd} contains: ${IMPORT_LINE}
|
|
@@ -9725,12 +10347,12 @@ ${anchor}
|
|
|
9725
10347
|
} else {
|
|
9726
10348
|
let claudeMdContent = "";
|
|
9727
10349
|
try {
|
|
9728
|
-
claudeMdContent = await
|
|
10350
|
+
claudeMdContent = await readFile23(rootClaudeMd, "utf-8");
|
|
9729
10351
|
} catch {
|
|
9730
10352
|
await mkdir11(dirname11(rootClaudeMd), { recursive: true });
|
|
9731
10353
|
}
|
|
9732
10354
|
if (!claudeMdContent.includes(IMPORT_LINE)) {
|
|
9733
|
-
await
|
|
10355
|
+
await writeFile18(
|
|
9734
10356
|
rootClaudeMd,
|
|
9735
10357
|
claudeMdContent + `
|
|
9736
10358
|
${IMPORT_LINE}
|
|
@@ -9741,8 +10363,8 @@ ${IMPORT_LINE}
|
|
|
9741
10363
|
}
|
|
9742
10364
|
for (const entry of plan.entries) {
|
|
9743
10365
|
if (entry.suggested_action !== "drop") continue;
|
|
9744
|
-
if (!
|
|
9745
|
-
|
|
10366
|
+
if (!resolve10(entry.source_path).startsWith(
|
|
10367
|
+
resolve10(plan.auto_memory_dir) + sep2
|
|
9746
10368
|
)) {
|
|
9747
10369
|
process.stderr.write(
|
|
9748
10370
|
`migrate-memory: skipping delete of "${entry.source_path}" \u2014 resolves outside auto_memory_dir
|
|
@@ -9760,13 +10382,13 @@ ${IMPORT_LINE}
|
|
|
9760
10382
|
} catch {
|
|
9761
10383
|
}
|
|
9762
10384
|
}
|
|
9763
|
-
const memoryMd =
|
|
9764
|
-
const safeRmdirBase =
|
|
10385
|
+
const memoryMd = join32(plan.auto_memory_dir, "MEMORY.md");
|
|
10386
|
+
const safeRmdirBase = join32(homedir8(), ".claude", "projects");
|
|
9765
10387
|
if (dryRun) {
|
|
9766
10388
|
process.stdout.write(`[dry-run] Would delete MEMORY.md: ${memoryMd}
|
|
9767
10389
|
`);
|
|
9768
10390
|
} else {
|
|
9769
|
-
if (
|
|
10391
|
+
if (resolve10(plan.auto_memory_dir).startsWith(safeRmdirBase + sep2)) {
|
|
9770
10392
|
try {
|
|
9771
10393
|
await unlink4(memoryMd);
|
|
9772
10394
|
} catch {
|
|
@@ -9784,7 +10406,7 @@ ${IMPORT_LINE}
|
|
|
9784
10406
|
`
|
|
9785
10407
|
);
|
|
9786
10408
|
} else {
|
|
9787
|
-
if (!
|
|
10409
|
+
if (!resolve10(plan.auto_memory_dir).startsWith(safeRmdirBase + sep2)) {
|
|
9788
10410
|
process.stderr.write(
|
|
9789
10411
|
`migrate-memory: skipping rmdir of "${plan.auto_memory_dir}" \u2014 not under ~/.claude/projects
|
|
9790
10412
|
`
|
|
@@ -9814,7 +10436,7 @@ async function runMigrateMemory(opts) {
|
|
|
9814
10436
|
if (applyFile) {
|
|
9815
10437
|
let planJson;
|
|
9816
10438
|
try {
|
|
9817
|
-
planJson = await
|
|
10439
|
+
planJson = await readFile23(resolve10(applyFile), "utf-8");
|
|
9818
10440
|
} catch (err) {
|
|
9819
10441
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9820
10442
|
process.stderr.write(
|
|
@@ -9886,11 +10508,11 @@ var init_migrate_memory = __esm({
|
|
|
9886
10508
|
// src/index.ts
|
|
9887
10509
|
init_version();
|
|
9888
10510
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
9889
|
-
import { resolve as
|
|
10511
|
+
import { resolve as resolve11 } from "node:path";
|
|
9890
10512
|
void (async () => {
|
|
9891
10513
|
if (!process.env.CODEBYPLAN_API_KEY) {
|
|
9892
10514
|
try {
|
|
9893
|
-
const envPath =
|
|
10515
|
+
const envPath = resolve11(process.cwd(), ".env.local");
|
|
9894
10516
|
const content = readFileSync10(envPath, "utf-8");
|
|
9895
10517
|
for (const line of content.split("\n")) {
|
|
9896
10518
|
const trimmed = line.trim();
|
|
@@ -10096,11 +10718,17 @@ void (async () => {
|
|
|
10096
10718
|
process.exit(1);
|
|
10097
10719
|
}
|
|
10098
10720
|
const { runGenerate: runGenerate2 } = await Promise.resolve().then(() => (init_generate(), generate_exports));
|
|
10721
|
+
const check = process.argv.slice(4).includes("--check");
|
|
10099
10722
|
await runGenerate2(
|
|
10100
|
-
parsed.projectDir != null ? { ...parsed.opts, projectDir: parsed.projectDir } : parsed.opts
|
|
10723
|
+
parsed.projectDir != null ? { ...parsed.opts, check, projectDir: parsed.projectDir } : { ...parsed.opts, check }
|
|
10101
10724
|
);
|
|
10102
10725
|
process.exit(process.exitCode ?? 0);
|
|
10103
10726
|
}
|
|
10727
|
+
if (subcommand === "readme") {
|
|
10728
|
+
const { runReadmeCommand: runReadmeCommand2 } = await Promise.resolve().then(() => (init_readme(), readme_exports));
|
|
10729
|
+
await runReadmeCommand2(process.argv.slice(4));
|
|
10730
|
+
process.exit(process.exitCode ?? 0);
|
|
10731
|
+
}
|
|
10104
10732
|
if (subcommand === "migrate-memory") {
|
|
10105
10733
|
if (parsed === null) {
|
|
10106
10734
|
process.exit(1);
|
|
@@ -10124,6 +10752,7 @@ void (async () => {
|
|
|
10124
10752
|
--write-cache Write result to .codebyplan/claude-status.local.json
|
|
10125
10753
|
--quiet Suppress stdout output
|
|
10126
10754
|
codebyplan claude generate [flags] Write .claude/generated/structure.md from local config
|
|
10755
|
+
codebyplan claude readme [flags] Generate / refresh README.md for outward-facing units
|
|
10127
10756
|
codebyplan claude migrate-memory [flags] Inventory auto-memory files and emit migration plan
|
|
10128
10757
|
|
|
10129
10758
|
Flags (apply to install/update/uninstall):
|
|
@@ -10142,6 +10771,13 @@ void (async () => {
|
|
|
10142
10771
|
Flags (apply to generate):
|
|
10143
10772
|
--project-dir <path> Override the project root (default: cwd)
|
|
10144
10773
|
--dry-run Print what would be written, write nothing
|
|
10774
|
+
--check Exit non-zero when AGENTS.md is missing or drifted
|
|
10775
|
+
|
|
10776
|
+
Flags (apply to readme):
|
|
10777
|
+
--project-dir <path> Override the project root (default: cwd)
|
|
10778
|
+
--dry-run Print what would be written, write nothing
|
|
10779
|
+
--check Exit non-zero on drift or missing READMEs
|
|
10780
|
+
--init Append managed block to marker-less existing READMEs
|
|
10145
10781
|
`);
|
|
10146
10782
|
process.exit(0);
|
|
10147
10783
|
}
|
|
@@ -10206,6 +10842,7 @@ void (async () => {
|
|
|
10206
10842
|
codebyplan claude update [flags] Update installed assets to latest versions
|
|
10207
10843
|
codebyplan claude uninstall [flags] Remove installed assets from ./.claude/
|
|
10208
10844
|
codebyplan claude generate [flags] Write .claude/generated/structure.md from local config
|
|
10845
|
+
codebyplan claude readme [flags] Generate / refresh README.md for outward-facing units
|
|
10209
10846
|
codebyplan claude migrate-memory [flags] Inventory auto-memory files and emit migration plan
|
|
10210
10847
|
|
|
10211
10848
|
Flags (install/update/uninstall):
|
|
@@ -10221,6 +10858,13 @@ void (async () => {
|
|
|
10221
10858
|
Flags (generate):
|
|
10222
10859
|
--project-dir <path> Override the project root (default: cwd)
|
|
10223
10860
|
--dry-run Print what would be written, write nothing
|
|
10861
|
+
--check Exit non-zero when AGENTS.md is missing or drifted
|
|
10862
|
+
|
|
10863
|
+
Flags (readme):
|
|
10864
|
+
--project-dir <path> Override the project root (default: cwd)
|
|
10865
|
+
--dry-run Print what would be written, write nothing
|
|
10866
|
+
--check Exit non-zero on drift or missing READMEs
|
|
10867
|
+
--init Append managed block to marker-less existing READMEs
|
|
10224
10868
|
|
|
10225
10869
|
Flags (migrate-memory):
|
|
10226
10870
|
--project-dir <path> Override the project root (default: cwd)
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@ This file is the **consumer contract** for DocsByPlan: what the MCP tools are, w
|
|
|
8
8
|
|
|
9
9
|
## What DocsByPlan Is
|
|
10
10
|
|
|
11
|
-
A DB-backed, version-aware library-doc retrieval service exposed via MCP at `codebyplan.com/mcp`. It replaces the retired `vendor/` filesystem mirror. Docs are ingested by the `apps/docs-ingest` worker, chunked and ranked by trust score, and served to agents on demand. The DB is the sole source of truth — there are no local files to read.
|
|
11
|
+
A DB-backed, version-aware library-doc retrieval service exposed via MCP at `mcp.codebyplan.com/mcp`. It replaces the retired `vendor/` filesystem mirror. Docs are ingested by the `apps/docs-ingest` worker, chunked and ranked by trust score, and served to agents on demand. The DB is the sole source of truth — there are no local files to read.
|
|
12
12
|
|
|
13
13
|
Purpose: Claude (planner + executor agents + the orchestrator) consults DocsByPlan **before** writing library-specific code, so that:
|
|
14
14
|
|
|
@@ -133,7 +133,7 @@ This file answers one question for one audience: **"As an agent (planner or exec
|
|
|
133
133
|
|---------|-----------|
|
|
134
134
|
| Ingest pipeline | `apps/docs-ingest` |
|
|
135
135
|
| Register a new library | `/cbp-add-library {pkg}` |
|
|
136
|
-
| MCP tool endpoint | `codebyplan.com/mcp` |
|
|
136
|
+
| MCP tool endpoint | `mcp.codebyplan.com/mcp` |
|
|
137
137
|
| Loading rule registration | `.claude/rules/context-file-loading.md` (Phase 2.6 / Step 3.4 mapping rows) |
|
|
138
138
|
| Planner integration | `packages/codebyplan-package/templates/agents/task-planner.md` Phase 2.6 |
|
|
139
139
|
| Executor integration | `packages/codebyplan-package/templates/agents/round-executor.md` Step 3.4 |
|