codebyplan 1.13.67 → 1.13.68

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.
@@ -16,7 +16,7 @@ export interface GenerateOpts {
16
16
  projectDir?: string;
17
17
  /** Print the would-be content to stdout, write nothing. */
18
18
  dryRun?: boolean;
19
- /** Exit non-zero when AGENTS.md is missing or drifted. Read-only — writes nothing. */
19
+ /** Exit non-zero when AGENTS.md or structure.md is missing or drifted. Read-only — writes nothing. */
20
20
  check?: boolean;
21
21
  }
22
22
  export declare function runGenerate(opts: GenerateOpts | Record<string, unknown>): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/cli/claude/generate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAqBH,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sFAAsF;IACtF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAyDD,wBAAsB,WAAW,CAC/B,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3C,OAAO,CAAC,IAAI,CAAC,CA4Of"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/cli/claude/generate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAqBH,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sGAAsG;IACtG,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAyDD,wBAAsB,WAAW,CAC/B,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3C,OAAO,CAAC,IAAI,CAAC,CAiOf"}
@@ -1 +1 @@
1
- {"version":3,"file":"readme.d.ts","sourceRoot":"","sources":["../../../src/cli/claude/readme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA4BH,MAAM,WAAW,UAAU;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA4KD,wBAAsB,SAAS,CAC7B,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACzC,OAAO,CAAC,IAAI,CAAC,CAkLf;AAmCD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBpE"}
1
+ {"version":3,"file":"readme.d.ts","sourceRoot":"","sources":["../../../src/cli/claude/readme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA4BH,MAAM,WAAW,UAAU;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA4ID,wBAAsB,SAAS,CAC7B,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACzC,OAAO,CAAC,IAAI,CAAC,CAkLf;AAmCD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBpE"}
package/dist/cli.js CHANGED
@@ -48,7 +48,7 @@ var VERSION, PACKAGE_NAME;
48
48
  var init_version = __esm({
49
49
  "src/lib/version.ts"() {
50
50
  "use strict";
51
- VERSION = "1.13.67";
51
+ VERSION = "1.13.68";
52
52
  PACKAGE_NAME = "codebyplan";
53
53
  }
54
54
  });
@@ -41334,6 +41334,45 @@ var init_verify_parity2 = __esm({
41334
41334
  }
41335
41335
  });
41336
41336
 
41337
+ // src/lib/tech-stack-render.ts
41338
+ function buildTechStackDisplay(flat) {
41339
+ const categoryMap = {};
41340
+ for (const entry of flat) {
41341
+ if (entry.name === SYNTHETIC_CARRIER_NAME) continue;
41342
+ if (!categoryMap[entry.category]) {
41343
+ categoryMap[entry.category] = [];
41344
+ }
41345
+ categoryMap[entry.category].push(entry.name);
41346
+ }
41347
+ if ((categoryMap["mobile"]?.length ?? 0) > 0) {
41348
+ const frameworkEntries = categoryMap["framework"] ?? [];
41349
+ const filtered = frameworkEntries.filter((n) => n !== "React");
41350
+ if (filtered.length > 0) {
41351
+ categoryMap["framework"] = filtered;
41352
+ } else {
41353
+ delete categoryMap["framework"];
41354
+ }
41355
+ }
41356
+ const techStack = {};
41357
+ for (const [cat, names] of Object.entries(categoryMap)) {
41358
+ const label = CATEGORY_LABELS[cat] ?? cat.charAt(0).toUpperCase() + cat.slice(1);
41359
+ techStack[label] = [...names].sort().join(" + ");
41360
+ }
41361
+ return { categoryMap, techStack };
41362
+ }
41363
+ var CATEGORY_LABELS;
41364
+ var init_tech_stack_render = __esm({
41365
+ "src/lib/tech-stack-render.ts"() {
41366
+ "use strict";
41367
+ init_tech_detect();
41368
+ CATEGORY_LABELS = {
41369
+ "component-lib": "Component Library",
41370
+ graphql: "GraphQL",
41371
+ quality: "Code Quality"
41372
+ };
41373
+ }
41374
+ });
41375
+
41337
41376
  // src/lib/structure-generator.ts
41338
41377
  function renderTechStack(techStack) {
41339
41378
  const entries = Object.entries(techStack).filter(([, value]) => value.trim().length > 0).sort(([a], [b]) => a.localeCompare(b));
@@ -41821,28 +41860,7 @@ async function runGenerate(opts) {
41821
41860
  });
41822
41861
  }
