baldart 3.6.2

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 (230) hide show
  1. package/CHANGELOG.md +599 -0
  2. package/README.md +566 -0
  3. package/VERSION +1 -0
  4. package/bin/baldart.js +143 -0
  5. package/framework/.claude/agents/REGISTRY.md +169 -0
  6. package/framework/.claude/agents/api-perf-cost-auditor.md +291 -0
  7. package/framework/.claude/agents/code-reviewer.md +350 -0
  8. package/framework/.claude/agents/codebase-architect.md +391 -0
  9. package/framework/.claude/agents/coder.md +291 -0
  10. package/framework/.claude/agents/deep-human-insight.md +198 -0
  11. package/framework/.claude/agents/doc-reviewer.md +440 -0
  12. package/framework/.claude/agents/email-deliverability-architect.md +193 -0
  13. package/framework/.claude/agents/hybrid-ml-architect.md +285 -0
  14. package/framework/.claude/agents/hyper-gamification-designer.md +149 -0
  15. package/framework/.claude/agents/legal-counsel-gdpr.md +179 -0
  16. package/framework/.claude/agents/marketing-conversion-strategist.md +162 -0
  17. package/framework/.claude/agents/motion-expert.md +108 -0
  18. package/framework/.claude/agents/onboarding-architect-lead.md +230 -0
  19. package/framework/.claude/agents/plan-auditor.md +546 -0
  20. package/framework/.claude/agents/prd-card-writer.md +372 -0
  21. package/framework/.claude/agents/prd.md +744 -0
  22. package/framework/.claude/agents/qa-sentinel.md +305 -0
  23. package/framework/.claude/agents/remotion-animator-orchestrator.md +218 -0
  24. package/framework/.claude/agents/security-reviewer.md +276 -0
  25. package/framework/.claude/agents/senior-researcher.md +175 -0
  26. package/framework/.claude/agents/seo-analytics-strategist.md +156 -0
  27. package/framework/.claude/agents/skill-improver.md +61 -0
  28. package/framework/.claude/agents/ui-expert.md +191 -0
  29. package/framework/.claude/agents/visual-designer.md +190 -0
  30. package/framework/.claude/agents/website-orchestrator.md +118 -0
  31. package/framework/.claude/agents/wiki-curator.md +145 -0
  32. package/framework/.claude/commands/baldart-push.md +15 -0
  33. package/framework/.claude/commands/check.md +237 -0
  34. package/framework/.claude/commands/codexreview.md +203 -0
  35. package/framework/.claude/commands/design-review.md +11 -0
  36. package/framework/.claude/commands/issue-review.md +34 -0
  37. package/framework/.claude/commands/new.md +331 -0
  38. package/framework/.claude/commands/qa.md +257 -0
  39. package/framework/.claude/hooks/framework-edit-gate.js +208 -0
  40. package/framework/.claude/hooks/lint-before-commit.sh.template +66 -0
  41. package/framework/.claude/settings.local.json.example +32 -0
  42. package/framework/.claude/skills/api-design-principles/SKILL.md +567 -0
  43. package/framework/.claude/skills/api-design-principles/assets/api-design-checklist.md +155 -0
  44. package/framework/.claude/skills/api-design-principles/assets/rest-api-template.py +182 -0
  45. package/framework/.claude/skills/api-design-principles/references/graphql-schema-design.md +583 -0
  46. package/framework/.claude/skills/api-design-principles/references/rest-best-practices.md +408 -0
  47. package/framework/.claude/skills/baldart-push/SKILL.md +222 -0
  48. package/framework/.claude/skills/bug/SKILL.md +200 -0
  49. package/framework/.claude/skills/bug/references/logging-patterns.md +174 -0
  50. package/framework/.claude/skills/capture/SKILL.md +125 -0
  51. package/framework/.claude/skills/capture/references/synthesis-template.md +42 -0
  52. package/framework/.claude/skills/context-primer/SKILL.md +189 -0
  53. package/framework/.claude/skills/copywriting/SKILL.md +273 -0
  54. package/framework/.claude/skills/copywriting/references/copy-frameworks.md +338 -0
  55. package/framework/.claude/skills/copywriting/references/natural-transitions.md +252 -0
  56. package/framework/.claude/skills/doc-writing-for-rag/SKILL.md +119 -0
  57. package/framework/.claude/skills/doc-writing-for-rag/references/before-after-examples.md +291 -0
  58. package/framework/.claude/skills/doc-writing-for-rag/references/compact-templates.md +183 -0
  59. package/framework/.claude/skills/doc-writing-for-rag/references/frontmatter-minimal.md +112 -0
  60. package/framework/.claude/skills/doc-writing-for-rag/references/line-count-targets.md +110 -0
  61. package/framework/.claude/skills/doc-writing-for-rag/references/schemas-and-errors.md +129 -0
  62. package/framework/.claude/skills/find-skills/SKILL.md +133 -0
  63. package/framework/.claude/skills/frontend-design/LICENSE.txt +177 -0
  64. package/framework/.claude/skills/frontend-design/SKILL.md +84 -0
  65. package/framework/.claude/skills/gamification-design/SKILL.md +130 -0
  66. package/framework/.claude/skills/issue-review/SKILL.md +45 -0
  67. package/framework/.claude/skills/kie-ai/SKILL.md +262 -0
  68. package/framework/.claude/skills/kie-ai/references/models-catalog.md +272 -0
  69. package/framework/.claude/skills/kie-ai/scripts/kie_api.sh +209 -0
  70. package/framework/.claude/skills/kie-ai/scripts/remove_greenscreen.py +69 -0
  71. package/framework/.claude/skills/kie-ai/scripts/setup_api_key.sh +77 -0
  72. package/framework/.claude/skills/motion-design/LICENSE +21 -0
  73. package/framework/.claude/skills/motion-design/README.md +82 -0
  74. package/framework/.claude/skills/motion-design/SKILL.md +336 -0
  75. package/framework/.claude/skills/motion-design/director/choreography.md +93 -0
  76. package/framework/.claude/skills/motion-design/director/context-adaptation.md +83 -0
  77. package/framework/.claude/skills/motion-design/director/core-philosophy.md +53 -0
  78. package/framework/.claude/skills/motion-design/director/decision-framework.md +91 -0
  79. package/framework/.claude/skills/motion-design/director/disney-principles.md +102 -0
  80. package/framework/.claude/skills/motion-design/director/emotion-mapping.md +71 -0
  81. package/framework/.claude/skills/motion-design/director/motion-personality.md +89 -0
  82. package/framework/.claude/skills/motion-design/director/narrative-structure.md +62 -0
  83. package/framework/.claude/skills/motion-design/patterns/ambient-continuous.md +81 -0
  84. package/framework/.claude/skills/motion-design/patterns/entrance-exit.md +82 -0
  85. package/framework/.claude/skills/motion-design/patterns/multi-element.md +69 -0
  86. package/framework/.claude/skills/motion-design/patterns/state-feedback.md +96 -0
  87. package/framework/.claude/skills/motion-design/reference/property-selection.md +95 -0
  88. package/framework/.claude/skills/motion-design/reference/quality-checklist.md +67 -0
  89. package/framework/.claude/skills/motion-design/reference/timing-easing-tables.md +106 -0
  90. package/framework/.claude/skills/motion-design/reference/troubleshooting.md +73 -0
  91. package/framework/.claude/skills/new/SKILL.md +1687 -0
  92. package/framework/.claude/skills/playwright-skill/API_REFERENCE.md +652 -0
  93. package/framework/.claude/skills/playwright-skill/SKILL.md +157 -0
  94. package/framework/.claude/skills/playwright-skill/package.json +26 -0
  95. package/framework/.claude/skills/prd/SKILL.md +228 -0
  96. package/framework/.claude/skills/prd/assets/card-template.yml +232 -0
  97. package/framework/.claude/skills/prd/assets/epic-template.yml +190 -0
  98. package/framework/.claude/skills/prd/assets/prd-template.md +230 -0
  99. package/framework/.claude/skills/prd/assets/state-template.md +78 -0
  100. package/framework/.claude/skills/prd/references/api-perf-gate.md +152 -0
  101. package/framework/.claude/skills/prd/references/audit-phase.md +478 -0
  102. package/framework/.claude/skills/prd/references/backlog-phase.md +145 -0
  103. package/framework/.claude/skills/prd/references/discovery-phase.md +359 -0
  104. package/framework/.claude/skills/prd/references/impact-analysis.md +233 -0
  105. package/framework/.claude/skills/prd/references/prd-add-phase.md +214 -0
  106. package/framework/.claude/skills/prd/references/prd-writing-phase.md +145 -0
  107. package/framework/.claude/skills/prd/references/research-phase.md +216 -0
  108. package/framework/.claude/skills/prd/references/ui-design-phase.md +61 -0
  109. package/framework/.claude/skills/prd/references/validation-phase.md +72 -0
  110. package/framework/.claude/skills/prd-add/SKILL.md +222 -0
  111. package/framework/.claude/skills/prd-add/references/impact-analysis.md +233 -0
  112. package/framework/.claude/skills/remotion-best-practices/SKILL.md +48 -0
  113. package/framework/.claude/skills/remotion-best-practices/rules/3d.md +86 -0
  114. package/framework/.claude/skills/remotion-best-practices/rules/animations.md +29 -0
  115. package/framework/.claude/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
  116. package/framework/.claude/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
  117. package/framework/.claude/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
  118. package/framework/.claude/skills/remotion-best-practices/rules/assets.md +78 -0
  119. package/framework/.claude/skills/remotion-best-practices/rules/audio.md +169 -0
  120. package/framework/.claude/skills/remotion-best-practices/rules/calculate-metadata.md +104 -0
  121. package/framework/.claude/skills/remotion-best-practices/rules/can-decode.md +75 -0
  122. package/framework/.claude/skills/remotion-best-practices/rules/charts.md +58 -0
  123. package/framework/.claude/skills/remotion-best-practices/rules/compositions.md +141 -0
  124. package/framework/.claude/skills/remotion-best-practices/rules/display-captions.md +184 -0
  125. package/framework/.claude/skills/remotion-best-practices/rules/extract-frames.md +229 -0
  126. package/framework/.claude/skills/remotion-best-practices/rules/fonts.md +152 -0
  127. package/framework/.claude/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
  128. package/framework/.claude/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
  129. package/framework/.claude/skills/remotion-best-practices/rules/get-video-duration.md +58 -0
  130. package/framework/.claude/skills/remotion-best-practices/rules/gifs.md +141 -0
  131. package/framework/.claude/skills/remotion-best-practices/rules/images.md +130 -0
  132. package/framework/.claude/skills/remotion-best-practices/rules/import-srt-captions.md +69 -0
  133. package/framework/.claude/skills/remotion-best-practices/rules/light-leaks.md +73 -0
  134. package/framework/.claude/skills/remotion-best-practices/rules/lottie.md +67 -0
  135. package/framework/.claude/skills/remotion-best-practices/rules/maps.md +401 -0
  136. package/framework/.claude/skills/remotion-best-practices/rules/measuring-dom-nodes.md +34 -0
  137. package/framework/.claude/skills/remotion-best-practices/rules/measuring-text.md +143 -0
  138. package/framework/.claude/skills/remotion-best-practices/rules/parameters.md +98 -0
  139. package/framework/.claude/skills/remotion-best-practices/rules/sequencing.md +118 -0
  140. package/framework/.claude/skills/remotion-best-practices/rules/subtitles.md +36 -0
  141. package/framework/.claude/skills/remotion-best-practices/rules/tailwind.md +11 -0
  142. package/framework/.claude/skills/remotion-best-practices/rules/text-animations.md +20 -0
  143. package/framework/.claude/skills/remotion-best-practices/rules/timing.md +179 -0
  144. package/framework/.claude/skills/remotion-best-practices/rules/transcribe-captions.md +70 -0
  145. package/framework/.claude/skills/remotion-best-practices/rules/transitions.md +197 -0
  146. package/framework/.claude/skills/remotion-best-practices/rules/transparent-videos.md +106 -0
  147. package/framework/.claude/skills/remotion-best-practices/rules/trimming.md +52 -0
  148. package/framework/.claude/skills/remotion-best-practices/rules/videos.md +171 -0
  149. package/framework/.claude/skills/seo-audit/SKILL.md +394 -0
  150. package/framework/.claude/skills/seo-audit/references/aeo-geo-patterns.md +279 -0
  151. package/framework/.claude/skills/seo-audit/references/ai-writing-detection.md +190 -0
  152. package/framework/.claude/skills/simplify/SKILL.md +137 -0
  153. package/framework/.claude/skills/skill-creator/LICENSE.txt +202 -0
  154. package/framework/.claude/skills/skill-creator/SKILL.md +356 -0
  155. package/framework/.claude/skills/skill-creator/references/output-patterns.md +82 -0
  156. package/framework/.claude/skills/skill-creator/references/workflows.md +28 -0
  157. package/framework/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
  158. package/framework/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
  159. package/framework/.claude/skills/skill-creator/scripts/quick_validate.py +95 -0
  160. package/framework/.claude/skills/ui-design/SKILL.md +199 -0
  161. package/framework/.claude/skills/ui-design/references/component-discovery.md +54 -0
  162. package/framework/.claude/skills/ui-design/references/evaluation.md +171 -0
  163. package/framework/.claude/skills/ui-design/references/generation.md +109 -0
  164. package/framework/.claude/skills/ui-design/references/inventory.md +59 -0
  165. package/framework/.claude/skills/webapp-testing/LICENSE.txt +202 -0
  166. package/framework/.claude/skills/webapp-testing/SKILL.md +123 -0
  167. package/framework/.claude/skills/webapp-testing/examples/console_logging.py +35 -0
  168. package/framework/.claude/skills/webapp-testing/examples/element_discovery.py +40 -0
  169. package/framework/.claude/skills/webapp-testing/examples/static_html_automation.py +33 -0
  170. package/framework/.claude/skills/webapp-testing/scripts/with_server.py +106 -0
  171. package/framework/.claude/skills/worktree-manager/SKILL.md +680 -0
  172. package/framework/AGENTS.md +240 -0
  173. package/framework/agents/api-contracts.md +137 -0
  174. package/framework/agents/architecture.md +145 -0
  175. package/framework/agents/coding-standards.md +148 -0
  176. package/framework/agents/data-model.md +110 -0
  177. package/framework/agents/deployment-protocol.md +232 -0
  178. package/framework/agents/design-review.md +172 -0
  179. package/framework/agents/env-reference.md +171 -0
  180. package/framework/agents/github-issue-subagent.md +252 -0
  181. package/framework/agents/index.md +261 -0
  182. package/framework/agents/llm-wiki-methodology.md +216 -0
  183. package/framework/agents/maintenance-protocol.md +305 -0
  184. package/framework/agents/observability.md +162 -0
  185. package/framework/agents/performance.md +155 -0
  186. package/framework/agents/project-context.md +145 -0
  187. package/framework/agents/runbook.md +208 -0
  188. package/framework/agents/security.md +168 -0
  189. package/framework/agents/skills-mapping.md +286 -0
  190. package/framework/agents/testing.md +111 -0
  191. package/framework/agents/workflows.md +215 -0
  192. package/framework/docs/PROJECT-CONFIGURATION.md +336 -0
  193. package/framework/docs/references/brand-guidelines.md +170 -0
  194. package/framework/docs/references/ui-guidelines.template.md +182 -0
  195. package/framework/routines/code-review.routine.yml +46 -0
  196. package/framework/routines/doc-review.routine.yml +45 -0
  197. package/framework/routines/ds-drift.routine.yml +52 -0
  198. package/framework/routines/full-sweep.routine.yml +51 -0
  199. package/framework/routines/index.yml +70 -0
  200. package/framework/routines/skill-improve.routine.yml +50 -0
  201. package/framework/routines/wiki-review.routine.yml +45 -0
  202. package/framework/templates/baldart.config.template.yml +113 -0
  203. package/framework/templates/breaking-change-checklist.md +484 -0
  204. package/framework/templates/feature-card.template.yml +125 -0
  205. package/framework/templates/overlays/README.md +44 -0
  206. package/framework/templates/overlays/copywriting.fidelity-example.md +62 -0
  207. package/framework/templates/overlays/ui-design.fidelity-example.md +75 -0
  208. package/framework/templates/skill-project-context.snippet.md +19 -0
  209. package/framework/templates/spec.template.md +208 -0
  210. package/package.json +51 -0
  211. package/src/commands/add.js +229 -0
  212. package/src/commands/configure.js +385 -0
  213. package/src/commands/doctor.js +486 -0
  214. package/src/commands/migrate.js +185 -0
  215. package/src/commands/push.js +0 -0
  216. package/src/commands/routines.js +269 -0
  217. package/src/commands/status.js +130 -0
  218. package/src/commands/update.js +419 -0
  219. package/src/commands/version.js +88 -0
  220. package/src/utils/contamination.js +400 -0
  221. package/src/utils/git.js +181 -0
  222. package/src/utils/hooks.js +152 -0
  223. package/src/utils/routine-adapters/claude-code-cloud.js +78 -0
  224. package/src/utils/routine-adapters/cron.js +138 -0
  225. package/src/utils/routine-adapters/github-actions.js +141 -0
  226. package/src/utils/routine-adapters/index.js +21 -0
  227. package/src/utils/routines.js +166 -0
  228. package/src/utils/state.js +143 -0
  229. package/src/utils/symlinks.js +425 -0
  230. package/src/utils/ui.js +133 -0
