@carboncode/cli 0.1.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 (159) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSES/DeepSeek-Reasonix-MIT.txt +21 -0
  3. package/README.md +109 -0
  4. package/README.zh-CN.md +91 -0
  5. package/THIRD_PARTY_NOTICES.md +14 -0
  6. package/dashboard/app.css +3233 -0
  7. package/dashboard/dist/app.js +30444 -0
  8. package/dashboard/dist/app.js.map +1 -0
  9. package/dashboard/dist/vendor-hljs.css +10 -0
  10. package/dashboard/dist/vendor-uplot.css +1 -0
  11. package/dashboard/index.html +19 -0
  12. package/data/deepseek-tokenizer.json.gz +0 -0
  13. package/dist/cli/acp-35C4ME6Y.js +711 -0
  14. package/dist/cli/acp-35C4ME6Y.js.map +1 -0
  15. package/dist/cli/chat-A6UJDPGV.js +51 -0
  16. package/dist/cli/chat-A6UJDPGV.js.map +1 -0
  17. package/dist/cli/chunk-2425HK6U.js +54 -0
  18. package/dist/cli/chunk-2425HK6U.js.map +1 -0
  19. package/dist/cli/chunk-25T6CVUP.js +172 -0
  20. package/dist/cli/chunk-25T6CVUP.js.map +1 -0
  21. package/dist/cli/chunk-2UQP6H6T.js +31 -0
  22. package/dist/cli/chunk-2UQP6H6T.js.map +1 -0
  23. package/dist/cli/chunk-3OAR6NVL.js +96 -0
  24. package/dist/cli/chunk-3OAR6NVL.js.map +1 -0
  25. package/dist/cli/chunk-3T6VBZCL.js +54 -0
  26. package/dist/cli/chunk-3T6VBZCL.js.map +1 -0
  27. package/dist/cli/chunk-4IBIPQVB.js +153 -0
  28. package/dist/cli/chunk-4IBIPQVB.js.map +1 -0
  29. package/dist/cli/chunk-4MQ3VURH.js +3106 -0
  30. package/dist/cli/chunk-4MQ3VURH.js.map +1 -0
  31. package/dist/cli/chunk-4TVNJWMA.js +11619 -0
  32. package/dist/cli/chunk-4TVNJWMA.js.map +1 -0
  33. package/dist/cli/chunk-4VR6XF4P.js +341 -0
  34. package/dist/cli/chunk-4VR6XF4P.js.map +1 -0
  35. package/dist/cli/chunk-5QCB62C4.js +25319 -0
  36. package/dist/cli/chunk-5QCB62C4.js.map +1 -0
  37. package/dist/cli/chunk-6OWJV3YW.js +390 -0
  38. package/dist/cli/chunk-6OWJV3YW.js.map +1 -0
  39. package/dist/cli/chunk-7EO27TB3.js +130 -0
  40. package/dist/cli/chunk-7EO27TB3.js.map +1 -0
  41. package/dist/cli/chunk-7L2WTRNU.js +308 -0
  42. package/dist/cli/chunk-7L2WTRNU.js.map +1 -0
  43. package/dist/cli/chunk-BHTZFEYE.js +47 -0
  44. package/dist/cli/chunk-BHTZFEYE.js.map +1 -0
  45. package/dist/cli/chunk-BSGCXZQN.js +343 -0
  46. package/dist/cli/chunk-BSGCXZQN.js.map +1 -0
  47. package/dist/cli/chunk-BSINVTTL.js +464 -0
  48. package/dist/cli/chunk-BSINVTTL.js.map +1 -0
  49. package/dist/cli/chunk-CPKCNHRR.js +323 -0
  50. package/dist/cli/chunk-CPKCNHRR.js.map +1 -0
  51. package/dist/cli/chunk-CXVWUPA3.js +96 -0
  52. package/dist/cli/chunk-CXVWUPA3.js.map +1 -0
  53. package/dist/cli/chunk-D5NFKRGO.js +160 -0
  54. package/dist/cli/chunk-D5NFKRGO.js.map +1 -0
  55. package/dist/cli/chunk-ECHSFYOY.js +109 -0
  56. package/dist/cli/chunk-ECHSFYOY.js.map +1 -0
  57. package/dist/cli/chunk-FEZK652I.js +3644 -0
  58. package/dist/cli/chunk-FEZK652I.js.map +1 -0
  59. package/dist/cli/chunk-GALC45Q2.js +696 -0
  60. package/dist/cli/chunk-GALC45Q2.js.map +1 -0
  61. package/dist/cli/chunk-IAUOP25G.js +2984 -0
  62. package/dist/cli/chunk-IAUOP25G.js.map +1 -0
  63. package/dist/cli/chunk-ILJOIQ5W.js +163 -0
  64. package/dist/cli/chunk-ILJOIQ5W.js.map +1 -0
  65. package/dist/cli/chunk-IX6XI2RG.js +225 -0
  66. package/dist/cli/chunk-IX6XI2RG.js.map +1 -0
  67. package/dist/cli/chunk-J5BYPUB5.js +62795 -0
  68. package/dist/cli/chunk-J5BYPUB5.js.map +1 -0
  69. package/dist/cli/chunk-J5XJHLWM.js +55 -0
  70. package/dist/cli/chunk-J5XJHLWM.js.map +1 -0
  71. package/dist/cli/chunk-JKGYMRX5.js +101 -0
  72. package/dist/cli/chunk-JKGYMRX5.js.map +1 -0
  73. package/dist/cli/chunk-JMBMLOBP.js +26 -0
  74. package/dist/cli/chunk-JMBMLOBP.js.map +1 -0
  75. package/dist/cli/chunk-LN3B5PMX.js +128 -0
  76. package/dist/cli/chunk-LN3B5PMX.js.map +1 -0
  77. package/dist/cli/chunk-M2UFZUX3.js +635 -0
  78. package/dist/cli/chunk-M2UFZUX3.js.map +1 -0
  79. package/dist/cli/chunk-PJS34556.js +809 -0
  80. package/dist/cli/chunk-PJS34556.js.map +1 -0
  81. package/dist/cli/chunk-QJG7OF27.js +655 -0
  82. package/dist/cli/chunk-QJG7OF27.js.map +1 -0
  83. package/dist/cli/chunk-QVC75MR3.js +232 -0
  84. package/dist/cli/chunk-QVC75MR3.js.map +1 -0
  85. package/dist/cli/chunk-S2KIUQKQ.js +378 -0
  86. package/dist/cli/chunk-S2KIUQKQ.js.map +1 -0
  87. package/dist/cli/chunk-S4XVGLRW.js +499 -0
  88. package/dist/cli/chunk-S4XVGLRW.js.map +1 -0
  89. package/dist/cli/chunk-T5TQ4NDT.js +190 -0
  90. package/dist/cli/chunk-T5TQ4NDT.js.map +1 -0
  91. package/dist/cli/chunk-TH756VLN.js +1924 -0
  92. package/dist/cli/chunk-TH756VLN.js.map +1 -0
  93. package/dist/cli/chunk-TUK7OWJA.js +51 -0
  94. package/dist/cli/chunk-TUK7OWJA.js.map +1 -0
  95. package/dist/cli/chunk-U4IJVG32.js +363 -0
  96. package/dist/cli/chunk-U4IJVG32.js.map +1 -0
  97. package/dist/cli/chunk-UI66BH6D.js +624 -0
  98. package/dist/cli/chunk-UI66BH6D.js.map +1 -0
  99. package/dist/cli/chunk-VPMBGAND.js +53 -0
  100. package/dist/cli/chunk-VPMBGAND.js.map +1 -0
  101. package/dist/cli/chunk-WLHH3OSR.js +522 -0
  102. package/dist/cli/chunk-WLHH3OSR.js.map +1 -0
  103. package/dist/cli/chunk-WRN65TRD.js +908 -0
  104. package/dist/cli/chunk-WRN65TRD.js.map +1 -0
  105. package/dist/cli/chunk-X53B3JIX.js +34320 -0
  106. package/dist/cli/chunk-X53B3JIX.js.map +1 -0
  107. package/dist/cli/chunk-XJ5SRLKK.js +50 -0
  108. package/dist/cli/chunk-XJ5SRLKK.js.map +1 -0
  109. package/dist/cli/chunk-YZSXRGFH.js +54 -0
  110. package/dist/cli/chunk-YZSXRGFH.js.map +1 -0
  111. package/dist/cli/code-4TUTAGO5.js +163 -0
  112. package/dist/cli/code-4TUTAGO5.js.map +1 -0
  113. package/dist/cli/commands-KMOZEYCF.js +356 -0
  114. package/dist/cli/commands-KMOZEYCF.js.map +1 -0
  115. package/dist/cli/commit-DTFA56VQ.js +292 -0
  116. package/dist/cli/commit-DTFA56VQ.js.map +1 -0
  117. package/dist/cli/desktop-7N3MHNBD.js +1274 -0
  118. package/dist/cli/desktop-7N3MHNBD.js.map +1 -0
  119. package/dist/cli/devtools-HW3WDT3Q.js +91 -0
  120. package/dist/cli/devtools-HW3WDT3Q.js.map +1 -0
  121. package/dist/cli/diff-E5OWTF4C.js +165 -0
  122. package/dist/cli/diff-E5OWTF4C.js.map +1 -0
  123. package/dist/cli/doctor-IEJQRJMN.js +27 -0
  124. package/dist/cli/doctor-IEJQRJMN.js.map +1 -0
  125. package/dist/cli/events-4625EGXI.js +340 -0
  126. package/dist/cli/events-4625EGXI.js.map +1 -0
  127. package/dist/cli/index.js +3536 -0
  128. package/dist/cli/index.js.map +1 -0
  129. package/dist/cli/mcp-PDI2PDLG.js +277 -0
  130. package/dist/cli/mcp-PDI2PDLG.js.map +1 -0
  131. package/dist/cli/mcp-browse-OSPXOFPZ.js +178 -0
  132. package/dist/cli/mcp-browse-OSPXOFPZ.js.map +1 -0
  133. package/dist/cli/mcp-inspect-QRFVTHMF.js +148 -0
  134. package/dist/cli/mcp-inspect-QRFVTHMF.js.map +1 -0
  135. package/dist/cli/package.json +3 -0
  136. package/dist/cli/prompt-3CDII3UO.js +16 -0
  137. package/dist/cli/prompt-3CDII3UO.js.map +1 -0
  138. package/dist/cli/prune-sessions-KZX4SXKW.js +44 -0
  139. package/dist/cli/prune-sessions-KZX4SXKW.js.map +1 -0
  140. package/dist/cli/replay-HYOSRQIV.js +291 -0
  141. package/dist/cli/replay-HYOSRQIV.js.map +1 -0
  142. package/dist/cli/run-2ZHADOUP.js +220 -0
  143. package/dist/cli/run-2ZHADOUP.js.map +1 -0
  144. package/dist/cli/server-X75PAZG5.js +3572 -0
  145. package/dist/cli/server-X75PAZG5.js.map +1 -0
  146. package/dist/cli/sessions-POOZA5CQ.js +120 -0
  147. package/dist/cli/sessions-POOZA5CQ.js.map +1 -0
  148. package/dist/cli/setup-YLPFI3OH.js +618 -0
  149. package/dist/cli/setup-YLPFI3OH.js.map +1 -0
  150. package/dist/cli/stats-NXJ3TO2D.js +16 -0
  151. package/dist/cli/stats-NXJ3TO2D.js.map +1 -0
  152. package/dist/cli/update-ZUO5MKQ6.js +15 -0
  153. package/dist/cli/update-ZUO5MKQ6.js.map +1 -0
  154. package/dist/cli/version-NXXWE3WN.js +33 -0
  155. package/dist/cli/version-NXXWE3WN.js.map +1 -0
  156. package/dist/index.d.ts +2523 -0
  157. package/dist/index.js +15408 -0
  158. package/dist/index.js.map +1 -0
  159. package/package.json +112 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/commands/index.ts","../../src/index/semantic/i18n.ts","../../src/index/semantic/preflight.ts"],"sourcesContent":["/** `carboncode index` — progress writes go to stderr so stdout stays pipeable. */\n\nimport { resolve } from \"node:path\";\nimport { loadIndexConfig, resolveSemanticEmbeddingConfig } from \"../../config.js\";\nimport { buildIndex } from \"../../index/semantic/builder.js\";\nimport type { BuildProgress, BuildResult, SkipBuckets } from \"../../index/semantic/builder.js\";\nimport { t } from \"../../index/semantic/i18n.js\";\nimport { semanticPreflight } from \"../../index/semantic/preflight.js\";\n\nexport interface IndexCommandOptions {\n rebuild?: boolean;\n model?: string;\n dir?: string;\n ollamaUrl?: string;\n yes?: boolean;\n}\n\nexport async function indexCommand(opts: IndexCommandOptions = {}): Promise<void> {\n const root = resolve(opts.dir ?? process.cwd());\n const tty = process.stderr.isTTY === true && process.stdin.isTTY === true;\n const resolved = resolveSemanticEmbeddingConfig();\n const embedding =\n resolved.provider === \"ollama\"\n ? {\n ...resolved,\n model: opts.model ?? resolved.model,\n baseUrl: opts.ollamaUrl ?? resolved.baseUrl,\n }\n : {\n ...resolved,\n model: opts.model ?? resolved.model,\n };\n\n const preflightOk = await semanticPreflight(embedding, {\n interactive: tty && !opts.yes,\n yesToAll: opts.yes ?? false,\n });\n if (!preflightOk) process.exit(1);\n\n const writer = makeProgressWriter(tty);\n\n const t0 = Date.now();\n let result: BuildResult;\n try {\n result = await buildIndex(root, {\n ...embedding,\n rebuild: opts.rebuild,\n indexConfig: loadIndexConfig(),\n onProgress: (p) => writer.update(p),\n });\n } catch (err) {\n writer.clear();\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(t(\"indexFailed\", { msg }));\n process.exit(1);\n }\n writer.clear();\n\n const seconds = ((Date.now() - t0) / 1000).toFixed(1);\n const successKey = result.chunksSkipped > 0 ? \"indexSuccessWithSkips\" : \"indexSuccess\";\n process.stderr.write(\n t(successKey, {\n scanned: result.filesScanned,\n changed: result.filesChanged,\n added: result.chunksAdded,\n removed: result.chunksRemoved,\n skipped: result.chunksSkipped,\n seconds,\n }),\n );\n const breakdown = renderSkipBreakdown(result.skipBuckets);\n if (breakdown) process.stderr.write(`${breakdown}\\n`);\n if (result.filesChanged === 0 && !opts.rebuild) {\n process.stderr.write(t(\"indexNothingToDo\"));\n }\n}\n\nfunction renderSkipBreakdown(buckets: SkipBuckets): string {\n const total = Object.values(buckets).reduce((a, b) => a + b, 0);\n if (total === 0) return \"\";\n const parts: string[] = [];\n if (buckets.gitignore) parts.push(`gitignore: ${buckets.gitignore}`);\n if (buckets.pattern) parts.push(`pattern: ${buckets.pattern}`);\n if (buckets.defaultDir) parts.push(`defaultDir: ${buckets.defaultDir}`);\n if (buckets.defaultFile) parts.push(`defaultFile: ${buckets.defaultFile}`);\n if (buckets.binaryExt) parts.push(`binaryExt: ${buckets.binaryExt}`);\n if (buckets.binaryContent) parts.push(`binaryContent: ${buckets.binaryContent}`);\n if (buckets.tooLarge) parts.push(`tooLarge: ${buckets.tooLarge}`);\n if (buckets.readError) parts.push(`readError: ${buckets.readError}`);\n return ` · skipped ${total} files (${parts.join(\", \")})`;\n}\n\ninterface ProgressWriter {\n update(p: BuildProgress): void;\n clear(): void;\n}\n\nconst SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\nconst SPINNER_INTERVAL_MS = 120;\n\nfunction makeProgressWriter(tty: boolean): ProgressWriter {\n if (!tty) return makeNonTtyWriter();\n return makeTtyWriter();\n}\n\nfunction makeNonTtyWriter(): ProgressWriter {\n let lastPhase: BuildProgress[\"phase\"] | null = null;\n let lastChunks = 0;\n return {\n update(p) {\n if (p.phase !== lastPhase) {\n lastPhase = p.phase;\n if (p.phase === \"scan\") {\n process.stderr.write(t(\"progressScanLine\"));\n } else if (p.phase === \"embed\") {\n process.stderr.write(\n t(\"progressEmbedLine\", {\n total: p.chunksTotal ?? 0,\n files: p.filesChanged ?? 0,\n }),\n );\n }\n }\n if (p.phase === \"embed\" && p.chunksDone !== undefined && p.chunksDone - lastChunks >= 50) {\n lastChunks = p.chunksDone;\n process.stderr.write(\n t(\"progressEmbedHeartbeat\", {\n done: p.chunksDone,\n total: p.chunksTotal ?? \"?\",\n }),\n );\n }\n },\n clear() {\n /* non-TTY keeps its accumulated lines */\n },\n };\n}\n\nfunction makeTtyWriter(): ProgressWriter {\n let status = t(\"progressStarting\");\n let lastLineLen = 0;\n let frameIdx = 0;\n const startTs = Date.now();\n\n const repaint = () => {\n const frame = SPINNER_FRAMES[frameIdx % SPINNER_FRAMES.length];\n frameIdx++;\n const elapsed = ((Date.now() - startTs) / 1000).toFixed(1);\n const line = `${frame} ${status} ${elapsed}s`;\n const padded = line + \" \".repeat(Math.max(0, lastLineLen - line.length));\n process.stderr.write(`\\r${padded}`);\n lastLineLen = line.length;\n };\n\n repaint();\n const interval = setInterval(repaint, SPINNER_INTERVAL_MS);\n\n return {\n update(p) {\n if (p.phase === \"scan\") {\n status = t(\"progressScan\", { files: p.filesScanned ?? 0 });\n } else if (p.phase === \"embed\") {\n const done = p.chunksDone ?? 0;\n const total = p.chunksTotal ?? 0;\n const pct = total > 0 ? ((done / total) * 100).toFixed(0) : \"0\";\n status = t(\"progressEmbed\", { done, total, pct });\n }\n repaint();\n },\n clear() {\n clearInterval(interval);\n if (lastLineLen > 0) {\n process.stderr.write(`\\r${\" \".repeat(lastLineLen)}\\r`);\n lastLineLen = 0;\n }\n },\n };\n}\n","/** EN+ZH for semantic-search prompts only; tool descriptions stay English to preserve prompt-cache. */\n\nexport type Locale = \"en\" | \"zh\";\n\nlet cachedLocale: Locale | null = null;\n\nexport function detectLocale(): Locale {\n if (cachedLocale) return cachedLocale;\n const override = (process.env.REASONIX_LANG ?? \"\").toLowerCase();\n if (override === \"zh\" || override === \"en\") {\n cachedLocale = override;\n return cachedLocale;\n }\n const env = process.env.LANG ?? process.env.LC_ALL ?? process.env.LC_MESSAGES ?? \"\";\n if (/^zh[-_]/i.test(env)) {\n cachedLocale = \"zh\";\n return \"zh\";\n }\n try {\n const sys = new Intl.DateTimeFormat().resolvedOptions().locale ?? \"\";\n if (/^zh[-_]/i.test(sys)) {\n cachedLocale = \"zh\";\n return \"zh\";\n }\n } catch {\n /* ignore — fall through to default */\n }\n cachedLocale = \"en\";\n return \"en\";\n}\n\n/** Reset the cached locale. Tests use this; production never needs it. */\nexport function resetLocaleCache(): void {\n cachedLocale = null;\n}\n\n/** Falls back to English so partial dictionary updates never show \"[missing]\". */\nexport function t(key: keyof typeof EN, vars: Record<string, string | number> = {}): string {\n const loc = detectLocale();\n const dict = loc === \"zh\" ? ZH : EN;\n const tpl = dict[key] ?? EN[key];\n return tpl.replace(/\\{(\\w+)\\}/g, (_m, name) => {\n const v = vars[name];\n return v === undefined ? `{${name}}` : String(v);\n });\n}\n\nconst EN = {\n // ── preflight ─────────────────────────────────────────────────────\n ollamaNotFound:\n \"✗ `ollama` not found on PATH.\\n Install from https://ollama.com (one-time, ~150 MB), then retry.\\n\",\n daemonNotReachableHint:\n \"✗ Ollama daemon not reachable. Run `ollama serve` and retry, or pass --yes to start it automatically.\\n\",\n daemonStartConfirm: \"Ollama daemon isn't running. Start `ollama serve` now?\",\n daemonAbortStart: \"✗ aborted — start `ollama serve` yourself and retry.\\n\",\n daemonStarting: \"▸ starting `ollama serve`…\\n\",\n daemonStartTimeout:\n \"✗ daemon didn't come up within 15s. Try `ollama serve` in a separate terminal and retry.\\n\",\n daemonReady: \"✓ daemon up{pid}\\n\",\n modelNotPulledHint:\n '✗ embedding model \"{model}\" not pulled. Run `ollama pull {model}` and retry, or pass --yes to pull it automatically.\\n',\n modelPullConfirm:\n 'Embedding model \"{model}\" isn\\'t pulled yet. Pull it now? (~274 MB for nomic-embed-text)',\n modelAbortPull: \"✗ aborted — pull the model yourself and retry.\\n\",\n modelPulling: \"▸ pulling {model}…\\n\",\n modelPullFailed: \"✗ `ollama pull {model}` failed (exit {code}).\\n\",\n modelPulled: \"✓ {model} pulled\\n\",\n\n // ── progress ─────────────────────────────────────────────────────\n // The TTY-mode progress writer paints `<spinner> <status> <elapsed>s`\n // every 120ms. The status itself comes from one of these keys based\n // on the current phase. {files}, {done}, {total}, {pct} are\n // substituted by the writer.\n progressStarting: \"starting…\",\n progressScan: \"scanning project · {files} files\",\n progressEmbed: \"embedding {done}/{total} chunks · {pct}%\",\n progressEmbedHeartbeat: \" {done}/{total}\\n\",\n progressScanLine: \"scanning files…\\n\",\n progressEmbedLine: \"embedding {total} chunks across {files} files…\\n\",\n // Final result line after a successful build.\n indexSuccess:\n \"✓ indexed {scanned} files ({changed} changed, {added} new chunks, {removed} stale removed) in {seconds}s\\n\",\n indexSuccessWithSkips:\n \"✓ indexed {scanned} files ({changed} changed, {added} new chunks, {removed} stale removed, {skipped} skipped due to embed errors) in {seconds}s\\n\",\n indexNothingToDo: \" (nothing to do — re-run with --rebuild to force a full rebuild)\\n\",\n indexFailed: \"✗ index failed: {msg}\\n\",\n\n // ── /semantic slash ──────────────────────────────────────────────\n slashHeader: \"semantic_search status\",\n slashEnabled: \"✓ enabled — index built, tool registered.\",\n slashEnabledDetail: \" index size: {chunks} chunks across {files} files\",\n slashEnabledHowto: \" the model will call semantic_search automatically when it fits.\",\n slashIndexMissing: \"✗ no index built yet for this project.\",\n slashHowToBuild: \" to enable, exit Carbon Code and run in your shell:\\n carboncode index\",\n slashOllamaMissing: \" prerequisite: install Ollama from https://ollama.com\",\n slashDaemonDown:\n \" Ollama is installed but the daemon isn't running. start it with: ollama serve\",\n slashIndexInfo:\n \" what semantic_search does: cross-language code understanding via local embeddings.\\n better than grep when you describe WHAT something does, not WHICH token to find.\",\n} as const;\n\nconst ZH: Partial<Record<keyof typeof EN, string>> = {\n ollamaNotFound:\n \"✗ 未找到 `ollama`。\\n 请访问 https://ollama.com 安装(一次性,约 150 MB),然后重试。\\n\",\n daemonNotReachableHint:\n \"✗ Ollama 守护进程未启动。请运行 `ollama serve` 后重试,或加 --yes 让我自动启动。\\n\",\n daemonStartConfirm: \"Ollama 守护进程未运行。现在启动 `ollama serve` 吗?\",\n daemonAbortStart: \"✗ 已取消——请自行运行 `ollama serve` 后重试。\\n\",\n daemonStarting: \"▸ 正在启动 `ollama serve`…\\n\",\n daemonStartTimeout: \"✗ 15 秒内守护进程未就绪。请在另一个终端运行 `ollama serve` 后重试。\\n\",\n daemonReady: \"✓ 守护进程已启动{pid}\\n\",\n modelNotPulledHint:\n '✗ 嵌入模型 \"{model}\" 未下载。请运行 `ollama pull {model}` 后重试,或加 --yes 让我自动下载。\\n',\n modelPullConfirm: '嵌入模型 \"{model}\" 还未下载。现在下载吗?(nomic-embed-text 约 274 MB)',\n modelAbortPull: \"✗ 已取消——请自行下载模型后重试。\\n\",\n modelPulling: \"▸ 正在下载 {model}…\\n\",\n modelPullFailed: \"✗ `ollama pull {model}` 失败(退出码 {code})。\\n\",\n modelPulled: \"✓ {model} 下载完成\\n\",\n\n progressStarting: \"正在启动…\",\n progressScan: \"扫描项目 · 已扫描 {files} 个文件\",\n progressEmbed: \"正在向量化 {done}/{total} 个片段 · {pct}%\",\n progressEmbedHeartbeat: \" {done}/{total}\\n\",\n progressScanLine: \"正在扫描文件…\\n\",\n progressEmbedLine: \"正在向量化 {total} 个片段(涉及 {files} 个文件)…\\n\",\n indexSuccess:\n \"✓ 已建立索引:扫描 {scanned} 个文件({changed} 个有变化,新增 {added} 个片段,移除 {removed} 个过期);耗时 {seconds}s\\n\",\n indexSuccessWithSkips:\n \"✓ 已建立索引:扫描 {scanned} 个文件({changed} 个有变化,新增 {added} 个片段,移除 {removed} 个过期,跳过 {skipped} 个嵌入失败的片段);耗时 {seconds}s\\n\",\n indexNothingToDo: \" (没有变化——加 --rebuild 强制重建)\\n\",\n indexFailed: \"✗ 建立索引失败:{msg}\\n\",\n\n slashHeader: \"semantic_search 状态\",\n slashEnabled: \"✓ 已启用——索引已建好,工具已注册。\",\n slashEnabledDetail: \" 索引规模:{chunks} 个片段,{files} 个文件\",\n slashEnabledHowto: \" 模型在合适的时候会自动调用 semantic_search。\",\n slashIndexMissing: \"✗ 当前项目还没有索引。\",\n slashHowToBuild: \" 启用方式:退出 Carbon Code,在终端运行:\\n carboncode index\",\n slashOllamaMissing: \" 前置依赖:从 https://ollama.com 安装 Ollama\",\n slashDaemonDown: \" 已装 Ollama 但守护进程未启动,请运行:ollama serve\",\n slashIndexInfo:\n ' semantic_search 用本地 embedding 做跨语言代码理解。\\n 当你描述\"做什么\"而不是具体 token 时,比 grep 更好。',\n};\n","import { stdin, stdout } from \"node:process\";\nimport { createInterface } from \"node:readline/promises\";\nimport type { ResolvedEmbeddingConfig } from \"../../config.js\";\nimport { t } from \"./i18n.js\";\nimport { checkOllamaStatus, pullOllamaModel, startOllamaDaemon } from \"./ollama-launcher.js\";\n\nexport interface PreflightOptions {\n model: string;\n baseUrl?: string | undefined;\n interactive: boolean;\n yesToAll: boolean;\n log?: (line: string) => void;\n}\n\nexport async function ollamaPreflight(opts: PreflightOptions): Promise<boolean> {\n const log = opts.log ?? ((line: string) => process.stderr.write(line));\n const status = await checkOllamaStatus(opts.model, opts.baseUrl);\n\n if (!status.binaryFound) {\n log(t(\"ollamaNotFound\"));\n return false;\n }\n\n if (!status.daemonRunning) {\n if (!opts.interactive && !opts.yesToAll) {\n log(t(\"daemonNotReachableHint\"));\n return false;\n }\n const ok = opts.yesToAll || (await confirm(t(\"daemonStartConfirm\"), true));\n if (!ok) {\n log(t(\"daemonAbortStart\"));\n return false;\n }\n log(t(\"daemonStarting\"));\n const started = await startOllamaDaemon({ baseUrl: opts.baseUrl, timeoutMs: 15_000 });\n if (!started.ready) {\n log(t(\"daemonStartTimeout\"));\n return false;\n }\n log(t(\"daemonReady\", { pid: started.pid ? ` (pid ${started.pid})` : \"\" }));\n }\n\n const after = status.daemonRunning ? status : await checkOllamaStatus(opts.model, opts.baseUrl);\n\n if (!after.modelPulled) {\n if (!opts.interactive && !opts.yesToAll) {\n log(t(\"modelNotPulledHint\", { model: opts.model }));\n return false;\n }\n const ok = opts.yesToAll || (await confirm(t(\"modelPullConfirm\", { model: opts.model }), true));\n if (!ok) {\n log(t(\"modelAbortPull\"));\n return false;\n }\n log(t(\"modelPulling\", { model: opts.model }));\n const ESC = String.fromCharCode(0x1b);\n const ANSI_CSI = new RegExp(`${ESC}\\\\[[0-9;]*[A-Za-z]`, \"g\");\n const code = await pullOllamaModel(opts.model, {\n onLine: (line) => {\n const cleaned = line.replace(ANSI_CSI, \"\").trim();\n if (cleaned.length === 0) return;\n log(` ${cleaned}\\n`);\n },\n });\n if (code !== 0) {\n log(t(\"modelPullFailed\", { model: opts.model, code }));\n return false;\n }\n log(t(\"modelPulled\", { model: opts.model }));\n }\n\n return true;\n}\n\nexport async function semanticPreflight(\n config: ResolvedEmbeddingConfig,\n opts: Omit<PreflightOptions, \"model\" | \"baseUrl\">,\n): Promise<boolean> {\n if (config.provider === \"openai-compat\") return true;\n return await ollamaPreflight({\n ...opts,\n model: config.model,\n baseUrl: config.baseUrl,\n });\n}\n\nexport async function confirm(question: string, defaultYes: boolean): Promise<boolean> {\n const suffix = defaultYes ? \"[Y/n]\" : \"[y/N]\";\n const rl = createInterface({ input: stdin, output: stdout });\n try {\n const raw = (await rl.question(`${question} ${suffix} `)).trim().toLowerCase();\n if (raw === \"\") return defaultYes;\n return raw === \"y\" || raw === \"yes\";\n } finally {\n rl.close();\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,292 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
