@crewx/workflow 0.3.22-rc.22 → 0.3.22-rc.221
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/SKILL.md +15 -4
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +23 -1012
- package/dist/src/cancel-reason.d.ts +4 -0
- package/dist/src/cancel-reason.js +1 -0
- package/dist/src/card-state.d.ts +20 -0
- package/dist/src/card-state.js +1 -0
- package/dist/src/engine.d.ts +14 -3
- package/dist/src/engine.js +1 -348
- package/dist/src/failure.d.ts +41 -0
- package/dist/src/failure.js +1 -0
- package/dist/src/file-lock.d.ts +1 -1
- package/dist/src/file-lock.js +1 -97
- package/dist/src/list-view.d.ts +22 -0
- package/dist/src/list-view.js +3 -0
- package/dist/src/mermaid.d.ts +1 -1
- package/dist/src/mermaid.js +2 -133
- package/dist/src/parent-task-sync.d.ts +142 -0
- package/dist/src/parent-task-sync.js +1 -0
- package/dist/src/retry-policy.d.ts +38 -0
- package/dist/src/retry-policy.js +1 -0
- package/dist/src/run-anchor.d.ts +9 -0
- package/dist/src/run-anchor.js +1 -0
- package/dist/src/run-manager.d.ts +43 -3
- package/dist/src/run-manager.js +4 -1228
- package/dist/src/run-projection.d.ts +30 -0
- package/dist/src/run-projection.js +1 -0
- package/dist/src/types.d.ts +41 -4
- package/dist/src/types.js +1 -3
- package/dist/src/utils/output-format.d.ts +1 -1
- package/dist/src/utils/output-format.js +12 -157
- package/dist/src/utils/shell-security.d.ts +1 -1
- package/dist/src/utils/shell-security.js +1 -138
- package/dist/src/workflow-persistence.d.ts +48 -0
- package/dist/src/workflow-persistence.js +1 -0
- package/dist/workflow-schema.json +29 -4
- package/package.json +23 -4
- package/workflow-schema.json +29 -4
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/src/engine.d.ts.map +0 -1
- package/dist/src/engine.js.map +0 -1
- package/dist/src/file-lock.d.ts.map +0 -1
- package/dist/src/file-lock.js.map +0 -1
- package/dist/src/mermaid.d.ts.map +0 -1
- package/dist/src/mermaid.js.map +0 -1
- package/dist/src/run-manager.d.ts.map +0 -1
- package/dist/src/run-manager.js.map +0 -1
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/types.js.map +0 -1
- package/dist/src/utils/output-format.d.ts.map +0 -1
- package/dist/src/utils/output-format.js.map +0 -1
- package/dist/src/utils/shell-security.d.ts.map +0 -1
- package/dist/src/utils/shell-security.js.map +0 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RunExecution, WorkflowSpec } from './types.js';
|
|
2
|
+
export type RunStepStatus = 'not_started' | 'running' | 'waiting_approval' | 'approved' | 'rejected' | 'completed' | 'failed' | 'stopped';
|
|
3
|
+
export interface RunStepProjection {
|
|
4
|
+
nodeId: string;
|
|
5
|
+
label: string;
|
|
6
|
+
type: string | null;
|
|
7
|
+
status: RunStepStatus;
|
|
8
|
+
isApproval: boolean;
|
|
9
|
+
startedAt: string | null;
|
|
10
|
+
endedAt: string | null;
|
|
11
|
+
durationMs: number | null;
|
|
12
|
+
exitCode: number | null;
|
|
13
|
+
retryCount: number;
|
|
14
|
+
taskIds: string[];
|
|
15
|
+
}
|
|
16
|
+
export type RunStepTaskLookup = (workflowRunId: string, nodeId: string) => readonly string[];
|
|
17
|
+
export interface RunProgressSummary {
|
|
18
|
+
done: number;
|
|
19
|
+
total: number | null;
|
|
20
|
+
current: {
|
|
21
|
+
nodeId: string;
|
|
22
|
+
label: string;
|
|
23
|
+
} | null;
|
|
24
|
+
waitingApproval: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function projectRunSteps(definition: WorkflowSpec | null | undefined, run: RunExecution, options?: {
|
|
27
|
+
findTaskIds?: RunStepTaskLookup;
|
|
28
|
+
}): RunStepProjection[];
|
|
29
|
+
export declare function summarizeRunProgress(definition: WorkflowSpec | null | undefined, run: RunExecution): RunProgressSummary;
|
|
30
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.projectRunSteps=N;exports.summarizeRunProgress=A;const j=require("./cancel-reason.js");const p="approval";const m="retry";function v(e){return e.status??(e.auto_run?"running":"pending")}function g(e){return(0,j.isUserCancelledRun)(e)?"stopped":"failed"}function y(e){return e==="end"||e==="error"}function R(e,t){for(let r=e.length-1;r>=0;r-=1){const n=e[r];if(n.node_id===t&&n.type===p&&n.decision)return n}return void 0}function h(e){let t;for(const r of e){const n=Date.parse(r);if(Number.isFinite(n)&&(!t||n<t.ms))t={value:r,ms:n}}return t?.value??null}function D(e){let t;for(const r of e){const n=Date.parse(r);if(Number.isFinite(n)&&(!t||n>t.ms))t={value:r,ms:n}}return t?.value??null}function O(e,t,r,n){if(n)return n.decision==="reject"?"rejected":"approved";const o=v(r);if(r.current_node===e){if(o==="cancelled")return g(r);if(o==="failed")return"failed";if(o==="completed")return"completed";return"waiting_approval"}if(!r.completed_nodes.includes(e))return"not_started";const c=a=>typeof a==="string"&&(r.completed_nodes.includes(a)||r.current_node===a);if(c(t?.on_approve))return"approved";if(c(t?.on_reject))return"rejected";return"completed"}function P(e,t,r){const n=v(t);const o=t.auto_run?.node_id||t.current_node;if(n==="cancelled"&&o===e&&!t.completed_nodes.includes(e)){return g(t)}if(t.completed_nodes.includes(e))return"completed";if(t.current_node===e){if(n==="running"||n==="retrying")return"running";if(n==="failed")return"failed";if(n==="completed")return"completed";return"not_started"}const c=r.at(-1);if(c)return c.error?"failed":"completed";return"not_started"}function T(e,t,r,n,o){const c=n.filter(d=>d.node_id===e&&d.type!==m&&d.type!==p);const a=R(n,e);const s=t?.type==="approval"||a!==void 0;const i=t?.type??(s?p:null);const l=s?a?.decided_at??null:h(c.map(d=>d.started_at));const u=s?a?.decided_at??null:D(c.map(d=>d.ended_at));const f=l?Date.parse(l):NaN;const _=u?Date.parse(u):NaN;const S=Number.isFinite(f)&&Number.isFinite(_)?Math.max(0,_-f):null;return{nodeId:e,label:t?.label??e,type:i,status:s?O(e,t,r,a):P(e,r,c),isApproval:s,startedAt:l,endedAt:u,durationMs:S,exitCode:s?null:c.at(-1)?.exit_code??null,retryCount:n.filter(d=>d.node_id===e&&d.type===m).length,taskIds:o?[...o(r.id,e)]:[]}}function b(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function w(e,t){const r=new Set;const n=[...e.completed_nodes,e.current_node,e.auto_run?.node_id,...(e.audit??[]).map(o=>o.node_id)];for(const o of n){if(o&&!b(t,o))r.add(o)}return[...r]}function N(e,t,r={}){const n=e?.nodes??{};const o=t.audit??[];const c=Object.keys(n);const a=[...c,...w(t,n)];return a.map(s=>T(s,b(n,s)?n[s]:void 0,t,o,r.findTaskIds))}function A(e,t){const r=N(e,t);const n=s=>s==="completed"||s==="approved"||s==="rejected";let o;let c;if(e){const s=Object.keys(e.nodes).filter(l=>!y(e.nodes[l]?.type));const i=new Map(r.map(l=>[l.nodeId,l]));o=s.filter(l=>{const u=i.get(l);return u!==void 0&&n(u.status)}).length;c=s.length}else{const s=r.filter(i=>!y(i.type));o=s.filter(i=>n(i.status)).length;c=null}const a=t.current_node?r.find(s=>s.nodeId===t.current_node):void 0;return{done:o,total:c,current:a?{nodeId:a.nodeId,label:a.label}:null,waitingApproval:r.some(s=>s.status==="waiting_approval")}}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export interface RetryConfig {
|
|
|
8
8
|
max: number;
|
|
9
9
|
delay: 'exponential' | 'fixed';
|
|
10
10
|
max_delay?: number;
|
|
11
|
-
on?:
|
|
11
|
+
on?: WorkflowFailureCode[];
|
|
12
12
|
}
|
|
13
13
|
export interface OnError {
|
|
14
14
|
handler?: string;
|
|
@@ -26,6 +26,7 @@ export interface WorkflowNode {
|
|
|
26
26
|
command?: string[];
|
|
27
27
|
cwd?: string;
|
|
28
28
|
env?: Record<string, string>;
|
|
29
|
+
stdin?: string;
|
|
29
30
|
output?: string;
|
|
30
31
|
output_format?: 'json';
|
|
31
32
|
output_schema?: JsonSchema;
|
|
@@ -40,6 +41,7 @@ export interface WorkflowNode {
|
|
|
40
41
|
default?: string;
|
|
41
42
|
join?: string;
|
|
42
43
|
on_failure?: 'fail_fast' | 'continue' | 'ignore';
|
|
44
|
+
label?: string;
|
|
43
45
|
description?: string;
|
|
44
46
|
assignee?: string;
|
|
45
47
|
timeout?: number;
|
|
@@ -79,7 +81,7 @@ export interface ValidationResult {
|
|
|
79
81
|
export interface AuditEntry {
|
|
80
82
|
exec_id: string;
|
|
81
83
|
node_id: string;
|
|
82
|
-
type: NodeType | string;
|
|
84
|
+
type: NodeType | 'retry' | string;
|
|
83
85
|
summary: string;
|
|
84
86
|
started_at: string;
|
|
85
87
|
ended_at: string;
|
|
@@ -87,6 +89,36 @@ export interface AuditEntry {
|
|
|
87
89
|
exit_code: number | null;
|
|
88
90
|
error?: string;
|
|
89
91
|
trigger: 'manual' | 'auto';
|
|
92
|
+
decision?: 'approve' | 'reject';
|
|
93
|
+
decided_at?: string;
|
|
94
|
+
actor?: string;
|
|
95
|
+
}
|
|
96
|
+
export interface WorkflowAutoRunLease {
|
|
97
|
+
pid: number;
|
|
98
|
+
token: string;
|
|
99
|
+
node_id: string;
|
|
100
|
+
started_at: string;
|
|
101
|
+
}
|
|
102
|
+
export interface WorkflowManualResume {
|
|
103
|
+
node_id: string;
|
|
104
|
+
requested_at: string;
|
|
105
|
+
}
|
|
106
|
+
export type WorkflowFailureCode = 'CLI_UNRESOLVABLE' | 'SPAWN_FAILED' | 'NODE_TIMEOUT' | 'NODE_EXIT_NONZERO' | 'OUTPUT_INVALID' | 'RATE_LIMITED' | 'CONFIG_INVALID' | 'INTERRUPTED' | 'CANCELLED' | 'UNKNOWN';
|
|
107
|
+
export interface RetryPolicy {
|
|
108
|
+
max: number;
|
|
109
|
+
delay: 'exponential' | 'fixed';
|
|
110
|
+
max_delay: number;
|
|
111
|
+
on: WorkflowFailureCode[];
|
|
112
|
+
}
|
|
113
|
+
export declare const NEVER_RETRYABLE: readonly WorkflowFailureCode[];
|
|
114
|
+
export interface WorkflowNodeFailure {
|
|
115
|
+
failedNode: string;
|
|
116
|
+
attempt: number;
|
|
117
|
+
causeCode: WorkflowFailureCode;
|
|
118
|
+
causeMessage: string;
|
|
119
|
+
exitCode: number | null;
|
|
120
|
+
evidencePreview: string | null;
|
|
121
|
+
occurredAt: string;
|
|
90
122
|
}
|
|
91
123
|
export interface RunExecution {
|
|
92
124
|
id: string;
|
|
@@ -98,10 +130,15 @@ export interface RunExecution {
|
|
|
98
130
|
completed_nodes: string[];
|
|
99
131
|
state: Record<string, unknown>;
|
|
100
132
|
initial_state: Record<string, unknown>;
|
|
101
|
-
status?: 'running' | 'completed' | 'failed' | 'cancelled';
|
|
133
|
+
status?: 'pending' | 'running' | 'retrying' | 'completed' | 'failed' | 'cancelled';
|
|
102
134
|
tasks?: Record<string, string>;
|
|
103
135
|
error?: string;
|
|
136
|
+
last_failure?: WorkflowNodeFailure;
|
|
104
137
|
audit?: AuditEntry[];
|
|
138
|
+
retry_count?: number;
|
|
139
|
+
node_attempts?: Record<string, number>;
|
|
140
|
+
auto_run?: WorkflowAutoRunLease;
|
|
141
|
+
manual_resume?: WorkflowManualResume;
|
|
105
142
|
}
|
|
106
143
|
export interface AutoRunResult {
|
|
107
144
|
run: RunExecution;
|
|
@@ -109,4 +146,4 @@ export interface AutoRunResult {
|
|
|
109
146
|
reason?: string;
|
|
110
147
|
executed: string[];
|
|
111
148
|
}
|
|
112
|
-
|
|
149
|
+
|
package/dist/src/types.js
CHANGED
|
@@ -15,4 +15,4 @@ export declare function buildJsonOutputSuffix(schema?: JsonSchema, strict?: bool
|
|
|
15
15
|
export declare function extractJson(text: string): string;
|
|
16
16
|
export declare function validateJsonSchema(value: unknown, schema: JsonSchema): Promise<void>;
|
|
17
17
|
export declare function toOpenAIStrictSchema(schema: JsonSchema): JsonSchema;
|
|
18
|
-
|
|
18
|
+
|
|
@@ -1,53 +1,8 @@
|
|
|
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.WORKFLOW_SIGNAL_KEY = void 0;
|
|
37
|
-
exports.buildWorkflowPreamble = buildWorkflowPreamble;
|
|
38
|
-
exports.detectWorkflowSignal = detectWorkflowSignal;
|
|
39
|
-
exports.buildJsonOutputSuffix = buildJsonOutputSuffix;
|
|
40
|
-
exports.extractJson = extractJson;
|
|
41
|
-
exports.validateJsonSchema = validateJsonSchema;
|
|
42
|
-
exports.toOpenAIStrictSchema = toOpenAIStrictSchema;
|
|
43
|
-
const node_crypto_1 = require("node:crypto");
|
|
44
|
-
exports.WORKFLOW_SIGNAL_KEY = 'workflow_signal';
|
|
45
|
-
function buildWorkflowPreamble(ctx) {
|
|
46
|
-
return `<crewx.workflow>
|
|
1
|
+
"use strict";var y=exports&&exports.__createBinding||(Object.create?(function(n,e,r,t){if(t===void 0)t=r;var o=Object.getOwnPropertyDescriptor(e,r);if(!o||("get"in o?!e.__esModule:o.writable||o.configurable)){o={enumerable:true,get:function(){return e[r]}}}Object.defineProperty(n,t,o)}):(function(n,e,r,t){if(t===void 0)t=r;n[t]=e[r]}));var _=exports&&exports.__setModuleDefault||(Object.create?(function(n,e){Object.defineProperty(n,"default",{enumerable:true,value:e})}):function(n,e){n["default"]=e});var v=exports&&exports.__importStar||(function(){var n=function(e){n=Object.getOwnPropertyNames||function(r){var t=[];for(var o in r)if(Object.prototype.hasOwnProperty.call(r,o))t[t.length]=o;return t};return n(e)};return function(e){if(e&&e.__esModule)return e;var r={};if(e!=null){for(var t=n(e),o=0;o<t.length;o++)if(t[o]!=="default")y(r,e,t[o])}_(r,e);return r}})();Object.defineProperty(exports,"__esModule",{value:true});exports.WORKFLOW_SIGNAL_KEY=void 0;exports.buildWorkflowPreamble=j;exports.detectWorkflowSignal=E;exports.buildJsonOutputSuffix=P;exports.extractJson=O;exports.validateJsonSchema=W;exports.toOpenAIStrictSchema=S;const N=require("node:crypto");exports.WORKFLOW_SIGNAL_KEY="workflow_signal";function j(n){return`<crewx.workflow>
|
|
47
2
|
## Execution Context
|
|
48
|
-
You are running headless as node "${
|
|
3
|
+
You are running headless as node "${n.nodeId}" of workflow "${n.workflowId}" (run ${n.execId}).
|
|
49
4
|
- No human is watching this session. NEVER ask clarifying questions or wait for
|
|
50
|
-
confirmation
|
|
5
|
+
confirmation \u2014 state your assumptions and proceed, or report failure.
|
|
51
6
|
- Your output is consumed verbatim by downstream nodes. Output the result only;
|
|
52
7
|
skip greetings, progress notes, and meta commentary.
|
|
53
8
|
- If the task cannot be completed (broken precondition, missing data, failed
|
|
@@ -57,118 +12,18 @@ You are running headless as node "${ctx.nodeId}" of workflow "${ctx.workflowId}"
|
|
|
57
12
|
The engine will halt the workflow at this node and record the reason.
|
|
58
13
|
</crewx.workflow>
|
|
59
14
|
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed) &&
|
|
67
|
-
parsed[exports.WORKFLOW_SIGNAL_KEY] === 'fail') {
|
|
68
|
-
const reason = parsed['reason'];
|
|
69
|
-
return { signal: 'fail', ...(typeof reason === 'string' && reason ? { reason } : {}) };
|
|
70
|
-
}
|
|
71
|
-
return null;
|
|
72
|
-
};
|
|
73
|
-
try {
|
|
74
|
-
const signal = toSignal(JSON.parse(extractJson(output)));
|
|
75
|
-
if (signal)
|
|
76
|
-
return signal;
|
|
77
|
-
}
|
|
78
|
-
catch { }
|
|
79
|
-
const inline = output.match(new RegExp(`\\{[^{}]*"${exports.WORKFLOW_SIGNAL_KEY}"\\s*:\\s*"fail"[^{}]*\\}`));
|
|
80
|
-
if (inline) {
|
|
81
|
-
try {
|
|
82
|
-
return toSignal(JSON.parse(inline[0]));
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return { signal: 'fail' };
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
function buildJsonOutputSuffix(schema, strict = false) {
|
|
91
|
-
const finalSchema = strict && schema ? toOpenAIStrictSchema(schema) : schema;
|
|
92
|
-
const schemaStr = finalSchema ? `JSON Schema:\n${JSON.stringify(finalSchema, null, 2)}\n` : '';
|
|
93
|
-
return `\n\n<crewx.workflow>
|
|
94
|
-
## ⚠️ Output Format (read first — drives branch evaluation)
|
|
15
|
+
`}function E(n){if(!n.includes(`"${exports.WORKFLOW_SIGNAL_KEY}"`))return null;const e=t=>{if(typeof t==="object"&&t!==null&&!Array.isArray(t)&&t[exports.WORKFLOW_SIGNAL_KEY]==="fail"){const o=t["reason"];return{signal:"fail",...typeof o==="string"&&o?{reason:o}:{}}}return null};try{const t=e(JSON.parse(O(n)));if(t)return t}catch{}const r=n.match(new RegExp(`\\{[^{}]*"${exports.WORKFLOW_SIGNAL_KEY}"\\s*:\\s*"fail"[^{}]*\\}`));if(r){try{return e(JSON.parse(r[0]))}catch{return{signal:"fail"}}}return null}function P(n,e=false){const r=e&&n?S(n):n;const t=r?`JSON Schema:
|
|
16
|
+
${JSON.stringify(r,null,2)}
|
|
17
|
+
`:"";return`
|
|
18
|
+
|
|
19
|
+
<crewx.workflow>
|
|
20
|
+
## \u26A0\uFE0F Output Format (read first \u2014 drives branch evaluation)
|
|
95
21
|
|
|
96
22
|
**The first character of your output MUST be \`{\`. The last character MUST be \`}\`.**
|
|
97
23
|
No other text is permitted (no explanations, greetings, progress notes, or analysis remarks).
|
|
98
24
|
**NEVER use markdown code fences (\`\`\`json ... \`\`\`).** Do not output even a single backtick.
|
|
99
|
-
Branch evaluation calls \`JSON.parse(state.<output>)\` directly
|
|
25
|
+
Branch evaluation calls \`JSON.parse(state.<output>)\` directly \u2014
|
|
100
26
|
even one non-JSON character at start or end will halt the workflow.
|
|
101
27
|
|
|
102
|
-
${
|
|
103
|
-
</crewx.workflow
|
|
104
|
-
}
|
|
105
|
-
function extractJson(text) {
|
|
106
|
-
let trimmed = text.trim();
|
|
107
|
-
const fenceMatch = trimmed.match(/^```(?:json|JSON)?\s*\n?([\s\S]*?)\n?```\s*$/);
|
|
108
|
-
if (fenceMatch && fenceMatch[1] !== undefined) {
|
|
109
|
-
trimmed = fenceMatch[1].trim();
|
|
110
|
-
}
|
|
111
|
-
const objMatch = trimmed.match(/\{[\s\S]*\}/);
|
|
112
|
-
const arrMatch = trimmed.match(/\[[\s\S]*\]/);
|
|
113
|
-
if (objMatch && arrMatch) {
|
|
114
|
-
return objMatch.index < arrMatch.index ? objMatch[0] : arrMatch[0];
|
|
115
|
-
}
|
|
116
|
-
return objMatch?.[0] ?? arrMatch?.[0] ?? trimmed;
|
|
117
|
-
}
|
|
118
|
-
async function validateJsonSchema(value, schema) {
|
|
119
|
-
const { registerSchema, validate } = await Promise.resolve().then(() => __importStar(require('@hyperjump/json-schema/draft-2020-12')));
|
|
120
|
-
const uri = `urn:crewx:schema:${(0, node_crypto_1.randomUUID)()}`;
|
|
121
|
-
registerSchema({ $schema: 'https://json-schema.org/draft/2020-12/schema', ...schema }, uri);
|
|
122
|
-
const result = await validate(uri, value);
|
|
123
|
-
if (!result.valid) {
|
|
124
|
-
const errors = (result.errors ?? [])
|
|
125
|
-
.map((e) => e.instanceLocation)
|
|
126
|
-
.join('; ');
|
|
127
|
-
throw new Error(`Schema validation failed: ${errors || 'unknown error'}`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
function toOpenAIStrictSchema(schema) {
|
|
131
|
-
return transformStrict(schema);
|
|
132
|
-
}
|
|
133
|
-
const OPENAI_UNSUPPORTED_KEYWORDS = new Set([
|
|
134
|
-
'default', 'format', 'pattern', 'minLength', 'maxLength',
|
|
135
|
-
'minimum', 'maximum', 'not',
|
|
136
|
-
]);
|
|
137
|
-
function transformStrict(schema) {
|
|
138
|
-
const result = {};
|
|
139
|
-
for (const [key, value] of Object.entries(schema)) {
|
|
140
|
-
if (OPENAI_UNSUPPORTED_KEYWORDS.has(key))
|
|
141
|
-
continue;
|
|
142
|
-
if (key === 'properties' && isRecord(value)) {
|
|
143
|
-
const transformed = {};
|
|
144
|
-
for (const [propKey, propVal] of Object.entries(value)) {
|
|
145
|
-
transformed[propKey] = transformStrict(propVal);
|
|
146
|
-
}
|
|
147
|
-
result['properties'] = transformed;
|
|
148
|
-
result['required'] = Object.keys(transformed);
|
|
149
|
-
result['additionalProperties'] = false;
|
|
150
|
-
}
|
|
151
|
-
else if (key === 'items' && isRecord(value)) {
|
|
152
|
-
result['items'] = transformStrict(value);
|
|
153
|
-
}
|
|
154
|
-
else if (key === 'required') {
|
|
155
|
-
if (!('properties' in schema)) {
|
|
156
|
-
result['required'] = value;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
else if (key === 'additionalProperties') {
|
|
160
|
-
result['additionalProperties'] = false;
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
result[key] = value;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
if (result['type'] === 'object' && !('additionalProperties' in result)) {
|
|
167
|
-
result['additionalProperties'] = false;
|
|
168
|
-
}
|
|
169
|
-
return result;
|
|
170
|
-
}
|
|
171
|
-
function isRecord(val) {
|
|
172
|
-
return typeof val === 'object' && val !== null && !Array.isArray(val);
|
|
173
|
-
}
|
|
174
|
-
//# sourceMappingURL=output-format.js.map
|
|
28
|
+
${t}Execute the task, then output **exactly one JSON object** matching the schema above. Nothing else.
|
|
29
|
+
</crewx.workflow>`}function O(n){let e=n.trim();const r=e.match(/^```(?:json|JSON)?\s*\n?([\s\S]*?)\n?```\s*$/);if(r&&r[1]!==void 0){e=r[1].trim()}const t=(i,d,b)=>{const w=[];let h=false;let p=false;let l=0;let u=-1;for(let s=0;s<i.length;s++){const f=i[s];if(p){p=false;continue}if(h){if(f==="\\"){p=true;continue}if(f==='"'){h=false}continue}if(f==='"'){h=true;continue}if(f===d){if(l===0)u=s;l++}else if(f===b){if(l>0){l--;if(l===0&&u!==-1){w.push({text:i.slice(u,s+1),start:u,end:s});u=-1}}}}return w};const o=t(e,"{","}");const a=t(e,"[","]");const c=[...o,...a].sort((i,d)=>d.end-i.end);for(const i of c){try{JSON.parse(i.text);return i.text}catch{}}return e}async function W(n,e){const{registerSchema:r,validate:t}=await Promise.resolve().then(()=>v(require("@hyperjump/json-schema/draft-2020-12")));const o=`urn:crewx:schema:${(0,N.randomUUID)()}`;r({$schema:"https://json-schema.org/draft/2020-12/schema",...e},o);const a=await t(o,n);if(!a.valid){const c=(a.errors??[]).map(i=>i.instanceLocation).join("; ");throw new Error(`Schema validation failed: ${c||"unknown error"}`)}}function S(n){return m(n)}const J=new Set(["default","format","pattern","minLength","maxLength","minimum","maximum","not"]);function m(n){const e={};for(const[r,t]of Object.entries(n)){if(J.has(r))continue;if(r==="properties"&&g(t)){const o={};for(const[a,c]of Object.entries(t)){o[a]=m(c)}e["properties"]=o;e["required"]=Object.keys(o);e["additionalProperties"]=false}else if(r==="items"&&g(t)){e["items"]=m(t)}else if(r==="required"){if(!("properties"in n)){e["required"]=t}}else if(r==="additionalProperties"){e["additionalProperties"]=false}else{e[r]=t}}if(e["type"]==="object"&&!("additionalProperties"in e)){e["additionalProperties"]=false}return e}function g(n){return typeof n==="object"&&n!==null&&!Array.isArray(n)}
|
|
@@ -15,4 +15,4 @@ export interface CwdCheck {
|
|
|
15
15
|
}
|
|
16
16
|
export declare function normalizeCwd(cwd: string | undefined, projectRoot: string): CwdCheck;
|
|
17
17
|
export declare function buildShellEnv(nodeEnv: Record<string, string> | undefined, parentEnv?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
18
|
-
|
|
18
|
+
|
|
@@ -1,138 +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.DANGEROUS_ENV_KEYS = exports.INLINE_CODE_INTERPRETERS = exports.SHELL_DENYLIST = exports.SKILL_NAME_RE = void 0;
|
|
37
|
-
exports.validateShellCommand = validateShellCommand;
|
|
38
|
-
exports.validateEnvKeys = validateEnvKeys;
|
|
39
|
-
exports.normalizeCwd = normalizeCwd;
|
|
40
|
-
exports.buildShellEnv = buildShellEnv;
|
|
41
|
-
const path = __importStar(require("path"));
|
|
42
|
-
const fs = __importStar(require("fs"));
|
|
43
|
-
exports.SKILL_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
44
|
-
exports.SHELL_DENYLIST = new Set([
|
|
45
|
-
'bash', 'sh', 'zsh', 'dash', 'fish',
|
|
46
|
-
'cmd', 'cmd.exe', 'powershell', 'powershell.exe', 'pwsh', 'pwsh.exe',
|
|
47
|
-
]);
|
|
48
|
-
exports.INLINE_CODE_INTERPRETERS = new Set([
|
|
49
|
-
'python', 'python3', 'node', 'nodejs', 'deno', 'perl', 'ruby', 'php',
|
|
50
|
-
]);
|
|
51
|
-
const INLINE_CODE_FLAGS = new Set(['-c', '-e', '--eval', '--exec']);
|
|
52
|
-
exports.DANGEROUS_ENV_KEYS = new Set([
|
|
53
|
-
'LD_PRELOAD', 'LD_LIBRARY_PATH', 'LD_AUDIT',
|
|
54
|
-
'DYLD_INSERT_LIBRARIES', 'DYLD_LIBRARY_PATH', 'DYLD_FRAMEWORK_PATH',
|
|
55
|
-
'NODE_OPTIONS',
|
|
56
|
-
]);
|
|
57
|
-
function baseName(cmd) {
|
|
58
|
-
return path.basename(cmd).toLowerCase();
|
|
59
|
-
}
|
|
60
|
-
function validateShellCommand(command) {
|
|
61
|
-
if (!Array.isArray(command)) {
|
|
62
|
-
return { ok: false, error: 'shell_task.command must be an array of strings (argv), not a string' };
|
|
63
|
-
}
|
|
64
|
-
if (command.length === 0) {
|
|
65
|
-
return { ok: false, error: 'shell_task.command must not be empty' };
|
|
66
|
-
}
|
|
67
|
-
if (!command.every((c) => typeof c === 'string')) {
|
|
68
|
-
return { ok: false, error: 'shell_task.command must contain only strings' };
|
|
69
|
-
}
|
|
70
|
-
const bin = baseName(command[0]);
|
|
71
|
-
const binNoExt = bin.replace(/\.exe$/, '');
|
|
72
|
-
if (exports.SHELL_DENYLIST.has(bin) || exports.SHELL_DENYLIST.has(binNoExt)) {
|
|
73
|
-
return { ok: false, error: `shell_task.command[0] "${command[0]}" is a blocked shell interpreter` };
|
|
74
|
-
}
|
|
75
|
-
if (exports.INLINE_CODE_INTERPRETERS.has(binNoExt)) {
|
|
76
|
-
const hasInlineFlag = command
|
|
77
|
-
.slice(1)
|
|
78
|
-
.some((arg) => INLINE_CODE_FLAGS.has(String(arg)));
|
|
79
|
-
if (hasInlineFlag) {
|
|
80
|
-
return {
|
|
81
|
-
ok: false,
|
|
82
|
-
error: `shell_task.command "${binNoExt} ${command[1]}" uses an inline-code flag (escape vector blocked)`,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return { ok: true };
|
|
87
|
-
}
|
|
88
|
-
function validateEnvKeys(env) {
|
|
89
|
-
if (!env)
|
|
90
|
-
return { ok: true };
|
|
91
|
-
for (const key of Object.keys(env)) {
|
|
92
|
-
if (exports.DANGEROUS_ENV_KEYS.has(key)) {
|
|
93
|
-
return { ok: false, error: `shell_task.env key "${key}" is not allowed` };
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return { ok: true };
|
|
97
|
-
}
|
|
98
|
-
function normalizeCwd(cwd, projectRoot) {
|
|
99
|
-
let root;
|
|
100
|
-
try {
|
|
101
|
-
root = fs.realpathSync(projectRoot);
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
return { ok: false, error: `project root "${projectRoot}" is not accessible: ${error.message}` };
|
|
105
|
-
}
|
|
106
|
-
if (cwd === undefined || cwd === '') {
|
|
107
|
-
return { ok: true, resolved: root };
|
|
108
|
-
}
|
|
109
|
-
const candidate = path.resolve(root, cwd);
|
|
110
|
-
let resolved;
|
|
111
|
-
try {
|
|
112
|
-
resolved = fs.realpathSync(candidate);
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
return { ok: false, error: `cwd "${cwd}" is not accessible: ${error.message}` };
|
|
116
|
-
}
|
|
117
|
-
if (resolved !== root && !resolved.startsWith(root + path.sep)) {
|
|
118
|
-
return { ok: false, error: `cwd "${cwd}" resolves outside the project root` };
|
|
119
|
-
}
|
|
120
|
-
return { ok: true, resolved };
|
|
121
|
-
}
|
|
122
|
-
function buildShellEnv(nodeEnv, parentEnv = process.env) {
|
|
123
|
-
const allowlist = process.platform === 'win32'
|
|
124
|
-
? ['PATH', 'Path', 'SystemRoot', 'COMSPEC', 'TEMP', 'TMP']
|
|
125
|
-
: ['PATH', 'HOME', 'LANG', 'TMPDIR'];
|
|
126
|
-
const env = {};
|
|
127
|
-
for (const key of allowlist) {
|
|
128
|
-
if (parentEnv[key] !== undefined)
|
|
129
|
-
env[key] = parentEnv[key];
|
|
130
|
-
}
|
|
131
|
-
if (nodeEnv) {
|
|
132
|
-
for (const [key, value] of Object.entries(nodeEnv)) {
|
|
133
|
-
env[key] = value;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return env;
|
|
137
|
-
}
|
|
138
|
-
//# sourceMappingURL=shell-security.js.map
|
|
1
|
+
"use strict";var u=exports&&exports.__createBinding||(Object.create?(function(e,r,n,s){if(s===void 0)s=n;var t=Object.getOwnPropertyDescriptor(r,n);if(!t||("get"in t?!r.__esModule:t.writable||t.configurable)){t={enumerable:true,get:function(){return r[n]}}}Object.defineProperty(e,s,t)}):(function(e,r,n,s){if(s===void 0)s=n;e[s]=r[n]}));var f=exports&&exports.__setModuleDefault||(Object.create?(function(e,r){Object.defineProperty(e,"default",{enumerable:true,value:r})}):function(e,r){e["default"]=r});var l=exports&&exports.__importStar||(function(){var e=function(r){e=Object.getOwnPropertyNames||function(n){var s=[];for(var t in n)if(Object.prototype.hasOwnProperty.call(n,t))s[s.length]=t;return s};return e(r)};return function(r){if(r&&r.__esModule)return r;var n={};if(r!=null){for(var s=e(r),t=0;t<s.length;t++)if(s[t]!=="default")u(n,r,s[t])}f(n,r);return n}})();Object.defineProperty(exports,"__esModule",{value:true});exports.DANGEROUS_ENV_KEYS=exports.INLINE_CODE_INTERPRETERS=exports.SHELL_DENYLIST=exports.SKILL_NAME_RE=void 0;exports.validateShellCommand=E;exports.validateEnvKeys=h;exports.normalizeCwd=d;exports.buildShellEnv=S;const a=l(require("path"));const i=l(require("fs"));exports.SKILL_NAME_RE=/^[a-z0-9][a-z0-9-]*$/;exports.SHELL_DENYLIST=new Set(["bash","sh","zsh","dash","fish","cmd","cmd.exe","powershell","powershell.exe","pwsh","pwsh.exe"]);exports.INLINE_CODE_INTERPRETERS=new Set(["python","python3","node","nodejs","deno","perl","ruby","php"]);const c=new Set(["-c","-e","--eval","--exec"]);exports.DANGEROUS_ENV_KEYS=new Set(["LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","NODE_OPTIONS"]);function _(e){return a.basename(e).toLowerCase()}function E(e){if(!Array.isArray(e)){return{ok:false,error:"shell_task.command must be an array of strings (argv), not a string"}}if(e.length===0){return{ok:false,error:"shell_task.command must not be empty"}}if(!e.every(s=>typeof s==="string")){return{ok:false,error:"shell_task.command must contain only strings"}}const r=_(e[0]);const n=r.replace(/\.exe$/,"");if(exports.SHELL_DENYLIST.has(r)||exports.SHELL_DENYLIST.has(n)){return{ok:false,error:`shell_task.command[0] "${e[0]}" is a blocked shell interpreter`}}if(exports.INLINE_CODE_INTERPRETERS.has(n)){const s=e.slice(1).some(t=>c.has(String(t)));if(s){return{ok:false,error:`shell_task.command "${n} ${e[1]}" uses an inline-code flag (escape vector blocked)`}}}return{ok:true}}function h(e){if(!e)return{ok:true};for(const r of Object.keys(e)){if(exports.DANGEROUS_ENV_KEYS.has(r)){return{ok:false,error:`shell_task.env key "${r}" is not allowed`}}}return{ok:true}}function d(e,r){let n;try{n=i.realpathSync(r)}catch(o){return{ok:false,error:`project root "${r}" is not accessible: ${o.message}`}}if(e===void 0||e===""){return{ok:true,resolved:n}}const s=a.resolve(n,e);let t;try{t=i.realpathSync(s)}catch(o){return{ok:false,error:`cwd "${e}" is not accessible: ${o.message}`}}if(t!==n&&!t.startsWith(n+a.sep)){return{ok:false,error:`cwd "${e}" resolves outside the project root`}}return{ok:true,resolved:t}}function S(e,r=process.env){const n=process.platform==="win32"?["PATH","Path","SystemRoot","COMSPEC","TEMP","TMP"]:["PATH","HOME","LANG","TMPDIR"];const s={};for(const t of n){if(r[t]!==void 0)s[t]=r[t]}if(e){for(const[t,o]of Object.entries(e)){s[t]=o}}return s}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { JsonObject, UiAuditSnapshotInput, UiInstance } from '@crewx/sdk';
|
|
2
|
+
import { type WorkflowApprovalState } from './card-state.js';
|
|
3
|
+
import { type WorkflowParentLifecycleChange, type WorkflowParentPersistTaskRepository, type WorkflowParentTaskKind } from './parent-task-sync.js';
|
|
4
|
+
import type { RunExecution, WorkflowSpec } from './types.js';
|
|
5
|
+
export interface WorkflowAuditSnapshotStore {
|
|
6
|
+
get(instanceId: string): UiInstance | null;
|
|
7
|
+
updateAuditSnapshot(input: UiAuditSnapshotInput): UiInstance | null;
|
|
8
|
+
}
|
|
9
|
+
export interface WorkflowPersistenceProjectionResult {
|
|
10
|
+
runId: string;
|
|
11
|
+
changedParentTaskIds: string[];
|
|
12
|
+
projectedAuditInstanceIds: string[];
|
|
13
|
+
errors: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface WorkflowAuditSnapshotChange {
|
|
16
|
+
instanceId: string;
|
|
17
|
+
before: JsonObject;
|
|
18
|
+
after: WorkflowApprovalState;
|
|
19
|
+
}
|
|
20
|
+
export interface WorkflowPersistenceProjectionPreview {
|
|
21
|
+
runId: string;
|
|
22
|
+
runStatus: NonNullable<RunExecution['status']>;
|
|
23
|
+
parentChanges: WorkflowParentLifecycleChange[];
|
|
24
|
+
auditSnapshotChanges: WorkflowAuditSnapshotChange[];
|
|
25
|
+
errors: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface WorkflowPersistenceProjectionPreviewOptions {
|
|
28
|
+
taskRepo: Pick<WorkflowParentPersistTaskRepository, 'findWorkflowParentTask'>;
|
|
29
|
+
workspaceId: string;
|
|
30
|
+
resolveWorkflowSpec: (run: RunExecution) => WorkflowSpec | null | undefined;
|
|
31
|
+
uiInstanceStore?: Pick<WorkflowAuditSnapshotStore, 'get'>;
|
|
32
|
+
getUiInstanceStore?: () => Pick<WorkflowAuditSnapshotStore, 'get'>;
|
|
33
|
+
parentKinds?: readonly WorkflowParentTaskKind[];
|
|
34
|
+
}
|
|
35
|
+
export interface WorkflowPersistenceProjectionOptions {
|
|
36
|
+
taskRepo: WorkflowParentPersistTaskRepository;
|
|
37
|
+
workspaceId: string;
|
|
38
|
+
resolveWorkflowSpec: (run: RunExecution) => WorkflowSpec | null | undefined;
|
|
39
|
+
uiInstanceStore?: WorkflowAuditSnapshotStore;
|
|
40
|
+
getUiInstanceStore?: () => WorkflowAuditSnapshotStore;
|
|
41
|
+
parentKinds?: readonly WorkflowParentTaskKind[];
|
|
42
|
+
onChanged?: (result: WorkflowPersistenceProjectionResult) => void;
|
|
43
|
+
warn?: (message: string) => void;
|
|
44
|
+
}
|
|
45
|
+
export type WorkflowPersistenceProjection = (run: RunExecution) => WorkflowPersistenceProjectionResult;
|
|
46
|
+
export declare function createWorkflowPersistenceProjection(options: WorkflowPersistenceProjectionOptions): WorkflowPersistenceProjection;
|
|
47
|
+
export declare function previewWorkflowPersistenceProjection(options: WorkflowPersistenceProjectionPreviewOptions, run: RunExecution): WorkflowPersistenceProjectionPreview;
|
|
48
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.createWorkflowPersistenceProjection=b;exports.previewWorkflowPersistenceProjection=m;const g=require("./card-state.js");const S=require("./parent-task-sync.js");function h(e){return e instanceof Error?e.message:String(e)}function _(e){return e}function w(e){if(Array.isArray(e))return`[${e.map(r=>w(r)).join(",")}]`;if(e!==null&&typeof e==="object"){const r=e;return`{${Object.keys(r).sort().map(i=>`${JSON.stringify(i)}:${w(r[i])}`).join(",")}}`}return JSON.stringify(e)??"null"}function A(e,r){return w(e)===w(r)}function P(e,r){return{runId:e,changedParentTaskIds:[...r.changedParentTaskIds],projectedAuditInstanceIds:[],errors:[]}}function b(e){const r={taskRepo:e.taskRepo,workspaceId:e.workspaceId,...e.parentKinds?{parentKinds:e.parentKinds}:{}};const i=(0,S.createWorkflowParentPersistSink)(r);const o=e.warn??(n=>console.warn(n));return n=>{let u;try{u=i(n)}catch(s){const t=`workflow persistence parent projection failed for ${n.id}: ${h(s)}`;o(t);return{runId:n.id,changedParentTaskIds:[],projectedAuditInstanceIds:[],errors:[t]}}const c=P(n.id,u);const d=(s,t)=>{const a=`workflow persistence ${s} failed for ${n.id}: ${h(t)}`;c.errors.push(a);o(a)};const p=[...new Set(u.linkedAuditInstanceIds)];if(p.length>0){let s;try{s=e.resolveWorkflowSpec(n);if(!s)throw new Error(`workflow spec not found for ${n.workflow_id}`)}catch(t){d("spec resolution",t)}if(s){let t=null;try{t=(0,g.buildWorkflowApprovalState)(n,s)}catch(a){d("audit state build",a)}if(t){const a=Date.parse(n.updated_at);if(!Number.isSafeInteger(a)||a<0){d("audit snapshot",new Error(`invalid run updated_at: ${n.updated_at}`))}else{let I=e.uiInstanceStore;if(!I&&e.getUiInstanceStore){try{I=e.getUiInstanceStore()}catch(l){d("audit store creation",l)}}if(!I){d("audit snapshot",new Error("no UiInstanceStore was provided"))}else{for(const l of p){try{const f=I.get(l);const $=f?.domainRef?.workflowRunId;if(!f||f.workspaceId!==e.workspaceId||$!==n.id){continue}const j=w(f.state);const y=f.updatedAt;const k=I.updateAuditSnapshot({instanceId:l,workspaceId:e.workspaceId,updatedAt:a,state:_(t)});if(k&&(w(k.state)!==j||k.updatedAt!==y)){c.projectedAuditInstanceIds.push(l)}}catch(f){d(`audit snapshot ${l}`,f)}}}}}}}if((c.changedParentTaskIds.length>0||c.projectedAuditInstanceIds.length>0)&&e.onChanged){try{e.onChanged(c)}catch(s){d("change callback",s)}}return c}}function m(e,r){const i=(0,S.previewWorkflowParentRepair)({taskRepo:e.taskRepo,run:r,workspaceId:e.workspaceId,...e.parentKinds?{parentKinds:e.parentKinds}:{}});const o={runId:r.id,runStatus:i.runStatus,parentChanges:[...i.changes],auditSnapshotChanges:[],errors:[]};const n=(t,a)=>{o.errors.push(`workflow persistence preview ${t} failed for ${r.id}: ${h(a)}`)};const u=[...new Set(i.linkedAuditInstanceIds)];if(u.length===0)return o;let c;try{c=e.resolveWorkflowSpec(r);if(!c)throw new Error(`workflow spec not found for ${r.workflow_id}`)}catch(t){n("spec resolution",t)}if(!c)return o;let d;try{d=(0,g.buildWorkflowApprovalState)(r,c)}catch(t){n("audit state build",t);return o}const p=Date.parse(r.updated_at);if(!Number.isSafeInteger(p)||p<0){n("audit snapshot",new Error(`invalid run updated_at: ${r.updated_at}`));return o}let s=e.uiInstanceStore;if(!s&&e.getUiInstanceStore){try{s=e.getUiInstanceStore()}catch(t){n("audit store creation",t)}}if(!s){n("audit snapshot",new Error("no UiInstanceStore was provided"));return o}for(const t of u){try{const a=s.get(t);if(!a||a.workspaceId!==e.workspaceId||a.domainRef.workflowRunId!==r.id){continue}if(!A(a.state,d)){o.auditSnapshotChanges.push({instanceId:t,before:a.state,after:d})}}catch(a){n(`audit snapshot ${t}`,a)}}void p;return o}
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
},
|
|
82
82
|
"cwd": {
|
|
83
83
|
"type": "string",
|
|
84
|
-
"description": "skill_task/shell_task: working directory, normalized and constrained under the project root."
|
|
84
|
+
"description": "agent_task/skill_task/shell_task: working directory, normalized and constrained under the project root."
|
|
85
85
|
},
|
|
86
86
|
"env": {
|
|
87
87
|
"type": "object",
|
|
@@ -90,6 +90,10 @@
|
|
|
90
90
|
},
|
|
91
91
|
"description": "shell_task: explicit env pass-through. Dangerous keys (LD_PRELOAD, etc.) are rejected."
|
|
92
92
|
},
|
|
93
|
+
"stdin": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"description": "skill_task/shell_task: optional stdin payload. Supports {{template}} interpolation."
|
|
96
|
+
},
|
|
93
97
|
"mode": {
|
|
94
98
|
"type": "string",
|
|
95
99
|
"enum": ["query", "execute"]
|
|
@@ -166,6 +170,10 @@
|
|
|
166
170
|
"type": "string",
|
|
167
171
|
"description": "error: failure message recorded in run.error. Supports {{template}} interpolation."
|
|
168
172
|
},
|
|
173
|
+
"label": {
|
|
174
|
+
"type": "string",
|
|
175
|
+
"description": "Short human-facing step name shown in run views. Falls back to the node id."
|
|
176
|
+
},
|
|
169
177
|
"on_approve": {
|
|
170
178
|
"type": "string"
|
|
171
179
|
},
|
|
@@ -218,19 +226,36 @@
|
|
|
218
226
|
"required": ["max", "delay"],
|
|
219
227
|
"properties": {
|
|
220
228
|
"max": {
|
|
221
|
-
"type": "
|
|
229
|
+
"type": "integer",
|
|
230
|
+
"minimum": 0,
|
|
231
|
+
"maximum": 10,
|
|
232
|
+
"description": "Number of additional retries after the first attempt (0 disables retry)."
|
|
222
233
|
},
|
|
223
234
|
"delay": {
|
|
224
235
|
"type": "string",
|
|
225
236
|
"enum": ["exponential", "fixed"]
|
|
226
237
|
},
|
|
227
238
|
"max_delay": {
|
|
228
|
-
"type": "
|
|
239
|
+
"type": "integer",
|
|
240
|
+
"minimum": 0,
|
|
241
|
+
"description": "Maximum retry delay in milliseconds; runtime hard-caps this at 60000."
|
|
229
242
|
},
|
|
230
243
|
"on": {
|
|
231
244
|
"type": "array",
|
|
232
245
|
"items": {
|
|
233
|
-
"type": "string"
|
|
246
|
+
"type": "string",
|
|
247
|
+
"enum": [
|
|
248
|
+
"CLI_UNRESOLVABLE",
|
|
249
|
+
"SPAWN_FAILED",
|
|
250
|
+
"NODE_TIMEOUT",
|
|
251
|
+
"NODE_EXIT_NONZERO",
|
|
252
|
+
"OUTPUT_INVALID",
|
|
253
|
+
"RATE_LIMITED",
|
|
254
|
+
"CONFIG_INVALID",
|
|
255
|
+
"INTERRUPTED",
|
|
256
|
+
"CANCELLED",
|
|
257
|
+
"UNKNOWN"
|
|
258
|
+
]
|
|
234
259
|
}
|
|
235
260
|
}
|
|
236
261
|
}
|