@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.
@@ -118,6 +118,38 @@ function readExecutionSignals(projectRoot, options = {}) {
118
118
  );
119
119
  }
120
120
 
121
+ function listExecutionSignalPathsForChange(projectRoot, options = {}) {
122
+ const changeId = options.changeId ? String(options.changeId).trim() : "";
123
+ const signalsDir = resolveSignalsDir(projectRoot);
124
+ if (!changeId || !pathExists(signalsDir)) {
125
+ return [];
126
+ }
127
+
128
+ const entries = fs
129
+ .readdirSync(signalsDir, { withFileTypes: true })
130
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".json"));
131
+ const paths = [];
132
+
133
+ for (const entry of entries) {
134
+ const absolutePath = path.join(signalsDir, entry.name);
135
+ const parsedName = parseSignalFileName(entry.name);
136
+ let include = false;
137
+
138
+ try {
139
+ const payload = JSON.parse(fs.readFileSync(absolutePath, "utf8"));
140
+ include = String(payload.changeId || "") === changeId;
141
+ } catch (_error) {
142
+ include = String(parsedName.changeId || "").trim() === changeId;
143
+ }
144
+
145
+ if (include) {
146
+ paths.push(absolutePath);
147
+ }
148
+ }
149
+
150
+ return paths.sort((left, right) => left.localeCompare(right));
151
+ }
152
+
121
153
  function summarizeSignalsBySurface(signals) {
122
154
  const summary = {};
123
155
  for (const signal of signals || []) {
@@ -148,6 +180,7 @@ function getLatestSignalBySurfacePrefix(signals, prefix) {
148
180
  module.exports = {
149
181
  writeExecutionSignal,
150
182
  readExecutionSignals,
183
+ listExecutionSignalPathsForChange,
151
184
  summarizeSignalsBySurface,
152
185
  listSignalsBySurfacePrefix,
153
186
  getLatestSignalBySurfacePrefix
package/lib/fs-safety.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const fs = require("fs");
2
2
  const path = require("path");
3
3
  const { pathExists } = require("./utils");
4
+ const { isPathInside } = require("./path-inside");
4
5
 
5
6
  const DEFAULT_MAX_DEPTH = 32;
6
7
  const DEFAULT_MAX_ENTRIES = 20000;
@@ -19,18 +20,6 @@ function toPositiveInteger(value, fallback) {
19
20
  return normalized;
20
21
  }
21
22
 
22
- function isPathInside(basePath, targetPath) {
23
- const resolvedBase = path.resolve(basePath);
24
- const resolvedTarget = path.resolve(targetPath);
25
-
26
- if (resolvedBase === resolvedTarget) {
27
- return true;
28
- }
29
-
30
- const relative = path.relative(resolvedBase, resolvedTarget);
31
- return Boolean(relative) && !relative.startsWith("..") && !path.isAbsolute(relative);
32
- }
33
-
34
23
  function listFilesRecursiveSafe(rootDir, options = {}) {
35
24
  const maxDepth = toPositiveInteger(options.maxDepth, DEFAULT_MAX_DEPTH);
36
25
  const maxEntries = toPositiveInteger(options.maxEntries, DEFAULT_MAX_ENTRIES);
@@ -0,0 +1,17 @@
1
+ const path = require("path");
2
+
3
+ function isPathInside(basePath, targetPath) {
4
+ const resolvedBase = path.resolve(basePath);
5
+ const resolvedTarget = path.resolve(targetPath);
6
+
7
+ if (resolvedBase === resolvedTarget) {
8
+ return true;
9
+ }
10
+
11
+ const relative = path.relative(resolvedBase, resolvedTarget);
12
+ return Boolean(relative) && !relative.startsWith("..") && !path.isAbsolute(relative);
13
+ }
14
+
15
+ module.exports = {
16
+ isPathInside
17
+ };
package/lib/utils.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const fs = require("fs");
2
2
  const path = require("path");
3
+ const { isPathInside } = require("./path-inside");
3
4
 
4
5
  const HAS_SYNC_WAIT =
5
6
  typeof SharedArrayBuffer === "function" &&
@@ -36,13 +37,7 @@ function normalizeRelativePath(relativePath) {
36
37
  }
37
38
 
38
39
  function pathWithinRoot(projectRoot, candidatePath) {
39
- const root = path.resolve(projectRoot);
40
- const candidate = path.resolve(candidatePath);
41
- if (candidate === root) {
42
- return true;
43
- }
44
- const prefix = root.endsWith(path.sep) ? root : `${root}${path.sep}`;
45
- return candidate.startsWith(prefix);
40
+ return isPathInside(projectRoot, candidatePath);
46
41
  }
47
42
 
48
43
  function uniqueValues(values) {
@@ -0,0 +1,134 @@
1
+ const { getStageById } = require("./workflow-contract");
2
+ const {
3
+ deriveStageFromArtifacts,
4
+ buildBaseHandoffGates
5
+ } = require("./workflow-stage");
6
+
7
+ /**
8
+ * @typedef {Object} WorkflowFindings
9
+ * @property {string[]} blockers
10
+ * @property {string[]} warnings
11
+ * @property {string[]} notes
12
+ */
13
+
14
+ /**
15
+ * @typedef {Object} WorkflowArtifactState
16
+ * @property {boolean} workflowRootReady
17
+ * @property {boolean} changeSelected
18
+ * @property {boolean} proposal
19
+ * @property {string[]} specFiles
20
+ * @property {boolean} design
21
+ * @property {boolean} pencilDesign
22
+ * @property {boolean} pencilBindings
23
+ * @property {boolean} tasks
24
+ * @property {boolean} verification
25
+ */
26
+
27
+ /**
28
+ * @typedef {Object.<string, string>} WorkflowCheckpointStatusMap
29
+ */
30
+
31
+ /**
32
+ * @typedef {Object} WorkflowCompletionAudit
33
+ * @property {string} [status]
34
+ * @property {string[]} [failures]
35
+ * @property {string[]} [warnings]
36
+ * @property {string[]} [notes]
37
+ */
38
+
39
+ /**
40
+ * @typedef {Object} PersistedWorkflowRecord
41
+ * @property {string} [stage]
42
+ * @property {Object.<string, string>} [gates]
43
+ */
44
+
45
+ /**
46
+ * @typedef {Object} WorkflowBaseView
47
+ * @property {"persisted"|"derived"} source
48
+ * @property {string} stageId
49
+ * @property {WorkflowFindings} findings
50
+ * @property {Object.<string, string>} baseGates
51
+ * @property {WorkflowCompletionAudit | null} completionAudit
52
+ * @property {Array<object>} taskGroupSeed
53
+ */
54
+
55
+ function cloneFindings(findings) {
56
+ return {
57
+ blockers: Array.isArray(findings && findings.blockers) ? findings.blockers.slice() : [],
58
+ warnings: Array.isArray(findings && findings.warnings) ? findings.warnings.slice() : [],
59
+ notes: Array.isArray(findings && findings.notes) ? findings.notes.slice() : []
60
+ };
61
+ }
62
+
63
+ function resolveCompletionAudit(stageId, resolver) {
64
+ if (typeof resolver !== "function") {
65
+ return null;
66
+ }
67
+ return resolver(stageId);
68
+ }
69
+
70
+ /**
71
+ * Normalize a trusted persisted workflow snapshot into the shared base-view shape.
72
+ *
73
+ * @param {{
74
+ * persistedRecord?: PersistedWorkflowRecord,
75
+ * findings?: WorkflowFindings,
76
+ * taskGroupSeed?: Array<object>,
77
+ * resolveCompletionAudit?: (stageId: string) => (WorkflowCompletionAudit | null)
78
+ * }} [options]
79
+ * @returns {WorkflowBaseView}
80
+ */
81
+ function buildPersistedWorkflowBaseView(options = {}) {
82
+ const persistedRecord = options.persistedRecord || {};
83
+ const stage = getStageById(persistedRecord.stage) || getStageById("bootstrap");
84
+
85
+ return {
86
+ source: "persisted",
87
+ stageId: stage.id,
88
+ findings: cloneFindings(options.findings),
89
+ baseGates:
90
+ persistedRecord && persistedRecord.gates && typeof persistedRecord.gates === "object"
91
+ ? { ...persistedRecord.gates }
92
+ : {},
93
+ completionAudit: resolveCompletionAudit(stage.id, options.resolveCompletionAudit),
94
+ taskGroupSeed: Array.isArray(options.taskGroupSeed) ? options.taskGroupSeed : []
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Build the artifact/checkpoint-backed base view before runtime overlays apply.
100
+ *
101
+ * @param {{
102
+ * artifactState?: WorkflowArtifactState,
103
+ * checkpointStatuses?: WorkflowCheckpointStatusMap,
104
+ * findings?: WorkflowFindings,
105
+ * taskGroupSeed?: Array<object>,
106
+ * resolveCompletionAudit?: (stageId: string) => (WorkflowCompletionAudit | null)
107
+ * }} [options]
108
+ * @returns {WorkflowBaseView}
109
+ */
110
+ function buildDerivedWorkflowBaseView(options = {}) {
111
+ const findings = cloneFindings(options.findings);
112
+ const stageId = deriveStageFromArtifacts(
113
+ options.artifactState || {},
114
+ options.checkpointStatuses || {},
115
+ findings
116
+ );
117
+ const completionAudit = resolveCompletionAudit(stageId, options.resolveCompletionAudit);
118
+
119
+ return {
120
+ source: "derived",
121
+ stageId,
122
+ findings,
123
+ baseGates: buildBaseHandoffGates(options.artifactState || {}, options.checkpointStatuses || {}, {
124
+ completionAudit
125
+ }),
126
+ completionAudit,
127
+ taskGroupSeed: Array.isArray(options.taskGroupSeed) ? options.taskGroupSeed : []
128
+ };
129
+ }
130
+
131
+ module.exports = {
132
+ buildPersistedWorkflowBaseView,
133
+ buildDerivedWorkflowBaseView
134
+ };