minimal-vibe-coding-kit 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/.agents/skills/agentshield-security-review/SKILL.md +75 -0
  2. package/.agents/skills/agentshield-security-review/agents/openai.yaml +5 -0
  3. package/.agents/skills/agentshield-security-review/references/native-install.md +97 -0
  4. package/.agents/skills/agentshield-security-review/references/report-template.md +54 -0
  5. package/.agents/skills/agentshield-security-review/references/review-checklist.md +45 -0
  6. package/.agents/skills/agentshield-security-review/scripts/agentshield_repo_probe.py +110 -0
  7. package/.agents/skills/autoresearch-coding/README.md +15 -0
  8. package/.agents/skills/autoresearch-coding/SKILL.md +101 -0
  9. package/.agents/skills/autoresearch-coding/references/experiment-contract.md +13 -0
  10. package/.agents/skills/autoresearch-coding/references/metric-extraction.md +8 -0
  11. package/.agents/skills/autoresearch-coding/references/result-ledger.md +15 -0
  12. package/.agents/skills/autoresearch-coding/scripts/log_result.py +24 -0
  13. package/.agents/skills/autoresearch-coding/scripts/run_logged.py +30 -0
  14. package/.agents/skills/clearthought/SKILL.md +100 -0
  15. package/.agents/skills/clearthought/examples/decision-framework.md +441 -0
  16. package/.agents/skills/clearthought/examples/metagame-examples.md +536 -0
  17. package/.agents/skills/clearthought/examples/sequential-thinking.md +380 -0
  18. package/.agents/skills/clearthought/references/output-schemas.md +494 -0
  19. package/.agents/skills/clearthought/references/parameter-reference.md +482 -0
  20. package/.agents/skills/coding-level/SKILL.md +27 -0
  21. package/.agents/skills/coding-level/references/level-0.md +131 -0
  22. package/.agents/skills/coding-level/references/level-1.md +118 -0
  23. package/.agents/skills/coding-level/references/level-2.md +140 -0
  24. package/.agents/skills/coding-level/references/level-3.md +142 -0
  25. package/.agents/skills/coding-level/references/level-4.md +152 -0
  26. package/.agents/skills/coding-level/references/level-5.md +84 -0
  27. package/.agents/skills/daily-workflow-curator/SKILL.md +52 -0
  28. package/.agents/skills/memento/SKILL.md +36 -0
  29. package/.agents/skills/reviewing-4p-priorities/SKILL.md +72 -0
  30. package/.agents/skills/reviewing-4p-priorities/examples.md +298 -0
  31. package/.agents/skills/sequential-thinking/SKILL.md +106 -0
  32. package/.agents/skills/sequential-thinking/examples/adaptive-depth.md +542 -0
  33. package/.agents/skills/sequential-thinking/examples/branching-exploration.md +474 -0
  34. package/.agents/skills/sequential-thinking/examples/linear-reasoning.md +210 -0
  35. package/.agents/skills/sequential-thinking/examples/revision-pattern.md +304 -0
  36. package/.agents/skills/sequential-thinking/references/output-schema.md +483 -0
  37. package/.agents/skills/sequential-thinking/references/parameters.md +463 -0
  38. package/.agents/skills/sequential-thinking/references/patterns.md +666 -0
  39. package/.agents/skills/vibekit-init/SKILL.md +52 -0
  40. package/.agents/skills/visual-design-loop/SKILL.md +103 -0
  41. package/.agents/skills/visual-design-loop/agents/openai.yaml +4 -0
  42. package/.claude/agents/code-reviewer.md +11 -0
  43. package/.claude/agents/context-architect.md +11 -0
  44. package/.claude/agents/debug-fixer.md +11 -0
  45. package/.claude/agents/hypothesis-planner.md +11 -0
  46. package/.claude/agents/implementation-hacker.md +11 -0
  47. package/.claude/agents/research-coordinator.md +11 -0
  48. package/.claude/agents/results-analyst.md +11 -0
  49. package/.claude/agents/security-reviewer.md +11 -0
  50. package/.claude/agents/test-runner.md +11 -0
  51. package/.claude/agents/workflow-curator.md +11 -0
  52. package/.claude/commands/autoresearch-coding.md +15 -0
  53. package/.claude/commands/council.md +7 -0
  54. package/.claude/commands/daily-enhance.md +7 -0
  55. package/.claude/commands/init-vibe.md +7 -0
  56. package/.claude/commands/security-scan.md +7 -0
  57. package/.claude/commands/vibe-finalize.md +7 -0
  58. package/.claude/rules/autoresearch.md +3 -0
  59. package/.claude/rules/security.md +3 -0
  60. package/.claude/rules/tooling.md +6 -0
  61. package/.claude/rules/vibe-core.md +8 -0
  62. package/.claude/settings.json +22 -0
  63. package/.claude/skills/agentshield-security-review/SKILL.md +75 -0
  64. package/.claude/skills/agentshield-security-review/agents/openai.yaml +5 -0
  65. package/.claude/skills/agentshield-security-review/references/native-install.md +97 -0
  66. package/.claude/skills/agentshield-security-review/references/report-template.md +54 -0
  67. package/.claude/skills/agentshield-security-review/references/review-checklist.md +45 -0
  68. package/.claude/skills/agentshield-security-review/scripts/agentshield_repo_probe.py +110 -0
  69. package/.claude/skills/autoresearch-coding/README.md +15 -0
  70. package/.claude/skills/autoresearch-coding/SKILL.md +101 -0
  71. package/.claude/skills/autoresearch-coding/references/experiment-contract.md +13 -0
  72. package/.claude/skills/autoresearch-coding/references/metric-extraction.md +8 -0
  73. package/.claude/skills/autoresearch-coding/references/result-ledger.md +15 -0
  74. package/.claude/skills/autoresearch-coding/scripts/log_result.py +24 -0
  75. package/.claude/skills/autoresearch-coding/scripts/run_logged.py +30 -0
  76. package/.claude/skills/clearthought/SKILL.md +100 -0
  77. package/.claude/skills/clearthought/examples/decision-framework.md +441 -0
  78. package/.claude/skills/clearthought/examples/metagame-examples.md +536 -0
  79. package/.claude/skills/clearthought/examples/sequential-thinking.md +380 -0
  80. package/.claude/skills/clearthought/references/output-schemas.md +494 -0
  81. package/.claude/skills/clearthought/references/parameter-reference.md +482 -0
  82. package/.claude/skills/coding-level/SKILL.md +27 -0
  83. package/.claude/skills/coding-level/references/level-0.md +131 -0
  84. package/.claude/skills/coding-level/references/level-1.md +118 -0
  85. package/.claude/skills/coding-level/references/level-2.md +140 -0
  86. package/.claude/skills/coding-level/references/level-3.md +142 -0
  87. package/.claude/skills/coding-level/references/level-4.md +152 -0
  88. package/.claude/skills/coding-level/references/level-5.md +84 -0
  89. package/.claude/skills/daily-workflow-curator/SKILL.md +52 -0
  90. package/.claude/skills/memento/SKILL.md +36 -0
  91. package/.claude/skills/reviewing-4p-priorities/SKILL.md +72 -0
  92. package/.claude/skills/reviewing-4p-priorities/examples.md +298 -0
  93. package/.claude/skills/sequential-thinking/SKILL.md +106 -0
  94. package/.claude/skills/sequential-thinking/examples/adaptive-depth.md +542 -0
  95. package/.claude/skills/sequential-thinking/examples/branching-exploration.md +474 -0
  96. package/.claude/skills/sequential-thinking/examples/linear-reasoning.md +210 -0
  97. package/.claude/skills/sequential-thinking/examples/revision-pattern.md +304 -0
  98. package/.claude/skills/sequential-thinking/references/output-schema.md +483 -0
  99. package/.claude/skills/sequential-thinking/references/parameters.md +463 -0
  100. package/.claude/skills/sequential-thinking/references/patterns.md +666 -0
  101. package/.claude/skills/vibekit-init/SKILL.md +52 -0
  102. package/.claude/skills/visual-design-loop/SKILL.md +103 -0
  103. package/.claude/skills/visual-design-loop/agents/openai.yaml +4 -0
  104. package/.codex/README.md +11 -0
  105. package/.codex/config.example.toml +8 -0
  106. package/.codex-plugin/plugin.json +10 -0
  107. package/.cursor/commands/autoresearch-coding.md +11 -0
  108. package/.cursor/commands/council.md +3 -0
  109. package/.cursor/commands/daily-enhance.md +3 -0
  110. package/.cursor/commands/init-vibe.md +3 -0
  111. package/.cursor/commands/security-scan.md +3 -0
  112. package/.cursor/commands/vibe-finalize.md +3 -0
  113. package/.cursor/rules/001-vibe-core.mdc +6 -0
  114. package/.cursor/rules/010-init.mdc +7 -0
  115. package/.cursor/rules/020-security-agentshield.mdc +7 -0
  116. package/.cursor/rules/030-autoresearch-loop.mdc +7 -0
  117. package/.cursor/settings.json +22 -0
  118. package/.cursor/skills/clearthought/SKILL.md +100 -0
  119. package/.cursor/skills/clearthought/examples/decision-framework.md +441 -0
  120. package/.cursor/skills/clearthought/examples/metagame-examples.md +536 -0
  121. package/.cursor/skills/clearthought/examples/sequential-thinking.md +380 -0
  122. package/.cursor/skills/clearthought/references/output-schemas.md +494 -0
  123. package/.cursor/skills/clearthought/references/parameter-reference.md +482 -0
  124. package/.cursor/skills/coding-level/SKILL.md +27 -0
  125. package/.cursor/skills/coding-level/references/level-0.md +131 -0
  126. package/.cursor/skills/coding-level/references/level-1.md +118 -0
  127. package/.cursor/skills/coding-level/references/level-2.md +140 -0
  128. package/.cursor/skills/coding-level/references/level-3.md +142 -0
  129. package/.cursor/skills/coding-level/references/level-4.md +152 -0
  130. package/.cursor/skills/coding-level/references/level-5.md +84 -0
  131. package/.cursor/skills/memento/SKILL.md +36 -0
  132. package/.cursor/skills/reviewing-4p-priorities/SKILL.md +72 -0
  133. package/.cursor/skills/reviewing-4p-priorities/examples.md +298 -0
  134. package/.cursor/skills/sequential-thinking/SKILL.md +106 -0
  135. package/.cursor/skills/sequential-thinking/examples/adaptive-depth.md +542 -0
  136. package/.cursor/skills/sequential-thinking/examples/branching-exploration.md +474 -0
  137. package/.cursor/skills/sequential-thinking/examples/linear-reasoning.md +210 -0
  138. package/.cursor/skills/sequential-thinking/examples/revision-pattern.md +304 -0
  139. package/.cursor/skills/sequential-thinking/references/output-schema.md +483 -0
  140. package/.cursor/skills/sequential-thinking/references/parameters.md +463 -0
  141. package/.cursor/skills/sequential-thinking/references/patterns.md +666 -0
  142. package/.vbkit-commands/autoresearch-coding.md +11 -0
  143. package/.vbkit-commands/council.md +3 -0
  144. package/.vbkit-commands/daily-enhance.md +3 -0
  145. package/.vbkit-commands/init-vibe.md +3 -0
  146. package/.vbkit-commands/security-scan.md +3 -0
  147. package/.vbkit-commands/vibe-finalize.md +3 -0
  148. package/.vbkit-docs/AUTORESEARCH_LEDGER.md +11 -0
  149. package/.vbkit-docs/BACKBONE_REFERENCE.md +59 -0
  150. package/.vbkit-docs/INSTALL.md +120 -0
  151. package/.vbkit-docs/RESEARCH_NOTES.md +22 -0
  152. package/.vbkit-docs/SECURITY_MODEL.md +40 -0
  153. package/.vbkit-docs/TOOLING_GUIDE.md +22 -0
  154. package/.vbkit-docs/backbone.schema.json +110 -0
  155. package/.vbkit-docs/templates/CONTEXT_TEMPLATE.md +47 -0
  156. package/.vbkit-docs/templates/PRD_TEMPLATE.md +48 -0
  157. package/.vbkit-scripts/agentshield-probe.mjs +22 -0
  158. package/.vbkit-scripts/daily-enhance.mjs +62 -0
  159. package/.vbkit-scripts/doctor.mjs +323 -0
  160. package/.vbkit-scripts/init-backbone.mjs +628 -0
  161. package/.vbkit-scripts/mvck.mjs +444 -0
  162. package/.vbkit-scripts/pack-dry-run.mjs +16 -0
  163. package/.vbkit-scripts/test-install.mjs +118 -0
  164. package/.vbkit-scripts/validate-kit.mjs +419 -0
  165. package/.vbkit-scripts/vibekit-finalize.mjs +185 -0
  166. package/AGENTS.md +60 -0
  167. package/CHANGELOG.md +34 -0
  168. package/CLAUDE-template.md +52 -0
  169. package/CODE_OF_CONDUCT.md +18 -0
  170. package/CONTRIBUTING.md +28 -0
  171. package/FIRST_PROMPT.md +54 -0
  172. package/FIRST_TIME_INIT.md +165 -0
  173. package/LICENSE +21 -0
  174. package/README.md +493 -0
  175. package/README.vi.md +431 -0
  176. package/SECURITY.md +28 -0
  177. package/backbone.yml +103 -0
  178. package/bin/mvck.js +2 -0
  179. package/bin/vibe-kit.js +2 -0
  180. package/install.ps1 +14 -0
  181. package/install.sh +8 -0
  182. package/package.json +92 -0
  183. package/skills/agentshield-security-review/SKILL.md +75 -0
  184. package/skills/agentshield-security-review/agents/openai.yaml +5 -0
  185. package/skills/agentshield-security-review/references/native-install.md +97 -0
  186. package/skills/agentshield-security-review/references/report-template.md +54 -0
  187. package/skills/agentshield-security-review/references/review-checklist.md +45 -0
  188. package/skills/agentshield-security-review/scripts/agentshield_repo_probe.py +110 -0
  189. package/skills/autoresearch-coding/README.md +15 -0
  190. package/skills/autoresearch-coding/SKILL.md +101 -0
  191. package/skills/autoresearch-coding/references/experiment-contract.md +13 -0
  192. package/skills/autoresearch-coding/references/metric-extraction.md +8 -0
  193. package/skills/autoresearch-coding/references/result-ledger.md +15 -0
  194. package/skills/autoresearch-coding/scripts/log_result.py +24 -0
  195. package/skills/autoresearch-coding/scripts/run_logged.py +30 -0
  196. package/skills/clearthought/SKILL.md +100 -0
  197. package/skills/clearthought/examples/decision-framework.md +441 -0
  198. package/skills/clearthought/examples/metagame-examples.md +536 -0
  199. package/skills/clearthought/examples/sequential-thinking.md +380 -0
  200. package/skills/clearthought/references/output-schemas.md +494 -0
  201. package/skills/clearthought/references/parameter-reference.md +482 -0
  202. package/skills/coding-level/SKILL.md +27 -0
  203. package/skills/coding-level/references/level-0.md +131 -0
  204. package/skills/coding-level/references/level-1.md +118 -0
  205. package/skills/coding-level/references/level-2.md +140 -0
  206. package/skills/coding-level/references/level-3.md +142 -0
  207. package/skills/coding-level/references/level-4.md +152 -0
  208. package/skills/coding-level/references/level-5.md +84 -0
  209. package/skills/daily-workflow-curator/SKILL.md +52 -0
  210. package/skills/memento/SKILL.md +36 -0
  211. package/skills/reviewing-4p-priorities/SKILL.md +72 -0
  212. package/skills/reviewing-4p-priorities/examples.md +298 -0
  213. package/skills/sequential-thinking/SKILL.md +106 -0
  214. package/skills/sequential-thinking/examples/adaptive-depth.md +542 -0
  215. package/skills/sequential-thinking/examples/branching-exploration.md +474 -0
  216. package/skills/sequential-thinking/examples/linear-reasoning.md +210 -0
  217. package/skills/sequential-thinking/examples/revision-pattern.md +304 -0
  218. package/skills/sequential-thinking/references/output-schema.md +483 -0
  219. package/skills/sequential-thinking/references/parameters.md +463 -0
  220. package/skills/sequential-thinking/references/patterns.md +666 -0
  221. package/skills/vibekit-init/SKILL.md +52 -0
  222. package/skills/visual-design-loop/SKILL.md +103 -0
  223. package/skills/visual-design-loop/agents/openai.yaml +4 -0
