@vibecompass/vibecompass 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -13
- package/package.json +1 -1
- package/src/cli.js +161 -2
- package/src/docs-review.js +813 -0
- package/src/generators/agent-files/template.js +3 -3
- package/src/index.js +1 -0
- package/src/init.js +3 -1
- package/src/manifest.js +34 -1
- package/src/project-memory.js +1 -1
- package/src/scaffold.js +220 -14
- package/src/session.js +256 -25
- package/src/setup.js +54 -0
|
@@ -35,14 +35,14 @@ export function renderSharedInstructionBody(context, options = {}) {
|
|
|
35
35
|
'',
|
|
36
36
|
'## Workflow Rules',
|
|
37
37
|
'- VibeCompass active builder sessions are named lanes. Use one lane per active feature or workstream; finalized session notes are append-only history under `sessions/YYYY-MM-DD-N-title.md`.',
|
|
38
|
-
'- Use `start session` for builder work
|
|
39
|
-
'- Use `vibecompass start-session --id <lane-id>`
|
|
38
|
+
'- Use `start session` for builder work, `join as reviewer` for review work, and `close session` / `end session` when the builder is ready to close the selected lane.',
|
|
39
|
+
'- Use `vibecompass start-session --id <lane-id>` to open a named lane for every active feature or workstream.',
|
|
40
40
|
'- Use `vibecompass list-sessions` and `vibecompass switch-session <lane-id>` to inspect or change the current lane.',
|
|
41
41
|
'- Treat `sessions/active/index.yaml` as the current lane source of truth; tool-specific Current session blocks are continuity summaries.',
|
|
42
42
|
'- Use optional planning mode for risky or ambiguous work: read the same context, propose scope, and record the agreed plan in the selected lane `wip.md` before implementation.',
|
|
43
43
|
'- Use `review handoff` to ask a reviewer to inspect the active handoff.',
|
|
44
44
|
'- Use `address review` to process reviewer feedback from the selected lane `wip.md` and `handoff.md`.',
|
|
45
|
-
'- End the active builder session with `vibecompass close-session --session <lane-id>`; `vibecompass end-session`
|
|
45
|
+
'- End the active builder session with the `close session` prompt, which runs close-out and ends with `vibecompass close-session --session <lane-id>`; `end session` and `vibecompass end-session` are accepted aliases.',
|
|
46
46
|
'- If stale scratch files block `start-session`, read them first, then close, recover, move, or delete them intentionally before retrying.',
|
|
47
47
|
'- Keep decisions append-only in `decisions/`. Session notes may reference decisions, but decisions are the durable source of truth.',
|
|
48
48
|
'- Treat generated agent files as views. Update canonical VibeCompass project memory instead of editing managed regions.',
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { STATE_VERSION, generateStateManifest, writeStateManifest } from './manifest.js';
|
|
2
2
|
export { initializeProjectMemory } from './init.js';
|
|
3
|
+
export { preflightDocsReview } from './docs-review.js';
|
|
3
4
|
export { scanProjectMemory } from './project-memory.js';
|
|
4
5
|
export {
|
|
5
6
|
closeProjectSession,
|
package/src/init.js
CHANGED
|
@@ -21,10 +21,10 @@ export async function initializeProjectMemory(options) {
|
|
|
21
21
|
|
|
22
22
|
await writeProjectFile(projectFilePath, normalized.projectConfig, normalized.force);
|
|
23
23
|
const gitignoreUpdated = await ensureStateIgnored(gitignorePath);
|
|
24
|
+
const scaffoldResult = await scaffoldInitFiles(normalized.bootstrap);
|
|
24
25
|
const manifestResult = await writeStateManifest(normalized.rootDir, {
|
|
25
26
|
generatedAt: normalized.generatedAt,
|
|
26
27
|
});
|
|
27
|
-
const scaffoldResult = await scaffoldInitFiles(normalized.bootstrap);
|
|
28
28
|
|
|
29
29
|
return {
|
|
30
30
|
rootDir: normalized.rootDir,
|
|
@@ -137,6 +137,7 @@ function normalizeInitOptions(options) {
|
|
|
137
137
|
rootDir,
|
|
138
138
|
toolingRootDir,
|
|
139
139
|
projectConfig,
|
|
140
|
+
generatedAt: preparedOptions.generatedAt,
|
|
140
141
|
});
|
|
141
142
|
|
|
142
143
|
return {
|
|
@@ -182,6 +183,7 @@ function normalizeBootstrapOptions(bootstrap, context) {
|
|
|
182
183
|
contextRelativeToToolingRoot: toPosix(
|
|
183
184
|
path.relative(context.toolingRootDir, contextFilePath) || 'context.md',
|
|
184
185
|
),
|
|
186
|
+
generatedAt: context.generatedAt,
|
|
185
187
|
};
|
|
186
188
|
}
|
|
187
189
|
|
package/src/manifest.js
CHANGED
|
@@ -2,6 +2,7 @@ import { mkdir, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { localRevisionFromManifestHash, stableHash } from './hash.js';
|
|
4
4
|
import { scanProjectMemory } from './project-memory.js';
|
|
5
|
+
import { listProjectSessions } from './session.js';
|
|
5
6
|
|
|
6
7
|
export const STATE_VERSION = 1;
|
|
7
8
|
|
|
@@ -50,13 +51,18 @@ export function generateStateManifest(scanResult, options = {}) {
|
|
|
50
51
|
warning_count: warningCount,
|
|
51
52
|
},
|
|
52
53
|
documents: manifestDocuments,
|
|
54
|
+
...(options.activeSessions ? { active_sessions: options.activeSessions } : {}),
|
|
53
55
|
...(options.sync ? { sync: options.sync } : {}),
|
|
54
56
|
};
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
export async function writeStateManifest(rootDir, options = {}) {
|
|
58
60
|
const scanResult = await scanProjectMemory(rootDir);
|
|
59
|
-
const
|
|
61
|
+
const activeSessions = await readActiveSessionsForManifest(rootDir);
|
|
62
|
+
const manifest = generateStateManifest(scanResult, {
|
|
63
|
+
...options,
|
|
64
|
+
...(activeSessions ? { activeSessions } : {}),
|
|
65
|
+
});
|
|
60
66
|
const stateDir = path.join(rootDir, 'state');
|
|
61
67
|
const manifestPath = path.join(stateDir, 'manifest.json');
|
|
62
68
|
|
|
@@ -70,6 +76,33 @@ export async function writeStateManifest(rootDir, options = {}) {
|
|
|
70
76
|
};
|
|
71
77
|
}
|
|
72
78
|
|
|
79
|
+
async function readActiveSessionsForManifest(rootDir) {
|
|
80
|
+
const sessions = await listProjectSessions({ rootDir });
|
|
81
|
+
if (sessions.lanes.length === 0 && !sessions.current) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
current: sessions.current,
|
|
87
|
+
lanes: sessions.lanes.map((lane) => ({
|
|
88
|
+
id: lane.id,
|
|
89
|
+
status: lane.status ?? 'active',
|
|
90
|
+
working_on: lane.workingOn,
|
|
91
|
+
feature_slugs: lane.features ?? [],
|
|
92
|
+
repos: lane.repos ?? [],
|
|
93
|
+
claimed_paths: lane.claims ?? [],
|
|
94
|
+
started_at: lane.startedAt ?? null,
|
|
95
|
+
...(lane.decisionSnapshot
|
|
96
|
+
? {
|
|
97
|
+
decision_snapshot: {
|
|
98
|
+
highest_decision_id: lane.decisionSnapshot.highestDecisionId ?? null,
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
: {}),
|
|
102
|
+
})),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
73
106
|
function toIsoString(value) {
|
|
74
107
|
return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
|
|
75
108
|
}
|
package/src/project-memory.js
CHANGED
|
@@ -5,7 +5,7 @@ import { sha256Text } from './hash.js';
|
|
|
5
5
|
import { parseSimpleYaml } from './simple-yaml.js';
|
|
6
6
|
|
|
7
7
|
const PROJECT_FILE = 'project.yaml';
|
|
8
|
-
const NON_CANONICAL_DECISION_FILES = new Set(['INDEX.md', 'README.md']);
|
|
8
|
+
const NON_CANONICAL_DECISION_FILES = new Set(['EXAMPLE.md', 'INDEX.md', 'README.md']);
|
|
9
9
|
const NON_CANONICAL_SESSION_FILES = new Set(['wip.md', 'handoff.md', 'README.md']);
|
|
10
10
|
const NON_CANONICAL_ARCHITECTURE_FILES = new Set(['README.md']);
|
|
11
11
|
const VALID_MODES = new Set(['local-only', 'local-primary', 'hosted-only']);
|
package/src/scaffold.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { access, mkdir, writeFile } from 'node:fs/promises';
|
|
1
|
+
import { access, mkdir, readdir, writeFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { resolveWorkflowSettings } from './workflow.js';
|
|
4
4
|
|
|
@@ -6,6 +6,45 @@ export async function scaffoldInitFiles(options) {
|
|
|
6
6
|
const createdFiles = [];
|
|
7
7
|
const skippedFiles = [];
|
|
8
8
|
|
|
9
|
+
await mkdir(path.join(options.rootDir, 'architecture'), { recursive: true });
|
|
10
|
+
await mkdir(path.join(options.rootDir, 'decisions'), { recursive: true });
|
|
11
|
+
await mkdir(path.join(options.rootDir, 'sessions'), { recursive: true });
|
|
12
|
+
|
|
13
|
+
const starterFiles = [
|
|
14
|
+
{
|
|
15
|
+
path: path.join(options.rootDir, 'decisions', 'EXAMPLE.md'),
|
|
16
|
+
content: generateDecisionExample(options.projectConfig),
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
if (!(await hasCanonicalMarkdown(path.join(options.rootDir, 'architecture'), {
|
|
21
|
+
ignoredNames: new Set(['README.md']),
|
|
22
|
+
}))) {
|
|
23
|
+
starterFiles.push({
|
|
24
|
+
path: path.join(options.rootDir, 'architecture', 'overview', 'project-shape.md'),
|
|
25
|
+
content: generateStarterArchitectureDoc(options.projectConfig),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!(await hasCanonicalMarkdown(path.join(options.rootDir, 'sessions'), {
|
|
30
|
+
ignoredNames: new Set(['README.md', 'wip.md', 'handoff.md']),
|
|
31
|
+
ignoredDirectories: new Set(['active']),
|
|
32
|
+
}))) {
|
|
33
|
+
starterFiles.push({
|
|
34
|
+
path: path.join(options.rootDir, 'sessions', `${sessionDateFromGeneratedAt(options.generatedAt)}-1-project-memory-initialized.md`),
|
|
35
|
+
content: generateStarterSessionNote(options),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (const file of starterFiles) {
|
|
40
|
+
const outcome = await writeIfMissing(file.path, file.content);
|
|
41
|
+
if (outcome.created) {
|
|
42
|
+
createdFiles.push(file.path);
|
|
43
|
+
} else {
|
|
44
|
+
skippedFiles.push(file.path);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
9
48
|
if (!options.workflow) {
|
|
10
49
|
return {
|
|
11
50
|
contextFilePath: null,
|
|
@@ -14,10 +53,6 @@ export async function scaffoldInitFiles(options) {
|
|
|
14
53
|
};
|
|
15
54
|
}
|
|
16
55
|
|
|
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
56
|
const contextFilePath = path.join(options.rootDir, 'context.md');
|
|
22
57
|
// context.md is a derived artifact owned by the package; regenerate it on rerun.
|
|
23
58
|
await writeFile(contextFilePath, generateContextMarkdown(options), 'utf8');
|
|
@@ -97,6 +132,43 @@ async function fileExists(filePath) {
|
|
|
97
132
|
}
|
|
98
133
|
}
|
|
99
134
|
|
|
135
|
+
async function hasCanonicalMarkdown(directoryPath, options = {}) {
|
|
136
|
+
const ignoredNames = options.ignoredNames ?? new Set();
|
|
137
|
+
const ignoredDirectories = options.ignoredDirectories ?? new Set();
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
const entries = await readdir(directoryPath, { withFileTypes: true });
|
|
141
|
+
for (const entry of entries) {
|
|
142
|
+
if (entry.name.startsWith('.')) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (entry.isDirectory()) {
|
|
147
|
+
if (ignoredDirectories.has(entry.name)) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (await hasCanonicalMarkdown(path.join(directoryPath, entry.name), options)) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (entry.isFile() && entry.name.endsWith('.md') && !ignoredNames.has(entry.name)) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
100
172
|
function generateContextMarkdown(options) {
|
|
101
173
|
const projectName = options.projectConfig.name;
|
|
102
174
|
const rootRelativePath = options.rootRelativePath;
|
|
@@ -125,7 +197,7 @@ This workspace uses VibeCompass project memory rooted at \`${rootRelativePath}\`
|
|
|
125
197
|
|
|
126
198
|
## Session model
|
|
127
199
|
- VibeCompass active builder sessions are named lanes. Use one lane per active feature or workstream.
|
|
128
|
-
- \`vibecompass start-session\`
|
|
200
|
+
- \`vibecompass start-session\` requires \`--id <lane-id>\` so each active lane has a meaningful feature or workstream name.
|
|
129
201
|
- The active lane scratch files live under \`${rootRelativePath}/sessions/active/<lane-id>/\`.
|
|
130
202
|
- \`${rootRelativePath}/sessions/active/index.yaml\` is the authoritative current lane pointer; the tool-specific Current session block is a human-readable continuity summary, not the lane-selection source of truth.
|
|
131
203
|
- Finalized sessions are append-only notes named \`${rootRelativePath}/sessions/YYYY-MM-DD-N-title.md\`; multiple sessions on the same day increment \`N\`.
|
|
@@ -135,7 +207,7 @@ This workspace uses VibeCompass project memory rooted at \`${rootRelativePath}\`
|
|
|
135
207
|
${repos}
|
|
136
208
|
|
|
137
209
|
## Session roles
|
|
138
|
-
|
|
|
210
|
+
| Entry trigger | Role | Owns session lifecycle? |
|
|
139
211
|
|---|---|---|
|
|
140
212
|
| "start session" | Builder | Yes — opens the session, keeps scratch files current, and writes the final session note |
|
|
141
213
|
| "join as reviewer" | Reviewer | No — reviews the builder's work, appends findings, and updates handoff guidance |
|
|
@@ -146,14 +218,20 @@ ${repos}
|
|
|
146
218
|
- \`planning mode\` — optional prompt-level mode for scoping work before implementation
|
|
147
219
|
- \`review handoff\` — reviewer reads the selected lane's \`wip.md\`, \`handoff.md\`, latest finalized note, and relevant diffs before appending findings
|
|
148
220
|
- \`address review\` — builder reads reviewer feedback in the selected lane's \`wip.md\` / \`handoff.md\`, responds inline, applies accepted changes, and refreshes the builder handoff
|
|
221
|
+
- \`close session\` — builder runs the close-out checklist and ends with \`vibecompass close-session --session <lane-id>\`; \`end session\` is accepted as a synonym
|
|
149
222
|
|
|
150
223
|
These are prompt commands for agent behavior, not \`vibecompass\` CLI subcommands.
|
|
151
|
-
Reviewer handback is explicit: the reviewer ends the pass by updating the selected lane's \`wip.md\` + \`handoff.md\` and then stopping.
|
|
224
|
+
Reviewer handback is explicit: the reviewer ends the pass by updating the selected lane's \`wip.md\` + \`handoff.md\` and then stopping. The \`close session\` prompt runs builder close-out and ends with \`vibecompass close-session --session <lane-id>\`, which follows the workflow defaults recorded in \`${rootRelativePath}/project.yaml\`.
|
|
152
225
|
\`vibecompass end-session\` is also accepted as an alias for \`vibecompass close-session\`; the canonical command name remains \`close-session\`.
|
|
153
226
|
|
|
154
227
|
## Workflow defaults
|
|
155
228
|
${renderWorkflowDefaults(workflow)}
|
|
156
229
|
|
|
230
|
+
## Documentation coverage
|
|
231
|
+
- The architecture, decision, and session files created by init are an initial scaffold, not a comprehensive codebase review.
|
|
232
|
+
- Before risky implementation work, inspect the relevant code and update the affected architecture docs.
|
|
233
|
+
- Run \`vibecompass docs-review --guided\` when you want a comprehensive documentation review. That command is explicit because it may inspect source files and use AI or hosted scan infrastructure.
|
|
234
|
+
|
|
157
235
|
## Session startup
|
|
158
236
|
1. Read \`${rootRelativePath}/project.yaml\`.
|
|
159
237
|
2. Read the latest finalized session note in \`${rootRelativePath}/sessions/\`.
|
|
@@ -163,7 +241,7 @@ ${renderWorkflowDefaults(workflow)}
|
|
|
163
241
|
6. Read the relevant docs under \`${rootRelativePath}/architecture/\` and \`${rootRelativePath}/decisions/\`.
|
|
164
242
|
|
|
165
243
|
## Builder workflow
|
|
166
|
-
At session start, prefer running \`vibecompass start-session --id <lane-id> --working-on "..." \`.
|
|
244
|
+
At session start, prefer running \`vibecompass start-session --id <lane-id> --working-on "..." \`.
|
|
167
245
|
If you manage files manually, create \`${rootRelativePath}/sessions/active/<lane-id>/session.yaml\` and \`${rootRelativePath}/sessions/active/index.yaml\`, then create \`${rootRelativePath}/sessions/active/<lane-id>/wip.md\` if it does not exist:
|
|
168
246
|
|
|
169
247
|
\`\`\`md
|
|
@@ -240,6 +318,119 @@ automatically by package commands.
|
|
|
240
318
|
`;
|
|
241
319
|
}
|
|
242
320
|
|
|
321
|
+
function generateStarterArchitectureDoc(projectConfig) {
|
|
322
|
+
const repos = projectConfig.repos.map((repo) => repo.id);
|
|
323
|
+
const repoLines = projectConfig.repos
|
|
324
|
+
.map((repo) => `- \`${repo.id}\` — ${repo.remote}${repo.default_branch ? ` (${repo.default_branch})` : ''}`)
|
|
325
|
+
.join('\n');
|
|
326
|
+
const repoEvidence = projectConfig.repos
|
|
327
|
+
.map((repo) => `- \`${repo.id}:/\` — declared repository root`)
|
|
328
|
+
.join('\n');
|
|
329
|
+
|
|
330
|
+
return `---
|
|
331
|
+
domain: Project
|
|
332
|
+
feature: Overview
|
|
333
|
+
component: Project Shape
|
|
334
|
+
status: In progress
|
|
335
|
+
repos:
|
|
336
|
+
${repos.map((repoId) => ` - ${quoteYamlString(repoId)}`).join('\n')}
|
|
337
|
+
confidence: Initial scaffold
|
|
338
|
+
coverage: Initial scaffold
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Description
|
|
342
|
+
Initial project-memory scaffold for ${projectConfig.name}.
|
|
343
|
+
|
|
344
|
+
${projectConfig.description ? `${projectConfig.description}\n` : ''}This document is a starting map, not a comprehensive architecture review.
|
|
345
|
+
|
|
346
|
+
## Details
|
|
347
|
+
- Mode: \`${projectConfig.mode}\`
|
|
348
|
+
- Documentation coverage: initial scaffold
|
|
349
|
+
- Repo inventory:
|
|
350
|
+
${repoLines}
|
|
351
|
+
|
|
352
|
+
## Coverage
|
|
353
|
+
Confirmed:
|
|
354
|
+
- Project identity and mode from \`project.yaml\`
|
|
355
|
+
- Declared repository IDs and remotes from \`project.yaml\`
|
|
356
|
+
- Project-memory root layout created by \`vibecompass init\`
|
|
357
|
+
|
|
358
|
+
Not yet documented:
|
|
359
|
+
- Runtime architecture and data flow
|
|
360
|
+
- Auth/session model
|
|
361
|
+
- Database or persistence ownership
|
|
362
|
+
- External integrations
|
|
363
|
+
- Deployment, jobs, and observability
|
|
364
|
+
- Test strategy
|
|
365
|
+
- Feature/domain/component map beyond this placeholder
|
|
366
|
+
|
|
367
|
+
Before changing any undocumented area, inspect the relevant code and update or add architecture docs.
|
|
368
|
+
|
|
369
|
+
## Next steps
|
|
370
|
+
- Run \`vibecompass docs-review --guided\` for a comprehensive documentation review.
|
|
371
|
+
- Replace this placeholder with domain/feature/component docs as the project map becomes evidence-backed.
|
|
372
|
+
- Keep architecture docs aligned with implementation changes during each builder session.
|
|
373
|
+
|
|
374
|
+
## Involved files
|
|
375
|
+
- \`project.yaml\`
|
|
376
|
+
${repoEvidence}
|
|
377
|
+
`;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function generateDecisionExample(projectConfig) {
|
|
381
|
+
return `# Decision Examples
|
|
382
|
+
|
|
383
|
+
This file is example-only guidance for ${projectConfig.name}. It is intentionally ignored by VibeCompass canonical decision parsing and must not be treated as a real decision log.
|
|
384
|
+
|
|
385
|
+
Real decisions belong in domain-grouped files such as \`cross-cutting.md\`, with append-only entries:
|
|
386
|
+
|
|
387
|
+
\`\`\`md
|
|
388
|
+
### D-001 — Example decision title
|
|
389
|
+
**Timestamp:** YYYY-MM-DD HH:MM TZ
|
|
390
|
+
**Decision:** What was decided.
|
|
391
|
+
**Rationale:** Why this was the correct tradeoff.
|
|
392
|
+
\`\`\`
|
|
393
|
+
|
|
394
|
+
Do not copy this example as-is. Allocate real decision IDs from the current canonical decision log when a decision is accepted.
|
|
395
|
+
`;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function generateStarterSessionNote(options) {
|
|
399
|
+
const sessionDate = sessionDateFromGeneratedAt(options.generatedAt);
|
|
400
|
+
const projectConfig = options.projectConfig;
|
|
401
|
+
const repoLines = projectConfig.repos.map((repo) => `- \`${repo.id}\` — ${repo.remote}`).join('\n');
|
|
402
|
+
|
|
403
|
+
return `# Session — ${sessionDate}-1 — Project Memory Initialized
|
|
404
|
+
|
|
405
|
+
Generated by \`vibecompass init\`; this is initialization history, not a builder/reviewer work session.
|
|
406
|
+
|
|
407
|
+
## What we worked on
|
|
408
|
+
Initialized VibeCompass project memory for ${projectConfig.name}.
|
|
409
|
+
|
|
410
|
+
## Completed
|
|
411
|
+
- Created the project-memory root and \`project.yaml\`.
|
|
412
|
+
- Created lightweight starter architecture memory.
|
|
413
|
+
- Created example-only decision guidance without seeding real decisions.
|
|
414
|
+
- Generated local state manifest data from canonical files.
|
|
415
|
+
|
|
416
|
+
## Decisions made
|
|
417
|
+
- No real project decisions were seeded by init. Use \`decisions/EXAMPLE.md\` only as format guidance.
|
|
418
|
+
|
|
419
|
+
## Models used
|
|
420
|
+
- VibeCompass init scaffold.
|
|
421
|
+
|
|
422
|
+
## Blockers / open questions
|
|
423
|
+
- Comprehensive architecture documentation has not been reviewed yet.
|
|
424
|
+
- Declared repos:
|
|
425
|
+
${repoLines}
|
|
426
|
+
|
|
427
|
+
## Next session should start with
|
|
428
|
+
1. Run \`vibecompass docs-review --guided\` if you want a comprehensive documentation review.
|
|
429
|
+
2. Inspect relevant code before making implementation changes in areas not covered by architecture docs.
|
|
430
|
+
3. Replace starter placeholders with evidence-backed domain/feature/component docs.
|
|
431
|
+
`;
|
|
432
|
+
}
|
|
433
|
+
|
|
243
434
|
function generateArchitectureGuide(projectConfig) {
|
|
244
435
|
return `# Architecture
|
|
245
436
|
|
|
@@ -256,7 +447,7 @@ architecture/<domain-slug>/<feature-slug>/<component>.md
|
|
|
256
447
|
- \`feature\`
|
|
257
448
|
- \`component\`
|
|
258
449
|
- \`status\`
|
|
259
|
-
-
|
|
450
|
+
- \`repos\`: array of repo IDs, even for single-repo projects
|
|
260
451
|
|
|
261
452
|
## Recommended sections
|
|
262
453
|
- \`## Description\`
|
|
@@ -328,7 +519,7 @@ Read \`${options.contextRelativeToToolingRoot}\` before doing substantive work.
|
|
|
328
519
|
|
|
329
520
|
## Session roles
|
|
330
521
|
|
|
331
|
-
|
|
|
522
|
+
| Entry trigger | Role | Owns session lifecycle? |
|
|
332
523
|
|---|---|---|
|
|
333
524
|
| "start session" | Builder | Yes |
|
|
334
525
|
| "join as reviewer" | Reviewer | No |
|
|
@@ -341,9 +532,10 @@ Read \`${options.contextRelativeToToolingRoot}\` before doing substantive work.
|
|
|
341
532
|
- \`planning mode\` — optional prompt-level mode for scoping risky or ambiguous work before implementation
|
|
342
533
|
- \`review handoff\` — reviewer reads the selected lane's \`wip.md\`, \`handoff.md\`, latest finalized note, and relevant diffs before appending findings
|
|
343
534
|
- \`address review\` — builder reads reviewer feedback in the selected lane's \`wip.md\` / \`handoff.md\`, responds inline, applies accepted changes, and refreshes the builder handoff
|
|
535
|
+
- \`close session\` — builder runs the close-out checklist and ends with \`vibecompass close-session --session <lane-id>\`; \`end session\` is accepted as a synonym
|
|
344
536
|
|
|
345
537
|
These are prompt commands for agent behavior, not \`vibecompass\` CLI subcommands.
|
|
346
|
-
Reviewer handback is explicit: the reviewer ends the pass by updating the selected lane's \`wip.md\` + \`handoff.md\` and then stopping.
|
|
538
|
+
Reviewer handback is explicit: the reviewer ends the pass by updating the selected lane's \`wip.md\` + \`handoff.md\` and then stopping. The \`close session\` prompt runs builder close-out and ends with \`vibecompass close-session --session <lane-id>\`, which follows the workflow defaults recorded in \`${options.rootRelativePath}/project.yaml\`.
|
|
347
539
|
\`vibecompass end-session\` is accepted as an alias for \`vibecompass close-session\`; \`close-session\` remains the canonical command name.
|
|
348
540
|
|
|
349
541
|
## Current session
|
|
@@ -380,7 +572,7 @@ This workspace uses VibeCompass project memory rooted at \`${options.rootRelativ
|
|
|
380
572
|
|
|
381
573
|
## Session roles
|
|
382
574
|
|
|
383
|
-
|
|
|
575
|
+
| Entry trigger | Role | Owns session lifecycle? |
|
|
384
576
|
|---|---|---|
|
|
385
577
|
| "start session" | Builder | Yes — opens and closes the session lifecycle |
|
|
386
578
|
| "join as reviewer" | Reviewer | No — reviews the builder's work and updates the handoff |
|
|
@@ -393,9 +585,10 @@ This workspace uses VibeCompass project memory rooted at \`${options.rootRelativ
|
|
|
393
585
|
- \`planning mode\` — optional prompt-level mode for scoping risky or ambiguous work before implementation
|
|
394
586
|
- \`review handoff\` — reviewer reads the selected lane's \`wip.md\`, \`handoff.md\`, latest finalized note, and relevant diffs before appending findings
|
|
395
587
|
- \`address review\` — builder reads reviewer feedback in the selected lane's \`wip.md\` / \`handoff.md\`, responds inline, applies accepted changes, and refreshes the builder handoff
|
|
588
|
+
- \`close session\` — builder runs the close-out checklist and ends with \`vibecompass close-session --session <lane-id>\`; \`end session\` is accepted as a synonym
|
|
396
589
|
|
|
397
590
|
These are prompt commands for agent behavior, not \`vibecompass\` CLI subcommands.
|
|
398
|
-
Reviewer handback is explicit: the reviewer ends the pass by updating the selected lane's \`wip.md\` + \`handoff.md\` and then stopping.
|
|
591
|
+
Reviewer handback is explicit: the reviewer ends the pass by updating the selected lane's \`wip.md\` + \`handoff.md\` and then stopping. The \`close session\` prompt runs builder close-out and ends with \`vibecompass close-session --session <lane-id>\`, which follows the workflow defaults recorded in \`${options.rootRelativePath}/project.yaml\`.
|
|
399
592
|
\`vibecompass end-session\` is accepted as an alias for \`vibecompass close-session\`; \`close-session\` remains the canonical command name.
|
|
400
593
|
|
|
401
594
|
## Startup
|
|
@@ -442,3 +635,16 @@ function describeReviewerHandback(workflow) {
|
|
|
442
635
|
|
|
443
636
|
return workflow.reviewerHandback;
|
|
444
637
|
}
|
|
638
|
+
|
|
639
|
+
function sessionDateFromGeneratedAt(value) {
|
|
640
|
+
const date = value ? new Date(value) : new Date();
|
|
641
|
+
if (Number.isNaN(date.getTime())) {
|
|
642
|
+
return new Date().toISOString().slice(0, 10);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return date.toISOString().slice(0, 10);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function quoteYamlString(value) {
|
|
649
|
+
return JSON.stringify(value);
|
|
650
|
+
}
|