@vibecompass/vibecompass 0.3.3 → 0.4.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 +185 -11
- package/package.json +1 -1
- package/src/cli.js +288 -0
- package/src/compatibility.js +308 -0
- package/src/generators/agent-files/index.js +57 -1
- package/src/generators/agent-files/markers.js +10 -1
- package/src/generators/agent-files/template.js +4 -0
- package/src/index.js +5 -1
- package/src/init.js +42 -2
- package/src/manifest.js +16 -4
- package/src/read-model.js +17 -1
- package/src/refresh-workflow.js +233 -0
- package/src/scaffold.js +38 -18
- package/src/setup.js +336 -0
- package/src/status.js +350 -0
- package/src/version.js +6 -0
package/src/cli.js
CHANGED
|
@@ -7,6 +7,9 @@ import { preflightDocsReview } from './docs-review.js';
|
|
|
7
7
|
import { resolveConnectHostedCliOptions, resolveInitCliOptions } from './setup.js';
|
|
8
8
|
import { closeProjectSession, listProjectSessions, startProjectSession, switchProjectSession } from './session.js';
|
|
9
9
|
import { syncAgentInstructionFiles } from './generators/agent-files/index.js';
|
|
10
|
+
import { getProjectStatus, renderStatusText, toStatusJson } from './status.js';
|
|
11
|
+
import { refreshWorkflow } from './refresh-workflow.js';
|
|
12
|
+
import { inspectProjectCompatibility, formatCompatibilityWarnings } from './compatibility.js';
|
|
10
13
|
import {
|
|
11
14
|
applyPullExport,
|
|
12
15
|
pullExportProjectMemory,
|
|
@@ -28,6 +31,10 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
28
31
|
io,
|
|
29
32
|
runtime,
|
|
30
33
|
});
|
|
34
|
+
if (initPlan.existingProject) {
|
|
35
|
+
return writeExistingInitProjectResult(io, initPlan.existingProject);
|
|
36
|
+
}
|
|
37
|
+
|
|
31
38
|
const result = await initializeProjectMemory({
|
|
32
39
|
...initPlan.initOptions,
|
|
33
40
|
...(runtime.cwd ? { cwd: runtime.cwd } : {}),
|
|
@@ -78,6 +85,14 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
78
85
|
io.stdout.write(`Left existing ${filePath} untouched\n`);
|
|
79
86
|
}
|
|
80
87
|
|
|
88
|
+
if (initPlan.agentFileSyncPlan) {
|
|
89
|
+
const agentFileSync = await syncAgentInstructionFiles({
|
|
90
|
+
...initPlan.agentFileSyncPlan,
|
|
91
|
+
...(runtime.cwd ? { cwd: runtime.cwd } : {}),
|
|
92
|
+
});
|
|
93
|
+
writeAgentFileSyncResult(io, agentFileSync);
|
|
94
|
+
}
|
|
95
|
+
|
|
81
96
|
if (initPlan.sessionPlan) {
|
|
82
97
|
const sessionResult = await startProjectSession({
|
|
83
98
|
rootDir: initPlan.initOptions.rootDir,
|
|
@@ -98,6 +113,7 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
98
113
|
}
|
|
99
114
|
|
|
100
115
|
if (parsed.command === 'start-session') {
|
|
116
|
+
await writeCompatibilityPreflightWarnings(io, parsed.options, runtime);
|
|
101
117
|
const result = await startProjectSession({
|
|
102
118
|
...parsed.options,
|
|
103
119
|
...(runtime.cwd ? { cwd: runtime.cwd } : {}),
|
|
@@ -112,6 +128,7 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
112
128
|
}
|
|
113
129
|
|
|
114
130
|
if (parsed.command === 'connect-hosted') {
|
|
131
|
+
await writeCompatibilityPreflightWarnings(io, parsed.options, runtime);
|
|
115
132
|
const connectPlan = await resolveConnectHostedCliOptions(parsed.options, {
|
|
116
133
|
cwd: runtime.cwd,
|
|
117
134
|
io,
|
|
@@ -133,7 +150,30 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
133
150
|
return 0;
|
|
134
151
|
}
|
|
135
152
|
|
|
153
|
+
if (parsed.command === 'status') {
|
|
154
|
+
const result = await getProjectStatus({
|
|
155
|
+
...parsed.options,
|
|
156
|
+
...(runtime.cwd ? { cwd: runtime.cwd } : {}),
|
|
157
|
+
});
|
|
158
|
+
if (parsed.options.json) {
|
|
159
|
+
io.stdout.write(`${JSON.stringify(toStatusJson(result), null, 2)}\n`);
|
|
160
|
+
} else {
|
|
161
|
+
io.stdout.write(renderStatusText(result));
|
|
162
|
+
}
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (parsed.command === 'refresh-workflow') {
|
|
167
|
+
const result = await refreshWorkflow({
|
|
168
|
+
...parsed.options,
|
|
169
|
+
...(runtime.cwd ? { cwd: runtime.cwd } : {}),
|
|
170
|
+
});
|
|
171
|
+
writeRefreshWorkflowResult(io, result);
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
|
|
136
175
|
if (parsed.command === 'close-session' || parsed.command === 'end-session') {
|
|
176
|
+
await writeCompatibilityPreflightWarnings(io, parsed.options, runtime);
|
|
137
177
|
const result = await closeProjectSession({
|
|
138
178
|
...parsed.options,
|
|
139
179
|
...(runtime.cwd ? { cwd: runtime.cwd } : {}),
|
|
@@ -152,6 +192,7 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
152
192
|
}
|
|
153
193
|
|
|
154
194
|
if (parsed.command === 'list-sessions') {
|
|
195
|
+
await writeCompatibilityPreflightWarnings(io, parsed.options, runtime);
|
|
155
196
|
const result = await listProjectSessions({
|
|
156
197
|
...parsed.options,
|
|
157
198
|
...(runtime.cwd ? { cwd: runtime.cwd } : {}),
|
|
@@ -169,6 +210,7 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
169
210
|
}
|
|
170
211
|
|
|
171
212
|
if (parsed.command === 'switch-session') {
|
|
213
|
+
await writeCompatibilityPreflightWarnings(io, parsed.options, runtime);
|
|
172
214
|
const result = await switchProjectSession({
|
|
173
215
|
...parsed.options,
|
|
174
216
|
...(runtime.cwd ? { cwd: runtime.cwd } : {}),
|
|
@@ -180,6 +222,7 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
180
222
|
}
|
|
181
223
|
|
|
182
224
|
if (parsed.command === 'sync-agents') {
|
|
225
|
+
await writeCompatibilityPreflightWarnings(io, parsed.options, runtime);
|
|
183
226
|
const result = await syncAgentInstructionFiles({
|
|
184
227
|
...parsed.options,
|
|
185
228
|
...(runtime.cwd ? { cwd: runtime.cwd } : {}),
|
|
@@ -189,6 +232,7 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
189
232
|
}
|
|
190
233
|
|
|
191
234
|
if (parsed.command === 'docs-review') {
|
|
235
|
+
await writeCompatibilityPreflightWarnings(io, parsed.options, runtime);
|
|
192
236
|
const result = await preflightDocsReview({
|
|
193
237
|
...parsed.options,
|
|
194
238
|
...(runtime.cwd ? { cwd: runtime.cwd } : {}),
|
|
@@ -238,6 +282,7 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
238
282
|
}
|
|
239
283
|
|
|
240
284
|
if (parsed.command === 'push') {
|
|
285
|
+
await writeCompatibilityPreflightWarnings(io, parsed.options, runtime);
|
|
241
286
|
const result = await pushProjectMemory(parsed.options, {
|
|
242
287
|
cwd: runtime.cwd,
|
|
243
288
|
env: runtime.env,
|
|
@@ -258,6 +303,7 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
258
303
|
}
|
|
259
304
|
|
|
260
305
|
if (parsed.command === 'pull-preview') {
|
|
306
|
+
await writeCompatibilityPreflightWarnings(io, parsed.options, runtime);
|
|
261
307
|
const result = await pullPreviewProjectMemory(parsed.options, {
|
|
262
308
|
cwd: runtime.cwd,
|
|
263
309
|
env: runtime.env,
|
|
@@ -282,6 +328,7 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
282
328
|
}
|
|
283
329
|
|
|
284
330
|
if (parsed.command === 'pull-export') {
|
|
331
|
+
await writeCompatibilityPreflightWarnings(io, parsed.options, runtime);
|
|
285
332
|
const result = await pullExportProjectMemory(parsed.options, {
|
|
286
333
|
cwd: runtime.cwd,
|
|
287
334
|
env: runtime.env,
|
|
@@ -297,6 +344,7 @@ export async function runCli(argv, io = createDefaultIo(), runtime = {}) {
|
|
|
297
344
|
}
|
|
298
345
|
|
|
299
346
|
if (parsed.command === 'apply-export') {
|
|
347
|
+
await writeCompatibilityPreflightWarnings(io, parsed.options, runtime);
|
|
300
348
|
const result = await applyPullExport(parsed.options, {
|
|
301
349
|
cwd: runtime.cwd,
|
|
302
350
|
env: runtime.env,
|
|
@@ -330,6 +378,14 @@ export function parseCliArgs(argv) {
|
|
|
330
378
|
return parseConnectHostedArgs(rest);
|
|
331
379
|
}
|
|
332
380
|
|
|
381
|
+
if (command === 'status') {
|
|
382
|
+
return parseStatusArgs(rest);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (command === 'refresh-workflow') {
|
|
386
|
+
return parseRefreshWorkflowArgs(rest);
|
|
387
|
+
}
|
|
388
|
+
|
|
333
389
|
if (command === 'close-session' || command === 'end-session') {
|
|
334
390
|
return parseCloseSessionArgs(rest);
|
|
335
391
|
}
|
|
@@ -382,6 +438,11 @@ export function parseCliArgs(argv) {
|
|
|
382
438
|
continue;
|
|
383
439
|
}
|
|
384
440
|
|
|
441
|
+
if (token === '--replace-active-lanes') {
|
|
442
|
+
parsed.replaceActiveLanes = true;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
|
|
385
446
|
if (token === '--guided') {
|
|
386
447
|
parsed.guided = true;
|
|
387
448
|
continue;
|
|
@@ -402,6 +463,11 @@ export function parseCliArgs(argv) {
|
|
|
402
463
|
continue;
|
|
403
464
|
}
|
|
404
465
|
|
|
466
|
+
if (token === '--adopt-existing-agent-files') {
|
|
467
|
+
parsed.adoptExistingAgentFiles = true;
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
|
|
405
471
|
if (token === '--start-session') {
|
|
406
472
|
parsed.startSession = true;
|
|
407
473
|
continue;
|
|
@@ -503,11 +569,13 @@ export function parseCliArgs(argv) {
|
|
|
503
569
|
mode: parsed.mode,
|
|
504
570
|
repos: parsed.repos,
|
|
505
571
|
force: parsed.force,
|
|
572
|
+
replaceActiveLanes: parsed.replaceActiveLanes,
|
|
506
573
|
startSession: parsed.startSession,
|
|
507
574
|
sessionWorkingOn: parsed.sessionWorkingOn,
|
|
508
575
|
sessionId: parsed.sessionId,
|
|
509
576
|
closeSessionGitPublish: parsed.closeSessionGitPublish,
|
|
510
577
|
closeSessionGitRemote: parsed.closeSessionGitRemote,
|
|
578
|
+
adoptExistingAgentFiles: parsed.adoptExistingAgentFiles,
|
|
511
579
|
...(parsed.withWorkflow || parsed.withClaude || parsed.withAgents
|
|
512
580
|
? {
|
|
513
581
|
bootstrap: {
|
|
@@ -648,6 +716,99 @@ function parseConnectHostedArgs(argv) {
|
|
|
648
716
|
};
|
|
649
717
|
}
|
|
650
718
|
|
|
719
|
+
function parseStatusArgs(argv) {
|
|
720
|
+
const parsed = {};
|
|
721
|
+
|
|
722
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
723
|
+
const token = argv[index];
|
|
724
|
+
|
|
725
|
+
if (token === '--json') {
|
|
726
|
+
parsed.json = true;
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
if (!token.startsWith('--')) {
|
|
731
|
+
throw new Error(`Unexpected argument "${token}".`);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
const value = argv[index + 1];
|
|
735
|
+
if (value === undefined) {
|
|
736
|
+
throw new Error(`Flag "${token}" requires a value.`);
|
|
737
|
+
}
|
|
738
|
+
index += 1;
|
|
739
|
+
|
|
740
|
+
switch (token) {
|
|
741
|
+
case '--root':
|
|
742
|
+
parsed.rootDir = value;
|
|
743
|
+
break;
|
|
744
|
+
case '--tooling-root':
|
|
745
|
+
parsed.toolingRootDir = value;
|
|
746
|
+
break;
|
|
747
|
+
default:
|
|
748
|
+
throw new Error(`Unknown flag "${token}".`);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
return {
|
|
753
|
+
command: 'status',
|
|
754
|
+
options: parsed,
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
function parseRefreshWorkflowArgs(argv) {
|
|
759
|
+
const parsed = {};
|
|
760
|
+
|
|
761
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
762
|
+
const token = argv[index];
|
|
763
|
+
|
|
764
|
+
if (token === '--dry-run') {
|
|
765
|
+
parsed.apply = false;
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (token === '--apply') {
|
|
770
|
+
parsed.apply = true;
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
if (token === '--update-package-stamp') {
|
|
775
|
+
parsed.updatePackageStamp = true;
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
if (token === '--allow-downgrade-templates') {
|
|
780
|
+
parsed.allowDowngradeTemplates = true;
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
if (!token.startsWith('--')) {
|
|
785
|
+
throw new Error(`Unexpected argument "${token}".`);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
const value = argv[index + 1];
|
|
789
|
+
if (value === undefined) {
|
|
790
|
+
throw new Error(`Flag "${token}" requires a value.`);
|
|
791
|
+
}
|
|
792
|
+
index += 1;
|
|
793
|
+
|
|
794
|
+
switch (token) {
|
|
795
|
+
case '--root':
|
|
796
|
+
parsed.rootDir = value;
|
|
797
|
+
break;
|
|
798
|
+
case '--tooling-root':
|
|
799
|
+
parsed.toolingRootDir = value;
|
|
800
|
+
break;
|
|
801
|
+
default:
|
|
802
|
+
throw new Error(`Unknown flag "${token}".`);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
return {
|
|
807
|
+
command: 'refresh-workflow',
|
|
808
|
+
options: parsed,
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
|
|
651
812
|
function parseCloseSessionArgs(argv) {
|
|
652
813
|
const parsed = {
|
|
653
814
|
completed: [],
|
|
@@ -804,6 +965,11 @@ function parseSyncAgentsArgs(argv) {
|
|
|
804
965
|
continue;
|
|
805
966
|
}
|
|
806
967
|
|
|
968
|
+
if (token === '--adopt-existing') {
|
|
969
|
+
parsed.adoptExisting = true;
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
|
|
807
973
|
if (!token.startsWith('--')) {
|
|
808
974
|
throw new Error(`Unexpected argument "${token}".`);
|
|
809
975
|
}
|
|
@@ -1087,7 +1253,51 @@ function writeAgentFileSyncResult(io, result) {
|
|
|
1087
1253
|
const suffix = item.warning ? ` — ${item.warning}` : '';
|
|
1088
1254
|
const stream = item.warning ? io.stderr : io.stdout;
|
|
1089
1255
|
stream.write(`- ${item.relativePath}: ${item.status}${suffix}\n`);
|
|
1256
|
+
if (item.conflicts?.length > 0) {
|
|
1257
|
+
const lineNumbers = item.conflicts.map((conflict) => conflict.line).join(', ');
|
|
1258
|
+
io.stderr.write(` possible workflow overlap on lines ${lineNumbers}; review existing instructions if behavior conflicts.\n`);
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
function writeRefreshWorkflowResult(io, result) {
|
|
1264
|
+
io.stdout.write(`${result.dryRun ? 'Planned' : 'Applied'} workflow refresh for ${result.rootDir}\n`);
|
|
1265
|
+
writeCompatibilityWarnings(io, result.compatibility);
|
|
1266
|
+
io.stdout.write('Project package stamp:\n');
|
|
1267
|
+
const projectSuffix = result.projectFile.warning ? ` — ${result.projectFile.warning}` : '';
|
|
1268
|
+
const projectStatus = result.dryRun && result.projectFile.changed
|
|
1269
|
+
? `dry-run-${result.projectFile.status}`
|
|
1270
|
+
: result.projectFile.status;
|
|
1271
|
+
io.stdout.write(`- project.yaml: ${projectStatus}${projectSuffix}\n`);
|
|
1272
|
+
|
|
1273
|
+
io.stdout.write('Workflow files:\n');
|
|
1274
|
+
for (const file of result.workflowFiles) {
|
|
1275
|
+
const suffix = file.warning ? ` — ${file.warning}` : '';
|
|
1276
|
+
io.stdout.write(`- ${file.relativePath}: ${result.dryRun && file.changed ? `dry-run-${file.status}` : file.status}${suffix}\n`);
|
|
1090
1277
|
}
|
|
1278
|
+
|
|
1279
|
+
io.stdout.write('State manifest:\n');
|
|
1280
|
+
io.stdout.write(`- ${result.manifest.path}: ${result.manifest.status} (${result.manifest.documentCount} canonical docs, ${result.manifest.warningCount} warnings)\n`);
|
|
1281
|
+
writeAgentFileSyncResult(io, result.agentFileSync);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
async function writeCompatibilityPreflightWarnings(io, options = {}, runtime = {}) {
|
|
1285
|
+
const result = await inspectProjectCompatibility({
|
|
1286
|
+
...options,
|
|
1287
|
+
...(runtime.cwd ? { cwd: runtime.cwd } : {}),
|
|
1288
|
+
});
|
|
1289
|
+
writeCompatibilityWarnings(io, result);
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
function writeCompatibilityWarnings(io, result) {
|
|
1293
|
+
const warnings = formatCompatibilityWarnings(result);
|
|
1294
|
+
if (warnings.length === 0) {
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
io.stderr.write('Compatibility warnings:\n');
|
|
1299
|
+
writeWarnings(io, warnings);
|
|
1300
|
+
io.stderr.write('Run `vibecompass status` for detail.\n');
|
|
1091
1301
|
}
|
|
1092
1302
|
|
|
1093
1303
|
function writeWarnings(io, warnings = []) {
|
|
@@ -1110,6 +1320,8 @@ function usageText() {
|
|
|
1110
1320
|
'Usage:',
|
|
1111
1321
|
' vibecompass init --name <project-name> --mode <local-only|local-primary|hosted-only> --repo <id=remote> [options]',
|
|
1112
1322
|
' vibecompass connect-hosted [options]',
|
|
1323
|
+
' vibecompass status [options]',
|
|
1324
|
+
' vibecompass refresh-workflow [--dry-run|--apply] [options]',
|
|
1113
1325
|
' vibecompass start-session --id <lane-id> --working-on <text> [options]',
|
|
1114
1326
|
' vibecompass close-session --title <text> --completed <text> --next-step <text> [options]',
|
|
1115
1327
|
' vibecompass end-session --title <text> --completed <text> --next-step <text> [options] # alias',
|
|
@@ -1138,12 +1350,14 @@ function usageText() {
|
|
|
1138
1350
|
' --with-workflow Scaffold context.md and workflow guide files',
|
|
1139
1351
|
' --with-claude Create a starter CLAUDE.md if missing',
|
|
1140
1352
|
' --with-agents Create a starter AGENTS.md if missing',
|
|
1353
|
+
' --adopt-existing-agent-files Adopt existing unmarked agent files after init',
|
|
1141
1354
|
' --start-session Open the first builder session after init',
|
|
1142
1355
|
' --session-working-on <text> Required with --start-session outside guided mode',
|
|
1143
1356
|
' --session-id <lane-id> Required with --start-session; names the first builder lane',
|
|
1144
1357
|
' --close-session-git-publish Include a Git publish step in the stored close-session workflow',
|
|
1145
1358
|
' --close-session-git-remote <name> Default Git remote name for that close-session publish step',
|
|
1146
1359
|
' --force Overwrite an existing project.yaml',
|
|
1360
|
+
' --replace-active-lanes Allow --force to replace a root that has active session lanes',
|
|
1147
1361
|
'',
|
|
1148
1362
|
'Connect-hosted options:',
|
|
1149
1363
|
' --root <path> Project-memory root. Defaults to .compass',
|
|
@@ -1152,6 +1366,19 @@ function usageText() {
|
|
|
1152
1366
|
' --sync-credential-env-var <name> Hosted sync env var reference',
|
|
1153
1367
|
' Replaces any existing project.yaml sync binding',
|
|
1154
1368
|
'',
|
|
1369
|
+
'Status options:',
|
|
1370
|
+
' --root <path> Project-memory root. Defaults to .compass',
|
|
1371
|
+
' --tooling-root <path> Directory where agent files are inspected. Defaults to cwd',
|
|
1372
|
+
' --json Print the typed status model as JSON',
|
|
1373
|
+
'',
|
|
1374
|
+
'Refresh-workflow options:',
|
|
1375
|
+
' --root <path> Project-memory root. Defaults to .compass',
|
|
1376
|
+
' --tooling-root <path> Directory where agent files are refreshed. Defaults to cwd',
|
|
1377
|
+
' --dry-run Show planned refresh without changing files (default)',
|
|
1378
|
+
' --apply Apply the planned workflow refresh',
|
|
1379
|
+
' --update-package-stamp Update an existing project.yaml package_version stamp',
|
|
1380
|
+
' --allow-downgrade-templates Allow applying templates with a CLI older than the root stamp',
|
|
1381
|
+
'',
|
|
1155
1382
|
'Start-session options:',
|
|
1156
1383
|
' --root <path> Project-memory root. Defaults to .compass',
|
|
1157
1384
|
' --tooling-root <path> Tooling root that contains CLAUDE.md. Defaults to cwd',
|
|
@@ -1187,6 +1414,7 @@ function usageText() {
|
|
|
1187
1414
|
' --root <path> Project-memory root. Defaults to .compass',
|
|
1188
1415
|
' --tooling-root <path> Directory where agent files are written. Defaults to cwd',
|
|
1189
1416
|
' --format <name> Optional format: claude_md, agents_md, cursor_rules, copilot_instructions',
|
|
1417
|
+
' --adopt-existing Append managed blocks to existing unmarked files',
|
|
1190
1418
|
' --dry-run Show planned writes without changing files',
|
|
1191
1419
|
'',
|
|
1192
1420
|
'Sync transport options:',
|
|
@@ -1235,6 +1463,66 @@ function formatOptionalRootFlag(rootDir) {
|
|
|
1235
1463
|
return ` --root ${rootDir}`;
|
|
1236
1464
|
}
|
|
1237
1465
|
|
|
1466
|
+
function writeExistingInitProjectResult(io, existingProject) {
|
|
1467
|
+
const rootFlag = formatOptionalRootFlag(existingProject.displayPath);
|
|
1468
|
+
const active = existingProject.activeSummary ?? { count: 0, current: null };
|
|
1469
|
+
|
|
1470
|
+
if (existingProject.status === 'ambiguous') {
|
|
1471
|
+
(io.stderr ?? process.stderr).write(
|
|
1472
|
+
[
|
|
1473
|
+
'Multiple VibeCompass project memory roots found:',
|
|
1474
|
+
...existingProject.candidates.map((candidate) => `- ${candidate.displayPath}`),
|
|
1475
|
+
'Pass --root explicitly to choose one.',
|
|
1476
|
+
'',
|
|
1477
|
+
].join('\n'),
|
|
1478
|
+
);
|
|
1479
|
+
return 1;
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
if (existingProject.status === 'unreadable') {
|
|
1483
|
+
(io.stderr ?? process.stderr).write('VibeCompass project memory already exists, but project.yaml is unreadable.\n');
|
|
1484
|
+
(io.stderr ?? process.stderr).write(`Root: ${existingProject.displayPath}\n`);
|
|
1485
|
+
(io.stderr ?? process.stderr).write(`Project file: ${existingProject.projectFilePath}\n`);
|
|
1486
|
+
(io.stderr ?? process.stderr).write(`Error: ${existingProject.errorMessage}\n`);
|
|
1487
|
+
if (active.count > 0) {
|
|
1488
|
+
(io.stderr ?? process.stderr).write(`Active lanes: ${formatActiveLaneSummary(active)}\n`);
|
|
1489
|
+
(io.stderr ?? process.stderr).write('Close active lanes before replacing this root, or pass --force --replace-active-lanes if replacement is intentional.\n');
|
|
1490
|
+
} else {
|
|
1491
|
+
(io.stderr ?? process.stderr).write('Fix project.yaml manually, or rerun with --force if replacement is intentional.\n');
|
|
1492
|
+
}
|
|
1493
|
+
return 1;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
const config = existingProject.projectConfig;
|
|
1497
|
+
const repos = Array.isArray(config.repos)
|
|
1498
|
+
? config.repos.map((repo) => repo.id).filter(Boolean)
|
|
1499
|
+
: [];
|
|
1500
|
+
io.stdout.write('VibeCompass is already initialized — here is how to continue.\n');
|
|
1501
|
+
io.stdout.write(`Project: ${config.name ?? 'Unknown'}\n`);
|
|
1502
|
+
io.stdout.write(`Mode: ${config.mode ?? 'Unknown'}\n`);
|
|
1503
|
+
io.stdout.write(`Root: ${existingProject.displayPath}\n`);
|
|
1504
|
+
io.stdout.write(`Repos: ${repos.length > 0 ? repos.join(', ') : 'None recorded'}\n`);
|
|
1505
|
+
io.stdout.write(`Active lanes: ${formatActiveLaneSummary(active)}\n`);
|
|
1506
|
+
io.stdout.write('Next commands:\n');
|
|
1507
|
+
io.stdout.write(`- vibecompass status${rootFlag}\n`);
|
|
1508
|
+
io.stdout.write(`- vibecompass list-sessions${rootFlag}\n`);
|
|
1509
|
+
io.stdout.write(`- vibecompass start-session${rootFlag} --id LANE_ID --working-on "TASK"\n`);
|
|
1510
|
+
io.stdout.write(`- vibecompass docs-review${rootFlag} --guided\n`);
|
|
1511
|
+
io.stdout.write(`- vibecompass sync-agents${rootFlag}\n`);
|
|
1512
|
+
if (['local-primary', 'hosted-only'].includes(config.mode)) {
|
|
1513
|
+
io.stdout.write(`- vibecompass connect-hosted${rootFlag}\n`);
|
|
1514
|
+
}
|
|
1515
|
+
return 0;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
function formatActiveLaneSummary(activeSummary) {
|
|
1519
|
+
if (!activeSummary || activeSummary.count === 0) {
|
|
1520
|
+
return 'none';
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
return `${activeSummary.count}${activeSummary.current ? ` (current: ${activeSummary.current})` : ''}`;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1238
1526
|
async function main() {
|
|
1239
1527
|
try {
|
|
1240
1528
|
const exitCode = await runCli(process.argv.slice(2));
|