@crewx/workflow 0.3.22-rc.21 → 0.3.22-rc.210

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 (48) hide show
  1. package/SKILL.md +4 -4
  2. package/dist/cli.d.ts +1 -1
  3. package/dist/cli.js +21 -1012
  4. package/dist/src/card-state.d.ts +20 -0
  5. package/dist/src/card-state.js +1 -0
  6. package/dist/src/engine.d.ts +10 -3
  7. package/dist/src/engine.js +1 -348
  8. package/dist/src/failure.d.ts +41 -0
  9. package/dist/src/failure.js +1 -0
  10. package/dist/src/file-lock.d.ts +1 -1
  11. package/dist/src/file-lock.js +1 -97
  12. package/dist/src/list-view.d.ts +22 -0
  13. package/dist/src/list-view.js +3 -0
  14. package/dist/src/mermaid.d.ts +1 -1
  15. package/dist/src/mermaid.js +2 -133
  16. package/dist/src/parent-task-sync.d.ts +139 -0
  17. package/dist/src/parent-task-sync.js +1 -0
  18. package/dist/src/retry-policy.d.ts +38 -0
  19. package/dist/src/retry-policy.js +1 -0
  20. package/dist/src/run-manager.d.ts +37 -3
  21. package/dist/src/run-manager.js +4 -1228
  22. package/dist/src/types.d.ts +37 -4
  23. package/dist/src/types.js +1 -3
  24. package/dist/src/utils/output-format.d.ts +1 -1
  25. package/dist/src/utils/output-format.js +12 -157
  26. package/dist/src/utils/shell-security.d.ts +1 -1
  27. package/dist/src/utils/shell-security.js +1 -138
  28. package/dist/src/workflow-persistence.d.ts +48 -0
  29. package/dist/src/workflow-persistence.js +1 -0
  30. package/dist/workflow-schema.json +25 -4
  31. package/package.json +23 -4
  32. package/workflow-schema.json +25 -4
  33. package/dist/cli.d.ts.map +0 -1
  34. package/dist/cli.js.map +0 -1
  35. package/dist/src/engine.d.ts.map +0 -1
  36. package/dist/src/engine.js.map +0 -1
  37. package/dist/src/file-lock.d.ts.map +0 -1
  38. package/dist/src/file-lock.js.map +0 -1
  39. package/dist/src/mermaid.d.ts.map +0 -1
  40. package/dist/src/mermaid.js.map +0 -1
  41. package/dist/src/run-manager.d.ts.map +0 -1
  42. package/dist/src/run-manager.js.map +0 -1
  43. package/dist/src/types.d.ts.map +0 -1
  44. package/dist/src/types.js.map +0 -1
  45. package/dist/src/utils/output-format.d.ts.map +0 -1
  46. package/dist/src/utils/output-format.js.map +0 -1
  47. package/dist/src/utils/shell-security.d.ts.map +0 -1
  48. package/dist/src/utils/shell-security.js.map +0 -1
