minimal-vibe-coding-kit 0.3.0 → 0.4.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.
- package/.agents/skills/agentshield-security-review/SKILL.md +6 -6
- package/.agents/skills/agentshield-security-review/references/native-install.md +10 -10
- package/.agents/skills/agentshield-security-review/references/report-template.md +1 -1
- package/.agents/skills/agentshield-security-review/scripts/agentshield_repo_probe.py +3 -3
- package/.agents/skills/autoresearch-coding/README.md +1 -1
- package/.agents/skills/autoresearch-coding/SKILL.md +4 -4
- package/.agents/skills/daily-workflow-curator/SKILL.md +3 -3
- package/.agents/skills/parallel-analysis/SKILL.md +160 -0
- package/.agents/skills/path-sensitive-shell-safety/SKILL.md +68 -0
- package/.agents/skills/path-sensitive-shell-safety/references/workflow.md +127 -0
- package/.agents/skills/vibekit-init/SKILL.md +6 -6
- package/.claude/commands/vibe-finalize.md +1 -1
- package/.claude/rules/security.md +2 -0
- package/.claude/rules/tooling.md +1 -1
- package/.claude/skills/agentshield-security-review/SKILL.md +6 -6
- package/.claude/skills/agentshield-security-review/references/native-install.md +10 -10
- package/.claude/skills/agentshield-security-review/references/report-template.md +1 -1
- package/.claude/skills/agentshield-security-review/scripts/agentshield_repo_probe.py +3 -3
- package/.claude/skills/autoresearch-coding/README.md +1 -1
- package/.claude/skills/autoresearch-coding/SKILL.md +4 -4
- package/.claude/skills/daily-workflow-curator/SKILL.md +3 -3
- package/.claude/skills/parallel-analysis/SKILL.md +160 -0
- package/.claude/skills/path-sensitive-shell-safety/SKILL.md +68 -0
- package/.claude/skills/path-sensitive-shell-safety/references/workflow.md +127 -0
- package/.claude/skills/vibekit-init/SKILL.md +6 -6
- package/.codex-plugin/plugin.json +2 -2
- package/.cursor/commands/vibe-finalize.md +1 -1
- package/.cursor/rules/001-vibe-core.mdc +1 -1
- package/.cursor/rules/010-init.mdc +1 -1
- package/.cursor/rules/020-security-agentshield.mdc +2 -2
- package/.cursor/rules/030-autoresearch-loop.mdc +1 -1
- package/.cursor/skills/parallel-analysis/SKILL.md +160 -0
- package/.cursor/skills/path-sensitive-shell-safety/SKILL.md +68 -0
- package/.cursor/skills/path-sensitive-shell-safety/references/workflow.md +127 -0
- package/.vibekit/commands/vibe-finalize.md +3 -0
- package/{.vbkit-docs → .vibekit/docs}/AUTORESEARCH_LEDGER.md +3 -3
- package/{.vbkit-docs → .vibekit/docs}/BACKBONE_REFERENCE.md +1 -1
- package/{.vbkit-docs → .vibekit/docs}/INSTALL.md +16 -16
- package/{.vbkit-docs → .vibekit/docs}/RESEARCH_NOTES.md +1 -1
- package/{.vbkit-docs → .vibekit/docs}/SECURITY_MODEL.md +2 -2
- package/{.vbkit-docs → .vibekit/docs}/TOOLING_GUIDE.md +2 -2
- package/{.vbkit-docs → .vibekit/docs}/templates/CONTEXT_TEMPLATE.md +1 -1
- package/{.vbkit-docs → .vibekit/docs}/templates/PRD_TEMPLATE.md +1 -1
- package/{CLAUDE-template.md → .vibekit/init/CLAUDE-template.md} +1 -1
- package/{FIRST_PROMPT.md → .vibekit/init/FIRST_PROMPT.md} +6 -6
- package/{FIRST_TIME_INIT.md → .vibekit/init/FIRST_TIME_INIT.md} +14 -14
- package/{.vbkit-scripts → .vibekit/scripts}/agentshield-probe.mjs +1 -1
- package/{.vbkit-scripts → .vibekit/scripts}/daily-enhance.mjs +3 -3
- package/{.vbkit-scripts → .vibekit/scripts}/doctor.mjs +6 -6
- package/{.vbkit-scripts → .vibekit/scripts}/init-backbone.mjs +22 -22
- package/{.vbkit-scripts → .vibekit/scripts}/mvck.mjs +61 -25
- package/{.vbkit-scripts → .vibekit/scripts}/test-install.mjs +32 -18
- package/{.vbkit-scripts → .vibekit/scripts}/validate-kit.mjs +47 -31
- package/{.vbkit-scripts → .vibekit/scripts}/vibekit-finalize.mjs +7 -7
- package/{skills → .vibekit/skills}/agentshield-security-review/SKILL.md +6 -6
- package/{skills → .vibekit/skills}/agentshield-security-review/references/native-install.md +10 -10
- package/{skills → .vibekit/skills}/agentshield-security-review/references/report-template.md +1 -1
- package/{skills → .vibekit/skills}/agentshield-security-review/scripts/agentshield_repo_probe.py +3 -3
- package/{skills → .vibekit/skills}/autoresearch-coding/README.md +1 -1
- package/{skills → .vibekit/skills}/autoresearch-coding/SKILL.md +4 -4
- package/{skills → .vibekit/skills}/daily-workflow-curator/SKILL.md +3 -3
- package/.vibekit/skills/parallel-analysis/SKILL.md +160 -0
- package/.vibekit/skills/path-sensitive-shell-safety/SKILL.md +68 -0
- package/.vibekit/skills/path-sensitive-shell-safety/references/workflow.md +127 -0
- package/{skills → .vibekit/skills}/vibekit-init/SKILL.md +6 -6
- package/AGENTS.md +5 -2
- package/CHANGELOG.md +13 -2
- package/CONTRIBUTING.md +3 -3
- package/README.md +133 -394
- package/README.vi.md +135 -334
- package/backbone.yml +8 -7
- package/bin/mvck.js +1 -1
- package/bin/vibe-kit.js +1 -1
- package/install.ps1 +1 -1
- package/install.sh +5 -3
- package/package.json +22 -18
- package/.vbkit-commands/vibe-finalize.md +0 -3
- /package/{.vbkit-commands → .vibekit/commands}/autoresearch-coding.md +0 -0
- /package/{.vbkit-commands → .vibekit/commands}/council.md +0 -0
- /package/{.vbkit-commands → .vibekit/commands}/daily-enhance.md +0 -0
- /package/{.vbkit-commands → .vibekit/commands}/init-vibe.md +0 -0
- /package/{.vbkit-commands → .vibekit/commands}/security-scan.md +0 -0
- /package/{.vbkit-docs → .vibekit/docs}/backbone.schema.json +0 -0
- /package/{.vbkit-scripts → .vibekit/scripts}/pack-dry-run.mjs +0 -0
- /package/{skills → .vibekit/skills}/agentshield-security-review/agents/openai.yaml +0 -0
- /package/{skills → .vibekit/skills}/agentshield-security-review/references/review-checklist.md +0 -0
- /package/{skills → .vibekit/skills}/autoresearch-coding/references/experiment-contract.md +0 -0
- /package/{skills → .vibekit/skills}/autoresearch-coding/references/metric-extraction.md +0 -0
- /package/{skills → .vibekit/skills}/autoresearch-coding/references/result-ledger.md +0 -0
- /package/{skills → .vibekit/skills}/autoresearch-coding/scripts/log_result.py +0 -0
- /package/{skills → .vibekit/skills}/autoresearch-coding/scripts/run_logged.py +0 -0
- /package/{skills → .vibekit/skills}/clearthought/SKILL.md +0 -0
- /package/{skills → .vibekit/skills}/clearthought/examples/decision-framework.md +0 -0
- /package/{skills → .vibekit/skills}/clearthought/examples/metagame-examples.md +0 -0
- /package/{skills → .vibekit/skills}/clearthought/examples/sequential-thinking.md +0 -0
- /package/{skills → .vibekit/skills}/clearthought/references/output-schemas.md +0 -0
- /package/{skills → .vibekit/skills}/clearthought/references/parameter-reference.md +0 -0
- /package/{skills → .vibekit/skills}/coding-level/SKILL.md +0 -0
- /package/{skills → .vibekit/skills}/coding-level/references/level-0.md +0 -0
- /package/{skills → .vibekit/skills}/coding-level/references/level-1.md +0 -0
- /package/{skills → .vibekit/skills}/coding-level/references/level-2.md +0 -0
- /package/{skills → .vibekit/skills}/coding-level/references/level-3.md +0 -0
- /package/{skills → .vibekit/skills}/coding-level/references/level-4.md +0 -0
- /package/{skills → .vibekit/skills}/coding-level/references/level-5.md +0 -0
- /package/{skills → .vibekit/skills}/memento/SKILL.md +0 -0
- /package/{skills → .vibekit/skills}/reviewing-4p-priorities/SKILL.md +0 -0
- /package/{skills → .vibekit/skills}/reviewing-4p-priorities/examples.md +0 -0
- /package/{skills → .vibekit/skills}/sequential-thinking/SKILL.md +0 -0
- /package/{skills → .vibekit/skills}/sequential-thinking/examples/adaptive-depth.md +0 -0
- /package/{skills → .vibekit/skills}/sequential-thinking/examples/branching-exploration.md +0 -0
- /package/{skills → .vibekit/skills}/sequential-thinking/examples/linear-reasoning.md +0 -0
- /package/{skills → .vibekit/skills}/sequential-thinking/examples/revision-pattern.md +0 -0
- /package/{skills → .vibekit/skills}/sequential-thinking/references/output-schema.md +0 -0
- /package/{skills → .vibekit/skills}/sequential-thinking/references/parameters.md +0 -0
- /package/{skills → .vibekit/skills}/sequential-thinking/references/patterns.md +0 -0
- /package/{skills → .vibekit/skills}/visual-design-loop/SKILL.md +0 -0
- /package/{skills → .vibekit/skills}/visual-design-loop/agents/openai.yaml +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# FIRST_TIME_INIT.md - bootstrap runbook
|
|
1
|
+
# .vibekit/init/FIRST_TIME_INIT.md - bootstrap runbook
|
|
2
2
|
|
|
3
3
|
Audience: Claude, Cursor, Codex, or any AI coding agent in a repo that just received Minimal Vibe Coding Kit.
|
|
4
4
|
|
|
5
|
-
Keep this flow short. Detailed schema notes live in `.
|
|
5
|
+
Keep this flow short. Detailed schema notes live in `.vibekit/docs/BACKBONE_REFERENCE.md`.
|
|
6
6
|
|
|
7
7
|
## Requirements to print before starting
|
|
8
8
|
|
|
@@ -10,17 +10,17 @@ Before writing anything, print this checklist and mark each item as found, missi
|
|
|
10
10
|
|
|
11
11
|
1. `backbone.yml` exists.
|
|
12
12
|
2. `AGENTS.md` exists or will be created/merged.
|
|
13
|
-
3. `CLAUDE.md` exists or will be created from
|
|
13
|
+
3. `CLAUDE.md` exists or will be created from `.vibekit/init/CLAUDE-template.md` when Claude support is installed.
|
|
14
14
|
4. At least one harness folder exists: `.claude/`, `.cursor/`, `.agents/`, or `.codex-plugin/`.
|
|
15
15
|
5. Git status is known. If user changes exist, do not overwrite them.
|
|
16
|
-
6. A validation command is inferred or set to `node .
|
|
16
|
+
6. A validation command is inferred or set to `node .vibekit/scripts/validate-kit.mjs .` for the kit itself.
|
|
17
17
|
7. Protected paths include `.env*`, secrets, lockfiles, generated files, build output, migrations, and infra unless the user says otherwise.
|
|
18
18
|
8. Existing naming, architecture, resource, and localization conventions are scanned or marked missing.
|
|
19
19
|
|
|
20
20
|
## Canonical prompt
|
|
21
21
|
|
|
22
22
|
```text
|
|
23
|
-
Read FIRST_TIME_INIT.md and initialize this repo with Minimal Vibe Coding Kit.
|
|
23
|
+
Read .vibekit/init/FIRST_TIME_INIT.md and initialize this repo with Minimal Vibe Coding Kit.
|
|
24
24
|
First print the requirements you will check. Then run detection, propose one diff for backbone.yml and managed instruction blocks, and wait for my yes before writing.
|
|
25
25
|
Include inferred project conventions for naming, architecture, resources, localization, generated definitions, and per-app/package differences.
|
|
26
26
|
After approval, write the files, run validation, and summarize what changed.
|
|
@@ -64,9 +64,9 @@ Ask (keep it short):
|
|
|
64
64
|
|
|
65
65
|
Then:
|
|
66
66
|
|
|
67
|
-
- If `project.prd` is `none`, propose creating `.
|
|
67
|
+
- If `project.prd` is `none`, propose creating `.vibekit/docs/PRD.md` from `.vibekit/docs/templates/PRD_TEMPLATE.md` using the answers, and set `project.prd` to that path in the same diff.
|
|
68
68
|
- If a PRD already exists, read it, link it in `project.prd`, and offer to refresh it without overwriting unapproved content.
|
|
69
|
-
- Record domain terms and acronyms in `.
|
|
69
|
+
- Record domain terms and acronyms in `.vibekit/docs/CONTEXT.md` (scaffold from `.vibekit/docs/templates/CONTEXT_TEMPLATE.md`) and link it in `project.context`, so future agents stay concise.
|
|
70
70
|
- Keep the PRD short: it captures intent and focus, not a full specification.
|
|
71
71
|
|
|
72
72
|
## FIRST_TIME_INIT_RULES
|
|
@@ -85,7 +85,7 @@ Create project rules from evidence in the existing repo, not from a fixed langua
|
|
|
85
85
|
Optional helper:
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
|
-
node .
|
|
88
|
+
node .vibekit/scripts/init-backbone.mjs . --propose
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
## Propose before writing
|
|
@@ -117,14 +117,14 @@ Apply this proposed backbone and convention rules? Reply yes, edit, or abort.
|
|
|
117
117
|
CLI helper after approval:
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
|
-
node .
|
|
120
|
+
node .vibekit/scripts/init-backbone.mjs . --write --yes
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
## Merge rules
|
|
124
124
|
|
|
125
125
|
### CLAUDE.md
|
|
126
126
|
|
|
127
|
-
- If no `CLAUDE.md` exists, copy
|
|
127
|
+
- If no `CLAUDE.md` exists, copy `.vibekit/init/CLAUDE-template.md` to `CLAUDE.md`.
|
|
128
128
|
- If `CLAUDE.md` exists, append or replace only this managed block:
|
|
129
129
|
|
|
130
130
|
```markdown
|
|
@@ -134,7 +134,7 @@ node .vbkit-scripts/init-backbone.mjs . --write --yes
|
|
|
134
134
|
## Minimal Vibe Coding Kit
|
|
135
135
|
|
|
136
136
|
- Read `backbone.yml` before changing code.
|
|
137
|
-
- If `meta.template_status` is `uninitialized`, follow
|
|
137
|
+
- If `meta.template_status` is `uninitialized`, follow `.vibekit/init/FIRST_TIME_INIT.md` and wait for approval before writing.
|
|
138
138
|
- After init, follow `backbone.yml` `conventions` before adding new project patterns.
|
|
139
139
|
- Prefer project skills for multi-step workflows: `/autoresearch-coding`, `/security-scan`, `/daily-enhance`.
|
|
140
140
|
<!-- END: minimal-vibe-coding-kit -->
|
|
@@ -150,10 +150,10 @@ node .vbkit-scripts/init-backbone.mjs . --write --yes
|
|
|
150
150
|
|
|
151
151
|
Once init is `initialized` and the first prompt is complete, the bootstrap files are no longer needed in the project. Offer to graduate them so the repo stays clean.
|
|
152
152
|
|
|
153
|
-
- Preview: `node .
|
|
154
|
-
- Apply after the user agrees: `node .
|
|
153
|
+
- Preview: `node .vibekit/scripts/vibekit-finalize.mjs . --propose`
|
|
154
|
+
- Apply after the user agrees: `node .vibekit/scripts/vibekit-finalize.mjs . --write --yes`
|
|
155
155
|
|
|
156
|
-
This moves one-time files (
|
|
156
|
+
This moves one-time files (`.vibekit/init/FIRST_TIME_INIT.md`, `.vibekit/init/FIRST_PROMPT.md`, `.vibekit/init/PUSH_TO_GITHUB.md`, `.vibekit/init/CLAUDE-template.md` once `CLAUDE.md` exists) into the folder named by `automation.finalize.cleanup_dir` (default `_vibekit-cleanup/`), writes a `RESTORE.md`, and sets `automation.finalize.marker`. It is idempotent, reversible with `--restore --write`, and refuses to run on the kit source repo. The durable project map is `backbone.yml`; none of the graduated files are needed to keep working. Delete the cleanup folder when satisfied.
|
|
157
157
|
|
|
158
158
|
## Guardrails
|
|
159
159
|
|
|
@@ -5,7 +5,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
5
5
|
|
|
6
6
|
const target = path.resolve(process.argv[2] || process.cwd());
|
|
7
7
|
const extra = process.argv.slice(3);
|
|
8
|
-
const probe = path.join(target, 'skills/agentshield-security-review/scripts/agentshield_repo_probe.py');
|
|
8
|
+
const probe = path.join(target, '.vibekit/skills/agentshield-security-review/scripts/agentshield_repo_probe.py');
|
|
9
9
|
|
|
10
10
|
if (!fs.existsSync(probe)) {
|
|
11
11
|
console.error(`AgentShield probe not found: ${path.relative(target, probe)}`);
|
|
@@ -25,17 +25,17 @@ function list(dir) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const checks = [];
|
|
28
|
-
for (const rel of ['backbone.yml', 'AGENTS.md', 'FIRST_TIME_INIT.md', 'skills/autoresearch-coding/SKILL.md', 'skills/agentshield-security-review/SKILL.md']) {
|
|
28
|
+
for (const rel of ['backbone.yml', 'AGENTS.md', '.vibekit/init/FIRST_TIME_INIT.md', '.vibekit/skills/autoresearch-coding/SKILL.md', '.vibekit/skills/agentshield-security-review/SKILL.md']) {
|
|
29
29
|
checks.push(`- ${rel}: ${exists(rel) ? 'found' : 'missing'}`);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const skills = list('skills').filter((f) => f.endsWith('SKILL.md'));
|
|
32
|
+
const skills = list('.vibekit/skills').filter((f) => f.endsWith('SKILL.md'));
|
|
33
33
|
const claudeSkills = list('.claude/skills').filter((f) => f.endsWith('SKILL.md'));
|
|
34
34
|
const codexSkills = list('.agents/skills').filter((f) => f.endsWith('SKILL.md'));
|
|
35
35
|
const cursorRules = list('.cursor/rules').filter((f) => f.endsWith('.mdc'));
|
|
36
36
|
|
|
37
37
|
let validation = 'not run';
|
|
38
|
-
const validator = path.join(target, '.
|
|
38
|
+
const validator = path.join(target, '.vibekit/scripts/validate-kit.mjs');
|
|
39
39
|
if (fs.existsSync(validator)) {
|
|
40
40
|
const result = spawnSync(process.execPath, [validator, target], { encoding: 'utf8' });
|
|
41
41
|
validation = result.stdout.trim() || result.stderr.trim() || `exit ${result.status}`;
|
|
@@ -122,7 +122,7 @@ function runNodeScript(rel, extra = []) {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
function runProbe() {
|
|
125
|
-
const nodeProbeRel = '.
|
|
125
|
+
const nodeProbeRel = '.vibekit/scripts/agentshield-probe.mjs';
|
|
126
126
|
const nodeProbe = path.join(target, nodeProbeRel);
|
|
127
127
|
if (fs.existsSync(nodeProbe)) {
|
|
128
128
|
const result = spawnSync(process.execPath, [nodeProbe, target, '--json'], { encoding: 'utf8' });
|
|
@@ -134,7 +134,7 @@ function runProbe() {
|
|
|
134
134
|
};
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
const probe = path.join(target, 'skills/agentshield-security-review/scripts/agentshield_repo_probe.py');
|
|
137
|
+
const probe = path.join(target, '.vibekit/skills/agentshield-security-review/scripts/agentshield_repo_probe.py');
|
|
138
138
|
if (!fs.existsSync(probe)) return { found: false, status: null, output: 'missing' };
|
|
139
139
|
for (const python of ['python', 'python3']) {
|
|
140
140
|
const result = spawnSync(python, [probe, target, '--json'], { encoding: 'utf8' });
|
|
@@ -161,7 +161,7 @@ const kitVersion = isKitTemplate
|
|
|
161
161
|
: exists('.vibekit/KIT_VERSION') ? read('.vibekit/KIT_VERSION').trim() : 'unknown';
|
|
162
162
|
const surfaces = {
|
|
163
163
|
agents: exists('AGENTS.md'),
|
|
164
|
-
claude: exists('CLAUDE.md') || exists('CLAUDE-template.md') || exists('.claude'),
|
|
164
|
+
claude: exists('CLAUDE.md') || exists('.vibekit/init/CLAUDE-template.md') || exists('.claude'),
|
|
165
165
|
cursor: exists('.cursor/rules'),
|
|
166
166
|
codex: exists('.agents') || exists('.codex-plugin/plugin.json')
|
|
167
167
|
};
|
|
@@ -180,7 +180,7 @@ const legacySurfaces = [
|
|
|
180
180
|
].filter(exists);
|
|
181
181
|
const nativeReasoningSkills = ['clearthought', 'sequential-thinking', 'reviewing-4p-priorities'];
|
|
182
182
|
const nativeSkillSurfaces = {
|
|
183
|
-
shared: 'skills',
|
|
183
|
+
shared: '.vibekit/skills',
|
|
184
184
|
claude: '.claude/skills',
|
|
185
185
|
codex: '.agents/skills',
|
|
186
186
|
cursor: '.cursor/skills'
|
|
@@ -192,7 +192,7 @@ for (const [surface, dir] of Object.entries(nativeSkillSurfaces)) {
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
const commands = commandMap();
|
|
195
|
-
const validation = runNodeScript('.
|
|
195
|
+
const validation = runNodeScript('.vibekit/scripts/validate-kit.mjs');
|
|
196
196
|
const probe = runProbe();
|
|
197
197
|
const risks = [];
|
|
198
198
|
|
|
@@ -239,7 +239,7 @@ const report = {
|
|
|
239
239
|
status: probe.status
|
|
240
240
|
},
|
|
241
241
|
aiRulesLoaded: {
|
|
242
|
-
sharedSkills: listFiles('skills').filter((f) => f.endsWith('SKILL.md')).length,
|
|
242
|
+
sharedSkills: listFiles('.vibekit/skills').filter((f) => f.endsWith('SKILL.md')).length,
|
|
243
243
|
claudeSkills: listFiles('.claude/skills').filter((f) => f.endsWith('SKILL.md')).length,
|
|
244
244
|
codexSkills: listFiles('.agents/skills').filter((f) => f.endsWith('SKILL.md')).length,
|
|
245
245
|
cursorSkills: listFiles('.cursor/skills').filter((f) => f.endsWith('SKILL.md')).length,
|
|
@@ -92,22 +92,22 @@ function cleanName(name) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
function isKitManagedPath(file) {
|
|
95
|
-
const managedRoots = new Set(['.claude', '.cursor', '.agents', '.codex', '.codex-plugin', '
|
|
95
|
+
const managedRoots = new Set(['.claude', '.cursor', '.agents', '.codex', '.codex-plugin', '.vibekit']);
|
|
96
96
|
const managedFiles = new Set([
|
|
97
97
|
'AGENTS.md',
|
|
98
|
-
'CLAUDE-template.md',
|
|
99
|
-
'FIRST_PROMPT.md',
|
|
100
|
-
'FIRST_TIME_INIT.md',
|
|
98
|
+
'.vibekit/init/CLAUDE-template.md',
|
|
99
|
+
'.vibekit/init/FIRST_PROMPT.md',
|
|
100
|
+
'.vibekit/init/FIRST_TIME_INIT.md',
|
|
101
101
|
'backbone.yml',
|
|
102
|
-
'.
|
|
103
|
-
'.
|
|
104
|
-
'.
|
|
105
|
-
'.
|
|
106
|
-
'.
|
|
107
|
-
'.
|
|
108
|
-
'.
|
|
109
|
-
'.
|
|
110
|
-
'.
|
|
102
|
+
'.vibekit/scripts/mvck.mjs',
|
|
103
|
+
'.vibekit/scripts/init-backbone.mjs',
|
|
104
|
+
'.vibekit/scripts/daily-enhance.mjs',
|
|
105
|
+
'.vibekit/scripts/validate-kit.mjs',
|
|
106
|
+
'.vibekit/scripts/doctor.mjs',
|
|
107
|
+
'.vibekit/scripts/test-install.mjs',
|
|
108
|
+
'.vibekit/scripts/agentshield-probe.mjs',
|
|
109
|
+
'.vibekit/scripts/pack-dry-run.mjs',
|
|
110
|
+
'.vibekit/scripts/vibekit-finalize.mjs'
|
|
111
111
|
]);
|
|
112
112
|
const root = file.split('/')[0];
|
|
113
113
|
return managedRoots.has(root) || managedFiles.has(file);
|
|
@@ -514,10 +514,10 @@ function detectConventions(files, type) {
|
|
|
514
514
|
}
|
|
515
515
|
|
|
516
516
|
const PRD_CANDIDATES = [
|
|
517
|
-
'PRD.md', '.
|
|
518
|
-
'REQUIREMENTS.md', '.
|
|
519
|
-
'SPEC.md', '.
|
|
520
|
-
'PRODUCT.md', '.
|
|
517
|
+
'PRD.md', '.vibekit/docs/PRD.md', 'prd.md', '.vibekit/docs/prd.md',
|
|
518
|
+
'REQUIREMENTS.md', '.vibekit/docs/REQUIREMENTS.md',
|
|
519
|
+
'SPEC.md', '.vibekit/docs/SPEC.md', '.vibekit/docs/spec.md',
|
|
520
|
+
'PRODUCT.md', '.vibekit/docs/PRODUCT.md'
|
|
521
521
|
];
|
|
522
522
|
|
|
523
523
|
function countCodeFiles(files) {
|
|
@@ -538,7 +538,7 @@ function detectPrd(files) {
|
|
|
538
538
|
}
|
|
539
539
|
|
|
540
540
|
function detectContext() {
|
|
541
|
-
for (const candidate of ['.
|
|
541
|
+
for (const candidate of ['.vibekit/docs/CONTEXT.md', 'CONTEXT.md', '.vibekit/docs/context.md']) {
|
|
542
542
|
if (fileExists(candidate)) return candidate;
|
|
543
543
|
}
|
|
544
544
|
return 'none';
|
|
@@ -547,7 +547,7 @@ function detectContext() {
|
|
|
547
547
|
function render(data) {
|
|
548
548
|
const cmd = data.commands;
|
|
549
549
|
const rules = data.conventions;
|
|
550
|
-
return `# Minimal Vibe Coding Kit backbone. See .
|
|
550
|
+
return `# Minimal Vibe Coding Kit backbone. See .vibekit/docs/BACKBONE_REFERENCE.md for details.\nversion: 2\nmeta:\n template_status: initialized\n initialized_at: ${yamlString(data.initializedAt)}\n template_source: minimal-vibe-coding-kit\n schema_version: 3\n init_runbook: .vibekit/init/FIRST_TIME_INIT.md\n init_done_marker: .vibekit/INIT_DONE\n\nproject:\n name: ${yamlString(data.name)}\n description: ${yamlString(data.description)}\n type: ${data.type}\n primary_language: ${data.language}\n package_manager: ${data.packageManager}\n mode: ${data.mode}\n prd: ${yamlString(data.prd)}\n context: ${yamlString(data.context)}\n\npaths:\n root: .\n apps:${yamlList(data.appPaths, 4)}\n source: ${JSON.stringify(data.sourcePaths)}\n tests: ${JSON.stringify(data.testPaths)}\n docs: [README.md, .vibekit/docs/]\n generated: [node_modules/, dist/, build/, coverage/]\n\nconventions:\n review_required_before_write: true\n scope: ${yamlString(rules.scope)}\n naming:\n files: ${yamlString(rules.naming.files)}\n directories: ${yamlString(rules.naming.directories)}\n symbols: follow existing language and framework conventions in nearby code\n evidence:${yamlList(rules.naming.evidence, 6)}\n architecture:\n detected:${yamlList(rules.architecture.detected, 6)}\n rule: ${yamlString(rules.architecture.rule)}\n resources:\n detected_asset_roots:${yamlList(rules.resources.assetRoots, 6)}\n detected_registries:${yamlList(rules.resources.registries, 6)}\n rule: ${yamlString(rules.resources.rule)}\n localization:\n detected_catalogs:${yamlList(rules.localization.catalogs, 6)}\n detected_accessors:${yamlList(rules.localization.accessors, 6)}\n rule: ${yamlString(rules.localization.rule)}\n custom_rules:\n - Add team-specific rules here during init review; future agents must follow them.\n\ncommands:\n install: ${yamlString(cmd.install)}\n test: ${yamlString(cmd.test)}\n lint: ${yamlString(cmd.lint)}\n typecheck: ${yamlString(cmd.typecheck)}\n build: ${yamlString(cmd.build)}\n validate: ${yamlString(cmd.validate)}\n\npolicy:\n default_branch: main\n branch_naming: "feat/<short-topic>"\n commit_style: conventional\n editable_paths: [.]\n protected_paths:\n - .git/\n - .env*\n - "**/*secret*"\n - "**/*token*"\n - "**/migrations/**"\n - "**/node_modules/**"\n - "**/dist/**"\n - "**/build/**"\n - "**/coverage/**"\n - "**/*lock*"\n\nagent_surfaces:\n claude: .claude/\n cursor: .cursor/\n codex: .agents/\n codex_plugin: .codex-plugin/plugin.json\n shared_skills: .vibekit/skills/\n shared_commands: .vibekit/commands/\n\nautomation:\n autoresearch:\n results_file: results.tsv\n logs_dir: .autoresearch/logs\n default_budget: 3\n default_timeout_seconds: 600\n daily_enhance:\n report_dir: .vibekit/reports\n write_mode: propose_only\n finalize:\n cleanup_dir: _vibekit-cleanup\n marker: .vibekit/FINALIZE_DONE\n one_time_files: [.vibekit/init/FIRST_TIME_INIT.md, .vibekit/init/FIRST_PROMPT.md, .vibekit/init/PUSH_TO_GITHUB.md, .vibekit/init/CLAUDE-template.md]\n security:\n probe: node .vibekit/scripts/agentshield-probe.mjs .\n scan: npx ecc-agentshield scan --path . --format text --min-severity medium\n`;
|
|
551
551
|
}
|
|
552
552
|
|
|
553
553
|
function inferPaths(files) {
|
|
@@ -614,15 +614,15 @@ if (shouldWrite) {
|
|
|
614
614
|
console.log('- What are the key constraints or non-goals?');
|
|
615
615
|
if (inferred.mode === 'brownfield') console.log('- Which existing area should we focus on improving first?');
|
|
616
616
|
console.log(inferred.prd === 'none'
|
|
617
|
-
? '- Offer to create .
|
|
617
|
+
? '- Offer to create .vibekit/docs/PRD.md from .vibekit/docs/templates/PRD_TEMPLATE.md using the answers.'
|
|
618
618
|
: `- Offer to refresh ${inferred.prd} with the answers; do not overwrite without approval.`);
|
|
619
619
|
console.log(inferred.context === 'none'
|
|
620
|
-
? '- Offer to create .
|
|
620
|
+
? '- Offer to create .vibekit/docs/CONTEXT.md (glossary) from .vibekit/docs/templates/CONTEXT_TEMPLATE.md.'
|
|
621
621
|
: `- CONTEXT glossary found at ${inferred.context}; keep it current.`);
|
|
622
622
|
console.log('\nConvention review questions:');
|
|
623
623
|
for (const question of inferred.conventions.reviewQuestions) console.log(`- ${question}`);
|
|
624
624
|
console.log('\nProposed backbone.yml:\n');
|
|
625
625
|
console.log(out);
|
|
626
626
|
console.log('Apply this proposed backbone and convention rules? Reply yes, edit, or abort.');
|
|
627
|
-
console.log('To write it after approval, run: node .
|
|
627
|
+
console.log('To write it after approval, run: node .vibekit/scripts/init-backbone.mjs . --write --yes');
|
|
628
628
|
}
|
|
@@ -6,7 +6,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
6
6
|
|
|
7
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
8
|
const __dirname = path.dirname(__filename);
|
|
9
|
-
const kitRoot = path.resolve(__dirname, '..');
|
|
9
|
+
const kitRoot = path.resolve(__dirname, '..', '..');
|
|
10
10
|
const args = process.argv.slice(2);
|
|
11
11
|
|
|
12
12
|
function usage() {
|
|
@@ -22,12 +22,12 @@ Usage:
|
|
|
22
22
|
mvck finalize [target] [--write --yes] [--restore] [--json]
|
|
23
23
|
|
|
24
24
|
Examples:
|
|
25
|
-
node .
|
|
25
|
+
node .vibekit/scripts/mvck.mjs install ~/work/my-repo --profile all
|
|
26
26
|
npx --yes minimal-vibe-coding-kit@latest update .
|
|
27
|
-
node .
|
|
28
|
-
node .
|
|
29
|
-
node .
|
|
30
|
-
node .
|
|
27
|
+
node .vibekit/scripts/mvck.mjs init . --propose
|
|
28
|
+
node .vibekit/scripts/mvck.mjs doctor .
|
|
29
|
+
node .vibekit/scripts/mvck.mjs validate .
|
|
30
|
+
node .vibekit/scripts/mvck.mjs finalize .
|
|
31
31
|
|
|
32
32
|
update refreshes kit-owned files (skills, commands, rules, scripts, docs, agent
|
|
33
33
|
mirrors) to the running kit version. It never overwrites user-owned files
|
|
@@ -98,13 +98,14 @@ function copyFileSafe(srcRel, destRel, target, { force = false, dryRun = false }
|
|
|
98
98
|
return { action: fs.existsSync(dest) && force ? 'replace' : 'copy', path: destRel ?? srcRel };
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
function copyDirSafe(srcRel, destRel, target, { force = false, dryRun = false } = {}) {
|
|
101
|
+
function copyDirSafe(srcRel, destRel, target, { force = false, dryRun = false, exclude = [] } = {}) {
|
|
102
102
|
const src = path.join(kitRoot, srcRel);
|
|
103
103
|
const destRoot = path.join(target, destRel ?? srcRel);
|
|
104
104
|
if (!fs.existsSync(src)) throw new Error(`Missing source dir: ${srcRel}`);
|
|
105
105
|
let copied = 0;
|
|
106
106
|
let skipped = 0;
|
|
107
107
|
function copyRecursive(from, to) {
|
|
108
|
+
if (exclude.includes(path.relative(src, from).replaceAll(path.sep, '/'))) return;
|
|
108
109
|
const stat = fs.statSync(from);
|
|
109
110
|
if (stat.isDirectory()) {
|
|
110
111
|
if (!dryRun) fs.mkdirSync(to, { recursive: true });
|
|
@@ -149,19 +150,30 @@ function managedBlockFromTemplate(block, begin, end) {
|
|
|
149
150
|
return `${begin}\n${block.trim()}\n${end}`;
|
|
150
151
|
}
|
|
151
152
|
|
|
152
|
-
const KIT_SEED_FILES = ['FIRST_TIME_INIT.md', 'FIRST_PROMPT.md', 'CLAUDE-template.md', 'backbone.yml'];
|
|
153
|
-
const KIT_SHARED_DIRS = ['skills', '.
|
|
153
|
+
const KIT_SEED_FILES = ['.vibekit/init/FIRST_TIME_INIT.md', '.vibekit/init/FIRST_PROMPT.md', '.vibekit/init/CLAUDE-template.md', 'backbone.yml'];
|
|
154
|
+
const KIT_SHARED_DIRS = ['.vibekit/skills', '.vibekit/commands', '.vibekit/docs'];
|
|
155
|
+
// Kit-maintainer files that end-user repos do not need; never copied by install/update.
|
|
156
|
+
const KIT_DOC_EXCLUDES = ['RESEARCH_NOTES.md', 'AUTORESEARCH_LEDGER.md'];
|
|
154
157
|
const KIT_SCRIPTS = [
|
|
155
|
-
'.
|
|
156
|
-
'.
|
|
158
|
+
'.vibekit/scripts/mvck.mjs', '.vibekit/scripts/init-backbone.mjs', '.vibekit/scripts/daily-enhance.mjs', '.vibekit/scripts/validate-kit.mjs',
|
|
159
|
+
'.vibekit/scripts/doctor.mjs', '.vibekit/scripts/agentshield-probe.mjs', '.vibekit/scripts/vibekit-finalize.mjs'
|
|
157
160
|
];
|
|
161
|
+
const VALID_PROFILES = new Set(['claude', 'cursor', 'codex']);
|
|
162
|
+
|
|
163
|
+
function parseProfiles(profileRaw) {
|
|
164
|
+
const profiles = new Set(profileRaw === 'all' ? ['claude', 'cursor', 'codex'] : profileRaw.split(',').map((x) => x.trim()).filter(Boolean));
|
|
165
|
+
for (const p of profiles) {
|
|
166
|
+
if (!VALID_PROFILES.has(p)) throw new Error(`Unknown profile: ${p}. Valid values: all, claude, cursor, codex (comma-separated).`);
|
|
167
|
+
}
|
|
168
|
+
return profiles;
|
|
169
|
+
}
|
|
158
170
|
const CLAUDE_DIRS = ['.claude/agents', '.claude/commands', '.claude/rules'];
|
|
159
171
|
const CLAUDE_SKILLS = [
|
|
160
172
|
'autoresearch-coding', 'agentshield-security-review', 'daily-workflow-curator', 'vibekit-init', 'visual-design-loop',
|
|
161
|
-
'clearthought', 'sequential-thinking', 'reviewing-4p-priorities', 'memento', 'coding-level'
|
|
173
|
+
'clearthought', 'sequential-thinking', 'reviewing-4p-priorities', 'path-sensitive-shell-safety', 'memento', 'coding-level', 'parallel-analysis'
|
|
162
174
|
];
|
|
163
175
|
const CURSOR_DIRS = ['.cursor/rules', '.cursor/commands'];
|
|
164
|
-
const CURSOR_SKILLS = ['clearthought', 'sequential-thinking', 'reviewing-4p-priorities', 'memento', 'coding-level'];
|
|
176
|
+
const CURSOR_SKILLS = ['clearthought', 'sequential-thinking', 'reviewing-4p-priorities', 'path-sensitive-shell-safety', 'memento', 'coding-level', 'parallel-analysis'];
|
|
165
177
|
const CODEX_DIRS = ['.agents', '.codex', '.codex-plugin'];
|
|
166
178
|
const GITIGNORE_BLOCK = `# BEGIN: minimal-vibe-coding-kit\n.autoresearch/\nresults.tsv\n.vibekit/INIT_DONE\n.vibekit/FINALIZE_DONE\n.vibekit/reports/\n.vibekit/update-backup/\n_vibekit-cleanup/\nCLAUDE.local.md\n# END: minimal-vibe-coding-kit`;
|
|
167
179
|
|
|
@@ -187,9 +199,9 @@ function applyManagedBlocks(target, profiles, actions, { dryRun = false } = {})
|
|
|
187
199
|
if (profiles.has('claude')) {
|
|
188
200
|
const claudeTarget = path.join(target, 'CLAUDE.md');
|
|
189
201
|
if (!fs.existsSync(claudeTarget)) {
|
|
190
|
-
actions.push(copyFileSafe('CLAUDE-template.md', 'CLAUDE.md', target, { force: false, dryRun }));
|
|
202
|
+
actions.push(copyFileSafe('.vibekit/init/CLAUDE-template.md', 'CLAUDE.md', target, { force: false, dryRun }));
|
|
191
203
|
} else {
|
|
192
|
-
const block = `<!-- BEGIN: minimal-vibe-coding-kit -->\n@AGENTS.md\n\n## Minimal Vibe Coding Kit\n\n- Read \`backbone.yml\` before changing code.\n- If \`meta.template_status\` is \`uninitialized\`, follow
|
|
204
|
+
const block = `<!-- BEGIN: minimal-vibe-coding-kit -->\n@AGENTS.md\n\n## Minimal Vibe Coding Kit\n\n- Read \`backbone.yml\` before changing code.\n- If \`meta.template_status\` is \`uninitialized\`, follow \`.vibekit/init/FIRST_TIME_INIT.md\` and wait for approval before writing.\n- After init, follow \`backbone.yml\` \`conventions\` before adding new project patterns.\n- Prefer project skills for multi-step workflows: \`/autoresearch-coding\`, \`/security-scan\`, \`/daily-enhance\`.\n<!-- END: minimal-vibe-coding-kit -->`;
|
|
193
205
|
appendManagedBlock(claudeTarget, block, '<!-- BEGIN: minimal-vibe-coding-kit -->', '<!-- END: minimal-vibe-coding-kit -->', { dryRun });
|
|
194
206
|
actions.push({ action: 'managed-block', path: 'CLAUDE.md' });
|
|
195
207
|
}
|
|
@@ -213,8 +225,7 @@ function install() {
|
|
|
213
225
|
const dryRun = hasFlag('--dry-run');
|
|
214
226
|
const json = hasFlag('--json');
|
|
215
227
|
const target = parseTargetAndFlags('install', { valueFlags: ['--profile'] }).target;
|
|
216
|
-
const
|
|
217
|
-
const profiles = new Set(profileRaw === 'all' ? ['claude', 'cursor', 'codex'] : profileRaw.split(',').map((x) => x.trim()).filter(Boolean));
|
|
228
|
+
const profiles = parseProfiles(optionValue('--profile', 'all'));
|
|
218
229
|
|
|
219
230
|
if (!fs.existsSync(target)) throw new Error(`Target does not exist: ${target}`);
|
|
220
231
|
const actions = [];
|
|
@@ -224,7 +235,7 @@ function install() {
|
|
|
224
235
|
actions.push(copyFileSafe(file, file, target, opts));
|
|
225
236
|
}
|
|
226
237
|
for (const dir of KIT_SHARED_DIRS) {
|
|
227
|
-
actions.push(copyDirSafe(dir, dir, target, opts));
|
|
238
|
+
actions.push(copyDirSafe(dir, dir, target, dir === '.vibekit/docs' ? { ...opts, exclude: KIT_DOC_EXCLUDES } : opts));
|
|
228
239
|
}
|
|
229
240
|
for (const file of KIT_SCRIPTS) {
|
|
230
241
|
actions.push(copyFileSafe(file, file, target, opts));
|
|
@@ -258,7 +269,8 @@ function install() {
|
|
|
258
269
|
writeKitVersion(target, dryRun);
|
|
259
270
|
actions.push({ action: 'version-marker', path: '.vibekit/KIT_VERSION' });
|
|
260
271
|
|
|
261
|
-
const nextPrompt = 'Read FIRST_TIME_INIT.md and initialize this repo with Minimal Vibe Coding Kit. Print requirements first, infer project conventions, propose a diff, and wait for my yes before writing.';
|
|
272
|
+
const nextPrompt = 'Read .vibekit/init/FIRST_TIME_INIT.md and initialize this repo with Minimal Vibe Coding Kit. Print requirements first, infer project conventions, propose a diff, and wait for my yes before writing.';
|
|
273
|
+
const legacyPaths = detectLegacyLayout(target);
|
|
262
274
|
if (json) {
|
|
263
275
|
console.log(JSON.stringify({
|
|
264
276
|
status: dryRun ? 'dry-run' : 'installed',
|
|
@@ -267,6 +279,7 @@ function install() {
|
|
|
267
279
|
force,
|
|
268
280
|
dryRun,
|
|
269
281
|
actions,
|
|
282
|
+
legacyPaths,
|
|
270
283
|
nextPrompt
|
|
271
284
|
}, null, 2));
|
|
272
285
|
return;
|
|
@@ -274,10 +287,29 @@ function install() {
|
|
|
274
287
|
|
|
275
288
|
console.log(dryRun ? 'Dry-run install plan:' : 'Install complete:');
|
|
276
289
|
for (const a of actions) console.log(`- ${a.action}: ${a.path}`);
|
|
290
|
+
printLegacyLayoutNote(legacyPaths);
|
|
277
291
|
console.log('\nNext prompt:');
|
|
278
292
|
console.log(nextPrompt);
|
|
279
293
|
}
|
|
280
294
|
|
|
295
|
+
// Pre-0.4 installs placed kit dirs at the target root. Detection is advisory
|
|
296
|
+
// only: nothing is deleted automatically, and a root `skills/` dir is flagged
|
|
297
|
+
// only when it contains a known kit skill (it may be the user's own folder).
|
|
298
|
+
function detectLegacyLayout(target) {
|
|
299
|
+
const legacy = ['.vbkit-scripts', '.vbkit-commands', '.vbkit-docs',
|
|
300
|
+
'FIRST_TIME_INIT.md', 'FIRST_PROMPT.md', 'CLAUDE-template.md', 'PUSH_TO_GITHUB.md']
|
|
301
|
+
.filter((rel) => fs.existsSync(path.join(target, rel)));
|
|
302
|
+
if (fs.existsSync(path.join(target, 'skills', 'vibekit-init', 'SKILL.md'))) legacy.push('skills');
|
|
303
|
+
return legacy;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function printLegacyLayoutNote(legacy) {
|
|
307
|
+
if (!legacy.length) return;
|
|
308
|
+
console.log('\nLegacy kit layout detected (pre-0.4). Kit files now live under .vibekit/.');
|
|
309
|
+
console.log('After verifying the new .vibekit/ copies, remove or `git mv` these leftovers:');
|
|
310
|
+
for (const rel of legacy) console.log(`- ${rel}`);
|
|
311
|
+
}
|
|
312
|
+
|
|
281
313
|
function updateFileSafe(srcRel, destRel, target, { dryRun = false, backup = null } = {}) {
|
|
282
314
|
const src = path.join(kitRoot, srcRel);
|
|
283
315
|
const dest = path.join(target, destRel ?? srcRel);
|
|
@@ -312,10 +344,12 @@ function updateFileSafe(srcRel, destRel, target, { dryRun = false, backup = null
|
|
|
312
344
|
function updateDirSafe(srcRel, target, opts) {
|
|
313
345
|
const src = path.join(kitRoot, srcRel);
|
|
314
346
|
if (!fs.existsSync(src)) throw new Error(`Missing source dir: ${srcRel}`);
|
|
347
|
+
const exclude = opts.exclude ?? [];
|
|
315
348
|
const results = [];
|
|
316
349
|
function walk(current) {
|
|
317
350
|
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
|
|
318
351
|
const child = path.join(current, entry.name);
|
|
352
|
+
if (exclude.includes(path.relative(src, child).replaceAll(path.sep, '/'))) continue;
|
|
319
353
|
if (entry.isDirectory()) walk(child);
|
|
320
354
|
else {
|
|
321
355
|
const rel = path.join(srcRel, path.relative(src, child)).replaceAll(path.sep, '/');
|
|
@@ -332,15 +366,14 @@ function update() {
|
|
|
332
366
|
const json = hasFlag('--json');
|
|
333
367
|
const noBackup = hasFlag('--no-backup');
|
|
334
368
|
const target = parseTargetAndFlags('update', { valueFlags: ['--profile'] }).target;
|
|
335
|
-
const
|
|
336
|
-
const profiles = new Set(profileRaw === 'all' ? ['claude', 'cursor', 'codex'] : profileRaw.split(',').map((x) => x.trim()).filter(Boolean));
|
|
369
|
+
const profiles = parseProfiles(optionValue('--profile', 'all'));
|
|
337
370
|
|
|
338
371
|
if (!fs.existsSync(target)) throw new Error(`Target does not exist: ${target}`);
|
|
339
372
|
if (fs.realpathSync(kitRoot) === fs.realpathSync(target)) {
|
|
340
373
|
throw new Error('Update source and target are the same directory. Run the update from a newer kit, e.g.: npx --yes minimal-vibe-coding-kit@latest update .');
|
|
341
374
|
}
|
|
342
|
-
if (!fs.existsSync(path.join(target, 'backbone.yml')) && !fs.existsSync(path.join(target, '.
|
|
343
|
-
throw new Error('Kit not detected in target (no backbone.yml or .
|
|
375
|
+
if (!fs.existsSync(path.join(target, 'backbone.yml')) && !fs.existsSync(path.join(target, '.vibekit/scripts'))) {
|
|
376
|
+
throw new Error('Kit not detected in target (no backbone.yml or .vibekit/scripts). Run mvck install first.');
|
|
344
377
|
}
|
|
345
378
|
|
|
346
379
|
const previousVersionFile = path.join(target, '.vibekit', 'KIT_VERSION');
|
|
@@ -352,7 +385,7 @@ function update() {
|
|
|
352
385
|
const actions = [];
|
|
353
386
|
|
|
354
387
|
// Kit-owned surfaces: refresh to the running kit version, never delete extras.
|
|
355
|
-
for (const dir of KIT_SHARED_DIRS) actions.push(...updateDirSafe(dir, target, opts));
|
|
388
|
+
for (const dir of KIT_SHARED_DIRS) actions.push(...updateDirSafe(dir, target, dir === '.vibekit/docs' ? { ...opts, exclude: KIT_DOC_EXCLUDES } : opts));
|
|
356
389
|
for (const file of KIT_SCRIPTS) actions.push(updateFileSafe(file, file, target, opts));
|
|
357
390
|
if (profiles.has('claude')) {
|
|
358
391
|
for (const dir of CLAUDE_DIRS) actions.push(...updateDirSafe(dir, target, opts));
|
|
@@ -381,6 +414,7 @@ function update() {
|
|
|
381
414
|
const backupInfo = backup && backup.count > 0 ? path.relative(target, backup.dir) : null;
|
|
382
415
|
const preserved = ['backbone.yml', 'CLAUDE.md', 'AGENTS.md content outside the managed block', '.claude/settings.json', '.cursor/settings.json'];
|
|
383
416
|
|
|
417
|
+
const legacyPaths = detectLegacyLayout(target);
|
|
384
418
|
if (json) {
|
|
385
419
|
console.log(JSON.stringify({
|
|
386
420
|
status: dryRun ? 'dry-run' : 'updated',
|
|
@@ -391,6 +425,7 @@ function update() {
|
|
|
391
425
|
summary,
|
|
392
426
|
backupDir: backupInfo,
|
|
393
427
|
preserved,
|
|
428
|
+
legacyPaths,
|
|
394
429
|
actions: actions.filter((a) => a.action !== 'unchanged')
|
|
395
430
|
}, null, 2));
|
|
396
431
|
return;
|
|
@@ -405,11 +440,12 @@ function update() {
|
|
|
405
440
|
console.log(`\nSummary: ${summary.add} added, ${summary.update} updated, ${summary.unchanged} unchanged.`);
|
|
406
441
|
if (backupInfo) console.log(`Backups of replaced files: ${backupInfo}/`);
|
|
407
442
|
console.log(`Preserved (never overwritten by update): ${preserved.join(', ')}.`);
|
|
443
|
+
printLegacyLayoutNote(legacyPaths);
|
|
408
444
|
}
|
|
409
445
|
|
|
410
446
|
function delegate(scriptName, { valueFlags = [] } = {}) {
|
|
411
447
|
const { target, flags } = parseTargetAndFlags(args[0], { valueFlags });
|
|
412
|
-
const script = path.join(kitRoot, '.
|
|
448
|
+
const script = path.join(kitRoot, '.vibekit/scripts', scriptName);
|
|
413
449
|
const childArgs = [script, target, ...flags];
|
|
414
450
|
const result = spawnSync(process.execPath, childArgs, { stdio: 'inherit' });
|
|
415
451
|
process.exit(result.status ?? 1);
|
|
@@ -6,7 +6,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const kitRoot = path.resolve(path.dirname(__filename), '..');
|
|
9
|
+
const kitRoot = path.resolve(path.dirname(__filename), '..', '..');
|
|
10
10
|
const node = process.execPath;
|
|
11
11
|
const keep = process.argv.includes('--keep');
|
|
12
12
|
const temps = [];
|
|
@@ -44,21 +44,35 @@ function count(text, marker) {
|
|
|
44
44
|
|
|
45
45
|
try {
|
|
46
46
|
const clean = tempDir('clean');
|
|
47
|
-
run(['.
|
|
48
|
-
run(['.
|
|
47
|
+
run(['.vibekit/scripts/mvck.mjs', 'install', clean, '--profile', 'all']);
|
|
48
|
+
run(['.vibekit/scripts/validate-kit.mjs', clean]);
|
|
49
49
|
assert(fs.existsSync(path.join(clean, 'AGENTS.md')), 'clean install creates AGENTS.md');
|
|
50
|
-
assert(fs.existsSync(path.join(clean, '.
|
|
51
|
-
assert(fs.existsSync(path.join(clean, '.
|
|
52
|
-
assert(fs.existsSync(path.join(clean, '.
|
|
50
|
+
assert(fs.existsSync(path.join(clean, '.vibekit/commands')), 'clean install creates .vibekit/commands');
|
|
51
|
+
assert(fs.existsSync(path.join(clean, '.vibekit/scripts')), 'clean install creates .vibekit/scripts');
|
|
52
|
+
assert(fs.existsSync(path.join(clean, '.vibekit/docs')), 'clean install creates .vibekit/docs');
|
|
53
53
|
assert(!fs.existsSync(path.join(clean, 'commands')), 'clean install does not create root commands');
|
|
54
54
|
assert(!fs.existsSync(path.join(clean, 'scripts')), 'clean install does not create root scripts');
|
|
55
55
|
assert(!fs.existsSync(path.join(clean, 'docs')), 'clean install does not create root docs');
|
|
56
|
+
assert(fs.existsSync(path.join(clean, '.vibekit/skills/vibekit-init/SKILL.md')), 'clean install creates .vibekit/skills');
|
|
57
|
+
assert(fs.existsSync(path.join(clean, '.vibekit/init/FIRST_TIME_INIT.md')), 'clean install seeds init files under .vibekit/init');
|
|
58
|
+
assert(!fs.existsSync(path.join(clean, 'skills')), 'clean install does not create root skills');
|
|
59
|
+
assert(!fs.existsSync(path.join(clean, '.vbkit-scripts')), 'clean install does not create legacy .vbkit-scripts');
|
|
60
|
+
assert(!fs.existsSync(path.join(clean, '.vbkit-commands')), 'clean install does not create legacy .vbkit-commands');
|
|
61
|
+
assert(!fs.existsSync(path.join(clean, '.vbkit-docs')), 'clean install does not create legacy .vbkit-docs');
|
|
62
|
+
assert(!fs.existsSync(path.join(clean, 'FIRST_TIME_INIT.md')), 'clean install does not seed root FIRST_TIME_INIT.md');
|
|
63
|
+
assert(!fs.existsSync(path.join(clean, '.vibekit/scripts/test-install.mjs')), 'clean install omits kit-dev test-install.mjs');
|
|
64
|
+
assert(!fs.existsSync(path.join(clean, '.vibekit/scripts/pack-dry-run.mjs')), 'clean install omits kit-dev pack-dry-run.mjs');
|
|
65
|
+
assert(!fs.existsSync(path.join(clean, '.vibekit/docs/RESEARCH_NOTES.md')), 'clean install omits maintainer RESEARCH_NOTES.md');
|
|
66
|
+
assert(!fs.existsSync(path.join(clean, '.vibekit/docs/AUTORESEARCH_LEDGER.md')), 'clean install omits maintainer AUTORESEARCH_LEDGER.md');
|
|
67
|
+
assert(fs.existsSync(path.join(clean, '.vibekit/docs/INSTALL.md')), 'clean install keeps end-user docs like INSTALL.md');
|
|
68
|
+
run(['.vibekit/scripts/mvck.mjs', 'install', clean, '--profile', 'bogus'], { expect: 1 });
|
|
69
|
+
assert(true, 'install rejects an unknown --profile value');
|
|
56
70
|
|
|
57
71
|
const existing = tempDir('existing');
|
|
58
72
|
fs.writeFileSync(path.join(existing, 'AGENTS.md'), '# Existing\n');
|
|
59
73
|
fs.writeFileSync(path.join(existing, 'CLAUDE.md'), '# Existing Claude\n');
|
|
60
|
-
run(['.
|
|
61
|
-
run(['.
|
|
74
|
+
run(['.vibekit/scripts/mvck.mjs', 'install', existing, '--profile', 'all']);
|
|
75
|
+
run(['.vibekit/scripts/mvck.mjs', 'install', existing, '--profile', 'all']);
|
|
62
76
|
|
|
63
77
|
const agents = fs.readFileSync(path.join(existing, 'AGENTS.md'), 'utf8');
|
|
64
78
|
const claude = fs.readFileSync(path.join(existing, 'CLAUDE.md'), 'utf8');
|
|
@@ -70,39 +84,39 @@ try {
|
|
|
70
84
|
assert(count(claude, 'END: minimal-vibe-coding-kit') === 1, 'CLAUDE.md has one managed end marker');
|
|
71
85
|
|
|
72
86
|
const cwdTarget = tempDir('cwd-target');
|
|
73
|
-
run([path.join(kitRoot, '.
|
|
87
|
+
run([path.join(kitRoot, '.vibekit/scripts/mvck.mjs'), 'install', '--profile', 'all'], { cwd: cwdTarget });
|
|
74
88
|
assert(fs.existsSync(path.join(cwdTarget, 'backbone.yml')), 'install without target uses current working directory');
|
|
75
89
|
|
|
76
|
-
const proposed = run([path.join(kitRoot, '.
|
|
90
|
+
const proposed = run([path.join(kitRoot, '.vibekit/scripts/mvck.mjs'), 'init', '--propose'], { cwd: cwdTarget });
|
|
77
91
|
assert(proposed.stdout.includes('Proposed backbone.yml'), 'init --propose without target preserves flag');
|
|
78
92
|
|
|
79
|
-
const jsonPlan = run(['.
|
|
93
|
+
const jsonPlan = run(['.vibekit/scripts/mvck.mjs', 'install', clean, '--dry-run', '--json']);
|
|
80
94
|
const parsed = JSON.parse(jsonPlan.stdout);
|
|
81
95
|
assert(parsed.status === 'dry-run' && parsed.dryRun === true, 'install --dry-run --json returns machine-readable plan');
|
|
82
96
|
|
|
83
97
|
const upd = tempDir('update');
|
|
84
|
-
run(['.
|
|
98
|
+
run(['.vibekit/scripts/mvck.mjs', 'install', upd, '--profile', 'all']);
|
|
85
99
|
assert(fs.existsSync(path.join(upd, '.vibekit/KIT_VERSION')), 'install stamps .vibekit/KIT_VERSION');
|
|
86
100
|
fs.appendFileSync(path.join(upd, 'backbone.yml'), '# user-custom-line\n');
|
|
87
|
-
fs.writeFileSync(path.join(upd, 'skills/memento/SKILL.md'), '# stale kit file\n');
|
|
101
|
+
fs.writeFileSync(path.join(upd, '.vibekit/skills/memento/SKILL.md'), '# stale kit file\n');
|
|
88
102
|
fs.rmSync(path.join(upd, '.claude/skills/coding-level'), { recursive: true, force: true });
|
|
89
103
|
|
|
90
|
-
run(['.
|
|
91
|
-
assert(fs.readFileSync(path.join(upd, 'skills/memento/SKILL.md'), 'utf8').includes('name: memento'), 'update refreshes stale kit files');
|
|
104
|
+
run(['.vibekit/scripts/mvck.mjs', 'update', upd]);
|
|
105
|
+
assert(fs.readFileSync(path.join(upd, '.vibekit/skills/memento/SKILL.md'), 'utf8').includes('name: memento'), 'update refreshes stale kit files');
|
|
92
106
|
assert(fs.existsSync(path.join(upd, '.claude/skills/coding-level/SKILL.md')), 'update re-adds missing kit skill mirrors');
|
|
93
107
|
assert(fs.readFileSync(path.join(upd, 'backbone.yml'), 'utf8').includes('# user-custom-line'), 'update preserves user-modified backbone.yml');
|
|
94
108
|
const backupRoot = path.join(upd, '.vibekit', 'update-backup');
|
|
95
109
|
assert(fs.existsSync(backupRoot) && fs.readdirSync(backupRoot).length >= 1, 'update backs up replaced kit files');
|
|
96
|
-
run(['.
|
|
110
|
+
run(['.vibekit/scripts/validate-kit.mjs', upd]);
|
|
97
111
|
|
|
98
112
|
const updAgents = fs.readFileSync(path.join(upd, 'AGENTS.md'), 'utf8');
|
|
99
113
|
assert(count(updAgents, 'BEGIN: minimal-vibe-coding-kit') === 1, 'update keeps one managed begin marker in AGENTS.md');
|
|
100
114
|
|
|
101
115
|
const emptyTarget = tempDir('update-empty');
|
|
102
|
-
run(['.
|
|
116
|
+
run(['.vibekit/scripts/mvck.mjs', 'update', emptyTarget], { expect: 1 });
|
|
103
117
|
assert(true, 'update refuses a target without the kit installed');
|
|
104
118
|
|
|
105
|
-
const updPlan = run(['.
|
|
119
|
+
const updPlan = run(['.vibekit/scripts/mvck.mjs', 'update', upd, '--dry-run', '--json']);
|
|
106
120
|
const updParsed = JSON.parse(updPlan.stdout);
|
|
107
121
|
assert(updParsed.status === 'dry-run' && typeof updParsed.toVersion === 'string', 'update --dry-run --json returns machine-readable plan');
|
|
108
122
|
|