@contentrain/mcp 1.2.0 → 1.3.0

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.
Files changed (154) hide show
  1. package/README.md +93 -25
  2. package/dist/annotations-Clhbw2lh.mjs +126 -0
  3. package/dist/annotations-Clhbw2lh.mjs.map +1 -0
  4. package/dist/{apply-manager-BkPMfpsN.mjs → apply-manager-D5ym5Jba.mjs} +7 -7
  5. package/dist/{apply-manager-BkPMfpsN.mjs.map → apply-manager-D5ym5Jba.mjs.map} +1 -1
  6. package/dist/{astro-parser-BJ-54JGe.mjs → astro-parser-B-nLl0zE.mjs} +3 -3
  7. package/dist/{astro-parser-BJ-54JGe.mjs.map → astro-parser-B-nLl0zE.mjs.map} +1 -1
  8. package/dist/{branch-lifecycle-wGJg25LT.mjs → branch-lifecycle-CFVpTpNT.mjs} +33 -3
  9. package/dist/{branch-lifecycle-wGJg25LT.mjs.map → branch-lifecycle-CFVpTpNT.mjs.map} +1 -1
  10. package/dist/{compiler-rIC4ETHv.mjs → compiler-k4yttlzM.mjs} +2 -2
  11. package/dist/{compiler-rIC4ETHv.mjs.map → compiler-k4yttlzM.mjs.map} +1 -1
  12. package/dist/{compiler-sfc.cjs-BbD04rn_.mjs → compiler-sfc.cjs-D0d_OicF.mjs} +2 -2
  13. package/dist/{compiler-sfc.cjs-BbD04rn_.mjs.map → compiler-sfc.cjs-D0d_OicF.mjs.map} +1 -1
  14. package/dist/config-BIl5Ybj0.mjs +40 -0
  15. package/dist/config-BIl5Ybj0.mjs.map +1 -0
  16. package/dist/content-manager-DqDLSNQ-.d.mts +63 -0
  17. package/dist/content-manager-DqDLSNQ-.d.mts.map +1 -0
  18. package/dist/context-J0OU9Nfp.mjs +102 -0
  19. package/dist/context-J0OU9Nfp.mjs.map +1 -0
  20. package/dist/contracts-DfL0BfrD.mjs +2 -0
  21. package/dist/core/apply-manager.mjs +10 -10
  22. package/dist/core/config.d.mts +13 -0
  23. package/dist/core/config.d.mts.map +1 -1
  24. package/dist/core/config.mjs +2 -3
  25. package/dist/core/content-manager.d.mts +2 -45
  26. package/dist/core/content-manager.mjs +3 -4
  27. package/dist/core/context.d.mts +32 -2
  28. package/dist/core/context.d.mts.map +1 -1
  29. package/dist/core/context.mjs +7 -7
  30. package/dist/core/contracts/index.d.mts +2 -0
  31. package/dist/core/contracts/index.mjs +2 -0
  32. package/dist/core/doctor.d.mts +76 -0
  33. package/dist/core/doctor.d.mts.map +1 -0
  34. package/dist/core/doctor.mjs +8 -0
  35. package/dist/core/graph-builder.mjs +3 -4
  36. package/dist/core/meta-manager.mjs +2 -3
  37. package/dist/core/model-manager.d.mts +34 -1
  38. package/dist/core/model-manager.d.mts.map +1 -1
  39. package/dist/core/model-manager.mjs +3 -4
  40. package/dist/core/ops/index.d.mts +137 -0
  41. package/dist/core/ops/index.d.mts.map +1 -0
  42. package/dist/core/ops/index.mjs +4 -0
  43. package/dist/core/overlay-reader.d.mts +42 -0
  44. package/dist/core/overlay-reader.d.mts.map +1 -0
  45. package/dist/core/overlay-reader.mjs +2 -0
  46. package/dist/core/scan-config.mjs +2 -3
  47. package/dist/core/scanner.mjs +4 -5
  48. package/dist/core/validator/index.d.mts +129 -0
  49. package/dist/core/validator/index.d.mts.map +1 -0
  50. package/dist/core/validator/index.mjs +6 -0
  51. package/dist/{detect-DinOQAmK.mjs → detect-DL9mFmaS.mjs} +2 -2
  52. package/dist/{detect-DinOQAmK.mjs.map → detect-DL9mFmaS.mjs.map} +1 -1
  53. package/dist/doctor-CgBoT6h1.mjs +338 -0
  54. package/dist/doctor-CgBoT6h1.mjs.map +1 -0
  55. package/dist/{fs-BnIQ4dKj.mjs → fs-DLbVB-Ek.mjs} +2 -2
  56. package/dist/fs-DLbVB-Ek.mjs.map +1 -0
  57. package/dist/git/branch-lifecycle.d.mts +30 -1
  58. package/dist/git/branch-lifecycle.d.mts.map +1 -1
  59. package/dist/git/branch-lifecycle.mjs +4 -5
  60. package/dist/git/transaction.d.mts +2 -2
  61. package/dist/git/transaction.d.mts.map +1 -1
  62. package/dist/git/transaction.mjs +8 -8
  63. package/dist/{graph-builder-tM7zj-SX.mjs → graph-builder-DXv2JEp-.mjs} +3 -3
  64. package/dist/{graph-builder-tM7zj-SX.mjs.map → graph-builder-DXv2JEp-.mjs.map} +1 -1
  65. package/dist/{id-DV_T9Ic8.mjs → id-CIO9s0x_.mjs} +1 -1
  66. package/dist/{id-DV_T9Ic8.mjs.map → id-CIO9s0x_.mjs.map} +1 -1
  67. package/dist/index-D0wQJSgs.d.mts +2 -0
  68. package/dist/index.mjs +22 -17
  69. package/dist/index.mjs.map +1 -1
  70. package/dist/local-DvP4Y4T-.mjs +182 -0
  71. package/dist/local-DvP4Y4T-.mjs.map +1 -0
  72. package/dist/{meta-manager--0IwAPCl.mjs → meta-manager-C900rEyG.mjs} +2 -2
  73. package/dist/{meta-manager--0IwAPCl.mjs.map → meta-manager-C900rEyG.mjs.map} +1 -1
  74. package/dist/{model-manager-DW_fOGRM.mjs → model-manager-BhLsUgaB.mjs} +241 -49
  75. package/dist/model-manager-BhLsUgaB.mjs.map +1 -0
  76. package/dist/{node-Cbq5eR5i.mjs → node-DN9hZeil.mjs} +1 -1
  77. package/dist/{node-Cbq5eR5i.mjs.map → node-DN9hZeil.mjs.map} +1 -1
  78. package/dist/ops-DjEWi5Wa.mjs +486 -0
  79. package/dist/ops-DjEWi5Wa.mjs.map +1 -0
  80. package/dist/overlay-reader-DOdyDRIv.mjs +74 -0
  81. package/dist/overlay-reader-DOdyDRIv.mjs.map +1 -0
  82. package/dist/paths-C3xNyc7z.mjs +52 -0
  83. package/dist/paths-C3xNyc7z.mjs.map +1 -0
  84. package/dist/paths-CYl5vCBD.mjs +54 -0
  85. package/dist/paths-CYl5vCBD.mjs.map +1 -0
  86. package/dist/providers/github/index.d.mts +144 -0
  87. package/dist/providers/github/index.d.mts.map +1 -0
  88. package/dist/providers/github/index.mjs +414 -0
  89. package/dist/providers/github/index.mjs.map +1 -0
  90. package/dist/providers/gitlab/index.d.mts +158 -0
  91. package/dist/providers/gitlab/index.d.mts.map +1 -0
  92. package/dist/providers/gitlab/index.mjs +361 -0
  93. package/dist/providers/gitlab/index.mjs.map +1 -0
  94. package/dist/providers/local/index.d.mts +106 -0
  95. package/dist/providers/local/index.d.mts.map +1 -0
  96. package/dist/providers/local/index.mjs +12 -0
  97. package/dist/{scan-config-QgnJ1-52.mjs → scan-config-jC6XmiqF.mjs} +2 -2
  98. package/dist/{scan-config-QgnJ1-52.mjs.map → scan-config-jC6XmiqF.mjs.map} +1 -1
  99. package/dist/{scanner-CQOxARUU.mjs → scanner-DKMwc03k.mjs} +26 -8
  100. package/dist/scanner-DKMwc03k.mjs.map +1 -0
  101. package/dist/serialization-B1CEzR4H.mjs +2 -0
  102. package/dist/server/http/index.d.mts +65 -0
  103. package/dist/server/http/index.d.mts.map +1 -0
  104. package/dist/server/http/index.mjs +137 -0
  105. package/dist/server/http/index.mjs.map +1 -0
  106. package/dist/{server-DfWRpzdP.mjs → server-B1OJrUQ9.mjs} +486 -355
  107. package/dist/server-B1OJrUQ9.mjs.map +1 -0
  108. package/dist/server-WqGx6ait.d.mts +50 -0
  109. package/dist/server-WqGx6ait.d.mts.map +1 -0
  110. package/dist/server.d.mts +2 -7
  111. package/dist/server.mjs +22 -17
  112. package/dist/{source-map-generator-DpO-ejrt.mjs → source-map-generator-BWDva49I.mjs} +1 -1
  113. package/dist/{source-map-generator-DpO-ejrt.mjs.map → source-map-generator-BWDva49I.mjs.map} +1 -1
  114. package/dist/{svelte-parser-1bBcMx3T.mjs → svelte-parser-Dr9mmZuk.mjs} +3 -3
  115. package/dist/{svelte-parser-1bBcMx3T.mjs.map → svelte-parser-Dr9mmZuk.mjs.map} +1 -1
  116. package/dist/templates/index.mjs +1 -1
  117. package/dist/{templates-bRPzYq4M.mjs → templates-VrLVqfe5.mjs} +1 -1
  118. package/dist/{templates-bRPzYq4M.mjs.map → templates-VrLVqfe5.mjs.map} +1 -1
  119. package/dist/tools/annotations.d.mts +24 -0
  120. package/dist/tools/annotations.d.mts.map +1 -0
  121. package/dist/tools/annotations.mjs +2 -0
  122. package/dist/{transaction-C_Pvux78.mjs → transaction-DgkNgWSI.mjs} +61 -32
  123. package/dist/transaction-DgkNgWSI.mjs.map +1 -0
  124. package/dist/tsx-parser-BOMZE_yQ.mjs +2 -0
  125. package/dist/{tsx-parser-BWiMGAIR.mjs → tsx-parser-CQc6nr-o.mjs} +1 -1
  126. package/dist/{tsx-parser-BWiMGAIR.mjs.map → tsx-parser-CQc6nr-o.mjs.map} +1 -1
  127. package/dist/util/detect.mjs +2 -3
  128. package/dist/util/fs.mjs +1 -2
  129. package/dist/util/id.mjs +1 -1
  130. package/dist/validator-B0nNRFeU.mjs +906 -0
  131. package/dist/validator-B0nNRFeU.mjs.map +1 -0
  132. package/dist/{vue-parser-DTPTN3Yb.mjs → vue-parser-COgjArqv.mjs} +3 -3
  133. package/dist/{vue-parser-DTPTN3Yb.mjs.map → vue-parser-COgjArqv.mjs.map} +1 -1
  134. package/package.json +75 -21
  135. package/dist/config-B5kc2oeV.mjs +0 -27
  136. package/dist/config-B5kc2oeV.mjs.map +0 -1
  137. package/dist/context-DIDt_TxX.mjs +0 -46
  138. package/dist/context-DIDt_TxX.mjs.map +0 -1
  139. package/dist/core/content-manager.d.mts.map +0 -1
  140. package/dist/core/validator.d.mts +0 -23
  141. package/dist/core/validator.d.mts.map +0 -1
  142. package/dist/core/validator.mjs +0 -7
  143. package/dist/fs-BnIQ4dKj.mjs.map +0 -1
  144. package/dist/model-manager-DW_fOGRM.mjs.map +0 -1
  145. package/dist/scanner-CQOxARUU.mjs.map +0 -1
  146. package/dist/serializer-CnHTtmc1.mjs +0 -2
  147. package/dist/server-DfWRpzdP.mjs.map +0 -1
  148. package/dist/server.d.mts.map +0 -1
  149. package/dist/transaction-C_Pvux78.mjs.map +0 -1
  150. package/dist/tsx-parser-BFLv292Y.mjs +0 -2
  151. package/dist/util/serializer.d.mts +0 -2
  152. package/dist/util/serializer.mjs +0 -2
  153. package/dist/validator-SQYUV2JP.mjs +0 -581
  154. package/dist/validator-SQYUV2JP.mjs.map +0 -1
