@vibecompass/vibecompass 0.8.0 → 0.9.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/CHANGELOG.md +12 -0
- package/README.md +68 -27
- package/package.json +1 -1
- package/src/cli.js +12 -1
- package/src/docs-review.js +64 -18
- package/src/init.js +32 -3
- package/src/project-memory.js +24 -5
- package/src/read-model.js +8 -4
- package/src/scaffold.js +12 -4
- package/src/setup.js +7 -6
- package/src/status.js +2 -0
- package/src/workflows/registry.js +9 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.1 - 2026-06-14
|
|
4
|
+
|
|
5
|
+
- Make local docs-review prompts self-contained by printing the accepted output file, root-scoped apply command, and same-version `npx` fallback the agent should run after user acceptance.
|
|
6
|
+
|
|
7
|
+
## 0.9.0 - 2026-06-14
|
|
8
|
+
|
|
9
|
+
- Add explicit local folder sources for non-Git projects: `project.yaml.repos[]` may use `source: local` plus `path`, and `init` accepts `--repo-local <id=path>`.
|
|
10
|
+
- Keep blank Git remotes invalid, but report an actionable `--repo-local` hint when `--repo <id=remote>` resolves to an empty value.
|
|
11
|
+
- Update guided init, starter docs, status, scanning, and read-model output so local-source roots validate and render cleanly.
|
|
12
|
+
- Bump docs-review to `VibeCompass Docs Review Prompt v3`, requiring first-pass docs to include a user journey, project/system map, and core journey-facing feature summaries.
|
|
13
|
+
- Add `vibecompass-project-map version=1` support inside `architecture/overview/project-shape.md`, including nested-fence parsing so generated overview docs can round-trip the machine-readable journey map block.
|
|
14
|
+
|
|
3
15
|
## 0.8.0 - 2026-06-12
|
|
4
16
|
|
|
5
17
|
- Add named sync targets (D-236): `connect-hosted --target <name>` binds one project root to multiple hosted environments (for example `dev` on localhost and `prod` on vibecompass.dev).
|
package/README.md
CHANGED
|
@@ -16,38 +16,79 @@ Full docs: https://vibecompass.dev/developers
|
|
|
16
16
|
|
|
17
17
|
## Install
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Most people can run VibeCompass without installing it globally:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
npx -y @vibecompass/vibecompass --help
|
|
22
|
+
npx -y @vibecompass/vibecompass@latest --help
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
Or install
|
|
25
|
+
Or install it globally if you want the shorter `vibecompass` command:
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
npm install @vibecompass/vibecompass
|
|
28
|
+
npm install -g @vibecompass/vibecompass@latest
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Requires Node.js 20+.
|
|
32
32
|
|
|
33
33
|
## Quick Start
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
### Easiest path: ask your AI coding tool
|
|
36
|
+
|
|
37
|
+
Open Claude Code, Codex, Cursor, or Copilot in the project folder you want
|
|
38
|
+
VibeCompass to remember, then paste:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
VibeCompass is project memory for vibe coding. Use the npm package
|
|
42
|
+
@vibecompass/vibecompass@latest.
|
|
43
|
+
|
|
44
|
+
Please set it up in this project:
|
|
45
|
+
1. Run the needed VibeCompass commands with npx.
|
|
46
|
+
2. Initialize project memory with guided setup.
|
|
47
|
+
3. If this folder is not a Git repo, use a local folder source.
|
|
48
|
+
4. Start a named session lane for this setup work.
|
|
49
|
+
5. Tell me which files changed and what I should review.
|
|
50
|
+
|
|
51
|
+
Do not ask me to paste secret tokens into chat.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
After setup, start a fresh AI session in the same project and type:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
docs review
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
That asks the AI to inspect your code and create the first real architecture
|
|
61
|
+
docs. The package prints the output file and the exact apply command when the
|
|
62
|
+
docs are ready for you to accept.
|
|
63
|
+
|
|
64
|
+
### Terminal path
|
|
65
|
+
|
|
66
|
+
Run this from your project folder:
|
|
36
67
|
|
|
37
68
|
```bash
|
|
38
|
-
npx -y @vibecompass/vibecompass init --guided
|
|
69
|
+
npx -y @vibecompass/vibecompass@latest init --guided
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
If the folder is not a Git repo, use a local folder source:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npx -y @vibecompass/vibecompass@latest init \
|
|
76
|
+
--root .compass \
|
|
77
|
+
--name "My Project" \
|
|
78
|
+
--mode local-primary \
|
|
79
|
+
--repo-local app=.
|
|
39
80
|
```
|
|
40
81
|
|
|
41
82
|
Check what to do next:
|
|
42
83
|
|
|
43
84
|
```bash
|
|
44
|
-
npx -y @vibecompass/vibecompass status --root .compass
|
|
85
|
+
npx -y @vibecompass/vibecompass@latest status --root .compass
|
|
45
86
|
```
|
|
46
87
|
|
|
47
88
|
Start a builder session:
|
|
48
89
|
|
|
49
90
|
```bash
|
|
50
|
-
npx -y @vibecompass/vibecompass start-session \
|
|
91
|
+
npx -y @vibecompass/vibecompass@latest start-session \
|
|
51
92
|
--root .compass \
|
|
52
93
|
--id feature-lane \
|
|
53
94
|
--working-on "Build the next feature"
|
|
@@ -56,13 +97,13 @@ npx -y @vibecompass/vibecompass start-session \
|
|
|
56
97
|
Generate evidence-backed architecture docs:
|
|
57
98
|
|
|
58
99
|
```bash
|
|
59
|
-
npx -y @vibecompass/vibecompass docs-review --root .compass --guided
|
|
100
|
+
npx -y @vibecompass/vibecompass@latest docs-review --root .compass --guided
|
|
60
101
|
```
|
|
61
102
|
|
|
62
103
|
Close the session:
|
|
63
104
|
|
|
64
105
|
```bash
|
|
65
|
-
npx -y @vibecompass/vibecompass close-session \
|
|
106
|
+
npx -y @vibecompass/vibecompass@latest close-session \
|
|
66
107
|
--root .compass \
|
|
67
108
|
--session feature-lane \
|
|
68
109
|
--title "Feature Lane" \
|
|
@@ -74,25 +115,25 @@ npx -y @vibecompass/vibecompass close-session \
|
|
|
74
115
|
|
|
75
116
|
```bash
|
|
76
117
|
# Create or inspect project memory
|
|
77
|
-
vibecompass init --guided
|
|
78
|
-
vibecompass status --root .compass
|
|
118
|
+
npx -y @vibecompass/vibecompass@latest init --guided
|
|
119
|
+
npx -y @vibecompass/vibecompass@latest status --root .compass
|
|
79
120
|
|
|
80
121
|
# Session workflow
|
|
81
|
-
vibecompass start-session --root .compass --id auth-flow --working-on "Auth flow"
|
|
82
|
-
vibecompass list-sessions --root .compass
|
|
83
|
-
vibecompass switch-session auth-flow --root .compass
|
|
84
|
-
vibecompass close-session --root .compass --session auth-flow --title "Auth Flow" --completed "Built auth" --next-step "Review"
|
|
122
|
+
npx -y @vibecompass/vibecompass@latest start-session --root .compass --id auth-flow --working-on "Auth flow"
|
|
123
|
+
npx -y @vibecompass/vibecompass@latest list-sessions --root .compass
|
|
124
|
+
npx -y @vibecompass/vibecompass@latest switch-session auth-flow --root .compass
|
|
125
|
+
npx -y @vibecompass/vibecompass@latest close-session --root .compass --session auth-flow --title "Auth Flow" --completed "Built auth" --next-step "Review"
|
|
85
126
|
|
|
86
127
|
# Agent instruction files
|
|
87
|
-
vibecompass sync-agents --root .compass
|
|
128
|
+
npx -y @vibecompass/vibecompass@latest sync-agents --root .compass
|
|
88
129
|
|
|
89
130
|
# Architecture docs review
|
|
90
|
-
vibecompass docs-review --root .compass --guided
|
|
91
|
-
vibecompass docs-review --root .compass --apply-output
|
|
131
|
+
npx -y @vibecompass/vibecompass@latest docs-review --root .compass --guided
|
|
132
|
+
npx -y @vibecompass/vibecompass@latest docs-review --root .compass --apply-output
|
|
92
133
|
|
|
93
134
|
# Rerun docs review from an archived architecture-doc slate
|
|
94
|
-
vibecompass docs-review --root .compass --rebuild --path architecture
|
|
95
|
-
vibecompass docs-review --root .compass --rebuild --apply --stale-policy archive --path architecture
|
|
135
|
+
npx -y @vibecompass/vibecompass@latest docs-review --root .compass --rebuild --path architecture
|
|
136
|
+
npx -y @vibecompass/vibecompass@latest docs-review --root .compass --rebuild --apply --stale-policy archive --path architecture
|
|
96
137
|
```
|
|
97
138
|
|
|
98
139
|
## What It Creates
|
|
@@ -137,13 +178,13 @@ Use hosted sync when you want browser review, team workflows, or hosted
|
|
|
137
178
|
docs-review proposals:
|
|
138
179
|
|
|
139
180
|
```bash
|
|
140
|
-
vibecompass connect-hosted \
|
|
181
|
+
npx -y @vibecompass/vibecompass@latest connect-hosted \
|
|
141
182
|
--root .compass \
|
|
142
183
|
--sync-api-url https://vibecompass.dev \
|
|
143
184
|
--sync-project-id vc_proj_example \
|
|
144
185
|
--sync-credential-env-var VIBECOMPASS_SYNC_TOKEN
|
|
145
186
|
|
|
146
|
-
vibecompass push --root .compass
|
|
187
|
+
npx -y @vibecompass/vibecompass@latest push --root .compass
|
|
147
188
|
```
|
|
148
189
|
|
|
149
190
|
### Multiple environments
|
|
@@ -153,16 +194,16 @@ production) so you never have to rebind:
|
|
|
153
194
|
|
|
154
195
|
```bash
|
|
155
196
|
# add targets once — the first one becomes the default
|
|
156
|
-
vibecompass connect-hosted --root .compass --target dev \
|
|
197
|
+
npx -y @vibecompass/vibecompass@latest connect-hosted --root .compass --target dev \
|
|
157
198
|
--sync-api-url http://localhost:3000 --sync-project-id vc_proj_dev \
|
|
158
199
|
--sync-credential-env-var VIBECOMPASS_SYNC_TOKEN
|
|
159
|
-
vibecompass connect-hosted --root .compass --target prod \
|
|
200
|
+
npx -y @vibecompass/vibecompass@latest connect-hosted --root .compass --target prod \
|
|
160
201
|
--sync-api-url https://vibecompass.dev --sync-project-id vc_proj_prod \
|
|
161
202
|
--sync-credential-env-var VIBECOMPASS_SYNC_TOKEN_PROD
|
|
162
203
|
|
|
163
204
|
# then pick per command, or switch the default
|
|
164
|
-
vibecompass push --root .compass --sync-target prod
|
|
165
|
-
vibecompass sync-target prod --root .compass
|
|
205
|
+
npx -y @vibecompass/vibecompass@latest push --root .compass --sync-target prod
|
|
206
|
+
npx -y @vibecompass/vibecompass@latest sync-target prod --root .compass
|
|
166
207
|
```
|
|
167
208
|
|
|
168
209
|
Tip: if you already have a single (flat) binding, add it as your first named
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -568,6 +568,11 @@ export function parseCliArgs(argv) {
|
|
|
568
568
|
parsed.repos.push({ id, remote });
|
|
569
569
|
break;
|
|
570
570
|
}
|
|
571
|
+
case '--repo-local': {
|
|
572
|
+
const [id, repoPath] = splitAssignment(value, '--repo-local');
|
|
573
|
+
parsed.repos.push({ id, source: 'local', path: repoPath });
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
571
576
|
case '--repo-branch': {
|
|
572
577
|
const [id, defaultBranch] = splitAssignment(value, '--repo-branch');
|
|
573
578
|
parsed.repoBranches.set(id, defaultBranch);
|
|
@@ -1461,6 +1466,11 @@ function writeWarnings(io, warnings = []) {
|
|
|
1461
1466
|
function splitAssignment(value, flagName) {
|
|
1462
1467
|
const separatorIndex = value.indexOf('=');
|
|
1463
1468
|
if (separatorIndex <= 0 || separatorIndex === value.length - 1) {
|
|
1469
|
+
if (flagName === '--repo' && separatorIndex > 0 && separatorIndex === value.length - 1) {
|
|
1470
|
+
throw new Error(
|
|
1471
|
+
'--repo remote resolved to empty. For a non-Git folder, use --repo-local <id=path> instead of --repo <id=remote>.',
|
|
1472
|
+
);
|
|
1473
|
+
}
|
|
1464
1474
|
throw new Error(`${flagName} expects id=value.`);
|
|
1465
1475
|
}
|
|
1466
1476
|
|
|
@@ -1495,7 +1505,8 @@ function usageText() {
|
|
|
1495
1505
|
' --placement <workspace-root|dedicated-memory-repo|primary-repo>',
|
|
1496
1506
|
' Optional explicit placement pattern',
|
|
1497
1507
|
' --guided Ask placement and setup questions interactively',
|
|
1498
|
-
' --repo <id=remote> Repeatable repo descriptor',
|
|
1508
|
+
' --repo <id=remote> Repeatable Git-backed repo descriptor',
|
|
1509
|
+
' --repo-local <id=path> Repeatable local folder source for non-Git projects',
|
|
1499
1510
|
' --repo-branch <id=branch> Optional per-repo default branch',
|
|
1500
1511
|
' --sync-api-url <url> Optional hosted sync api_url',
|
|
1501
1512
|
' --sync-project-id <id> Optional hosted sync project_id',
|
package/src/docs-review.js
CHANGED
|
@@ -6,8 +6,9 @@ import { sha256Text } from './hash.js';
|
|
|
6
6
|
import { writeStateManifest } from './manifest.js';
|
|
7
7
|
import { parseSimpleYaml } from './simple-yaml.js';
|
|
8
8
|
import { readSyncCursor, resolveSyncBinding } from './sync-binding.js';
|
|
9
|
+
import { PACKAGE_VERSION } from './version.js';
|
|
9
10
|
|
|
10
|
-
const DOCS_REVIEW_PROMPT_VERSION = 'VibeCompass Docs Review Prompt
|
|
11
|
+
const DOCS_REVIEW_PROMPT_VERSION = 'VibeCompass Docs Review Prompt v3';
|
|
11
12
|
const ARCHITECTURE_DOC_SOFT_SIZE_LIMIT_BYTES = 12000;
|
|
12
13
|
const COVERAGE_PLAN_OUTPUT_VERSION = 1;
|
|
13
14
|
const COVERAGE_PLAN_STATUSES = new Set(['accepted', 'deferred', 'missing']);
|
|
@@ -785,13 +786,13 @@ function extractAnthropicText(body) {
|
|
|
785
786
|
|
|
786
787
|
function parseArchitectureDocBlocks(source) {
|
|
787
788
|
const blocks = [];
|
|
788
|
-
const pattern =
|
|
789
|
+
const pattern = /^(`{3,})vibecompass-architecture-doc\s+path=([^\s`]+)\s*\n([\s\S]*?)^\1[ \t]*$/gm;
|
|
789
790
|
let match;
|
|
790
791
|
|
|
791
792
|
while ((match = pattern.exec(source)) !== null) {
|
|
792
793
|
blocks.push({
|
|
793
|
-
path: normalizeBlockPath(match[
|
|
794
|
-
content: match[
|
|
794
|
+
path: normalizeBlockPath(match[2]),
|
|
795
|
+
content: match[3].replace(/\n$/, ''),
|
|
795
796
|
});
|
|
796
797
|
}
|
|
797
798
|
|
|
@@ -829,8 +830,8 @@ function parseDecisionRecommendationBlocks(source) {
|
|
|
829
830
|
}
|
|
830
831
|
|
|
831
832
|
function countMalformedArchitectureDocFences(source) {
|
|
832
|
-
const fencePattern =
|
|
833
|
-
const acceptedOpeningPattern =
|
|
833
|
+
const fencePattern = /^`{3,}vibecompass-architecture-doc\b.*$/gm;
|
|
834
|
+
const acceptedOpeningPattern = /^`{3,}vibecompass-architecture-doc\s+path=[^\s`]+\s*$/;
|
|
834
835
|
let count = 0;
|
|
835
836
|
let match;
|
|
836
837
|
|
|
@@ -1683,6 +1684,10 @@ function renderApplyOutputMessage(options) {
|
|
|
1683
1684
|
}
|
|
1684
1685
|
|
|
1685
1686
|
function renderReviewPrompt(options) {
|
|
1687
|
+
const outputPath = path.join(options.rootDir, 'state', 'docs-review-output.md');
|
|
1688
|
+
const applyCommand = `vibecompass docs-review --root ${shellQuote(options.rootDir)} --apply-output --output ${shellQuote(outputPath)}`;
|
|
1689
|
+
const npxApplyCommand = `npx -y @vibecompass/vibecompass@${PACKAGE_VERSION} docs-review --root ${shellQuote(options.rootDir)} --apply-output --output ${shellQuote(outputPath)}`;
|
|
1690
|
+
|
|
1686
1691
|
return [
|
|
1687
1692
|
`# ${DOCS_REVIEW_PROMPT_VERSION}`,
|
|
1688
1693
|
'',
|
|
@@ -1694,6 +1699,9 @@ function renderReviewPrompt(options) {
|
|
|
1694
1699
|
`- Project mode: ${options.project.mode}`,
|
|
1695
1700
|
`- Review provider to record: ${options.llm}`,
|
|
1696
1701
|
`- Review model/version to record: ${options.model}`,
|
|
1702
|
+
`- Accepted output file: ${outputPath}`,
|
|
1703
|
+
`- Apply command after user acceptance: ${applyCommand}`,
|
|
1704
|
+
`- Apply command if the CLI is not installed on PATH: ${npxApplyCommand}`,
|
|
1697
1705
|
'',
|
|
1698
1706
|
'## Required Inputs',
|
|
1699
1707
|
'1. Read `project.yaml`.',
|
|
@@ -1705,24 +1713,28 @@ function renderReviewPrompt(options) {
|
|
|
1705
1713
|
'Stage 1 — Evidence inventory:',
|
|
1706
1714
|
'- Build a compact repo inventory from file paths, manifests/config files, route/job/test directories, and existing architecture frontmatter before reading large file bodies.',
|
|
1707
1715
|
'- Mine finalized session notes for decision candidates and product constraints, but cap proposed decisions to the five highest-value architecture choices.',
|
|
1708
|
-
'- Identify candidate domains, features, components,
|
|
1716
|
+
'- Identify candidate domains, features, components, ownership boundaries, user journey entry points, feature-to-feature relationships, and system-layer connections with concrete `repo:path` evidence.',
|
|
1709
1717
|
'- Do not fetch or summarize broad source bodies until the coverage plan says a file is needed.',
|
|
1710
1718
|
'',
|
|
1711
1719
|
'Stage 2 — Coverage plan:',
|
|
1712
1720
|
'- Propose the smallest useful architecture-doc set that will let future agents understand the project and retrieve targeted context.',
|
|
1713
|
-
'-
|
|
1721
|
+
'- The minimum useful set must cover: user journey, project/system map (frontend/backend/API/data/integration structure and connections), and summaries of the core journey-facing features.',
|
|
1722
|
+
'- Prioritize entry points, user-flow/gating relationships, data ownership, external integrations, jobs/async boundaries, auth/security boundaries, and test surfaces.',
|
|
1714
1723
|
'- Mark each proposed doc as `comprehensive`, `partial`, or `initial`, with the reason and blindspots.',
|
|
1715
1724
|
'- Emit the accepted plan as one `vibecompass-coverage-plan version=1` JSON fence before architecture-doc blocks.',
|
|
1716
1725
|
'- Ask for user acceptance before emitting fenced architecture-doc blocks.',
|
|
1717
1726
|
'',
|
|
1718
1727
|
'Stage 3 — Bounded doc generation:',
|
|
1719
1728
|
'- Generate only accepted docs, one complete fenced block per architecture path.',
|
|
1729
|
+
'- Ensure `architecture/overview/project-shape.md` includes a concise system map plus one `vibecompass-project-map version=1` JSON fence that lists journey-facing features and supported relationships.',
|
|
1720
1730
|
'- Keep docs concise and retrieval-oriented: explain contracts, flows, invariants, and ownership; do not rewrite source code or produce file-by-file walkthroughs.',
|
|
1721
1731
|
`- Soft size budget: keep each generated architecture doc under ${ARCHITECTURE_DOC_SOFT_SIZE_LIMIT_BYTES} bytes unless the extra detail is necessary and called out in Blindspots or Retrieval guidance.`,
|
|
1722
1732
|
'- Include only the most important involved files; prefer representative entry points and owned contracts over exhaustive file lists.',
|
|
1723
1733
|
'',
|
|
1724
1734
|
'Stage 4 — Apply and verify:',
|
|
1725
|
-
|
|
1735
|
+
`- After the user accepts Stage 2, write the complete accepted fenced output verbatim to \`${outputPath}\`.`,
|
|
1736
|
+
`- Then run \`${applyCommand}\` to validate and apply the accepted blocks.`,
|
|
1737
|
+
`- If \`vibecompass\` is not installed on PATH, run \`${npxApplyCommand}\` instead.`,
|
|
1726
1738
|
'- Surface any parser warnings, especially oversized docs, so the user can decide whether to compact or accept the output.',
|
|
1727
1739
|
'',
|
|
1728
1740
|
'## Architecture Doc Contract',
|
|
@@ -1746,18 +1758,46 @@ function renderReviewPrompt(options) {
|
|
|
1746
1758
|
'',
|
|
1747
1759
|
'## Review Rules',
|
|
1748
1760
|
'1. Do not delete `architecture/overview/project-shape.md`.',
|
|
1749
|
-
'2. Add
|
|
1750
|
-
'3.
|
|
1751
|
-
'4.
|
|
1752
|
-
'5.
|
|
1753
|
-
'6.
|
|
1754
|
-
'7.
|
|
1755
|
-
'8. Do not
|
|
1756
|
-
'9.
|
|
1761
|
+
'2. Add or update `architecture/overview/project-shape.md` so it explains the project/system map and includes the accepted `vibecompass-project-map version=1` block.',
|
|
1762
|
+
'3. Add evidence-backed component docs alongside the overview for core journey-facing features and important supporting systems.',
|
|
1763
|
+
'4. Update `architecture/overview/project-shape.md` coverage and blindspot sections to summarize what has now been mapped.',
|
|
1764
|
+
'5. Keep all implementation claims source-backed with `repo:path` evidence.',
|
|
1765
|
+
'6. Use only the exact confidence and coverage enum values listed above.',
|
|
1766
|
+
'7. Put uncertainty in `Blindspots`; do not fill gaps with guesses.',
|
|
1767
|
+
'8. Do not append real `D-NNN` decisions without explicit user acceptance. Propose candidate decisions separately.',
|
|
1768
|
+
'9. Do not edit `decisions/INDEX.md` directly unless a canonical decision file was explicitly accepted and appended.',
|
|
1769
|
+
'10. Optimize for future retrieval: project-level docs stay compact; component docs carry focused context for a specific area.',
|
|
1770
|
+
'',
|
|
1771
|
+
'## Project Map Block',
|
|
1772
|
+
'Include exactly one project-map block inside `architecture/overview/project-shape.md` when the user accepts journey/system mapping output:',
|
|
1773
|
+
'',
|
|
1774
|
+
'```vibecompass-project-map version=1',
|
|
1775
|
+
'{',
|
|
1776
|
+
' "features": [',
|
|
1777
|
+
' {',
|
|
1778
|
+
' "domain": "Domain name matching architecture frontmatter",',
|
|
1779
|
+
' "feature": "Feature name matching architecture frontmatter",',
|
|
1780
|
+
' "is_entry_point": true,',
|
|
1781
|
+
' "summary": "Short user-facing feature summary"',
|
|
1782
|
+
' }',
|
|
1783
|
+
' ],',
|
|
1784
|
+
' "relationships": [',
|
|
1785
|
+
' {',
|
|
1786
|
+
' "from": { "domain": "Domain", "feature": "Feature" },',
|
|
1787
|
+
' "to": { "domain": "Domain", "feature": "Feature" },',
|
|
1788
|
+
' "kind": "gates | navigates_to | depends_on | writes_to",',
|
|
1789
|
+
' "label": "Short evidence-backed relationship label"',
|
|
1790
|
+
' }',
|
|
1791
|
+
' ]',
|
|
1792
|
+
'}',
|
|
1793
|
+
'```',
|
|
1794
|
+
'',
|
|
1795
|
+
'Only include relationships supported by evidence. Prefer `navigates_to` and `gates` for the main user journey; use `depends_on` and `writes_to` for supporting system relationships. If useful journey links cannot be inferred, state that as a coverage gap rather than inventing links.',
|
|
1757
1796
|
'',
|
|
1758
1797
|
'## Output Contract',
|
|
1759
1798
|
'First provide a concise findings summary with:',
|
|
1760
1799
|
'- mapped areas',
|
|
1800
|
+
'- user journey and project/system map coverage',
|
|
1761
1801
|
'- gaps/blindspots',
|
|
1762
1802
|
'- evidence inventory summary',
|
|
1763
1803
|
'- coverage plan and proposed architecture docs',
|
|
@@ -1791,6 +1831,8 @@ function renderReviewPrompt(options) {
|
|
|
1791
1831
|
'<complete markdown file content>',
|
|
1792
1832
|
'```',
|
|
1793
1833
|
'',
|
|
1834
|
+
'If the complete markdown file content contains its own fenced block, such as `vibecompass-project-map version=1`, use a longer outer fence for the architecture-doc block (for example four backticks) so the inner fence stays inside the document body.',
|
|
1835
|
+
'',
|
|
1794
1836
|
'If the review surfaced accepted decision candidates, output each candidate as a separate block without assigning a D-number:',
|
|
1795
1837
|
'',
|
|
1796
1838
|
'```vibecompass-decision-recommendation target=decisions/cross-cutting.md',
|
|
@@ -1800,10 +1842,14 @@ function renderReviewPrompt(options) {
|
|
|
1800
1842
|
'**Context:** Optional supporting context.',
|
|
1801
1843
|
'```',
|
|
1802
1844
|
'',
|
|
1803
|
-
|
|
1845
|
+
`Only include accepted coverage, architecture, and decision-recommendation blocks. After user acceptance, save the final accepted output to \`${outputPath}\`, run \`${applyCommand}\` or \`${npxApplyCommand}\`, and report applied paths plus parser warnings.`,
|
|
1804
1846
|
].join('\n');
|
|
1805
1847
|
}
|
|
1806
1848
|
|
|
1849
|
+
function shellQuote(value) {
|
|
1850
|
+
return `'${String(value).replaceAll("'", "'\\''")}'`;
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1807
1853
|
function ensureTrailingNewline(value) {
|
|
1808
1854
|
return value.endsWith('\n') ? value : `${value}\n`;
|
|
1809
1855
|
}
|
package/src/init.js
CHANGED
|
@@ -257,13 +257,42 @@ function normalizeInitOptions(options) {
|
|
|
257
257
|
}
|
|
258
258
|
seenRepoIds.add(repo.id);
|
|
259
259
|
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
const source = typeof repo.source === 'string' && repo.source.trim() !== ''
|
|
261
|
+
? repo.source.trim()
|
|
262
|
+
: null;
|
|
263
|
+
const pathValue = typeof repo.path === 'string' && repo.path.trim() !== ''
|
|
264
|
+
? repo.path.trim()
|
|
265
|
+
: null;
|
|
266
|
+
const remote = typeof repo.remote === 'string' ? repo.remote.trim() : '';
|
|
267
|
+
|
|
268
|
+
if (source && !['git', 'local'].includes(source)) {
|
|
269
|
+
throw new Error(`repo "${repo.id}" source must be git or local.`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (source === 'local' || (!source && !remote && pathValue)) {
|
|
273
|
+
if (!['local-only', 'local-primary'].includes(preparedOptions.mode)) {
|
|
274
|
+
throw new Error(`repo "${repo.id}" local sources are supported only in local-only or local-primary mode.`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (!pathValue) {
|
|
278
|
+
throw new Error(`repo "${repo.id}" source local requires a non-empty path.`);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
id: repo.id,
|
|
283
|
+
source: 'local',
|
|
284
|
+
path: pathValue,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (!remote) {
|
|
289
|
+
throw new Error(`repo "${repo.id}" requires a non-empty remote, or use a local repo source with source: local and path.`);
|
|
262
290
|
}
|
|
263
291
|
|
|
264
292
|
return {
|
|
265
293
|
id: repo.id,
|
|
266
|
-
|
|
294
|
+
...(source === 'git' ? { source: 'git' } : {}),
|
|
295
|
+
remote,
|
|
267
296
|
...(repo.defaultBranch ? { default_branch: repo.defaultBranch } : {}),
|
|
268
297
|
};
|
|
269
298
|
});
|
package/src/project-memory.js
CHANGED
|
@@ -34,7 +34,7 @@ const KNOWN_PROJECT_FIELDS = new Set([
|
|
|
34
34
|
'sync',
|
|
35
35
|
'metadata',
|
|
36
36
|
]);
|
|
37
|
-
const KNOWN_REPO_FIELDS = new Set(['id', 'remote', 'default_branch']);
|
|
37
|
+
const KNOWN_REPO_FIELDS = new Set(['id', 'source', 'remote', 'path', 'default_branch']);
|
|
38
38
|
const KNOWN_SYNC_FIELDS = new Set([
|
|
39
39
|
'provider',
|
|
40
40
|
'api_url',
|
|
@@ -278,8 +278,25 @@ function validateProjectData(data, relativePath) {
|
|
|
278
278
|
repoIds.push(repo.id);
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
-
|
|
282
|
-
|
|
281
|
+
const source = typeof repo.source === 'string' && repo.source.trim() !== ''
|
|
282
|
+
? repo.source.trim()
|
|
283
|
+
: null;
|
|
284
|
+
const remote = typeof repo.remote === 'string' ? repo.remote.trim() : '';
|
|
285
|
+
const sourcePath = typeof repo.path === 'string' ? repo.path.trim() : '';
|
|
286
|
+
|
|
287
|
+
if (source && !['git', 'local'].includes(source)) {
|
|
288
|
+
errors.push(createError(relativePath, 'project-invalid-repo-source', `${prefix}.source must be git or local.`));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (source === 'local' || (!source && !remote && sourcePath)) {
|
|
292
|
+
if (!['local-only', 'local-primary'].includes(data.mode)) {
|
|
293
|
+
errors.push(createError(relativePath, 'project-invalid-repo-source', `${prefix}.source local is supported only when mode is local-only or local-primary.`));
|
|
294
|
+
}
|
|
295
|
+
if (!sourcePath) {
|
|
296
|
+
errors.push(createError(relativePath, 'project-invalid-repo-path', `${prefix}.path must be a non-empty string for local sources.`));
|
|
297
|
+
}
|
|
298
|
+
} else if (!remote) {
|
|
299
|
+
errors.push(createError(relativePath, 'project-invalid-repo-remote', `${prefix}.remote must be a non-empty string for Git-backed sources.`));
|
|
283
300
|
}
|
|
284
301
|
}
|
|
285
302
|
}
|
|
@@ -336,10 +353,12 @@ function validateProjectData(data, relativePath) {
|
|
|
336
353
|
repo_ids: repoIds,
|
|
337
354
|
repos: Array.isArray(data.repos)
|
|
338
355
|
? data.repos
|
|
339
|
-
.filter((repo) => isPlainObject(repo) && typeof repo.id === 'string'
|
|
356
|
+
.filter((repo) => isPlainObject(repo) && typeof repo.id === 'string')
|
|
340
357
|
.map((repo) => ({
|
|
341
358
|
id: repo.id,
|
|
342
|
-
|
|
359
|
+
source: typeof repo.source === 'string' ? repo.source : (typeof repo.remote === 'string' ? 'git' : 'local'),
|
|
360
|
+
remote: typeof repo.remote === 'string' ? repo.remote : null,
|
|
361
|
+
path: typeof repo.path === 'string' ? repo.path : null,
|
|
343
362
|
default_branch: typeof repo.default_branch === 'string' ? repo.default_branch : null,
|
|
344
363
|
}))
|
|
345
364
|
: [],
|
package/src/read-model.js
CHANGED
|
@@ -105,7 +105,9 @@ function buildProjectSummary(scanResult, currentManifest, freshness, existingMan
|
|
|
105
105
|
const extracted = scanResult.project.extracted ?? {};
|
|
106
106
|
const repos = (extracted.repos ?? []).map((repo) => ({
|
|
107
107
|
id: repo.id,
|
|
108
|
+
source: repo.source,
|
|
108
109
|
remote: repo.remote,
|
|
110
|
+
path: repo.path,
|
|
109
111
|
default_branch: repo.default_branch,
|
|
110
112
|
}));
|
|
111
113
|
|
|
@@ -451,10 +453,12 @@ function buildRepoAliasMap(repos) {
|
|
|
451
453
|
aliases.set(repo.id, repo.id);
|
|
452
454
|
aliases.set(repo.id.toLowerCase(), repo.id);
|
|
453
455
|
|
|
454
|
-
const remoteName = repo.remote
|
|
455
|
-
.
|
|
456
|
-
|
|
457
|
-
|
|
456
|
+
const remoteName = typeof repo.remote === 'string'
|
|
457
|
+
? repo.remote
|
|
458
|
+
.replace(/\.git$/, '')
|
|
459
|
+
.split('/')
|
|
460
|
+
.pop()
|
|
461
|
+
: null;
|
|
458
462
|
|
|
459
463
|
if (remoteName) {
|
|
460
464
|
aliases.set(remoteName, repo.id);
|
package/src/scaffold.js
CHANGED
|
@@ -206,7 +206,7 @@ function generateContextMarkdown(options) {
|
|
|
206
206
|
const workflow = resolveWorkflowSettings(options.projectConfig);
|
|
207
207
|
const promptCommands = renderPromptCommandLines({ rootRelativePath }).join('\n');
|
|
208
208
|
const repos = options.projectConfig.repos
|
|
209
|
-
.map((repo) => `- \`${repo.id}\` → ${repo
|
|
209
|
+
.map((repo) => `- \`${repo.id}\` → ${formatRepoDescriptor(repo)}`)
|
|
210
210
|
.join('\n');
|
|
211
211
|
|
|
212
212
|
return `# Project Context — ${projectName}
|
|
@@ -348,7 +348,7 @@ automatically by package commands.
|
|
|
348
348
|
function generateStarterArchitectureDoc(projectConfig) {
|
|
349
349
|
const repos = projectConfig.repos.map((repo) => repo.id);
|
|
350
350
|
const repoLines = projectConfig.repos
|
|
351
|
-
.map((repo) => `- \`${repo.id}\` — ${repo
|
|
351
|
+
.map((repo) => `- \`${repo.id}\` — ${formatRepoDescriptor(repo)}${repo.default_branch ? ` (${repo.default_branch})` : ''}`)
|
|
352
352
|
.join('\n');
|
|
353
353
|
const repoEvidence = projectConfig.repos
|
|
354
354
|
.map((repo) => `- \`${repo.id}:/\` — declared repository root`)
|
|
@@ -379,7 +379,7 @@ ${repoLines}
|
|
|
379
379
|
## Coverage
|
|
380
380
|
Confirmed:
|
|
381
381
|
- Project identity and mode from \`project.yaml\`
|
|
382
|
-
- Declared repository IDs and
|
|
382
|
+
- Declared repository IDs and source descriptors from \`project.yaml\`
|
|
383
383
|
- Project-memory root layout created by \`vibecompass init\`
|
|
384
384
|
|
|
385
385
|
Not yet documented:
|
|
@@ -425,7 +425,7 @@ Do not copy this example as-is. Allocate real decision IDs from the current cano
|
|
|
425
425
|
function generateStarterSessionNote(options) {
|
|
426
426
|
const sessionDate = sessionDateFromGeneratedAt(options.generatedAt);
|
|
427
427
|
const projectConfig = options.projectConfig;
|
|
428
|
-
const repoLines = projectConfig.repos.map((repo) => `- \`${repo.id}\` — ${repo
|
|
428
|
+
const repoLines = projectConfig.repos.map((repo) => `- \`${repo.id}\` — ${formatRepoDescriptor(repo)}`).join('\n');
|
|
429
429
|
|
|
430
430
|
return `# Session — ${sessionDate}-1 — Project Memory Initialized
|
|
431
431
|
|
|
@@ -458,6 +458,14 @@ ${repoLines}
|
|
|
458
458
|
`;
|
|
459
459
|
}
|
|
460
460
|
|
|
461
|
+
function formatRepoDescriptor(repo) {
|
|
462
|
+
if (repo.source === 'local') {
|
|
463
|
+
return `local folder ${repo.path}`;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return repo.remote;
|
|
467
|
+
}
|
|
468
|
+
|
|
461
469
|
function generateArchitectureGuide(projectConfig) {
|
|
462
470
|
return `# Architecture
|
|
463
471
|
|
package/src/setup.js
CHANGED
|
@@ -882,12 +882,13 @@ async function promptForRepos(prompter, cwd) {
|
|
|
882
882
|
|
|
883
883
|
for (let index = 0; index < repoCount; index += 1) {
|
|
884
884
|
const ordinal = index + 1;
|
|
885
|
-
const
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
885
|
+
const repoId = await askInput(prompter, `Repo ${ordinal} id`, {
|
|
886
|
+
defaultValue: repoCount === 1 ? repoIdDefault : `repo-${ordinal}`,
|
|
887
|
+
});
|
|
888
|
+
const remote = await askOptionalInput(prompter, `Repo ${ordinal} remote (blank for local folder)`);
|
|
889
|
+
const repo = remote
|
|
890
|
+
? { id: repoId, remote }
|
|
891
|
+
: { id: repoId, source: 'local', path: '.' };
|
|
891
892
|
|
|
892
893
|
const defaultBranch = await askOptionalInput(prompter, `Repo ${ordinal} default branch`);
|
|
893
894
|
if (defaultBranch) {
|
package/src/status.js
CHANGED
|
@@ -143,7 +143,9 @@ async function readProjectSummary(projectFilePath) {
|
|
|
143
143
|
.filter((repo) => repo && typeof repo === 'object')
|
|
144
144
|
.map((repo) => ({
|
|
145
145
|
id: typeof repo.id === 'string' ? repo.id : null,
|
|
146
|
+
source: typeof repo.source === 'string' ? repo.source : (typeof repo.remote === 'string' ? 'git' : 'local'),
|
|
146
147
|
remote: typeof repo.remote === 'string' ? repo.remote : null,
|
|
148
|
+
path: typeof repo.path === 'string' ? repo.path : null,
|
|
147
149
|
defaultBranch: typeof repo.default_branch === 'string' ? repo.default_branch : null,
|
|
148
150
|
}))
|
|
149
151
|
.filter((repo) => repo.id)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { PACKAGE_VERSION } from '../version.js';
|
|
2
|
+
|
|
1
3
|
export const WORKFLOW_REGISTRY = [
|
|
2
4
|
{
|
|
3
5
|
id: 'session-lifecycle',
|
|
@@ -88,6 +90,8 @@ function renderDocsReviewWorkflow(options = {}) {
|
|
|
88
90
|
const decisionsPath = joinRootRelative(rootRelativePath, 'decisions/');
|
|
89
91
|
const sessionsPath = joinRootRelative(rootRelativePath, 'sessions/');
|
|
90
92
|
const outputPath = joinRootRelative(rootRelativePath, 'state/docs-review-output.md');
|
|
93
|
+
const applyCommand = `vibecompass docs-review --root ${rootRelativePath} --apply-output`;
|
|
94
|
+
const npxApplyCommand = `npx -y @vibecompass/vibecompass@${PACKAGE_VERSION} docs-review --root ${rootRelativePath} --apply-output`;
|
|
91
95
|
|
|
92
96
|
return `# VibeCompass Workflow — docs review
|
|
93
97
|
|
|
@@ -99,7 +103,7 @@ When the user says \`docs review\`, run this workflow inside the current Claude
|
|
|
99
103
|
|
|
100
104
|
## Goal
|
|
101
105
|
|
|
102
|
-
Turn starter project memory into evidence-backed architecture docs under \`architecture/<domain>/<feature>/<component>.md\`, a projected coverage plan, and optional accepted decision recommendations.
|
|
106
|
+
Turn starter project memory into evidence-backed architecture docs under \`architecture/<domain>/<feature>/<component>.md\`, a projected coverage plan, a journey-aware project map, and optional accepted decision recommendations.
|
|
103
107
|
|
|
104
108
|
## Steps
|
|
105
109
|
|
|
@@ -109,11 +113,11 @@ Turn starter project memory into evidence-backed architecture docs under \`archi
|
|
|
109
113
|
- produce a coverage plan before reading broad source bodies
|
|
110
114
|
- read targeted source files only when the coverage plan needs evidence
|
|
111
115
|
3. Run \`vibecompass docs-review --guided --llm <tool-name> --model <model-name>\` to record the review marker and print the canonical docs-review contract. Use the current AI tool name and model when known.
|
|
112
|
-
4. Present the evidence inventory, coverage plan, proposed architecture docs, blindspots, token-budget risks, and any decision candidates before generating accepted output.
|
|
113
|
-
5. Draft only output the user accepts. The accepted plan must be fenced as \`vibecompass-coverage-plan version=1\`. Accepted architecture docs must be fenced as \`vibecompass-architecture-doc path=architecture/domain/feature/component.md\` blocks and must include required frontmatter: \`domain\`, \`feature\`, \`component\`, and \`status\`. Accepted local decisions may be fenced as \`vibecompass-decision-recommendation target=decisions/domain.md\` blocks without D-numbers.
|
|
116
|
+
4. Present the evidence inventory, coverage plan, user journey, project/system map, proposed architecture docs, blindspots, token-budget risks, and any decision candidates before generating accepted output.
|
|
117
|
+
5. Draft only output the user accepts. The accepted plan must be fenced as \`vibecompass-coverage-plan version=1\`. Accepted architecture docs must be fenced as \`vibecompass-architecture-doc path=architecture/domain/feature/component.md\` blocks and must include required frontmatter: \`domain\`, \`feature\`, \`component\`, and \`status\`. The accepted \`architecture/overview/project-shape.md\` doc should include exactly one \`vibecompass-project-map version=1\` JSON block with journey-facing features, entry points, and evidence-backed relationships. Accepted local decisions may be fenced as \`vibecompass-decision-recommendation target=decisions/domain.md\` blocks without D-numbers.
|
|
114
118
|
6. Keep each generated architecture doc focused and retrieval-oriented. Soft budget: under 12000 bytes per doc unless the extra detail is necessary and called out in review metadata or retrieval guidance.
|
|
115
|
-
7. Write the accepted fenced blocks to \`${outputPath}\`.
|
|
116
|
-
8. Run \`
|
|
119
|
+
7. Write the accepted fenced blocks verbatim to \`${outputPath}\`.
|
|
120
|
+
8. Run \`${applyCommand}\` to validate and apply the accepted blocks. If \`vibecompass\` is not installed on PATH, run \`${npxApplyCommand}\` instead. If accepted docs were written manually outside the output file, run \`vibecompass docs-review --root ${rootRelativePath} --complete\` after confirming the marker should be completed.
|
|
117
121
|
9. Run \`vibecompass status\` to confirm the docs-review marker is complete and not drifted. Report the applied architecture paths, coverage projection, decision recommendations, parser warnings such as oversized docs or missing review metadata, and any blindspots documented in the accepted docs-review output.
|
|
118
122
|
|
|
119
123
|
## Rebuild option
|