@xenonbyte/da-vinci-workflow 0.1.24 → 0.1.26

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.
Files changed (62) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/README.md +41 -10
  3. package/README.zh-CN.md +30 -10
  4. package/SKILL.md +4 -0
  5. package/commands/claude/dv/design.md +2 -1
  6. package/commands/codex/prompts/dv-design.md +2 -1
  7. package/commands/gemini/dv/design.toml +2 -1
  8. package/docs/constraint-files.md +1 -0
  9. package/docs/dv-command-reference.md +14 -2
  10. package/docs/pencil-rendering-workflow.md +9 -7
  11. package/docs/prompt-presets/README.md +4 -0
  12. package/docs/visual-assist-presets/README.md +4 -0
  13. package/docs/workflow-examples.md +13 -11
  14. package/docs/workflow-overview.md +2 -0
  15. package/docs/zh-CN/constraint-files.md +1 -0
  16. package/docs/zh-CN/dv-command-reference.md +14 -2
  17. package/docs/zh-CN/pencil-rendering-workflow.md +9 -7
  18. package/docs/zh-CN/prompt-presets/README.md +5 -1
  19. package/docs/zh-CN/visual-assist-presets/README.md +5 -1
  20. package/docs/zh-CN/workflow-examples.md +13 -11
  21. package/docs/zh-CN/workflow-overview.md +2 -0
  22. package/examples/greenfield-spec-markupflow/README.md +6 -1
  23. package/lib/async-offload-worker.js +26 -0
  24. package/lib/async-offload.js +82 -0
  25. package/lib/audit-parsers.js +223 -51
  26. package/lib/audit.js +91 -23
  27. package/lib/cli.js +749 -433
  28. package/lib/fs-safety.js +1 -4
  29. package/lib/icon-aliases.js +7 -7
  30. package/lib/icon-search.js +21 -14
  31. package/lib/icon-sync.js +220 -41
  32. package/lib/install.js +128 -60
  33. package/lib/mcp-runtime-gate.js +4 -7
  34. package/lib/pen-persistence.js +365 -46
  35. package/lib/pencil-lock.js +237 -25
  36. package/lib/pencil-preflight.js +233 -12
  37. package/lib/pencil-session.js +216 -36
  38. package/lib/supervisor-review.js +56 -34
  39. package/lib/utils.js +121 -0
  40. package/lib/workflow-bootstrap.js +255 -0
  41. package/package.json +13 -3
  42. package/references/artifact-templates.md +1 -0
  43. package/references/checkpoints.md +2 -0
  44. package/references/design-inputs.md +2 -0
  45. package/references/pencil-design-to-code.md +2 -0
  46. package/scripts/fixtures/complex-sample.pen +0 -295
  47. package/scripts/fixtures/mock-pencil.js +0 -49
  48. package/scripts/test-audit-context-delta.js +0 -446
  49. package/scripts/test-audit-design-supervisor.js +0 -537
  50. package/scripts/test-audit-safety.js +0 -92
  51. package/scripts/test-icon-aliases.js +0 -96
  52. package/scripts/test-icon-search.js +0 -77
  53. package/scripts/test-icon-sync.js +0 -178
  54. package/scripts/test-mcp-runtime-gate.js +0 -287
  55. package/scripts/test-mode-consistency.js +0 -339
  56. package/scripts/test-pen-persistence.js +0 -254
  57. package/scripts/test-pencil-lock.js +0 -130
  58. package/scripts/test-pencil-preflight.js +0 -169
  59. package/scripts/test-pencil-session.js +0 -192
  60. package/scripts/test-persistence-flows.js +0 -345
  61. package/scripts/test-supervisor-review-cli.js +0 -619
  62. package/scripts/test-supervisor-review-integration.js +0 -115
package/lib/audit.js CHANGED
@@ -1,8 +1,16 @@
1
1
  const fs = require("fs");
2
2
  const path = require("path");
3
- const { getStandardPenStatePath, readPenState, hashPenDocument, readPenDocument } = require("./pen-persistence");
3
+ const {
4
+ getStandardPenStatePath,
5
+ readPenState,
6
+ hashPenDocument,
7
+ readPenDocument,
8
+ assertPenDocumentShape
9
+ } = require("./pen-persistence");
4
10
  const { getSessionStatePath, readSessionState } = require("./pencil-session");
5
11
  const { isPathInside, listFilesRecursiveSafe } = require("./fs-safety");
