@vibecompass/vibecompass 0.6.0 → 0.8.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/src/sync.js CHANGED
@@ -3,6 +3,11 @@ import path from 'node:path';
3
3
  import { sha256Text } from './hash.js';
4
4
  import { writeStateManifest } from './manifest.js';
5
5
  import { parseSimpleYaml } from './simple-yaml.js';
6
+ import {
7
+ buildSyncStateWithCursor,
8
+ readSyncCursor,
9
+ resolveSyncBinding,
10
+ } from './sync-binding.js';
6
11
 
7
12
  const DEFAULT_EXPORT_PATH = 'state/pull-export.json';
8
13
 
@@ -14,7 +19,8 @@ export async function pushProjectMemory(options = {}, environment = {}) {
14
19
  });
15
20
  const manifest = manifestResult.manifest;
16
21
  const documents = await readPushDocuments(context.rootDir, manifest.documents);
17
- const baseRemoteRevisionId = normalizeUuid(manifest.sync?.last_successful_remote_revision);
22
+ const cursor = readSyncCursor(manifest.sync, context.binding);
23
+ const baseRemoteRevisionId = normalizeUuid(cursor.last_successful_remote_revision);
18
24
  const body = {
19
25
  ...(baseRemoteRevisionId ? { base_remote_revision_id: baseRemoteRevisionId } : {}),
20
26
  local_root_revision: manifest.canonical.local_root_revision,
@@ -25,15 +31,15 @@ export async function pushProjectMemory(options = {}, environment = {}) {
25
31
 
26
32
  const response = await postJson(context, 'push', body);
27
33
  const now = new Date().toISOString();
28
- const sync = {
29
- ...(manifest.sync ?? {}),
34
+ const sync = buildSyncStateWithCursor(manifest.sync, context.binding, {
35
+ ...cursor,
30
36
  last_successful_remote_revision: response.remote_revision_id,
31
37
  last_successful_local_root_revision: manifest.canonical.local_root_revision,
32
38
  last_successful_manifest_hash: manifest.canonical.manifest_hash,
33
39
  last_sync_direction: 'push',
34
40
  last_sync_at: now,
35
41
  pending_previews: [],
36
- };
42
+ });
37
43
  const updatedManifest = await writeStateManifest(context.rootDir, { sync });
38
44
 
39
45
  return {
@@ -55,10 +61,11 @@ export async function pullPreviewProjectMemory(options = {}, environment = {}) {
55
61
  sync: existingManifest?.sync,
56
62
  });
57
63
  const manifest = manifestResult.manifest;
64
+ const cursor = readSyncCursor(manifest.sync, context.binding);
58
65
 
59
66
  const response = await postJson(context, 'pull-preview', {
60
67
  state_version: manifest.state_version,
61
- base_remote_revision_id: normalizeUuid(manifest.sync?.last_successful_remote_revision),
68
+ base_remote_revision_id: normalizeUuid(cursor.last_successful_remote_revision),
62
69
  local_root_revision: manifest.canonical.local_root_revision,
63
70
  local_manifest_hash: manifest.canonical.manifest_hash,
64
71
  local_documents: buildLocalDocumentSummaries(manifest.documents),
@@ -81,13 +88,13 @@ export async function pullPreviewProjectMemory(options = {}, environment = {}) {
81
88
  created_at: response.created_at ?? new Date().toISOString(),
82
89
  expires_at: response.expires_at,
83
90
  };
84
- const sync = {
85
- ...(manifest.sync ?? {}),
91
+ const sync = buildSyncStateWithCursor(manifest.sync, context.binding, {
92
+ ...cursor,
86
93
  pending_previews: [
87
- ...(Array.isArray(manifest.sync?.pending_previews) ? manifest.sync.pending_previews : []),
94
+ ...(Array.isArray(cursor.pending_previews) ? cursor.pending_previews : []),
88
95
  previewRecord,
89
96
  ].slice(-5),
90
- };
97
+ });
91
98
  const updatedManifest = await writeStateManifest(context.rootDir, { sync });
92
99
 
93
100
  return {
@@ -105,7 +112,7 @@ export async function pullPreviewProjectMemory(options = {}, environment = {}) {
105
112
  export async function pullExportProjectMemory(options = {}, environment = {}) {
106
113
  const context = await loadSyncContext(options, environment);
107
114
  const manifest = await readRequiredManifest(context.manifestPath);
108
- const preview = resolvePreview(manifest, options.previewToken);
115
+ const preview = resolvePreview(manifest, options.previewToken, context.binding);
109
116
  const proposalIds = options.proposalIds?.length
110
117
  ? options.proposalIds
111
118
  : preview.available_proposal_ids ?? [];
@@ -200,18 +207,15 @@ async function loadSyncContext(options, environment) {
200
207
  if (project.mode !== 'local-primary') {
201
208
  throw new Error('Hosted sync commands require project.yaml mode: local-primary.');
202
209
  }
203
- if (
204
- !project.sync ||
205
- typeof project.sync.api_url !== 'string' ||
206
- typeof project.sync.project_id !== 'string' ||
207
- typeof project.sync.credential_env_var !== 'string'
208
- ) {
209
- throw new Error('Hosted sync commands require sync.api_url, sync.project_id, and sync.credential_env_var in project.yaml.');
210
+
211
+ const binding = resolveSyncBinding(project, options.syncTarget ?? null);
212
+ if (!binding) {
213
+ throw new Error('Hosted sync commands require sync.api_url, sync.project_id, and sync.credential_env_var in project.yaml (or a named target under sync.targets).');
210
214
  }
211
215
 
212
- const credential = normalizeOptionalString((environment.env ?? process.env)[project.sync.credential_env_var]);
216
+ const credential = normalizeOptionalString((environment.env ?? process.env)[binding.credentialEnvVar]);
213
217
  if (!credential) {
214
- throw new Error(`Hosted sync command requires ${project.sync.credential_env_var}.`);
218
+ throw new Error(`Hosted sync command requires ${binding.credentialEnvVar}.`);
215
219
  }
216
220
 
217
221
  const fetchImpl = environment.runtime?.fetch ?? globalThis.fetch;
@@ -225,8 +229,10 @@ async function loadSyncContext(options, environment) {
225
229
  manifestPath,
226
230
  fetch: fetchImpl,
227
231
  credential,
228
- apiUrl: project.sync.api_url,
229
- projectId: project.sync.project_id,
232
+ apiUrl: binding.apiUrl,
233
+ projectId: binding.projectId,
234
+ syncTarget: binding.target,
235
+ binding,
230
236
  };
231
237
  }
232
238
 
@@ -308,9 +314,10 @@ function buildLocalDocumentExtractedSummary(kind, extracted = {}) {
308
314
  return {};
309
315
  }
310
316
 
311
- function resolvePreview(manifest, previewToken) {
312
- const previews = Array.isArray(manifest.sync?.pending_previews)
313
- ? manifest.sync.pending_previews
317
+ function resolvePreview(manifest, previewToken, binding) {
318
+ const cursor = readSyncCursor(manifest.sync, binding);
319
+ const previews = Array.isArray(cursor.pending_previews)
320
+ ? cursor.pending_previews
314
321
  : [];
315
322
  if (previewToken) {
316
323
  const match = previews.find((preview) => preview.preview_token === previewToken);
@@ -95,11 +95,11 @@ Generated by VibeCompass. This file is a package-owned workflow guide and may be
95
95
 
96
96
  ## Prompt trigger
97
97
 
98
- When the user says \`docs review\`, run this workflow inside the current Claude Code, Codex, Cursor, or Copilot session. The npm package owns state markers and apply mechanics; the AI session owns repository inspection and writing accepted architecture docs.
98
+ When the user says \`docs review\`, run this workflow inside the current Claude Code, Codex, Cursor, or Copilot session. The npm package owns state markers and apply mechanics; the AI session owns repository inspection and writing accepted docs-review output.
99
99
 
100
100
  ## Goal
101
101
 
102
- Turn starter project memory into evidence-backed architecture docs under \`architecture/<domain>/<feature>/<component>.md\`.
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.
103
103
 
104
104
  ## Steps
105
105
 
@@ -109,12 +109,16 @@ Turn starter project memory into evidence-backed architecture docs under \`archi
109
109
  - produce a coverage plan before reading broad source bodies
110
110
  - read targeted source files only when the coverage plan needs evidence
111
111
  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, and token-budget risks before generating accepted docs.
113
- 5. Draft only architecture docs the user accepts. Accepted docs must be fenced exactly as \`vibecompass-architecture-doc path=architecture/domain/feature/component.md\` blocks and must include required frontmatter: \`domain\`, \`feature\`, \`component\`, and \`status\`.
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.
114
114
  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
115
  7. Write the accepted fenced blocks to \`${outputPath}\`.
116
116
  8. Run \`vibecompass docs-review --apply-output\` to validate and apply the accepted blocks. If accepted docs were written manually outside the output file, run \`vibecompass docs-review --complete\` after confirming the marker should be completed.
117
- 9. Run \`vibecompass status\` to confirm the docs-review marker is complete. Report the applied architecture paths, any parser warnings such as oversized docs, and any blindspots documented in the accepted docs-review output.
117
+ 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
+
119
+ ## Rebuild option
120
+
121
+ If the user explicitly wants to rerun docs-review from a clean or narrower architecture-doc slate, preview the scope first with \`vibecompass docs-review --rebuild --path architecture/<scope>\`. Only apply cleanup after the user accepts the preview; use \`vibecompass docs-review --rebuild --apply --stale-policy archive --path architecture/<scope>\` when the user explicitly wants selected stale docs archived before the next review. Rebuild archives selected \`architecture/**/*.md\` docs under \`state/docs-review-archive/\`; it does not mutate decisions, sessions, project.yaml, workflow files, agent instruction files, \`architecture/README.md\`, or \`architecture/overview/project-shape.md\`.
118
122
 
119
123
  ## Rules
120
124