@@ -0,0 +1,20 @@
1
+ import type { NodeType, RunExecution, WorkflowSpec } from './types';
2
+ export type WorkflowApprovalPhase = 'not_started' | 'running' | 'retrying' | 'waiting_approval' | 'paused' | 'completed' | 'failed' | 'cancelled';
3
+ export interface WorkflowApprovalNodeState {
4
+ id: string;
5
+ type: NodeType;
6
+ }
7
+ export interface WorkflowApprovalState {
8
+ phase: WorkflowApprovalPhase;
9
+ status: RunExecution['status'] | null;
10
+ workflowId: string;
11
+ completedCount: number;
12
+ totalNodes: number;
13
+ currentNode: WorkflowApprovalNodeState | null;
14
+ approval: {
15
+ question: string;
16
+ approveNode: WorkflowApprovalNodeState | null;
17
+ } | null;
18
+ }
19
+ export declare function buildWorkflowApprovalState(run: RunExecution, spec: WorkflowSpec): WorkflowApprovalState;
20
+
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.buildWorkflowApprovalState=h;const u="Approval required.";function l(t,e){const r=e.split(".").map(o=>o.trim()).filter(Boolean);let n=t;for(const o of r){if(!n||typeof n!=="object"||!(o in n))return void 0;n=n[o]}return n}function p(t){if(t===void 0||t===null)return"";if(typeof t==="string")return t;if(typeof t==="number"||typeof t==="boolean")return String(t);if(Array.isArray(t)){return t.map(e=>y(e)).filter(Boolean).join(", ")}if(typeof t==="object")return c(t);return String(t)}function y(t){if(!t||typeof t!=="object"||Array.isArray(t)){return p(t)}const e=t;const r=typeof e.name==="string"?e.name:void 0;const n=typeof e.version==="string"?e.version:void 0;const o=typeof e.action==="string"?e.action:void 0;const s=typeof e.reason==="string"?e.reason:void 0;const f=typeof e.path==="string"?e.path:void 0;if(r||f){const i=[r??f,n].filter(Boolean).join("@");const a=[o,s].filter(Boolean).join("; ");return a?`${i} (${a})`:i}return c(e)}function c(t){const e=["status","should_publish","next_version","version","action","reason","message"];const r=e.filter(n=>n in t).map(n=>`${n}=${p(t[n])}`);return r.length>0?r.join(", "):JSON.stringify(t)}function g(t,e){return t.replace(/\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g,(r,n)=>p(l(e,n)))}function _(t){if(typeof t!=="string"||!t.trim())return u;if(/<\/?[A-Za-z][^>]*>/.test(t)||/^(?:https?|file|ftp|ws|wss):\/\//i.test(t)||/^(?:[A-Za-z]:[\\/]|\\\\|~[\\/]|\/)/.test(t)){return u}return t}function d(t,e){return e?{id:t,type:e.type}:null}function m(t){return t==="completed"||t==="failed"||t==="cancelled"}function A(t,e){const r=t.status;if(m(r))return r;if(e?.type==="approval")return"waiting_approval";if(r==="retrying")return"retrying";if(r==="pending"||!t.current_node&&r===void 0)return"not_started";if(e?.type==="parallel")return"paused";return"running"}function h(t,e){const r=e.nodes??{};const n=t.current_node?r[t.current_node]:void 0;const o=d(t.current_node,n);let s=null;if(n?.type==="approval"){const f=typeof n.description==="string"?n.description.trim():"Approving this request will run the next workflow node.";const i=typeof n.on_approve==="string"?n.on_approve:void 0;s={question:_(g(f,t.state)),approveNode:i?d(i,r[i]):null}}return{phase:A(t,n),status:t.status??null,workflowId:t.workflow_id,completedCount:t.completed_nodes?.length??0,totalNodes:Object.keys(r).length,currentNode:o,approval:s}}
@@ -10,6 +10,13 @@ export declare class WorkflowEngine {
10
10
  };
11
11
  toMermaid(spec: WorkflowSpec): string;
12
12
  }
13
- export { RunManager } from './run-manager';
14
- export type { AutoRunResult, RunExecution, WorkflowNode, WorkflowSpec } from './types';
15
- //# sourceMappingURL=engine.d.ts.map
13
+ export { RunManager, WORKFLOW_RUN_INTERRUPTED_ERROR, WORKFLOW_RUN_LEGACY_RECOVERY_GRACE_MS, normalizeRunStatus, } from './run-manager';
14
+ export type { RunManagerDependencies, RunPersistedSink } from './run-manager';
15
+ export { createWorkflowParentPersistSink, deriveWorkflowParentLifecycle, deriveWorkflowParentLifecycleChange, deriveWorkflowParentLifecycleDecision, previewWorkflowParentRepair, reconcileWorkflowParentRunFiles, reconcileWorkflowParentTasks, syncWorkflowParentTaskLifecycle, WORKFLOW_PARENT_ORPHAN_ERROR, WORKFLOW_PARENT_ORPHAN_GRACE_MS, WORKFLOW_PARENT_TASK_KINDS, } from './parent-task-sync';
16
+ export type { ReconcileWorkflowParentTasksOptions, SyncWorkflowParentTaskLifecycleOptions, WorkflowParentPersistSinkOptions, WorkflowParentPersistResult, WorkflowParentPersistTaskRepository, WorkflowParentLifecycle, WorkflowParentLifecycleChange, WorkflowParentLifecycleDecision, WorkflowParentLifecycleDecisionStatus, WorkflowParentLifecycleSnapshot, WorkflowParentRepairPreview, WorkflowParentReconciliationResult, WorkflowParentReconciliationSkipCounts, WorkflowParentReconciliationSkipReason, ReconcileWorkflowParentRunFilesOptions, WorkflowParentWorkspace, WorkflowParentTaskKind, WorkflowParentTaskLookup, WorkflowParentTaskRepository, WorkflowParentTaskRow, WorkflowParentTaskStatus, DeriveWorkflowParentLifecycleChangeOptions, PreviewWorkflowParentRepairOptions, } from './parent-task-sync';
17
+ export { createWorkflowPersistenceProjection, previewWorkflowPersistenceProjection, } from './workflow-persistence';
18
+ export type { WorkflowAuditSnapshotChange, WorkflowAuditSnapshotStore, WorkflowPersistenceProjection, WorkflowPersistenceProjectionOptions, WorkflowPersistenceProjectionResult, WorkflowPersistenceProjectionPreview, WorkflowPersistenceProjectionPreviewOptions, } from './workflow-persistence';
19
+ export type { AutoRunResult, RunExecution, WorkflowAutoRunLease, WorkflowManualResume, WorkflowNode, WorkflowSpec, } from './types';
20
+ export { buildWorkflowApprovalState } from './card-state';
21
+ export type { WorkflowApprovalNodeState, WorkflowApprovalPhase, WorkflowApprovalState, } from './card-state';
22
+
@@ -1,348 +1 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.RunManager = exports.WorkflowEngine = void 0;
37
- const fs = __importStar(require("fs"));
38
- const path = __importStar(require("path"));
39
- const yaml = __importStar(require("js-yaml"));
40
- const mermaid_1 = require("./mermaid");
41
- const shell_security_1 = require("./utils/shell-security");
42
- const run_manager_1 = require("./run-manager");
43
- const NODE_REQUIRED_FIELDS = {
44
- agent_task: ['agent'],
45
- skill_task: ['skill'],
46
- shell_task: ['command'],
47
- parallel: ['branches', 'join'],
48
- join: [],
49
- branch: ['condition', 'branches'],
50
- approval: ['description', 'on_approve', 'on_reject'],
51
- expression: ['set', 'next'],
52
- end: [],
53
- error: [],
54
- };
55
- function resolveRef(ref, root, depth) {
56
- if (depth > 10)
57
- return null;
58
- const parts = ref.replace('#/', '').split('/');
59
- let node = root;
60
- for (const p of parts) {
61
- node = node?.[p];
62
- if (!node)
63
- return null;
64
- }
65
- const schemaNode = node;
66
- if (schemaNode.$ref)
67
- return resolveRef(schemaNode.$ref, root, depth + 1);
68
- return schemaNode;
69
- }
70
- function getJsonType(value) {
71
- if (value === null || value === undefined)
72
- return 'null';
73
- if (Array.isArray(value))
74
- return 'array';
75
- return typeof value;
76
- }
77
- function validateSchema(value, schemaNode, root, jsonPath, errors, depth) {
78
- if (depth > 20 || !schemaNode)
79
- return;
80
- if (schemaNode.$ref) {
81
- const resolved = resolveRef(schemaNode.$ref, root, 0);
82
- if (!resolved) {
83
- errors.push({ path: jsonPath, message: `cannot resolve $ref "${schemaNode.$ref}"` });
84
- return;
85
- }
86
- schemaNode = resolved;
87
- }
88
- if (schemaNode.type) {
89
- const actualType = getJsonType(value);
90
- if (schemaNode.type !== actualType) {
91
- errors.push({ path: jsonPath, message: `expected type "${schemaNode.type}", got "${actualType}"` });
92
- return;
93
- }
94
- }
95
- if (schemaNode.enum) {
96
- if (!schemaNode.enum.includes(value)) {
97
- errors.push({ path: jsonPath, message: `value "${value}" not in enum [${schemaNode.enum.join(', ')}]` });
98
- }
99
- }
100
- if (schemaNode.type === 'object' && typeof value === 'object' && value !== null && !Array.isArray(value)) {
101
- const obj = value;
102
- if (schemaNode.required) {
103
- for (const req of schemaNode.required) {
104
- if (!(req in obj)) {
105
- errors.push({ path: `${jsonPath}.${req}`, message: 'required field missing' });
106
- }
107
- }
108
- }
109
- if (schemaNode.properties) {
110
- for (const [key, propSchema] of Object.entries(schemaNode.properties)) {
111
- if (key in obj) {
112
- validateSchema(obj[key], propSchema, root, `${jsonPath}.${key}`, errors, depth + 1);
113
- }
114
- }
115
- }
116
- if (schemaNode.additionalProperties && typeof schemaNode.additionalProperties === 'object') {
117
- const knownKeys = schemaNode.properties ? Object.keys(schemaNode.properties) : [];
118
- for (const key of Object.keys(obj)) {
119
- if (!knownKeys.includes(key)) {
120
- validateSchema(obj[key], schemaNode.additionalProperties, root, `${jsonPath}.${key}`, errors, depth + 1);
121
- }
122
- }
123
- }
124
- }
125
- if (schemaNode.type === 'array' && Array.isArray(value)) {
126
- if (schemaNode.items) {
127
- value.forEach((item, i) => {
128
- validateSchema(item, schemaNode.items, root, `${jsonPath}[${i}]`, errors, depth + 1);
129
- });
130
- }
131
- }
132
- }
133
- function validateNodeTypeRequirements(nodeId, node, jsonPath, errors) {
134
- const required = NODE_REQUIRED_FIELDS[node.type];
135
- if (!required)
136
- return;
137
- for (const field of required) {
138
- if (!(field in node)) {
139
- errors.push({ path: `${jsonPath}.${field}`, message: `"${node.type}" node requires "${field}" field` });
140
- }
141
- }
142
- if (node.type === 'parallel' && node.branches && !Array.isArray(node.branches)) {
143
- errors.push({ path: `${jsonPath}.branches`, message: '"parallel" node branches must be an array of node IDs' });
144
- }
145
- if (node.type === 'branch' && node.branches && Array.isArray(node.branches)) {
146
- errors.push({ path: `${jsonPath}.branches`, message: '"branch" node branches must be a Record (object), not an array' });
147
- }
148
- if (node.type === 'branch' && typeof node.condition === 'string') {
149
- try {
150
- (0, run_manager_1.validateSafeBranchCondition)(node.condition);
151
- }
152
- catch (error) {
153
- errors.push({ path: `${jsonPath}.condition`, message: `unsafe branch condition: ${error.message}` });
154
- }
155
- }
156
- if (typeof node.fail_when === 'string') {
157
- const taskTypes = ['agent_task', 'skill_task', 'shell_task'];
158
- if (!taskTypes.includes(node.type)) {
159
- errors.push({
160
- path: `${jsonPath}.fail_when`,
161
- message: `"fail_when" is only supported on task nodes (${taskTypes.join(', ')}), not "${node.type}"`,
162
- });
163
- }
164
- else {
165
- try {
166
- (0, run_manager_1.validateSafeBranchCondition)(node.fail_when);
167
- }
168
- catch (error) {
169
- errors.push({ path: `${jsonPath}.fail_when`, message: `unsafe fail_when condition: ${error.message}` });
170
- }
171
- }
172
- }
173
- if (node.type === 'skill_task' && node.skill !== undefined && !shell_security_1.SKILL_NAME_RE.test(node.skill)) {
174
- errors.push({
175
- path: `${jsonPath}.skill`,
176
- message: `skill name "${node.skill}" is invalid (must match ^[a-z0-9][a-z0-9-]*$, no path traversal)`,
177
- });
178
- }
179
- if (node.type === 'shell_task' && node.command !== undefined) {
180
- const check = (0, shell_security_1.validateShellCommand)(node.command);
181
- if (!check.ok) {
182
- errors.push({ path: `${jsonPath}.command`, message: check.error });
183
- }
184
- const envCheck = (0, shell_security_1.validateEnvKeys)(node.env);
185
- if (!envCheck.ok) {
186
- errors.push({ path: `${jsonPath}.env`, message: envCheck.error });
187
- }
188
- }
189
- }
190
- function levenshtein(a, b) {
191
- const m = a.length;
192
- const n = b.length;
193
- const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
194
- for (let i = 0; i <= m; i++)
195
- dp[i][0] = i;
196
- for (let j = 0; j <= n; j++)
197
- dp[0][j] = j;
198
- for (let i = 1; i <= m; i++) {
199
- for (let j = 1; j <= n; j++) {
200
- dp[i][j] = a[i - 1] === b[j - 1]
201
- ? dp[i - 1][j - 1]
202
- : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
203
- }
204
- }
205
- return dp[m][n];
206
- }
207
- function findSimilar(target, candidates) {
208
- let best = null;
209
- let bestScore = Infinity;
210
- for (const c of candidates) {
211
- const score = levenshtein(target, c);
212
- if (score < bestScore && score <= 3) {
213
- bestScore = score;
214
- best = c;
215
- }
216
- }
217
- return best;
218
- }
219
- function validateReferences(wfName, spec, agents, errors) {
220
- const nodes = spec.nodes;
221
- const nodeIds = new Set(Object.keys(nodes));
222
- const prefix = `workflows.${wfName}`;
223
- for (const [nodeId, node] of Object.entries(nodes)) {
224
- const np = `${prefix}.nodes.${nodeId}`;
225
- if (node.next && !nodeIds.has(node.next)) {
226
- errors.push({ path: `${np}.next`, message: `"${node.next}" node not found` });
227
- }
228
- if (node.agent && agents && !agents[node.agent]) {
229
- errors.push({ path: `${np}.agent`, message: `agent "${node.agent}" not found in agents section` });
230
- }
231
- if (node.type === 'parallel' && Array.isArray(node.branches)) {
232
- node.branches.forEach((branchId, i) => {
233
- if (!nodeIds.has(branchId)) {
234
- errors.push({ path: `${np}.branches[${i}]`, message: `"${branchId}" node not found` });
235
- }
236
- });
237
- if (node.join && !nodeIds.has(node.join)) {
238
- errors.push({ path: `${np}.join`, message: `"${node.join}" node not found` });
239
- }
240
- }
241
- if (node.type === 'branch' && node.branches && typeof node.branches === 'object' && !Array.isArray(node.branches)) {
242
- for (const [condVal, targetId] of Object.entries(node.branches)) {
243
- if (!nodeIds.has(targetId)) {
244
- const similar = findSimilar(targetId, nodeIds);
245
- let msg = `"${targetId}" node not found`;
246
- if (similar)
247
- msg += ` (did you mean "${similar}"?)`;
248
- errors.push({ path: `${np}.branches.${condVal}`, message: msg });
249
- }
250
- }
251
- }
252
- if (node.default && !nodeIds.has(node.default)) {
253
- errors.push({ path: `${np}.default`, message: `"${node.default}" node not found` });
254
- }
255
- if (node.type === 'approval') {
256
- if (node.on_approve && !nodeIds.has(node.on_approve)) {
257
- errors.push({ path: `${np}.on_approve`, message: `"${node.on_approve}" node not found` });
258
- }
259
- if (node.on_reject && !nodeIds.has(node.on_reject)) {
260
- errors.push({ path: `${np}.on_reject`, message: `"${node.on_reject}" node not found` });
261
- }
262
- }
263
- if (node.on_error?.fallback_node && !nodeIds.has(node.on_error.fallback_node)) {
264
- errors.push({ path: `${np}.on_error.fallback_node`, message: `"${node.on_error.fallback_node}" node not found` });
265
- }
266
- }
267
- }
268
- class WorkflowEngine {
269
- constructor() {
270
- let schemaPath = path.join(__dirname, '..', 'workflow-schema.json');
271
- if (!fs.existsSync(schemaPath)) {
272
- schemaPath = path.join(__dirname, '..', '..', 'workflow-schema.json');
273
- }
274
- this.schema = JSON.parse(fs.readFileSync(schemaPath, 'utf-8'));
275
- }
276
- loadWorkflows(dir) {
277
- if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
278
- return null;
279
- }
280
- const files = fs.readdirSync(dir).filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
281
- const workflows = [];
282
- for (const file of files) {
283
- const filePath = path.join(dir, file);
284
- try {
285
- const content = fs.readFileSync(filePath, 'utf-8');
286
- const doc = yaml.load(content);
287
- if (!doc?.workflows || typeof doc.workflows !== 'object')
288
- continue;
289
- for (const [id, spec] of Object.entries(doc.workflows)) {
290
- workflows.push({ id, filePath, spec });
291
- }
292
- }
293
- catch {
294
- }
295
- }
296
- return workflows;
297
- }
298
- validateFile(filePath) {
299
- let content;
300
- try {
301
- content = fs.readFileSync(filePath, 'utf-8');
302
- }
303
- catch {
304
- return { success: false, results: [], error: `File not found or unreadable: ${filePath}` };
305
- }
306
- let doc;
307
- try {
308
- doc = yaml.load(content);
309
- }
310
- catch (err) {
311
- const message = err instanceof Error ? err.message : String(err);
312
- return { success: false, results: [], error: `YAML parse error: ${message}` };
313
- }
314
- if (!doc || typeof doc !== 'object') {
315
- return { success: false, results: [], error: 'Invalid YAML: document is empty or not an object' };
316
- }
317
- if (!doc.workflows || typeof doc.workflows !== 'object') {
318
- return { success: true, results: [] };
319
- }
320
- const agents = doc.agents ?? null;
321
- const results = [];
322
- let hasErrors = false;
323
- for (const [wfName, wfSpec] of Object.entries(doc.workflows)) {
324
- const errors = [];
325
- const basePath = `workflows.${wfName}`;
326
- validateSchema(wfSpec, this.schema.definitions['WorkflowSpec'], this.schema, basePath, errors, 0);
327
- if (wfSpec.nodes && typeof wfSpec.nodes === 'object') {
328
- for (const [nodeId, node] of Object.entries(wfSpec.nodes)) {
329
- if (node && typeof node === 'object' && node.type) {
330
- validateNodeTypeRequirements(nodeId, node, `${basePath}.nodes.${nodeId}`, errors);
331
- }
332
- }
333
- }
334
- validateReferences(wfName, wfSpec, agents, errors);
335
- if (errors.length > 0)
336
- hasErrors = true;
337
- results.push({ name: wfName, valid: errors.length === 0, errors });
338
- }
339
- return { success: !hasErrors, results };
340
- }
341
- toMermaid(spec) {
342
- return (0, mermaid_1.toMermaid)(spec);
343
- }
344
- }
345
- exports.WorkflowEngine = WorkflowEngine;
346
- var run_manager_2 = require("./run-manager");
347
- Object.defineProperty(exports, "RunManager", { enumerable: true, get: function () { return run_manager_2.RunManager; } });
348
- //# sourceMappingURL=engine.js.map
1
+ "use strict";var P=exports&&exports.__createBinding||(Object.create?(function(a,e,i,t){if(t===void 0)t=i;var n=Object.getOwnPropertyDescriptor(e,i);if(!n||("get"in n?!e.__esModule:n.writable||n.configurable)){n={enumerable:true,get:function(){return e[i]}}}Object.defineProperty(a,t,n)}):(function(a,e,i,t){if(t===void 0)t=i;a[t]=e[i]}));var W=exports&&exports.__setModuleDefault||(Object.create?(function(a,e){Object.defineProperty(a,"default",{enumerable:true,value:e})}):function(a,e){a["default"]=e});var b=exports&&exports.__importStar||(function(){var a=function(e){a=Object.getOwnPropertyNames||function(i){var t=[];for(var n in i)if(Object.prototype.hasOwnProperty.call(i,n))t[t.length]=n;return t};return a(e)};return function(e){if(e&&e.__esModule)return e;var i={};if(e!=null){for(var t=a(e),n=0;n<t.length;n++)if(t[n]!=="default")P(i,e,t[n])}W(i,e);return i}})();Object.defineProperty(exports,"__esModule",{value:true});exports.buildWorkflowApprovalState=exports.previewWorkflowPersistenceProjection=exports.createWorkflowPersistenceProjection=exports.WORKFLOW_PARENT_TASK_KINDS=exports.WORKFLOW_PARENT_ORPHAN_GRACE_MS=exports.WORKFLOW_PARENT_ORPHAN_ERROR=exports.syncWorkflowParentTaskLifecycle=exports.reconcileWorkflowParentTasks=exports.reconcileWorkflowParentRunFiles=exports.previewWorkflowParentRepair=exports.deriveWorkflowParentLifecycleDecision=exports.deriveWorkflowParentLifecycleChange=exports.deriveWorkflowParentLifecycle=exports.createWorkflowParentPersistSink=exports.normalizeRunStatus=exports.WORKFLOW_RUN_LEGACY_RECOVERY_GRACE_MS=exports.WORKFLOW_RUN_INTERRUPTED_ERROR=exports.RunManager=exports.WorkflowEngine=void 0;const E=require("./list-view");const m=b(require("fs"));const R=b(require("path"));const j=b(require("js-yaml"));const A=require("./mermaid");const g=require("./utils/shell-security");const k=require("./run-manager");const O=require("./retry-policy");const v={agent_task:["agent"],skill_task:["skill"],shell_task:["command"],parallel:["branches","join"],join:[],branch:["condition","branches"],approval:["description","on_approve","on_reject"],expression:["set","next"],end:[],error:[]};function w(a,e,i){if(i>10)return null;const t=a.replace("#/","").split("/");let n=e;for(const s of t){n=n?.[s];if(!n)return null}const r=n;if(r.$ref)return w(r.$ref,e,i+1);return r}function S(a){if(a===null||a===void 0)return"null";if(Array.isArray(a))return"array";return typeof a}function y(a,e,i,t,n,r){if(r>20||!e)return;if(e.$ref){const s=w(e.$ref,i,0);if(!s){n.push({path:t,message:`cannot resolve $ref "${e.$ref}"`});return}e=s}if(e.type){const s=S(a);const f=e.type==="integer"?s==="number"&&Number.isInteger(a):e.type===s;if(!f){n.push({path:t,message:`expected type "${e.type}", got "${s}"`});return}}if(typeof a==="number"){if(e.minimum!==void 0&&a<e.minimum){n.push({path:t,message:`number must be >= ${e.minimum}`})}if(e.maximum!==void 0&&a>e.maximum){n.push({path:t,message:`number must be <= ${e.maximum}`})}}if(e.enum){if(!e.enum.includes(a)){n.push({path:t,message:`value "${a}" not in enum [${e.enum.join(", ")}]`})}}if(e.type==="object"&&typeof a==="object"&&a!==null&&!Array.isArray(a)){const s=a;if(e.required){for(const f of e.required){if(!(f in s)){n.push({path:`${t}.${f}`,message:"required field missing"})}}}if(e.properties){for(const[f,o]of Object.entries(e.properties)){if(f in s){y(s[f],o,i,`${t}.${f}`,n,r+1)}}}if(e.additionalProperties&&typeof e.additionalProperties==="object"){const f=e.properties?Object.keys(e.properties):[];for(const o of Object.keys(s)){if(!f.includes(o)){y(s[o],e.additionalProperties,i,`${t}.${o}`,n,r+1)}}}}if(e.type==="array"&&Array.isArray(a)){if(e.items){a.forEach((s,f)=>{y(s,e.items,i,`${t}[${f}]`,n,r+1)})}}}function L(a,e,i,t){const n=v[e.type];if(!n)return;for(const r of n){if(!(r in e)){t.push({path:`${i}.${r}`,message:`"${e.type}" node requires "${r}" field`})}}if(e.type==="parallel"&&e.branches&&!Array.isArray(e.branches)){t.push({path:`${i}.branches`,message:'"parallel" node branches must be an array of node IDs'})}if(e.type==="branch"&&e.branches&&Array.isArray(e.branches)){t.push({path:`${i}.branches`,message:'"branch" node branches must be a Record (object), not an array'})}if(e.type==="branch"&&typeof e.condition==="string"){try{(0,k.validateSafeBranchCondition)(e.condition)}catch(r){t.push({path:`${i}.condition`,message:`unsafe branch condition: ${r.message}`})}}if(typeof e.fail_when==="string"){const r=["agent_task","skill_task","shell_task"];if(!r.includes(e.type)){t.push({path:`${i}.fail_when`,message:`"fail_when" is only supported on task nodes (${r.join(", ")}), not "${e.type}"`})}else{try{(0,k.validateSafeBranchCondition)(e.fail_when)}catch(s){t.push({path:`${i}.fail_when`,message:`unsafe fail_when condition: ${s.message}`})}}}if(e.retry!==void 0){if(!O.RETRYABLE_NODE_TYPES.includes(e.type)){t.push({path:`${i}.retry`,message:'"retry" is only supported on agent_task, skill_task, and shell_task nodes'})}else{const r=(0,O.parseRetryPolicy)(e);if(!r.ok){const s=`${i}.${r.path}`;if(!t.some(f=>f.path===s)){t.push({path:s,message:r.reason})}}}}if(e.type==="skill_task"&&e.skill!==void 0&&!g.SKILL_NAME_RE.test(e.skill)){t.push({path:`${i}.skill`,message:`skill name "${e.skill}" is invalid (must match ^[a-z0-9][a-z0-9-]*$, no path traversal)`})}if(e.type==="shell_task"&&e.command!==void 0){const r=(0,g.validateShellCommand)(e.command);if(!r.ok){t.push({path:`${i}.command`,message:r.error})}const s=(0,g.validateEnvKeys)(e.env);if(!s.ok){t.push({path:`${i}.env`,message:s.error})}}}function T(a,e){const i=a.length;const t=e.length;const n=Array.from({length:i+1},()=>Array(t+1).fill(0));for(let r=0;r<=i;r++)n[r][0]=r;for(let r=0;r<=t;r++)n[0][r]=r;for(let r=1;r<=i;r++){for(let s=1;s<=t;s++){n[r][s]=a[r-1]===e[s-1]?n[r-1][s-1]:1+Math.min(n[r-1][s],n[r][s-1],n[r-1][s-1])}}return n[i][t]}function K(a,e){let i=null;let t=Infinity;for(const n of e){const r=T(a,n);if(r<t&&r<=3){t=r;i=n}}return i}function F(a,e,i,t){const n=e.nodes;const r=new Set(Object.keys(n));const s=`workflows.${a}`;for(const[f,o]of Object.entries(n)){const c=`${s}.nodes.${f}`;if(o.next&&!r.has(o.next)){t.push({path:`${c}.next`,message:`"${o.next}" node not found`})}if(o.agent&&i&&!i[o.agent]){t.push({path:`${c}.agent`,message:`agent "${o.agent}" not found in agents section`})}if(o.type==="parallel"&&Array.isArray(o.branches)){o.branches.forEach((p,l)=>{if(!r.has(p)){t.push({path:`${c}.branches[${l}]`,message:`"${p}" node not found`})}});if(o.join&&!r.has(o.join)){t.push({path:`${c}.join`,message:`"${o.join}" node not found`})}}if(o.type==="branch"&&o.branches&&typeof o.branches==="object"&&!Array.isArray(o.branches)){for(const[p,l]of Object.entries(o.branches)){if(!r.has(l)){const _=K(l,r);let h=`"${l}" node not found`;if(_)h+=` (did you mean "${_}"?)`;t.push({path:`${c}.branches.${p}`,message:h})}}}if(o.default&&!r.has(o.default)){t.push({path:`${c}.default`,message:`"${o.default}" node not found`})}if(o.type==="approval"){if(o.on_approve&&!r.has(o.on_approve)){t.push({path:`${c}.on_approve`,message:`"${o.on_approve}" node not found`})}if(o.on_reject&&!r.has(o.on_reject)){t.push({path:`${c}.on_reject`,message:`"${o.on_reject}" node not found`})}}if(o.on_error?.fallback_node&&!r.has(o.on_error.fallback_node)){t.push({path:`${c}.on_error.fallback_node`,message:`"${o.on_error.fallback_node}" node not found`})}}}class M{constructor(){let e=R.join(__dirname,"..","workflow-schema.json");if(!m.existsSync(e)){e=R.join(__dirname,"..","..","workflow-schema.json")}this.schema=JSON.parse(m.readFileSync(e,"utf-8"))}loadWorkflows(e){return(0,E.loadWorkflowDirectory)(e)}validateFile(e){let i;try{i=m.readFileSync(e,"utf-8")}catch{return{success:false,results:[],error:`File not found or unreadable: ${e}`}}let t;try{t=j.load(i)}catch(f){const o=f instanceof Error?f.message:String(f);return{success:false,results:[],error:`YAML parse error: ${o}`}}if(!t||typeof t!=="object"){return{success:false,results:[],error:"Invalid YAML: document is empty or not an object"}}if(!t.workflows||typeof t.workflows!=="object"){return{success:true,results:[]}}const n=t.agents??null;const r=[];let s=false;for(const[f,o]of Object.entries(t.workflows)){const c=[];const p=`workflows.${f}`;y(o,this.schema.definitions["WorkflowSpec"],this.schema,p,c,0);if(o.nodes&&typeof o.nodes==="object"){for(const[l,_]of Object.entries(o.nodes)){if(_&&typeof _==="object"&&_.type){L(l,_,`${p}.nodes.${l}`,c)}}}F(f,o,n,c);if(c.length>0)s=true;r.push({name:f,valid:c.length===0,errors:c})}return{success:!s,results:r}}toMermaid(e){return(0,A.toMermaid)(e)}}exports.WorkflowEngine=M;var d=require("./run-manager");Object.defineProperty(exports,"RunManager",{enumerable:true,get:function(){return d.RunManager}});Object.defineProperty(exports,"WORKFLOW_RUN_INTERRUPTED_ERROR",{enumerable:true,get:function(){return d.WORKFLOW_RUN_INTERRUPTED_ERROR}});Object.defineProperty(exports,"WORKFLOW_RUN_LEGACY_RECOVERY_GRACE_MS",{enumerable:true,get:function(){return d.WORKFLOW_RUN_LEGACY_RECOVERY_GRACE_MS}});Object.defineProperty(exports,"normalizeRunStatus",{enumerable:true,get:function(){return d.normalizeRunStatus}});var u=require("./parent-task-sync");Object.defineProperty(exports,"createWorkflowParentPersistSink",{enumerable:true,get:function(){return u.createWorkflowParentPersistSink}});Object.defineProperty(exports,"deriveWorkflowParentLifecycle",{enumerable:true,get:function(){return u.deriveWorkflowParentLifecycle}});Object.defineProperty(exports,"deriveWorkflowParentLifecycleChange",{enumerable:true,get:function(){return u.deriveWorkflowParentLifecycleChange}});Object.defineProperty(exports,"deriveWorkflowParentLifecycleDecision",{enumerable:true,get:function(){return u.deriveWorkflowParentLifecycleDecision}});Object.defineProperty(exports,"previewWorkflowParentRepair",{enumerable:true,get:function(){return u.previewWorkflowParentRepair}});Object.defineProperty(exports,"reconcileWorkflowParentRunFiles",{enumerable:true,get:function(){return u.reconcileWorkflowParentRunFiles}});Object.defineProperty(exports,"reconcileWorkflowParentTasks",{enumerable:true,get:function(){return u.reconcileWorkflowParentTasks}});Object.defineProperty(exports,"syncWorkflowParentTaskLifecycle",{enumerable:true,get:function(){return u.syncWorkflowParentTaskLifecycle}});Object.defineProperty(exports,"WORKFLOW_PARENT_ORPHAN_ERROR",{enumerable:true,get:function(){return u.WORKFLOW_PARENT_ORPHAN_ERROR}});Object.defineProperty(exports,"WORKFLOW_PARENT_ORPHAN_GRACE_MS",{enumerable:true,get:function(){return u.WORKFLOW_PARENT_ORPHAN_GRACE_MS}});Object.defineProperty(exports,"WORKFLOW_PARENT_TASK_KINDS",{enumerable:true,get:function(){return u.WORKFLOW_PARENT_TASK_KINDS}});var $=require("./workflow-persistence");Object.defineProperty(exports,"createWorkflowPersistenceProjection",{enumerable:true,get:function(){return $.createWorkflowPersistenceProjection}});Object.defineProperty(exports,"previewWorkflowPersistenceProjection",{enumerable:true,get:function(){return $.previewWorkflowPersistenceProjection}});var q=require("./card-state");Object.defineProperty(exports,"buildWorkflowApprovalState",{enumerable:true,get:function(){return q.buildWorkflowApprovalState}});
@@ -0,0 +1,41 @@
1
+ import type { RunExecution, WorkflowFailureCode, WorkflowNodeFailure } from './types';
2
+ export type WorkflowErrorOrigin = 'spawn' | 'post_spawn' | 'stdin' | null;
3
+ export interface ProcessFailureMetadata {
4
+ status: number | null;
5
+ timedOut: boolean;
6
+ signal: NodeJS.Signals | null;
7
+ errorOrigin: WorkflowErrorOrigin;
8
+ }
9
+ export type PersistedWorkflowFailureCode = Exclude<WorkflowFailureCode, 'RATE_LIMITED'>;
10
+ export interface WorkflowFailureClassificationInput {
11
+ errorCode?: unknown;
12
+ process?: ProcessFailureMetadata;
13
+ }
14
+ export declare function getStableCauseMessage(code: PersistedWorkflowFailureCode): string;
15
+ export declare function createWorkflowFailureError(code: PersistedWorkflowFailureCode, message: string): Error & {
16
+ code: PersistedWorkflowFailureCode;
17
+ };
18
+ export declare function getWorkflowFailureCode(error: unknown): PersistedWorkflowFailureCode | undefined;
19
+ export declare function classifyWorkflowFailure(input: WorkflowFailureClassificationInput): PersistedWorkflowFailureCode;
20
+ export interface NodeFailureInput {
21
+ failedNode: string;
22
+ attempt: number;
23
+ causeCode: PersistedWorkflowFailureCode;
24
+ exitCode: number | null;
25
+ signal: NodeJS.Signals | null;
26
+ errorOrigin: WorkflowErrorOrigin;
27
+ timedOut?: boolean;
28
+ occurredAt?: string;
29
+ }
30
+ export declare function buildNodeFailure(input: NodeFailureInput): WorkflowNodeFailure;
31
+ export interface EvidenceInput {
32
+ causeCode: PersistedWorkflowFailureCode;
33
+ exitCode: number | null;
34
+ signal: NodeJS.Signals | null;
35
+ errorOrigin: WorkflowErrorOrigin;
36
+ timedOut: boolean;
37
+ }
38
+ export declare function buildEvidencePreview(input: EvidenceInput): string | null;
39
+ export declare function sanitizeLocalRunError(raw: unknown, fallback: string): string;
40
+ export declare function readNodeAttempt(run: RunExecution, nodeId: string): number;
41
+
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.getStableCauseMessage=n;exports.createWorkflowFailureError=d;exports.getWorkflowFailureCode=a;exports.classifyWorkflowFailure=c;exports.buildNodeFailure=N;exports.buildEvidencePreview=i;exports.sanitizeLocalRunError=l;exports.readNodeAttempt=E;const s=require("@crewx/sdk");const o={CLI_UNRESOLVABLE:"CrewX CLI executable could not be resolved.",SPAWN_FAILED:"The node process could not be started.",NODE_TIMEOUT:"The node execution exceeded its timeout.",NODE_EXIT_NONZERO:"The node process exited with a non-zero status.",OUTPUT_INVALID:"The node output did not match the required format.",CONFIG_INVALID:"The workflow node configuration is invalid.",INTERRUPTED:"The node execution was interrupted.",CANCELLED:"The workflow run was cancelled.",UNKNOWN:"The node execution failed."};const u=new Set(Object.keys(o));function n(e){return o[e]}function d(e,r){const t=new Error(r);t.code=e;return t}function a(e){if(!e||typeof e!=="object")return void 0;const r=e.code;return typeof r==="string"&&u.has(r)?r:void 0}function c(e){const r=e.errorCode;if(r==="CLI_UNRESOLVABLE")return"CLI_UNRESOLVABLE";if(r==="CONFIG_INVALID")return"CONFIG_INVALID";if(r==="OUTPUT_INVALID")return"OUTPUT_INVALID";if(r==="CANCELLED")return"CANCELLED";if(r==="INTERRUPTED")return"INTERRUPTED";if(r==="UNKNOWN")return"UNKNOWN";const t=e.process;if(!t)return"UNKNOWN";if(t.errorOrigin==="spawn")return"SPAWN_FAILED";if(t.timedOut)return"NODE_TIMEOUT";if(t.signal!==null)return"INTERRUPTED";if(t.errorOrigin==="post_spawn"||t.errorOrigin==="stdin"){return"UNKNOWN"}if(typeof t.status==="number"&&t.status!==0){return"NODE_EXIT_NONZERO"}return"UNKNOWN"}function N(e){const r=e.causeCode==="NODE_EXIT_NONZERO"&&typeof e.exitCode==="number"?e.exitCode:null;const t=e.causeCode==="INTERRUPTED"?e.signal:null;return{failedNode:e.failedNode,attempt:e.attempt,causeCode:e.causeCode,causeMessage:n(e.causeCode),exitCode:r,evidencePreview:i({causeCode:e.causeCode,exitCode:r,signal:t,errorOrigin:e.errorOrigin,timedOut:e.timedOut??false}),occurredAt:e.occurredAt??new Date().toISOString()}}function i(e){switch(e.causeCode){case"NODE_EXIT_NONZERO":return typeof e.exitCode==="number"?`exit code: ${e.exitCode}`:null;case"NODE_TIMEOUT":return e.timedOut?"timeout":null;case"SPAWN_FAILED":return e.errorOrigin==="spawn"?"origin: spawn":null;case"INTERRUPTED":return e.signal===null?null:`signal: ${e.signal}`;case"UNKNOWN":return e.errorOrigin==="post_spawn"||e.errorOrigin==="stdin"?`origin: ${e.errorOrigin}`:null;default:return null}}function l(e,r){try{return(0,s.redactTechnicalMessage)(e)??r}catch{return r}}function E(e,r){const t=e.node_attempts?.[r];return typeof t==="number"&&Number.isInteger(t)&&t>0?t:1}
@@ -6,4 +6,4 @@ export declare class FileLock {
6
6
  release(): void;
7
7
  private removeIfStale;
8
8
  }
