@xenonbyte/da-vinci-workflow 0.2.1 → 0.2.3

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 (57) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +33 -12
  3. package/README.zh-CN.md +34 -12
  4. package/bin/da-vinci-tui.js +8 -0
  5. package/commands/claude/dv/breakdown.md +8 -0
  6. package/commands/claude/dv/build.md +11 -0
  7. package/commands/claude/dv/design.md +5 -2
  8. package/commands/claude/dv/tasks.md +8 -0
  9. package/commands/claude/dv/verify.md +9 -0
  10. package/commands/codex/prompts/dv-breakdown.md +8 -0
  11. package/commands/codex/prompts/dv-build.md +11 -0
  12. package/commands/codex/prompts/dv-design.md +5 -2
  13. package/commands/codex/prompts/dv-tasks.md +8 -0
  14. package/commands/codex/prompts/dv-verify.md +8 -0
  15. package/commands/gemini/dv/breakdown.toml +8 -0
  16. package/commands/gemini/dv/build.toml +11 -0
  17. package/commands/gemini/dv/design.toml +5 -2
  18. package/commands/gemini/dv/tasks.toml +8 -0
  19. package/commands/gemini/dv/verify.toml +8 -0
  20. package/docs/dv-command-reference.md +47 -0
  21. package/docs/execution-chain-plan.md +10 -3
  22. package/docs/mode-use-cases.md +2 -1
  23. package/docs/pencil-rendering-workflow.md +15 -12
  24. package/docs/prompt-entrypoints.md +2 -0
  25. package/docs/prompt-presets/README.md +1 -1
  26. package/docs/prompt-presets/desktop-app.md +3 -3
  27. package/docs/prompt-presets/mobile-app.md +3 -3
  28. package/docs/prompt-presets/tablet-app.md +3 -3
  29. package/docs/prompt-presets/web-app.md +3 -3
  30. package/docs/skill-usage.md +224 -0
  31. package/docs/workflow-examples.md +16 -13
  32. package/docs/workflow-overview.md +3 -0
  33. package/docs/zh-CN/dv-command-reference.md +47 -0
  34. package/docs/zh-CN/mode-use-cases.md +2 -1
  35. package/docs/zh-CN/pencil-rendering-workflow.md +15 -12
  36. package/docs/zh-CN/prompt-entrypoints.md +2 -0
  37. package/docs/zh-CN/prompt-presets/README.md +1 -1
  38. package/docs/zh-CN/prompt-presets/desktop-app.md +3 -3
  39. package/docs/zh-CN/prompt-presets/mobile-app.md +3 -3
  40. package/docs/zh-CN/prompt-presets/tablet-app.md +3 -3
  41. package/docs/zh-CN/prompt-presets/web-app.md +3 -3
  42. package/docs/zh-CN/skill-usage.md +224 -0
  43. package/docs/zh-CN/workflow-examples.md +15 -13
  44. package/docs/zh-CN/workflow-overview.md +3 -0
  45. package/examples/greenfield-spec-markupflow/.da-vinci/state/execution-signals/demo__lint-tasks.json +16 -0
  46. package/lib/audit-parsers.js +18 -9
  47. package/lib/audit.js +3 -26
  48. package/lib/cli.js +72 -0
  49. package/lib/design-source-registry.js +146 -0
  50. package/lib/save-current-design.js +790 -0
  51. package/lib/supervisor-review.js +1 -1
  52. package/lib/workflow-bootstrap.js +2 -13
  53. package/lib/workflow-persisted-state.js +3 -1
  54. package/lib/workflow-state.js +51 -3
  55. package/package.json +4 -2
  56. package/tui/catalog.js +1293 -0
  57. package/tui/index.js +2583 -0
package/lib/cli.js CHANGED
@@ -32,6 +32,11 @@ const {
32
32
  endPencilSession,
33
33
  getPencilSessionStatus
34
34
  } = require("./pencil-session");
