@pixelbyte-software/pixcode 1.42.0 → 1.42.2
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/dist/assets/{index-CkOamyD3.js → index-CMeiCqQf.js} +182 -182
- package/dist/index.html +1 -1
- package/dist-server/server/modules/orchestration/workflows/context-packet.js +89 -0
- package/dist-server/server/modules/orchestration/workflows/context-packet.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-fallback-policy.js +114 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-fallback-policy.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-replay.js +177 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-replay.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js +58 -7
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js.map +1 -1
- package/dist-server/server/modules/orchestration/workflows/workflow-trace.js +95 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-trace.js.map +1 -1
- package/dist-server/server/modules/orchestration/workflows/workflow.routes.js +88 -0
- package/dist-server/server/modules/orchestration/workflows/workflow.routes.js.map +1 -1
- package/package.json +1 -1
- package/scripts/smoke/context-packet.mjs +43 -0
- package/scripts/smoke/workflow-fallback-replay.mjs +56 -0
- package/server/modules/orchestration/workflows/context-packet.ts +186 -0
- package/server/modules/orchestration/workflows/workflow-fallback-policy.ts +161 -0
- package/server/modules/orchestration/workflows/workflow-replay.ts +254 -0
- package/server/modules/orchestration/workflows/workflow-runner.ts +119 -6
- package/server/modules/orchestration/workflows/workflow-trace.ts +98 -0
- package/server/modules/orchestration/workflows/workflow.routes.ts +107 -0
- package/server/modules/orchestration/workflows/workflow.types.ts +7 -0
|
@@ -2,6 +2,10 @@ import type { Router } from 'express';
|
|
|
2
2
|
import express from 'express';
|
|
3
3
|
|
|
4
4
|
import { workflowRunner } from '@/modules/orchestration/workflows/workflow-runner.js';
|
|
5
|
+
import {
|
|
6
|
+
type WorkflowReplayScope,
|
|
7
|
+
buildWorkflowReplayPlan,
|
|
8
|
+
} from '@/modules/orchestration/workflows/workflow-replay.js';
|
|
5
9
|
import { workflowStore } from '@/modules/orchestration/workflows/workflow-store.js';
|
|
6
10
|
import { buildWorkflowTrace } from '@/modules/orchestration/workflows/workflow-trace.js';
|
|
7
11
|
import { findPixcodeAppRoot } from '@/modules/orchestration/workflows/workspace-target.js';
|
|
@@ -45,6 +49,30 @@ function readRequestUserId(req: express.Request): string | number | null {
|
|
|
45
49
|
return user?.id ?? user?.userId ?? null;
|
|
46
50
|
}
|
|
47
51
|
|
|
52
|
+
function readReplayScope(value: unknown): WorkflowReplayScope {
|
|
53
|
+
return value === 'run' ? 'run' : 'node';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function readOptionalString(value: unknown): string | undefined {
|
|
57
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function readBooleanFlag(value: unknown): boolean {
|
|
61
|
+
return value === true || value === 'true' || value === '1';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function replayOptions(req: express.Request): {
|
|
65
|
+
scope: WorkflowReplayScope;
|
|
66
|
+
fromNodeId?: string;
|
|
67
|
+
approveReplay: boolean;
|
|
68
|
+
} {
|
|
69
|
+
return {
|
|
70
|
+
scope: readReplayScope(req.body?.scope ?? req.query.scope),
|
|
71
|
+
fromNodeId: readOptionalString(req.body?.fromNodeId ?? req.query.fromNodeId),
|
|
72
|
+
approveReplay: readBooleanFlag(req.body?.approveReplay ?? req.query.approveReplay),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
48
76
|
function sendRunSnapshot(res: express.Response, runId: string): boolean {
|
|
49
77
|
const run = workflowStore.getRun(runId);
|
|
50
78
|
if (!run) {
|
|
@@ -134,6 +162,85 @@ export function createWorkflowRouter(): Router {
|
|
|
134
162
|
});
|
|
135
163
|
});
|
|
136
164
|
|
|
165
|
+
router.get('/workflows/runs/:runId/replay-plan', (req, res) => {
|
|
166
|
+
const run = workflowStore.getRun(req.params.runId);
|
|
167
|
+
if (!run) {
|
|
168
|
+
res.status(404).json({ error: { code: 'RUN_NOT_FOUND', message: req.params.runId } });
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
const options = replayOptions(req);
|
|
174
|
+
res.json({
|
|
175
|
+
replayPlan: buildWorkflowReplayPlan(run, {
|
|
176
|
+
scope: options.scope,
|
|
177
|
+
fromNodeId: options.fromNodeId,
|
|
178
|
+
}),
|
|
179
|
+
});
|
|
180
|
+
} catch (error) {
|
|
181
|
+
res.status(400).json({
|
|
182
|
+
error: {
|
|
183
|
+
code: 'REPLAY_PLAN_INVALID',
|
|
184
|
+
message: error instanceof Error ? error.message : String(error),
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
router.post('/workflows/runs/:runId/replay', (req, res) => {
|
|
191
|
+
const run = workflowStore.getRun(req.params.runId);
|
|
192
|
+
if (!run) {
|
|
193
|
+
res.status(404).json({ error: { code: 'RUN_NOT_FOUND', message: req.params.runId } });
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const options = replayOptions(req);
|
|
199
|
+
const replayPlan = buildWorkflowReplayPlan(run, {
|
|
200
|
+
scope: options.scope,
|
|
201
|
+
fromNodeId: options.fromNodeId,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (replayPlan.requiresApproval && !options.approveReplay) {
|
|
205
|
+
res.status(409).json({
|
|
206
|
+
error: {
|
|
207
|
+
code: 'REPLAY_APPROVAL_REQUIRED',
|
|
208
|
+
message: 'Replay requires explicit approval because prior shell, network, or file-write activity was detected.',
|
|
209
|
+
},
|
|
210
|
+
replayPlan,
|
|
211
|
+
});
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const replayRun = workflowRunner.start(
|
|
216
|
+
replayPlan.workflow,
|
|
217
|
+
replayPlan.input,
|
|
218
|
+
{
|
|
219
|
+
...replayPlan.metadata,
|
|
220
|
+
userId: readRequestUserId(req) ?? run.metadata?.userId,
|
|
221
|
+
replay: {
|
|
222
|
+
...(replayPlan.metadata.replay && typeof replayPlan.metadata.replay === 'object'
|
|
223
|
+
? replayPlan.metadata.replay as Record<string, unknown>
|
|
224
|
+
: {}),
|
|
225
|
+
approved: options.approveReplay,
|
|
226
|
+
approvedAt: options.approveReplay ? Date.now() : undefined,
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
);
|
|
230
|
+
res.status(202).json({
|
|
231
|
+
run: replayRun,
|
|
232
|
+
replayPlan,
|
|
233
|
+
});
|
|
234
|
+
} catch (error) {
|
|
235
|
+
res.status(400).json({
|
|
236
|
+
error: {
|
|
237
|
+
code: 'REPLAY_START_FAILED',
|
|
238
|
+
message: error instanceof Error ? error.message : String(error),
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
137
244
|
router.get('/workflows/runs/:runId', (req, res) => {
|
|
138
245
|
const run = workflowStore.getRun(req.params.runId);
|
|
139
246
|
if (!run) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { WorkflowContextPacket } from '@/modules/orchestration/workflows/context-packet.js';
|
|
2
|
+
import type { WorkflowFallbackTrigger } from '@/modules/orchestration/workflows/workflow-fallback-policy.js';
|
|
1
3
|
import type { WorkflowHandoffArtifact } from '@/modules/orchestration/workflows/handoff-artifact.js';
|
|
2
4
|
|
|
3
5
|
export type WorkflowRunStatus = 'queued' | 'running' | 'completed' | 'failed' | 'canceled';
|
|
@@ -20,6 +22,8 @@ export interface WorkflowNode {
|
|
|
20
22
|
isolation?: 'host' | 'worktree' | 'docker';
|
|
21
23
|
timeoutMs?: number;
|
|
22
24
|
internal?: boolean;
|
|
25
|
+
fallbackTrigger?: WorkflowFallbackTrigger;
|
|
26
|
+
fallbackSourceNodeId?: string;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
export interface Workflow {
|
|
@@ -43,12 +47,15 @@ export interface WorkflowNodeRun {
|
|
|
43
47
|
timeoutMs?: number;
|
|
44
48
|
stage?: string;
|
|
45
49
|
internal?: boolean;
|
|
50
|
+
fallbackTrigger?: WorkflowFallbackTrigger;
|
|
51
|
+
fallbackSourceNodeId?: string;
|
|
46
52
|
status: WorkflowNodeStatus;
|
|
47
53
|
a2aTaskId?: string;
|
|
48
54
|
startedAt?: number;
|
|
49
55
|
finishedAt?: number;
|
|
50
56
|
error?: string;
|
|
51
57
|
outputText?: string;
|
|
58
|
+
contextPacket?: WorkflowContextPacket;
|
|
52
59
|
handoffArtifact?: WorkflowHandoffArtifact;
|
|
53
60
|
messages?: Array<{
|
|
54
61
|
role: string;
|