@vibecompass/vibecompass 0.10.3 → 0.10.5

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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.10.5 - 2026-06-20
4
+
5
+ - Include compact docs-review evidence summaries in hosted review submissions, covering coverage score basis, source-inventory totals, documentation-plan totals, reconciliation deltas, producer stamps, and warning provenance.
6
+ - Bump docs-review to `VibeCompass Docs Review Prompt v7` and reject accepted coverage plans where `areas[].linked_inventory_ids[]` references inventory IDs missing from the same plan's `completeness_inventory[]`; hosted parsing now enforces the same contract under `hosted-docs-review-parser-v6`.
7
+ - Preserve optional `completeness_inventory[].repo_id` and `confidence` fields in accepted coverage-plan projections for hosted source-inventory filtering.
8
+
9
+ ## 0.10.4 - 2026-06-19
10
+
11
+ - Add `vibecompass --version`, `vibecompass -v`, and `vibecompass version` CLI support.
12
+ - Make bare `vibecompass init` errors point users to `vibecompass init --guided`.
13
+ - Clarify guided first-session prompts so lane IDs are presented as short kebab-case slugs and reserved yes/no answers explain that pressing Enter accepts the suggested slug.
14
+ - Propagate declared project repo ids into the first lane opened by guided init.
15
+
3
16
  ## 0.10.3 - 2026-06-19
4
17
 
5
18
  - Let `start-session` create a missing `## Current session` summary block in adopted existing `CLAUDE.md` files instead of failing after guided init.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibecompass/vibecompass",
3
- "version": "0.10.3",
3
+ "version": "0.10.5",
4
4
  "description": "Local-first project-memory core for VibeCompass",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -10,6 +10,7 @@ import { syncAgentInstructionFiles } from './generators/agent-files/index.js';
10
10
  import { getProjectStatus, renderStatusText, toStatusJson } from './status.js';
11
11
  import { refreshWorkflow } from './refresh-workflow.js';
12
12
  import { inspectProjectCompatibility, formatCompatibilityWarnings } from './compatibility.js';
13
+ import { PACKAGE_VERSION } from './version.js';
13
14
  import {
14
15
  applyPullExport,
15
16
  pullExportProjectMemory,
@@ -25,6 +26,11 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
25
26
  return 0;
26
27
  }
27
28
 