@@ -0,0 +1,419 @@
1
+ const GitUtils = require('../utils/git');
2
+ const SymlinkUtils = require('../utils/symlinks');
3
+ const UI = require('../utils/ui');
4
+ const State = require('../utils/state');
5
+ const Hooks = require('../utils/hooks');
6
+
7
+ // Path prefixes BALDART itself writes during install/update. Anything outside
8
+ // these patterns is treated as user-owned and never auto-staged.
9
+ const BALDART_MANAGED_PATTERNS = [
10
+ /^\.framework(\/|$)/,
11
+ /^AGENTS\.md$/,
12
+ /^agents(\.backup)?(\/|$)/,
13
+ /^\.claude\/(agents|commands|skills|hooks|routines|settings\.json)(\/|$)/,
14
+ /^\.baldart(\/|$)/,
15
+ /^baldart\.config\.yml$/,
16
+ /^docs\/references\/(ui-guidelines\.template\.md|brand-guidelines\.md)$/,
17
+ /^templates(\/|$)/,
18
+ /^\.github\/workflows\/baldart-/,
19
+ /^scripts\/routines(\/|$)/
20
+ ];
21
+
22
+ function isBaldartManagedPath(p) {
23
+ return BALDART_MANAGED_PATTERNS.some((rx) => rx.test(p));
24
+ }
25
+
26
+ async function postUpdateAutoCommit(git, newVersion, options) {
27
+ if (options && options.commit === false) {
28
+ UI.info('Auto-commit skipped (--no-commit).');
29
+ return;
30
+ }
31
+ let status;
32
+ try {
33
+ status = await git.git.status();
34
+ } catch (err) {
35
+ UI.warning(`Could not read git status for auto-commit: ${err.message}`);
36
+ return;
37
+ }
38
+ // Collect every dirty path simple-git reports, classify against the allowlist.
39
+ const allDirty = [
40
+ ...status.not_added,
41
+ ...status.modified,
42
+ ...status.created,
43
+ ...status.deleted,
44
+ ...status.renamed.map((r) => r.to),
45
+ ...status.staged
46
+ ];
47
+ const seen = new Set();
48
+ const managed = [];
49
+ const userOwned = [];
50
+ for (const p of allDirty) {
51
+ if (!p || seen.has(p)) continue;
52
+ seen.add(p);
53
+ (isBaldartManagedPath(p) ? managed : userOwned).push(p);
54
+ }
55
+ if (managed.length === 0) {
56
+ return;
57
+ }
58
+ UI.newline();
59
+ UI.section('Auto-commit BALDART-managed changes');
60
+ UI.info(`${managed.length} BALDART-managed file(s) changed during this update:`);
61
+ const preview = managed.slice(0, 10);
62
+ UI.list(preview, 'cyan');
63
+ if (managed.length > preview.length) {
64
+ UI.info(`…and ${managed.length - preview.length} more.`);
65
+ }
66
+ if (userOwned.length > 0) {
67
+ UI.warning(`${userOwned.length} other dirty path(s) will be left untouched (not BALDART-managed).`);
68
+ }
69
+ const ok = await UI.confirm(`Commit them as \`chore(baldart): post-update reconcile to v${newVersion}\`?`, true);
70
+ if (!ok) {
71
+ UI.info('Auto-commit declined. Your worktree keeps the changes for manual review.');
72
+ return;
73
+ }
74
+ try {
75
+ await git.git.add(managed);
76
+ const subject = `chore(baldart): post-update reconcile to v${newVersion}`;
77
+ const body = [
78
+ 'Automated by `npx baldart update`.',
79
+ '',
80
+ 'Reconciles BALDART-managed files after framework upgrade:',
81
+ ...managed.map((p) => ` - ${p}`),
82
+ '',
83
+ 'Revert this commit to undo the local reconcile without rolling back the framework subtree.'
84
+ ].join('\n');
85
+ await git.git.commit(`${subject}\n\n${body}`);
86
+ UI.success(`Committed ${managed.length} file(s).`);
87
+ } catch (err) {
88
+ UI.warning(`Auto-commit failed: ${err.message}`);
89
+ UI.info('Your changes are still in the worktree — commit manually when ready.');
90
+ }
91
+ }
92
+
93
+ async function update(options = {}) {
94
+ const git = new GitUtils();
95
+ const symlinks = new SymlinkUtils();
96
+ const repo = 'antbald/BALDART'; // Default repo
97
+
98
+ try {
99
+ // Step 1: Verify installation
100
+ UI.header('STEP 1/5: Verify Installation');
101
+
102
+ const exists = await git.frameworkExists();
103
+ if (!exists) {
104
+ UI.error('Framework not installed!');
105
+ UI.newline();
106
+ UI.box('ERROR', [
107
+ 'Framework directory .framework/ not found.',
108
+ '',
109
+ 'Solution:',
110
+ ' Install first: npx baldart add'
111
+ ]);
112
+ process.exit(1);
113
+ }
114
+
115
+ const currentVersion = await git.getFrameworkVersion();
116
+ UI.success(`Current version: ${currentVersion}`);
117
+
118
+ // Step 2: Check for updates
119
+ UI.header('STEP 2/5: Check for Updates');
120
+
121
+ const spinner = UI.spinner('Connecting to repository...').start();
122
+
123
+ try {
124
+ await git.fetch(repo);
125
+ spinner.succeed('Connected to repository');
126
+ } catch (error) {
127
+ spinner.fail();
128
+ UI.error('Cannot connect to repository!');
129
+ UI.newline();
130
+ UI.box('ERROR', [
131
+ 'Possible causes:',
132
+ ' • No internet connection',
133
+ ' • Repository not accessible',
134
+ '',
135
+ 'Solution:',
136
+ ' • Check internet connection',
137
+ ' • Try again later'
138
+ ]);
139
+ process.exit(1);
140
+ }
141
+
142
+ // Compare versions (simplified - in real scenario would fetch VERSION from remote)
143
+ UI.info('Checking for updates...');
144
+
145
+ const hasChanges = await git.hasChangesToPush();
146
+ if (!hasChanges) {
147
+ UI.success('Already up to date!');
148
+ process.exit(0);
149
+ }
150
+
151
+ UI.warning('Updates available!');
152
+
153
+ // Step 3: Show changes preview
154
+ UI.header('STEP 3/5: Preview Changes');
155
+
156
+ const diff = await git.diffWithRemote();
157
+ if (diff) {
158
+ UI.info('Changes detected. Review recommended.');
159
+ const showDiff = await UI.confirm('Show detailed diff?', false);
160
+
161
+ if (showDiff) {
162
+ console.log(diff);
163
+ }
164
+ }
165
+
166
+ const proceedUpdate = await UI.confirm('Proceed with update?', true);
167
+ if (!proceedUpdate) {
168
+ UI.info('Update cancelled');
169
+ process.exit(0);
170
+ }
171
+
172
+ // Pre-flight: git subtree pull --squash refuses a dirty worktree with
173
+ // "fatal: working tree has modifications. Cannot add." Offer to stash
174
+ // and re-apply after the update, so the user doesn't have to abort mid-flow.
175
+ let stashRef = null;
176
+ const isClean = await git.hasCleanWorkingTree();
177
+ if (!isClean) {
178
+ UI.newline();
179
+ UI.warning('Working tree has uncommitted changes. `git subtree pull` requires a clean tree.');
180
+ const dirty = await git.git.status();
181
+ const dirtyPaths = [
182
+ ...dirty.not_added, ...dirty.modified, ...dirty.created,
183
+ ...dirty.deleted, ...dirty.renamed.map((r) => r.to), ...dirty.staged
184
+ ];
185
+ const unique = [...new Set(dirtyPaths)];
186
+ UI.info(`${unique.length} dirty path(s):`);
187
+ UI.list(unique.slice(0, 8), 'yellow');
188
+ if (unique.length > 8) UI.info(`…and ${unique.length - 8} more.`);
189
+
190
+ const action = await UI.select('How would you like to proceed?', [
191
+ { name: 'Auto-stash now and re-apply after the update (recommended)', value: 'stash' },
192
+ { name: 'Abort — I want to commit or stash manually first', value: 'abort' }
193
+ ]);
194
+ if (action === 'abort') {
195
+ UI.info('Aborted. Commit or `git stash -u`, then re-run `npx baldart update`.');
196
+ process.exit(0);
197
+ }
198
+ stashRef = `baldart-pre-update-${new Date().toISOString().replace(/[:.]/g, '-')}`;
199
+ try {
200
+ await git.git.stash(['push', '-u', '-m', stashRef]);
201
+ UI.success(`Stashed working tree as "${stashRef}".`);
202
+ } catch (err) {
203
+ UI.error(`Could not stash: ${err.message}`);
204
+ process.exit(1);
205
+ }
206
+ }
207
+
208
+ // Step 4: Create backup
209
+ UI.header('STEP 4/5: Create Backup');
210
+
211
+ const backupSpinner = UI.spinner('Creating backup tag...').start();
212
+ const backupTag = await git.createBackupTag();
213
+ backupSpinner.succeed(`Backup created: ${backupTag}`);
214
+
215
+ UI.newline();
216
+ UI.box('ROLLBACK INFO', [
217
+ 'If something goes wrong, rollback with:',
218
+ ` git checkout ${backupTag}`,
219
+ ' git checkout -b recovery-branch'
220
+ ]);
221
+
222
+ // Step 5: Update framework
223
+ UI.header('STEP 5/5: Update Framework');
224
+
225
+ const updateSpinner = UI.spinner('Updating framework...').start();
226
+ let newVersion;
227
+
228
+ try {
229
+ await git.updateSubtree(repo);
230
+ updateSpinner.succeed('Framework updated');
231
+
232
+ newVersion = await git.getFrameworkVersion();
233
+ UI.success(`New version: ${newVersion}`);
234
+ try { State.recordUpdate({ from: currentVersion, to: newVersion }); } catch (_) { /* non-fatal */ }
235
+
236
+ // Re-apply the pre-update stash (if any). Conflicts mean we leave the
237
+ // stash intact and tell the user how to resolve — never silently drop.
238
+ if (stashRef) {
239
+ try {
240
+ await git.git.stash(['pop']);
241
+ UI.success(`Re-applied pre-update stash "${stashRef}".`);
242
+ } catch (err) {
243
+ UI.newline();
244
+ UI.warning(`Could not auto-re-apply stash "${stashRef}" — conflicts with the framework update.`);
245
+ UI.box('STASH CONFLICT', [
246
+ 'Your pre-update changes are preserved in the stash.',
247
+ '',
248
+ 'Inspect: git stash list',
249
+ 'Apply: git stash pop (resolve conflicts manually)',
250
+ 'Discard: git stash drop (only if you no longer need them)'
251
+ ]);
252
+ }
253
+ }
254
+ } catch (error) {
255
+ updateSpinner.fail();
256
+ UI.error('Update failed!');
257
+
258
+ if (error.message.includes('conflict')) {
259
+ UI.newline();
260
+ UI.box('MERGE CONFLICT', [
261
+ 'Git found conflicts during update.',
262
+ '',
263
+ 'Resolution:',
264
+ ' 1. Check conflicts: git status',
265
+ ' 2. For each conflict file:',
266
+ ' • Keep yours: git checkout --ours <file>',
267
+ ' • Use new: git checkout --theirs <file>',
268
+ ' • Edit manually to resolve',
269
+ ' 3. After resolving:',
270
+ ' git add <files>',
271
+ ' git commit -m "Resolved update conflicts"',
272
+ ' 4. Retry: baldart update',
273
+ '',
274
+ 'Or rollback:',
275
+ ` git checkout ${backupTag}`
276
+ ]);
277
+ }
278
+
279
+ // Subtree pull failed — restore the pre-update stash so the user's
280
+ // dirty changes don't appear lost. Conflicts here are unlikely (we
281
+ // never reached the modifying step), but we still report instead of
282
+ // silently dropping.
283
+ if (stashRef) {
284
+ try {
285
+ await git.git.stash(['pop']);
286
+ UI.info(`Restored pre-update stash "${stashRef}".`);
287
+ } catch (popErr) {
288
+ UI.warning(`Could not auto-restore stash "${stashRef}": ${popErr.message}`);
289
+ UI.info('Recover with: git stash list && git stash pop');
290
+ }
291
+ }
292
+
293
+ throw error;
294
+ }
295
+
296
+ // Verify symlinks
297
+ UI.newline();
298
+ UI.section('Verifying Symlinks');
299
+
300
+ const symlinkValid = symlinks.verifySymlinks();
301
+ if (!symlinkValid) {
302
+ UI.info('Some symlinks are missing or out of date. The framework will:');
303
+ UI.list([
304
+ 'Refuse to overwrite any file/dir you customised (you\'ll be asked first).',
305
+ 'Convert legacy .claude/skills/ bulk symlink (v2.0.x) into the new per-item layout.',
306
+ 'Merge framework skills into .claude/skills/ without touching your personal skills.'
307
+ ]);
308
+ const recreate = await UI.confirm('Reconcile symlinks now?', true);
309
+ if (recreate) {
310
+ // Use 'prompt' mode so any customised file (non-symlink) gets a
311
+ // confirmation prompt before being moved to .backup.
312
+ await symlinks.createAllSymlinks({ mode: 'prompt' });
313
+ }
314
+ } else {
315
+ // Even when bulk symlinks are valid, re-run the per-item skill merge
316
+ // to pick up new framework skills shipped in this version.
317
+ symlinks.mergeSkills();
318
+ }
319
+
320
+ // Routines wizard (since v2.1.0) — surfaces routines added in the new framework version
321
+ try {
322
+ const routinesCmd = require('./routines');
323
+ await routinesCmd.postUpdateWizard();
324
+ } catch (err) {
325
+ UI.warning(`Routines wizard skipped: ${err.message}`);
326
+ }
327
+
328
+ // Framework-edit-gate hook (since v3.3.0) — backfill for consumers
329
+ // installed before v3.3.0 didn't have this hook. We register it on every
330
+ // update (idempotent — no-op if already present).
331
+ try {
332
+ const res = Hooks.register();
333
+ if (res.status === 'created' || res.status === 'updated') {
334
+ UI.success('Registered framework-edit-gate hook in .claude/settings.json (v3.3.0+ default).');
335
+ }
336
+ } catch (err) {
337
+ UI.warning(`Hook registration skipped: ${err.message}`);
338
+ }
339
+
340
+ // Project configuration check (since v3.0.0)
341
+ // Never overwrite baldart.config.yml on update. Offer to (re)run configure
342
+ // if the schema has gained required keys, or if no config exists at all.
343
+ try {
344
+ const fs = require('fs');
345
+ const path = require('path');
346
+ const configPath = path.join(process.cwd(), 'baldart.config.yml');
347
+ if (!fs.existsSync(configPath)) {
348
+ UI.newline();
349
+ UI.warning('No baldart.config.yml in this project — skills installed by this framework version require it.');
350
+ const runConfigure = await UI.confirm('Run `baldart configure` now?', true);
351
+ if (runConfigure) {
352
+ const configureCmd = require('./configure');
353
+ await configureCmd();
354
+ }
355
+ } else {
356
+ // Optional: detect schema drift by comparing template vs existing.
357
+ const yaml = require('js-yaml');
358
+ const templatePath = path.join('.framework', 'framework', 'templates', 'baldart.config.template.yml');
359
+ if (fs.existsSync(templatePath)) {
360
+ try {
361
+ const tpl = yaml.load(fs.readFileSync(templatePath, 'utf8')) || {};
362
+ const cur = yaml.load(fs.readFileSync(configPath, 'utf8')) || {};
363
+ const missingFeatures = Object.keys(tpl.features || {})
364
+ .filter((k) => !(k in (cur.features || {})));
365
+ const missingPaths = Object.keys(tpl.paths || {})
366
+ .filter((k) => !(k in (cur.paths || {})));
367
+ if (missingFeatures.length || missingPaths.length) {
368
+ UI.newline();
369
+ UI.warning(
370
+ `New config keys in this version: ${[...missingPaths, ...missingFeatures].join(', ')}. ` +
371
+ 'Re-run `npx baldart configure` to populate them (existing values are preserved).'
372
+ );
373
+ }
374
+ } catch (_) {
375
+ // Non-fatal — schema drift detection is best-effort.
376
+ }
377
+ }
378
+ }
379
+ } catch (err) {
380
+ UI.warning(`Configuration check skipped: ${err.message}`);
381
+ }
382
+
383
+ // Post-update auto-commit (v3.5.0+) — keep the worktree clean and leave
384
+ // a single revertable commit for the reconcile step.
385
+ try {
386
+ await postUpdateAutoCommit(git, newVersion, options);
387
+ } catch (err) {
388
+ UI.warning(`Auto-commit step skipped: ${err.message}`);
389
+ }
390
+
391
+ // Success
392
+ UI.header('✓ UPDATE COMPLETE');
393
+
394
+ UI.box('WHAT CHANGED', [
395
+ `Version: ${currentVersion} → ${newVersion}`,
396
+ '',
397
+ 'Review CHANGELOG:',
398
+ ' cat .framework/CHANGELOG.md',
399
+ '',
400
+ 'Check template updates:',
401
+ ' diff .framework/.claude/hooks/*.template .claude/hooks/',
402
+ '',
403
+ 'Review routines:',
404
+ ' npx baldart routines list',
405
+ '',
406
+ `Backup available: ${backupTag}`,
407
+ `Remove when confident: git tag -d ${backupTag}`
408
+ ]);
409
+
410
+ UI.newline();
411
+ UI.success('Framework updated successfully!');
412
+
413
+ } catch (error) {
414
+ UI.error(`Update failed: ${error.message}`);
415
+ process.exit(1);
416
+ }
417
+ }
418
+
419
+ module.exports = update;
@@ -0,0 +1,88 @@
1
+ const GitUtils = require('../utils/git');
2
+ const UI = require('../utils/ui');
3
+ const State = require('../utils/state');
4
+
5
+ const REPO_DEFAULT = 'antbald/BALDART';
6
+ const FRAMEWORK_DIR = '.framework';
7
+
8
+ function fmtDate(iso) {
9
+ if (!iso) return '—';
10
+ try { return iso.slice(0, 10); } catch (_) { return iso; }
11
+ }
12
+
13
+ async function describeDrift(git) {
14
+ // Returns { ahead, behind, uncommittedFiles, hasFetchHead } or null on failure.
15
+ try {
16
+ let hasFetchHead = false;
17
+ try {
18
+ const out = await git.git.raw(['rev-list', '--left-right', '--count', 'HEAD...FETCH_HEAD']);
19
+ const [a, b] = out.trim().split('\t').map(Number);
20
+ hasFetchHead = !Number.isNaN(a) && !Number.isNaN(b);
21
+ var ahead = a, behind = b;
22
+ } catch (_) { /* no FETCH_HEAD — needs fetch first */ }
23
+
24
+ // Uncommitted local edits to .framework/
25
+ let uncommittedFiles = 0;
26
+ try {
27
+ const dirty = await git.git.raw(['diff', '--name-only', 'HEAD', '--', FRAMEWORK_DIR]);
28
+ uncommittedFiles = dirty.trim() ? dirty.trim().split('\n').length : 0;
29
+ } catch (_) { /* repo without HEAD yet */ }
30
+
31
+ return { ahead, behind, uncommittedFiles, hasFetchHead };
32
+ } catch (_) {
33
+ return null;
34
+ }
35
+ }
36
+
37
+ async function version(opts = {}) {
38
+ const git = new GitUtils();
39
+
40
+ try {
41
+ const exists = await git.frameworkExists();
42
+ if (!exists) {
43
+ UI.warning('Framework not installed');
44
+ UI.info('Install with: npx baldart add');
45
+ process.exit(0);
46
+ }
47
+
48
+ const frameworkVersion = await git.getFrameworkVersion();
49
+ const state = State.load();
50
+ const cliVersion = require('../../package.json').version;
51
+
52
+ // Optionally fetch upstream to compute drift (default: yes).
53
+ const offline = opts.offline === true;
54
+ if (!offline) {
55
+ try {
56
+ await git.fetch(state.framework_repo || REPO_DEFAULT);
57
+ } catch (_) { /* offline — drift report falls back */ }
58
+ }
59
+ const drift = await describeDrift(git);
60
+
61
+ UI.newline();
62
+ UI.box('BALDART VERSION', [
63
+ `Installed: v${frameworkVersion} ${state.install_date ? `(since ${fmtDate(state.install_date)})` : ''}`.trim(),
64
+ drift && drift.hasFetchHead
65
+ ? (drift.behind > 0
66
+ ? `Remote: ${drift.behind} commit(s) ahead — pull with \`npx baldart update\``
67
+ : 'Remote: up to date')
68
+ : 'Remote: (offline / not fetched)',
69
+ drift
70
+ ? (drift.uncommittedFiles > 0
71
+ ? `Local: v${frameworkVersion} + ${drift.uncommittedFiles} uncommitted file(s) in .framework/`
72
+ : `Local: v${frameworkVersion} (clean)`)
73
+ : '',
74
+ '',
75
+ `Last update: ${fmtDate(state.last_update_date)}`,
76
+ `Last push: v${state.last_pushed_version || '—'} ${state.last_push_date ? `(${fmtDate(state.last_push_date)})` : ''}`.trim(),
77
+ '',
78
+ `CLI: v${cliVersion}`,
79
+ `Repository: https://github.com/${state.framework_repo || REPO_DEFAULT}`,
80
+ ].filter((l) => l !== ''));
81
+ UI.newline();
82
+ } catch (error) {
83
+ UI.error(`Failed to get version: ${error.message}`);
84
+ process.exit(1);
85
+ }
86
+ }
87
+
88
+ module.exports = version;