@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.
- package/CHANGELOG.md +13 -0
- package/README.md +32 -7
- package/README.zh-CN.md +151 -7
- package/commands/claude/dv/build.md +5 -0
- package/commands/claude/dv/continue.md +4 -0
- package/commands/claude/dv/tasks.md +6 -0
- package/commands/claude/dv/verify.md +2 -0
- package/commands/codex/prompts/dv-build.md +5 -0
- package/commands/codex/prompts/dv-continue.md +4 -0
- package/commands/codex/prompts/dv-tasks.md +6 -0
- package/commands/codex/prompts/dv-verify.md +2 -0
- package/commands/gemini/dv/build.toml +5 -0
- package/commands/gemini/dv/continue.toml +4 -0
- package/commands/gemini/dv/tasks.toml +6 -0
- package/commands/gemini/dv/verify.toml +2 -0
- package/commands/templates/dv-continue.shared.md +4 -0
- package/docs/discipline-and-orchestration-upgrade.md +83 -0
- package/docs/dv-command-reference.md +18 -2
- package/docs/execution-chain-migration.md +23 -0
- package/docs/prompt-entrypoints.md +5 -0
- package/docs/skill-usage.md +16 -0
- package/docs/workflow-overview.md +17 -0
- package/docs/zh-CN/dv-command-reference.md +16 -2
- package/docs/zh-CN/execution-chain-migration.md +23 -0
- package/docs/zh-CN/prompt-entrypoints.md +5 -0
- package/docs/zh-CN/skill-usage.md +16 -0
- package/docs/zh-CN/workflow-overview.md +17 -0
- package/lib/audit-parsers.js +148 -1
- package/lib/cli.js +106 -1
- package/lib/execution-profile.js +143 -0
- package/lib/execution-signals.js +19 -1
- package/lib/lint-tasks.js +86 -2
- package/lib/planning-parsers.js +255 -18
- package/lib/supervisor-review.js +2 -1
- package/lib/task-execution.js +160 -0
- package/lib/task-review.js +197 -0
- package/lib/verify.js +152 -1
- package/lib/workflow-state.js +452 -30
- package/lib/worktree-preflight.js +214 -0
- package/package.json +1 -1
- 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
|
};
|