@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.
- package/CHANGELOG.md +35 -1
- package/README.md +41 -10
- package/README.zh-CN.md +30 -10
- package/SKILL.md +4 -0
- package/commands/claude/dv/design.md +2 -1
- package/commands/codex/prompts/dv-design.md +2 -1
- package/commands/gemini/dv/design.toml +2 -1
- package/docs/constraint-files.md +1 -0
- package/docs/dv-command-reference.md +14 -2
- package/docs/pencil-rendering-workflow.md +9 -7
- package/docs/prompt-presets/README.md +4 -0
- package/docs/visual-assist-presets/README.md +4 -0
- package/docs/workflow-examples.md +13 -11
- package/docs/workflow-overview.md +2 -0
- package/docs/zh-CN/constraint-files.md +1 -0
- package/docs/zh-CN/dv-command-reference.md +14 -2
- package/docs/zh-CN/pencil-rendering-workflow.md +9 -7
- package/docs/zh-CN/prompt-presets/README.md +5 -1
- package/docs/zh-CN/visual-assist-presets/README.md +5 -1
- package/docs/zh-CN/workflow-examples.md +13 -11
- package/docs/zh-CN/workflow-overview.md +2 -0
- package/examples/greenfield-spec-markupflow/README.md +6 -1
- package/lib/async-offload-worker.js +26 -0
- package/lib/async-offload.js +82 -0
- package/lib/audit-parsers.js +223 -51
- package/lib/audit.js +91 -23
- package/lib/cli.js +749 -433
- package/lib/fs-safety.js +1 -4
- package/lib/icon-aliases.js +7 -7
- package/lib/icon-search.js +21 -14
- package/lib/icon-sync.js +220 -41
- package/lib/install.js +128 -60
- package/lib/mcp-runtime-gate.js +4 -7
- package/lib/pen-persistence.js +365 -46
- package/lib/pencil-lock.js +237 -25
- package/lib/pencil-preflight.js +233 -12
- package/lib/pencil-session.js +216 -36
- package/lib/supervisor-review.js +56 -34
- package/lib/utils.js +121 -0
- package/lib/workflow-bootstrap.js +255 -0
- package/package.json +13 -3
- package/references/artifact-templates.md +1 -0
- package/references/checkpoints.md +2 -0
- package/references/design-inputs.md +2 -0
- package/references/pencil-design-to-code.md +2 -0
- package/scripts/fixtures/complex-sample.pen +0 -295
- package/scripts/fixtures/mock-pencil.js +0 -49
- package/scripts/test-audit-context-delta.js +0 -446
- package/scripts/test-audit-design-supervisor.js +0 -537
- package/scripts/test-audit-safety.js +0 -92
- package/scripts/test-icon-aliases.js +0 -96
- package/scripts/test-icon-search.js +0 -77
- package/scripts/test-icon-sync.js +0 -178
- package/scripts/test-mcp-runtime-gate.js +0 -287
- package/scripts/test-mode-consistency.js +0 -339
- package/scripts/test-pen-persistence.js +0 -254
- package/scripts/test-pencil-lock.js +0 -130
- package/scripts/test-pencil-preflight.js +0 -169
- package/scripts/test-pencil-session.js +0 -192
- package/scripts/test-persistence-flows.js +0 -345
- package/scripts/test-supervisor-review-cli.js +0 -619
- 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 {
|
|
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
|
-
|
|
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
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
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
|
|
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
|
|
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
|
};
|