@phuc1403/musketeer 0.8.0 → 0.10.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 (236) hide show
  1. package/INSTALLATION.md +52 -52
  2. package/README.md +49 -49
  3. package/bin/musketeer.js +168 -168
  4. package/manifest.json +333 -301
  5. package/package.json +48 -48
  6. package/src/dotnet-scaffold-copier.js +79 -79
  7. package/src/provisioner/detect.js +93 -93
  8. package/src/self-update.js +77 -77
  9. package/template/.claude/agents/code-reviewer.md +182 -166
  10. package/template/.claude/agents/git-manager.md +18 -18
  11. package/template/.claude/agents/hallmark-auditor.md +78 -78
  12. package/template/.claude/agents/researcher.md +33 -33
  13. package/template/.claude/hooks/block-unsafe-adr-title.cjs +85 -85
  14. package/template/.claude/hooks/git-skill-reminder.cjs +53 -0
  15. package/template/.claude/hooks/init-adr-dir.cjs +173 -173
  16. package/template/.claude/hooks/inject-adr-flags.cjs +94 -94
  17. package/template/.claude/hooks/lib/adr/command-scan.cjs +115 -115
  18. package/template/.claude/hooks/lib/characteristics/checker.cjs +357 -357
  19. package/template/.claude/hooks/lib/colors.cjs +180 -122
  20. package/template/.claude/hooks/lib/git-info-cache.cjs +191 -191
  21. package/template/.claude/hooks/lib/transcript-parser.cjs +300 -277
  22. package/template/.claude/hooks/sync-adr-toc.cjs +146 -146
  23. package/template/.claude/hooks/{usage-context-awareness.cjs → usage-quota-cache-refresh.cjs} +166 -166
  24. package/template/.claude/hooks/validate-characteristics-hook.cjs +66 -66
  25. package/template/.claude/hooks/validate-cml-hook.js +145 -145
  26. package/template/.claude/skills/adr-writer/SKILL.md +48 -48
  27. package/template/.claude/skills/adr-writer/references/adr-example.md +35 -35
  28. package/template/.claude/skills/architecture-characteristic-writer/SKILL.md +215 -215
  29. package/template/.claude/skills/architecture-characteristic-writer/assets/worksheet-template.md +29 -29
  30. package/template/.claude/skills/architecture-characteristic-writer/references/characteristics-catalog.md +40 -40
  31. package/template/.claude/skills/architecture-characteristic-writer/scripts/ranking-table.cjs +171 -171
  32. package/template/.claude/skills/code-review/SKILL.md +201 -54
  33. package/template/.claude/skills/code-review/references/checklist-workflow.md +96 -0
  34. package/template/.claude/skills/code-review/references/checklists/api.md +52 -52
  35. package/template/.claude/skills/code-review/references/checklists/base.md +100 -100
  36. package/template/.claude/skills/code-review/references/checklists/web-app.md +54 -54
  37. package/template/.claude/skills/code-review/references/code-review-reception.md +113 -0
  38. package/template/.claude/skills/code-review/references/codebase-scan-workflow.md +30 -0
  39. package/template/.claude/skills/code-review/references/edge-case-scouting.md +119 -0
  40. package/template/.claude/skills/code-review/references/input-mode-resolution.md +135 -0
  41. package/template/.claude/skills/code-review/references/parallel-review-workflow.md +76 -0
  42. package/template/.claude/skills/code-review/references/requesting-code-review.md +116 -0
  43. package/template/.claude/skills/code-review/references/spec-compliance-review.md +43 -0
  44. package/template/.claude/skills/code-review/references/task-management-reviews.md +140 -0
  45. package/template/.claude/skills/code-review/references/verification-before-completion.md +139 -0
  46. package/template/.claude/skills/context-map/SKILL.md +80 -80
  47. package/template/.claude/skills/context-map/example.cml +106 -106
  48. package/template/.claude/skills/context-map/reference/Bounded Context/Bounded Context.md +40 -40
  49. package/template/.claude/skills/context-map/reference/Bounded Context/businessModel.md +5 -5
  50. package/template/.claude/skills/context-map/reference/Bounded Context/domainVisionStatement.md +2 -2
  51. package/template/.claude/skills/context-map/reference/Bounded Context/evolution.md +5 -5
  52. package/template/.claude/skills/context-map/reference/Bounded Context/implementationTechnology.md +1 -1
  53. package/template/.claude/skills/context-map/reference/Bounded Context/implements.md +1 -1
  54. package/template/.claude/skills/context-map/reference/Bounded Context/knowledgeLevel.md +4 -4
  55. package/template/.claude/skills/context-map/reference/Bounded Context/realizes.md +9 -9
  56. package/template/.claude/skills/context-map/reference/Bounded Context/refines.md +10 -10
  57. package/template/.claude/skills/context-map/reference/Bounded Context/responsibilities.md +26 -26
  58. package/template/.claude/skills/context-map/reference/Bounded Context/type.md +23 -23
  59. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Anticorruption Layer.md +5 -5
  60. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Bounded Context Relationship.md +12 -12
  61. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Conformist.md +5 -5
  62. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Customer-Supplier (C-S).md +22 -22
  63. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Open Host Service.md +4 -4
  64. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Partnership (P).md +13 -13
  65. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Published Language.md +4 -4
  66. package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Shared Kernel (SK).md +12 -12
  67. package/template/.claude/skills/context-map/reference/Context Map.md +62 -62
  68. package/template/.claude/skills/context-map/reference/Domain/Domain.md +30 -30
  69. package/template/.claude/skills/context-map/reference/Domain/supports.md +33 -33
  70. package/template/.claude/skills/context-map/reference/Domain/type.md +3 -3
  71. package/template/.claude/skills/context-map/reference/Semantic Rules.md +32 -32
  72. package/template/.claude/skills/git/SKILL.md +131 -115
  73. package/template/.claude/skills/git/references/branch-management.md +88 -88
  74. package/template/.claude/skills/git/references/commit-standards.md +46 -46
  75. package/template/.claude/skills/git/references/context-efficiency.md +54 -0
  76. package/template/.claude/skills/git/references/gh-cli-guide.md +109 -109
  77. package/template/.claude/skills/git/references/safety-protocols.md +69 -69
  78. package/template/.claude/skills/git/references/workflow-commit.md +58 -58
  79. package/template/.claude/skills/git/references/workflow-merge-pr.md +136 -0
  80. package/template/.claude/skills/git/references/workflow-merge.md +48 -48
  81. package/template/.claude/skills/git/references/workflow-pr.md +58 -58
  82. package/template/.claude/skills/git/references/workflow-push.md +52 -52
  83. package/template/.claude/skills/hallmark/SKILL.md +552 -552
  84. package/template/.claude/skills/hallmark/references/anti-patterns.md +412 -412
  85. package/template/.claude/skills/hallmark/references/assets.md +406 -406
  86. package/template/.claude/skills/hallmark/references/color.md +95 -95
  87. package/template/.claude/skills/hallmark/references/component-cookbook.md +256 -256
  88. package/template/.claude/skills/hallmark/references/components/c1-outlined-chip.md +12 -12
  89. package/template/.claude/skills/hallmark/references/components/c2-inline-form-as-cta.md +16 -16
  90. package/template/.claude/skills/hallmark/references/components/c3-typographic-link.md +8 -8
  91. package/template/.claude/skills/hallmark/references/components/c4-sticky-bottom-bar.md +16 -16
  92. package/template/.claude/skills/hallmark/references/components/f1-bento-grid.md +20 -20
  93. package/template/.claude/skills/hallmark/references/components/f2-sticky-scroll-stack.md +20 -20
  94. package/template/.claude/skills/hallmark/references/components/f3-tabular-spec-sheet.md +11 -11
  95. package/template/.claude/skills/hallmark/references/components/f4-step-sequence.md +11 -11
  96. package/template/.claude/skills/hallmark/references/components/f5-annotated-screenshot.md +11 -11
  97. package/template/.claude/skills/hallmark/references/components/f6-product-card-grid.md +41 -41
  98. package/template/.claude/skills/hallmark/references/components/ft1-mast-headed.md +13 -13
  99. package/template/.claude/skills/hallmark/references/components/ft2-inline-rule-single-line.md +10 -10
  100. package/template/.claude/skills/hallmark/references/components/ft3-index-style-category-list.md +12 -12
  101. package/template/.claude/skills/hallmark/references/components/ft4-dense-typographic.md +10 -10
  102. package/template/.claude/skills/hallmark/references/components/ft5-statement.md +21 -21
  103. package/template/.claude/skills/hallmark/references/components/ft6-letter-close.md +19 -19
  104. package/template/.claude/skills/hallmark/references/components/ft7-newsletter-first.md +27 -27
  105. package/template/.claude/skills/hallmark/references/components/ft8-marquee-scroll.md +25 -25
  106. package/template/.claude/skills/hallmark/references/components/h1-marquee.md +15 -15
  107. package/template/.claude/skills/hallmark/references/components/h2-split-diptych.md +15 -15
  108. package/template/.claude/skills/hallmark/references/components/h3-quote-led.md +11 -11
  109. package/template/.claude/skills/hallmark/references/components/h4-stat-led.md +14 -14
  110. package/template/.claude/skills/hallmark/references/components/h5-letter-hero.md +11 -11
  111. package/template/.claude/skills/hallmark/references/components/h6-photographic-fold.md +16 -16
  112. package/template/.claude/skills/hallmark/references/components/h7-demo-video-clipped-by-viewport-edge.md +27 -27
  113. package/template/.claude/skills/hallmark/references/components/h8-mockup-split-browser-framed.md +23 -23
  114. package/template/.claude/skills/hallmark/references/components/h9-custom-illustration-centerpiece.md +27 -27
  115. package/template/.claude/skills/hallmark/references/components/n1-wordmark-2-links.md +12 -12
  116. package/template/.claude/skills/hallmark/references/components/n10-floating-on-scroll-morph.md +19 -19
  117. package/template/.claude/skills/hallmark/references/components/n2-floating-chip.md +14 -14
  118. package/template/.claude/skills/hallmark/references/components/n3-side-rail.md +14 -14
  119. package/template/.claude/skills/hallmark/references/components/n4-hidden-behind-k.md +9 -9
  120. package/template/.claude/skills/hallmark/references/components/n5-floating-pill.md +28 -28
  121. package/template/.claude/skills/hallmark/references/components/n6-newspaper-masthead.md +24 -24
  122. package/template/.claude/skills/hallmark/references/components/n7-brutal-slab.md +22 -22
  123. package/template/.claude/skills/hallmark/references/components/n8-terminal-command.md +21 -21
  124. package/template/.claude/skills/hallmark/references/components/n9-edge-aligned-minimal.md +17 -17
  125. package/template/.claude/skills/hallmark/references/components/s1-left-margin-numbered.md +15 -15
  126. package/template/.claude/skills/hallmark/references/components/s2-hanging.md +13 -13
  127. package/template/.claude/skills/hallmark/references/components/s3-sticky-pinned.md +19 -19
  128. package/template/.claude/skills/hallmark/references/components/s4-inline-no-break.md +11 -11
  129. package/template/.claude/skills/hallmark/references/components/s5-bottom-anchored.md +13 -13
  130. package/template/.claude/skills/hallmark/references/components/t1-pull-quote-with-marginalia.md +12 -12
  131. package/template/.claude/skills/hallmark/references/components/t2-logo-wall-hairline.md +19 -19
  132. package/template/.claude/skills/hallmark/references/components/t3-single-huge-quote.md +11 -11
  133. package/template/.claude/skills/hallmark/references/components/t4-numbered-stat-strip.md +14 -14
  134. package/template/.claude/skills/hallmark/references/contract.md +24 -24
  135. package/template/.claude/skills/hallmark/references/copy.md +182 -182
  136. package/template/.claude/skills/hallmark/references/custom-craft.md +626 -626
  137. package/template/.claude/skills/hallmark/references/custom-theme.md +329 -329
  138. package/template/.claude/skills/hallmark/references/design-md.md +116 -116
  139. package/template/.claude/skills/hallmark/references/export-formats.md +328 -328
  140. package/template/.claude/skills/hallmark/references/floating-nav.md +89 -89
  141. package/template/.claude/skills/hallmark/references/genres/atmospheric.md +65 -65
  142. package/template/.claude/skills/hallmark/references/genres/editorial.md +70 -70
  143. package/template/.claude/skills/hallmark/references/genres/modern-minimal.md +67 -67
  144. package/template/.claude/skills/hallmark/references/genres/playful.md +65 -65
  145. package/template/.claude/skills/hallmark/references/hero-enrichment.md +474 -474
  146. package/template/.claude/skills/hallmark/references/imagery-kit.md +170 -170
  147. package/template/.claude/skills/hallmark/references/interaction-and-states.md +207 -207
  148. package/template/.claude/skills/hallmark/references/layout-and-space.md +111 -111
  149. package/template/.claude/skills/hallmark/references/macrostructures/01-bento-grid.md +35 -35
  150. package/template/.claude/skills/hallmark/references/macrostructures/02-long-document.md +34 -34
  151. package/template/.claude/skills/hallmark/references/macrostructures/03-marquee-hero.md +31 -31
  152. package/template/.claude/skills/hallmark/references/macrostructures/04-stat-led.md +32 -32
  153. package/template/.claude/skills/hallmark/references/macrostructures/05-workbench.md +32 -32
  154. package/template/.claude/skills/hallmark/references/macrostructures/06-conversational-faq.md +33 -33
  155. package/template/.claude/skills/hallmark/references/macrostructures/07-manifesto.md +32 -32
  156. package/template/.claude/skills/hallmark/references/macrostructures/08-photographic.md +34 -34
  157. package/template/.claude/skills/hallmark/references/macrostructures/09-quote-led.md +32 -32
  158. package/template/.claude/skills/hallmark/references/macrostructures/10-specimen.md +32 -32
  159. package/template/.claude/skills/hallmark/references/macrostructures/11-catalogue.md +23 -23
  160. package/template/.claude/skills/hallmark/references/macrostructures/12-letter.md +23 -23
  161. package/template/.claude/skills/hallmark/references/macrostructures/13-index-first.md +23 -23
  162. package/template/.claude/skills/hallmark/references/macrostructures/14-narrative-workflow.md +23 -23
  163. package/template/.claude/skills/hallmark/references/macrostructures/15-split-studio.md +23 -23
  164. package/template/.claude/skills/hallmark/references/macrostructures/16-feature-stack.md +23 -23
  165. package/template/.claude/skills/hallmark/references/macrostructures/17-type-specimen.md +23 -23
  166. package/template/.claude/skills/hallmark/references/macrostructures/18-portfolio-grid.md +23 -23
  167. package/template/.claude/skills/hallmark/references/macrostructures/19-map-diagram.md +23 -23
  168. package/template/.claude/skills/hallmark/references/macrostructures/20-ecosystem-index.md +23 -23
  169. package/template/.claude/skills/hallmark/references/macrostructures/21-component-playground.md +23 -23
  170. package/template/.claude/skills/hallmark/references/macrostructures.md +89 -89
  171. package/template/.claude/skills/hallmark/references/microinteractions.md +260 -260
  172. package/template/.claude/skills/hallmark/references/motion.md +109 -109
  173. package/template/.claude/skills/hallmark/references/preview-examples.md +49 -49
  174. package/template/.claude/skills/hallmark/references/responsive.md +138 -138
  175. package/template/.claude/skills/hallmark/references/slop-test.md +205 -205
  176. package/template/.claude/skills/hallmark/references/structure.md +164 -164
  177. package/template/.claude/skills/hallmark/references/study.md +511 -511
  178. package/template/.claude/skills/hallmark/references/typography.md +243 -243
  179. package/template/.claude/skills/hallmark/references/verbs/audit.md +25 -25
  180. package/template/.claude/skills/hallmark/references/verbs/redesign.md +269 -269
  181. package/template/.claude/skills/hallmark-loop/SKILL.md +105 -105
  182. package/template/.claude/skills/hallmark-loop/references/auditor-call.md +60 -60
  183. package/template/.claude/skills/hallmark-loop/references/capture.md +78 -78
  184. package/template/.claude/skills/hallmark-loop/references/loop-control.md +79 -79
  185. package/template/.claude/skills/handoff/SKILL.md +15 -15
  186. package/template/.claude/skills/knowledge-crunching/SKILL.md +94 -94
  187. package/template/.claude/skills/research/SKILL.md +69 -69
  188. package/template/.claude/skills/skill-creator/LICENSE.txt +201 -201
  189. package/template/.claude/skills/skill-creator/SKILL.md +154 -149
  190. package/template/.claude/skills/skill-creator/agents/analyzer.md +274 -274
  191. package/template/.claude/skills/skill-creator/agents/comparator.md +202 -202
  192. package/template/.claude/skills/skill-creator/agents/grader.md +223 -223
  193. package/template/.claude/skills/skill-creator/assets/eval_review.html +146 -146
  194. package/template/.claude/skills/skill-creator/eval-viewer/generate_review.py +471 -471
  195. package/template/.claude/skills/skill-creator/eval-viewer/viewer.html +1325 -1325
  196. package/template/.claude/skills/skill-creator/references/benchmark-optimization-guide.md +86 -86
  197. package/template/.claude/skills/skill-creator/references/distribution-guide.md +79 -79
  198. package/template/.claude/skills/skill-creator/references/eval-infrastructure-guide.md +129 -129
  199. package/template/.claude/skills/skill-creator/references/eval-schemas.md +121 -121
  200. package/template/.claude/skills/skill-creator/references/mcp-skills-integration.md +71 -71
  201. package/template/.claude/skills/skill-creator/references/metadata-quality-criteria.md +94 -94
  202. package/template/.claude/skills/skill-creator/references/plugin-marketplace-hosting.md +104 -104
  203. package/template/.claude/skills/skill-creator/references/plugin-marketplace-overview.md +89 -89
  204. package/template/.claude/skills/skill-creator/references/plugin-marketplace-schema.md +93 -93
  205. package/template/.claude/skills/skill-creator/references/plugin-marketplace-sources.md +103 -103
  206. package/template/.claude/skills/skill-creator/references/plugin-marketplace-troubleshooting.md +76 -76
  207. package/template/.claude/skills/skill-creator/references/script-quality-criteria.md +106 -106
  208. package/template/.claude/skills/skill-creator/references/skill-anatomy-and-requirements.md +77 -77
  209. package/template/.claude/skills/skill-creator/references/skill-creation-workflow.md +152 -151
  210. package/template/.claude/skills/skill-creator/references/skill-design-patterns.md +75 -75
  211. package/template/.claude/skills/skill-creator/references/skillmark-benchmark-criteria.md +102 -102
  212. package/template/.claude/skills/skill-creator/references/structure-organization-criteria.md +114 -114
  213. package/template/.claude/skills/skill-creator/references/testing-and-iteration.md +78 -78
  214. package/template/.claude/skills/skill-creator/references/token-efficiency-criteria.md +74 -74
  215. package/template/.claude/skills/skill-creator/references/troubleshooting-guide.md +81 -81
  216. package/template/.claude/skills/skill-creator/references/validation-checklist.md +83 -83
  217. package/template/.claude/skills/skill-creator/references/writing-effective-instructions.md +88 -88
  218. package/template/.claude/skills/skill-creator/references/yaml-frontmatter-reference.md +92 -92
  219. package/template/.claude/skills/skill-creator/scripts/aggregate_benchmark.py +401 -401
  220. package/template/.claude/skills/skill-creator/scripts/encoding_utils.py +36 -36
  221. package/template/.claude/skills/skill-creator/scripts/generate_report.py +326 -326
  222. package/template/.claude/skills/skill-creator/scripts/improve_description.py +248 -248
  223. package/template/.claude/skills/skill-creator/scripts/init_skill.py +360 -360
  224. package/template/.claude/skills/skill-creator/scripts/package_skill.py +143 -143
  225. package/template/.claude/skills/skill-creator/scripts/quick_validate.py +110 -110
  226. package/template/.claude/skills/skill-creator/scripts/run_eval.py +310 -310
  227. package/template/.claude/skills/skill-creator/scripts/run_loop.py +332 -332
  228. package/template/.claude/skills/skill-creator/scripts/utils.py +47 -47
  229. package/template/.claude/skills/tdd/SKILL.md +142 -142
  230. package/template/.claude/skills/tdd/deep-modules.md +15 -15
  231. package/template/.claude/skills/tdd/interface-design.md +31 -31
  232. package/template/.claude/skills/tdd/mocking.md +59 -59
  233. package/template/.claude/skills/tdd/refactoring.md +10 -10
  234. package/template/.claude/skills/tdd/tests.md +61 -61
  235. package/template/.claude/statusline.cjs +0 -0
  236. package/template/.claude/skills/code-review/references/adversarial-review.md +0 -223
