@vibecompass/vibecompass 0.1.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.
@@ -0,0 +1,404 @@
1
+ import { access, mkdir, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { resolveWorkflowSettings } from './workflow.js';
4
+
5
+ export async function scaffoldInitFiles(options) {
6
+ const createdFiles = [];
7
+ const skippedFiles = [];
8
+
9
+ if (!options.workflow) {
10
+ return {
11
+ contextFilePath: null,
12
+ createdFiles,
13
+ skippedFiles,
14
+ };
15
+ }
16
+
17
+ await mkdir(path.join(options.rootDir, 'architecture'), { recursive: true });
18
+ await mkdir(path.join(options.rootDir, 'decisions'), { recursive: true });
19
+ await mkdir(path.join(options.rootDir, 'sessions'), { recursive: true });
20
+
21
+ const contextFilePath = path.join(options.rootDir, 'context.md');
22
+ // context.md is a derived artifact owned by the package; regenerate it on rerun.
23
+ await writeFile(contextFilePath, generateContextMarkdown(options), 'utf8');
24
+ createdFiles.push(contextFilePath);
25
+
26
+ const workflowFiles = [
27
+ {
28
+ path: path.join(options.rootDir, 'architecture', 'README.md'),
29
+ content: generateArchitectureGuide(options.projectConfig),
30
+ },
31
+ {
32
+ path: path.join(options.rootDir, 'decisions', 'README.md'),
33
+ content: generateDecisionsGuide(options.projectConfig),
34
+ },
35
+ {
36
+ path: path.join(options.rootDir, 'sessions', 'README.md'),
37
+ content: generateSessionsGuide(options.projectConfig),
38
+ },
39
+ ];
40
+
41
+ for (const file of workflowFiles) {
42
+ const outcome = await writeIfMissing(file.path, file.content);
43
+ if (outcome.created) {
44
+ createdFiles.push(file.path);
45
+ } else {
46
+ skippedFiles.push(file.path);
47
+ }
48
+ }
49
+
50
+ const bootstrapFiles = [];
51
+ if (options.claude) {
52
+ bootstrapFiles.push({
53
+ path: path.join(options.toolingRootDir, 'CLAUDE.md'),
54
+ content: generateClaudeTemplate(options),
55
+ });
56
+ }
57
+
58
+ if (options.agents) {
59
+ bootstrapFiles.push({
60
+ path: path.join(options.toolingRootDir, 'AGENTS.md'),
61
+ content: generateAgentsTemplate(options),
62
+ });
63
+ }
64
+
65
+ for (const file of bootstrapFiles) {
66
+ const outcome = await writeIfMissing(file.path, file.content);
67
+ if (outcome.created) {
68
+ createdFiles.push(file.path);
69
+ } else {
70
+ skippedFiles.push(file.path);
71
+ }
72
+ }
73
+
74
+ return {
75
+ contextFilePath,
76
+ createdFiles,
77
+ skippedFiles,
78
+ };
79
+ }
80
+
81
+ async function writeIfMissing(filePath, content) {
82
+ if (await fileExists(filePath)) {
83
+ return { created: false };
84
+ }
85
+
86
+ await mkdir(path.dirname(filePath), { recursive: true });
87
+ await writeFile(filePath, content, 'utf8');
88
+ return { created: true };
89
+ }
90
+
91
+ async function fileExists(filePath) {
92
+ try {
93
+ await access(filePath);
94
+ return true;
95
+ } catch {
96
+ return false;
97
+ }
98
+ }
99
+
100
+ function generateContextMarkdown(options) {
101
+ const projectName = options.projectConfig.name;
102
+ const rootRelativePath = options.rootRelativePath;
103
+ const workflow = resolveWorkflowSettings(options.projectConfig);
104
+ const repos = options.projectConfig.repos
105
+ .map((repo) => `- \`${repo.id}\` → ${repo.remote}`)
106
+ .join('\n');
107
+
108
+ return `# Project Context — ${projectName}
109
+
110
+ This workspace uses VibeCompass project memory rooted at \`${rootRelativePath}\`.
111
+
112
+ ## Canonical files
113
+ - \`${rootRelativePath}/project.yaml\` — machine-oriented project metadata
114
+ - \`${rootRelativePath}/architecture/\` — canonical architecture docs
115
+ - \`${rootRelativePath}/decisions/\` — canonical decision log
116
+ - \`${rootRelativePath}/sessions/\` — finalized session notes
117
+
118
+ ## Derived and scratch files
119
+ - \`${rootRelativePath}/context.md\` — generated AI-facing workflow context
120
+ - \`${rootRelativePath}/state/manifest.json\` — machine-owned local state; do not hand-edit
121
+ - \`${rootRelativePath}/sessions/wip.md\` — active builder scratchpad during a session
122
+ - \`${rootRelativePath}/sessions/handoff.md\` — builder/reviewer relay during a session
123
+
124
+ ## Repos in scope
125
+ ${repos}
126
+
127
+ ## Session roles
128
+ | Trigger | Role | Owns session lifecycle? |
129
+ |---|---|---|
130
+ | "start session" | Builder | Yes — opens the session, keeps scratch files current, and writes the final session note |
131
+ | "join as reviewer" | Reviewer | No — reviews the builder's work, appends findings, and updates handoff guidance |
132
+
133
+ ## Session prompt commands
134
+ - \`start session\` — builder role trigger
135
+ - \`join as reviewer\` — reviewer role trigger
136
+ - \`review handoff\` — reviewer reads the latest finalized note, \`wip.md\`, \`handoff.md\`, and relevant diffs before appending findings
137
+ - \`address review\` — builder reads reviewer feedback in \`wip.md\` / \`handoff.md\`, responds inline, applies accepted changes, and refreshes the builder handoff
138
+
139
+ These are prompt commands for agent behavior, not \`vibecompass\` CLI subcommands.
140
+ Reviewer handback is explicit: the reviewer ends the pass by updating \`wip.md\` + \`handoff.md\` and then stopping. Builder close-out uses \`vibecompass close-session\`, which follows the workflow defaults recorded in \`${rootRelativePath}/project.yaml\`.
141
+
142
+ ## Workflow defaults
143
+ ${renderWorkflowDefaults(workflow)}
144
+
145
+ ## Session startup
146
+ 1. Read \`${rootRelativePath}/project.yaml\`.
147
+ 2. Read the latest finalized session note in \`${rootRelativePath}/sessions/\`.
148
+ 3. If present, read \`${rootRelativePath}/sessions/wip.md\`.
149
+ 4. If present, read \`${rootRelativePath}/sessions/handoff.md\`.
150
+ 5. Read the relevant docs under \`${rootRelativePath}/architecture/\` and \`${rootRelativePath}/decisions/\`.
151
+
152
+ ## Builder workflow
153
+ At session start, prefer running \`vibecompass start-session --working-on "..." \`.
154
+ If you manage files manually, create \`${rootRelativePath}/sessions/wip.md\` if it does not exist:
155
+
156
+ \`\`\`md
157
+ # WIP — YYYY-MM-DD (session N)
158
+
159
+ ## Working on
160
+
161
+ ## Log
162
+
163
+ ## Reviewer input needed
164
+
165
+ ## Review log
166
+ \`\`\`
167
+
168
+ Also create \`${rootRelativePath}/sessions/handoff.md\` if it does not exist:
169
+
170
+ \`\`\`md
171
+ # Handoff — YYYY-MM-DD (session N)
172
+
173
+ ## Builder → Reviewer
174
+
175
+ ### What changed
176
+
177
+ ### What needs review
178
+
179
+ ### What's next
180
+
181
+ ## Reviewer → Builder
182
+
183
+ ### Findings summary
184
+
185
+ ### Recommended next step
186
+ \`\`\`
187
+
188
+ During the session:
189
+ - append short summaries to \`wip.md\` after meaningful exchanges
190
+ - keep \`handoff.md\` current after substantive work blocks
191
+ - use \`address review\` when reviewer feedback lands so the builder resolves it from the latest \`wip.md\` / \`handoff.md\`
192
+ - stay in builder role through close-out; resolve or explicitly defer reviewer feedback before running \`vibecompass close-session\`
193
+ - record architectural decisions in \`${rootRelativePath}/decisions/\` before implementing them
194
+
195
+ At session close:
196
+ - prefer running \`vibecompass close-session --title "..." --completed "..." --model "..." --next-step "..."\`
197
+ - follow the stored close-session defaults from \`${rootRelativePath}/project.yaml\`
198
+ - finalize \`wip.md\` into \`${rootRelativePath}/sessions/YYYY-MM-DD-N-title.md\`
199
+ - delete \`wip.md\` and \`handoff.md\`
200
+ - refresh any affected architecture/decision docs
201
+
202
+ ## Reviewer workflow
203
+ - use \`review handoff\` when you want the reviewer to run the next review pass
204
+ - read the latest finalized session note, then \`wip.md\`, then \`handoff.md\`
205
+ - inspect the relevant code/docs diffs
206
+ - append findings under \`## Review log\` in \`wip.md\`
207
+ - write a concise baton-pass summary into \`handoff.md\`
208
+ - end the review pass after those file updates; there is no separate reviewer-exit step
209
+
210
+ ## Tooling note
211
+ \`CLAUDE.md\` and \`AGENTS.md\` are developer-owned starter files. If they exist,
212
+ they should point back to this context file and should not be overwritten
213
+ automatically by package commands.
214
+ `;
215
+ }
216
+
217
+ function generateArchitectureGuide(projectConfig) {
218
+ return `# Architecture
219
+
220
+ This directory holds canonical architecture docs for ${projectConfig.name}.
221
+
222
+ ## Recommended layout
223
+
224
+ \`\`\`text
225
+ architecture/<domain-slug>/<feature-slug>/<component>.md
226
+ \`\`\`
227
+
228
+ ## Required frontmatter
229
+ - \`domain\`
230
+ - \`feature\`
231
+ - \`component\`
232
+ - \`status\`
233
+ - optional \`repo\` or \`repos\`
234
+
235
+ ## Recommended sections
236
+ - \`## Description\`
237
+ - \`## Details\`
238
+ - \`## Next steps\`
239
+ - \`## Involved files\`
240
+
241
+ Each component doc is canonical. This README is only a convenience guide.
242
+ `;
243
+ }
244
+
245
+ function generateDecisionsGuide(projectConfig) {
246
+ return `# Decisions
247
+
248
+ Append-only decision log for ${projectConfig.name}.
249
+
250
+ ## Conventions
251
+ - store canonical decision entries in domain-grouped files such as \`cross-cutting.md\`
252
+ - never edit or delete prior decision entries
253
+ - use headings in the form \`### D-<number> — Title\`
254
+ - include \`**Timestamp:**\`, \`**Decision:**\`, and \`**Rationale:**\`
255
+
256
+ ## Example
257
+
258
+ \`\`\`md
259
+ ### D-001 — Example decision
260
+ **Timestamp:** YYYY-MM-DD HH:MM TZ
261
+ **Decision:** What was decided.
262
+ **Rationale:** Why this was the correct tradeoff.
263
+ \`\`\`
264
+
265
+ This README is guidance only; canonical decision content lives in the domain files.
266
+ `;
267
+ }
268
+
269
+ function generateSessionsGuide(projectConfig) {
270
+ return `# Sessions
271
+
272
+ Finalized session notes for ${projectConfig.name} live here.
273
+
274
+ ## Finalized session note format
275
+ - recommended filename: \`YYYY-MM-DD-N-title.md\`
276
+ - recommended H1: \`# Session — YYYY-MM-DD-N — Title\`
277
+
278
+ ## Recommended sections
279
+ - \`## What we worked on\`
280
+ - \`## Completed\`
281
+ - \`## Decisions made\`
282
+ - \`## Models used\`
283
+ - \`## Blockers / open questions\`
284
+ - \`## Next session should start with\`
285
+
286
+ ## Active-session scratch files
287
+ - \`wip.md\` — builder scratchpad during an active session
288
+ - \`handoff.md\` — reviewer/builder baton-pass during an active session
289
+
290
+ Those scratch files are session-scoped working artifacts, not finalized history.
291
+ `;
292
+ }
293
+
294
+ function generateClaudeTemplate(options) {
295
+ const workflow = resolveWorkflowSettings(options.projectConfig);
296
+
297
+ return `# ${options.projectConfig.name} Workspace
298
+
299
+ Read \`${options.contextRelativeToToolingRoot}\` before doing substantive work.
300
+
301
+ ## Session roles
302
+
303
+ | Trigger | Role | Owns session lifecycle? |
304
+ |---|---|---|
305
+ | "start session" | Builder | Yes |
306
+ | "join as reviewer" | Reviewer | No |
307
+
308
+ ## Prompt commands
309
+
310
+ - \`start session\` — builder role trigger
311
+ - \`join as reviewer\` — reviewer role trigger
312
+ - \`review handoff\` — reviewer reads the latest finalized note, \`wip.md\`, \`handoff.md\`, and relevant diffs before appending findings
313
+ - \`address review\` — builder reads reviewer feedback in \`wip.md\` / \`handoff.md\`, responds inline, applies accepted changes, and refreshes the builder handoff
314
+
315
+ These are prompt commands for agent behavior, not \`vibecompass\` CLI subcommands.
316
+ Reviewer handback is explicit: the reviewer ends the pass by updating \`${options.rootRelativePath}/sessions/wip.md\` + \`${options.rootRelativePath}/sessions/handoff.md\` and then stopping. Builder close-out uses \`vibecompass close-session\`, which follows the workflow defaults recorded in \`${options.rootRelativePath}/project.yaml\`.
317
+
318
+ ## Current session
319
+
320
+ **Update this block at the start and end of every session.**
321
+
322
+ \`\`\`
323
+ Date: not started
324
+ Working on: Session not started yet.
325
+ Last thing completed: Project memory bootstrap completed.
326
+ Blockers: None recorded.
327
+ Next session should: Read \`${options.contextRelativeToToolingRoot}\`, then open the first builder or reviewer session.
328
+ \`\`\`
329
+
330
+ ## Startup
331
+ - Read \`${options.contextRelativeToToolingRoot}\`
332
+ - Follow the builder/reviewer protocol defined there
333
+ - Use \`vibecompass start-session\` and \`vibecompass close-session\` to manage the active-session files when possible
334
+ - Keep \`${options.rootRelativePath}/sessions/wip.md\` and \`${options.rootRelativePath}/sessions/handoff.md\` current during an active session
335
+ - Workflow defaults:
336
+ ${renderWorkflowDefaults(workflow)}
337
+ `;
338
+ }
339
+
340
+ function generateAgentsTemplate(options) {
341
+ const workflow = resolveWorkflowSettings(options.projectConfig);
342
+
343
+ return `# ${options.projectConfig.name} Workspace
344
+
345
+ This workspace uses VibeCompass project memory rooted at \`${options.rootRelativePath}\`.
346
+
347
+ ## Session roles
348
+
349
+ | Trigger | Role | Owns session lifecycle? |
350
+ |---|---|---|
351
+ | "start session" | Builder | Yes — opens and closes the session lifecycle |
352
+ | "join as reviewer" | Reviewer | No — reviews the builder's work and updates the handoff |
353
+
354
+ ## Prompt commands
355
+
356
+ - \`start session\` — builder role trigger
357
+ - \`join as reviewer\` — reviewer role trigger
358
+ - \`review handoff\` — reviewer reads the latest finalized note, \`wip.md\`, \`handoff.md\`, and relevant diffs before appending findings
359
+ - \`address review\` — builder reads reviewer feedback in \`wip.md\` / \`handoff.md\`, responds inline, applies accepted changes, and refreshes the builder handoff
360
+
361
+ These are prompt commands for agent behavior, not \`vibecompass\` CLI subcommands.
362
+ Reviewer handback is explicit: the reviewer ends the pass by updating \`${options.rootRelativePath}/sessions/wip.md\` + \`${options.rootRelativePath}/sessions/handoff.md\` and then stopping. Builder close-out uses \`vibecompass close-session\`, which follows the workflow defaults recorded in \`${options.rootRelativePath}/project.yaml\`.
363
+
364
+ ## Startup
365
+ Before doing substantive work:
366
+ 1. Read \`${options.contextRelativeToToolingRoot}\`.
367
+ 2. Read the latest finalized session note under \`${options.rootRelativePath}/sessions/\`.
368
+ 3. If present, read \`${options.rootRelativePath}/sessions/wip.md\`.
369
+ 4. If present, read \`${options.rootRelativePath}/sessions/handoff.md\`.
370
+ 5. Read the relevant docs under \`${options.rootRelativePath}/architecture/\` and \`${options.rootRelativePath}/decisions/\`.
371
+
372
+ ## Working rule
373
+ Treat \`${options.contextRelativeToToolingRoot}\` as the local workflow source of truth for the builder/reviewer protocol and session scratch-file structure. When the package provides \`start-session\` / \`close-session\`, prefer those commands over hand-editing boilerplate.
374
+ - Workflow defaults:
375
+ ${renderWorkflowDefaults(workflow)}
376
+ `;
377
+ }
378
+
379
+ function renderWorkflowDefaults(workflow) {
380
+ const lines = [
381
+ `- reviewer handback: ${describeReviewerHandback(workflow)}`,
382
+ '- close-session: refresh any relevant architecture docs before finalizing the session',
383
+ '- close-session: refresh any relevant decision files before finalizing the session',
384
+ ];
385
+
386
+ if (workflow.closeSession.gitPublish) {
387
+ lines.push(
388
+ `- close-session: include a Git publish step after finalization using remote \`${workflow.closeSession.gitRemote}\``,
389
+ `- close-session: use commit message format \`${workflow.closeSession.commitTemplate}\` for VibeCompass-templated commits`,
390
+ );
391
+ } else {
392
+ lines.push('- close-session: no Git publish step is included by default');
393
+ }
394
+
395
+ return lines.join('\n');
396
+ }
397
+
398
+ function describeReviewerHandback(workflow) {
399
+ if (workflow.reviewerHandback === 'handoff-file') {
400
+ return 'update sessions/wip.md and sessions/handoff.md, then stop the review pass';
401
+ }
402
+
403
+ return workflow.reviewerHandback;
404
+ }