@xenonbyte/da-vinci-workflow 0.2.8 → 0.2.9

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.
@@ -0,0 +1,221 @@
1
+ const { registerCommand } = require("./helpers");
2
+
3
+ /**
4
+ * @typedef {Object} CliWorkflowCommandContext
5
+ * @property {string[]} argv
6
+ * @property {string[]} positionalArgs
7
+ * @property {boolean} continueOnError
8
+ * @property {(args: string[], name: string) => string | undefined} getOption
9
+ * @property {(args: string[], name: string) => string[]} getCommaSeparatedOptionValues
10
+ * @property {Function} deriveWorkflowStatus
11
+ * @property {Function} formatWorkflowStatusReport
12
+ * @property {Function} formatNextStepReport
13
+ * @property {Function} generatePlanningSidecars
14
+ * @property {Function} formatGenerateSidecarsReport
15
+ * @property {Function} writeTaskExecutionEnvelope
16
+ * @property {Function} formatTaskExecutionReport
17
+ * @property {Function} writeTaskReviewEnvelope
18
+ * @property {Function} formatTaskReviewReport
19
+ * @property {Function} runWorktreePreflight
20
+ * @property {Function} formatWorktreePreflightReport
21
+ * @property {Function} diffSpec
22
+ * @property {Function} formatDiffSpecReport
23
+ * @property {Function} scaffoldFromBindings
24
+ * @property {Function} formatScaffoldReport
25
+ * @property {Function} auditProject
26
+ * @property {Function} formatAuditReport
27
+ * @property {Function} bootstrapProjectArtifacts
28
+ * @property {Function} formatBootstrapProjectReport
29
+ * @property {Function} persistExecutionSignal
30
+ * @property {Function} emitCommandOutput
31
+ * @property {Function} emitOrThrowOnStatus
32
+ */
33
+
34
+ /**
35
+ * Register workflow, planning, review, and audit-oriented CLI commands.
36
+ *
37
+ * @param {import("./helpers").CliCommandHandlerMap} handlers
38
+ * @param {CliWorkflowCommandContext} context
39
+ * @returns {void}
40
+ */
41
+ function registerWorkflowCommands(handlers, context) {
42
+ const {
43
+ argv,
44
+ positionalArgs,
45
+ continueOnError,
46
+ getOption,
47
+ getCommaSeparatedOptionValues,
48
+ deriveWorkflowStatus,
49
+ formatWorkflowStatusReport,
50
+ formatNextStepReport,
51
+ generatePlanningSidecars,
52
+ formatGenerateSidecarsReport,
53
+ writeTaskExecutionEnvelope,
54
+ formatTaskExecutionReport,
55
+ writeTaskReviewEnvelope,
56
+ formatTaskReviewReport,
57
+ runWorktreePreflight,
58
+ formatWorktreePreflightReport,
59
+ diffSpec,
60
+ formatDiffSpecReport,
61
+ scaffoldFromBindings,
62
+ formatScaffoldReport,
63
+ auditProject,
64
+ formatAuditReport,
65
+ bootstrapProjectArtifacts,
66
+ formatBootstrapProjectReport,
67
+ persistExecutionSignal,
68
+ emitCommandOutput,
69
+ emitOrThrowOnStatus
70
+ } = context;
71
+
72
+ registerCommand(handlers, "workflow-status", async () => {
73
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
74
+ const changeId = getOption(argv, "--change");
75
+ const result = deriveWorkflowStatus(projectPath, {
76
+ changeId,
77
+ traceSurface: "workflow-status",
78
+ env: process.env
79
+ });
80
+
81
+ if (argv.includes("--json")) {
82
+ console.log(JSON.stringify(result, null, 2));
83
+ return;
84
+ }
85
+
86
+ console.log(formatWorkflowStatusReport(result));
87
+ });
88
+
89
+ registerCommand(handlers, "next-step", async () => {
90
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
91
+ const changeId = getOption(argv, "--change");
92
+ const result = deriveWorkflowStatus(projectPath, {
93
+ changeId,
94
+ traceSurface: "next-step",
95
+ env: process.env
96
+ });
97
+
98
+ if (argv.includes("--json")) {
99
+ console.log(
100
+ JSON.stringify(
101
+ {
102
+ stage: result.stage,
103
+ checkpointState: result.checkpointState,
104
+ nextStep: result.nextStep || null,
105
+ blockingGate: result.blockingGate || null,
106
+ discipline: result.discipline || null,
107
+ executionProfile: result.executionProfile || null,
108
+ worktreePreflight: result.worktreePreflight || null,
109
+ verificationFreshness: result.verificationFreshness || null,
110
+ traceDiagnostics: result.traceDiagnostics || null
111
+ },
112
+ null,
113
+ 2
114
+ )
115
+ );
116
+ return;
117
+ }
118
+
119
+ console.log(formatNextStepReport(result));
120
+ });
121
+
122
+ registerCommand(handlers, "generate-sidecars", async () => {
123
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
124
+ const changeId = getOption(argv, "--change");
125
+ const result = generatePlanningSidecars(projectPath, { changeId, write: true });
126
+ persistExecutionSignal(projectPath, result.changeId || changeId, "generate-sidecars", result, false);
127
+ emitCommandOutput(result, argv, formatGenerateSidecarsReport, ["BLOCK"], continueOnError);
128
+ });
129
+
130
+ registerCommand(handlers, "task-execution", async () => {
131
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
132
+ const changeId = getOption(argv, "--change");
133
+ const result = writeTaskExecutionEnvelope(projectPath, {
134
+ changeId,
135
+ taskGroupId: getOption(argv, "--task-group"),
136
+ status: getOption(argv, "--status"),
137
+ summary: getOption(argv, "--summary"),
138
+ changedFiles: getCommaSeparatedOptionValues(argv, "--changed-files"),
139
+ testEvidence: getCommaSeparatedOptionValues(argv, "--test-evidence"),
140
+ pendingTestEvidence: getCommaSeparatedOptionValues(argv, "--pending-test-evidence"),
141
+ confirmTestEvidenceExecuted: argv.includes("--confirm-test-evidence-executed"),
142
+ concerns: getCommaSeparatedOptionValues(argv, "--concerns"),
143
+ blockers: getCommaSeparatedOptionValues(argv, "--blockers"),
144
+ outOfScopeWrites: getCommaSeparatedOptionValues(argv, "--out-of-scope-writes"),
145
+ partial: argv.includes("--partial")
146
+ });
147
+ emitCommandOutput(result, argv, formatTaskExecutionReport, ["BLOCK"], continueOnError);
148
+ });
149
+
150
+ registerCommand(handlers, "task-review", async () => {
151
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
152
+ const changeId = getOption(argv, "--change");
153
+ const result = writeTaskReviewEnvelope(projectPath, {
154
+ changeId,
155
+ taskGroupId: getOption(argv, "--task-group"),
156
+ stage: getOption(argv, "--stage"),
157
+ status: getOption(argv, "--status"),
158
+ summary: getOption(argv, "--summary"),
159
+ issues: getCommaSeparatedOptionValues(argv, "--issues"),
160
+ reviewer: getOption(argv, "--reviewer"),
161
+ writeVerification: argv.includes("--write-verification")
162
+ });
163
+ emitCommandOutput(result, argv, formatTaskReviewReport, ["BLOCK"], continueOnError);
164
+ });
165
+
166
+ registerCommand(handlers, "worktree-preflight", async () => {
167
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
168
+ const changeId = getOption(argv, "--change");
169
+ const result = runWorktreePreflight(projectPath);
170
+ persistExecutionSignal(projectPath, changeId || "global", "worktree-preflight", result, false);
171
+ if (argv.includes("--json")) {
172
+ console.log(JSON.stringify(result, null, 2));
173
+ return;
174
+ }
175
+ console.log(formatWorktreePreflightReport(result));
176
+ });
177
+
178
+ registerCommand(handlers, "diff-spec", async () => {
179
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
180
+ const changeId = getOption(argv, "--change");
181
+ const fromDir = getOption(argv, "--from");
182
+ const result = diffSpec(projectPath, { changeId, fromDir });
183
+ persistExecutionSignal(projectPath, result.changeId || changeId, "diff-spec", result, false);
184
+ emitCommandOutput(result, argv, formatDiffSpecReport, ["BLOCK"], continueOnError);
185
+ });
186
+
187
+ registerCommand(handlers, "scaffold", async () => {
188
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
189
+ const changeId = getOption(argv, "--change");
190
+ const outputDir = getOption(argv, "--output");
191
+ const result = scaffoldFromBindings(projectPath, { changeId, outputDir });
192
+ persistExecutionSignal(projectPath, result.changeId || changeId, "scaffold", result, false);
193
+ emitCommandOutput(result, argv, formatScaffoldReport, ["BLOCK"], continueOnError);
194
+ });
195
+
196
+ registerCommand(handlers, "audit", async () => {
197
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
198
+ const mode = getOption(argv, "--mode");
199
+ const changeId = getOption(argv, "--change");
200
+ const result = auditProject(projectPath, { mode, changeId });
201
+ const report = formatAuditReport(result);
202
+
203
+ if (emitOrThrowOnStatus(result.status, ["FAIL"], report, continueOnError)) {
204
+ return;
205
+ }
206
+
207
+ console.log(report);
208
+ });
209
+
210
+ registerCommand(handlers, "bootstrap-project", async () => {
211
+ const projectPath = getOption(argv, "--project") || positionalArgs[0] || process.cwd();
212
+ const changeId = getOption(argv, "--change");
213
+ const force = argv.includes("--force");
214
+ const result = bootstrapProjectArtifacts(projectPath, { changeId, force });
215
+ console.log(formatBootstrapProjectReport(result));
216
+ });
217
+ }
218
+
219
+ module.exports = {
220
+ registerWorkflowCommands
221
+ };
@@ -0,0 +1,49 @@
1
+ const { registerCoreCommands } = require("./command-handlers-core");
2
+ const { registerWorkflowCommands } = require("./command-handlers-workflow");
3
+ const { registerDesignCommands } = require("./command-handlers-design");
4
+ const { registerPenCommands } = require("./command-handlers-pen");
5
+
6
+ function resolveFamilyContext(shared, optionHelpers, family) {
7
+ return {
8
+ ...shared,
9
+ ...optionHelpers,
10
+ ...(family || {})
11
+ };
12
+ }
13
+
14
+ /**
15
+ * Build the complete CLI command registry from command-family registration modules.
16
+ *
17
+ * @param {object} context
18
+ * @returns {Map<string, Function>}
19
+ */
20
+ function buildCommandHandlers(context) {
21
+ const shared = context && context.shared ? context.shared : context;
22
+ const optionHelpers = context && context.optionHelpers ? context.optionHelpers : context;
23
+ const handlers = new Map();
24
+ registerCoreCommands(
25
+ handlers,
26
+ resolveFamilyContext(shared, optionHelpers, context && context.core ? context.core : context)
27
+ );
28
+ registerWorkflowCommands(
29
+ handlers,
30
+ resolveFamilyContext(
31
+ shared,
32
+ optionHelpers,
33
+ context && context.workflow ? context.workflow : context
34
+ )
35
+ );
36
+ registerDesignCommands(
37
+ handlers,
38
+ resolveFamilyContext(shared, optionHelpers, context && context.design ? context.design : context)
39
+ );
40
+ registerPenCommands(
41
+ handlers,
42
+ resolveFamilyContext(shared, optionHelpers, context && context.pen ? context.pen : context)
43
+ );
44
+ return handlers;
45
+ }
46
+
47
+ module.exports = {
48
+ buildCommandHandlers
49
+ };
@@ -1,6 +1,19 @@
1
1
  const { writeExecutionSignal } = require("../execution-signals");