9
- //# sourceMappingURL=file-lock.d.ts.map
9
+
@@ -1,97 +1 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.FileLock = void 0;
37
- const fs = __importStar(require("fs"));
38
- const DEFAULT_TIMEOUT_MS = 10000;
39
- const RETRY_INTERVAL_MS = 50;
40
- const STALE_THRESHOLD_MS = 30000;
41
- class FileLock {
42
- constructor(filePath) {
43
- this.lockDir = filePath + '.lock';
44
- }
45
- acquire(timeoutMs = DEFAULT_TIMEOUT_MS) {
46
- const deadline = Date.now() + timeoutMs;
47
- while (Date.now() < deadline) {
48
- try {
49
- fs.mkdirSync(this.lockDir);
50
- return;
51
- }
52
- catch (e) {
53
- if (e.code !== 'EEXIST')
54
- throw e;
55
- this.removeIfStale();
56
- const until = Date.now() + RETRY_INTERVAL_MS + Math.random() * RETRY_INTERVAL_MS;
57
- while (Date.now() < until) { }
58
- }
59
- }
60
- throw new Error(`FileLock timeout after ${timeoutMs}ms: ${this.lockDir}`);
61
- }
62
- async acquireAsync(timeoutMs = DEFAULT_TIMEOUT_MS) {
63
- const deadline = Date.now() + timeoutMs;
64
- while (Date.now() < deadline) {
65
- try {
66
- fs.mkdirSync(this.lockDir);
67
- return;
68
- }
69
- catch (e) {
70
- if (e.code !== 'EEXIST')
71
- throw e;
72
- this.removeIfStale();
73
- await new Promise(resolve => setTimeout(resolve, RETRY_INTERVAL_MS + Math.random() * RETRY_INTERVAL_MS));
74
- }
75
- }
76
- throw new Error(`FileLock timeout after ${timeoutMs}ms: ${this.lockDir}`);
77
- }
78
- release() {
79
- try {
80
- fs.rmdirSync(this.lockDir);
81
- }
82
- catch {
83
- }
84
- }
85
- removeIfStale() {
86
- try {
87
- const stat = fs.statSync(this.lockDir);
88
- if (Date.now() - stat.mtimeMs > STALE_THRESHOLD_MS) {
89
- fs.rmdirSync(this.lockDir);
90
- }
91
- }
92
- catch {
93
- }
94
- }
95
- }
96
- exports.FileLock = FileLock;
97
- //# sourceMappingURL=file-lock.js.map
1
+ "use strict";var l=exports&&exports.__createBinding||(Object.create?(function(n,e,i,t){if(t===void 0)t=i;var r=Object.getOwnPropertyDescriptor(e,i);if(!r||("get"in r?!e.__esModule:r.writable||r.configurable)){r={enumerable:true,get:function(){return e[i]}}}Object.defineProperty(n,t,r)}):(function(n,e,i,t){if(t===void 0)t=i;n[t]=e[i]}));var u=exports&&exports.__setModuleDefault||(Object.create?(function(n,e){Object.defineProperty(n,"default",{enumerable:true,value:e})}):function(n,e){n["default"]=e});var s=exports&&exports.__importStar||(function(){var n=function(e){n=Object.getOwnPropertyNames||function(i){var t=[];for(var r in i)if(Object.prototype.hasOwnProperty.call(i,r))t[t.length]=r;return t};return n(e)};return function(e){if(e&&e.__esModule)return e;var i={};if(e!=null){for(var t=n(e),r=0;r<t.length;r++)if(t[r]!=="default")l(i,e,t[r])}u(i,e);return i}})();Object.defineProperty(exports,"__esModule",{value:true});exports.FileLock=void 0;const c=s(require("fs"));const a=1e4;const o=50;const f=3e4;class h{constructor(e){this.lockDir=e+".lock"}acquire(e=a){const i=Date.now()+e;while(Date.now()<i){try{c.mkdirSync(this.lockDir);return}catch(t){if(t.code!=="EEXIST")throw t;this.removeIfStale();const r=Date.now()+o+Math.random()*o;while(Date.now()<r){}}}throw new Error(`FileLock timeout after ${e}ms: ${this.lockDir}`)}async acquireAsync(e=a){const i=Date.now()+e;while(Date.now()<i){try{c.mkdirSync(this.lockDir);return}catch(t){if(t.code!=="EEXIST")throw t;this.removeIfStale();await new Promise(r=>setTimeout(r,o+Math.random()*o))}}throw new Error(`FileLock timeout after ${e}ms: ${this.lockDir}`)}release(){try{c.rmdirSync(this.lockDir)}catch{}}removeIfStale(){try{const e=c.statSync(this.lockDir);if(Date.now()-e.mtimeMs>f){c.rmdirSync(this.lockDir)}}catch{}}}exports.FileLock=h;
@@ -0,0 +1,22 @@
1
+ import type { PromptListResolver } from '@crewx/sdk';
2
+ import type { LoadedWorkflow } from './types';
3
+ export declare function loadWorkflowDirectory(dir: string): LoadedWorkflow[] | null;
4
+ export declare function loadWorkflowPaths(paths: string[], cwd: string): LoadedWorkflow[];
5
+ export declare function readWorkflowConfig(configPath: string): {
6
+ paths: string[];
7
+ };
8
+ export declare function readWorkflowList(options: {
9
+ cwd: string;
10
+ env: Record<string, string>;
11
+ configPath?: string;
12
+ }): {
13
+ paths: string[];
14
+ workflows: LoadedWorkflow[];
15
+ };
16
+ export declare function createWorkflowListPromptResolver(configPath?: string): PromptListResolver;
17
+ export declare function formatWorkflowList({ paths, workflows, jsonMode }: {
18
+ paths: string[];
19
+ workflows: LoadedWorkflow[];
20
+ jsonMode: boolean;
21
+ }): string;
22
+
@@ -0,0 +1,3 @@
1
+ "use strict";var v=exports&&exports.__createBinding||(Object.create?(function(r,n,o,e){if(e===void 0)e=o;var t=Object.getOwnPropertyDescriptor(n,o);if(!t||("get"in t?!n.__esModule:t.writable||t.configurable)){t={enumerable:true,get:function(){return n[o]}}}Object.defineProperty(r,e,t)}):(function(r,n,o,e){if(e===void 0)e=o;r[e]=n[o]}));var I=exports&&exports.__setModuleDefault||(Object.create?(function(r,n){Object.defineProperty(r,"default",{enumerable:true,value:n})}):function(r,n){r["default"]=n});var d=exports&&exports.__importStar||(function(){var r=function(n){r=Object.getOwnPropertyNames||function(o){var e=[];for(var t in o)if(Object.prototype.hasOwnProperty.call(o,t))e[e.length]=t;return e};return r(n)};return function(n){if(n&&n.__esModule)return n;var o={};if(n!=null){for(var e=r(n),t=0;t<e.length;t++)if(e[t]!=="default")v(o,n,e[t])}I(o,n);return o}})();Object.defineProperty(exports,"__esModule",{value:true});exports.loadWorkflowDirectory=_;exports.loadWorkflowPaths=p;exports.readWorkflowConfig=y;exports.readWorkflowList=O;exports.createWorkflowListPromptResolver=j;exports.formatWorkflowList=g;const u=d(require("fs"));const f=d(require("path"));const w=d(require("js-yaml"));const h=require("@crewx/knowledge-core");const S=new Set(["GIT_DIR","GIT_WORK_TREE","GIT_COMMON_DIR","GIT_CEILING_DIRECTORIES","GIT_DISCOVERY_ACROSS_FILESYSTEM"]);function W(r){return Object.keys(r).some(n=>S.has(n))}function _(r){if(!u.existsSync(r)||!u.statSync(r).isDirectory()){return null}const n=u.readdirSync(r).filter(e=>e.endsWith(".yaml")||e.endsWith(".yml"));const o=[];for(const e of n){const t=f.join(r,e);try{const s=u.readFileSync(t,"utf-8");const c=w.load(s);if(!c?.workflows||typeof c.workflows!=="object")continue;for(const[i,l]of Object.entries(c.workflows)){o.push({id:i,filePath:t,spec:l})}}catch{}}return o}function p(r,n){const o=[];const e=new Set;for(const t of r){const s=f.resolve(n,t);const c=_(s);if(!c)continue;for(const i of c){if(!e.has(i.id)){e.add(i.id);o.push(i)}}}return o}function y(r){try{const n=u.readFileSync(r,"utf8");const o=w.load(n);const e=o?.settings;const t=e?.workflow??{};return{paths:t.paths??["workflows"]}}catch{return{paths:["workflows"]}}}function O(r){const n=f.resolve(r.cwd,r.env.CREWX_CONFIG??r.configPath??"crewx.yaml");const{paths:o}=y(n);return{paths:o,workflows:p(o,r.cwd)}}function j(r){const n=process.cwd();return(o,e)=>{if(o.length!==3||o[0]!=="crewx"||o[1]!=="workflow"||o[2]!=="list")return void 0;const t=e.cwd===n?r:void 0;if(e.env.CREWX_CONFIG==="")return void 0;if(!e.env.CREWX_CONFIG){if(t&&f.resolve(e.cwd,t)!==f.resolve(e.cwd,"crewx.yaml"))return void 0;if(W(e.env))return void 0;if(!u.existsSync(f.join(e.cwd,".git"))){let s=f.dirname(e.cwd);while(s!==f.dirname(s)){if(u.existsSync(f.join(s,".git")))return void 0;s=f.dirname(s)}}}if(!e.env.CREWX_CONFIG&&!t&&!u.existsSync(f.resolve(e.cwd,"crewx.yaml")))return void 0;return g({...O({...e,configPath:t}),jsonMode:false})+"\n"}}function g({paths:r,workflows:n,jsonMode:o}){const e=[];if(n.length===0){const t=`No workflow YAML files found in: ${r.join(", ")}`;if(o){e.push(JSON.stringify({success:true,message:t,workflows:[]}))}else{e.push(`\u2139\uFE0F ${t}`)}return e.join("\n")}if(o){e.push(JSON.stringify({success:true,workflows:n.map(t=>{const s=t.spec.metadata??{};const c=t.spec.nodes?Object.keys(t.spec.nodes).length:0;return{id:t.id,name:s.name??t.id,description:s.description??"",node_count:c,file:t.filePath}})},null,2))}else{e.push("\u{1F4CB} Workflows");n.forEach((i,l)=>{const a=i.spec.metadata??{};const m=i.spec.nodes?Object.keys(i.spec.nodes).length:0;const C=a.description?`
2
+ \u{1F4DD} ${a.description.trim().split("\n")[0]}`:"";e.push(` ${l+1}. ${i.id} \u2014 ${a.name??i.id} (${m} nodes)
3
+ \u{1F4C1} ${i.filePath}${C}`)});const t={commandId:"workflow.list",params:{},resultIds:n.slice(0,3).map(i=>i.id),resultCount:n.length};const s=(0,h.generateNextActions)(t);const c=(0,h.formatActions)(s);if(c)e.push(c)}return e.join("\n")}
@@ -2,4 +2,4 @@ import type { WorkflowSpec } from './types';
2
2
  export declare function safeNodeId(nodeId: string): string;
3
3
  export declare function escapeMermaidLabel(s: string): string;
4
4
  export declare function toMermaid(spec: WorkflowSpec): string;
5
- //# sourceMappingURL=mermaid.d.ts.map
5
+