41823
41862
  const techResult = await detectTechStack(rootDir);
41824
- const CATEGORY_LABELS = {
41825
- "component-lib": "Component Library",
41826
- graphql: "GraphQL",
41827
- quality: "Code Quality"
41828
- };
41829
- const categoryMap = {};
41830
- for (const entry of techResult.flat) {
41831
- if (entry.name === SYNTHETIC_CARRIER_NAME) continue;
41832
- if (!categoryMap[entry.category]) {
41833
- categoryMap[entry.category] = [];
41834
- }
41835
- categoryMap[entry.category].push(entry.name);
41836
- }
41837
- if ((categoryMap["mobile"]?.length ?? 0) > 0) {
41838
- const frameworkEntries = categoryMap["framework"] ?? [];
41839
- const filtered = frameworkEntries.filter((n) => n !== "React");
41840
- if (filtered.length > 0) {
41841
- categoryMap["framework"] = filtered;
41842
- } else {
41843
- delete categoryMap["framework"];
41844
- }
41845
- }
41863
+ const { categoryMap, techStack } = buildTechStackDisplay(techResult.flat);
41846
41864
  const hasNextjs = (categoryMap["framework"] ?? []).some(
41847
41865
  (n) => n.toLowerCase().includes("next")
41848
41866
  );
@@ -41850,11 +41868,6 @@ async function runGenerate(opts) {
41850
41868
  if (p.server_type === "nextjs" && !hasNextjs) return false;
41851
41869
  return true;
41852
41870
  });