+ import {
4
+ DeepSeekClient
5
+ } from "./chunk-BSGCXZQN.js";
6
+ import "./chunk-25T6CVUP.js";
7
+ import {
8
+ loadDotenv
9
+ } from "./chunk-2UQP6H6T.js";
10
+ import {
11
+ loadApiKey,
12
+ loadBaseUrl
13
+ } from "./chunk-4MQ3VURH.js";
14
+ import "./chunk-TUK7OWJA.js";
15
+
16
+ // src/cli/commands/commit.ts
17
+ import { spawn, spawnSync } from "child_process";
18
+ import { mkdtempSync, readFileSync, unlinkSync, writeFileSync } from "fs";
19
+ import { tmpdir } from "os";
20
+ import { join } from "path";
21
+ import { stdin, stdout } from "process";
22
+ import { createInterface } from "readline/promises";
23
+ var DEFAULT_MODEL = "deepseek-v4-flash";
24
+ var DIFF_BYTE_CAP = 80 * 1024;
25
+ var LOG_COUNT = 10;
26
+ var SYSTEM_PROMPT = `You draft git commit messages.
27
+
28
+ Output ONLY the commit message \u2014 no preamble, no \`\`\` fences, no "Here's a commit message:" lead-in. The first line of your output IS the commit subject.
29
+
30
+ Match the project's existing style:
31
+ - Look at the recent commits provided. Mirror their voice, conventional-commit prefix usage (or absence), tense, length, body structure.
32
+ - If recent commits use a "type(scope): summary" prefix, use it. If they don't, don't invent one.
33
+ - Subject line: one line, \u226472 chars, imperative mood, no trailing period.
34
+ - Body (optional): explain WHY when the diff isn't self-evident. Wrap at ~72 chars. Skip the body for trivial changes \u2014 repeating the subject in the body is noise.
35
+
36
+ The diff is the source of truth for what changed; describe THAT, not your guesses about the broader project. If the diff includes a deletion you can't explain from the surrounding context, name it but don't speculate about why.
37
+
38
+ No emojis unless the recent commits use them.
39
+ No co-author trailers, no "Generated with X" footers.`;
40
+ function runGit(args, opts = {}) {
41
+ const result = spawnSync("git", args, {
42
+ encoding: "utf8",
43
+ stdio: ["pipe", "pipe", "pipe"],
44
+ input: opts.input,
45
+ maxBuffer: 32 * 1024 * 1024
46
+ });
47
+ return {
48
+ stdout: result.stdout ?? "",
49
+ stderr: result.stderr ?? "",
50
+ status: result.status
51
+ };
52
+ }
53
+ function dieIfNotGitRepo() {
54
+ const r = runGit(["rev-parse", "--is-inside-work-tree"]);
55
+ if (r.status !== 0) {
56
+ process.stderr.write("carboncode commit: not inside a git repository.\n");
57
+ process.exit(1);
58
+ }
59
+ }
60
+ function readDiff() {
61
+ const staged = runGit(["diff", "--staged", "--no-color"]);
62
+ if (staged.status !== 0) {
63
+ process.stderr.write(`carboncode commit: git diff --staged failed: ${staged.stderr.trim()}
64
+ `);
65
+ process.exit(1);
66
+ }
67
+ if (staged.stdout.trim().length > 0) {
68
+ return capDiff(staged.stdout, "staged");
69
+ }
70
+ const wt = runGit(["diff", "--no-color"]);
71
+ if (wt.stdout.trim().length === 0) {
72
+ return null;
73
+ }
74
+ return capDiff(wt.stdout, "working-tree");
75
+ }
76
+ function capDiff(raw, source) {
77
+ if (raw.length <= DIFF_BYTE_CAP) {
78
+ return { diff: raw, source, truncated: false };
79
+ }
80
+ const head = raw.slice(0, Math.floor(DIFF_BYTE_CAP * 0.7));
81
+ const tail = raw.slice(-Math.floor(DIFF_BYTE_CAP * 0.3));
82
+ return {
83
+ diff: `${head}
84
+
85
+ [\u2026 ${raw.length - DIFF_BYTE_CAP} bytes of diff truncated \u2026]
86
+
87
+ ${tail}`,
88
+ source,
89
+ truncated: true
90
+ };
91
+ }
92
+ function readRecentCommits() {
93
+ const r = runGit(["log", `-${LOG_COUNT}`, "--no-merges", "--format=%s%n%b%n---END---"]);
94
+ if (r.status !== 0) {
95
+ return "";
96
+ }
97
+ return r.stdout.trim();
98
+ }
99
+ async function draftMessage(client, model, diff, recentCommits) {
100
+ const userParts = [];
101
+ if (recentCommits) {
102
+ userParts.push(`Recent commits (style reference):
103
+
104
+ ${recentCommits}`);
105
+ }
106
+ if (diff.source === "working-tree") {
107
+ userParts.push(
108
+ "(NOTE: diff is from the working tree, not the staging area \u2014 nothing is staged yet. The user will stage selectively after seeing the draft.)"
109
+ );
110
+ }
111
+ userParts.push(`Diff to summarize:
112
+
113
+ ${diff.diff}`);
114
+ const resp = await client.chat({
115
+ model,
116
+ messages: [
117
+ { role: "system", content: SYSTEM_PROMPT },
118
+ { role: "user", content: userParts.join("\n\n") }
119
+ ],
120
+ temperature: 0.2
121
+ });
122
+ return stripCodeFences(resp.content.trim());
123
+ }
124
+ function stripCodeFences(s) {
125
+ const trimmed = s.trim();
126
+ const fenceOpen = /^```[a-zA-Z]*\n/;
127
+ const fenceClose = /\n?```$/;
128
+ if (fenceOpen.test(trimmed) && fenceClose.test(trimmed)) {
129
+ return trimmed.replace(fenceOpen, "").replace(fenceClose, "").trim();
130
+ }
131
+ return trimmed;
132
+ }
133
+ function printDraft(message) {
134
+ const sep = "\u2500".repeat(60);
135
+ process.stdout.write(`
136
+ ${sep}
137
+ ${message}
138
+ ${sep}
139
+
140
+ `);
141
+ }
142
+ async function promptChoice() {
143
+ const rl = createInterface({ input: stdin, output: stdout });
144
+ try {
145
+ const answer = await rl.question("[a]ccept / [r]egenerate / [e]dit / [c]ancel: ");
146
+ const k = answer.trim().toLowerCase();
147
+ if (k === "" || k === "a" || k === "y" || k === "yes") return "accept";
148
+ if (k === "r" || k === "regen" || k === "regenerate") return "regen";
149
+ if (k === "e" || k === "edit") return "edit";
150
+ return "cancel";
151
+ } finally {
152
+ rl.close();
153
+ }
154
+ }
155
+ function editInExternal(initial) {
156
+ const editor = process.env.GIT_EDITOR ?? process.env.VISUAL ?? process.env.EDITOR;
157
+ if (!editor) {
158
+ process.stderr.write(
159
+ "carboncode commit: no $EDITOR / $VISUAL / $GIT_EDITOR set \u2014 can't open editor. Pick [a]ccept and `git commit --amend` afterwards.\n"
160
+ );
161
+ return null;
162
+ }
163
+ const dir = mkdtempSync(join(tmpdir(), "carboncode-commit-"));
164
+ const path = join(dir, "COMMIT_EDITMSG");
165
+ writeFileSync(path, initial, "utf8");
166
+ const result = spawnSync(`${editor} "${path}"`, {
167
+ stdio: "inherit",
168
+ shell: true
169
+ });
170
+ if (result.status !== 0) {
171
+ try {
172
+ unlinkSync(path);
173
+ } catch {
174
+ }
175
+ process.stderr.write(
176
+ `carboncode commit: editor exited ${result.status} \u2014 keeping prior draft.
177
+ `
178
+ );
179
+ return null;
180
+ }
181
+ let edited;
182
+ try {
183
+ edited = readFileSync(path, "utf8");
184
+ } catch {
185
+ return null;
186
+ } finally {
187
+ try {
188
+ unlinkSync(path);
189
+ } catch {
190
+ }
191
+ }
192
+ const cleaned = edited.split(/\r?\n/).filter((line) => !/^\s*#/.test(line)).join("\n").trim();
193
+ return cleaned || null;
194
+ }
195
+ function commitWithMessage(message) {
196
+ const child = spawn("git", ["commit", "-F", "-"], {
197
+ stdio: ["pipe", "inherit", "inherit"]
198
+ });
199
+ child.stdin.write(message);
200
+ child.stdin.end();
201
+ child.on("close", (code) => {
202
+ if (code !== 0) {
203
+ process.stderr.write(`carboncode commit: git commit exited ${code}.
204
+ `);
205
+ process.exit(code ?? 1);
206
+ }
207
+ });
208
+ }
209
+ async function commitCommand(opts = {}) {
210
+ loadDotenv();
211
+ dieIfNotGitRepo();
212
+ const apiKey = loadApiKey() ?? process.env.DEEPSEEK_API_KEY;
213
+ if (!apiKey) {
214
+ process.stderr.write(
215
+ "carboncode commit: DEEPSEEK_API_KEY not set. Run `carboncode setup` to save one, or export it.\n"
216
+ );
217
+ process.exit(1);
218
+ }
219
+ const diff = readDiff();
220
+ if (!diff) {
221
+ process.stderr.write(
222
+ "carboncode commit: no staged changes and working tree is clean \u2014 nothing to commit.\n"
223
+ );
224
+ process.exit(1);
225
+ }
226
+ if (diff.source === "working-tree") {
227
+ process.stderr.write(
228
+ "carboncode commit: nothing staged \u2014 drafting from working-tree diff. Stage your changes and re-run, or use the draft as a starting point.\n"
229
+ );
230
+ }
231
+ if (diff.truncated) {
232
+ process.stderr.write(
233
+ "carboncode commit: diff exceeded 80KB; head + tail sent to the model. Large diffs often produce vague drafts \u2014 consider committing in smaller chunks.\n"
234
+ );
235
+ }
236
+ const client = new DeepSeekClient({ apiKey, baseUrl: loadBaseUrl() });
237
+ const model = opts.model ?? DEFAULT_MODEL;
238
+ const recentCommits = readRecentCommits();
239
+ let message = "";
240
+ let firstPass = true;
241
+ while (true) {
242
+ if (firstPass) {
243
+ process.stdout.write("Drafting commit message\u2026\n");
244
+ } else {
245
+ process.stdout.write("Regenerating\u2026\n");
246
+ }
247
+ firstPass = false;
248
+ try {
249
+ message = await draftMessage(client, model, diff, recentCommits);
250
+ } catch (err) {
251
+ process.stderr.write(`carboncode commit: model call failed \u2014 ${err.message}
252
+ `);
253
+ process.exit(1);
254
+ }
255
+ if (!message) {
256
+ process.stderr.write("carboncode commit: model returned an empty draft. Try again.\n");
257
+ process.exit(1);
258
+ }
259
+ printDraft(message);
260
+ if (opts.yes) break;
261
+ if (diff.source === "working-tree") {
262
+ process.stdout.write(
263
+ "(no staged changes \u2014 draft printed above for you to copy. Stage with `git add` and re-run to commit.)\n"
264
+ );
265
+ return;
266
+ }
267
+ const choice = await promptChoice();
268
+ if (choice === "accept") break;
269
+ if (choice === "cancel") {
270
+ process.stderr.write("commit cancelled.\n");
271
+ return;
272
+ }
273
+ if (choice === "edit") {
274
+ const edited = editInExternal(message);
275
+ if (edited) {
276
+ message = edited;
277
+ printDraft(message);
278
+ const next = await promptChoice();
279
+ if (next === "accept") break;
280
+ if (next === "cancel") {
281
+ process.stderr.write("commit cancelled.\n");
282
+ return;
283
+ }
284
+ }
285
+ }
286
+ }
287
+ commitWithMessage(message);
288
+ }
289
+ export {
290
+ commitCommand
291
+ };
292
+ //# sourceMappingURL=commit-DTFA56VQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/commands/commit.ts"],"sourcesContent":["/** Drafts via diff + recent log (style mimicry); commit uses `-F -` so multi-line bodies survive shell quoting. */\n\nimport { spawn, spawnSync } from \"node:child_process\";\nimport { mkdtempSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { stdin, stdout } from \"node:process\";\nimport { createInterface } from \"node:readline/promises\";\nimport { DeepSeekClient } from \"../../client.js\";\nimport { loadApiKey, loadBaseUrl } from \"../../config.js\";\nimport { loadDotenv } from \"../../env.js\";\n\nexport interface CommitOptions {\n /** Override the default model (deepseek-v4-flash). */\n model?: string;\n /** Skip the confirmation step — useful in scripts where the diff has been pre-reviewed. */\n yes?: boolean;\n}\n\nconst DEFAULT_MODEL = \"deepseek-v4-flash\";\nconst DIFF_BYTE_CAP = 80 * 1024;\nconst LOG_COUNT = 10;\n\nconst SYSTEM_PROMPT = `You draft git commit messages.\n\nOutput ONLY the commit message — no preamble, no \\`\\`\\` fences, no \"Here's a commit message:\" lead-in. The first line of your output IS the commit subject.\n\nMatch the project's existing style:\n- Look at the recent commits provided. Mirror their voice, conventional-commit prefix usage (or absence), tense, length, body structure.\n- If recent commits use a \"type(scope): summary\" prefix, use it. If they don't, don't invent one.\n- Subject line: one line, ≤72 chars, imperative mood, no trailing period.\n- Body (optional): explain WHY when the diff isn't self-evident. Wrap at ~72 chars. Skip the body for trivial changes — repeating the subject in the body is noise.\n\nThe diff is the source of truth for what changed; describe THAT, not your guesses about the broader project. If the diff includes a deletion you can't explain from the surrounding context, name it but don't speculate about why.\n\nNo emojis unless the recent commits use them.\nNo co-author trailers, no \"Generated with X\" footers.`;\n\nfunction runGit(\n args: string[],\n opts: { input?: string } = {},\n): { stdout: string; stderr: string; status: number | null } {\n const result = spawnSync(\"git\", args, {\n encoding: \"utf8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n input: opts.input,\n maxBuffer: 32 * 1024 * 1024,\n });\n return {\n stdout: result.stdout ?? \"\",\n stderr: result.stderr ?? \"\",\n status: result.status,\n };\n}\n\nfunction dieIfNotGitRepo(): void {\n const r = runGit([\"rev-parse\", \"--is-inside-work-tree\"]);\n if (r.status !== 0) {\n process.stderr.write(\"carboncode commit: not inside a git repository.\\n\");\n process.exit(1);\n }\n}\n\ninterface DiffResult {\n diff: string;\n source: \"staged\" | \"working-tree\";\n truncated: boolean;\n}\n\nfunction readDiff(): DiffResult | null {\n const staged = runGit([\"diff\", \"--staged\", \"--no-color\"]);\n if (staged.status !== 0) {\n process.stderr.write(`carboncode commit: git diff --staged failed: ${staged.stderr.trim()}\\n`);\n process.exit(1);\n }\n if (staged.stdout.trim().length > 0) {\n return capDiff(staged.stdout, \"staged\");\n }\n const wt = runGit([\"diff\", \"--no-color\"]);\n if (wt.stdout.trim().length === 0) {\n return null;\n }\n return capDiff(wt.stdout, \"working-tree\");\n}\n\nfunction capDiff(raw: string, source: \"staged\" | \"working-tree\"): DiffResult {\n if (raw.length <= DIFF_BYTE_CAP) {\n return { diff: raw, source, truncated: false };\n }\n const head = raw.slice(0, Math.floor(DIFF_BYTE_CAP * 0.7));\n const tail = raw.slice(-Math.floor(DIFF_BYTE_CAP * 0.3));\n return {\n diff: `${head}\\n\\n[… ${raw.length - DIFF_BYTE_CAP} bytes of diff truncated …]\\n\\n${tail}`,\n source,\n truncated: true,\n };\n}\n\nfunction readRecentCommits(): string {\n const r = runGit([\"log\", `-${LOG_COUNT}`, \"--no-merges\", \"--format=%s%n%b%n---END---\"]);\n if (r.status !== 0) {\n // Repo may not have any commits yet (initial commit case). Don't\n // fail — let the model work from the diff alone.\n return \"\";\n }\n return r.stdout.trim();\n}\n\nasync function draftMessage(\n client: DeepSeekClient,\n model: string,\n diff: DiffResult,\n recentCommits: string,\n): Promise<string> {\n const userParts: string[] = [];\n if (recentCommits) {\n userParts.push(`Recent commits (style reference):\\n\\n${recentCommits}`);\n }\n if (diff.source === \"working-tree\") {\n userParts.push(\n \"(NOTE: diff is from the working tree, not the staging area — nothing is staged yet. The user will stage selectively after seeing the draft.)\",\n );\n }\n userParts.push(`Diff to summarize:\\n\\n${diff.diff}`);\n\n const resp = await client.chat({\n model,\n messages: [\n { role: \"system\", content: SYSTEM_PROMPT },\n { role: \"user\", content: userParts.join(\"\\n\\n\") },\n ],\n temperature: 0.2,\n });\n return stripCodeFences(resp.content.trim());\n}\n\nfunction stripCodeFences(s: string): string {\n // Some models still wrap output in ``` despite the system prompt\n // telling them not to. Strip a single leading + trailing fence pair\n // if present. Only operates on a wrapping pair — internal fences\n // (a code block inside the body) stay.\n const trimmed = s.trim();\n const fenceOpen = /^```[a-zA-Z]*\\n/;\n const fenceClose = /\\n?```$/;\n if (fenceOpen.test(trimmed) && fenceClose.test(trimmed)) {\n return trimmed.replace(fenceOpen, \"\").replace(fenceClose, \"\").trim();\n }\n return trimmed;\n}\n\nfunction printDraft(message: string): void {\n const sep = \"─\".repeat(60);\n process.stdout.write(`\\n${sep}\\n${message}\\n${sep}\\n\\n`);\n}\n\nasync function promptChoice(): Promise<\"accept\" | \"regen\" | \"edit\" | \"cancel\"> {\n const rl = createInterface({ input: stdin, output: stdout });\n try {\n const answer = await rl.question(\"[a]ccept / [r]egenerate / [e]dit / [c]ancel: \");\n const k = answer.trim().toLowerCase();\n if (k === \"\" || k === \"a\" || k === \"y\" || k === \"yes\") return \"accept\";\n if (k === \"r\" || k === \"regen\" || k === \"regenerate\") return \"regen\";\n if (k === \"e\" || k === \"edit\") return \"edit\";\n return \"cancel\";\n } finally {\n rl.close();\n }\n}\n\nfunction editInExternal(initial: string): string | null {\n const editor = process.env.GIT_EDITOR ?? process.env.VISUAL ?? process.env.EDITOR;\n if (!editor) {\n process.stderr.write(\n \"carboncode commit: no $EDITOR / $VISUAL / $GIT_EDITOR set — can't open editor. Pick [a]ccept and `git commit --amend` afterwards.\\n\",\n );\n return null;\n }\n const dir = mkdtempSync(join(tmpdir(), \"carboncode-commit-\"));\n const path = join(dir, \"COMMIT_EDITMSG\");\n writeFileSync(path, initial, \"utf8\");\n // spawnSync with shell:true is required so $EDITOR strings like\n // `code --wait` work — they're shell command lines, not argv tuples.\n // The trust boundary is the user's own env var; matches how git\n // itself launches editors.\n const result = spawnSync(`${editor} \"${path}\"`, {\n stdio: \"inherit\",\n shell: true,\n });\n if (result.status !== 0) {\n try {\n unlinkSync(path);\n } catch {\n /* ignore */\n }\n process.stderr.write(\n `carboncode commit: editor exited ${result.status} — keeping prior draft.\\n`,\n );\n return null;\n }\n let edited: string;\n try {\n edited = readFileSync(path, \"utf8\");\n } catch {\n return null;\n } finally {\n try {\n unlinkSync(path);\n } catch {\n /* ignore */\n }\n }\n // Strip git's standard `# …` comment lines, even though we didn't\n // emit any — a user habituated to `git commit` may add `#`-prefixed\n // notes by reflex.\n const cleaned = edited\n .split(/\\r?\\n/)\n .filter((line) => !/^\\s*#/.test(line))\n .join(\"\\n\")\n .trim();\n return cleaned || null;\n}\n\nfunction commitWithMessage(message: string): void {\n // -F - reads the message from stdin, sidestepping shell quoting and\n // letting multi-line bodies through cleanly. Inherit stdio so the\n // user sees git's own confirmation / pre-commit hook output.\n const child = spawn(\"git\", [\"commit\", \"-F\", \"-\"], {\n stdio: [\"pipe\", \"inherit\", \"inherit\"],\n });\n child.stdin.write(message);\n child.stdin.end();\n child.on(\"close\", (code) => {\n if (code !== 0) {\n process.stderr.write(`carboncode commit: git commit exited ${code}.\\n`);\n process.exit(code ?? 1);\n }\n });\n}\n\nexport async function commitCommand(opts: CommitOptions = {}): Promise<void> {\n loadDotenv();\n dieIfNotGitRepo();\n\n const apiKey = loadApiKey() ?? process.env.DEEPSEEK_API_KEY;\n if (!apiKey) {\n process.stderr.write(\n \"carboncode commit: DEEPSEEK_API_KEY not set. Run `carboncode setup` to save one, or export it.\\n\",\n );\n process.exit(1);\n }\n\n const diff = readDiff();\n if (!diff) {\n process.stderr.write(\n \"carboncode commit: no staged changes and working tree is clean — nothing to commit.\\n\",\n );\n process.exit(1);\n }\n if (diff.source === \"working-tree\") {\n process.stderr.write(\n \"carboncode commit: nothing staged — drafting from working-tree diff. Stage your changes and re-run, or use the draft as a starting point.\\n\",\n );\n }\n if (diff.truncated) {\n process.stderr.write(\n \"carboncode commit: diff exceeded 80KB; head + tail sent to the model. Large diffs often produce vague drafts — consider committing in smaller chunks.\\n\",\n );\n }\n\n const client = new DeepSeekClient({ apiKey, baseUrl: loadBaseUrl() });\n const model = opts.model ?? DEFAULT_MODEL;\n const recentCommits = readRecentCommits();\n\n let message = \"\";\n let firstPass = true;\n while (true) {\n if (firstPass) {\n process.stdout.write(\"Drafting commit message…\\n\");\n } else {\n process.stdout.write(\"Regenerating…\\n\");\n }\n firstPass = false;\n try {\n message = await draftMessage(client, model, diff, recentCommits);\n } catch (err) {\n process.stderr.write(`carboncode commit: model call failed — ${(err as Error).message}\\n`);\n process.exit(1);\n }\n if (!message) {\n process.stderr.write(\"carboncode commit: model returned an empty draft. Try again.\\n\");\n process.exit(1);\n }\n printDraft(message);\n\n if (opts.yes) break;\n if (diff.source === \"working-tree\") {\n // Refuse to commit a working-tree-derived draft — the staging\n // area is empty so `git commit` would fail anyway. Print the\n // draft so the user can copy it; exit 0 because we did our job.\n process.stdout.write(\n \"(no staged changes — draft printed above for you to copy. Stage with `git add` and re-run to commit.)\\n\",\n );\n return;\n }\n\n const choice = await promptChoice();\n if (choice === \"accept\") break;\n if (choice === \"cancel\") {\n process.stderr.write(\"commit cancelled.\\n\");\n return;\n }\n if (choice === \"edit\") {\n const edited = editInExternal(message);\n if (edited) {\n message = edited;\n printDraft(message);\n // Re-prompt: the user may want to edit again, accept, etc.\n const next = await promptChoice();\n if (next === \"accept\") break;\n if (next === \"cancel\") {\n process.stderr.write(\"commit cancelled.\\n\");\n return;\n }\n // next is \"regen\" or another \"edit\" — fall through to the\n // loop top to re-draft (regen) or land back at this branch.\n }\n // editor returned no edit — loop top will regen by default.\n }\n // Anything else (regen, or unsuccessful edit) → loop top redraws.\n }\n\n commitWithMessage(message);\n}\n"],"mappings":"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","names":[]}