@xenonbyte/da-vinci-workflow 0.1.25 → 0.2.1
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 +37 -0
- package/README.md +48 -67
- package/README.zh-CN.md +36 -66
- package/SKILL.md +3 -0
- package/commands/claude/dv/continue.md +5 -0
- package/commands/claude/dv/design.md +1 -0
- package/commands/codex/prompts/dv-continue.md +6 -1
- package/commands/codex/prompts/dv-design.md +1 -0
- package/commands/gemini/dv/continue.toml +5 -0
- package/commands/gemini/dv/design.toml +1 -0
- package/commands/templates/dv-continue.shared.md +33 -0
- package/docs/dv-command-reference.md +45 -2
- package/docs/execution-chain-migration.md +46 -0
- package/docs/execution-chain-plan.md +125 -0
- package/docs/pencil-rendering-workflow.md +9 -7
- package/docs/prompt-entrypoints.md +6 -0
- package/docs/prompt-presets/README.md +4 -0
- package/docs/visual-assist-presets/README.md +4 -0
- package/docs/workflow-examples.md +23 -11
- package/docs/workflow-overview.md +27 -0
- package/docs/zh-CN/dv-command-reference.md +45 -2
- package/docs/zh-CN/execution-chain-migration.md +46 -0
- package/docs/zh-CN/pencil-rendering-workflow.md +9 -7
- package/docs/zh-CN/prompt-entrypoints.md +6 -0
- 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 +23 -11
- package/docs/zh-CN/workflow-overview.md +27 -0
- package/examples/greenfield-spec-markupflow/README.md +6 -1
- package/lib/artifact-parsers.js +120 -0
- package/lib/async-offload-worker.js +26 -0
- package/lib/async-offload.js +82 -0
- package/lib/audit-parsers.js +152 -32
- package/lib/audit.js +145 -23
- package/lib/cli.js +1068 -437
- package/lib/diff-spec.js +242 -0
- package/lib/execution-signals.js +136 -0
- 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/lint-bindings.js +143 -0
- package/lib/lint-spec.js +408 -0
- package/lib/lint-tasks.js +176 -0
- package/lib/mcp-runtime-gate.js +4 -7
- package/lib/pen-persistence.js +318 -46
- package/lib/pencil-lock.js +237 -25
- package/lib/pencil-preflight.js +233 -12
- package/lib/pencil-session.js +216 -36
- package/lib/planning-parsers.js +567 -0
- package/lib/scaffold.js +193 -0
- package/lib/scope-check.js +603 -0
- package/lib/sidecars.js +369 -0
- package/lib/supervisor-review.js +82 -35
- package/lib/utils.js +129 -0
- package/lib/verify.js +652 -0
- package/lib/workflow-bootstrap.js +255 -0
- package/lib/workflow-contract.js +107 -0
- package/lib/workflow-persisted-state.js +297 -0
- package/lib/workflow-state.js +785 -0
- package/package.json +21 -3
- package/references/artifact-templates.md +26 -0
- package/references/checkpoints.md +16 -0
- package/references/design-inputs.md +2 -0
- package/references/modes.md +10 -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 -691
- 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 -344
- package/scripts/test-pen-persistence.js +0 -403
- 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,17 @@
|
|
|
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");
|
|
14
|
+
const { readExecutionSignals, summarizeSignalsBySurface } = require("./execution-signals");
|
|
6
15
|
const {
|
|
7
16
|
normalizeCheckpointLabel,
|
|
8
17
|
parseCheckpointStatusMap,
|
|
@@ -30,17 +39,13 @@ const EXPORT_SCAN_LIMITS = Object.freeze({
|
|
|
30
39
|
maxDepth: 4,
|
|
31
40
|
maxEntries: 1200
|
|
32
41
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return "";
|
|
41
|
-
}
|
|
42
|
-
return fs.readFileSync(targetPath, "utf8");
|
|
43
|
-
}
|
|
42
|
+
const PLANNING_SIGNAL_SURFACES = new Set(["lint-spec", "scope-check", "lint-tasks", "lint-bindings"]);
|
|
43
|
+
const VERIFICATION_SIGNAL_SURFACES = new Set([
|
|
44
|
+
"verify-bindings",
|
|
45
|
+
"verify-implementation",
|
|
46
|
+
"verify-structure",
|
|
47
|
+
"verify-coverage"
|
|
48
|
+
]);
|
|
44
49
|
|
|
45
50
|
function listFilesRecursive(rootDir, limits = {}) {
|
|
46
51
|
return listFilesRecursiveSafe(rootDir, {
|
|
@@ -200,6 +205,16 @@ function normalizeReviewerToken(value) {
|
|
|
200
205
|
return String(value || "").trim().toLowerCase();
|
|
201
206
|
}
|
|
202
207
|
|
|
208
|
+
function buildBootstrapCommand(projectRoot, mode, changeId = null) {
|
|
209
|
+
const parts = ["da-vinci", "bootstrap-project", "--project", projectRoot];
|
|
210
|
+
if (changeId) {
|
|
211
|
+
parts.push("--change", changeId);
|
|
212
|
+
} else if (mode === "completion") {
|
|
213
|
+
parts.push("--change", "<change-id>");
|
|
214
|
+
}
|
|
215
|
+
return parts.join(" ");
|
|
216
|
+
}
|
|
217
|
+
|
|
203
218
|
function auditProject(projectPathInput, options = {}) {
|
|
204
219
|
const projectRoot = path.resolve(projectPathInput || process.cwd());
|
|
205
220
|
const mode = options.mode || "integrity";
|
|
@@ -246,6 +261,20 @@ function auditProject(projectPathInput, options = {}) {
|
|
|
246
261
|
|
|
247
262
|
if (!pathExists(daVinciDir)) {
|
|
248
263
|
failures.push("Missing `.da-vinci/` directory.");
|
|
264
|
+
addMissingArtifacts(projectRoot, [path.join(projectRoot, "DA-VINCI.md"), designsDir], failures);
|
|
265
|
+
const missingWorkflowArtifacts = [
|
|
266
|
+
path.join(daVinciDir, "project-inventory.md"),
|
|
267
|
+
path.join(daVinciDir, "page-map.md"),
|
|
268
|
+
designRegistryPath
|
|
269
|
+
];
|
|
270
|
+
if (mode === "completion") {
|
|
271
|
+
addMissingArtifacts(projectRoot, missingWorkflowArtifacts, failures);
|
|
272
|
+
} else {
|
|
273
|
+
addMissingArtifacts(projectRoot, missingWorkflowArtifacts, warnings);
|
|
274
|
+
}
|
|
275
|
+
notes.push(
|
|
276
|
+
`Hint: scaffold the required workflow files with \`${buildBootstrapCommand(projectRoot, mode, options.changeId || null)}\`.`
|
|
277
|
+
);
|
|
249
278
|
return {
|
|
250
279
|
projectRoot,
|
|
251
280
|
mode,
|
|
@@ -274,6 +303,12 @@ function auditProject(projectPathInput, options = {}) {
|
|
|
274
303
|
addMissingArtifacts(projectRoot, completionRequiredArtifacts.slice(1, 4), warnings);
|
|
275
304
|
}
|
|
276
305
|
|
|
306
|
+
if (failures.some((message) => message.startsWith("Missing required artifact: "))) {
|
|
307
|
+
notes.push(
|
|
308
|
+
`Hint: scaffold missing workflow artifacts with \`${buildBootstrapCommand(projectRoot, mode, options.changeId || null)}\`.`
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
277
312
|
if (designSupervisorRequired && !designSupervisorConfigured) {
|
|
278
313
|
const message =
|
|
279
314
|
"DA-VINCI.md sets `Require Supervisor Review: true` but no `Design-supervisor reviewers` are configured.";
|
|
@@ -365,7 +400,15 @@ function auditProject(projectPathInput, options = {}) {
|
|
|
365
400
|
continue;
|
|
366
401
|
}
|
|
367
402
|
|
|
368
|
-
|
|
403
|
+
let persistedDocument;
|
|
404
|
+
try {
|
|
405
|
+
persistedDocument = assertPenDocumentShape(readPenDocument(registeredPenPath), registeredPenPath);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
failures.push(
|
|
408
|
+
`Registered design source is not a valid .pen document: ${relativeTo(projectRoot, registeredPenPath)}`
|
|
409
|
+
);
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
369
412
|
const currentHash = hashPenDocument(persistedDocument);
|
|
370
413
|
if (state.snapshotHash !== currentHash) {
|
|
371
414
|
failures.push(
|
|
@@ -396,16 +439,48 @@ function auditProject(projectPathInput, options = {}) {
|
|
|
396
439
|
failures.push("Completion audit requires the Pencil session to be ended and recorded as `closed`.");
|
|
397
440
|
}
|
|
398
441
|
|
|
442
|
+
if (sessionState.forceWithoutSync === true) {
|
|
443
|
+
const message =
|
|
444
|
+
"Pencil session was force-closed without a final live MCP sync verification. " +
|
|
445
|
+
"Run a fresh session persist/end cycle before completion.";
|
|
446
|
+
if (mode === "completion") {
|
|
447
|
+
failures.push(message);
|
|
448
|
+
} else {
|
|
449
|
+
warnings.push(message);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
399
453
|
if (sessionState.penPath && pathExists(sessionState.penPath)) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
454
|
+
let sessionPenValid = true;
|
|
455
|
+
let currentPenDocument = null;
|
|
456
|
+
try {
|
|
457
|
+
currentPenDocument = assertPenDocumentShape(
|
|
458
|
+
readPenDocument(sessionState.penPath),
|
|
459
|
+
sessionState.penPath
|
|
460
|
+
);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
failures.push(
|
|
463
|
+
`Session-bound .pen is not a valid document: ${relativeTo(projectRoot, sessionState.penPath)}`
|
|
408
464
|
);
|
|
465
|
+
sessionPenValid = false;
|
|
466
|
+
}
|
|
467
|
+
if (sessionPenValid) {
|
|
468
|
+
const currentHash = hashPenDocument(currentPenDocument);
|
|
469
|
+
const penState = readPenState(sessionState.penPath);
|
|
470
|
+
const persistedHash = penState && penState.snapshotHash ? String(penState.snapshotHash) : "";
|
|
471
|
+
|
|
472
|
+
if (persistedHash && persistedHash !== currentHash) {
|
|
473
|
+
failures.push("Pencil session state metadata hash does not match the current `.pen` document on disk.");
|
|
474
|
+
} else if (
|
|
475
|
+
sessionState.lastPersistedHash &&
|
|
476
|
+
sessionState.lastPersistedHash !== currentHash
|
|
477
|
+
) {
|
|
478
|
+
failures.push("Pencil session state hash does not match the current persisted `.pen` state hash.");
|
|
479
|
+
} else if (persistedHash) {
|
|
480
|
+
notes.push(
|
|
481
|
+
`Detected Pencil session state for ${relativeTo(projectRoot, sessionState.penPath)}.`
|
|
482
|
+
);
|
|
483
|
+
}
|
|
409
484
|
}
|
|
410
485
|
}
|
|
411
486
|
}
|
|
@@ -486,7 +561,7 @@ function auditProject(projectPathInput, options = {}) {
|
|
|
486
561
|
if (!review.found) {
|
|
487
562
|
const message =
|
|
488
563
|
`DA-VINCI.md configures Design-supervisor reviewers, but ${relativeTo(projectRoot, pencilDesignPath)} ` +
|
|
489
|
-
"does not record a
|
|
564
|
+
"does not record a `Design-Supervisor Review` section.";
|
|
490
565
|
if (enforceAsFailure) {
|
|
491
566
|
failures.push(message);
|
|
492
567
|
} else {
|
|
@@ -643,7 +718,7 @@ function auditProject(projectPathInput, options = {}) {
|
|
|
643
718
|
if (!hasAnyConcreteContextDelta) {
|
|
644
719
|
pushUnique(
|
|
645
720
|
warnings,
|
|
646
|
-
`Checkpoint-bearing artifacts in ${changeRel} do not record any concrete
|
|
721
|
+
`Checkpoint-bearing artifacts in ${changeRel} do not record any concrete \`Context Delta\` entries.`
|
|
647
722
|
);
|
|
648
723
|
} else {
|
|
649
724
|
notes.push(`Detected context-delta recovery notes in ${changeRel}.`);
|
|
@@ -758,6 +833,48 @@ function auditProject(projectPathInput, options = {}) {
|
|
|
758
833
|
}
|
|
759
834
|
}
|
|
760
835
|
|
|
836
|
+
const signalSummary =
|
|
837
|
+
options && options.preloadedSignalSummary && typeof options.preloadedSignalSummary === "object"
|
|
838
|
+
? options.preloadedSignalSummary
|
|
839
|
+
: summarizeSignalsBySurface(
|
|
840
|
+
readExecutionSignals(projectRoot, {
|
|
841
|
+
changeId: options.changeId || ""
|
|
842
|
+
})
|
|
843
|
+
);
|
|
844
|
+
for (const [surface, signal] of Object.entries(signalSummary)) {
|
|
845
|
+
if (surface === "signal-file-parse") {
|
|
846
|
+
const warningMessage =
|
|
847
|
+
Array.isArray(signal.warnings) && signal.warnings[0]
|
|
848
|
+
? String(signal.warnings[0])
|
|
849
|
+
: "Malformed execution signal files were detected.";
|
|
850
|
+
pushUnique(warnings, warningMessage);
|
|
851
|
+
continue;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
if (mode === "integrity" && PLANNING_SIGNAL_SURFACES.has(surface)) {
|
|
855
|
+
if (signal.status === "BLOCK") {
|
|
856
|
+
pushUnique(warnings, `Planning signal ${surface} is BLOCK (advisory in integrity mode).`);
|
|
857
|
+
} else if (signal.status === "WARN") {
|
|
858
|
+
pushUnique(notes, `Planning signal ${surface} is WARN.`);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
if (mode === "completion" && VERIFICATION_SIGNAL_SURFACES.has(surface)) {
|
|
863
|
+
if (signal.status === "BLOCK") {
|
|
864
|
+
failures.push(`Verification signal ${surface} is BLOCK.`);
|
|
865
|
+
} else if (signal.status === "WARN") {
|
|
866
|
+
pushUnique(warnings, `Verification signal ${surface} is WARN.`);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
if (surface === "diff-spec" && signal.status !== "PASS") {
|
|
871
|
+
pushUnique(warnings, `Planning diff signal ${surface} reports ${signal.status}.`);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
notes.push(
|
|
875
|
+
"Execution-chain signal integration uses advisory planning semantics in integrity mode and blocking verification semantics in completion mode."
|
|
876
|
+
);
|
|
877
|
+
|
|
761
878
|
const status = failures.length > 0 ? "FAIL" : warnings.length > 0 ? "WARN" : "PASS";
|
|
762
879
|
|
|
763
880
|
return {
|
|
@@ -771,6 +888,10 @@ function auditProject(projectPathInput, options = {}) {
|
|
|
771
888
|
};
|
|
772
889
|
}
|
|
773
890
|
|
|
891
|
+
function auditProjectAsync(projectPathInput, options = {}) {
|
|
892
|
+
return runModuleExportInWorker(__filename, "auditProject", [projectPathInput, options]);
|
|
893
|
+
}
|
|
894
|
+
|
|
774
895
|
function formatAuditReport(result) {
|
|
775
896
|
const lines = [
|
|
776
897
|
"Da Vinci audit",
|
|
@@ -809,5 +930,6 @@ function formatAuditReport(result) {
|
|
|
809
930
|
|
|
810
931
|
module.exports = {
|
|
811
932
|
auditProject,
|
|
933
|
+
auditProjectAsync,
|
|
812
934
|
formatAuditReport
|
|
813
935
|
};
|