@xenonbyte/da-vinci-workflow 0.2.3 → 0.2.4

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 (41) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +32 -7
  3. package/README.zh-CN.md +151 -7
  4. package/commands/claude/dv/build.md +5 -0
  5. package/commands/claude/dv/continue.md +4 -0
  6. package/commands/claude/dv/tasks.md +6 -0
  7. package/commands/claude/dv/verify.md +2 -0
  8. package/commands/codex/prompts/dv-build.md +5 -0
  9. package/commands/codex/prompts/dv-continue.md +4 -0
  10. package/commands/codex/prompts/dv-tasks.md +6 -0
  11. package/commands/codex/prompts/dv-verify.md +2 -0
  12. package/commands/gemini/dv/build.toml +5 -0
  13. package/commands/gemini/dv/continue.toml +4 -0
  14. package/commands/gemini/dv/tasks.toml +6 -0
  15. package/commands/gemini/dv/verify.toml +2 -0
  16. package/commands/templates/dv-continue.shared.md +4 -0
  17. package/docs/discipline-and-orchestration-upgrade.md +83 -0
  18. package/docs/dv-command-reference.md +18 -2
  19. package/docs/execution-chain-migration.md +23 -0
  20. package/docs/prompt-entrypoints.md +5 -0
  21. package/docs/skill-usage.md +16 -0
  22. package/docs/workflow-overview.md +17 -0
  23. package/docs/zh-CN/dv-command-reference.md +16 -2
  24. package/docs/zh-CN/execution-chain-migration.md +23 -0
  25. package/docs/zh-CN/prompt-entrypoints.md +5 -0
  26. package/docs/zh-CN/skill-usage.md +16 -0
  27. package/docs/zh-CN/workflow-overview.md +17 -0
  28. package/lib/audit-parsers.js +148 -1
  29. package/lib/cli.js +106 -1
  30. package/lib/execution-profile.js +143 -0
  31. package/lib/execution-signals.js +19 -1
  32. package/lib/lint-tasks.js +86 -2
  33. package/lib/planning-parsers.js +255 -18
  34. package/lib/supervisor-review.js +2 -1
  35. package/lib/task-execution.js +160 -0
  36. package/lib/task-review.js +197 -0
  37. package/lib/verify.js +152 -1
  38. package/lib/workflow-state.js +452 -30
  39. package/lib/worktree-preflight.js +214 -0
  40. package/package.json +1 -1
  41. package/references/artifact-templates.md +56 -6
package/lib/verify.js CHANGED
@@ -13,6 +13,7 @@ const {
13
13
  readChangeArtifacts,
14
14
  readArtifactTexts
15
15
  } = require("./planning-parsers");
16
+ const { readExecutionSignals, summarizeSignalsBySurface } = require("./execution-signals");
16
17
 
17
18
  const CODE_FILE_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx", ".html", ".css", ".scss"]);