35
+ const {
36
+ SAVE_STATUS,
37
+ saveCurrentDesign,
38
+ formatSaveCurrentDesignReport
39
+ } = require("./save-current-design");
35
40
  const {
36
41
  searchIconLibrary,
37
42
  formatIconSearchReport
@@ -74,6 +79,7 @@ const {
74
79
  const { diffSpec, formatDiffSpecReport } = require("./diff-spec");
75
80
  const { scaffoldFromBindings, formatScaffoldReport } = require("./scaffold");
76
81
  const { writeExecutionSignal } = require("./execution-signals");
82
+ const { formatTuiHelp, launchTui } = require("../tui");
77
83
 
78
84
  const DEFAULT_MAX_PREFLIGHT_STDIN_BYTES = 1024 * 1024;
79
85
  const DEFAULT_MAX_STDIN_TRANSIENT_RETRIES = 2000;
@@ -81,6 +87,8 @@ const DEFAULT_MAX_STDIN_TRANSIENT_BACKOFF_MS = 25;
81
87
  const OPTION_FLAGS_WITH_VALUES = new Set([
82
88
  "--home",
83
89
  "--platform",
90
+ "--lang",
91
+ "--tui-width",
84
92
  "--project",
85
93
  "--mode",
86
94
  "--change",
@@ -111,6 +119,7 @@ const OPTION_FLAGS_WITH_VALUES = new Set([
111
119
  "--from",
112
120
  "--to",
113
121
  "--pen",
122
+ "--pencil-bin",
114
123
  "--nodes-file",
115
124
  "--variables-file",
116
125
  "--version",
@@ -120,6 +129,8 @@ const OPTION_FLAGS_WITH_VALUES = new Set([
120
129
 
121
130
  const HELP_OPTION_SPECS = [
122
131
  { flag: "--platform <value>", description: "codex, claude, gemini, or all" },
132
+ { flag: "--lang <value>", description: "ui language for `da-vinci tui`: en or zh" },
133
+ { flag: "--tui-width <cols>", description: "fixed layout width (columns) for `da-vinci tui`" },
123
134
  { flag: "--home <path>", description: "override HOME for installation targets" },
124
135
  { flag: "--project <path>", description: "override project path for audit" },
125
136
  {
@@ -185,12 +196,15 @@ const HELP_OPTION_SPECS = [
185
196
  flag: "--strict",
186
197
  description: "enable strict failure mode for commands that support advisory defaults (for example icon-sync, lint-spec)"
187
198
  },
199
+ { flag: "--alt-screen", description: "enable alternate terminal screen buffer for `da-vinci tui`" },
200
+ { flag: "--no-alt-screen", description: "disable alternate terminal screen buffer for `da-vinci tui`" },
188
201
  {
189
202
  flag: "--continue-on-error",
190
203
  description: "print BLOCK/FAIL command results without throwing process errors"
191
204
  },
192
205
  { flag: "--json", description: "print structured JSON output when supported by the command" },
193
206
  { flag: "--pen <path>", description: "registered .pen path for sync checks" },
207
+ { flag: "--pencil-bin <path>", description: "override Pencil executable for interactive capture/verify flows" },
194
208
  {
195
209
  flag: "--from <path>",
196
210
  description: "source path for sync-pen-source, or baseline sidecars directory for diff-spec"
@@ -472,6 +486,7 @@ function printHelp() {
472
486
  " da-vinci install --platform codex,claude,gemini",
473
487
  " da-vinci uninstall --platform codex,claude,gemini",
474
488
  " da-vinci status",
489
+ " da-vinci tui [--project <path>] [--change <id>] [--lang en|zh] [--strict] [--json] [--continue-on-error] [--tui-width <cols>] [--alt-screen|--no-alt-screen]",
475
490
  " da-vinci workflow-status [--project <path>] [--change <id>] [--json]",
476
491
  " da-vinci next-step [--project <path>] [--change <id>] [--json]",
477
492
  " da-vinci lint-spec [--project <path>] [--change <id>] [--strict] [--json]",
@@ -498,6 +513,7 @@ function printHelp() {
498
513
  " da-vinci check-pen-baseline --pen <path> --baseline <path>[,<path>...] [--baseline <path>] [--prefer-source <path>]",
499
514
  " da-vinci sync-pen-source --from <path> --to <path>",
500
515
  " da-vinci snapshot-pen --input <path> --output <path>",
516
+ " da-vinci save-current-design --project <path> [--json] [--continue-on-error]",
501
517
  " da-vinci pencil-lock acquire --project <path>",
502
518
  " da-vinci pencil-lock release --project <path>",
503
519
  " da-vinci pencil-lock status",
@@ -937,6 +953,33 @@ async function runCli(argv) {
937
953
  return;
938
954
  }
939
955
 
956
+ if (command === "tui") {
957
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
958
+ const changeId = getOption(argv, "--change");
959
+ const lang = getOption(argv, "--lang");
960
+ const tuiWidth = getOption(argv, "--tui-width");
961
+ const altScreen = argv.includes("--alt-screen")
962
+ ? true
963
+ : argv.includes("--no-alt-screen")
964
+ ? false
965
+ : undefined;
966
+ if (argv.includes("--help") || argv.includes("-h")) {
967
+ console.log(formatTuiHelp(lang));
968
+ return;
969
+ }
970
+ await launchTui({
971
+ projectPath,
972
+ changeId,
973
+ lang,
974
+ tuiWidth,
975
+ altScreen,
976
+ strict: argv.includes("--strict"),
977
+ jsonOutput: argv.includes("--json"),
978
+ continueOnError
979
+ });
980
+ return;
981
+ }
982
+
940
983
  if (command === "workflow-status") {
941
984
  const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
942
985
  const changeId = getOption(argv, "--change");
@@ -1402,6 +1445,35 @@ async function runCli(argv) {
1402
1445
  return;
1403
1446
  }
1404
1447
 
1448
+ if (command === "save-current-design") {
1449
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
1450
+ const pencilBin = getOption(argv, "--pencil-bin");
1451
+ const result = await saveCurrentDesign({
1452
+ projectPath,
1453
+ homeDir,
1454
+ pencilBin,
1455
+ allowLocalBridge: true
1456
+ });
1457
+ const useJson = argv.includes("--json");
1458
+ const output = useJson
1459
+ ? JSON.stringify(result, null, 2)
1460
+ : formatSaveCurrentDesignReport(result);
1461
+
1462
+ if (
1463
+ emitOrThrowOnStatus(
1464
+ result.status,
1465
+ [SAVE_STATUS.BLOCKED, SAVE_STATUS.UNAVAILABLE],
1466
+ output,
1467
+ continueOnError
1468
+ )
1469
+ ) {
1470
+ return;
1471
+ }
1472
+
1473
+ console.log(output);
1474
+ return;
1475
+ }
1476
+
1405
1477
  if (command === "pencil-lock") {
1406
1478
  handlePencilLockCommand(argv, homeDir);
1407
1479
  return;
@@ -0,0 +1,146 @@
1
+ const path = require("path");
2
+ const { isPathInside } = require("./fs-safety");
3
+
4
+ const REGISTERED_PEN_PATTERN = /\.da-vinci\/designs\/[^\s`]+\.pen/g;
5
+
6
+ function normalizeProjectRoot(projectRoot) {
7
+ return path.resolve(projectRoot || process.cwd());
8
+ }
9
+
10
+ function collectRegisteredPenReferences(registryText) {
11
+ const matches = String(registryText || "").match(REGISTERED_PEN_PATTERN) || [];
12
+ const seen = new Set();
13
+ const unique = [];
14
+
15
+ for (const match of matches) {
16
+ const normalized = String(match || "").trim();
17
+ if (!normalized || seen.has(normalized)) {
18
+ continue;
19
+ }
20
+ seen.add(normalized);
21
+ unique.push(normalized);
22
+ }
23
+
24
+ return unique;
25
+ }
26
+
27
+ function normalizeBoundPenPath(projectRoot, penPath, options = {}) {
28
+ const root = normalizeProjectRoot(projectRoot);
29
+ const raw = typeof penPath === "string" ? penPath.trim() : "";
30
+
31
+ if (!raw) {
32
+ return {
33
+ ok: false,
34
+ code: options.missingCode || "missing_path",
35
+ input: raw,
36
+ resolvedPath: ""
37
+ };
38
+ }
39
+
40
+ if (options.rejectNew && raw.toLowerCase() === "new") {
41
+ return {
42
+ ok: false,
43
+ code: options.newCode || "active_editor_new",
44
+ input: raw,
45
+ resolvedPath: ""
46
+ };
47
+ }
48
+
49
+ const resolvedPath = path.normalize(path.isAbsolute(raw) ? raw : path.resolve(root, raw));
50
+ if (!isPathInside(root, resolvedPath)) {
51
+ return {
52
+ ok: false,
53
+ code: options.outsideCode || "outside_project_root",
54
+ input: raw,
55
+ resolvedPath
56
+ };
57
+ }
58
+
59
+ if (options.requirePenExtension !== false && !/\.pen$/i.test(resolvedPath)) {
60
+ return {
61
+ ok: false,
62
+ code: options.extensionCode || "not_pen_path",
63
+ input: raw,
64
+ resolvedPath
65
+ };
66
+ }
67
+
68
+ return {
69
+ ok: true,
70
+ code: "ok",
71
+ input: raw,
72
+ resolvedPath
73
+ };
74
+ }
75
+
76
+ function normalizeRegisteredPenPath(projectRoot, penPath) {
77
+ return normalizeBoundPenPath(projectRoot, penPath, {
78
+ missingCode: "registered_pen_missing",
79
+ outsideCode: "registered_pen_outside_project_root",
80
+ extensionCode: "registered_pen_not_pen_path"
81
+ });
82
+ }
83
+
84
+ function normalizeSessionPenPath(projectRoot, penPath) {
85
+ return normalizeBoundPenPath(projectRoot, penPath, {
86
+ missingCode: "session_pen_missing",
87
+ outsideCode: "session_pen_outside_project_root",
88
+ extensionCode: "session_pen_not_pen_path"
89
+ });
90
+ }
91
+
92
+ function normalizeActiveEditorPath(projectRoot, activeEditorPath) {
93
+ return normalizeBoundPenPath(projectRoot, activeEditorPath, {
94
+ rejectNew: true,
95
+ missingCode: "active_editor_missing",
96
+ newCode: "active_editor_new",
97
+ outsideCode: "active_editor_outside_project_root",
98
+ extensionCode: "active_editor_not_pen_path"
99
+ });
100
+ }
101
+
102
+ function collectRegisteredPenPaths(projectRoot, registryText) {
103
+ const root = normalizeProjectRoot(projectRoot);
104
+ const references = collectRegisteredPenReferences(registryText);
105
+ const validPaths = [];
106
+ const escapedPaths = [];
107
+ const seenResolved = new Set();
108
+
109
+ for (const relativePath of references) {
110
+ const normalized = normalizeRegisteredPenPath(root, relativePath);
111
+ if (normalized.ok) {
112
+ if (!seenResolved.has(normalized.resolvedPath)) {
113
+ seenResolved.add(normalized.resolvedPath);
114
+ validPaths.push(normalized.resolvedPath);
115
+ }
116
+ continue;
117
+ }
118
+
119
+ if (normalized.code === "registered_pen_outside_project_root") {
120
+ escapedPaths.push({
121
+ relativePath,
122
+ resolvedPath: normalized.resolvedPath
123
+ });
124
+ }
125
+ }
126
+
127
+ return {
128
+ validPaths,
129
+ escapedPaths
130
+ };
131
+ }
132
+
133
+ function resolvePreferredRegisteredPenPath(projectRoot, registryText) {
134
+ const resolved = collectRegisteredPenPaths(projectRoot, registryText);
135
+ return resolved.validPaths[0] || "";
136
+ }
137
+
138
+ module.exports = {
139
+ collectRegisteredPenReferences,
140
+ normalizeBoundPenPath,
141
+ normalizeRegisteredPenPath,
142
+ normalizeSessionPenPath,
143
+ normalizeActiveEditorPath,
144
+ collectRegisteredPenPaths,
145
+ resolvePreferredRegisteredPenPath
146
+ };