@xenonbyte/da-vinci-workflow 0.2.7 → 0.2.9

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/lib/cli.js CHANGED
@@ -79,7 +79,12 @@ const {
79
79
  } = require("./verify");
80
80
  const { diffSpec, formatDiffSpecReport } = require("./diff-spec");
81
81
  const { scaffoldFromBindings, formatScaffoldReport } = require("./scaffold");
82
- const { emitOrThrowOnStatus, persistExecutionSignal } = require("./cli/helpers");
82
+ const {
83
+ emitOrThrowOnStatus,
84
+ emitCommandOutput,
85
+ persistExecutionSignal
86
+ } = require("./cli/helpers");
87
+ const { buildCommandHandlers } = require("./cli/command-handlers");
83
88
  const { handleVerifyFamilyCommand } = require("./cli/verify-family");
84
89
  const { handleLintFamilyCommand } = require("./cli/lint-family");
85
90
  const {
@@ -280,6 +285,18 @@ const HELP_OPTION_SPECS = [
280
285
  { flag: "--force", description: "overwrite bootstrap placeholders or force commands that explicitly support it" }
281
286
  ];
282
287
 
288
+ const HELP_COMMANDS = new Set(["help", "--help", "-h"]);
289
+ const HELP_OPTION_FLAG_WIDTH = 30;
290
+
291
+ function formatHelpOptionLine(optionSpec) {
292
+ const flag = String(optionSpec.flag || "").trim();
293
+ const description = String(optionSpec.description || "").trim();
294
+ if (flag.length >= HELP_OPTION_FLAG_WIDTH) {
295
+ return [` ${flag}`, `${" ".repeat(HELP_OPTION_FLAG_WIDTH + 2)}${description}`].join("\n");
296
+ }
297
+ return ` ${flag.padEnd(HELP_OPTION_FLAG_WIDTH, " ")}${description}`;
298
+ }
299
+
283
300
  function readLimitedStdin(maxBytes = DEFAULT_MAX_PREFLIGHT_STDIN_BYTES, options = {}) {
284
301
  const limit =
285
302
  Number.isFinite(Number(maxBytes)) && Number(maxBytes) > 0
@@ -546,10 +563,7 @@ function appendStatusIssues(lines, label, missing = [], mismatched = [], unreada
546
563
  }
547
564
 
548
565
  function printHelp() {
549
- const optionLines = HELP_OPTION_SPECS.map((optionSpec) => {
550
- const paddedFlag = optionSpec.flag.padEnd(30, " ");
551
- return ` ${paddedFlag}${optionSpec.description}`;
552
- });
566
+ const optionLines = HELP_OPTION_SPECS.map(formatHelpOptionLine);
553
567
 
554
568
  console.log(
555
569
  [
@@ -1000,140 +1014,92 @@ async function runCli(argv) {
1000
1014
  const positionalArgs = getPositionalArgs(argv.slice(1), OPTION_FLAGS_WITH_VALUES);
1001
1015
  const continueOnError = shouldContinueOnError(argv);
1002
1016
 
1003
- if (!command || command === "help" || command === "--help" || command === "-h") {
1017
+ if (!command || HELP_COMMANDS.has(command)) {
1004
1018
  printHelp();
1005
1019
  return;
1006
1020
  }
1007
1021
 
1008
- if (command === "--version" || command === "-v" || command === "version") {
1009
- console.log(`Da Vinci v${VERSION}`);
1010
- return;
1011
- }
1012
-
1013
- if (command === "install") {
1014
- const platformValue = getOption(argv, "--platform") || "all";
1015
- const result = installPlatforms(platformValue, { homeDir });
1016
- console.log(
1017
- `Installed Da Vinci v${result.version} for ${result.platforms.join(", ")} at ${result.homeDir}`
1018
- );
1019
- return;
1020
- }
1021
-
1022
- if (command === "uninstall") {
1023
- const platformValue = getOption(argv, "--platform") || "all";
1024
- const result = uninstallPlatforms(platformValue, { homeDir });
1025
- console.log(
1026
- `Uninstalled Da Vinci v${result.version} for ${result.platforms.join(", ")} from ${result.homeDir}`
1027
- );
1028
- return;
1029
- }
1030
-
1031
- if (command === "status") {
1032
- console.log(formatStatus(getStatus({ homeDir })));
1033
- return;
1034
- }
1035
-
1036
- if (command === "verify-install") {
1037
- const platformValue = getOption(argv, "--platform") || "";
1038
- const result = verifyInstall({
1039
- homeDir,
1040
- platforms: platformValue
1041
- });
1042
- const output = argv.includes("--json")
1043
- ? JSON.stringify(result, null, 2)
1044
- : formatVerifyInstallReport(result);
1045
- if (emitOrThrowOnStatus(result.status, ["BLOCK"], output, continueOnError)) {
1046
- return;
1047
- }
1048
- console.log(output);
1049
- return;
1050
- }
1051
-
1052
- if (command === "maintainer-readiness") {
1053
- const platformValue = getOption(argv, "--platform") || "";
1054
- const repoRoot = getOption(argv, "--project") || process.cwd();
1055
- const result = runMaintainerReadinessCheck({
1056
- repoRoot,
1022
+ const handlers = buildCommandHandlers({
1023
+ shared: {
1024
+ argv,
1057
1025
  homeDir,
1058
- platforms: platformValue
1059
- });
1060
- const output = argv.includes("--json")
1061
- ? JSON.stringify(result, null, 2)
1062
- : formatMaintainerReadinessReport(result);
1063
- if (emitOrThrowOnStatus(result.status, ["BLOCK"], output, continueOnError)) {
1064
- return;
1065
- }
1066
- console.log(output);
1067
- return;
1068
- }
1069
-
1070
- if (command === "tui") {
1071
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1072
- const changeId = getOption(argv, "--change");
1073
- const lang = getOption(argv, "--lang");
1074
- const tuiWidth = getOption(argv, "--tui-width");
1075
- const altScreen = argv.includes("--alt-screen")
1076
- ? true
1077
- : argv.includes("--no-alt-screen")
1078
- ? false
1079
- : undefined;
1080
- if (argv.includes("--help") || argv.includes("-h")) {
1081
- console.log(formatTuiHelp(lang));
1082
- return;
1083
- }
1084
- await launchTui({
1085
- projectPath,
1086
- changeId,
1087
- lang,
1088
- tuiWidth,
1089
- altScreen,
1090
- strict: argv.includes("--strict"),
1091
- jsonOutput: argv.includes("--json"),
1026
+ positionalArgs,
1092
1027
  continueOnError
1093
- });
1094
- return;
1095
- }
1096
-
1097
- if (command === "workflow-status") {
1098
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1099
- const changeId = getOption(argv, "--change");
1100
- const result = deriveWorkflowStatus(projectPath, { changeId });
1101
-
1102
- if (argv.includes("--json")) {
1103
- console.log(JSON.stringify(result, null, 2));
1104
- return;
1105
- }
1106
-
1107
- console.log(formatWorkflowStatusReport(result));
1108
- return;
1109
- }
1110
-
1111
- if (command === "next-step") {
1112
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1113
- const changeId = getOption(argv, "--change");
1114
- const result = deriveWorkflowStatus(projectPath, { changeId });
1115
-
1116
- if (argv.includes("--json")) {
1117
- console.log(
1118
- JSON.stringify(
1119
- {
1120
- stage: result.stage,
1121
- checkpointState: result.checkpointState,
1122
- nextStep: result.nextStep || null,
1123
- blockingGate: result.blockingGate || null,
1124
- discipline: result.discipline || null,
1125
- executionProfile: result.executionProfile || null,
1126
- worktreePreflight: result.worktreePreflight || null,
1127
- verificationFreshness: result.verificationFreshness || null
1128
- },
1129
- null,
1130
- 2
1131
- )
1132
- );
1133
- return;
1028
+ },
1029
+ optionHelpers: {
1030
+ getOption,
1031
+ getIntegerOption,
1032
+ getCommaSeparatedOptionValues
1033
+ },
1034
+ core: {
1035
+ VERSION,
1036
+ installPlatforms,
1037
+ uninstallPlatforms,
1038
+ getStatus,
1039
+ verifyInstall,
1040
+ validateAssets,
1041
+ runMaintainerReadinessCheck,
1042
+ formatMaintainerReadinessReport,
1043
+ formatStatus,
1044
+ formatVerifyInstallReport,
1045
+ emitCommandOutput,
1046
+ formatTuiHelp,
1047
+ launchTui
1048
+ },
1049
+ workflow: {
1050
+ deriveWorkflowStatus,
1051
+ formatWorkflowStatusReport,
1052
+ formatNextStepReport,
1053
+ generatePlanningSidecars,
1054
+ formatGenerateSidecarsReport,
1055
+ writeTaskExecutionEnvelope,
1056
+ formatTaskExecutionReport,
1057
+ writeTaskReviewEnvelope,
1058
+ formatTaskReviewReport,
1059
+ runWorktreePreflight,
1060
+ formatWorktreePreflightReport,
1061
+ diffSpec,
1062
+ formatDiffSpecReport,
1063
+ scaffoldFromBindings,
1064
+ formatScaffoldReport,
1065
+ auditProject,
1066
+ formatAuditReport,
1067
+ bootstrapProjectArtifacts,
1068
+ formatBootstrapProjectReport,
1069
+ persistExecutionSignal,
1070
+ emitCommandOutput,
1071
+ emitOrThrowOnStatus
1072
+ },
1073
+ design: {
1074
+ syncIconCatalog,
1075
+ formatIconSyncReport,
1076
+ handleIconSearchCommand,
1077
+ readOperations,
1078
+ readLimitedStdin,
1079
+ preflightPencilBatch,
1080
+ formatPencilPreflightReport,
1081
+ emitOrThrowOnStatus,
1082
+ handleSupervisorReviewCommand,
1083
+ saveCurrentDesign,
1084
+ formatSaveCurrentDesignReport,
1085
+ SAVE_STATUS
1086
+ },
1087
+ pen: {
1088
+ ensurePenFile,
1089
+ writePenFromPayloadFiles,
1090
+ comparePenSync,
1091
+ comparePenBaselineAlignment,
1092
+ formatPenBaselineAlignmentReport,
1093
+ syncPenSource,
1094
+ snapshotPenFile,
1095
+ handlePencilLockCommand,
1096
+ handlePencilSessionCommand,
1097
+ emitOrThrowOnStatus
1134
1098
  }
1135
-
1136
- console.log(formatNextStepReport(result));
1099
+ });
1100
+ const commandHandler = handlers.get(command);
1101
+ if (commandHandler) {
1102
+ await commandHandler();
1137
1103
  return;
1138
1104
  }
1139
1105
 
@@ -1158,22 +1124,6 @@ async function runCli(argv) {
1158
1124
  return;
1159
1125
  }
1160
1126
 
1161
- if (command === "generate-sidecars") {
1162
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1163
- const changeId = getOption(argv, "--change");
1164
- const result = generatePlanningSidecars(projectPath, { changeId, write: true });
1165
- persistExecutionSignal(projectPath, result.changeId || changeId, "generate-sidecars", result, false);
1166
- const useJson = argv.includes("--json");
1167
- const output = useJson ? JSON.stringify(result, null, 2) : formatGenerateSidecarsReport(result);
1168
-
1169
- if (emitOrThrowOnStatus(result.status, ["BLOCK"], output, continueOnError)) {
1170
- return;
1171
- }
1172
-
1173
- console.log(output);
1174
- return;
1175
- }
1176
-
1177
1127
  if (
1178
1128
  handleVerifyFamilyCommand(command, {
1179
1129
  argv,
@@ -1194,391 +1144,6 @@ async function runCli(argv) {
1194
1144
  return;
1195
1145
  }
1196
1146
 
1197
- if (command === "task-execution") {
1198
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1199
- const changeId = getOption(argv, "--change");
1200
- const result = writeTaskExecutionEnvelope(projectPath, {
1201
- changeId,
1202
- taskGroupId: getOption(argv, "--task-group"),
1203
- status: getOption(argv, "--status"),
1204
- summary: getOption(argv, "--summary"),
1205
- changedFiles: getCommaSeparatedOptionValues(argv, "--changed-files"),
1206
- testEvidence: getCommaSeparatedOptionValues(argv, "--test-evidence"),
1207
- pendingTestEvidence: getCommaSeparatedOptionValues(argv, "--pending-test-evidence"),
1208
- confirmTestEvidenceExecuted: argv.includes("--confirm-test-evidence-executed"),
1209
- concerns: getCommaSeparatedOptionValues(argv, "--concerns"),
1210
- blockers: getCommaSeparatedOptionValues(argv, "--blockers"),
1211
- outOfScopeWrites: getCommaSeparatedOptionValues(argv, "--out-of-scope-writes"),
1212
- partial: argv.includes("--partial")
1213
- });
1214
- const useJson = argv.includes("--json");
1215
- const output = useJson ? JSON.stringify(result, null, 2) : formatTaskExecutionReport(result);
1216
- if (emitOrThrowOnStatus(result.status, ["BLOCK"], output, continueOnError)) {
1217
- return;
1218
- }
1219
- console.log(output);
1220
- return;
1221
- }
1222
-
1223
- if (command === "task-review") {
1224
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1225
- const changeId = getOption(argv, "--change");
1226
- const result = writeTaskReviewEnvelope(projectPath, {
1227
- changeId,
1228
- taskGroupId: getOption(argv, "--task-group"),
1229
- stage: getOption(argv, "--stage"),
1230
- status: getOption(argv, "--status"),
1231
- summary: getOption(argv, "--summary"),
1232
- issues: getCommaSeparatedOptionValues(argv, "--issues"),
1233
- reviewer: getOption(argv, "--reviewer"),
1234
- writeVerification: argv.includes("--write-verification")
1235
- });
1236
- const useJson = argv.includes("--json");
1237
- const output = useJson ? JSON.stringify(result, null, 2) : formatTaskReviewReport(result);
1238
- if (emitOrThrowOnStatus(result.status, ["BLOCK"], output, continueOnError)) {
1239
- return;
1240
- }
1241
- console.log(output);
1242
- return;
1243
- }
1244
-
1245
- if (command === "worktree-preflight") {
1246
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1247
- const changeId = getOption(argv, "--change");
1248
- const result = runWorktreePreflight(projectPath);
1249
- persistExecutionSignal(projectPath, changeId || "global", "worktree-preflight", result, false);
1250
- if (argv.includes("--json")) {
1251
- console.log(JSON.stringify(result, null, 2));
1252
- return;
1253
- }
1254
- console.log(formatWorktreePreflightReport(result));
1255
- return;
1256
- }
1257
-
1258
- if (command === "diff-spec") {
1259
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1260
- const changeId = getOption(argv, "--change");
1261
- const fromDir = getOption(argv, "--from");
1262
- const result = diffSpec(projectPath, { changeId, fromDir });
1263
- persistExecutionSignal(projectPath, result.changeId || changeId, "diff-spec", result, false);
1264
- const useJson = argv.includes("--json");
1265
- const output = useJson ? JSON.stringify(result, null, 2) : formatDiffSpecReport(result);
1266
- if (emitOrThrowOnStatus(result.status, ["BLOCK"], output, continueOnError)) {
1267
- return;
1268
- }
1269
- console.log(output);
1270
- return;
1271
- }
1272
-
1273
- if (command === "scaffold") {
1274
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1275
- const changeId = getOption(argv, "--change");
1276
- const outputDir = getOption(argv, "--output");
1277
- const result = scaffoldFromBindings(projectPath, { changeId, outputDir });
1278
- persistExecutionSignal(projectPath, result.changeId || changeId, "scaffold", result, false);
1279
- const useJson = argv.includes("--json");
1280
- const output = useJson ? JSON.stringify(result, null, 2) : formatScaffoldReport(result);
1281
- if (emitOrThrowOnStatus(result.status, ["BLOCK"], output, continueOnError)) {
1282
- return;
1283
- }
1284
- console.log(output);
1285
- return;
1286
- }
1287
-
1288
- if (command === "validate-assets") {
1289
- const result = validateAssets();
1290
- console.log(`Da Vinci v${result.version} assets are complete (${result.requiredAssets} required files).`);
1291
- return;
1292
- }
1293
-
1294
- if (command === "audit") {
1295
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1296
- const mode = getOption(argv, "--mode");
1297
- const changeId = getOption(argv, "--change");
1298
- const result = auditProject(projectPath, { mode, changeId });
1299
- const report = formatAuditReport(result);
1300
-
1301
- if (emitOrThrowOnStatus(result.status, ["FAIL"], report, continueOnError)) {
1302
- return;
1303
- }
1304
-
1305
- console.log(report);
1306
- return;
1307
- }
1308
-
1309
- if (command === "bootstrap-project") {
1310
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1311
- const changeId = getOption(argv, "--change");
1312
- const force = argv.includes("--force");
1313
- const result = bootstrapProjectArtifacts(projectPath, { changeId, force });
1314
- console.log(formatBootstrapProjectReport(result));
1315
- return;
1316
- }
1317
-
1318
- if (command === "icon-sync") {
1319
- const outputPath = getOption(argv, "--output") || getOption(argv, "--catalog");
1320
- const timeoutMs = getIntegerOption(argv, "--timeout-ms", { min: 1 });
1321
- const strict = argv.includes("--strict");
1322
-
1323
- const result = await syncIconCatalog({
1324
- outputPath,
1325
- timeoutMs,
1326
- strict,
1327
- homeDir
1328
- });
1329
-
1330
- console.log(formatIconSyncReport(result));
1331
- return;
1332
- }
1333
-
1334
- if (command === "icon-search") {
1335
- await handleIconSearchCommand(argv, homeDir);
1336
- return;
1337
- }
1338
-
1339
- if (command === "preflight-pencil") {
1340
- const opsFile = getOption(argv, "--ops-file");
1341
- let operations = "";
1342
-
1343
- if (opsFile) {
1344
- operations = readOperations(opsFile);
1345
- } else if (!process.stdin.isTTY) {
1346
- operations = readLimitedStdin();
1347
- } else {
1348
- throw new Error("`preflight-pencil` requires `--ops-file <path>` or piped stdin input.");
1349
- }
1350
-
1351
- const result = preflightPencilBatch(operations);
1352
- const report = formatPencilPreflightReport(result);
1353
-
1354
- if (emitOrThrowOnStatus(result.status, ["FAIL"], report, continueOnError)) {
1355
- return;
1356
- }
1357
-
1358
- console.log(report);
1359
- return;
1360
- }
1361
-
1362
- if (command === "supervisor-review") {
1363
- await handleSupervisorReviewCommand(argv);
1364
- return;
1365
- }
1366
-
1367
- if (command === "ensure-pen") {
1368
- const outputPath = getOption(argv, "--output");
1369
- const version = getOption(argv, "--version");
1370
- const verifyWithPencil = argv.includes("--verify-open");
1371
-
1372
- if (!outputPath) {
1373
- throw new Error("`ensure-pen` requires `--output <path>`.");
1374
- }
1375
-
1376
- const result = ensurePenFile({
1377
- outputPath,
1378
- version,
1379
- verifyWithPencil
1380
- });
1381
-
1382
- console.log(`${result.created ? "Created" : "Verified existing"} .pen source at ${result.outputPath}`);
1383
- console.log(`State file: ${result.statePath}`);
1384
- console.log(`Snapshot hash: ${result.state.snapshotHash}`);
1385
- if (result.verification) {
1386
- console.log(`Verified reopen with Pencil (${result.verification.topLevelCount} top-level nodes).`);
1387
- }
1388
- return;
1389
- }
1390
-
1391
- if (command === "write-pen") {
1392
- const outputPath = getOption(argv, "--output");
1393
- const nodesFile = getOption(argv, "--nodes-file");
1394
- const variablesFile = getOption(argv, "--variables-file");
1395
- const version = getOption(argv, "--version");
1396
- const verifyWithPencil = argv.includes("--verify-open");
1397
-
1398
- if (!outputPath || !nodesFile) {
1399
- throw new Error("`write-pen` requires `--output <path>` and `--nodes-file <path>`.");
1400
- }
1401
-
1402
- const result = writePenFromPayloadFiles({
1403
- outputPath,
1404
- nodesFile,
1405
- variablesFile,
1406
- version,
1407
- verifyWithPencil
1408
- });
1409
-
1410
- console.log(`Wrote .pen file to ${result.outputPath}`);
1411
- console.log(`State file: ${result.statePath}`);
1412
- console.log(`Snapshot hash: ${result.state.snapshotHash}`);
1413
- console.log(`Top-level nodes: ${result.document.children.length}`);
1414
- if (result.verification) {
1415
- console.log(`Verified reopen with Pencil (${result.verification.topLevelCount} top-level nodes).`);
1416
- }
1417
- return;
1418
- }
1419
-
1420
- if (command === "check-pen-sync") {
1421
- const penPath = getOption(argv, "--pen");
1422
- const nodesFile = getOption(argv, "--nodes-file");
1423
- const variablesFile = getOption(argv, "--variables-file");
1424
- const version = getOption(argv, "--version");
1425
-
1426
- if (!penPath || !nodesFile) {
1427
- throw new Error("`check-pen-sync` requires `--pen <path>` and `--nodes-file <path>`.");
1428
- }
1429
-
1430
- const result = comparePenSync({
1431
- penPath,
1432
- nodesFile,
1433
- variablesFile,
1434
- version
1435
- });
1436
-
1437
- if (!result.inSync) {
1438
- throw new Error(
1439
- [
1440
- "Registered `.pen` is out of sync with the provided live payload.",
1441
- `Pen: ${result.penPath}`,
1442
- `State file: ${result.statePath}`,
1443
- `Persisted hash: ${result.persistedHash}`,
1444
- `Live hash: ${result.liveHash}`
1445
- ].join("\n")
1446
- );
1447
- }
1448
-
1449
- console.log(`Registered .pen is in sync: ${result.penPath}`);
1450
- console.log(`State file: ${result.statePath}`);
1451
- console.log(`Snapshot hash: ${result.liveHash}`);
1452
- if (!result.usedStateFile) {
1453
- console.log(
1454
- result.stateHash
1455
- ? "State file hash was stale; sync comparison fell back to hashing the disk .pen file directly."
1456
- : "State file was missing; sync comparison fell back to hashing the disk .pen file directly."
1457
- );
1458
- }
1459
- return;
1460
- }
1461
-
1462
- if (command === "check-pen-baseline") {
1463
- const penPath = getOption(argv, "--pen");
1464
- const baselinePaths = getCommaSeparatedOptionValues(argv, "--baseline");
1465
- const preferredSource = getOption(argv, "--prefer-source");
1466
-
1467
- if (!penPath || baselinePaths.length === 0) {
1468
- throw new Error(
1469
- "`check-pen-baseline` requires `--pen <path>` and at least one `--baseline <path>`."
1470
- );
1471
- }
1472
-
1473
- const result = comparePenBaselineAlignment({
1474
- penPath,
1475
- baselinePaths,
1476
- preferredSource
1477
- });
1478
-
1479
- if (
1480
- emitOrThrowOnStatus(
1481
- result.status,
1482
- ["BLOCK"],
1483
- [
1484
- "Baseline alignment check failed.",
1485
- formatPenBaselineAlignmentReport(result)
1486
- ].join("\n"),
1487
- continueOnError
1488
- )
1489
- ) {
1490
- return;
1491
- }
1492
-
1493
- console.log(formatPenBaselineAlignmentReport(result));
1494
- return;
1495
- }
1496
-
1497
- if (command === "sync-pen-source") {
1498
- const sourcePath = getOption(argv, "--from");
1499
- const targetPath = getOption(argv, "--to");
1500
-
1501
- if (!sourcePath || !targetPath) {
1502
- throw new Error("`sync-pen-source` requires `--from <path>` and `--to <path>`.");
1503
- }
1504
-
1505
- const result = syncPenSource({
1506
- sourcePath,
1507
- targetPath
1508
- });
1509
-
1510
- console.log(`Synced .pen source from ${result.sourcePath} to ${result.targetPath}`);
1511
- console.log(`State file: ${result.statePath}`);
1512
- console.log(`Snapshot hash: ${result.state.snapshotHash}`);
1513
- return;
1514
- }
1515
-
1516
- if (command === "snapshot-pen") {
1517
- const inputPath = getOption(argv, "--input");
1518
- const outputPath = getOption(argv, "--output");
1519
- const version = getOption(argv, "--version");
1520
- const verifyWithPencil = argv.includes("--verify-open");
1521
-
1522
- if (!inputPath || !outputPath) {
1523
- throw new Error("`snapshot-pen` requires `--input <path>` and `--output <path>`.");
1524
- }
1525
-
1526
- const result = snapshotPenFile({
1527
- inputPath,
1528
- outputPath,
1529
- version,
1530
- verifyWithPencil
1531
- });
1532
-
1533
- console.log(`Snapshotted ${result.inputPath} to ${result.outputPath}`);
1534
- console.log(`State file: ${result.statePath}`);
1535
- console.log(`Snapshot hash: ${result.state.snapshotHash}`);
1536
- console.log(`Top-level nodes: ${result.document.children.length}`);
1537
- if (result.verification) {
1538
- console.log(`Verified reopen with Pencil (${result.verification.topLevelCount} top-level nodes).`);
1539
- }
1540
- return;
1541
- }
1542
-
1543
- if (command === "save-current-design") {
1544
- const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1545
- const pencilBin = getOption(argv, "--pencil-bin");
1546
- const result = await saveCurrentDesign({
1547
- projectPath,
1548
- homeDir,
1549
- pencilBin,
1550
- allowLocalBridge: true
1551
- });
1552
- const useJson = argv.includes("--json");
1553
- const output = useJson
1554
- ? JSON.stringify(result, null, 2)
1555
- : formatSaveCurrentDesignReport(result);
1556
-
1557
- if (
1558
- emitOrThrowOnStatus(
1559
- result.status,
1560
- [SAVE_STATUS.BLOCKED, SAVE_STATUS.UNAVAILABLE],
1561
- output,
1562
- continueOnError
1563
- )
1564
- ) {
1565
- return;
1566
- }
1567
-
1568
- console.log(output);
1569
- return;
1570
- }
1571
-
1572
- if (command === "pencil-lock") {
1573
- handlePencilLockCommand(argv, homeDir);
1574
- return;
1575
- }
1576
-
1577
- if (command === "pencil-session") {
1578
- handlePencilSessionCommand(argv, homeDir);
1579
- return;
1580
- }
1581
-
1582
1147
  throw new Error(`Unknown command: ${command}`);
1583
1148
  }
1584
1149