@govindchaudhary/vibekit 0.1.1
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/LICENSE +21 -0
- package/README.md +149 -0
- package/dist/cli.js +73 -0
- package/dist/commands/init.js +112 -0
- package/dist/commands/log.js +90 -0
- package/dist/commands/packs.js +83 -0
- package/dist/commands/prune.js +101 -0
- package/dist/commands/sync.js +63 -0
- package/dist/utils/fileio.js +99 -0
- package/dist/utils/markers.js +132 -0
- package/package.json +51 -0
- package/packs/core.md +7 -0
- package/packs/data-eng.md +8 -0
- package/packs/dev.md +7 -0
- package/principles-catalog.md +83 -0
- package/templates/AGENTS.md.template +22 -0
- package/templates/CHANGELOG.md.template +10 -0
- package/templates/DECISIONS.md.template +6 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vibekit contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
[](https://www.npmjs.com/package/@govindchaudhary/vibekit)
|
|
2
|
+
[](./LICENSE)
|
|
3
|
+
|
|
4
|
+
# Vibekit
|
|
5
|
+
|
|
6
|
+
**Vibe code without losing the plot.** Vibekit keeps fast, AI-driven "vibe
|
|
7
|
+
coding" accurate by giving your assistant lean, *verifiable* context — a
|
|
8
|
+
lightweight alternative to heavyweight Spec-Driven Development (SDD). Instead of
|
|
9
|
+
generating a spec/plan/tasks document set for every feature, Vibekit maintains
|
|
10
|
+
**3 persistent markdown files** that any AI coding assistant — Copilot, Claude,
|
|
11
|
+
Cursor, Windsurf — reads automatically. No per-feature ceremony, no token bloat,
|
|
12
|
+
and a working setup in **under 2 minutes**. It's tool-agnostic by design: the
|
|
13
|
+
canonical file is `AGENTS.md`, and everything else mirrors from it.
|
|
14
|
+
|
|
15
|
+
> **Motto:** *vibe fast, stay grounded.* The `AGENTS.md` Verify-before-trust
|
|
16
|
+
> rule means the AI treats notes as hints and the current code as ground truth.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Quickstart
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx @govindchaudhary/vibekit init
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Answer one question ("What's this project mostly?") and you're done — under two
|
|
27
|
+
minutes to a working setup. Vibekit creates four files in your current
|
|
28
|
+
directory:
|
|
29
|
+
|
|
30
|
+
| File | Purpose |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| `AGENTS.md` | Stable context + coding principles (the file AI actually reads) |
|
|
33
|
+
| `CHANGELOG.md` | Rolling log of recent changes |
|
|
34
|
+
| `DECISIONS.md` | Architecture decisions worth not re-litigating |
|
|
35
|
+
| `principles-catalog.md` | Human reference menu — **never loaded by AI** |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Two ways to adopt it
|
|
40
|
+
|
|
41
|
+
**(a) Use this template (zero install).** Click **"Use this template"** at the
|
|
42
|
+
top of this GitHub repo to clone the structure into a fresh repository. Good for
|
|
43
|
+
brand-new projects.
|
|
44
|
+
|
|
45
|
+
**(b) npx CLI (add to an existing repo).** Run `npx @govindchaudhary/vibekit init` inside any
|
|
46
|
+
existing project to drop the files in without touching the rest of your code.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Vibekit vs. typical SDD tools
|
|
51
|
+
|
|
52
|
+
| | Vibekit | Typical SDD tool (Spec-Kit, BMAD) |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| Setup time | < 2 minutes | 15–60 minutes |
|
|
55
|
+
| Files per feature | 0 (3 persistent files total) | 3+ (spec, plan, tasks) per feature |
|
|
56
|
+
| Token overhead | Low — one stable context file | High — large generated specs reloaded |
|
|
57
|
+
| Best when | Solo devs / small teams wanting fast AI context | Large teams needing formal, auditable specs for complex features |
|
|
58
|
+
|
|
59
|
+
Use a full SDD framework when you genuinely need formal, reviewable
|
|
60
|
+
specifications per feature. Reach for Vibekit when you just want your AI
|
|
61
|
+
assistant to have accurate, lightweight context without the overhead.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## The 3 files
|
|
66
|
+
|
|
67
|
+
### `AGENTS.md` — stable context
|
|
68
|
+
The one file AI tools read by default. It holds your active principle packs, a
|
|
69
|
+
**Verify-before-trust** safeguard, your project stack, and your conventions.
|
|
70
|
+
Keep it accurate; it's the source of durable context.
|
|
71
|
+
|
|
72
|
+
### `CHANGELOG.md` — rolling log
|
|
73
|
+
Newest entry first. Each entry has an exact ISO date, what changed and why, and
|
|
74
|
+
the files/functions touched. Mark resolved entries `[DONE]`; `vibekit prune`
|
|
75
|
+
trims old resolved entries so the file stays small (~10 active entries max).
|
|
76
|
+
|
|
77
|
+
### `DECISIONS.md` — architecture decisions
|
|
78
|
+
Only record choices a future session would otherwise guess wrong or re-debate —
|
|
79
|
+
architecture and library choices, not routine bug fixes.
|
|
80
|
+
|
|
81
|
+
> **Verify-before-trust:** CHANGELOG and DECISIONS are *hints, not ground truth*.
|
|
82
|
+
> Before relying on an entry, confirm the referenced code still matches. If it
|
|
83
|
+
> doesn't, the current code wins.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## How packs work
|
|
88
|
+
|
|
89
|
+
A **pack** is a small, reusable block of coding principles wrapped in markers:
|
|
90
|
+
|
|
91
|
+
```markdown
|
|
92
|
+
<!-- pack:dev:start -->
|
|
93
|
+
### SOLID Principles
|
|
94
|
+
- ...
|
|
95
|
+
<!-- pack:dev:end -->
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Built-in packs:
|
|
99
|
+
|
|
100
|
+
- **`core`** — always included (SRP, DRY, KISS, fail fast)
|
|
101
|
+
- **`dev`** — SOLID principles for application development
|
|
102
|
+
- **`data-eng`** — idempotency, schema validation, ETL separation, immutable raw data, reproducibility
|
|
103
|
+
|
|
104
|
+
Manage packs at any time:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
vibekit packs add data-eng
|
|
108
|
+
vibekit packs remove dev
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Add a custom pack
|
|
112
|
+
|
|
113
|
+
1. Create `packs/<name>.md`, e.g. `packs/security.md`.
|
|
114
|
+
2. Wrap the content in markers whose name matches the file:
|
|
115
|
+
|
|
116
|
+
```markdown
|
|
117
|
+
<!-- pack:security:start -->
|
|
118
|
+
### Security Principles
|
|
119
|
+
- Least privilege: grant the minimum access required
|
|
120
|
+
- Never trust client input: validate at every boundary
|
|
121
|
+
<!-- pack:security:end -->
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
3. Activate it: `vibekit packs add security`.
|
|
125
|
+
|
|
126
|
+
See [`principles-catalog.md`](./principles-catalog.md) for the full menu.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Commands
|
|
131
|
+
|
|
132
|
+
| Command | What it does |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| `vibekit init` | Scaffold the 4 files (asks one question). |
|
|
135
|
+
| `vibekit log "<message>"` | Append a dated changelog entry (newest on top). |
|
|
136
|
+
| `vibekit prune` | Remove `[DONE]` entries except the 5 most recent. |
|
|
137
|
+
| `vibekit packs add <name>` | Insert a pack block into `AGENTS.md`. |
|
|
138
|
+
| `vibekit packs remove <name>` | Remove a pack block from `AGENTS.md`. |
|
|
139
|
+
| `vibekit sync` | Mirror `AGENTS.md` to `CLAUDE.md`, `.windsurfrules`, `.github/copilot-instructions.md`. |
|
|
140
|
+
|
|
141
|
+
> **About `sync`:** most modern tools (Copilot, Cursor, Windsurf) now read
|
|
142
|
+
> `AGENTS.md` natively. `sync` is a fallback for tools/older setups that don't
|
|
143
|
+
> yet, or for teams who want the explicit native filename present.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
[MIT](./LICENSE)
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const init_1 = require("./commands/init");
|
|
6
|
+
const log_1 = require("./commands/log");
|
|
7
|
+
const prune_1 = require("./commands/prune");
|
|
8
|
+
const packs_1 = require("./commands/packs");
|
|
9
|
+
const sync_1 = require("./commands/sync");
|
|
10
|
+
const program = new commander_1.Command();
|
|
11
|
+
program
|
|
12
|
+
.name('vibekit')
|
|
13
|
+
.description('Lean, AI-tool-agnostic project context: 3 persistent markdown files ' +
|
|
14
|
+
'(AGENTS.md, CHANGELOG.md, DECISIONS.md) that keep vibe coding accurate, ' +
|
|
15
|
+
'instead of heavyweight SDD specs.')
|
|
16
|
+
.version('0.1.1');
|
|
17
|
+
program
|
|
18
|
+
.command('init')
|
|
19
|
+
.description('Scaffold AGENTS.md, CHANGELOG.md, DECISIONS.md, and principles-catalog.md in the current directory.')
|
|
20
|
+
.action(async () => {
|
|
21
|
+
await (0, init_1.initCommand)();
|
|
22
|
+
});
|
|
23
|
+
program
|
|
24
|
+
.command('log')
|
|
25
|
+
.description('Append a new entry to CHANGELOG.md (newest on top) with today\'s date.')
|
|
26
|
+
.argument('<message>', 'short description of what changed')
|
|
27
|
+
.action((message) => {
|
|
28
|
+
(0, log_1.logCommand)(message);
|
|
29
|
+
});
|
|
30
|
+
program
|
|
31
|
+
.command('prune')
|
|
32
|
+
.description('Remove resolved [DONE] changelog entries, keeping the 5 most recent.')
|
|
33
|
+
.action(() => {
|
|
34
|
+
(0, prune_1.pruneCommand)();
|
|
35
|
+
});
|
|
36
|
+
const packs = program
|
|
37
|
+
.command('packs')
|
|
38
|
+
.description('Add or remove principle packs in AGENTS.md.');
|
|
39
|
+
packs
|
|
40
|
+
.command('add')
|
|
41
|
+
.description('Insert a pack block (packs/<name>.md) into AGENTS.md.')
|
|
42
|
+
.argument('<name>', 'pack name, e.g. dev or data-eng')
|
|
43
|
+
.action((name) => {
|
|
44
|
+
(0, packs_1.packsAddCommand)(name);
|
|
45
|
+
});
|
|
46
|
+
packs
|
|
47
|
+
.command('remove')
|
|
48
|
+
.description('Remove a pack block from AGENTS.md.')
|
|
49
|
+
.argument('<name>', 'pack name, e.g. dev or data-eng')
|
|
50
|
+
.action((name) => {
|
|
51
|
+
(0, packs_1.packsRemoveCommand)(name);
|
|
52
|
+
});
|
|
53
|
+
program
|
|
54
|
+
.command('sync')
|
|
55
|
+
.description('Mirror AGENTS.md to CLAUDE.md, .windsurfrules, and ' +
|
|
56
|
+
'.github/copilot-instructions.md. Most modern tools (Copilot, Cursor, ' +
|
|
57
|
+
'Windsurf) now read AGENTS.md natively — sync is a fallback for older ' +
|
|
58
|
+
'setups that don\'t yet, or for teams who want the explicit native ' +
|
|
59
|
+
'filename present.')
|
|
60
|
+
.action(() => {
|
|
61
|
+
(0, sync_1.syncCommand)();
|
|
62
|
+
});
|
|
63
|
+
async function main() {
|
|
64
|
+
try {
|
|
65
|
+
await program.parseAsync(process.argv);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
69
|
+
console.error(`Error: ${message}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
main();
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.initCommand = initCommand;
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
42
|
+
const fileio_1 = require("../utils/fileio");
|
|
43
|
+
const markers_1 = require("../utils/markers");
|
|
44
|
+
const KIND_TO_PACKS = {
|
|
45
|
+
dev: ['core', 'dev'],
|
|
46
|
+
data: ['core', 'data-eng'],
|
|
47
|
+
both: ['core', 'dev', 'data-eng'],
|
|
48
|
+
skip: ['core'],
|
|
49
|
+
};
|
|
50
|
+
async function initCommand() {
|
|
51
|
+
const cwd = process.cwd();
|
|
52
|
+
const agentsPath = path.join(cwd, 'AGENTS.md');
|
|
53
|
+
if ((0, fileio_1.exists)(agentsPath)) {
|
|
54
|
+
const { overwrite } = await (0, prompts_1.default)({
|
|
55
|
+
type: 'confirm',
|
|
56
|
+
name: 'overwrite',
|
|
57
|
+
message: 'AGENTS.md already exists. Overwrite it?',
|
|
58
|
+
initial: false,
|
|
59
|
+
});
|
|
60
|
+
if (!overwrite) {
|
|
61
|
+
console.log('Aborted — existing AGENTS.md left untouched.');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const { kind } = await (0, prompts_1.default)({
|
|
66
|
+
type: 'select',
|
|
67
|
+
name: 'kind',
|
|
68
|
+
message: "What's this project mostly?",
|
|
69
|
+
choices: [
|
|
70
|
+
{ title: 'Dev', value: 'dev' },
|
|
71
|
+
{ title: 'Data Engineering', value: 'data' },
|
|
72
|
+
{ title: 'Both', value: 'both' },
|
|
73
|
+
{ title: "Skip — I'll write my own", value: 'skip' },
|
|
74
|
+
],
|
|
75
|
+
initial: 0,
|
|
76
|
+
});
|
|
77
|
+
// Handle abort (Ctrl+C) gracefully.
|
|
78
|
+
const selected = kind ?? 'skip';
|
|
79
|
+
const packs = KIND_TO_PACKS[selected];
|
|
80
|
+
// Build AGENTS.md from the template.
|
|
81
|
+
let agents = (0, fileio_1.readFile)((0, fileio_1.assetPath)('templates', 'AGENTS.md.template'));
|
|
82
|
+
if (selected === 'skip') {
|
|
83
|
+
// Core only, with a hint comment about adding more packs later.
|
|
84
|
+
const coreBlock = (0, markers_1.extractBlock)((0, fileio_1.readFile)((0, fileio_1.assetPath)('packs', 'core.md')), 'core');
|
|
85
|
+
const hint = '<!-- Add more packs later, e.g. `vibekit packs add dev` ' +
|
|
86
|
+
'or `vibekit packs add data-eng`. See principles-catalog.md. -->';
|
|
87
|
+
agents = agents.replace(markers_1.PACK_PLACEHOLDER, `${coreBlock}\n\n${hint}\n`);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
for (const name of packs) {
|
|
91
|
+
const block = (0, markers_1.extractBlock)((0, fileio_1.readFile)((0, fileio_1.assetPath)('packs', `${name}.md`)), name);
|
|
92
|
+
agents = (0, markers_1.insertPack)(agents, block);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
agents = (0, markers_1.setActivePacksLine)(agents, packs);
|
|
96
|
+
// Write the 4 files.
|
|
97
|
+
(0, fileio_1.writeFile)(agentsPath, agents);
|
|
98
|
+
(0, fileio_1.writeFile)(path.join(cwd, 'CHANGELOG.md'), (0, fileio_1.readFile)((0, fileio_1.assetPath)('templates', 'CHANGELOG.md.template')));
|
|
99
|
+
(0, fileio_1.writeFile)(path.join(cwd, 'DECISIONS.md'), (0, fileio_1.readFile)((0, fileio_1.assetPath)('templates', 'DECISIONS.md.template')));
|
|
100
|
+
(0, fileio_1.writeFile)(path.join(cwd, 'principles-catalog.md'), (0, fileio_1.readFile)((0, fileio_1.assetPath)('principles-catalog.md')));
|
|
101
|
+
console.log('');
|
|
102
|
+
console.log('Vibekit initialized. Created:');
|
|
103
|
+
console.log(' - AGENTS.md (stable context + active packs: ' + packs.join(', ') + ')');
|
|
104
|
+
console.log(' - CHANGELOG.md (rolling log of recent changes)');
|
|
105
|
+
console.log(' - DECISIONS.md (architecture decisions worth keeping)');
|
|
106
|
+
console.log(' - principles-catalog.md (reference only — never loaded by AI)');
|
|
107
|
+
console.log('');
|
|
108
|
+
console.log("What's next:");
|
|
109
|
+
console.log(' 1. Fill in the Project Stack & Conventions sections of AGENTS.md.');
|
|
110
|
+
console.log(' 2. Record changes with: vibekit log "what you changed"');
|
|
111
|
+
console.log(' 3. (Optional) mirror AGENTS.md for older tools: vibekit sync');
|
|
112
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.logCommand = logCommand;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fileio_1 = require("../utils/fileio");
|
|
39
|
+
const CHANGELOG_HEADING = /^## Changelog\s*$/m;
|
|
40
|
+
const EMPTY_PLACEHOLDER = /\(no entries yet — run `vibekit log "description"` after your first change\)\s*/;
|
|
41
|
+
/**
|
|
42
|
+
* Append a new changelog entry (newest on top) with today's ISO date.
|
|
43
|
+
*/
|
|
44
|
+
function logCommand(message) {
|
|
45
|
+
if (!message || !message.trim()) {
|
|
46
|
+
throw new Error('A message is required: vibekit log "what you changed"');
|
|
47
|
+
}
|
|
48
|
+
const cwd = process.cwd();
|
|
49
|
+
const changelogPath = path.join(cwd, 'CHANGELOG.md');
|
|
50
|
+
if (!(0, fileio_1.exists)(changelogPath)) {
|
|
51
|
+
throw new Error('CHANGELOG.md not found. Run `vibekit init` first.');
|
|
52
|
+
}
|
|
53
|
+
let content = (0, fileio_1.readFile)(changelogPath);
|
|
54
|
+
const date = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
|
|
55
|
+
const entry = `### ${date} — ${message.trim()}\nFiles: \n`;
|
|
56
|
+
// Drop the "no entries yet" placeholder if present.
|
|
57
|
+
content = content.replace(EMPTY_PLACEHOLDER, '');
|
|
58
|
+
const headingMatch = content.match(CHANGELOG_HEADING);
|
|
59
|
+
if (headingMatch && headingMatch.index !== undefined) {
|
|
60
|
+
const insertAt = headingMatch.index + headingMatch[0].length;
|
|
61
|
+
const before = content.slice(0, insertAt).replace(/\s*$/, '');
|
|
62
|
+
const after = content.slice(insertAt).replace(/^\s*/, '');
|
|
63
|
+
content = `${before}\n\n${entry}\n${after}`.replace(/\n{3,}/g, '\n\n');
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// No heading found — prepend.
|
|
67
|
+
content = `## Changelog\n\n${entry}\n${content}`;
|
|
68
|
+
}
|
|
69
|
+
(0, fileio_1.writeFile)(changelogPath, content.replace(/\s*$/, '') + '\n');
|
|
70
|
+
console.log(`Logged entry for ${date}: ${message.trim()}`);
|
|
71
|
+
const activeCount = countActiveEntries(content);
|
|
72
|
+
if (activeCount > 10) {
|
|
73
|
+
console.log('');
|
|
74
|
+
console.log(`You now have ${activeCount} active entries. ` +
|
|
75
|
+
'Consider running `vibekit prune` to trim resolved [DONE] entries.');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Count entries (lines starting with "### ") that are NOT tagged [DONE].
|
|
80
|
+
*/
|
|
81
|
+
function countActiveEntries(content) {
|
|
82
|
+
const lines = content.split('\n');
|
|
83
|
+
let count = 0;
|
|
84
|
+
for (const line of lines) {
|
|
85
|
+
if (/^###\s+/.test(line) && !/\[DONE\]/i.test(line)) {
|
|
86
|
+
count++;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return count;
|
|
90
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.packsAddCommand = packsAddCommand;
|
|
37
|
+
exports.packsRemoveCommand = packsRemoveCommand;
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const fileio_1 = require("../utils/fileio");
|
|
40
|
+
const markers_1 = require("../utils/markers");
|
|
41
|
+
function loadAgents() {
|
|
42
|
+
const cwd = process.cwd();
|
|
43
|
+
const agentsPath = path.join(cwd, 'AGENTS.md');
|
|
44
|
+
if (!(0, fileio_1.exists)(agentsPath)) {
|
|
45
|
+
throw new Error('AGENTS.md not found. Run `vibekit init` first.');
|
|
46
|
+
}
|
|
47
|
+
return { agentsPath, content: (0, fileio_1.readFile)(agentsPath) };
|
|
48
|
+
}
|
|
49
|
+
function packsAddCommand(name) {
|
|
50
|
+
if (!name) {
|
|
51
|
+
throw new Error('Usage: vibekit packs add <name>');
|
|
52
|
+
}
|
|
53
|
+
const packFile = (0, fileio_1.assetPath)('packs', `${name}.md`);
|
|
54
|
+
if (!(0, fileio_1.exists)(packFile)) {
|
|
55
|
+
throw new Error(`Pack "${name}" does not exist in packs/. ` +
|
|
56
|
+
'See principles-catalog.md for available packs, or create packs/' +
|
|
57
|
+
`${name}.md with matching <!-- pack:${name}:start --> markers.`);
|
|
58
|
+
}
|
|
59
|
+
const { agentsPath, content } = loadAgents();
|
|
60
|
+
if ((0, markers_1.hasPack)(content, name)) {
|
|
61
|
+
console.log(`Pack "${name}" is already active in AGENTS.md.`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const block = (0, markers_1.extractBlock)((0, fileio_1.readFile)(packFile), name);
|
|
65
|
+
let updated = (0, markers_1.insertPack)(content, block);
|
|
66
|
+
updated = (0, markers_1.setActivePacksLine)(updated, (0, markers_1.listActivePacks)(updated));
|
|
67
|
+
(0, fileio_1.writeFile)(agentsPath, updated);
|
|
68
|
+
console.log(`Added pack "${name}" to AGENTS.md.`);
|
|
69
|
+
}
|
|
70
|
+
function packsRemoveCommand(name) {
|
|
71
|
+
if (!name) {
|
|
72
|
+
throw new Error('Usage: vibekit packs remove <name>');
|
|
73
|
+
}
|
|
74
|
+
const { agentsPath, content } = loadAgents();
|
|
75
|
+
if (!(0, markers_1.hasPack)(content, name)) {
|
|
76
|
+
throw new Error(`Pack "${name}" is not currently active in AGENTS.md. ` +
|
|
77
|
+
`Active packs: ${(0, markers_1.listActivePacks)(content).join(', ') || '(none)'}.`);
|
|
78
|
+
}
|
|
79
|
+
let updated = (0, markers_1.removePack)(content, name);
|
|
80
|
+
updated = (0, markers_1.setActivePacksLine)(updated, (0, markers_1.listActivePacks)(updated));
|
|
81
|
+
(0, fileio_1.writeFile)(agentsPath, updated);
|
|
82
|
+
console.log(`Removed pack "${name}" from AGENTS.md.`);
|
|
83
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.pruneCommand = pruneCommand;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fileio_1 = require("../utils/fileio");
|
|
39
|
+
/**
|
|
40
|
+
* Remove all [DONE]-tagged entries except the 5 most recent ones.
|
|
41
|
+
*
|
|
42
|
+
* Entries are blocks starting at a line matching "### " and running until the
|
|
43
|
+
* next "### " line (or end of file). "Most recent" means earliest in the file,
|
|
44
|
+
* since the changelog keeps newest entries on top.
|
|
45
|
+
*/
|
|
46
|
+
function pruneCommand() {
|
|
47
|
+
const cwd = process.cwd();
|
|
48
|
+
const changelogPath = path.join(cwd, 'CHANGELOG.md');
|
|
49
|
+
if (!(0, fileio_1.exists)(changelogPath)) {
|
|
50
|
+
throw new Error('CHANGELOG.md not found. Run `vibekit init` first.');
|
|
51
|
+
}
|
|
52
|
+
const content = (0, fileio_1.readFile)(changelogPath);
|
|
53
|
+
const lines = content.split('\n');
|
|
54
|
+
// Identify entry start indices.
|
|
55
|
+
const entryStarts = [];
|
|
56
|
+
for (let i = 0; i < lines.length; i++) {
|
|
57
|
+
if (/^###\s+/.test(lines[i])) {
|
|
58
|
+
entryStarts.push(i);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (entryStarts.length === 0) {
|
|
62
|
+
console.log('No changelog entries found — nothing to prune.');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const headerEnd = entryStarts[0];
|
|
66
|
+
const header = lines.slice(0, headerEnd).join('\n').replace(/\s*$/, '');
|
|
67
|
+
const entries = [];
|
|
68
|
+
for (let e = 0; e < entryStarts.length; e++) {
|
|
69
|
+
const start = entryStarts[e];
|
|
70
|
+
const end = e + 1 < entryStarts.length ? entryStarts[e + 1] : lines.length;
|
|
71
|
+
const text = lines.slice(start, end).join('\n').replace(/\s*$/, '');
|
|
72
|
+
const done = /\[DONE\]/i.test(lines[start]);
|
|
73
|
+
entries.push({ text, done });
|
|
74
|
+
}
|
|
75
|
+
// Keep the 5 most recent [DONE] entries (topmost = most recent).
|
|
76
|
+
let doneKept = 0;
|
|
77
|
+
const kept = [];
|
|
78
|
+
let removed = 0;
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
if (entry.done) {
|
|
81
|
+
if (doneKept < 5) {
|
|
82
|
+
doneKept++;
|
|
83
|
+
kept.push(entry);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
removed++;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
kept.push(entry);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (removed === 0) {
|
|
94
|
+
console.log('No prunable [DONE] entries (kept the 5 most recent).');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const body = kept.map((e) => e.text).join('\n\n');
|
|
98
|
+
const rebuilt = `${header}\n\n${body}\n`.replace(/\n{3,}/g, '\n\n');
|
|
99
|
+
(0, fileio_1.writeFile)(changelogPath, rebuilt);
|
|
100
|
+
console.log(`Pruned ${removed} resolved [DONE] ${removed === 1 ? 'entry' : 'entries'} (kept the 5 most recent).`);
|
|
101
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.syncCommand = syncCommand;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fileio_1 = require("../utils/fileio");
|
|
39
|
+
/**
|
|
40
|
+
* Mirror AGENTS.md to the filenames used by tools that don't yet read
|
|
41
|
+
* AGENTS.md natively.
|
|
42
|
+
*/
|
|
43
|
+
function syncCommand() {
|
|
44
|
+
const cwd = process.cwd();
|
|
45
|
+
const agentsPath = path.join(cwd, 'AGENTS.md');
|
|
46
|
+
if (!(0, fileio_1.exists)(agentsPath)) {
|
|
47
|
+
throw new Error('AGENTS.md not found. Run `vibekit init` first.');
|
|
48
|
+
}
|
|
49
|
+
const content = (0, fileio_1.readFile)(agentsPath);
|
|
50
|
+
const targets = [
|
|
51
|
+
path.join(cwd, 'CLAUDE.md'),
|
|
52
|
+
path.join(cwd, '.windsurfrules'),
|
|
53
|
+
path.join(cwd, '.github', 'copilot-instructions.md'),
|
|
54
|
+
];
|
|
55
|
+
(0, fileio_1.ensureDir)(path.join(cwd, '.github'));
|
|
56
|
+
for (const target of targets) {
|
|
57
|
+
(0, fileio_1.writeFile)(target, content);
|
|
58
|
+
}
|
|
59
|
+
console.log('Synced AGENTS.md to:');
|
|
60
|
+
console.log(' - CLAUDE.md');
|
|
61
|
+
console.log(' - .windsurfrules');
|
|
62
|
+
console.log(' - .github/copilot-instructions.md');
|
|
63
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.readFile = readFile;
|
|
37
|
+
exports.writeFile = writeFile;
|
|
38
|
+
exports.exists = exists;
|
|
39
|
+
exports.ensureDir = ensureDir;
|
|
40
|
+
exports.assetPath = assetPath;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
/**
|
|
44
|
+
* Read a UTF-8 text file. Throws a clear error if it doesn't exist.
|
|
45
|
+
*/
|
|
46
|
+
function readFile(filePath) {
|
|
47
|
+
if (!fs.existsSync(filePath)) {
|
|
48
|
+
throw new Error(`File not found: ${filePath}`);
|
|
49
|
+
}
|
|
50
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Write a UTF-8 text file, creating parent directories if needed.
|
|
54
|
+
*/
|
|
55
|
+
function writeFile(filePath, content) {
|
|
56
|
+
const dir = path.dirname(filePath);
|
|
57
|
+
if (!fs.existsSync(dir)) {
|
|
58
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
59
|
+
}
|
|
60
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* True if a file or directory exists at the given path.
|
|
64
|
+
*/
|
|
65
|
+
function exists(filePath) {
|
|
66
|
+
return fs.existsSync(filePath);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Ensure a directory exists, creating it (and parents) if necessary.
|
|
70
|
+
*/
|
|
71
|
+
function ensureDir(dirPath) {
|
|
72
|
+
if (!fs.existsSync(dirPath)) {
|
|
73
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Resolve a path inside the packaged template/pack assets.
|
|
78
|
+
*
|
|
79
|
+
* When compiled, this file lives in dist/utils/. The templates/ and packs/
|
|
80
|
+
* folders ship at the package root, one level above dist/. We walk upward
|
|
81
|
+
* until we find a directory that contains both, so the CLI works whether it
|
|
82
|
+
* runs from source (ts-node) or from the published dist build.
|
|
83
|
+
*/
|
|
84
|
+
function assetPath(...segments) {
|
|
85
|
+
let dir = __dirname;
|
|
86
|
+
for (let i = 0; i < 6; i++) {
|
|
87
|
+
if (fs.existsSync(path.join(dir, 'templates')) &&
|
|
88
|
+
fs.existsSync(path.join(dir, 'packs'))) {
|
|
89
|
+
return path.join(dir, ...segments);
|
|
90
|
+
}
|
|
91
|
+
const parent = path.dirname(dir);
|
|
92
|
+
if (parent === dir) {
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
dir = parent;
|
|
96
|
+
}
|
|
97
|
+
throw new Error('Could not locate Vibekit assets (templates/ and packs/). ' +
|
|
98
|
+
'The package may be installed incorrectly.');
|
|
99
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Utilities for parsing, inserting, and removing pack marker blocks of the form:
|
|
4
|
+
*
|
|
5
|
+
* <!-- pack:<name>:start -->
|
|
6
|
+
* ...content...
|
|
7
|
+
* <!-- pack:<name>:end -->
|
|
8
|
+
*
|
|
9
|
+
* These markers live inside AGENTS.md and the packs/*.md source files.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PACKS_PLACEHOLDER = exports.PACK_PLACEHOLDER = void 0;
|
|
13
|
+
exports.packBlockRegex = packBlockRegex;
|
|
14
|
+
exports.anyPackBlockRegex = anyPackBlockRegex;
|
|
15
|
+
exports.listActivePacks = listActivePacks;
|
|
16
|
+
exports.hasPack = hasPack;
|
|
17
|
+
exports.extractBlock = extractBlock;
|
|
18
|
+
exports.removePack = removePack;
|
|
19
|
+
exports.insertPack = insertPack;
|
|
20
|
+
exports.setActivePacksLine = setActivePacksLine;
|
|
21
|
+
exports.PACK_PLACEHOLDER = '{{PACK_BLOCKS_INSERTED_HERE}}';
|
|
22
|
+
exports.PACKS_PLACEHOLDER = '{{PACKS}}';
|
|
23
|
+
const ACTIVE_PACKS_LINE = /^### Active principle packs:.*$/m;
|
|
24
|
+
/**
|
|
25
|
+
* Build a regex that matches a single pack block (start marker through end
|
|
26
|
+
* marker, inclusive) for the given pack name.
|
|
27
|
+
*/
|
|
28
|
+
function packBlockRegex(name) {
|
|
29
|
+
const escaped = escapeRegExp(name);
|
|
30
|
+
return new RegExp(`<!--\\s*pack:${escaped}:start\\s*-->[\\s\\S]*?<!--\\s*pack:${escaped}:end\\s*-->`, 'm');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Global regex matching any pack block, capturing the pack name in group 1.
|
|
34
|
+
*/
|
|
35
|
+
function anyPackBlockRegex() {
|
|
36
|
+
return /<!--\s*pack:([a-zA-Z0-9_-]+):start\s*-->[\s\S]*?<!--\s*pack:\1:end\s*-->/g;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Return the list of active pack names found in the given content, in order.
|
|
40
|
+
*/
|
|
41
|
+
function listActivePacks(content) {
|
|
42
|
+
const names = [];
|
|
43
|
+
const regex = anyPackBlockRegex();
|
|
44
|
+
let match;
|
|
45
|
+
while ((match = regex.exec(content)) !== null) {
|
|
46
|
+
names.push(match[1]);
|
|
47
|
+
}
|
|
48
|
+
return names;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* True if the named pack block is present in content.
|
|
52
|
+
*/
|
|
53
|
+
function hasPack(content, name) {
|
|
54
|
+
return packBlockRegex(name).test(content);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extract the marker block for a pack from a packs/*.md source file.
|
|
58
|
+
* Falls back to the raw (trimmed) file content if no markers are present.
|
|
59
|
+
*/
|
|
60
|
+
function extractBlock(packFileContent, name) {
|
|
61
|
+
const match = packFileContent.match(packBlockRegex(name));
|
|
62
|
+
if (match) {
|
|
63
|
+
return match[0].trim();
|
|
64
|
+
}
|
|
65
|
+
return packFileContent.trim();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Remove a pack block (and surrounding blank lines) from content.
|
|
69
|
+
*/
|
|
70
|
+
function removePack(content, name) {
|
|
71
|
+
const regex = packBlockRegex(name);
|
|
72
|
+
if (!regex.test(content)) {
|
|
73
|
+
return content;
|
|
74
|
+
}
|
|
75
|
+
const without = content.replace(regex, '');
|
|
76
|
+
return collapseBlankLines(without);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Insert a pack block into AGENTS.md content.
|
|
80
|
+
*
|
|
81
|
+
* If other pack blocks already exist, the new block is inserted immediately
|
|
82
|
+
* after the last existing pack block. Otherwise it replaces the
|
|
83
|
+
* {{PACK_BLOCKS_INSERTED_HERE}} placeholder, or is appended after the
|
|
84
|
+
* Verify-before-trust section if the placeholder is gone.
|
|
85
|
+
*/
|
|
86
|
+
function insertPack(content, block) {
|
|
87
|
+
// If the placeholder still exists (fresh template), replace it.
|
|
88
|
+
if (content.includes(exports.PACK_PLACEHOLDER)) {
|
|
89
|
+
return content.replace(exports.PACK_PLACEHOLDER, `${block}\n`);
|
|
90
|
+
}
|
|
91
|
+
const activePacks = listLastBlockMatch(content);
|
|
92
|
+
if (activePacks) {
|
|
93
|
+
const insertAt = activePacks.index + activePacks.length;
|
|
94
|
+
return (content.slice(0, insertAt) + `\n\n${block}` + content.slice(insertAt));
|
|
95
|
+
}
|
|
96
|
+
// No existing packs and no placeholder: insert after Verify-before-trust.
|
|
97
|
+
const verifyRegex = /(### Verify-before-trust[\s\S]*?source of truth — not the note\.)/m;
|
|
98
|
+
const verifyMatch = content.match(verifyRegex);
|
|
99
|
+
if (verifyMatch && verifyMatch.index !== undefined) {
|
|
100
|
+
const insertAt = verifyMatch.index + verifyMatch[0].length;
|
|
101
|
+
return (content.slice(0, insertAt) + `\n\n${block}` + content.slice(insertAt));
|
|
102
|
+
}
|
|
103
|
+
// Last resort: append to the end.
|
|
104
|
+
return `${content.trimEnd()}\n\n${block}\n`;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Replace (or set) the "Active principle packs" line with the given names.
|
|
108
|
+
*/
|
|
109
|
+
function setActivePacksLine(content, names) {
|
|
110
|
+
const value = names.length > 0 ? names.join(', ') : '(none)';
|
|
111
|
+
const line = `### Active principle packs: ${value}`;
|
|
112
|
+
if (ACTIVE_PACKS_LINE.test(content)) {
|
|
113
|
+
return content.replace(ACTIVE_PACKS_LINE, line);
|
|
114
|
+
}
|
|
115
|
+
return content;
|
|
116
|
+
}
|
|
117
|
+
/** Find the last pack block and return its index and length. */
|
|
118
|
+
function listLastBlockMatch(content) {
|
|
119
|
+
const regex = anyPackBlockRegex();
|
|
120
|
+
let match;
|
|
121
|
+
let last = null;
|
|
122
|
+
while ((match = regex.exec(content)) !== null) {
|
|
123
|
+
last = { index: match.index, length: match[0].length };
|
|
124
|
+
}
|
|
125
|
+
return last;
|
|
126
|
+
}
|
|
127
|
+
function collapseBlankLines(content) {
|
|
128
|
+
return content.replace(/\n{3,}/g, '\n\n');
|
|
129
|
+
}
|
|
130
|
+
function escapeRegExp(value) {
|
|
131
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
132
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@govindchaudhary/vibekit",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Make vibe coding accurate: 3 persistent markdown files (AGENTS.md, CHANGELOG.md, DECISIONS.md) that give any AI coding assistant lean, verifiable context — a lightweight alternative to heavyweight Spec-Driven Development.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"vibe-coding",
|
|
7
|
+
"ai-coding",
|
|
8
|
+
"agents-md",
|
|
9
|
+
"developer-tools",
|
|
10
|
+
"context",
|
|
11
|
+
"copilot",
|
|
12
|
+
"claude",
|
|
13
|
+
"cursor",
|
|
14
|
+
"windsurf",
|
|
15
|
+
"spec-driven-development"
|
|
16
|
+
],
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"type": "commonjs",
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"bin": {
|
|
23
|
+
"vibekit": "dist/cli.js"
|
|
24
|
+
},
|
|
25
|
+
"main": "dist/cli.js",
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"templates",
|
|
29
|
+
"packs",
|
|
30
|
+
"principles-catalog.md",
|
|
31
|
+
"README.md",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc",
|
|
36
|
+
"prepublishOnly": "npm run build",
|
|
37
|
+
"start": "node dist/cli.js"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"commander": "^12.1.0",
|
|
41
|
+
"prompts": "^2.4.2"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^20.14.0",
|
|
45
|
+
"@types/prompts": "^2.4.9",
|
|
46
|
+
"typescript": "^5.4.5"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18"
|
|
50
|
+
}
|
|
51
|
+
}
|
package/packs/core.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<!-- pack:core:start -->
|
|
2
|
+
### Core Principles
|
|
3
|
+
- Single Responsibility: one function/module does one job
|
|
4
|
+
- DRY: don't duplicate logic, extract shared code
|
|
5
|
+
- KISS: simplest solution that meets the requirement — no premature abstraction
|
|
6
|
+
- Fail fast: validate inputs early, raise clear errors instead of failing silently
|
|
7
|
+
<!-- pack:core:end -->
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<!-- pack:data-eng:start -->
|
|
2
|
+
### Data Engineering Principles
|
|
3
|
+
- Idempotency: re-running a job with the same input must not duplicate side effects
|
|
4
|
+
- Validate at the boundary: enforce schema on ingestion, fail loudly on mismatch — never silently coerce
|
|
5
|
+
- Separate Extract / Transform / Load: don't mix stages in one function
|
|
6
|
+
- Immutable raw data: never mutate ingested source data; transformations always produce new datasets
|
|
7
|
+
- Reproducibility: every run should be deterministic and log enough (row counts, versions, timestamps) to debug without re-running
|
|
8
|
+
<!-- pack:data-eng:end -->
|
package/packs/dev.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<!-- pack:dev:start -->
|
|
2
|
+
### SOLID Principles
|
|
3
|
+
- Open/Closed: extend behavior with new code; don't modify working code to add a feature
|
|
4
|
+
- Liskov Substitution: a subtype must be usable anywhere its base type is, without surprises
|
|
5
|
+
- Interface Segregation: small focused interfaces beat one large general-purpose one
|
|
6
|
+
- Dependency Inversion: depend on abstractions, not concrete implementations
|
|
7
|
+
<!-- pack:dev:end -->
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Principles Catalog
|
|
2
|
+
|
|
3
|
+
> A human-readable menu of the principle packs Vibekit ships with.
|
|
4
|
+
>
|
|
5
|
+
> **This file is pure documentation.** It is copied into your repo for reference
|
|
6
|
+
> only and is **never loaded or referenced by any AI assistant**. The packs that
|
|
7
|
+
> AI actually reads live inside `AGENTS.md`. Use this catalog to decide which
|
|
8
|
+
> packs to add via `vibekit packs add <name>`.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## How to read this
|
|
13
|
+
|
|
14
|
+
Each pack below maps 1:1 to a file in `packs/<name>.md`. When a pack is active,
|
|
15
|
+
its block is inserted into `AGENTS.md` between markers like
|
|
16
|
+
`<!-- pack:<name>:start -->` and `<!-- pack:<name>:end -->`.
|
|
17
|
+
|
|
18
|
+
To add a pack:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
vibekit packs add dev
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
To remove one:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
vibekit packs remove data-eng
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Available packs
|
|
33
|
+
|
|
34
|
+
### `core` — Core Principles *(included by default)*
|
|
35
|
+
|
|
36
|
+
Foundational rules that apply to almost any codebase.
|
|
37
|
+
|
|
38
|
+
- **Single Responsibility** — one function/module does one job
|
|
39
|
+
- **DRY** — don't duplicate logic, extract shared code
|
|
40
|
+
- **KISS** — simplest solution that meets the requirement; no premature abstraction
|
|
41
|
+
- **Fail fast** — validate inputs early, raise clear errors instead of failing silently
|
|
42
|
+
|
|
43
|
+
### `dev` — SOLID Principles
|
|
44
|
+
|
|
45
|
+
For general application/software development.
|
|
46
|
+
|
|
47
|
+
- **Open/Closed** — extend behavior with new code; don't modify working code to add a feature
|
|
48
|
+
- **Liskov Substitution** — a subtype must be usable anywhere its base type is, without surprises
|
|
49
|
+
- **Interface Segregation** — small focused interfaces beat one large general-purpose one
|
|
50
|
+
- **Dependency Inversion** — depend on abstractions, not concrete implementations
|
|
51
|
+
|
|
52
|
+
### `data-eng` — Data Engineering Principles
|
|
53
|
+
|
|
54
|
+
For pipelines, ETL/ELT, and analytics engineering.
|
|
55
|
+
|
|
56
|
+
- **Idempotency** — re-running a job with the same input must not duplicate side effects
|
|
57
|
+
- **Validate at the boundary** — enforce schema on ingestion, fail loudly on mismatch; never silently coerce
|
|
58
|
+
- **Separate Extract / Transform / Load** — don't mix stages in one function
|
|
59
|
+
- **Immutable raw data** — never mutate ingested source data; transformations always produce new datasets
|
|
60
|
+
- **Reproducibility** — every run should be deterministic and log enough (row counts, versions, timestamps) to debug without re-running
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Adding your own custom pack
|
|
65
|
+
|
|
66
|
+
1. Create a new file in `packs/`, e.g. `packs/security.md`.
|
|
67
|
+
2. Wrap its content in start/end markers matching the file name:
|
|
68
|
+
|
|
69
|
+
```markdown
|
|
70
|
+
<!-- pack:security:start -->
|
|
71
|
+
### Security Principles
|
|
72
|
+
- Least privilege: grant the minimum access required
|
|
73
|
+
- Never trust client input: validate and sanitize at every boundary
|
|
74
|
+
<!-- pack:security:end -->
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
3. Activate it:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
vibekit packs add security
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The marker name (`security`) must match the file name (`security.md`).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
> Stable context and coding principles for AI assistants working in this repo.
|
|
4
|
+
> This file is read automatically by most modern AI coding tools. Keep it accurate.
|
|
5
|
+
|
|
6
|
+
### Active principle packs: {{PACKS}}
|
|
7
|
+
(See principles-catalog.md in repo root for other available packs)
|
|
8
|
+
|
|
9
|
+
### Verify-before-trust
|
|
10
|
+
Treat CHANGELOG.md and DECISIONS.md as hints, not ground truth. Before relying
|
|
11
|
+
on an entry, confirm the referenced file/function still matches what's described.
|
|
12
|
+
If it doesn't, the current code is the source of truth — not the note.
|
|
13
|
+
|
|
14
|
+
{{PACK_BLOCKS_INSERTED_HERE}}
|
|
15
|
+
|
|
16
|
+
### Project Stack
|
|
17
|
+
[Fill in: languages, frameworks, key libraries]
|
|
18
|
+
|
|
19
|
+
### Conventions
|
|
20
|
+
[Fill in: naming, testing approach, file structure — be specific and verifiable,
|
|
21
|
+
e.g. "2-space indentation" not "clean formatting". Where a rule isn't obvious,
|
|
22
|
+
add a one-line reason, e.g. "Use X instead of Y because Y is deprecated."]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
FORMAT: newest entry first. Each entry: exact date (never "yesterday"/"recently"),
|
|
3
|
+
what changed, why, files/functions touched. Mark resolved entries [DONE] —
|
|
4
|
+
the prune command deletes [DONE] entries older than the most recent 5.
|
|
5
|
+
Keep this file under ~10 active entries at all times.
|
|
6
|
+
-->
|
|
7
|
+
|
|
8
|
+
## Changelog
|
|
9
|
+
|
|
10
|
+
(no entries yet — run `vibekit log "description"` after your first change)
|