@@ -0,0 +1,419 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { spawnSync } from 'node:child_process';
5
+
6
+ const root = path.resolve(process.argv[2] || process.cwd());
7
+ let failures = 0;
8
+ let warnings = 0;
9
+
10
+ function ok(msg) { console.log(`PASS ${msg}`); }
11
+ function warn(msg) { warnings += 1; console.log(`WARN ${msg}`); }
12
+ function fail(msg) { failures += 1; console.log(`FAIL ${msg}`); }
13
+ function exists(rel) { return fs.existsSync(path.join(root, rel)); }
14
+ function read(rel) { return fs.readFileSync(path.join(root, rel), 'utf8'); }
15
+ function readJson(rel) {
16
+ try { return JSON.parse(read(rel)); } catch { return null; }
17
+ }
18
+ function requireText(rel, snippet, msg) {
19
+ if (!exists(rel)) return;
20
+ read(rel).includes(snippet) ? ok(msg) : fail(`${rel} missing ${msg}`);
21
+ }
22
+ function listFiles(rel) {
23
+ const base = path.join(root, rel);
24
+ const out = [];
25
+ function inner(current) {
26
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
27
+ const child = path.join(current, entry.name);
28
+ if (entry.isDirectory()) inner(child);
29
+ else out.push(path.relative(base, child).replaceAll(path.sep, '/'));
30
+ }
31
+ }
32
+ try { inner(base); } catch {}
33
+ return out.sort();
34
+ }
35
+
36
+ const required = [
37
+ 'AGENTS.md', 'CLAUDE-template.md', 'FIRST_TIME_INIT.md', 'FIRST_PROMPT.md', 'backbone.yml',
38
+ '.vbkit-scripts/mvck.mjs', '.vbkit-scripts/init-backbone.mjs', '.vbkit-scripts/daily-enhance.mjs', '.vbkit-scripts/validate-kit.mjs',
39
+ '.vbkit-scripts/doctor.mjs', '.vbkit-scripts/test-install.mjs', '.vbkit-scripts/agentshield-probe.mjs', '.vbkit-scripts/pack-dry-run.mjs', '.vbkit-scripts/vibekit-finalize.mjs',
40
+ 'skills/autoresearch-coding/SKILL.md', 'skills/agentshield-security-review/SKILL.md', 'skills/daily-workflow-curator/SKILL.md', 'skills/vibekit-init/SKILL.md',
41
+ 'skills/clearthought/SKILL.md', 'skills/sequential-thinking/SKILL.md', 'skills/reviewing-4p-priorities/SKILL.md', 'skills/visual-design-loop/SKILL.md',
42
+ 'skills/memento/SKILL.md', 'skills/coding-level/SKILL.md',
43
+ '.vbkit-docs/templates/PRD_TEMPLATE.md', '.vbkit-docs/templates/CONTEXT_TEMPLATE.md',
44
+ '.codex/README.md', '.codex/config.example.toml',
45
+ '.claude/skills/autoresearch-coding/SKILL.md', '.claude/skills/agentshield-security-review/SKILL.md',
46
+ '.claude/skills/daily-workflow-curator/SKILL.md', '.claude/skills/vibekit-init/SKILL.md',
47
+ '.claude/skills/clearthought/SKILL.md', '.claude/skills/sequential-thinking/SKILL.md', '.claude/skills/reviewing-4p-priorities/SKILL.md', '.claude/skills/visual-design-loop/SKILL.md',
48
+ '.claude/skills/memento/SKILL.md', '.claude/skills/coding-level/SKILL.md',
49
+ '.cursor/rules/001-vibe-core.mdc', '.cursor/skills/clearthought/SKILL.md', '.cursor/skills/sequential-thinking/SKILL.md', '.cursor/skills/reviewing-4p-priorities/SKILL.md',
50
+ '.cursor/skills/memento/SKILL.md', '.cursor/skills/coding-level/SKILL.md',
51
+ '.agents/skills/autoresearch-coding/SKILL.md', '.agents/skills/agentshield-security-review/SKILL.md',
52
+ '.agents/skills/daily-workflow-curator/SKILL.md', '.agents/skills/vibekit-init/SKILL.md',
53
+ '.agents/skills/clearthought/SKILL.md', '.agents/skills/sequential-thinking/SKILL.md', '.agents/skills/reviewing-4p-priorities/SKILL.md', '.agents/skills/visual-design-loop/SKILL.md',
54
+ '.agents/skills/memento/SKILL.md', '.agents/skills/coding-level/SKILL.md',
55
+ '.codex-plugin/plugin.json'
56
+ ];
57
+
58
+ const reasoningSkillResources = {
59
+ 'clearthought': [
60
+ 'references/output-schemas.md',
61
+ 'references/parameter-reference.md',
62
+ 'examples/sequential-thinking.md',
63
+ 'examples/decision-framework.md',
64
+ 'examples/metagame-examples.md'
65
+ ],
66
+ 'sequential-thinking': [
67
+ 'references/output-schema.md',
68
+ 'references/parameters.md',
69
+ 'references/patterns.md',
70
+ 'examples/linear-reasoning.md',
71
+ 'examples/revision-pattern.md',
72
+ 'examples/branching-exploration.md',
73
+ 'examples/adaptive-depth.md'
74
+ ],
75
+ 'reviewing-4p-priorities': [
76
+ 'examples.md'
77
+ ]
78
+ };
79
+
80
+ for (const surface of ['skills', '.claude/skills', '.cursor/skills', '.agents/skills']) {
81
+ for (const [skill, files] of Object.entries(reasoningSkillResources)) {
82
+ for (const file of files) required.push(`${surface}/${skill}/${file}`);
83
+ }
84
+ }
85
+
86
+ for (const rel of required) exists(rel) ? ok(`required file ${rel}`) : fail(`missing required file ${rel}`);
87
+ if (exists('README.md')) ok('optional README.md present');
88
+ else console.log('INFO optional README.md not present in target project');
89
+
90
+ requireText('.github/workflows/vibekit-validate.yml', 'npm test', 'CI workflow runs npm test');
91
+ requireText('.github/workflows/vibekit-validate.yml', 'npm run security:probe', 'CI workflow runs AgentShield probe');
92
+ requireText('.github/workflows/vibekit-validate.yml', 'npm run pack:dry-run', 'CI workflow verifies npm package contents');
93
+ requireText('.vbkit-docs/AUTORESEARCH_LEDGER.md', 'node .vbkit-scripts/validate-kit.mjs .', 'autoresearch ledger documents validation command');
94
+ requireText('.cursor/rules/020-security-agentshield.mdc', 'node .vbkit-scripts/agentshield-probe.mjs .', 'Cursor security rule uses Node AgentShield probe wrapper');
95
+ requireText('.vbkit-scripts/doctor.mjs', '.vbkit-scripts/agentshield-probe.mjs', 'doctor uses Node AgentShield probe wrapper');
96
+
97
+ if (exists('.vbkit-docs/AUTORESEARCH_LEDGER.md')) {
98
+ const ledgerText = read('.vbkit-docs/AUTORESEARCH_LEDGER.md');
99
+ const stalePhrases = ['pending during build', 'BUILD_REPORT.md'];
100
+ const stalePhrase = stalePhrases.find((phrase) => ledgerText.includes(phrase));
101
+ stalePhrase ? fail(`.vbkit-docs/AUTORESEARCH_LEDGER.md contains stale phrase: ${stalePhrase}`) : ok('autoresearch ledger has no stale build placeholders');
102
+ }
103
+
104
+ const skillMirrors = {
105
+ 'autoresearch-coding': ['.claude/skills/autoresearch-coding', '.agents/skills/autoresearch-coding'],
106
+ 'agentshield-security-review': ['.claude/skills/agentshield-security-review', '.agents/skills/agentshield-security-review'],
107
+ 'daily-workflow-curator': ['.claude/skills/daily-workflow-curator', '.agents/skills/daily-workflow-curator'],
108
+ 'vibekit-init': ['.claude/skills/vibekit-init', '.agents/skills/vibekit-init'],
109
+ 'clearthought': ['.claude/skills/clearthought', '.cursor/skills/clearthought', '.agents/skills/clearthought'],
110
+ 'sequential-thinking': ['.claude/skills/sequential-thinking', '.cursor/skills/sequential-thinking', '.agents/skills/sequential-thinking'],
111
+ 'reviewing-4p-priorities': ['.claude/skills/reviewing-4p-priorities', '.cursor/skills/reviewing-4p-priorities', '.agents/skills/reviewing-4p-priorities'],
112
+ 'visual-design-loop': ['.claude/skills/visual-design-loop', '.agents/skills/visual-design-loop'],
113
+ 'memento': ['.claude/skills/memento', '.cursor/skills/memento', '.agents/skills/memento'],
114
+ 'coding-level': ['.claude/skills/coding-level', '.cursor/skills/coding-level', '.agents/skills/coding-level']
115
+ };
116
+
117
+ function validateSkillMirror(sourceRel, mirrorRel) {
118
+ if (!exists(sourceRel)) { fail(`missing canonical skill dir ${sourceRel}`); return; }
119
+ if (!exists(mirrorRel)) { fail(`missing skill mirror dir ${mirrorRel}`); return; }
120
+
121
+ const sourceFiles = listFiles(sourceRel);
122
+ const mirrorFiles = listFiles(mirrorRel);
123
+ const sourceSet = new Set(sourceFiles);
124
+ const mirrorSet = new Set(mirrorFiles);
125
+ let mismatches = 0;
126
+
127
+ for (const file of sourceFiles) {
128
+ if (!mirrorSet.has(file)) {
129
+ mismatches += 1;
130
+ fail(`skill mirror ${mirrorRel} missing ${file}`);
131
+ continue;
132
+ }
133
+ const sourceText = fs.readFileSync(path.join(root, sourceRel, file), 'utf8');
134
+ const mirrorText = fs.readFileSync(path.join(root, mirrorRel, file), 'utf8');
135
+ if (sourceText !== mirrorText) {
136
+ mismatches += 1;
137
+ fail(`skill mirror ${mirrorRel}/${file} differs from ${sourceRel}/${file}`);
138
+ }
139
+ }
140
+
141
+ for (const file of mirrorFiles) {
142
+ if (!sourceSet.has(file)) {
143
+ mismatches += 1;
144
+ fail(`skill mirror ${mirrorRel} has extra file ${file}`);
145
+ }
146
+ }
147
+
148
+ if (mismatches === 0) ok(`skill mirror ${mirrorRel} matches ${sourceRel} (${sourceFiles.length} files)`);
149
+ }
150
+
151
+ for (const [skill, mirrors] of Object.entries(skillMirrors)) {
152
+ for (const mirror of mirrors) validateSkillMirror(`skills/${skill}`, mirror);
153
+ }
154
+
155
+ function parseFrontmatter(text) {
156
+ const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
157
+ if (!match) return null;
158
+ const fields = {};
159
+ for (const line of match[1].split(/\r?\n/)) {
160
+ const kv = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
161
+ if (kv) fields[kv[1]] = kv[2].trim();
162
+ }
163
+ return fields;
164
+ }
165
+
166
+ for (const surface of ['skills', '.claude/skills', '.cursor/skills', '.agents/skills']) {
167
+ if (!exists(surface)) continue;
168
+ for (const file of listFiles(surface).filter((f) => f.endsWith('SKILL.md'))) {
169
+ const rel = `${surface}/${file}`;
170
+ const fm = parseFrontmatter(read(rel));
171
+ if (fm && fm.name && fm.description) ok(`skill frontmatter has name + description: ${rel}`);
172
+ else fail(`skill frontmatter missing name/description: ${rel}`);
173
+ const skillDir = path.dirname(file);
174
+ if (fm && fm.name === skillDir) ok(`skill name matches directory: ${rel}`);
175
+ else fail(`skill name "${fm?.name ?? ''}" does not match directory "${skillDir}": ${rel}`);
176
+ }
177
+ }
178
+
179
+ function stripFrontmatter(text) {
180
+ return text.replace(/^---\n[\s\S]*?\n---\n?/, '').trim();
181
+ }
182
+
183
+ if (exists('.vbkit-commands')) {
184
+ const canonicalCmds = listFiles('.vbkit-commands').filter((f) => f.endsWith('.md'));
185
+ const cmdMirrors = { '.claude/commands': true, '.cursor/commands': true };
186
+ for (const [mirrorDir, stripFm] of Object.entries(cmdMirrors)) {
187
+ if (!exists(mirrorDir)) { warn(`command mirror dir missing: ${mirrorDir}`); continue; }
188
+ for (const file of canonicalCmds) {
189
+ const srcRel = `.vbkit-commands/${file}`;
190
+ const mirRel = `${mirrorDir}/${file}`;
191
+ if (!exists(mirRel)) { fail(`command mirror ${mirRel} missing`); continue; }
192
+ const srcText = read(srcRel).trim();
193
+ const mirText = stripFm ? stripFrontmatter(read(mirRel)) : read(mirRel).trim();
194
+ if (srcText === mirText) ok(`command mirror ${mirRel} matches`);
195
+ else fail(`command mirror ${mirRel} differs from ${srcRel}`);
196
+ }
197
+ }
198
+ }
199
+
200
+ for (const rel of ['package.json', '.claude/settings.json', '.cursor/settings.json', '.codex-plugin/plugin.json']) {
201
+ if (!exists(rel)) continue;
202
+ try { JSON.parse(read(rel)); ok(`valid JSON ${rel}`); } catch (error) { fail(`invalid JSON ${rel}: ${error.message}`); }
203
+ }
204
+
205
+ const pkg = exists('package.json') ? readJson('package.json') : null;
206
+ if (pkg?.bin && typeof pkg.bin === 'object') {
207
+ for (const [name, target] of Object.entries(pkg.bin)) {
208
+ if (typeof target !== 'string') { fail(`package bin ${name} target must be a string`); continue; }
209
+ exists(target) ? ok(`package bin ${name} target exists: ${target}`) : fail(`package bin ${name} target missing: ${target}`);
210
+ }
211
+ }
212
+
213
+ if (Array.isArray(pkg?.files)) {
214
+ for (const entry of pkg.files) {
215
+ if (typeof entry !== 'string') { fail('package files entry must be a string'); continue; }
216
+ const cleanEntry = entry.replace(/\/+$/, '');
217
+ exists(cleanEntry) ? ok(`package files entry exists: ${entry}`) : fail(`package files entry missing: ${entry}`);
218
+ }
219
+ }
220
+
221
+ if (pkg?.scripts && typeof pkg.scripts === 'object') {
222
+ const scriptTargetRe = /node\s+(?:--check\s+)?((?:\.\/)?(?:\.vbkit-scripts|bin)\/[A-Za-z0-9._-]+\.(?:mjs|js))/g;
223
+ const targets = new Set();
224
+ for (const command of Object.values(pkg.scripts)) {
225
+ if (typeof command !== 'string') continue;
226
+ let match;
227
+ while ((match = scriptTargetRe.exec(command))) targets.add(match[1].replace(/^\.\//, ''));
228
+ }
229
+ for (const target of [...targets].sort()) {
230
+ exists(target) ? ok(`package script target exists: ${target}`) : fail(`package script references missing file: ${target}`);
231
+ }
232
+ }
233
+
234
+ function extractDenyCategories(denyList) {
235
+ const cats = new Set();
236
+ for (const rule of denyList) {
237
+ const match = rule.match(/^Bash\(([a-z][a-z -]*)/);
238
+ if (match) cats.add(match[1].trim());
239
+ }
240
+ return cats;
241
+ }
242
+
243
+ const claudeSettings = readJson('.claude/settings.json');
244
+ const cursorSettings = readJson('.cursor/settings.json');
245
+ if (claudeSettings?.permissions?.deny && cursorSettings?.permissions?.deny) {
246
+ const claudeCats = extractDenyCategories(claudeSettings.permissions.deny);
247
+ const cursorCats = extractDenyCategories(cursorSettings.permissions.deny);
248
+ let parity = true;
249
+ for (const cat of claudeCats) {
250
+ if (!cursorCats.has(cat)) { warn(`deny list parity: .claude blocks "${cat}" but .cursor does not`); parity = false; }
251
+ }
252
+ for (const cat of cursorCats) {
253
+ if (!claudeCats.has(cat)) { warn(`deny list parity: .cursor blocks "${cat}" but .claude does not`); parity = false; }
254
+ }
255
+ if (parity) ok(`deny list category parity across .claude and .cursor (${claudeCats.size} categories)`);
256
+ }
257
+
258
+ if (pkg?.name === 'minimal-vibe-coding-kit') {
259
+ for (const rel of ['SECURITY.md', 'CONTRIBUTING.md', 'CODE_OF_CONDUCT.md', '.github/dependabot.yml', '.github/workflows/vibekit-validate.yml', '.vbkit-docs/backbone.schema.json']) {
260
+ exists(rel) ? ok(`release safety file ${rel}`) : fail(`missing release safety file ${rel}`);
261
+ }
262
+ }
263
+
264
+ if (exists('CLAUDE-template.md')) {
265
+ const lines = read('CLAUDE-template.md').split(/\r?\n/).length;
266
+ if (lines <= 120) ok(`CLAUDE-template.md is concise (${lines} lines)`);
267
+ else warn(`CLAUDE-template.md is long (${lines} lines); target <= 120`);
268
+ }
269
+
270
+ if (exists('backbone.yml')) {
271
+ const text = read('backbone.yml');
272
+ if (text.split(/\r?\n/).length <= 120) ok('backbone.yml template is concise');
273
+ else warn('backbone.yml template is longer than target');
274
+ if (text.includes('template_status:')) ok('backbone.yml has template_status'); else fail('backbone.yml missing template_status');
275
+ validateBackboneSchema(text);
276
+ }
277
+
278
+ function collectYamlKeys(text) {
279
+ const keys = new Set();
280
+ const values = new Map();
281
+ const stack = [];
282
+ for (const raw of text.split(/\r?\n/)) {
283
+ const line = raw.replace(/\s+#.*$/, '');
284
+ if (!line.trim() || line.trimStart().startsWith('- ')) continue;
285
+ const match = line.match(/^(\s*)([A-Za-z0-9_-]+):(?:\s*(.*))?$/);
286
+ if (!match) continue;
287
+ const indent = match[1].length;
288
+ const key = match[2];
289
+ const value = (match[3] || '').trim();
290
+ while (stack.length && stack[stack.length - 1].indent >= indent) stack.pop();
291
+ const full = [...stack.map((item) => item.key), key].join('.');
292
+ keys.add(full);
293
+ values.set(full, value);
294
+ stack.push({ indent, key });
295
+ }
296
+ return { keys, values };
297
+ }
298
+
299
+ function hasListItems(text, keyPath) {
300
+ const parts = keyPath.split('.');
301
+ const key = parts[parts.length - 1];
302
+ const lines = text.split(/\r?\n/);
303
+ const matches = [];
304
+ const stack = [];
305
+ for (let i = 0; i < lines.length; i += 1) {
306
+ const line = lines[i].replace(/\s+#.*$/, '');
307
+ const match = line.match(/^(\s*)([A-Za-z0-9_-]+):(?:\s*(.*))?$/);
308
+ if (!match) continue;
309
+ const indent = match[1].length;
310
+ while (stack.length && stack[stack.length - 1].indent >= indent) stack.pop();
311
+ const full = [...stack.map((item) => item.key), match[2]].join('.');
312
+ if (full === keyPath && match[2] === key) matches.push({ line: i, indent, value: (match[3] || '').trim() });
313
+ stack.push({ indent, key: match[2] });
314
+ }
315
+ if (!matches.length) return false;
316
+ const item = matches[0];
317
+ if (item.value.startsWith('[')) return item.value !== '[]';
318
+ for (const line of lines.slice(item.line + 1)) {
319
+ if (!line.trim()) continue;
320
+ const indent = line.match(/^\s*/)[0].length;
321
+ if (indent <= item.indent) return false;
322
+ if (/^\s*-\s+\S/.test(line)) return true;
323
+ }
324
+ return false;
325
+ }
326
+
327
+ function validateBackboneSchema(text) {
328
+ const { keys, values } = collectYamlKeys(text);
329
+ const requiredKeys = [
330
+ 'version',
331
+ 'meta.template_status',
332
+ 'meta.schema_version',
333
+ 'project.name',
334
+ 'project.primary_language',
335
+ 'project.mode',
336
+ 'project.context',
337
+ 'conventions',
338
+ 'conventions.review_required_before_write',
339
+ 'conventions.resources.rule',
340
+ 'conventions.localization.rule',
341
+ 'commands.validate',
342
+ 'policy.protected_paths',
343
+ 'agent_surfaces',
344
+ 'automation.finalize.cleanup_dir',
345
+ 'automation.security.probe'
346
+ ];
347
+ for (const key of requiredKeys) keys.has(key) ? ok(`backbone schema key ${key}`) : fail(`backbone missing schema key ${key}`);
348
+
349
+ const templateStatus = values.get('meta.template_status');
350
+ if (['initialized', 'uninitialized'].includes(templateStatus)) ok(`backbone template_status is ${templateStatus}`);
351
+ else fail(`backbone template_status must be initialized or uninitialized, got ${templateStatus || 'empty'}`);
352
+
353
+ const schemaVersion = values.get('meta.schema_version');
354
+ if (/^\d+$/.test(schemaVersion || '')) ok(`backbone schema_version is ${schemaVersion}`);
355
+ else fail(`backbone schema_version must be numeric, got ${schemaVersion || 'empty'}`);
356
+
357
+ const validateCommand = values.get('commands.validate');
358
+ if (validateCommand && validateCommand !== 'null') ok('backbone commands.validate is set');
359
+ else fail('backbone commands.validate is empty');
360
+
361
+ hasListItems(text, 'policy.protected_paths') ? ok('backbone protected_paths is non-empty') : fail('backbone protected_paths must be non-empty');
362
+
363
+ for (const key of [...keys].filter((k) => k.startsWith('agent_surfaces.') && !k.includes('.', 'agent_surfaces.'.length))) {
364
+ const surfacePath = values.get(key);
365
+ if (!surfacePath || surfacePath === 'null') continue;
366
+ const cleanPath = surfacePath.replace(/^["']|["']$/g, '');
367
+ if (exists(cleanPath)) ok(`agent_surfaces path exists: ${cleanPath}`);
368
+ else fail(`agent_surfaces path missing: ${cleanPath}`);
369
+ }
370
+ }
371
+
372
+ for (const rel of ['AGENTS.md', 'CLAUDE.md', '.gitignore']) {
373
+ if (!exists(rel)) continue;
374
+ const text = read(rel);
375
+ const begins = (text.match(/BEGIN: minimal-vibe-coding-kit/g) || []).length;
376
+ const ends = (text.match(/END: minimal-vibe-coding-kit/g) || []).length;
377
+ if (begins === ends && begins <= 1) ok(`${rel} managed block markers are balanced`);
378
+ else fail(`${rel} has duplicate or unbalanced managed block markers (${begins} begin, ${ends} end)`);
379
+ }
380
+
381
+ const riskyPatterns = [
382
+ { pattern: 'Bash' + '(*)', message: 'unrestricted Bash permission marker' },
383
+ { pattern: 'curl' + ' | sh', message: 'curl pipe to shell marker' },
384
+ { pattern: 'wget' + ' | sh', message: 'wget pipe to shell marker' },
385
+ { pattern: 'ignore previous' + ' instructions', message: 'prompt injection phrase' }
386
+ ];
387
+
388
+ const scanDirs = ['.claude', '.cursor', '.agents', '.codex-plugin', 'skills', '.vbkit-commands', '.vbkit-scripts', 'AGENTS.md', 'CLAUDE-template.md'];
389
+ function walk(item) {
390
+ const p = path.join(root, item);
391
+ if (!fs.existsSync(p)) return [];
392
+ const stat = fs.statSync(p);
393
+ if (stat.isFile()) return [p];
394
+ const out = [];
395
+ for (const entry of fs.readdirSync(p, { withFileTypes: true })) {
396
+ const child = path.join(p, entry.name);
397
+ if (entry.isDirectory()) out.push(...walk(path.relative(root, child)));
398
+ else out.push(child);
399
+ }
400
+ return out;
401
+ }
402
+
403
+ for (const file of scanDirs.flatMap(walk)) {
404
+ if (!/\.(md|mdc|json|toml|yml|yaml|js|mjs|py|sh)$/i.test(file)) continue;
405
+ const text = fs.readFileSync(file, 'utf8');
406
+ for (const r of riskyPatterns) {
407
+ if (text.includes(r.pattern)) warn(`${path.relative(root, file)} contains ${r.message}`);
408
+ }
409
+ }
410
+
411
+ const probe = path.join(root, '.vbkit-scripts/agentshield-probe.mjs');
412
+ if (fs.existsSync(probe)) {
413
+ const result = spawnSync(process.execPath, [probe, root, '--json'], { encoding: 'utf8' });
414
+ if (result.status === 0) ok('AgentShield repo probe runs');
415
+ else warn(`AgentShield probe did not run: ${result.stderr || result.stdout}`);
416
+ }
417
+
418
+ console.log(`\nValidation summary: ${failures} failures, ${warnings} warnings.`);
419
+ process.exit(failures ? 1 : 0);
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env node
2
+ // Graduate a consumer project: move one-time bootstrap files into a cleanup
3
+ // folder once init and the first prompt are complete. Safe, idempotent, and
4
+ // reversible. Refuses to run on the kit source repo so it never deletes the
5
+ // kit's own bootstrap files (and never breaks .vbkit-scripts/validate-kit.mjs).
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+
9
+ const args = process.argv.slice(2);
10
+ const target = path.resolve(args.find((a) => !a.startsWith('--')) || process.cwd());
11
+ const shouldWrite = args.includes('--write');
12
+ const yes = args.includes('--yes');
13
+ const restore = args.includes('--restore');
14
+ const json = args.includes('--json');
15
+
16
+ const DEFAULTS = {
17
+ cleanupDir: '_vibekit-cleanup',
18
+ marker: '.vibekit/FINALIZE_DONE',
19
+ // CLAUDE-template.md is only graduated once CLAUDE.md exists (see below).
20
+ oneTimeFiles: ['FIRST_TIME_INIT.md', 'FIRST_PROMPT.md', 'PUSH_TO_GITHUB.md', 'CLAUDE-template.md']
21
+ };
22
+
23
+ function exists(rel) { return fs.existsSync(path.join(target, rel)); }
24
+ function read(rel) { return fs.readFileSync(path.join(target, rel), 'utf8'); }
25
+ function readJson(rel) { try { return JSON.parse(read(rel)); } catch { return null; } }
26
+
27
+ function backboneValue(text, key) {
28
+ const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
29
+ const match = text.match(new RegExp(`^\\s*${escaped}:\\s*(.+?)\\s*$`, 'm'));
30
+ return match ? match[1].replace(/^["']|["']$/g, '') : null;
31
+ }
32
+
33
+ function backboneList(text, key) {
34
+ const lines = text.split(/\r?\n/);
35
+ const idx = lines.findIndex((line) => line.match(new RegExp(`^\\s*${key}:`)));
36
+ if (idx < 0) return null;
37
+ const inline = lines[idx].split(':').slice(1).join(':').trim();
38
+ if (inline.startsWith('[') && inline.endsWith(']')) {
39
+ return inline.slice(1, -1).split(',').map((x) => x.trim().replace(/^["']|["']$/g, '')).filter(Boolean);
40
+ }
41
+ const indent = lines[idx].match(/^\s*/)[0].length;
42
+ const out = [];
43
+ for (const line of lines.slice(idx + 1)) {
44
+ if (!line.trim()) continue;
45
+ if (line.match(/^\s*/)[0].length <= indent) break;
46
+ const item = line.match(/^\s*-\s+(.+?)\s*$/);
47
+ if (item) out.push(item[1].replace(/^["']|["']$/g, ''));
48
+ }
49
+ return out.length ? out : null;
50
+ }
51
+
52
+ function loadConfig() {
53
+ const cfg = { ...DEFAULTS };
54
+ if (!exists('backbone.yml')) return cfg;
55
+ const text = read('backbone.yml');
56
+ cfg.cleanupDir = backboneValue(text, 'cleanup_dir') || cfg.cleanupDir;
57
+ cfg.marker = backboneValue(text, 'marker') || cfg.marker;
58
+ cfg.oneTimeFiles = backboneList(text, 'one_time_files') || cfg.oneTimeFiles;
59
+ return cfg;
60
+ }
61
+
62
+ function fail(message) {
63
+ if (json) console.log(JSON.stringify({ status: 'error', error: message }, null, 2));
64
+ else console.error(`Refusing: ${message}`);
65
+ process.exit(1);
66
+ }
67
+
68
+ const pkg = readJson('package.json');
69
+ if (pkg?.name === 'minimal-vibe-coding-kit') {
70
+ fail('this is the Minimal Vibe Coding Kit source repo. Graduation only runs in a consumer project.');
71
+ }
72
+ if (!exists('backbone.yml')) fail('backbone.yml is missing. Install the kit first.');
73
+ const status = backboneValue(read('backbone.yml'), 'template_status');
74
+ if (status !== 'initialized' && !restore) {
75
+ fail(`backbone.yml template_status is "${status || 'unknown'}". Run init (FIRST_TIME_INIT.md) before graduating.`);
76
+ }
77
+
78
+ const cfg = loadConfig();
79
+ const cleanupRoot = path.join(target, cfg.cleanupDir);
80
+ const markerPath = path.join(target, cfg.marker);
81
+
82
+ function graduateFile(rel) {
83
+ if (rel === 'CLAUDE-template.md' && !exists('CLAUDE.md')) return false;
84
+ return exists(rel);
85
+ }
86
+
87
+ // --- restore mode -----------------------------------------------------------
88
+ if (restore) {
89
+ if (!fs.existsSync(cleanupRoot)) fail(`no ${cfg.cleanupDir}/ folder to restore from.`);
90
+ const moved = [];
91
+ for (const entry of fs.readdirSync(cleanupRoot)) {
92
+ if (entry === 'RESTORE.md') continue;
93
+ const from = path.join(cleanupRoot, entry);
94
+ const to = path.join(target, entry);
95
+ if (shouldWrite) {
96
+ if (fs.existsSync(to)) { console.error(`Skip ${entry}: already exists at root.`); continue; }
97
+ fs.renameSync(from, to);
98
+ }
99
+ moved.push(entry);
100
+ }
101
+ if (shouldWrite) {
102
+ fs.rmSync(path.join(cleanupRoot, 'RESTORE.md'), { force: true });
103
+ if (fs.readdirSync(cleanupRoot).length === 0) fs.rmdirSync(cleanupRoot);
104
+ fs.rmSync(markerPath, { force: true });
105
+ }
106
+ const result = { status: shouldWrite ? 'restored' : 'restore-preview', restored: moved };
107
+ if (json) console.log(JSON.stringify(result, null, 2));
108
+ else {
109
+ console.log(shouldWrite ? 'Restored one-time files to repo root:' : 'Would restore one-time files:');
110
+ for (const m of moved) console.log(`- ${m}`);
111
+ if (!shouldWrite) console.log('\nRun with --write to apply.');
112
+ }
113
+ process.exit(0);
114
+ }
115
+
116
+ // --- already finalized ------------------------------------------------------
117
+ if (fs.existsSync(markerPath)) {
118
+ const result = { status: 'already-finalized', cleanupDir: cfg.cleanupDir, marker: cfg.marker };
119
+ if (json) console.log(JSON.stringify(result, null, 2));
120
+ else console.log(`Already graduated. One-time files live in ${cfg.cleanupDir}/. Remove that folder when ready, or run --restore to undo.`);
121
+ process.exit(0);
122
+ }
123
+
124
+ const planned = cfg.oneTimeFiles.filter(graduateFile);
125
+
126
+ // --- propose (default) ------------------------------------------------------
127
+ if (!shouldWrite) {
128
+ const result = { status: 'preview', cleanupDir: cfg.cleanupDir, willMove: planned };
129
+ if (json) console.log(JSON.stringify(result, null, 2));
130
+ else {
131
+ console.log(`Graduation preview for ${target}`);
132
+ console.log(`These one-time bootstrap files would move into ${cfg.cleanupDir}/ (then you delete that folder):`);
133
+ for (const f of planned) console.log(`- ${f}`);
134
+ if (!planned.length) console.log('- (none found; nothing to graduate)');
135
+ console.log(`\nApply with: node .vbkit-scripts/vibekit-finalize.mjs ${args[0] && !args[0].startsWith('--') ? args[0] : '.'} --write --yes`);
136
+ console.log('Undo later with: --restore --write');
137
+ }
138
+ process.exit(0);
139
+ }
140
+
141
+ // --- write ------------------------------------------------------------------
142
+ if (!yes) fail('refusing to write without --yes. Preview first, then re-run with --write --yes.');
143
+ if (!planned.length) {
144
+ if (json) console.log(JSON.stringify({ status: 'noop', moved: [] }, null, 2));
145
+ else console.log('Nothing to graduate; no one-time files found.');
146
+ process.exit(0);
147
+ }
148
+
149
+ fs.mkdirSync(cleanupRoot, { recursive: true });
150
+ const moved = [];
151
+ for (const rel of planned) {
152
+ fs.renameSync(path.join(target, rel), path.join(cleanupRoot, rel));
153
+ moved.push(rel);
154
+ }
155
+
156
+ const restoreDoc = `# Safe to delete
157
+
158
+ These files were one-time setup helpers for Minimal Vibe Coding Kit. Init and the
159
+ first prompt are complete, so they are no longer needed in this project.
160
+
161
+ Graduated files:
162
+ ${moved.map((m) => `- ${m}`).join('\n')}
163
+
164
+ ## Options
165
+
166
+ - Delete this whole \`${cfg.cleanupDir}/\` folder when you are happy with the setup.
167
+ - Or restore everything to the repo root:
168
+
169
+ \`\`\`bash
170
+ node .vbkit-scripts/vibekit-finalize.mjs . --restore --write
171
+ \`\`\`
172
+
173
+ The durable project map is \`backbone.yml\`; you do not need these files to keep working.
174
+ `;
175
+ fs.writeFileSync(path.join(cleanupRoot, 'RESTORE.md'), restoreDoc);
176
+ fs.mkdirSync(path.dirname(markerPath), { recursive: true });
177
+ fs.writeFileSync(markerPath, `finalized_at: ${new Date().toISOString()}\ncleanup_dir: ${cfg.cleanupDir}\nmoved: ${moved.length}\n`);
178
+
179
+ const result = { status: 'finalized', cleanupDir: cfg.cleanupDir, moved };
180
+ if (json) console.log(JSON.stringify(result, null, 2));
181
+ else {
182
+ console.log(`Graduated ${moved.length} one-time file(s) into ${cfg.cleanupDir}/:`);
183
+ for (const m of moved) console.log(`- ${m}`);
184
+ console.log(`\nReview ${cfg.cleanupDir}/RESTORE.md, then delete the folder when ready. Undo with --restore --write.`);
185
+ }
package/AGENTS.md ADDED
@@ -0,0 +1,60 @@
1
+ # AGENTS.md
2
+
3
+ Shared instructions for Claude, Cursor, Codex, and other coding agents.
4
+
5
+ <!-- BEGIN: minimal-vibe-coding-kit -->
6
+ ## Minimal Vibe Coding Kit
7
+
8
+ ### Source of truth
9
+
10
+ - Read `backbone.yml` before changing code.
11
+ - If `meta.template_status` is `uninitialized`, follow `FIRST_TIME_INIT.md` and wait for approval before writing.
12
+ - After init, follow the `conventions` rules in `backbone.yml`; ask before changing broad project patterns.
13
+ - Prefer concise root instructions. Put long procedures in skills and docs.
14
+
15
+ ### Work style
16
+
17
+ - Start with a short plan for multi-file or risky changes.
18
+ - Prefer small, reviewable diffs.
19
+ - Reuse existing resource, localization, route, config, and generated-definition accessors instead of hardcoding literals when the repo has them.
20
+ - Run the validation command listed in `backbone.yml` after relevant changes.
21
+ - Summarize changed files, validation results, and remaining risks.
22
+
23
+ ### Visual design loop trigger
24
+
25
+ Always use the `visual-design-loop` skill when a Claude skill loop or Codex goal touches UI, visual design, screenshots, rendering, product polish, or visible frontend behavior.
26
+
27
+ Use the current brief as the source of truth. Render the product, capture screenshots, review them visually, make one targeted improvement, and repeat until the design is polished, blocked, or the loop budget is reached.
28
+
29
+ Track every loop in `/tmp/design-{project_slug}.md`. Each loop entry must include screenshot reviewed, issue found, fix applied, before/after judgment, remaining concerns, and stop/continue decision. Default budget is 3 loops unless the user specifies otherwise.
30
+
31
+ ### Safety
32
+
33
+ - Never print full secrets.
34
+ - Do not run untrusted hooks, MCP servers, deploy scripts, package lifecycle scripts, migrations, or destructive shell commands just to inspect a repo.
35
+ - Do not modify protected paths from `backbone.yml` without explicit approval.
36
+ - If a task changes agent surfaces (`CLAUDE.md`, `AGENTS.md`, `.claude/**`, `.cursor/**`, `.agents/**`, `.codex-plugin/**`, `skills/**`, `.vbkit-commands/**`, `.vbkit-scripts/**`, hooks, MCP config), run the AgentShield probe or explain why it was skipped.
37
+
38
+ ### Skills to prefer
39
+
40
+ - `vibekit-init`: first-time init and repair.
41
+ - `autoresearch-coding`: metric-driven experiment loop.
42
+ - `agentshield-security-review`: agent-surface security review.
43
+ - `daily-workflow-curator`: daily proposal for improving rules, skills, workflows, and docs.
44
+ - `visual-design-loop`: screenshot-driven UI polish loop.
45
+
46
+ ### Autoresearch loop contract
47
+
48
+ Use this when improving a repo over repeated experiments:
49
+
50
+ 1. Define goal, metric command, direction, editable paths, protected paths, budget, and timeout.
51
+ 2. Run a baseline before edits.
52
+ 3. Change only editable paths.
53
+ 4. Log every experiment.
54
+ 5. Keep only changes that improve the metric or simplify without regression.
55
+ 6. Discard or revert failed experiments.
56
+
57
+ ### Daily enhance contract
58
+
59
+ Daily enhancement must propose changes, not silently apply them. The expected output is a report plus a diff proposal for user approval.
60
+ <!-- END: minimal-vibe-coding-kit -->