2
2
  const { STATUS } = require("../workflow-contract");
3
3
 
4
+ /**
5
+ * @typedef {Map<string, Function>} CliCommandHandlerMap
6
+ */
7
+
8
+ /**
9
+ * Throw on blocked/failing statuses unless `--continue-on-error` is active.
10
+ *
11
+ * @param {string} status
12
+ * @param {string[]} blockedStatuses
13
+ * @param {string} output
14
+ * @param {boolean} continueOnError
15
+ * @returns {boolean}
16
+ */
4
17
  function emitOrThrowOnStatus(status, blockedStatuses, output, continueOnError) {
5
18
  if (!Array.isArray(blockedStatuses) || !blockedStatuses.includes(status)) {
6
19
  return false;
@@ -12,6 +25,53 @@ function emitOrThrowOnStatus(status, blockedStatuses, output, continueOnError) {
12
25
  throw new Error(output);
13
26
  }
14
27
 
28
+ /**
29
+ * Emit either JSON or formatted text for a command result, respecting `--continue-on-error`.
30
+ *
31
+ * @param {{ status: string }} result
32
+ * @param {string[]} argv
33
+ * @param {(result: object) => string} formatter
34
+ * @param {string[]} blockedStatuses
35
+ * @param {boolean} continueOnError
36
+ * @returns {void}
37
+ */
38
+ function emitCommandOutput(result, argv, formatter, blockedStatuses, continueOnError) {
39
+ const output = argv.includes("--json")
40
+ ? JSON.stringify(result, null, 2)
41
+ : formatter(result);
42
+ if (
43
+ Array.isArray(blockedStatuses) &&
44
+ emitOrThrowOnStatus(result.status, blockedStatuses, output, continueOnError)
45
+ ) {
46
+ return;
47
+ }
48
+ console.log(output);
49
+ }
50
+
51
+ /**
52
+ * Register one or more command names against the same handler.
53
+ *
54
+ * @param {CliCommandHandlerMap} handlers
55
+ * @param {string|string[]} names
56
+ * @param {Function} handler
57
+ * @returns {void}
58
+ */
59
+ function registerCommand(handlers, names, handler) {
60
+ for (const name of Array.isArray(names) ? names : [names]) {
61
+ handlers.set(name, handler);
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Persist an advisory execution signal for workflow/routing consumers.
67
+ *
68
+ * @param {string} projectPath
69
+ * @param {string} changeId
70
+ * @param {string} surface
71
+ * @param {{ status?: string, failures?: string[], warnings?: string[], notes?: string[], gates?: object, summary?: object }} result
72
+ * @param {boolean} [strict=false]
73
+ * @returns {void}
74
+ */
15
75
  function persistExecutionSignal(projectPath, changeId, surface, result, strict = false) {
16
76
  const normalizeStatus = (status) => {
17
77
  const normalized = String(status || "").trim().toUpperCase();
@@ -100,5 +160,7 @@ function persistExecutionSignal(projectPath, changeId, surface, result, strict =
100
160
 
101
161
  module.exports = {
102
162
  emitOrThrowOnStatus,
163
+ emitCommandOutput,
164
+ registerCommand,
103
165
  persistExecutionSignal
104
166
  };