@@ -1,191 +1,191 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * Git Info Cache - Cross-platform git information batching
6
- *
7
- * Problem: 5-6 git process spawns per statusline render are slow on Windows (CreateProcess overhead)
8
- * Solution: Cache git query results for 3 seconds — subsequent renders read cache (zero processes)
9
- *
10
- * Performance: 5 spawns per render → event-driven refresh + 30s TTL fallback
11
- * Cross-platform: No bash-only syntax (no 2>/dev/null), windowsHide on all exec calls
12
- */
13
-
14
- const { execSync } = require('child_process');
15
- const fs = require('fs');
16
- const path = require('path');
17
- const os = require('os');
18
-
19
- // Cache TTL — long fallback for external changes (git checkout outside Claude)
20
- // Active invalidation happens via PostToolUse hooks after Edit/Write/Bash
21
- const CACHE_TTL = 30000;
22
- const CACHE_MISS = Symbol('cache_miss');
23
- const CACHE_SKIP = Symbol('cache_skip');
24
-
25
- function isTimeoutError(error) {
26
- if (!error) return false;
27
- if (error.killed) return true;
28
- if (error.signal === 'SIGTERM') return true;
29
- return /timed out|etimedout/i.test(String(error.message || ''));
30
- }
31
-
32
- function getExecTimeoutMs() {
33
- const parsed = Number.parseInt(process.env.CK_GIT_TIMEOUT_MS || '', 10);
34
- if (Number.isFinite(parsed) && parsed > 0) return parsed;
35
- return 3000;
36
- }
37
-
38
- /**
39
- * Safe command execution wrapper with optional cwd
40
- * Timeout prevents hangs on slow/network-mounted repos
41
- */
42
- function execIn(cmd, cwd) {
43
- try {
44
- return {
45
- output: execSync(cmd, {
46
- encoding: 'utf8',
47
- stdio: ['pipe', 'pipe', 'ignore'],
48
- windowsHide: true,
49
- cwd: cwd || undefined,
50
- timeout: getExecTimeoutMs()
51
- }).trim(),
52
- timedOut: false
53
- };
54
- } catch (error) {
55
- return {
56
- output: '',
57
- timedOut: isTimeoutError(error)
58
- };
59
- }
60
- }
61
-
62
- /**
63
- * Get cache file path for current working directory
64
- */
65
- function getCachePath(cwd) {
66
- const hash = require('crypto')
67
- .createHash('md5')
68
- .update(cwd)
69
- .digest('hex')
70
- .slice(0, 8);
71
- return path.join(os.tmpdir(), `ck-git-cache-${hash}.json`);
72
- }
73
-
74
- /**
75
- * Read cache if valid (not expired). Returns CACHE_MISS on miss.
76
- * No existsSync check (TOCTOU race) — just try read and catch.
77
- */
78
- function readCache(cachePath, options = {}) {
79
- const { allowStale = false } = options;
80
- try {
81
- const cache = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
82
- if (Date.now() - cache.timestamp < CACHE_TTL || allowStale) {
83
- return cache.data; // Can be null (non-git dir) or object (git info)
84
- }
85
- } catch {
86
- // File missing, corrupted, or expired — all treated as cache miss
87
- }
88
- return CACHE_MISS;
89
- }
90
-
91
- /**
92
- * Write cache atomically (temp file + rename to avoid partial reads on Windows)
93
- */
94
- function writeCache(cachePath, data) {
95
- const tmpPath = cachePath + '.tmp';
96
- try {
97
- fs.writeFileSync(tmpPath, JSON.stringify({ timestamp: Date.now(), data }));
98
- fs.renameSync(tmpPath, cachePath);
99
- } catch {
100
- try { fs.unlinkSync(tmpPath); } catch {}
101
- }
102
- }
103
-
104
- /**
105
- * Count non-empty lines in a newline-delimited string
106
- */
107
- function countLines(str) {
108
- if (!str) return 0;
109
- return str.split('\n').filter(l => l.trim()).length;
110
- }
111
-
112
- /**
113
- * Fetch git info directly in-process
114
- * The cache is what eliminates redundant spawns — not subprocess wrapping
115
- * @param {string} cwd - Directory to run git commands in
116
- * Returns: { branch, unstaged, staged, ahead, behind } or null if not git repo
117
- */
118
- function fetchGitInfo(cwd) {
119
- // Check if git repo (fast check) — run in target cwd, not process.cwd()
120
- const repoCheck = execIn('git rev-parse --git-dir', cwd);
121
- if (repoCheck.timedOut) return CACHE_SKIP;
122
- if (!repoCheck.output) {
123
- return null;
124
- }
125
-
126
- const branchPrimary = execIn('git branch --show-current', cwd);
127
- const branchFallback = execIn('git rev-parse --short HEAD', cwd);
128
- const unstagedResult = execIn('git diff --name-only', cwd);
129
- const stagedResult = execIn('git diff --cached --name-only', cwd);
130
- const aheadBehindResult = execIn('git rev-list --left-right --count @{u}...HEAD', cwd);
131
-
132
- if (
133
- branchPrimary.timedOut ||
134
- branchFallback.timedOut ||
135
- unstagedResult.timedOut ||
136
- stagedResult.timedOut ||
137
- aheadBehindResult.timedOut
138
- ) {
139
- return CACHE_SKIP;
140
- }
141
-
142
- const branch = branchPrimary.output || branchFallback.output;
143
- const unstaged = countLines(unstagedResult.output);
144
- const staged = countLines(stagedResult.output);
145
-
146
- // Ahead/behind — no 2>/dev/null (invalid on Windows cmd.exe)
147
- let ahead = 0;
148
- let behind = 0;
149
- if (aheadBehindResult.output) {
150
- const parts = aheadBehindResult.output.split(/\s+/);
151
- behind = parseInt(parts[0], 10) || 0;
152
- ahead = parseInt(parts[1], 10) || 0;
153
- }
154
-
155
- return { branch, unstaged, staged, ahead, behind };
156
- }
157
-
158
- /**
159
- * Get git info with caching
160
- * Main export function used by statusline
161
- */
162
- function getGitInfo(cwd = process.cwd()) {
163
- const cachePath = getCachePath(cwd);
164
-
165
- // Try cache first (includes cached null for non-git dirs)
166
- const cached = readCache(cachePath);
167
- if (cached !== CACHE_MISS) return cached;
168
-
169
- // Cache miss or expired, fetch fresh data in target cwd
170
- const data = fetchGitInfo(cwd);
171
- if (data === CACHE_SKIP) {
172
- // Timeout/transient failures should not poison cache as non-git.
173
- // Prefer last known value (even stale) if available.
174
- const stale = readCache(cachePath, { allowStale: true });
175
- return stale === CACHE_MISS ? null : stale;
176
- }
177
-
178
- // Cache both positive and null results (avoids re-spawning git in non-git dirs)
179
- writeCache(cachePath, data);
180
-
181
- return data;
182
- }
183
-
184
- /**
185
- * Invalidate cache for a directory (call after file changes to trigger fresh git query)
186
- */
187
- function invalidateCache(cwd = process.cwd()) {
188
- try { fs.unlinkSync(getCachePath(cwd)); } catch {}
189
- }
190
-
191
- module.exports = { getGitInfo, invalidateCache };
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Git Info Cache - Cross-platform git information batching
6
+ *
7
+ * Problem: 5-6 git process spawns per statusline render are slow on Windows (CreateProcess overhead)
8
+ * Solution: Cache git query results for 3 seconds — subsequent renders read cache (zero processes)
9
+ *
10
+ * Performance: 5 spawns per render → event-driven refresh + 30s TTL fallback
11
+ * Cross-platform: No bash-only syntax (no 2>/dev/null), windowsHide on all exec calls
12
+ */
13
+
14
+ const { execSync } = require('child_process');
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+ const os = require('os');
18
+
19
+ // Cache TTL — long fallback for external changes (git checkout outside Claude)
20
+ // Active invalidation happens via PostToolUse hooks after Edit/Write/Bash
21
+ const CACHE_TTL = 30000;
22
+ const CACHE_MISS = Symbol('cache_miss');
23
+ const CACHE_SKIP = Symbol('cache_skip');
24
+
25
+ function isTimeoutError(error) {
26
+ if (!error) return false;
27
+ if (error.killed) return true;
28
+ if (error.signal === 'SIGTERM') return true;
29
+ return /timed out|etimedout/i.test(String(error.message || ''));
30
+ }
31
+
32
+ function getExecTimeoutMs() {
33
+ const parsed = Number.parseInt(process.env.CK_GIT_TIMEOUT_MS || '', 10);
34
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
35
+ return 3000;
36
+ }
37
+
38
+ /**
39
+ * Safe command execution wrapper with optional cwd
40
+ * Timeout prevents hangs on slow/network-mounted repos
41
+ */
42
+ function execIn(cmd, cwd) {
43
+ try {
44
+ return {
45
+ output: execSync(cmd, {
46
+ encoding: 'utf8',
47
+ stdio: ['pipe', 'pipe', 'ignore'],
48
+ windowsHide: true,
49
+ cwd: cwd || undefined,
50
+ timeout: getExecTimeoutMs()
51
+ }).trim(),
52
+ timedOut: false
53
+ };
54
+ } catch (error) {
55
+ return {
56
+ output: '',
57
+ timedOut: isTimeoutError(error)
58
+ };
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Get cache file path for current working directory
64
+ */
65
+ function getCachePath(cwd) {
66
+ const hash = require('crypto')
67
+ .createHash('md5')
68
+ .update(cwd)
69
+ .digest('hex')
70
+ .slice(0, 8);
71
+ return path.join(os.tmpdir(), `ck-git-cache-${hash}.json`);
72
+ }
73
+
74
+ /**
75
+ * Read cache if valid (not expired). Returns CACHE_MISS on miss.
76
+ * No existsSync check (TOCTOU race) — just try read and catch.
77
+ */
78
+ function readCache(cachePath, options = {}) {
79
+ const { allowStale = false } = options;
80
+ try {
81
+ const cache = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
82
+ if (Date.now() - cache.timestamp < CACHE_TTL || allowStale) {
83
+ return cache.data; // Can be null (non-git dir) or object (git info)
84
+ }
85
+ } catch {
86
+ // File missing, corrupted, or expired — all treated as cache miss
87
+ }
88
+ return CACHE_MISS;
89
+ }
90
+
91
+ /**
92
+ * Write cache atomically (temp file + rename to avoid partial reads on Windows)
93
+ */
94
+ function writeCache(cachePath, data) {
95
+ const tmpPath = cachePath + '.tmp';
96
+ try {
97
+ fs.writeFileSync(tmpPath, JSON.stringify({ timestamp: Date.now(), data }));
98
+ fs.renameSync(tmpPath, cachePath);
99
+ } catch {
100
+ try { fs.unlinkSync(tmpPath); } catch {}
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Count non-empty lines in a newline-delimited string
106
+ */
107
+ function countLines(str) {
108
+ if (!str) return 0;
109
+ return str.split('\n').filter(l => l.trim()).length;
110
+ }
111
+
112
+ /**
113
+ * Fetch git info directly in-process
114
+ * The cache is what eliminates redundant spawns — not subprocess wrapping
115
+ * @param {string} cwd - Directory to run git commands in
116
+ * Returns: { branch, unstaged, staged, ahead, behind } or null if not git repo
117
+ */
118
+ function fetchGitInfo(cwd) {
119
+ // Check if git repo (fast check) — run in target cwd, not process.cwd()
120
+ const repoCheck = execIn('git rev-parse --git-dir', cwd);
121
+ if (repoCheck.timedOut) return CACHE_SKIP;
122
+ if (!repoCheck.output) {
123
+ return null;
124
+ }
125
+
126
+ const branchPrimary = execIn('git branch --show-current', cwd);
127
+ const branchFallback = execIn('git rev-parse --short HEAD', cwd);
128
+ const unstagedResult = execIn('git diff --name-only', cwd);
129
+ const stagedResult = execIn('git diff --cached --name-only', cwd);
130
+ const aheadBehindResult = execIn('git rev-list --left-right --count @{u}...HEAD', cwd);
131
+
132
+ if (
133
+ branchPrimary.timedOut ||
134
+ branchFallback.timedOut ||
135
+ unstagedResult.timedOut ||
136
+ stagedResult.timedOut ||
137
+ aheadBehindResult.timedOut
138
+ ) {
139
+ return CACHE_SKIP;
140
+ }
141
+
142
+ const branch = branchPrimary.output || branchFallback.output;
143
+ const unstaged = countLines(unstagedResult.output);
144
+ const staged = countLines(stagedResult.output);
145
+
146
+ // Ahead/behind — no 2>/dev/null (invalid on Windows cmd.exe)
147
+ let ahead = 0;
148
+ let behind = 0;
149
+ if (aheadBehindResult.output) {
150
+ const parts = aheadBehindResult.output.split(/\s+/);
151
+ behind = parseInt(parts[0], 10) || 0;
152
+ ahead = parseInt(parts[1], 10) || 0;
153
+ }
154
+
155
+ return { branch, unstaged, staged, ahead, behind };
156
+ }
157
+
158
+ /**
159
+ * Get git info with caching
160
+ * Main export function used by statusline
161
+ */
162
+ function getGitInfo(cwd = process.cwd()) {
163
+ const cachePath = getCachePath(cwd);
164
+
165
+ // Try cache first (includes cached null for non-git dirs)
166
+ const cached = readCache(cachePath);
167
+ if (cached !== CACHE_MISS) return cached;
168
+
169
+ // Cache miss or expired, fetch fresh data in target cwd
170
+ const data = fetchGitInfo(cwd);
171
+ if (data === CACHE_SKIP) {
172
+ // Timeout/transient failures should not poison cache as non-git.
173
+ // Prefer last known value (even stale) if available.
174
+ const stale = readCache(cachePath, { allowStale: true });
175
+ return stale === CACHE_MISS ? null : stale;
176
+ }
177
+
178
+ // Cache both positive and null results (avoids re-spawning git in non-git dirs)
179
+ writeCache(cachePath, data);
180
+
181
+ return data;
182
+ }
183
+
184
+ /**
185
+ * Invalidate cache for a directory (call after file changes to trigger fresh git query)
186
+ */
187
+ function invalidateCache(cwd = process.cwd()) {
188
+ try { fs.unlinkSync(getCachePath(cwd)); } catch {}
189
+ }
190
+
191
+ module.exports = { getGitInfo, invalidateCache };