29
+ if (parsed.command === 'version') {
30
+ io.stdout.write(`${PACKAGE_VERSION}\n`);
31
+ return 0;
32
+ }
33
+
28
34
  if (parsed.command === 'init') {
29
35
  const initPlan = await resolveInitCliOptions(parsed.options, {
30
36
  cwd: runtime.cwd,
@@ -99,6 +105,7 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
99
105
  toolingRootDir: initPlan.initOptions.toolingRootDir,
100
106
  sessionId: initPlan.sessionPlan.sessionId,
101
107
  workingOn: initPlan.sessionPlan.workingOn,
108
+ repos: initPlan.sessionPlan.repos,
102
109
  ...(runtime.cwd ? { cwd: runtime.cwd } : {}),
103
110
  });
104
111
  io.stdout.write(`Started session ${sessionResult.sessionDate}-${sessionResult.sessionNumber}\n`);
@@ -425,6 +432,10 @@ export function parseCliArgs(argv) {
425
432
  return { command: 'help' };
426
433
  }
427
434
 
435
+ if (command === 'version' || command === '--version' || command === '-v') {
436
+ return { command: 'version' };
437
+ }
438
+
428
439
  if (command !== 'init') {
429
440
  if (command === 'start-session') {
430
441
  return parseStartSessionArgs(rest);
@@ -1495,6 +1506,8 @@ function splitAssignment(value, flagName) {
1495
1506
  function usageText() {
1496
1507
  return [
1497
1508
  'Usage:',
1509
+ ' vibecompass --version',
1510
+ ' vibecompass version',
1498
1511
  ' vibecompass init --name <project-name> --mode <local-only|local-primary|hosted-only> --repo <id=remote> [options]',
1499
1512
  ' vibecompass connect-hosted [options]',
1500
1513
  ' vibecompass sync-target [<name>] [options]',
@@ -17,8 +17,9 @@ import {
17
17
  import { readSyncCursor, resolveSyncBinding } from './sync-binding.js';
18
18
  import { PACKAGE_VERSION } from './version.js';
19
19
 
20
- const DOCS_REVIEW_PROMPT_VERSION = 'VibeCompass Docs Review Prompt v6';
20
+ const DOCS_REVIEW_PROMPT_VERSION = 'VibeCompass Docs Review Prompt v7';
21
21
  const DOCS_REVIEW_PARSER_VERSION = 'docs-review-parser-v1';
22
+ const DOCS_REVIEW_ACCEPTED_OUTPUT_CONTRACT_VERSION = 'docs-review-accepted-output-v7';
22
23
  const DOCS_REVIEW_DOCUMENTATION_PLAN_PROJECTION_VERSION = 'docs-review-documentation-plan-v1';
23
24
  const DOCUMENTATION_PLAN_STATE_VERSION = 1;
24
25
  const ARCHITECTURE_DOC_SOFT_SIZE_LIMIT_BYTES = 12000;
@@ -26,6 +27,7 @@ const COVERAGE_PLAN_OUTPUT_VERSION = 1;
26
27
  const COVERAGE_PLAN_STATUSES = new Set(['accepted', 'deferred', 'missing']);
27
28
  const COVERAGE_LEVELS = new Set(['comprehensive', 'partial', 'initial', 'missing']);
28
29
  const ANCHOR_ACTIONS = new Set(['reuse', 'update', 'split', 'merge', 'defer', 'replace', 'new']);
30
+ const SOURCE_CONFIDENCE_LEVELS = new Set(['high', 'medium', 'low']);
29
31
  const DOCUMENTATION_PLAN_RUN_SCOPES = new Set(['baseline', 'deepening']);
30
32
  const REBUILD_STALE_POLICIES = new Set(['keep', 'archive']);
31
33
  const PROJECT_MAP_PATH = 'architecture/overview/project-shape.md';
@@ -984,6 +986,7 @@ function buildCoverageProjection(blocks, options) {
984
986
  const areaById = new Map(areas.map((area) => [area.id, area]));
985
987
  const hasCompletenessInventory = Object.prototype.hasOwnProperty.call(plan, 'completeness_inventory');
986
988
  const completenessInventory = normalizeCompletenessInventory(plan.completeness_inventory, areaById);
989
+ validateCoverageAreaInventoryLinks(areas, completenessInventory);
987
990
  const statuses = countBy(areas, 'status');
988
991
  const coverage_levels = countBy(areas, 'coverage');
989
992
  const inventory_statuses = countBy(completenessInventory, 'status');
@@ -994,6 +997,7 @@ function buildCoverageProjection(blocks, options) {
994
997
  package_version: PACKAGE_VERSION,
995
998
  prompt_version: DOCS_REVIEW_PROMPT_VERSION,
996
999
  parser_version: DOCS_REVIEW_PARSER_VERSION,
1000
+ accepted_output_contract: DOCS_REVIEW_ACCEPTED_OUTPUT_CONTRACT_VERSION,
997
1001
  coverage_projection_version: COVERAGE_PLAN_OUTPUT_VERSION,
998
1002
  ...(options.sourceInventory?.producer?.scanner_version
999
1003
  ? { scanner_version: options.sourceInventory.producer.scanner_version }
@@ -1061,6 +1065,7 @@ function buildDocumentationPlanProjection(coverageProjection, sourceInventory, o
1061
1065
  package_version: PACKAGE_VERSION,
1062
1066
  prompt_version: DOCS_REVIEW_PROMPT_VERSION,
1063
1067
  parser_version: DOCS_REVIEW_PARSER_VERSION,
1068
+ accepted_output_contract: DOCS_REVIEW_ACCEPTED_OUTPUT_CONTRACT_VERSION,
1064
1069
  documentation_plan_projection_version: DOCS_REVIEW_DOCUMENTATION_PLAN_PROJECTION_VERSION,
1065
1070
  coverage_projection_version: coverageProjection.version,
1066
1071
  ...(sourceInventory?.producer?.scanner_version
@@ -1177,8 +1182,12 @@ function normalizeCompletenessInventoryItem(item, index, ids, areaById, unknownC
1177
1182
 
1178
1183
  return {
1179
1184
  id,
1185
+ ...(normalizeOptionalString(item.repo_id) ? { repo_id: normalizeOptionalString(item.repo_id) } : {}),
1180
1186
  ...(normalizeOptionalString(item.kind) ? { kind: normalizeOptionalString(item.kind) } : {}),
1181
1187
  ...(normalizeOptionalString(item.label) ? { label: normalizeOptionalString(item.label) } : {}),
1188
+ ...(SOURCE_CONFIDENCE_LEVELS.has(normalizeOptionalString(item.confidence) ?? '')
1189
+ ? { confidence: normalizeOptionalString(item.confidence) }
1190
+ : {}),
1182
1191
  status,
1183
1192
  ...(coverageAreaIds.length > 0 ? { coverage_area_ids: coverageAreaIds } : {}),
1184
1193
  evidence: normalizeStringArray(item.evidence),
@@ -1193,6 +1202,28 @@ function formatUnknownCoverageAreaReferences(references) {
1193
1202
  return `Coverage plan completeness_inventory references unknown coverage area ids: ${formatted}`;
1194
1203
  }
1195
1204
 
1205
+ function validateCoverageAreaInventoryLinks(areas, completenessInventory) {
1206
+ const inventoryIds = new Set(completenessInventory.map((item) => item.id));
1207
+ const unknownInventoryReferences = [];
1208
+ for (const area of areas) {
1209
+ for (const inventoryId of area.linked_inventory_ids ?? []) {
1210
+ if (!inventoryIds.has(inventoryId)) {
1211
+ unknownInventoryReferences.push({ areaId: area.id, inventoryId });
1212
+ }
1213
+ }
1214
+ }
1215
+ if (unknownInventoryReferences.length > 0) {
1216
+ throw new Error(formatUnknownLinkedInventoryReferences(unknownInventoryReferences));
1217
+ }
1218
+ }
1219
+
1220
+ function formatUnknownLinkedInventoryReferences(references) {
1221
+ const formatted = references
1222
+ .map((reference) => `"${reference.areaId}" -> "${reference.inventoryId}"`)
1223
+ .join(', ');
1224
+ return `Coverage plan areas reference unknown linked_inventory_ids: ${formatted}`;
1225
+ }
1226
+
1196
1227
  function normalizeCoverageArea(area, index, ids) {
1197
1228
  if (!area || typeof area !== 'object' || Array.isArray(area)) {
1198
1229
  throw new Error(`Coverage plan area at index ${index} must be an object.`);
@@ -1461,6 +1492,7 @@ async function submitHostedDocsReview(options) {
1461
1492
  const baselineRemoteRevisionId = normalizeUuid(
1462
1493
  submitCursor.last_successful_remote_revision,
1463
1494
  );
1495
+ const evidenceScope = await buildHostedDocsReviewEvidenceScope(options);
1464
1496
  const response = await options.fetch(endpoint.href, {
1465
1497
  method: 'POST',
1466
1498
  headers: {
@@ -1481,11 +1513,7 @@ async function submitHostedDocsReview(options) {
1481
1513
  ? { baseline_remote_revision_id: baselineRemoteRevisionId }
1482
1514
  : {}),
1483
1515
  local_root_revision: options.manifest?.manifest?.canonical?.local_root_revision,
1484
- evidence_scope: {
1485
- manifest_hash: options.manifest?.manifest?.canonical?.manifest_hash,
1486
- document_count: options.manifest?.manifest?.canonical?.document_count,
1487
- warning_count: options.manifest?.manifest?.canonical?.warning_count,
1488
- },
1516
+ evidence_scope: evidenceScope,
1489
1517
  }),
1490
1518
  });
1491
1519
 
@@ -1517,6 +1545,75 @@ async function submitHostedDocsReview(options) {
1517
1545
  };
1518
1546
  }
1519
1547
 
1548
+ async function buildHostedDocsReviewEvidenceScope(options) {
1549
+ const rootDir = options.rootDir;
1550
+ const coverage = rootDir
1551
+ ? await readJsonOptional(path.join(rootDir, 'state', 'docs-review-coverage.json'))
1552
+ : null;
1553
+ const sourceInventory = rootDir
1554
+ ? await readJsonOptional(docsReviewSourceInventoryPath(rootDir))
1555
+ : null;
1556
+ const documentationPlan = rootDir
1557
+ ? await readJsonOptional(path.join(rootDir, 'state', 'docs-review-documentation-plan.json'))
1558
+ : null;
1559
+ const warnings = Array.isArray(coverage?.warnings) ? coverage.warnings : [];
1560
+
1561
+ return {
1562
+ manifest_hash: options.manifest?.manifest?.canonical?.manifest_hash,
1563
+ document_count: options.manifest?.manifest?.canonical?.document_count,
1564
+ warning_count: options.manifest?.manifest?.canonical?.warning_count,
1565
+ ...(coverage?.producer ? { producer: coverage.producer } : {}),
1566
+ ...(coverage ? { coverage_summary: summarizeHostedCoverage(coverage) } : {}),
1567
+ ...(coverage?.source_inventory_summary
1568
+ ? { source_inventory_summary: coverage.source_inventory_summary }
1569
+ : sourceInventory
1570
+ ? { source_inventory_summary: summarizeSourceInventory(sourceInventory) }
1571
+ : {}),
1572
+ ...(coverage?.documentation_plan_summary
1573
+ ? { documentation_plan_summary: coverage.documentation_plan_summary }
1574
+ : documentationPlan
1575
+ ? { documentation_plan_summary: summarizeDocumentationPlan(documentationPlan) }
1576
+ : {}),
1577
+ ...(coverage?.reconciliation_summary ? { reconciliation_summary: coverage.reconciliation_summary } : {}),
1578
+ ...(warnings.length > 0 ? { warning_provenance: summarizeWarningProvenance(warnings) } : {}),
1579
+ };
1580
+ }
1581
+
1582
+ async function readJsonOptional(filePath) {
1583
+ try {
1584
+ return JSON.parse(await readFile(filePath, 'utf8'));
1585
+ } catch (error) {
1586
+ if (error?.code === 'ENOENT') {
1587
+ return null;
1588
+ }
1589
+ throw error;
1590
+ }
1591
+ }
1592
+
1593
+ function summarizeHostedCoverage(coverage) {
1594
+ return {
1595
+ path: 'state/docs-review-coverage.json',
1596
+ ...(coverage.score_basis ? { score_basis: coverage.score_basis } : {}),
1597
+ ...(typeof coverage.area_count === 'number' ? { area_count: coverage.area_count } : {}),
1598
+ ...(typeof coverage.coverage_score === 'number' || coverage.coverage_score === null
1599
+ ? { coverage_score: coverage.coverage_score }
1600
+ : {}),
1601
+ ...(coverage.statuses ? { statuses: coverage.statuses } : {}),
1602
+ ...(coverage.coverage_levels ? { coverage_levels: coverage.coverage_levels } : {}),
1603
+ ...(typeof coverage.inventory_count === 'number' ? { inventory_count: coverage.inventory_count } : {}),
1604
+ ...(coverage.inventory_statuses ? { inventory_statuses: coverage.inventory_statuses } : {}),
1605
+ ...(coverage.topology ? { topology: coverage.topology } : {}),
1606
+ ...(coverage.taxonomy?.primary_axis ? { taxonomy_primary_axis: coverage.taxonomy.primary_axis } : {}),
1607
+ };
1608
+ }
1609
+
1610
+ function summarizeWarningProvenance(warnings) {
1611
+ return {
1612
+ warning_count: warnings.length,
1613
+ codes: countBy(warnings, 'code'),
1614
+ };
1615
+ }
1616
+
1520
1617
  function parseJsonObject(value) {
1521
1618
  if (!value) return null;
1522
1619
  try {
@@ -2352,6 +2449,7 @@ function renderReviewPrompt(options) {
2352
2449
  '- Prioritize entry points, user-flow/gating relationships, data ownership, external integrations, jobs/async boundaries, auth/security boundaries, and test surfaces.',
2353
2450
  '- Account for each completeness-inventory item in the coverage plan as accepted, deferred, or missing. Do not inflate coverage by omitting large discovered subsystems; honest deferred/missing entries are expected when the first pass cannot cover everything.',
2354
2451
  '- Before generating prose, self-check that every `completeness_inventory[].coverage_area_ids[]` value points to an `areas[].id` in the same accepted plan. Fix all dangling ids together at the plan gate.',
2452
+ '- Before generating prose, self-check that every `areas[].linked_inventory_ids[]` value points to a `completeness_inventory[].id` in the same accepted plan. Fix all dangling ids together at the plan gate.',
2355
2453
  '- Choose one primary taxonomy axis from topology evidence and keep it stable: single-repo/monolith may default domain-first; multi-repo or multi-surface projects may use platform/repo-first or domain-first with per-surface components. Do not mix taxonomy axes at the same tier unless you explicitly propose and justify a restructuring.',
2356
2454
  '- For every prior architecture doc or project-map feature identity in Re-review Anchors, classify the plan action as `reuse`, `update`, `split`, `merge`, `defer`, or `replace`. Use `new` only for areas not represented by the prior tree.',
2357
2455
  '- Every `split`, `merge`, or `replace` action requires an evidence-backed anchor reason before prose generation. No unexplained slug rename is allowed.',
package/src/init.js CHANGED
@@ -231,7 +231,9 @@ function normalizeInitOptions(options) {
231
231
  : cwd;
232
232
 
233
233
  if (typeof preparedOptions.name !== 'string' || preparedOptions.name.trim() === '') {
234
- throw new Error('init requires a non-empty project name.');
234
+ throw new Error(
235
+ 'init requires a non-empty project name. Run guided setup with `vibecompass init --guided`, or provide `--name <project-name>`.',
236
+ );
235
237
  }
236
238
 
237
239
  if (typeof preparedOptions.mode !== 'string' || !VALID_MODES.has(preparedOptions.mode)) {
package/src/setup.js CHANGED
@@ -104,6 +104,7 @@ export async function resolveInitCliOptions(options, environment = {}) {
104
104
  ? {
105
105
  sessionId: resolved.sessionId,
106
106
  workingOn: resolved.sessionWorkingOn,
107
+ repos: resolved.repos.map((repo) => repo.id),
107
108
  }
108
109
  : null,
109
110
  };
@@ -608,14 +609,15 @@ async function completeGuidedInitOptions(options, environment) {
608
609
  }
609
610
 
610
611
  if (!resolved.sessionWorkingOn) {
611
- resolved.sessionWorkingOn = await askInput(prompter, 'What are you working on?');
612
+ resolved.sessionWorkingOn = await askInput(prompter, 'Work summary for this first session');
612
613
  }
613
614
 
614
615
  if (!resolved.sessionId) {
615
- resolved.sessionId = await askInput(prompter, 'Session lane id', {
616
- defaultValue: suggestLaneId(resolved.sessionWorkingOn),
616
+ const defaultSessionId = suggestLaneId(resolved.sessionWorkingOn);
617
+ resolved.sessionId = await askInput(prompter, 'Session lane id, short kebab-case slug', {
618
+ defaultValue: defaultSessionId,
617
619
  validate(value) {
618
- return validateLaneIdForPrompt(value);
620
+ return validateLaneIdForPrompt(value, defaultSessionId);
619
621
  },
620
622
  });
621
623
  }
@@ -1245,7 +1247,7 @@ function suggestLaneId(value) {
1245
1247
  return slug.length >= 3 ? slug : 'builder-session';
1246
1248
  }
1247
1249
 
1248
- function validateLaneIdForPrompt(value) {
1250
+ function validateLaneIdForPrompt(value, defaultValue) {
1249
1251
  if (!/^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/.test(value)) {
1250
1252
  return 'Lane id must be 3-64 lowercase letters, numbers, or hyphens, and must start and end with a letter or number.';
1251
1253
  }
@@ -1268,7 +1270,7 @@ function validateLaneIdForPrompt(value) {
1268
1270
  'wip',
1269
1271
  'yes',
1270
1272
  ].includes(value)) {
1271
- return `Lane id "${value}" is reserved.`;
1273
+ return `Lane id "${value}" is reserved. Enter a short kebab-case lane id, or press Enter to use "${defaultValue}".`;
1272
1274
  }
1273
1275
 
1274
1276
  return null;