41853
- const techStack = {};
41854
- for (const [cat, names] of Object.entries(categoryMap)) {
41855
- const label = CATEGORY_LABELS[cat] ?? cat.charAt(0).toUpperCase() + cat.slice(1);
41856
- techStack[label] = [...names].sort().join(" + ");
41857
- }
41858
41871
  const config = {
41859
41872
  techStack: Object.keys(techStack).length > 0 ? techStack : void 0,
41860
41873
  packageManager,
@@ -41889,6 +41902,25 @@ async function runGenerate(opts) {
41889
41902
  `);
41890
41903
  }
41891
41904
  }
41905
+ const structurePath = join56(rootDir, ".claude", "generated", "structure.md");
41906
+ let existingStructureCheck = null;
41907
+ try {
41908
+ existingStructureCheck = await readFile30(structurePath, "utf-8");
41909
+ } catch {
41910
+ existingStructureCheck = null;
41911
+ }
41912
+ if (existingStructureCheck === null) {
41913
+ process.stdout.write(`structure.md missing
41914
+ `);
41915
+ process.exitCode = 1;
41916
+ } else if (existingStructureCheck !== structureMdContent) {
41917
+ process.stdout.write(`structure.md drifted
41918
+ `);
41919
+ process.exitCode = 1;
41920
+ } else {
41921
+ process.stdout.write(`.claude/generated/structure.md up to date
41922
+ `);
41923
+ }
41892
41924
  return;
41893
41925
  }
41894
41926
  if (dryRun) {
@@ -41908,9 +41940,20 @@ async function runGenerate(opts) {
41908
41940
  const outputDir = join56(rootDir, ".claude", "generated");
41909
41941
  await mkdir14(outputDir, { recursive: true });
41910
41942
  const outputPath = join56(outputDir, "structure.md");
41911
- await writeFile20(outputPath, structureMdContent, "utf-8");
41912
- process.stdout.write(`Wrote: .claude/generated/structure.md
41943
+ let existingStructure = null;
41944
+ try {
41945
+ existingStructure = await readFile30(outputPath, "utf-8");
41946
+ } catch {
41947
+ existingStructure = null;
41948
+ }
41949
+ if (existingStructure !== null && existingStructure === structureMdContent) {
41950
+ process.stdout.write(`Up to date: .claude/generated/structure.md
41951
+ `);
41952
+ } else {
41953
+ await writeFile20(outputPath, structureMdContent, "utf-8");
41954
+ process.stdout.write(`Wrote: .claude/generated/structure.md
41913
41955
  `);
41956
+ }
41914
41957
  const agentsMdPath = join56(rootDir, "AGENTS.md");
41915
41958
  let existingAgentsContent = null;
41916
41959
  try {
@@ -41931,6 +41974,7 @@ var init_generate = __esm({
41931
41974
  "src/cli/claude/generate.ts"() {
41932
41975
  "use strict";
41933
41976
  init_tech_detect();
41977
+ init_tech_stack_render();
41934
41978
  init_structure_generator();
41935
41979
  init_agents_generator();
41936
41980
  }
@@ -41956,34 +42000,9 @@ async function buildConfig(absPath, isRoot, allPackages, rootPkgJson, pkgJson) {
41956
42000
  let techStack;
41957
42001
  try {
41958
42002
  const techResult = await detectTechStack(absPath);
41959
- const CATEGORY_LABELS = {
41960
- "component-lib": "Component Library",
41961
- graphql: "GraphQL",
41962
- quality: "Code Quality"
41963
- };
41964
- const categoryMap = {};
41965
- for (const entry of techResult.flat) {
41966
- if (entry.name === SYNTHETIC_CARRIER_NAME) continue;
41967
- if (!categoryMap[entry.category]) {
41968
- categoryMap[entry.category] = [];
41969
- }
41970
- categoryMap[entry.category].push(entry.name);
41971
- }
41972
- if ((categoryMap["mobile"]?.length ?? 0) > 0) {
41973
- const frameworkEntries = categoryMap["framework"] ?? [];
41974
- const filtered = frameworkEntries.filter((n) => n !== "React");
41975
- if (filtered.length > 0) {
41976
- categoryMap["framework"] = filtered;
41977
- } else {
41978
- delete categoryMap["framework"];
41979
- }
41980
- }
41981
- if (Object.keys(categoryMap).length > 0) {
41982
- techStack = {};
41983
- for (const [cat, names] of Object.entries(categoryMap)) {
41984
- const label = CATEGORY_LABELS[cat] ?? cat.charAt(0).toUpperCase() + cat.slice(1);
41985
- techStack[label] = [...names].sort().join(" + ");
41986
- }
42003
+ const { techStack: ts } = buildTechStackDisplay(techResult.flat);
42004
+ if (Object.keys(ts).length > 0) {
42005
+ techStack = ts;
41987
42006
  }
41988
42007
  } catch {
41989
42008
  }
@@ -42218,6 +42237,7 @@ var init_readme = __esm({
42218
42237
  "src/cli/claude/readme.ts"() {
42219
42238
  "use strict";
42220
42239
  init_tech_detect();
42240
+ init_tech_stack_render();
42221
42241
  init_readme_generator();
42222
42242
  }
42223
42243
  });
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Pure, I/O-free helper for rendering a flat TechStackEntry[] into the
3
+ * display structures used by `codebyplan claude generate` and
4
+ * `codebyplan claude readme`.
5
+ *
6
+ * Both callers previously contained identical copies of this logic.
7
+ * Extracted here so changes propagate uniformly and the logic can be
8
+ * unit-tested in isolation.
9
+ */
10
+ import type { TechStackEntry } from "./types.js";
11
+ /** Human-readable labels for multi-word category keys. */
12
+ export declare const CATEGORY_LABELS: Record<string, string>;
13
+ export interface TechStackRenderResult {
14
+ /** Per-category name lists, post-F5 mobile guard. */
15
+ categoryMap: Record<string, string[]>;
16
+ /** Display-ready map: label → sorted joined names (e.g. "Framework" → "Next.js + React"). */
17
+ techStack: Record<string, string>;
18
+ }
19
+ /**
20
+ * Build category and display maps from a flat TechStackEntry array.
21
+ *
22
+ * Behaviour:
23
+ * 1. Iterates `flat`, skipping entries where `entry.name === SYNTHETIC_CARRIER_NAME`.
24
+ * 2. F5 mobile guard: when `categoryMap["mobile"]` is non-empty, strips "React"
25
+ * from `categoryMap["framework"]`; deletes the key entirely if that leaves it empty.
26
+ * 3. Builds `techStack` by joining sorted names per category under a human-readable label.
27
+ * 4. Empty input → `{ categoryMap: {}, techStack: {} }`.
28
+ */
29
+ export declare function buildTechStackDisplay(flat: TechStackEntry[]): TechStackRenderResult;
30
+ //# sourceMappingURL=tech-stack-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tech-stack-render.d.ts","sourceRoot":"","sources":["../../src/lib/tech-stack-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,0DAA0D;AAC1D,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAIlD,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACtC,6FAA6F;IAC7F,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,cAAc,EAAE,GACrB,qBAAqB,CAgCvB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebyplan",
3
- "version": "1.13.67",
3
+ "version": "1.13.68",
4
4
  "description": "CLI for CodeByPlan — AI-powered development planning and tracking",
5
5
  "type": "module",
6
6
  "bin": {