@@ -0,0 +1,24 @@
1
+ import { ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
2
+
3
+ //#region src/tools/annotations.d.ts
4
+ /**
5
+ * Centralized tool annotations registry.
6
+ * MCP clients use these hints to distinguish read-only vs. write vs. destructive tools.
7
+ *
8
+ * Also serves as the **single source of truth for the tool name list**. Consumers
9
+ * that need to enumerate every registered tool (e.g. parity tests in
10
+ * `@contentrain/rules` / `@contentrain/skills`) should import `TOOL_NAMES` below
11
+ * rather than hardcoding the list.
12
+ */
13
+ declare const TOOL_ANNOTATIONS: Record<string, ToolAnnotations>;
14
+ /**
15
+ * Canonical list of every registered MCP tool name, derived from the
16
+ * single source of truth above. Re-exported here with a stable name so
17
+ * parity tests in sibling packages (`@contentrain/rules`,
18
+ * `@contentrain/skills`) can assert against it without depending on
19
+ * `TOOL_ANNOTATIONS` internals.
20
+ */
21
+ declare const TOOL_NAMES: readonly string[];
22
+ //#endregion
23
+ export { TOOL_ANNOTATIONS, TOOL_NAMES };
24
+ //# sourceMappingURL=annotations.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotations.d.mts","names":[],"sources":["../../src/tools/annotations.ts"],"mappings":";;;;;AAWA;;;;;AA6HA;;cA7Ha,gBAAA,EAAkB,MAAA,SAAe,eAAA;;;;;;;;cA6HjC,UAAA"}
@@ -0,0 +1,2 @@
1
+ import { n as TOOL_NAMES, t as TOOL_ANNOTATIONS } from "../annotations-Clhbw2lh.mjs";
2
+ export { TOOL_ANNOTATIONS, TOOL_NAMES };
@@ -1,44 +1,73 @@
1
- import { t as readConfig } from "./config-B5kc2oeV.mjs";
2
- import { n as writeContext } from "./context-DIDt_TxX.mjs";
3
- import { t as branchTimestamp } from "./id-DV_T9Ic8.mjs";
1
+ import { t as readConfig } from "./config-BIl5Ybj0.mjs";
2
+ import { r as writeContext } from "./context-J0OU9Nfp.mjs";
3
+ import { t as branchTimestamp } from "./id-CIO9s0x_.mjs";
4
4
  import { join } from "node:path";
5
- import { rm } from "node:fs/promises";
6
5
  import { CONTENTRAIN_BRANCH } from "@contentrain/types";
6
+ import { rm } from "node:fs/promises";
7
7
  import { simpleGit } from "simple-git";
8
8
  import { tmpdir } from "node:os";
9
9
  import { randomUUID } from "node:crypto";
10
+ //#region src/providers/local/migration.ts
11
+ /**
12
+ * Migration: the first MCP release used `contentrain/*` feature branches.
13
+ * Once we introduced the singleton `contentrain` branch (tracking the
14
+ * committed content state), those old feature branches became a ref-
15
+ * namespace conflict — git cannot hold both `contentrain` (a leaf ref)
16
+ * and `contentrain/foo` (implying a directory) simultaneously.
17
+ *
18
+ * `migrateLegacyBranches` removes the old-prefix branches so the
19
+ * singleton `contentrain` ref can be created. It is idempotent and
20
+ * safe to call before every `ensureContentBranch` run.
21
+ *
22
+ * Strategy:
23
+ * 1. Delete merged `contentrain/*` branches first (`-d`). Their commits
24
+ * are already on the base branch via the old auto-merge flow.
25
+ * 2. Force-delete whatever remains (`-D`). Any unmerged leftover is
26
+ * from an abandoned or partially-committed legacy branch — content
27
+ * on `main` always wins, and the singleton `contentrain` branch is
28
+ * about to be created from `main`/`baseBranch` anyway.
29
+ *
30
+ * Returns the number of branches that were deleted. Callers may log it;
31
+ * the git transaction layer does not need the count for correctness.
32
+ */
33
+ async function migrateLegacyBranches(git, baseBranch) {
34
+ if ((await git.branchLocal()).all.filter((b) => b.startsWith("contentrain/")).length === 0) return 0;
35
+ let deleted = 0;
36
+ let mergedLegacy = [];
37
+ try {
38
+ mergedLegacy = (await git.raw([
39
+ "branch",
40
+ "--merged",
41
+ baseBranch
42
+ ])).split("\n").map((b) => b.trim().replace(/^\*\s*/, "")).filter((b) => b.startsWith("contentrain/"));
43
+ } catch {}
44
+ for (const b of mergedLegacy) try {
45
+ await git.raw([
46
+ "branch",
47
+ "-d",
48
+ b
49
+ ]);
50
+ deleted++;
51
+ } catch {}
52
+ const remaining = (await git.branchLocal()).all.filter((b) => b.startsWith("contentrain/"));
53
+ for (const b of remaining) try {
54
+ await git.raw([
55
+ "branch",
56
+ "-D",
57
+ b
58
+ ]);
59
+ deleted++;
60
+ } catch {}
61
+ return deleted;
62
+ }
63
+ //#endregion
10
64
  //#region src/git/transaction.ts
11
65
  async function ensureContentBranch(projectRoot) {
12
66
  const git = simpleGit(projectRoot);
13
67
  const config = await readConfig(projectRoot);
14
- const branches = await git.branchLocal();
15
- if (branches.all.includes(CONTENTRAIN_BRANCH)) return;
68
+ if ((await git.branchLocal()).all.includes(CONTENTRAIN_BRANCH)) return;
16
69
  const baseBranch = config?.repository?.default_branch || (await git.raw(["branch", "--show-current"])).trim() || "main";
17
- if (branches.all.filter((b) => b.startsWith("contentrain/")).length > 0) {
18
- let mergedBranches = [];
19
- try {
20
- mergedBranches = (await git.raw([
21
- "branch",
22
- "--merged",
23
- baseBranch
24
- ])).split("\n").map((b) => b.trim().replace(/^\*\s*/, "")).filter((b) => b.startsWith("contentrain/"));
25
- } catch {}
26
- for (const b of mergedBranches) try {
27
- await git.raw([
28
- "branch",
29
- "-d",
30
- b
31
- ]);
32
- } catch {}
33
- const remaining = (await git.branchLocal()).all.filter((b) => b.startsWith("contentrain/"));
34
- if (remaining.length > 0) for (const b of remaining) try {
35
- await git.raw([
36
- "branch",
37
- "-D",
38
- b
39
- ]);
40
- } catch {}
41
- }
70
+ await migrateLegacyBranches(git, baseBranch);
42
71
  await git.branch([CONTENTRAIN_BRANCH, baseBranch]);
43
72
  const remoteName = process.env["CONTENTRAIN_REMOTE"] ?? "origin";
44
73
  try {
@@ -385,4 +414,4 @@ function buildBranchName(scope, target, locale) {
385
414
  //#endregion
386
415
  export { mergeBranch as i, createTransaction as n, ensureContentBranch as r, buildBranchName as t };
387
416
 
388
- //# sourceMappingURL=transaction-C_Pvux78.mjs.map
417
+ //# sourceMappingURL=transaction-DgkNgWSI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-DgkNgWSI.mjs","names":["removeFile"],"sources":["../src/providers/local/migration.ts","../src/git/transaction.ts"],"sourcesContent":["import type { SimpleGit } from 'simple-git'\n\n/**\n * Migration: the first MCP release used `contentrain/*` feature branches.\n * Once we introduced the singleton `contentrain` branch (tracking the\n * committed content state), those old feature branches became a ref-\n * namespace conflict — git cannot hold both `contentrain` (a leaf ref)\n * and `contentrain/foo` (implying a directory) simultaneously.\n *\n * `migrateLegacyBranches` removes the old-prefix branches so the\n * singleton `contentrain` ref can be created. It is idempotent and\n * safe to call before every `ensureContentBranch` run.\n *\n * Strategy:\n * 1. Delete merged `contentrain/*` branches first (`-d`). Their commits\n * are already on the base branch via the old auto-merge flow.\n * 2. Force-delete whatever remains (`-D`). Any unmerged leftover is\n * from an abandoned or partially-committed legacy branch — content\n * on `main` always wins, and the singleton `contentrain` branch is\n * about to be created from `main`/`baseBranch` anyway.\n *\n * Returns the number of branches that were deleted. Callers may log it;\n * the git transaction layer does not need the count for correctness.\n */\nexport async function migrateLegacyBranches(\n git: SimpleGit,\n baseBranch: string,\n): Promise<number> {\n const branches = await git.branchLocal()\n const oldPrefixBranches = branches.all.filter(b => b.startsWith('contentrain/'))\n if (oldPrefixBranches.length === 0) return 0\n\n let deleted = 0\n\n // 1) Delete merged legacy branches first — the safe path.\n let mergedLegacy: string[] = []\n try {\n const mergedOutput = await git.raw(['branch', '--merged', baseBranch])\n mergedLegacy = mergedOutput.split('\\n')\n .map(b => b.trim().replace(/^\\*\\s*/, ''))\n .filter(b => b.startsWith('contentrain/'))\n } catch {\n // `branch --merged` fails before baseBranch exists — fall through.\n }\n\n for (const b of mergedLegacy) {\n try {\n await git.raw(['branch', '-d', b])\n deleted++\n } catch {\n // Branch may be protected or already gone — safe to skip.\n }\n }\n\n // 2) Force-delete any unmerged legacy branches still present.\n const remaining = (await git.branchLocal()).all.filter(b => b.startsWith('contentrain/'))\n for (const b of remaining) {\n try {\n await git.raw(['branch', '-D', b])\n deleted++\n } catch {\n // Skip — best-effort cleanup.\n }\n }\n\n return deleted\n}\n","import { simpleGit } from 'simple-git'\nimport { join } from 'node:path'\nimport { rm as removeFile } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { randomUUID } from 'node:crypto'\nimport { readConfig } from '../core/config.js'\nimport { writeContext } from '../core/context.js'\nimport { branchTimestamp } from '../util/id.js'\nimport { migrateLegacyBranches } from '../providers/local/migration.js'\nimport type { SyncResult, WorkflowMode } from '@contentrain/types'\nimport { CONTENTRAIN_BRANCH } from '@contentrain/types'\n\nexport interface ContextUpdate {\n tool: string\n model: string\n locale?: string\n entries?: string[]\n}\n\nexport interface GitTransaction {\n worktree: string\n branch: string\n write(callback: (worktreePath: string) => Promise<void>): Promise<void>\n commit(message: string, contextUpdate?: ContextUpdate): Promise<string>\n complete(): Promise<{ action: 'auto-merged' | 'pending-review'; commit: string; sync?: SyncResult; warning?: string }>\n cleanup(): Promise<void>\n}\n\nexport async function ensureContentBranch(projectRoot: string): Promise<void> {\n const git = simpleGit(projectRoot)\n const config = await readConfig(projectRoot)\n\n // Check if contentrain branch exists locally\n const branches = await git.branchLocal()\n if (branches.all.includes(CONTENTRAIN_BRANCH)) return\n\n // Detect base branch\n const baseBranch = config?.repository?.default_branch\n || (await git.raw(['branch', '--show-current'])).trim()\n || 'main'\n\n // Clean up legacy `contentrain/*` feature branches so the singleton\n // `contentrain` ref can be created. Idempotent — safe to call even\n // when no legacy branches exist.\n await migrateLegacyBranches(git, baseBranch)\n\n // Create contentrain branch from base\n await git.branch([CONTENTRAIN_BRANCH, baseBranch])\n\n // Push to remote if exists\n const remoteName = process.env['CONTENTRAIN_REMOTE'] ?? 'origin'\n try {\n const remotes = await git.getRemotes()\n if (remotes.some(r => r.name === remoteName)) {\n await git.push(['-u', remoteName, CONTENTRAIN_BRANCH])\n }\n } catch {\n // Remote push is best-effort\n }\n}\n\nasync function selectiveSync(\n projectRoot: string,\n _worktreePath: string,\n contentrainTip: string,\n _previousBaseRef?: string,\n dirtyFilesBeforeUpdate?: Set<string>,\n): Promise<SyncResult> {\n const git = simpleGit(projectRoot)\n const synced: string[] = []\n const skipped: string[] = []\n\n // Use git plumbing to find ALL files that differ between old and new commits.\n // diff-tree is fast and ignores working tree / index state entirely.\n // Not limited to .contentrain/ — some ops also modify .gitignore, etc.\n const compareRef = _previousBaseRef ?? contentrainTip\n let changedFiles: string[] = []\n try {\n const diffOutput = await git.raw([\n 'diff-tree', '--name-only', '-r', '--no-commit-id',\n compareRef, contentrainTip,\n ])\n changedFiles = diffOutput.split('\\n').filter(f => f.trim().length > 0)\n } catch {\n // Fallback: list .contentrain/ files from the contentrainTip commit\n try {\n const lsOutput = await git.raw(['ls-tree', '-r', '--name-only', contentrainTip, '.contentrain/'])\n changedFiles = lsOutput.split('\\n').filter(f => f.trim().length > 0)\n } catch {\n return { synced, skipped }\n }\n }\n\n if (changedFiles.length === 0) return { synced, skipped }\n\n // Use pre-captured dirty files (before update-ref) to avoid false positives.\n // After update-ref, files appear as \"modified\" in status even though the developer\n // didn't touch them. We use the pre-update state to know what was truly dirty.\n const dirtyFiles = dirtyFilesBeforeUpdate ?? new Set<string>()\n\n // Determine which changed files still exist in contentrainTip (HEAD after update-ref)\n // Check each changed file individually — `ls-tree` on specific paths is efficient\n const filesInTip = new Set<string>()\n for (const file of changedFiles) {\n try {\n await git.raw(['cat-file', '-e', `${contentrainTip}:${file}`])\n filesInTip.add(file)\n } catch {\n // File does not exist in tip (was deleted)\n }\n }\n\n for (const file of changedFiles) {\n if (dirtyFiles.has(file)) {\n skipped.push(file)\n } else if (filesInTip.has(file)) {\n // File exists in new HEAD — checkout from HEAD\n try {\n await git.checkout(['HEAD', '--', file])\n synced.push(file)\n } catch {\n skipped.push(file)\n }\n } else {\n // File was deleted in new HEAD — remove from working tree\n try {\n const filePath = join(projectRoot, file)\n await removeFile(filePath, { force: true })\n synced.push(file)\n } catch {\n skipped.push(file)\n }\n }\n }\n\n const warning = skipped.length > 0\n ? `${skipped.length} file(s) skipped due to local changes: ${skipped.join(', ')}. Commit your changes, then run: git checkout HEAD -- ${skipped.join(' ')}`\n : undefined\n\n return { synced, skipped, warning }\n}\n\nexport async function createTransaction(\n projectRoot: string,\n branchName: string,\n options?: { workflowOverride?: WorkflowMode },\n): Promise<GitTransaction> {\n const git = simpleGit(projectRoot)\n const config = await readConfig(projectRoot)\n const workflow = options?.workflowOverride ?? config?.workflow ?? 'auto-merge'\n\n const remoteName = process.env['CONTENTRAIN_REMOTE'] ?? 'origin'\n\n // Detect base branch + current branch + remote in ONE batch\n // (reduces subprocess spawns from 4 to 2)\n let baseBranch = process.env['CONTENTRAIN_BRANCH'] ?? config?.repository?.default_branch ?? ''\n let currentBranch = ''\n let hasRemote = false\n\n const [branchResult, remotes] = await Promise.all([\n git.raw(['branch', '--show-current']).catch(() => ''),\n git.getRemotes().catch(() => []),\n ])\n currentBranch = branchResult.trim()\n if (!baseBranch) baseBranch = currentBranch || 'main'\n hasRemote = (remotes as { name: string }[]).some(r => r.name === remoteName)\n\n // Check if developer is on contentrain branch\n if (currentBranch === CONTENTRAIN_BRANCH) {\n throw Object.assign(new Error(\n `The '${CONTENTRAIN_BRANCH}' branch is checked out in your working directory. `\n + `Contentrain manages this branch automatically. `\n + `Switch to your working branch and retry.`,\n ), {\n code: 'CONTENT_BRANCH_CHECKED_OUT',\n agent_hint: 'Ask the developer to switch to their working branch (e.g., main or a feature branch), then retry the operation.',\n developer_action: `git checkout ${baseBranch}`,\n })\n }\n\n // Ensure contentrain branch exists (with migration for old contentrain/* branches)\n await ensureContentBranch(projectRoot)\n\n // Fetch latest from remote (parallel fetch for both branches)\n if (hasRemote) {\n await Promise.all([\n git.fetch(remoteName, baseBranch).catch(() => {}),\n git.fetch(remoteName, CONTENTRAIN_BRANCH).catch(() => {}),\n ])\n }\n\n const worktreePath = join(tmpdir(), `cr-${randomUUID()}`)\n const branch = branchName\n\n // Create worktree on contentrain branch\n await git.raw(['worktree', 'add', worktreePath, CONTENTRAIN_BRANCH])\n\n const wtGit = simpleGit(worktreePath)\n\n // Configure author (sequential — git config uses lock file)\n const authorName = process.env['CONTENTRAIN_AUTHOR_NAME'] ?? 'Contentrain'\n const authorEmail = process.env['CONTENTRAIN_AUTHOR_EMAIL'] ?? 'mcp@contentrain.io'\n await wtGit.addConfig('user.name', authorName)\n await wtGit.addConfig('user.email', authorEmail)\n\n // Sync contentrain with base branch (bring main changes into contentrain)\n try {\n await wtGit.merge([baseBranch, '--no-edit'])\n } catch {\n try { await wtGit.merge(['--abort']) } catch { /* not in merge state */ }\n if (hasRemote) {\n try {\n await wtGit.merge([`${remoteName}/${baseBranch}`, '--no-edit'])\n } catch {\n try { await wtGit.merge(['--abort']) } catch { /* ignore */ }\n }\n }\n }\n\n // Sync with remote contentrain if exists\n if (hasRemote) {\n try {\n await wtGit.merge([`${remoteName}/${CONTENTRAIN_BRANCH}`, '--no-edit'])\n } catch {\n try { await wtGit.merge(['--abort']) } catch { /* ignore */ }\n }\n }\n\n // Create feature branch from contentrain\n await wtGit.checkout(['-b', branch])\n\n let commitHash = ''\n\n return {\n worktree: worktreePath,\n branch,\n\n async write(callback) {\n await callback(worktreePath)\n },\n\n async commit(message, contextUpdate?) {\n // Write context.json together with content (no separate commit)\n if (contextUpdate) {\n await writeContext(worktreePath, contextUpdate)\n }\n await wtGit.add('.')\n const result = await wtGit.commit(message, { '--allow-empty': null })\n commitHash = result.commit || ''\n return commitHash\n },\n\n async complete() {\n if (workflow === 'review') {\n if (hasRemote) {\n await git.push(remoteName, branch)\n }\n return { action: 'pending-review', commit: commitHash }\n }\n\n // auto-merge: merge feature branch into contentrain, then advance base\n\n // Switch to contentrain branch in worktree\n await wtGit.checkout(CONTENTRAIN_BRANCH)\n\n // Merge feature branch into contentrain\n try {\n await wtGit.merge([branch, '--no-edit'])\n } catch {\n try {\n await wtGit.merge(['--abort'])\n } catch { /* not in merge state */ }\n throw Object.assign(new Error(\n `Merge conflict when merging branch \"${branch}\" into \"${CONTENTRAIN_BRANCH}\". `\n + `The branch still exists with your changes intact. `\n + `Resolve the conflict manually, or delete the branch and retry.`,\n ), {\n code: 'CONTENT_BRANCH_MERGE_CONFLICT',\n agent_hint: 'The feature branch could not be merged into the contentrain branch. Ask the developer to resolve the conflict.',\n developer_action: `git checkout ${CONTENTRAIN_BRANCH} && git merge ${branch}`,\n })\n }\n\n // Get contentrain tip + old base ref + dirty files in parallel\n const [contentrainTip, previousBaseRef, statusBeforeUpdate] = await Promise.all([\n wtGit.raw(['rev-parse', 'HEAD']).then(s => s.trim()),\n git.raw(['rev-parse', baseBranch]).then(s => s.trim()),\n git.status(),\n ])\n const dirtyFilesBeforeUpdate = new Set(statusBeforeUpdate.files.map(f => f.path))\n\n // Verify fast-forward: baseBranch must be an ancestor of contentrainTip\n // (guaranteed by the merge above, but verify for safety)\n try {\n await git.raw(['merge-base', '--is-ancestor', previousBaseRef, contentrainTip])\n } catch {\n throw Object.assign(new Error(\n `Cannot fast-forward \"${baseBranch}\" to contentrain tip. `\n + `The base branch has diverged. Merge \"${baseBranch}\" into \"${CONTENTRAIN_BRANCH}\" first.`,\n ), {\n code: 'BASE_UPDATE_FAILED',\n agent_hint: `The base branch has commits not in contentrain. Merge ${baseBranch} into ${CONTENTRAIN_BRANCH} first.`,\n developer_action: `git checkout ${CONTENTRAIN_BRANCH} && git merge ${baseBranch} && git checkout ${baseBranch}`,\n })\n }\n\n // Advance base branch to contentrain tip via update-ref\n await git.raw(['update-ref', `refs/heads/${baseBranch}`, contentrainTip])\n\n // Refresh index to match new HEAD.\n // update-ref moves the branch pointer but leaves the index stale.\n // read-tree updates the index to match HEAD without touching the working tree.\n try {\n await git.raw(['read-tree', 'HEAD'])\n } catch {\n // fallback: try reset for older git versions\n try { await git.raw(['reset', 'HEAD']) } catch { /* ignore */ }\n }\n\n // Selective sync: copy .contentrain/ files to developer's working tree\n const sync = await selectiveSync(projectRoot, worktreePath, contentrainTip, previousBaseRef, dirtyFilesBeforeUpdate)\n\n // Push to remote (best-effort with retry)\n if (hasRemote) {\n // Push contentrain branch\n try {\n await git.push(remoteName, CONTENTRAIN_BRANCH)\n } catch {\n // Retry: fetch, merge, push\n try {\n await wtGit.fetch(remoteName, CONTENTRAIN_BRANCH)\n await wtGit.merge([`${remoteName}/${CONTENTRAIN_BRANCH}`, '--no-edit'])\n await git.push(remoteName, CONTENTRAIN_BRANCH)\n } catch {\n // Push failed after retry — continue, local state is fine\n }\n }\n\n // Push base branch\n try {\n await git.push(remoteName, baseBranch)\n } catch {\n // push may fail, local merge succeeded\n }\n }\n\n return {\n action: 'auto-merged' as const,\n commit: commitHash,\n sync,\n ...(sync.warning ? { warning: sync.warning } : {}),\n }\n },\n\n async cleanup() {\n try {\n await git.raw(['worktree', 'remove', worktreePath, '--force'])\n } catch {\n // worktree may already be cleaned up\n }\n },\n }\n}\n\nexport async function mergeBranch(\n projectRoot: string,\n branchName: string,\n): Promise<{ action: 'merged'; commit: string; sync: SyncResult }> {\n const git = simpleGit(projectRoot)\n const config = await readConfig(projectRoot)\n const remoteName = process.env['CONTENTRAIN_REMOTE'] ?? 'origin'\n\n // Detect base branch\n const baseBranch = process.env['CONTENTRAIN_BRANCH']\n ?? config?.repository?.default_branch\n ?? ((await git.raw(['branch', '--show-current'])).trim() || 'main')\n\n // Ensure contentrain branch exists\n await ensureContentBranch(projectRoot)\n\n // Check remote\n let hasRemote = false\n try {\n const remotes = await git.getRemotes()\n hasRemote = remotes.some(r => r.name === remoteName)\n } catch {\n hasRemote = false\n }\n\n // Create temp worktree on contentrain branch\n const worktreePath = join(tmpdir(), `cr-merge-${randomUUID()}`)\n await git.raw(['worktree', 'add', worktreePath, CONTENTRAIN_BRANCH])\n\n const wtGit = simpleGit(worktreePath)\n\n // Configure author\n const authorName = process.env['CONTENTRAIN_AUTHOR_NAME'] ?? 'Contentrain'\n const authorEmail = process.env['CONTENTRAIN_AUTHOR_EMAIL'] ?? 'mcp@contentrain.io'\n await wtGit.addConfig('user.name', authorName)\n await wtGit.addConfig('user.email', authorEmail)\n\n try {\n // Merge the feature branch into contentrain\n try {\n await wtGit.merge([branchName, '--no-edit'])\n } catch {\n try { await wtGit.merge(['--abort']) } catch { /* not in merge state */ }\n throw Object.assign(new Error(\n `Merge conflict when merging branch \"${branchName}\" into \"${CONTENTRAIN_BRANCH}\". `\n + `The branch still exists with your changes intact. `\n + `Resolve the conflict manually, or delete the branch and retry.`,\n ), {\n code: 'CONTENT_BRANCH_MERGE_CONFLICT',\n agent_hint: 'The feature branch could not be merged into the contentrain branch. Ask the developer to resolve the conflict.',\n developer_action: `git checkout ${CONTENTRAIN_BRANCH} && git merge ${branchName}`,\n })\n }\n\n // Get contentrain tip + old base ref + dirty files in parallel\n const [contentrainTip, previousBaseRef, statusBeforeUpdate] = await Promise.all([\n wtGit.raw(['rev-parse', 'HEAD']).then(s => s.trim()),\n git.raw(['rev-parse', baseBranch]).then(s => s.trim()),\n git.status(),\n ])\n const dirtyFilesBeforeUpdate = new Set(statusBeforeUpdate.files.map(f => f.path))\n\n // Verify fast-forward: baseBranch must be an ancestor of contentrainTip\n try {\n await git.raw(['merge-base', '--is-ancestor', previousBaseRef, contentrainTip])\n } catch {\n throw Object.assign(new Error(\n `Cannot fast-forward \"${baseBranch}\" to contentrain tip. `\n + `The base branch has diverged. Merge \"${baseBranch}\" into \"${CONTENTRAIN_BRANCH}\" first.`,\n ), {\n code: 'BASE_UPDATE_FAILED',\n agent_hint: `The base branch has commits not in contentrain. Merge ${baseBranch} into ${CONTENTRAIN_BRANCH} first.`,\n developer_action: `git checkout ${CONTENTRAIN_BRANCH} && git merge ${baseBranch} && git checkout ${baseBranch}`,\n })\n }\n\n // Advance base branch to contentrain tip via update-ref\n await git.raw(['update-ref', `refs/heads/${baseBranch}`, contentrainTip])\n\n // Refresh index to match new HEAD\n try {\n await git.raw(['read-tree', 'HEAD'])\n } catch {\n try { await git.raw(['reset', 'HEAD']) } catch { /* ignore */ }\n }\n\n // Selective sync: copy .contentrain/ files to developer's working tree\n const sync = await selectiveSync(projectRoot, worktreePath, contentrainTip, previousBaseRef, dirtyFilesBeforeUpdate)\n\n // Push to remote (best-effort)\n if (hasRemote) {\n try {\n await git.push(remoteName, CONTENTRAIN_BRANCH)\n } catch {\n try {\n await wtGit.fetch(remoteName, CONTENTRAIN_BRANCH)\n await wtGit.merge([`${remoteName}/${CONTENTRAIN_BRANCH}`, '--no-edit'])\n await git.push(remoteName, CONTENTRAIN_BRANCH)\n } catch {\n // Push failed after retry — continue, local state is fine\n }\n }\n\n try {\n await git.push(remoteName, baseBranch)\n } catch {\n // push may fail, local merge succeeded\n }\n }\n\n return {\n action: 'merged' as const,\n commit: contentrainTip,\n sync,\n }\n } finally {\n // Cleanup worktree\n try {\n await git.raw(['worktree', 'remove', worktreePath, '--force'])\n } catch {\n // worktree may already be cleaned up\n }\n }\n}\n\nexport function buildBranchName(scope: string, target: string, locale?: string): string {\n const ts = branchTimestamp()\n const parts = ['cr', scope, target]\n if (locale) parts.push(locale)\n parts.push(ts)\n return parts.join('/')\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { t as parseTsx } from "./tsx-parser-CQc6nr-o.mjs";
2
+ export { parseTsx };
@@ -232,4 +232,4 @@ function buildSurrounding(lines, lineIdx) {
232
232
  //#endregion
233
233
  export { parseTsx as t };
234
234
 
235
- //# sourceMappingURL=tsx-parser-BWiMGAIR.mjs.map
235
+ //# sourceMappingURL=tsx-parser-CQc6nr-o.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"tsx-parser-BWiMGAIR.mjs","names":[],"sources":["../src/core/ast-scanner/tsx-parser.ts"],"sourcesContent":["import ts from 'typescript'\nimport type { ExtractedString, StructuralContext } from './types.js'\n\n// ─── Constants ───\n\nconst SURROUNDING_MAX = 120\n\n// ─── Public API ───\n\n/**\n * Parse a TSX/JSX/TS/JS file and extract all string literals with structural context.\n *\n * Uses TypeScript's syntax-only parser (no type checking, no tsconfig needed).\n * Walks the AST and classifies each string by its parent chain.\n */\nexport function parseTsx(content: string, fileName: string): ExtractedString[] {\n const scriptKind = getScriptKind(fileName)\n const sourceFile = ts.createSourceFile(\n fileName,\n content,\n ts.ScriptTarget.Latest,\n /* setParentNodes */ true,\n scriptKind,\n )\n\n const results: ExtractedString[] = []\n const lines = content.split('\\n')\n\n visit(sourceFile, sourceFile, lines, results)\n\n return results\n}\n\n// ─── Script kind detection ───\n\nfunction getScriptKind(fileName: string): ts.ScriptKind {\n const lower = fileName.toLowerCase()\n if (lower.endsWith('.tsx')) return ts.ScriptKind.TSX\n if (lower.endsWith('.jsx')) return ts.ScriptKind.JSX\n if (lower.endsWith('.ts')) return ts.ScriptKind.TS\n return ts.ScriptKind.JS\n}\n\n// ─── AST Walker ───\n\nfunction visit(\n node: ts.Node,\n sourceFile: ts.SourceFile,\n lines: string[],\n results: ExtractedString[],\n): void {\n // Handle JsxText nodes\n if (ts.isJsxText(node)) {\n const text = node.text.trim()\n // Skip whitespace-only or empty JsxText\n if (text.length > 0) {\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile))\n const parent = getJsxParentTag(node)\n results.push({\n value: text,\n line: lineIdx + 1,\n column: character + 1,\n context: 'jsx_text',\n scope: 'script',\n parent,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n }\n return\n }\n\n // Handle string literals\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {\n const value = node.text\n // Skip empty strings\n if (value.length === 0) return\n\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile))\n const classification = classifyByParentChain(node, sourceFile)\n\n results.push({\n value,\n line: lineIdx + 1,\n column: character + 1,\n context: classification.context,\n scope: 'script',\n parent: classification.parent,\n parentProperty: classification.parentProperty,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n return\n }\n\n // Handle template literals with expressions — extract static head/spans\n if (ts.isTemplateExpression(node)) {\n extractTemplateParts(node, sourceFile, lines, results)\n return\n }\n\n ts.forEachChild(node, (child) => {\n visit(child, sourceFile, lines, results)\n })\n}\n\n// ─── Template literal parts extraction ───\n\nfunction extractTemplateParts(\n node: ts.TemplateExpression,\n sourceFile: ts.SourceFile,\n lines: string[],\n results: ExtractedString[],\n): void {\n const classification = classifyByParentChain(node, sourceFile)\n\n // Head: text before first ${...}\n const headText = node.head.text\n if (headText.length > 0) {\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.head.getStart(sourceFile))\n results.push({\n value: headText,\n line: lineIdx + 1,\n column: character + 1,\n context: classification.context,\n scope: 'script',\n parent: classification.parent,\n parentProperty: classification.parentProperty,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n }\n\n // Template spans: text after each ${...} expression\n for (const span of node.templateSpans) {\n const spanText = span.literal.text\n if (spanText.length > 0) {\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(span.literal.getStart(sourceFile))\n results.push({\n value: spanText,\n line: lineIdx + 1,\n column: character + 1,\n context: classification.context,\n scope: 'script',\n parent: classification.parent,\n parentProperty: classification.parentProperty,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n }\n\n // Visit the expression inside ${...} for nested strings\n visit(span.expression, sourceFile, lines, results)\n }\n}\n\n// ─── Parent chain classification ───\n\ninterface Classification {\n context: StructuralContext\n parent: string\n parentProperty?: string\n}\n\nfunction classifyByParentChain(node: ts.Node, sourceFile: ts.SourceFile): Classification {\n let current = node.parent\n\n while (current) {\n // Import / Export declaration → import_path\n if (ts.isImportDeclaration(current) || ts.isExportDeclaration(current)) {\n return { context: 'import_path', parent: 'import' }\n }\n\n // Import specifier module path (dynamic import)\n if (ts.isCallExpression(current) && current.expression.kind === ts.SyntaxKind.ImportKeyword) {\n return { context: 'import_path', parent: 'import' }\n }\n\n // require() calls\n if (\n ts.isCallExpression(current)\n && ts.isIdentifier(current.expression)\n && current.expression.text === 'require'\n ) {\n return { context: 'import_path', parent: 'require' }\n }\n\n // JSX attribute → jsx_attribute or css_class\n if (ts.isJsxAttribute(current)) {\n const attrName = ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile)\n // className / class / style → CSS, not content\n if (attrName === 'className' || attrName === 'class' || attrName === 'style') {\n return { context: 'css_class', parent: attrName }\n }\n return { context: 'jsx_attribute', parent: attrName, parentProperty: attrName }\n }\n\n // Variable declaration → variable_assignment\n if (ts.isVariableDeclaration(current)) {\n const varName = ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile)\n return { context: 'variable_assignment', parent: varName }\n }\n\n // Property assignment → object_property\n if (ts.isPropertyAssignment(current)) {\n const key = ts.isIdentifier(current.name)\n ? current.name.text\n : ts.isStringLiteral(current.name)\n ? current.name.text\n : current.name.getText(sourceFile)\n return { context: 'object_property', parent: key, parentProperty: key }\n }\n\n // Enum member → enum_value\n if (ts.isEnumMember(current)) {\n const enumName = ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile)\n return { context: 'enum_value', parent: enumName }\n }\n\n // Call expression → function_argument or css_utility_call or console_call or test_assertion\n if (ts.isCallExpression(current)) {\n const callee = getCalleeName(current.expression, sourceFile)\n // CSS utility functions\n if (['cn', 'clsx', 'classNames', 'twMerge', 'twJoin', 'cva', 'cx'].includes(callee)) {\n return { context: 'css_utility_call', parent: callee }\n }\n // Console calls\n if (callee.startsWith('console.')) {\n return { context: 'console_call', parent: callee }\n }\n // Test assertions\n if (['describe', 'it', 'test', 'expect', 'beforeEach', 'afterEach', 'beforeAll', 'afterAll'].includes(callee)) {\n return { context: 'test_assertion', parent: callee }\n }\n return { context: 'function_argument', parent: callee }\n }\n\n // Array literal → array_element\n if (ts.isArrayLiteralExpression(current)) {\n return { context: 'array_element', parent: 'array' }\n }\n\n // Case clause → switch_case\n if (ts.isCaseClause(current)) {\n return { context: 'switch_case', parent: 'case' }\n }\n\n // Type contexts → type_annotation\n if (\n ts.isTypeAliasDeclaration(current)\n || ts.isTypeReferenceNode(current)\n || ts.isInterfaceDeclaration(current)\n || ts.isTypeLiteralNode(current)\n || ts.isLiteralTypeNode(current)\n || ts.isUnionTypeNode(current)\n || ts.isIntersectionTypeNode(current)\n ) {\n return { context: 'type_annotation', parent: 'type' }\n }\n\n // Property declaration with type context (e.g., `as const` typed properties)\n // Check if we're inside a type annotation specifically\n if (ts.isPropertySignature(current)) {\n return { context: 'type_annotation', parent: 'type' }\n }\n\n current = current.parent\n }\n\n return { context: 'other', parent: '' }\n}\n\n// ─── Callee name extraction ───\n\nfunction getCalleeName(expr: ts.Expression, sourceFile: ts.SourceFile): string {\n if (ts.isIdentifier(expr)) {\n return expr.text\n }\n if (ts.isPropertyAccessExpression(expr)) {\n // e.g., console.log → \"console.log\"\n const obj = getCalleeName(expr.expression, sourceFile)\n return obj ? `${obj}.${expr.name.text}` : expr.name.text\n }\n return expr.getText(sourceFile)\n}\n\n// ─── JSX parent tag extraction ───\n\nfunction getJsxParentTag(node: ts.Node): string {\n let current = node.parent\n\n while (current) {\n if (ts.isJsxElement(current)) {\n const tagName = current.openingElement.tagName.getText()\n return tagName\n }\n if (ts.isJsxFragment(current)) {\n return 'Fragment'\n }\n current = current.parent\n }\n\n return ''\n}\n\n// ─── Surrounding code builder ───\n\nfunction buildSurrounding(lines: string[], lineIdx: number): string {\n const start = Math.max(0, lineIdx - 1)\n const end = Math.min(lines.length - 1, lineIdx + 1)\n\n const parts: string[] = []\n for (let i = start; i <= end; i++) {\n const line = lines[i]\n if (line !== undefined) {\n parts.push(line)\n }\n }\n\n const joined = parts.join('\\n')\n if (joined.length > SURROUNDING_MAX) {\n return joined.slice(0, SURROUNDING_MAX)\n }\n return joined\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tsx-parser-CQc6nr-o.mjs","names":[],"sources":["../src/core/ast-scanner/tsx-parser.ts"],"sourcesContent":["import ts from 'typescript'\nimport type { ExtractedString, StructuralContext } from './types.js'\n\n// ─── Constants ───\n\nconst SURROUNDING_MAX = 120\n\n// ─── Public API ───\n\n/**\n * Parse a TSX/JSX/TS/JS file and extract all string literals with structural context.\n *\n * Uses TypeScript's syntax-only parser (no type checking, no tsconfig needed).\n * Walks the AST and classifies each string by its parent chain.\n */\nexport function parseTsx(content: string, fileName: string): ExtractedString[] {\n const scriptKind = getScriptKind(fileName)\n const sourceFile = ts.createSourceFile(\n fileName,\n content,\n ts.ScriptTarget.Latest,\n /* setParentNodes */ true,\n scriptKind,\n )\n\n const results: ExtractedString[] = []\n const lines = content.split('\\n')\n\n visit(sourceFile, sourceFile, lines, results)\n\n return results\n}\n\n// ─── Script kind detection ───\n\nfunction getScriptKind(fileName: string): ts.ScriptKind {\n const lower = fileName.toLowerCase()\n if (lower.endsWith('.tsx')) return ts.ScriptKind.TSX\n if (lower.endsWith('.jsx')) return ts.ScriptKind.JSX\n if (lower.endsWith('.ts')) return ts.ScriptKind.TS\n return ts.ScriptKind.JS\n}\n\n// ─── AST Walker ───\n\nfunction visit(\n node: ts.Node,\n sourceFile: ts.SourceFile,\n lines: string[],\n results: ExtractedString[],\n): void {\n // Handle JsxText nodes\n if (ts.isJsxText(node)) {\n const text = node.text.trim()\n // Skip whitespace-only or empty JsxText\n if (text.length > 0) {\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile))\n const parent = getJsxParentTag(node)\n results.push({\n value: text,\n line: lineIdx + 1,\n column: character + 1,\n context: 'jsx_text',\n scope: 'script',\n parent,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n }\n return\n }\n\n // Handle string literals\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {\n const value = node.text\n // Skip empty strings\n if (value.length === 0) return\n\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile))\n const classification = classifyByParentChain(node, sourceFile)\n\n results.push({\n value,\n line: lineIdx + 1,\n column: character + 1,\n context: classification.context,\n scope: 'script',\n parent: classification.parent,\n parentProperty: classification.parentProperty,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n return\n }\n\n // Handle template literals with expressions — extract static head/spans\n if (ts.isTemplateExpression(node)) {\n extractTemplateParts(node, sourceFile, lines, results)\n return\n }\n\n ts.forEachChild(node, (child) => {\n visit(child, sourceFile, lines, results)\n })\n}\n\n// ─── Template literal parts extraction ───\n\nfunction extractTemplateParts(\n node: ts.TemplateExpression,\n sourceFile: ts.SourceFile,\n lines: string[],\n results: ExtractedString[],\n): void {\n const classification = classifyByParentChain(node, sourceFile)\n\n // Head: text before first ${...}\n const headText = node.head.text\n if (headText.length > 0) {\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.head.getStart(sourceFile))\n results.push({\n value: headText,\n line: lineIdx + 1,\n column: character + 1,\n context: classification.context,\n scope: 'script',\n parent: classification.parent,\n parentProperty: classification.parentProperty,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n }\n\n // Template spans: text after each ${...} expression\n for (const span of node.templateSpans) {\n const spanText = span.literal.text\n if (spanText.length > 0) {\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(span.literal.getStart(sourceFile))\n results.push({\n value: spanText,\n line: lineIdx + 1,\n column: character + 1,\n context: classification.context,\n scope: 'script',\n parent: classification.parent,\n parentProperty: classification.parentProperty,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n }\n\n // Visit the expression inside ${...} for nested strings\n visit(span.expression, sourceFile, lines, results)\n }\n}\n\n// ─── Parent chain classification ───\n\ninterface Classification {\n context: StructuralContext\n parent: string\n parentProperty?: string\n}\n\nfunction classifyByParentChain(node: ts.Node, sourceFile: ts.SourceFile): Classification {\n let current = node.parent\n\n while (current) {\n // Import / Export declaration → import_path\n if (ts.isImportDeclaration(current) || ts.isExportDeclaration(current)) {\n return { context: 'import_path', parent: 'import' }\n }\n\n // Import specifier module path (dynamic import)\n if (ts.isCallExpression(current) && current.expression.kind === ts.SyntaxKind.ImportKeyword) {\n return { context: 'import_path', parent: 'import' }\n }\n\n // require() calls\n if (\n ts.isCallExpression(current)\n && ts.isIdentifier(current.expression)\n && current.expression.text === 'require'\n ) {\n return { context: 'import_path', parent: 'require' }\n }\n\n // JSX attribute → jsx_attribute or css_class\n if (ts.isJsxAttribute(current)) {\n const attrName = ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile)\n // className / class / style → CSS, not content\n if (attrName === 'className' || attrName === 'class' || attrName === 'style') {\n return { context: 'css_class', parent: attrName }\n }\n return { context: 'jsx_attribute', parent: attrName, parentProperty: attrName }\n }\n\n // Variable declaration → variable_assignment\n if (ts.isVariableDeclaration(current)) {\n const varName = ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile)\n return { context: 'variable_assignment', parent: varName }\n }\n\n // Property assignment → object_property\n if (ts.isPropertyAssignment(current)) {\n const key = ts.isIdentifier(current.name)\n ? current.name.text\n : ts.isStringLiteral(current.name)\n ? current.name.text\n : current.name.getText(sourceFile)\n return { context: 'object_property', parent: key, parentProperty: key }\n }\n\n // Enum member → enum_value\n if (ts.isEnumMember(current)) {\n const enumName = ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile)\n return { context: 'enum_value', parent: enumName }\n }\n\n // Call expression → function_argument or css_utility_call or console_call or test_assertion\n if (ts.isCallExpression(current)) {\n const callee = getCalleeName(current.expression, sourceFile)\n // CSS utility functions\n if (['cn', 'clsx', 'classNames', 'twMerge', 'twJoin', 'cva', 'cx'].includes(callee)) {\n return { context: 'css_utility_call', parent: callee }\n }\n // Console calls\n if (callee.startsWith('console.')) {\n return { context: 'console_call', parent: callee }\n }\n // Test assertions\n if (['describe', 'it', 'test', 'expect', 'beforeEach', 'afterEach', 'beforeAll', 'afterAll'].includes(callee)) {\n return { context: 'test_assertion', parent: callee }\n }\n return { context: 'function_argument', parent: callee }\n }\n\n // Array literal → array_element\n if (ts.isArrayLiteralExpression(current)) {\n return { context: 'array_element', parent: 'array' }\n }\n\n // Case clause → switch_case\n if (ts.isCaseClause(current)) {\n return { context: 'switch_case', parent: 'case' }\n }\n\n // Type contexts → type_annotation\n if (\n ts.isTypeAliasDeclaration(current)\n || ts.isTypeReferenceNode(current)\n || ts.isInterfaceDeclaration(current)\n || ts.isTypeLiteralNode(current)\n || ts.isLiteralTypeNode(current)\n || ts.isUnionTypeNode(current)\n || ts.isIntersectionTypeNode(current)\n ) {\n return { context: 'type_annotation', parent: 'type' }\n }\n\n // Property declaration with type context (e.g., `as const` typed properties)\n // Check if we're inside a type annotation specifically\n if (ts.isPropertySignature(current)) {\n return { context: 'type_annotation', parent: 'type' }\n }\n\n current = current.parent\n }\n\n return { context: 'other', parent: '' }\n}\n\n// ─── Callee name extraction ───\n\nfunction getCalleeName(expr: ts.Expression, sourceFile: ts.SourceFile): string {\n if (ts.isIdentifier(expr)) {\n return expr.text\n }\n if (ts.isPropertyAccessExpression(expr)) {\n // e.g., console.log → \"console.log\"\n const obj = getCalleeName(expr.expression, sourceFile)\n return obj ? `${obj}.${expr.name.text}` : expr.name.text\n }\n return expr.getText(sourceFile)\n}\n\n// ─── JSX parent tag extraction ───\n\nfunction getJsxParentTag(node: ts.Node): string {\n let current = node.parent\n\n while (current) {\n if (ts.isJsxElement(current)) {\n const tagName = current.openingElement.tagName.getText()\n return tagName\n }\n if (ts.isJsxFragment(current)) {\n return 'Fragment'\n }\n current = current.parent\n }\n\n return ''\n}\n\n// ─── Surrounding code builder ───\n\nfunction buildSurrounding(lines: string[], lineIdx: number): string {\n const start = Math.max(0, lineIdx - 1)\n const end = Math.min(lines.length - 1, lineIdx + 1)\n\n const parts: string[] = []\n for (let i = start; i <= end; i++) {\n const line = lines[i]\n if (line !== undefined) {\n parts.push(line)\n }\n }\n\n const joined = parts.join('\\n')\n if (joined.length > SURROUNDING_MAX) {\n return joined.slice(0, SURROUNDING_MAX)\n }\n return joined\n}\n"],"mappings":"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"}
@@ -1,4 +1,3 @@
1
- import "../serializer-CnHTtmc1.mjs";
2
- import "../fs-BnIQ4dKj.mjs";
3
- import { n as detectStackInfo, r as inferPlatform, t as detectStack } from "../detect-DinOQAmK.mjs";
1
+ import "../fs-DLbVB-Ek.mjs";
2
+ import { n as detectStackInfo, r as inferPlatform, t as detectStack } from "../detect-DL9mFmaS.mjs";
4
3
  export { detectStack, detectStackInfo, inferPlatform };
package/dist/util/fs.mjs CHANGED
@@ -1,3 +1,2 @@
1
- import "../serializer-CnHTtmc1.mjs";
2
- import { a as readJson, c as writeText, i as readDir, n as ensureDir, o as readText, r as pathExists, s as writeJson, t as contentrainDir } from "../fs-BnIQ4dKj.mjs";
1
+ import { a as readJson, c as writeText, i as readDir, n as ensureDir, o as readText, r as pathExists, s as writeJson, t as contentrainDir } from "../fs-DLbVB-Ek.mjs";
3
2
  export { contentrainDir, ensureDir, pathExists, readDir, readJson, readText, writeJson, writeText };
package/dist/util/id.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as generateEntryId, t as branchTimestamp } from "../id-DV_T9Ic8.mjs";
1
+ import { n as generateEntryId, t as branchTimestamp } from "../id-CIO9s0x_.mjs";
2
2
  export { branchTimestamp, generateEntryId };