@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
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
const { isPathInside } = require("./fs-safety");
|
|
5
|
+
const { ensurePenFile } = require("./pen-persistence");
|
|
6
|
+
const { pathExists, readTextIfExists, writeFileAtomic } = require("./utils");
|
|
7
|
+
|
|
8
|
+
const DEFAULT_PROJECT_PEN_RELATIVE_PATH = ".da-vinci/designs/project-baseline.pen";
|
|
9
|
+
|
|
10
|
+
function validateChangeId(changeId) {
|
|
11
|
+
const normalized = String(changeId || "").trim();
|
|
12
|
+
if (!normalized) {
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
15
|
+
if (!/^[A-Za-z0-9._-]+$/.test(normalized)) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`Invalid change id: ${normalized}. Use letters, numbers, dot, underscore, or dash.`
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
return normalized;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function extractRegisteredPenPath(projectRoot, registryText) {
|
|
24
|
+
const matches = String(registryText || "").match(/\.da-vinci\/designs\/[^\s`]+\.pen/g) || [];
|
|
25
|
+
for (const relativePath of matches) {
|
|
26
|
+
const resolvedPath = path.resolve(projectRoot, relativePath);
|
|
27
|
+
if (isPathInside(projectRoot, resolvedPath)) {
|
|
28
|
+
return resolvedPath;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function buildProjectTemplates(preferredPenRelativePath) {
|
|
35
|
+
return {
|
|
36
|
+
"DA-VINCI.md": [
|
|
37
|
+
"# DA-VINCI",
|
|
38
|
+
"",
|
|
39
|
+
"## Product Surface",
|
|
40
|
+
"- TODO",
|
|
41
|
+
"",
|
|
42
|
+
"## Visual Direction",
|
|
43
|
+
"- TODO",
|
|
44
|
+
"",
|
|
45
|
+
"## Visual Assist",
|
|
46
|
+
"- Preferred adapters:",
|
|
47
|
+
"- Fallback:",
|
|
48
|
+
" - native",
|
|
49
|
+
"",
|
|
50
|
+
"## Source Of Truth",
|
|
51
|
+
"- requirements",
|
|
52
|
+
"- project-local Pencil source",
|
|
53
|
+
""
|
|
54
|
+
].join("\n"),
|
|
55
|
+
".da-vinci/project-inventory.md": [
|
|
56
|
+
"# Project Inventory",
|
|
57
|
+
"",
|
|
58
|
+
"## Current Product",
|
|
59
|
+
"- TODO",
|
|
60
|
+
"",
|
|
61
|
+
"## Routes And Pages",
|
|
62
|
+
"- TODO",
|
|
63
|
+
""
|
|
64
|
+
].join("\n"),
|
|
65
|
+
".da-vinci/page-map.md": [
|
|
66
|
+
"# Page Map",
|
|
67
|
+
"",
|
|
68
|
+
"## Canonical Pages",
|
|
69
|
+
"- TODO",
|
|
70
|
+
"",
|
|
71
|
+
"## Shared Regions",
|
|
72
|
+
"- TODO",
|
|
73
|
+
""
|
|
74
|
+
].join("\n"),
|
|
75
|
+
".da-vinci/design-registry.md": [
|
|
76
|
+
"# Design Registry",
|
|
77
|
+
"",
|
|
78
|
+
"## Preferred Project-local Source",
|
|
79
|
+
`- Preferred .pen: ${preferredPenRelativePath}`,
|
|
80
|
+
""
|
|
81
|
+
].join("\n")
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function buildChangeTemplates(changeId) {
|
|
86
|
+
const changePrefix = `.da-vinci/changes/${changeId}`;
|
|
87
|
+
return {
|
|
88
|
+
[`${changePrefix}/design-brief.md`]: [
|
|
89
|
+
"# Design Brief",
|
|
90
|
+
"",
|
|
91
|
+
"## Product Form Factor",
|
|
92
|
+
"- TODO",
|
|
93
|
+
"",
|
|
94
|
+
"## Visual Direction",
|
|
95
|
+
"- TODO",
|
|
96
|
+
""
|
|
97
|
+
].join("\n"),
|
|
98
|
+
[`${changePrefix}/design.md`]: [
|
|
99
|
+
"# Design",
|
|
100
|
+
"",
|
|
101
|
+
"## Goals",
|
|
102
|
+
"- TODO",
|
|
103
|
+
"",
|
|
104
|
+
"## Anchor Surfaces",
|
|
105
|
+
"- TODO",
|
|
106
|
+
""
|
|
107
|
+
].join("\n"),
|
|
108
|
+
[`${changePrefix}/pencil-design.md`]: [
|
|
109
|
+
"# Pencil Design",
|
|
110
|
+
"",
|
|
111
|
+
"## Screenshot Review Records",
|
|
112
|
+
"- TODO",
|
|
113
|
+
"",
|
|
114
|
+
"## Checkpoint Status",
|
|
115
|
+
"- Design checkpoint: `WARN`",
|
|
116
|
+
""
|
|
117
|
+
].join("\n"),
|
|
118
|
+
[`${changePrefix}/pencil-bindings.md`]: [
|
|
119
|
+
"# Pencil Bindings",
|
|
120
|
+
"",
|
|
121
|
+
"## Bound Pages",
|
|
122
|
+
"- TODO",
|
|
123
|
+
""
|
|
124
|
+
].join("\n")
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function writeScaffoldFile(projectRoot, relativePath, content, force, result) {
|
|
129
|
+
const absolutePath = path.join(projectRoot, relativePath);
|
|
130
|
+
if (pathExists(absolutePath)) {
|
|
131
|
+
if (!force) {
|
|
132
|
+
result.skipped.push(relativePath);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
writeFileAtomic(absolutePath, content);
|
|
136
|
+
result.overwritten.push(relativePath);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
writeFileAtomic(absolutePath, content);
|
|
141
|
+
result.created.push(relativePath);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function bootstrapProjectArtifacts(projectPathInput, options = {}) {
|
|
145
|
+
const projectRoot = path.resolve(projectPathInput || process.cwd());
|
|
146
|
+
const changeId = validateChangeId(options.changeId);
|
|
147
|
+
const force = options.force === true;
|
|
148
|
+
|
|
149
|
+
fs.mkdirSync(projectRoot, { recursive: true });
|
|
150
|
+
fs.mkdirSync(path.join(projectRoot, ".da-vinci", "designs"), { recursive: true });
|
|
151
|
+
fs.mkdirSync(path.join(projectRoot, ".da-vinci", "changes"), { recursive: true });
|
|
152
|
+
|
|
153
|
+
const existingRegistryText = readTextIfExists(path.join(projectRoot, ".da-vinci", "design-registry.md"));
|
|
154
|
+
const registeredPenPath = extractRegisteredPenPath(projectRoot, existingRegistryText);
|
|
155
|
+
const preferredPenPath = registeredPenPath || path.join(projectRoot, DEFAULT_PROJECT_PEN_RELATIVE_PATH);
|
|
156
|
+
const preferredPenRelativePath = path.relative(projectRoot, preferredPenPath) || DEFAULT_PROJECT_PEN_RELATIVE_PATH;
|
|
157
|
+
|
|
158
|
+
const result = {
|
|
159
|
+
projectRoot,
|
|
160
|
+
changeId: changeId || null,
|
|
161
|
+
created: [],
|
|
162
|
+
overwritten: [],
|
|
163
|
+
skipped: [],
|
|
164
|
+
penPath: preferredPenPath,
|
|
165
|
+
penRelativePath: preferredPenRelativePath,
|
|
166
|
+
changeArtifactsCreated: Boolean(changeId),
|
|
167
|
+
registryUpdatedToPreferredPen: Boolean(registeredPenPath) || !pathExists(path.join(projectRoot, ".da-vinci", "design-registry.md"))
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const projectTemplates = buildProjectTemplates(preferredPenRelativePath);
|
|
171
|
+
for (const [relativePath, content] of Object.entries(projectTemplates)) {
|
|
172
|
+
writeScaffoldFile(projectRoot, relativePath, content, force, result);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (changeId) {
|
|
176
|
+
const changeTemplates = buildChangeTemplates(changeId);
|
|
177
|
+
for (const [relativePath, content] of Object.entries(changeTemplates)) {
|
|
178
|
+
writeScaffoldFile(projectRoot, relativePath, content, force, result);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const penResult = ensurePenFile({
|
|
183
|
+
outputPath: preferredPenPath
|
|
184
|
+
});
|
|
185
|
+
result.pen = {
|
|
186
|
+
path: penResult.outputPath,
|
|
187
|
+
relativePath: preferredPenRelativePath,
|
|
188
|
+
created: penResult.created,
|
|
189
|
+
statePath: penResult.statePath,
|
|
190
|
+
snapshotHash: penResult.state.snapshotHash
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
if (!registeredPenPath && pathExists(path.join(projectRoot, ".da-vinci", "design-registry.md")) && !force) {
|
|
194
|
+
const currentRegistryText = readTextIfExists(path.join(projectRoot, ".da-vinci", "design-registry.md"));
|
|
195
|
+
result.registryUpdatedToPreferredPen = currentRegistryText.includes(preferredPenRelativePath);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function formatBootstrapProjectReport(result) {
|
|
202
|
+
const lines = [
|
|
203
|
+
"Da Vinci bootstrap-project",
|
|
204
|
+
`Project: ${result.projectRoot}`,
|
|
205
|
+
`Project-local .pen: ${result.pen.relativePath} (${result.pen.created ? "created" : "verified existing"})`,
|
|
206
|
+
`State file: ${result.pen.statePath}`
|
|
207
|
+
];
|
|
208
|
+
|
|
209
|
+
if (result.changeId) {
|
|
210
|
+
lines.push(`Change scaffold: .da-vinci/changes/${result.changeId}/`);
|
|
211
|
+
} else {
|
|
212
|
+
lines.push("Change scaffold: skipped (pass `--change <change-id>` to create change-level artifacts)");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (result.created.length > 0) {
|
|
216
|
+
lines.push("", "Created:");
|
|
217
|
+
for (const relativePath of result.created) {
|
|
218
|
+
lines.push(`- ${relativePath}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (result.overwritten.length > 0) {
|
|
223
|
+
lines.push("", "Overwritten:");
|
|
224
|
+
for (const relativePath of result.overwritten) {
|
|
225
|
+
lines.push(`- ${relativePath}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (result.skipped.length > 0) {
|
|
230
|
+
lines.push("", "Preserved existing:");
|
|
231
|
+
for (const relativePath of result.skipped) {
|
|
232
|
+
lines.push(`- ${relativePath}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
lines.push("", "Next steps:");
|
|
237
|
+
if (!result.changeId) {
|
|
238
|
+
lines.push(`- scaffold change artifacts with: da-vinci bootstrap-project --project ${result.projectRoot} --change <change-id>`);
|
|
239
|
+
}
|
|
240
|
+
lines.push(`- begin a Pencil session with: da-vinci pencil-session begin --project ${result.projectRoot} --pen ${result.pen.path}`);
|
|
241
|
+
lines.push(`- after the first persisted write, run: da-vinci audit --mode integrity ${result.projectRoot}`);
|
|
242
|
+
if (!result.registryUpdatedToPreferredPen) {
|
|
243
|
+
lines.push(
|
|
244
|
+
`- update .da-vinci/design-registry.md to reference ${result.pen.relativePath}, or rerun bootstrap-project with --force`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return lines.join("\n");
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
module.exports = {
|
|
252
|
+
DEFAULT_PROJECT_PEN_RELATIVE_PATH,
|
|
253
|
+
bootstrapProjectArtifacts,
|
|
254
|
+
formatBootstrapProjectReport
|
|
255
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xenonbyte/da-vinci-workflow",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "Requirement-to-design-to-code workflow skill for Codex, Claude, and Gemini",
|
|
5
5
|
"bin": {
|
|
6
6
|
"da-vinci": "bin/da-vinci.js",
|
|
@@ -18,14 +18,19 @@
|
|
|
18
18
|
"examples",
|
|
19
19
|
"bin",
|
|
20
20
|
"lib",
|
|
21
|
-
"scripts"
|
|
21
|
+
"scripts/postinstall.js",
|
|
22
|
+
"scripts/validate-assets.js"
|
|
22
23
|
],
|
|
23
24
|
"scripts": {
|
|
24
25
|
"postinstall": "node scripts/postinstall.js",
|
|
25
26
|
"validate-assets": "node scripts/validate-assets.js",
|
|
27
|
+
"test": "node scripts/run-tests.js",
|
|
28
|
+
"test:audit-parsers": "node scripts/test-audit-parsers.js",
|
|
26
29
|
"test:audit-safety": "node scripts/test-audit-safety.js",
|
|
27
30
|
"test:audit-context-delta": "node scripts/test-audit-context-delta.js",
|
|
28
31
|
"test:audit-design-supervisor": "node scripts/test-audit-design-supervisor.js",
|
|
32
|
+
"test:bootstrap-project": "node scripts/test-bootstrap-project.js",
|
|
33
|
+
"test:doc-release-alignment": "node scripts/test-doc-release-alignment.js",
|
|
29
34
|
"test:pencil-lock": "node scripts/test-pencil-lock.js",
|
|
30
35
|
"test:mode-consistency": "node scripts/test-mode-consistency.js",
|
|
31
36
|
"test:mcp-runtime-gate": "node scripts/test-mcp-runtime-gate.js",
|
|
@@ -37,7 +42,12 @@
|
|
|
37
42
|
"test:icon-sync": "node scripts/test-icon-sync.js",
|
|
38
43
|
"test:icon-aliases": "node scripts/test-icon-aliases.js",
|
|
39
44
|
"test:supervisor-review-cli": "node scripts/test-supervisor-review-cli.js",
|
|
40
|
-
"test:supervisor-review-integration": "node scripts/test-supervisor-review-integration.js"
|
|
45
|
+
"test:supervisor-review-integration": "node scripts/test-supervisor-review-integration.js",
|
|
46
|
+
"test:install": "node scripts/test-install.js",
|
|
47
|
+
"test:package-contents": "node scripts/test-package-contents.js",
|
|
48
|
+
"quality:ci:core": "npm run test",
|
|
49
|
+
"quality:reviewer-bridge-smoke": "npm run test:supervisor-review-integration",
|
|
50
|
+
"quality:ci": "npm run quality:ci:core"
|
|
41
51
|
},
|
|
42
52
|
"engines": {
|
|
43
53
|
"node": ">=18"
|
|
@@ -569,6 +569,7 @@ Use this structure:
|
|
|
569
569
|
- Revision outcome
|
|
570
570
|
- Whether broad expansion is approved
|
|
571
571
|
- Whether implementation-task handoff is approved
|
|
572
|
+
- Keep one canonical structured supervisor-review section; avoid ad-hoc headings such as `## Design-Supervisor Review (Round X Attempt)`
|
|
572
573
|
|
|
573
574
|
## Anchor Surfaces
|
|
574
575
|
- Which 1-3 anchor screens were designed first
|
|
@@ -199,6 +199,7 @@ Check:
|
|
|
199
199
|
- the active editor is not still an unnamed live document such as `new`
|
|
200
200
|
- the workflow did not keep using an empty `filePath` after a registered `.pen` existed
|
|
201
201
|
- the active editor, registered project-local `.pen` path, and shell-visible `.pen` file are converged strongly enough to trust the runtime source
|
|
202
|
+
- when external or secondary `.pen` sources exist, their hashes have been reconciled against the project-local `.pen` baseline before new edits continue
|
|
202
203
|
- completion-stage runtime evidence includes an explicit live-to-disk sync verification for the registered `.pen`
|
|
203
204
|
- claimed anchor ids exist in the active live editor
|
|
204
205
|
- claimed reviewed screens and screenshot targets exist in the active live editor
|
|
@@ -231,6 +232,7 @@ Check:
|
|
|
231
232
|
- the preferred `.pen` path in `design-registry.md` is workflow-owned and specific, not hand-wavy
|
|
232
233
|
- the active Pencil editor path matches the preferred project-local `.pen` path, or the project-local file has been reconstructed explicitly
|
|
233
234
|
- the preferred project-local `.pen` file exists as a shell-visible file when the workflow created or edited Pencil work
|
|
235
|
+
- if external or secondary `.pen` files exist, the workflow records baseline hash alignment and explicit source-priority confirmation before the next edit round
|
|
234
236
|
- exported screenshots are treated only as review artifacts, not as page-to-design source of truth
|
|
235
237
|
- each implementation page has a Pencil page or an explicit exception
|
|
236
238
|
- shared layouts and shared regions are bound clearly enough to implement from
|
|
@@ -20,6 +20,7 @@ The preferred `.pen` path in `design-registry.md` is workflow-owned state.
|
|
|
20
20
|
- it should be generated and maintained by Da Vinci
|
|
21
21
|
- it should not rely on the user manually typing a path into `design-registry.md`
|
|
22
22
|
- external references may influence source priority, but the project-local path should still be resolved explicitly
|
|
23
|
+
- in multi-source scenarios, a successful `pencil-session persist` confirms only live-vs-project sync for that run; verify cross-source hash alignment before treating the project file as globally latest
|
|
23
24
|
|
|
24
25
|
Use these defaults:
|
|
25
26
|
|
|
@@ -32,6 +33,7 @@ Before broad Pencil work begins:
|
|
|
32
33
|
- resolve the exact project-local path
|
|
33
34
|
- record that path in `design-registry.md`
|
|
34
35
|
- treat that path as the required target for the active design pass
|
|
36
|
+
- if external or secondary `.pen` sources exist, run `da-vinci check-pen-baseline --pen <project-pen> --baseline <other-pen>`; when hashes diverge, confirm source priority and sync the chosen source into `<project-pen>` before new edits
|
|
35
37
|
|
|
36
38
|
If Pencil MCP is currently pointing at a different active editor:
|
|
37
39
|
|
|
@@ -75,6 +75,7 @@ When generating or editing Pencil data:
|
|
|
75
75
|
- if unsupported-property rollbacks repeat on the same anchor surface, stop treating that pass as stable forward progress until the schema usage is corrected
|
|
76
76
|
- after any rolled-back batch or structure-changing edit, refresh the live node structure before descendant-targeted follow-up operations
|
|
77
77
|
- before the first Pencil edit on a redesign pass, require `da-vinci pencil-session begin --project <project-path> --pen <path>` whenever the session wrapper is available so the registered project-local `.pen` exists before editing and the global lock is held; use `da-vinci ensure-pen --output <path> --verify-open` only as a lower-level fallback when the session wrapper truly cannot be used
|
|
78
|
+
- if external or secondary `.pen` files exist, run `da-vinci check-pen-baseline --pen <project-pen> --baseline <other-pen>` before the new write phase; if hashes diverge, confirm source priority and sync the chosen source into `<project-pen>` before new edits
|
|
78
79
|
- acquire the global Pencil lock before MCP write operations when multiple redesign sessions could overlap on the same machine
|
|
79
80
|
- on autonomous runs, require the higher-level wrapper:
|
|
80
81
|
`da-vinci pencil-session begin`
|
|
@@ -85,6 +86,7 @@ When generating or editing Pencil data:
|
|
|
85
86
|
- if a registered project-local `.pen` already existed, reopen it for continuity, but after material live edits persist a fresh MCP snapshot back to that same path instead of assuming live edits were flushed automatically
|
|
86
87
|
- use `da-vinci write-pen --output <path> --nodes-file <batch-get-json> --variables-file <get-variables-json> --version <version> --verify-open` when you already have MCP-readable snapshot payloads and need an atomic project-local `.pen` write
|
|
87
88
|
- run `da-vinci check-pen-sync --pen <path> --nodes-file <batch-get-json> --variables-file <get-variables-json> --version <version>` after material live edits and before completion claims to prove the live snapshot matches the persisted `.pen`
|
|
89
|
+
- when an external source is selected as latest, use `da-vinci sync-pen-source --from <preferred-source.pen> --to <project-pen>` to materialize it into the project-local baseline before reopening a write session
|
|
88
90
|
- use `da-vinci snapshot-pen --input <path> --output <path> --verify-open` only as a disk-to-disk utility when you need to re-canonicalize an existing `.pen`; it is not a substitute for persisting the current live editor
|
|
89
91
|
- completion audit expects `.da-vinci/state/pencil-session.json` to exist and reflect the latest persisted `.pen` hash
|
|
90
92
|
- keep workflow markdown out of `.da-vinci/designs/`; reserve that directory for `.pen` files only
|
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "2.9",
|
|
3
|
-
"variables": {
|
|
4
|
-
"surface-bg": {
|
|
5
|
-
"type": "color",
|
|
6
|
-
"value": "#F4EFE7"
|
|
7
|
-
},
|
|
8
|
-
"surface-panel": {
|
|
9
|
-
"type": "color",
|
|
10
|
-
"value": "#FFFDF8"
|
|
11
|
-
},
|
|
12
|
-
"surface-border": {
|
|
13
|
-
"type": "color",
|
|
14
|
-
"value": "#D7CCBC"
|
|
15
|
-
},
|
|
16
|
-
"deck-fill": {
|
|
17
|
-
"type": "color",
|
|
18
|
-
"value": "#17304A"
|
|
19
|
-
},
|
|
20
|
-
"deck-fill-deep": {
|
|
21
|
-
"type": "color",
|
|
22
|
-
"value": "#10263A"
|
|
23
|
-
},
|
|
24
|
-
"surface-ink": {
|
|
25
|
-
"type": "color",
|
|
26
|
-
"value": "#132033"
|
|
27
|
-
},
|
|
28
|
-
"surface-muted": {
|
|
29
|
-
"type": "color",
|
|
30
|
-
"value": "#5D6673"
|
|
31
|
-
},
|
|
32
|
-
"accent-amber": {
|
|
33
|
-
"type": "color",
|
|
34
|
-
"value": "#C98A2B"
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
"children": [
|
|
38
|
-
{
|
|
39
|
-
"type": "frame",
|
|
40
|
-
"id": "healthy",
|
|
41
|
-
"x": 0,
|
|
42
|
-
"y": 0,
|
|
43
|
-
"name": "Diagnostics Console / Healthy",
|
|
44
|
-
"width": 420,
|
|
45
|
-
"fill": "$surface-bg",
|
|
46
|
-
"layout": "vertical",
|
|
47
|
-
"gap": 18,
|
|
48
|
-
"padding": [
|
|
49
|
-
18,
|
|
50
|
-
18,
|
|
51
|
-
24,
|
|
52
|
-
18
|
|
53
|
-
],
|
|
54
|
-
"children": [
|
|
55
|
-
{
|
|
56
|
-
"type": "frame",
|
|
57
|
-
"id": "deckHealthy",
|
|
58
|
-
"name": "Command Deck",
|
|
59
|
-
"width": "fill_container",
|
|
60
|
-
"fill": [
|
|
61
|
-
{
|
|
62
|
-
"type": "gradient",
|
|
63
|
-
"gradientType": "linear",
|
|
64
|
-
"enabled": true,
|
|
65
|
-
"rotation": 180,
|
|
66
|
-
"size": {
|
|
67
|
-
"height": 1
|
|
68
|
-
},
|
|
69
|
-
"colors": [
|
|
70
|
-
{
|
|
71
|
-
"color": "$deck-fill",
|
|
72
|
-
"position": 0
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
"color": "$deck-fill-deep",
|
|
76
|
-
"position": 1
|
|
77
|
-
}
|
|
78
|
-
]
|
|
79
|
-
},
|
|
80
|
-
"#FFFFFF12"
|
|
81
|
-
],
|
|
82
|
-
"cornerRadius": 26,
|
|
83
|
-
"effect": {
|
|
84
|
-
"type": "shadow",
|
|
85
|
-
"shadowType": "outer",
|
|
86
|
-
"color": "#0B16231F",
|
|
87
|
-
"offset": {
|
|
88
|
-
"x": 0,
|
|
89
|
-
"y": 14
|
|
90
|
-
},
|
|
91
|
-
"blur": 28
|
|
92
|
-
},
|
|
93
|
-
"layout": "vertical",
|
|
94
|
-
"gap": 14,
|
|
95
|
-
"padding": 22,
|
|
96
|
-
"children": [
|
|
97
|
-
{
|
|
98
|
-
"type": "text",
|
|
99
|
-
"id": "healthyEyebrow",
|
|
100
|
-
"name": "heroEyebrow",
|
|
101
|
-
"content": "Diagnostics",
|
|
102
|
-
"fill": "$accent-amber",
|
|
103
|
-
"fontFamily": "Inter",
|
|
104
|
-
"fontSize": 12,
|
|
105
|
-
"fontWeight": "700",
|
|
106
|
-
"letterSpacing": 1.4
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
"type": "text",
|
|
110
|
-
"id": "healthyTitle",
|
|
111
|
-
"name": "heroTitle",
|
|
112
|
-
"content": "Healthy runway",
|
|
113
|
-
"fill": "#FFFDF8",
|
|
114
|
-
"fontFamily": "Inter",
|
|
115
|
-
"fontSize": 28,
|
|
116
|
-
"fontWeight": "700",
|
|
117
|
-
"textGrowth": "fixed-width",
|
|
118
|
-
"width": "fill_container"
|
|
119
|
-
}
|
|
120
|
-
]
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
"type": "frame",
|
|
124
|
-
"id": "panelHealthy",
|
|
125
|
-
"name": "Runway Panel",
|
|
126
|
-
"width": "fill_container",
|
|
127
|
-
"fill": "$surface-panel",
|
|
128
|
-
"cornerRadius": 24,
|
|
129
|
-
"stroke": {
|
|
130
|
-
"fill": "$surface-border",
|
|
131
|
-
"thickness": 1
|
|
132
|
-
},
|
|
133
|
-
"layout": "vertical",
|
|
134
|
-
"gap": 12,
|
|
135
|
-
"padding": 18,
|
|
136
|
-
"children": [
|
|
137
|
-
{
|
|
138
|
-
"type": "text",
|
|
139
|
-
"id": "panelHealthyTitle",
|
|
140
|
-
"name": "panelTitle",
|
|
141
|
-
"content": "Launch blocking scenarios",
|
|
142
|
-
"fill": "$surface-ink",
|
|
143
|
-
"fontFamily": "Inter",
|
|
144
|
-
"fontSize": 24,
|
|
145
|
-
"fontWeight": "700",
|
|
146
|
-
"textGrowth": "fixed-width",
|
|
147
|
-
"width": "fill_container"
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
"type": "text",
|
|
151
|
-
"id": "panelHealthyBody",
|
|
152
|
-
"name": "panelBody",
|
|
153
|
-
"content": "Routine and high-risk controls are separated so the dangerous path always reads clearly.",
|
|
154
|
-
"fill": "$surface-muted",
|
|
155
|
-
"fontFamily": "Inter",
|
|
156
|
-
"fontSize": 14,
|
|
157
|
-
"fontWeight": "normal",
|
|
158
|
-
"lineHeight": 1.45,
|
|
159
|
-
"textGrowth": "fixed-width",
|
|
160
|
-
"width": "fill_container"
|
|
161
|
-
}
|
|
162
|
-
]
|
|
163
|
-
}
|
|
164
|
-
]
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
"type": "frame",
|
|
168
|
-
"id": "degraded",
|
|
169
|
-
"x": 500,
|
|
170
|
-
"y": 0,
|
|
171
|
-
"name": "Diagnostics Console / Degraded",
|
|
172
|
-
"width": 420,
|
|
173
|
-
"fill": "$surface-bg",
|
|
174
|
-
"layout": "vertical",
|
|
175
|
-
"gap": 18,
|
|
176
|
-
"padding": [
|
|
177
|
-
18,
|
|
178
|
-
18,
|
|
179
|
-
24,
|
|
180
|
-
18
|
|
181
|
-
],
|
|
182
|
-
"children": [
|
|
183
|
-
{
|
|
184
|
-
"type": "frame",
|
|
185
|
-
"id": "deckDegraded",
|
|
186
|
-
"name": "Command Deck",
|
|
187
|
-
"width": "fill_container",
|
|
188
|
-
"fill": [
|
|
189
|
-
{
|
|
190
|
-
"type": "gradient",
|
|
191
|
-
"gradientType": "linear",
|
|
192
|
-
"enabled": true,
|
|
193
|
-
"rotation": 180,
|
|
194
|
-
"size": {
|
|
195
|
-
"height": 1
|
|
196
|
-
},
|
|
197
|
-
"colors": [
|
|
198
|
-
{
|
|
199
|
-
"color": "$deck-fill",
|
|
200
|
-
"position": 0
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
"color": "$deck-fill-deep",
|
|
204
|
-
"position": 1
|
|
205
|
-
}
|
|
206
|
-
]
|
|
207
|
-
},
|
|
208
|
-
"#FFFFFF12"
|
|
209
|
-
],
|
|
210
|
-
"cornerRadius": 26,
|
|
211
|
-
"effect": {
|
|
212
|
-
"type": "shadow",
|
|
213
|
-
"shadowType": "outer",
|
|
214
|
-
"color": "#0B16231F",
|
|
215
|
-
"offset": {
|
|
216
|
-
"x": 0,
|
|
217
|
-
"y": 14
|
|
218
|
-
},
|
|
219
|
-
"blur": 28
|
|
220
|
-
},
|
|
221
|
-
"layout": "vertical",
|
|
222
|
-
"gap": 14,
|
|
223
|
-
"padding": 22,
|
|
224
|
-
"children": [
|
|
225
|
-
{
|
|
226
|
-
"type": "text",
|
|
227
|
-
"id": "degradedEyebrow",
|
|
228
|
-
"name": "heroEyebrow",
|
|
229
|
-
"content": "Diagnostics",
|
|
230
|
-
"fill": "$accent-amber",
|
|
231
|
-
"fontFamily": "Inter",
|
|
232
|
-
"fontSize": 12,
|
|
233
|
-
"fontWeight": "700",
|
|
234
|
-
"letterSpacing": 1.4
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
"type": "text",
|
|
238
|
-
"id": "degradedTitle",
|
|
239
|
-
"name": "heroTitle",
|
|
240
|
-
"content": "Degraded runway",
|
|
241
|
-
"fill": "#FFFDF8",
|
|
242
|
-
"fontFamily": "Inter",
|
|
243
|
-
"fontSize": 28,
|
|
244
|
-
"fontWeight": "700",
|
|
245
|
-
"textGrowth": "fixed-width",
|
|
246
|
-
"width": "fill_container"
|
|
247
|
-
}
|
|
248
|
-
]
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
"type": "frame",
|
|
252
|
-
"id": "panelDegraded",
|
|
253
|
-
"name": "Runway Panel",
|
|
254
|
-
"width": "fill_container",
|
|
255
|
-
"fill": "$surface-panel",
|
|
256
|
-
"cornerRadius": 24,
|
|
257
|
-
"stroke": {
|
|
258
|
-
"fill": "$surface-border",
|
|
259
|
-
"thickness": 1
|
|
260
|
-
},
|
|
261
|
-
"layout": "vertical",
|
|
262
|
-
"gap": 12,
|
|
263
|
-
"padding": 18,
|
|
264
|
-
"children": [
|
|
265
|
-
{
|
|
266
|
-
"type": "text",
|
|
267
|
-
"id": "panelDegradedTitle",
|
|
268
|
-
"name": "panelTitle",
|
|
269
|
-
"content": "Signal drift detected",
|
|
270
|
-
"fill": "$surface-ink",
|
|
271
|
-
"fontFamily": "Inter",
|
|
272
|
-
"fontSize": 24,
|
|
273
|
-
"fontWeight": "700",
|
|
274
|
-
"textGrowth": "fixed-width",
|
|
275
|
-
"width": "fill_container"
|
|
276
|
-
},
|
|
277
|
-
{
|
|
278
|
-
"type": "text",
|
|
279
|
-
"id": "panelDegradedBody",
|
|
280
|
-
"name": "panelBody",
|
|
281
|
-
"content": "Telemetry stays legible while the top surface shifts the operator toward the corrective lane.",
|
|
282
|
-
"fill": "$surface-muted",
|
|
283
|
-
"fontFamily": "Inter",
|
|
284
|
-
"fontSize": 14,
|
|
285
|
-
"fontWeight": "normal",
|
|
286
|
-
"lineHeight": 1.45,
|
|
287
|
-
"textGrowth": "fixed-width",
|
|
288
|
-
"width": "fill_container"
|
|
289
|
-
}
|
|
290
|
-
]
|
|
291
|
-
}
|
|
292
|
-
]
|
|
293
|
-
}
|
|
294
|
-
]
|
|
295
|
-
}
|