18
19
  const NON_IMPLEMENTATION_DIR_NAMES = new Set([
@@ -47,6 +48,7 @@ const MAX_SCANNED_FILES = 2000;
47
48
  const MAX_SCANNED_BYTES_PER_FILE = 512 * 1024;
48
49
  const MAX_SCANNED_DIRECTORIES = 10000;
49
50
  const MAX_SCAN_DEPTH = 32;
51
+ const DEFAULT_EVIDENCE_MAX_AGE_MS = 24 * 60 * 60 * 1000;
50
52
 
51
53
  function buildEnvelope(name, projectRoot, strict) {
52
54
  return {
@@ -226,6 +228,138 @@ function allCovered(checks) {
226
228
  return true;
227
229
  }
228
230
 
231
+ function safeMtimeMs(filePath) {
232
+ try {
233
+ const stat = fs.statSync(filePath);
234
+ return Number(stat.mtimeMs) || 0;
235
+ } catch (_error) {
236
+ return 0;
237
+ }
238
+ }
239
+
240
+ function collectFreshnessBaseline(projectRoot, resolved, artifactPaths) {
241
+ const baselineCandidates = [];
242
+ if (artifactPaths) {
243
+ baselineCandidates.push(
244
+ artifactPaths.proposalPath,
245
+ artifactPaths.tasksPath,
246
+ artifactPaths.bindingsPath,
247
+ artifactPaths.pencilDesignPath,
248
+ artifactPaths.verificationPath
249
+ );
250
+ }
251
+ if (resolved && resolved.changeDir) {
252
+ const specsRoot = path.join(resolved.changeDir, "specs");
253
+ if (fs.existsSync(specsRoot)) {
254
+ const stack = [specsRoot];
255
+ while (stack.length > 0) {
256
+ const current = stack.pop();
257
+ let entries = [];
258
+ try {
259
+ entries = fs.readdirSync(current, { withFileTypes: true });
260
+ } catch (_error) {
261
+ continue;
262
+ }
263
+ for (const entry of entries) {
264
+ const absolutePath = path.join(current, entry.name);
265
+ if (entry.isDirectory() && !entry.isSymbolicLink()) {
266
+ stack.push(absolutePath);
267
+ continue;
268
+ }
269
+ if (entry.isFile() && entry.name === "spec.md") {
270
+ baselineCandidates.push(absolutePath);
271
+ }
272
+ }
273
+ }
274
+ }
275
+ }
276
+ const baselineMs = baselineCandidates.reduce((latest, candidate) => Math.max(latest, safeMtimeMs(candidate)), 0);
277
+ return {
278
+ baselineMs,
279
+ baselineIso: baselineMs > 0 ? new Date(baselineMs).toISOString() : ""
280
+ };
281
+ }
282
+
283
+ function collectVerificationFreshness(projectPathInput, options = {}) {
284
+ const projectRoot = path.resolve(projectPathInput || process.cwd());
285
+ const changeId = options.changeId ? String(options.changeId).trim() : "";
286
+ if (!changeId) {
287
+ return {
288
+ fresh: false,
289
+ changeId: null,
290
+ requiredSurfaces: [],
291
+ surfaces: {},
292
+ staleReasons: ["Missing change id for verification freshness checks."],
293
+ baselineIso: ""
294
+ };
295
+ }
296
+
297
+ const requiredSurfaces =
298
+ Array.isArray(options.requiredSurfaces) && options.requiredSurfaces.length > 0
299
+ ? options.requiredSurfaces
300
+ : ["verify-bindings", "verify-implementation", "verify-structure", "verify-coverage"];
301
+ const maxAgeMs =
302
+ Number.isFinite(Number(options.maxAgeMs)) && Number(options.maxAgeMs) > 0
303
+ ? Number(options.maxAgeMs)
304
+ : DEFAULT_EVIDENCE_MAX_AGE_MS;
305
+ const nowMs = Date.now();
306
+ const signals = readExecutionSignals(projectRoot, { changeId });
307
+ const summary = summarizeSignalsBySurface(signals);
308
+ const baseline = collectFreshnessBaseline(projectRoot, options.resolved, options.artifactPaths);
309
+ const staleReasons = [];
310
+ const surfaces = {};
311
+
312
+ for (const surface of requiredSurfaces) {
313
+ const key = String(surface || "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-");
314
+ const signal = summary[key];
315
+ if (!signal) {
316
+ staleReasons.push(`Missing evidence signal: ${surface}.`);
317
+ surfaces[surface] = {
318
+ present: false,
319
+ stale: true
320
+ };
321
+ continue;
322
+ }
323
+ const timestampMs = Date.parse(String(signal.timestamp || ""));
324
+ if (!Number.isFinite(timestampMs)) {
325
+ staleReasons.push(`Invalid evidence timestamp for ${surface}.`);
326
+ surfaces[surface] = {
327
+ present: true,
328
+ stale: true,
329
+ timestamp: signal.timestamp || ""
330
+ };
331
+ continue;
332
+ }
333
+ const olderThanBaseline = baseline.baselineMs > 0 && timestampMs < baseline.baselineMs;
334
+ const olderThanMaxAge = nowMs - timestampMs > maxAgeMs;
335
+ if (olderThanBaseline) {
336
+ staleReasons.push(
337
+ `${surface} evidence is older than current artifact baseline (${new Date(timestampMs).toISOString()} < ${baseline.baselineIso}).`
338
+ );
339
+ }
340
+ if (olderThanMaxAge) {
341
+ staleReasons.push(
342
+ `${surface} evidence is older than freshness window (${Math.round((nowMs - timestampMs) / 1000)}s).`
343
+ );
344
+ }
345
+ surfaces[surface] = {
346
+ present: true,
347
+ stale: olderThanBaseline || olderThanMaxAge,
348
+ status: signal.status,
349
+ timestamp: signal.timestamp
350
+ };
351
+ }
352
+
353
+ return {
354
+ fresh: staleReasons.length === 0,
355
+ changeId,
356
+ requiredSurfaces,
357
+ surfaces,
358
+ staleReasons: unique(staleReasons),
359
+ baselineIso: baseline.baselineIso
360
+ };
361
+ }
362
+
229
363
  function createSharedSetup(projectPathInput, options = {}) {
230
364
  const projectRoot = path.resolve(projectPathInput || process.cwd());
231
365
  const strict = options && options.strict === true;
@@ -600,6 +734,22 @@ function verifyCoverage(projectPathInput, options = {}) {
600
734
  }
601
735
  };
602
736
 
737
+ const freshness = collectVerificationFreshness(projectRoot, {
738
+ changeId: result.changeId,
739
+ resolved: sharedSetup.resolved,
740
+ artifactPaths: sharedSetup.artifactPaths,
741
+ requiredSurfaces: ["verify-bindings", "verify-implementation", "verify-structure"]
742
+ });
743
+ result.freshness = freshness;
744
+ if (!freshness.fresh) {
745
+ result.warnings.push(
746
+ "Verification freshness is stale for completion-facing claims; re-run verify surfaces before completion wording."
747
+ );
748
+ for (const reason of freshness.staleReasons) {
749
+ result.warnings.push(reason);
750
+ }
751
+ }
752
+
603
753
  return finalize(result);
604
754
  }
605
755
 
@@ -648,5 +798,6 @@ module.exports = {
648
798
  verifyImplementation,
649
799
  verifyStructure,
650
800
  verifyCoverage,
651
- formatVerifyReport
801
+ formatVerifyReport,
802
+ collectVerificationFreshness
652
803
  };