12
+ const { pathExists, readTextIfExists } = require("./utils");
13
+ const { runModuleExportInWorker } = require("./async-offload");
6
14
  const {
7
15
  normalizeCheckpointLabel,
8
16
  parseCheckpointStatusMap,
@@ -31,17 +39,6 @@ const EXPORT_SCAN_LIMITS = Object.freeze({
31
39
  maxEntries: 1200
32
40
  });
33
41
 
34
- function pathExists(targetPath) {
35
- return fs.existsSync(targetPath);
36
- }
37
-
38
- function readTextIfExists(targetPath) {
39
- if (!pathExists(targetPath)) {
40
- return "";
41
- }
42
- return fs.readFileSync(targetPath, "utf8");
43
- }
44
-
45
42
  function listFilesRecursive(rootDir, limits = {}) {
46
43
  return listFilesRecursiveSafe(rootDir, {
47
44
  includeDotfiles: true,
@@ -200,6 +197,16 @@ function normalizeReviewerToken(value) {
200
197
  return String(value || "").trim().toLowerCase();
201
198
  }
202
199
 
200
+ function buildBootstrapCommand(projectRoot, mode, changeId = null) {
201
+ const parts = ["da-vinci", "bootstrap-project", "--project", projectRoot];
202
+ if (changeId) {
203
+ parts.push("--change", changeId);
204
+ } else if (mode === "completion") {
205
+ parts.push("--change", "<change-id>");
206
+ }
207
+ return parts.join(" ");
208
+ }
209
+
203
210
  function auditProject(projectPathInput, options = {}) {
204
211
  const projectRoot = path.resolve(projectPathInput || process.cwd());
205
212
  const mode = options.mode || "integrity";
@@ -246,6 +253,9 @@ function auditProject(projectPathInput, options = {}) {
246
253
 
247
254
  if (!pathExists(daVinciDir)) {
248
255
  failures.push("Missing `.da-vinci/` directory.");
256
+ notes.push(
257
+ `Hint: scaffold the required workflow files with \`${buildBootstrapCommand(projectRoot, mode, options.changeId || null)}\`.`
258
+ );
249
259
  return {
250
260
  projectRoot,
251
261
  mode,
@@ -274,6 +284,12 @@ function auditProject(projectPathInput, options = {}) {
274
284
  addMissingArtifacts(projectRoot, completionRequiredArtifacts.slice(1, 4), warnings);
275
285
  }
276
286
 
287
+ if (failures.some((message) => message.startsWith("Missing required artifact: "))) {
288
+ notes.push(
289
+ `Hint: scaffold missing workflow artifacts with \`${buildBootstrapCommand(projectRoot, mode, options.changeId || null)}\`.`
290
+ );
291
+ }
292
+
277
293
  if (designSupervisorRequired && !designSupervisorConfigured) {
278
294
  const message =
279
295
  "DA-VINCI.md sets `Require Supervisor Review: true` but no `Design-supervisor reviewers` are configured.";
@@ -365,7 +381,15 @@ function auditProject(projectPathInput, options = {}) {
365
381
  continue;
366
382
  }
367
383
 
368
- const persistedDocument = readPenDocument(registeredPenPath);
384
+ let persistedDocument;
385
+ try {
386
+ persistedDocument = assertPenDocumentShape(readPenDocument(registeredPenPath), registeredPenPath);
387
+ } catch (error) {
388
+ failures.push(
389
+ `Registered design source is not a valid .pen document: ${relativeTo(projectRoot, registeredPenPath)}`
390
+ );
391
+ continue;
392
+ }
369
393
  const currentHash = hashPenDocument(persistedDocument);
370
394
  if (state.snapshotHash !== currentHash) {
371
395
  failures.push(
@@ -396,16 +420,48 @@ function auditProject(projectPathInput, options = {}) {
396
420
  failures.push("Completion audit requires the Pencil session to be ended and recorded as `closed`.");
397
421
  }
398
422
 
423
+ if (sessionState.forceWithoutSync === true) {
424
+ const message =
425
+ "Pencil session was force-closed without a final live MCP sync verification. " +
426
+ "Run a fresh session persist/end cycle before completion.";
427
+ if (mode === "completion") {
428
+ failures.push(message);
429
+ } else {
430
+ warnings.push(message);
431
+ }
432
+ }
433
+
399
434
  if (sessionState.penPath && pathExists(sessionState.penPath)) {
400
- const penState = readPenState(sessionState.penPath);
401
- const persistedHash = penState && penState.snapshotHash ? String(penState.snapshotHash) : "";
402
-
403
- if (sessionState.lastPersistedHash && persistedHash && sessionState.lastPersistedHash !== persistedHash) {
404
- failures.push("Pencil session state hash does not match the current persisted `.pen` state hash.");
405
- } else if (persistedHash) {
406
- notes.push(
407
- `Detected Pencil session state for ${relativeTo(projectRoot, sessionState.penPath)}.`
435
+ let sessionPenValid = true;
436
+ let currentPenDocument = null;
437
+ try {
438
+ currentPenDocument = assertPenDocumentShape(
439
+ readPenDocument(sessionState.penPath),
440
+ sessionState.penPath
441
+ );
442
+ } catch (error) {
443
+ failures.push(
444
+ `Session-bound .pen is not a valid document: ${relativeTo(projectRoot, sessionState.penPath)}`
408
445
  );
446
+ sessionPenValid = false;
447
+ }
448
+ if (sessionPenValid) {
449
+ const currentHash = hashPenDocument(currentPenDocument);
450
+ const penState = readPenState(sessionState.penPath);
451
+ const persistedHash = penState && penState.snapshotHash ? String(penState.snapshotHash) : "";
452
+
453
+ if (persistedHash && persistedHash !== currentHash) {
454
+ failures.push("Pencil session state metadata hash does not match the current `.pen` document on disk.");
455
+ } else if (
456
+ sessionState.lastPersistedHash &&
457
+ sessionState.lastPersistedHash !== currentHash
458
+ ) {
459
+ failures.push("Pencil session state hash does not match the current persisted `.pen` state hash.");
460
+ } else if (persistedHash) {
461
+ notes.push(
462
+ `Detected Pencil session state for ${relativeTo(projectRoot, sessionState.penPath)}.`
463
+ );
464
+ }
409
465
  }
410
466
  }
411
467
  }
@@ -474,12 +530,19 @@ function auditProject(projectPathInput, options = {}) {
474
530
  const enforceAsFailure =
475
531
  mode === "completion" && scopedChangeDirs.includes(changeDir) && designSupervisorRequired;
476
532
 
533
+ if (review.usedStructuredSectionFallback) {
534
+ warnings.push(
535
+ `Latest design-supervisor review entry in ${relativeTo(projectRoot, pencilDesignPath)} ` +
536
+ `is a legacy/non-structured format; gate evaluation used ${review.selectedSectionHeading}.`
537
+ );
538
+ }
539
+
477
540
  let reviewRecordValid = true;
478
541
 
479
542
  if (!review.found) {
480
543
  const message =
481
544
  `DA-VINCI.md configures Design-supervisor reviewers, but ${relativeTo(projectRoot, pencilDesignPath)} ` +
482
- "does not record a `## Design-Supervisor Review` section.";
545
+ "does not record a `Design-Supervisor Review` section.";
483
546
  if (enforceAsFailure) {
484
547
  failures.push(message);
485
548
  } else {
@@ -636,7 +699,7 @@ function auditProject(projectPathInput, options = {}) {
636
699
  if (!hasAnyConcreteContextDelta) {
637
700
  pushUnique(
638
701
  warnings,
639
- `Checkpoint-bearing artifacts in ${changeRel} do not record any concrete \`## Context Delta\` entries.`
702
+ `Checkpoint-bearing artifacts in ${changeRel} do not record any concrete \`Context Delta\` entries.`
640
703
  );
641
704
  } else {
642
705
  notes.push(`Detected context-delta recovery notes in ${changeRel}.`);
@@ -764,6 +827,10 @@ function auditProject(projectPathInput, options = {}) {
764
827
  };
765
828
  }
766
829
 
830
+ function auditProjectAsync(projectPathInput, options = {}) {
831
+ return runModuleExportInWorker(__filename, "auditProject", [projectPathInput, options]);
832
+ }
833
+
767
834
  function formatAuditReport(result) {
768
835
  const lines = [
769
836
  "Da Vinci audit",
@@ -802,5 +869,6 @@ function formatAuditReport(result) {
802
869
 
803
870
  module.exports = {
804
871
  auditProject,
872
+ auditProjectAsync,
805
873
  formatAuditReport
806
874
  };