@pixelbyte-software/pixcode 1.42.3 → 1.42.5
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-BnaWRV1a.js → index-nefOyhzb.js} +168 -168
- package/dist/index.html +1 -1
- package/dist-server/server/claude-sdk.js +23 -2
- package/dist-server/server/claude-sdk.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js +2 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/routes.js +2 -0
- package/dist-server/server/modules/orchestration/a2a/routes.js.map +1 -1
- package/dist-server/server/modules/orchestration/index.js +2 -0
- package/dist-server/server/modules/orchestration/index.js.map +1 -1
- package/dist-server/server/modules/orchestration/security/permission-policy.js +269 -0
- package/dist-server/server/modules/orchestration/security/permission-policy.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js +115 -1
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js.map +1 -1
- package/dist-server/server/modules/orchestration/workflows/workflow-templates.js +242 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-templates.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-trace.js +53 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-trace.js.map +1 -1
- package/dist-server/server/modules/orchestration/workflows/workflow.routes.js +137 -0
- package/dist-server/server/modules/orchestration/workflows/workflow.routes.js.map +1 -1
- package/package.json +1 -1
- package/scripts/smoke/permission-policy.mjs +50 -0
- package/scripts/smoke/workflow-templates.mjs +43 -0
- package/server/claude-sdk.js +24 -2
- package/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.ts +8 -0
- package/server/modules/orchestration/a2a/adapters/claude-code.adapter.ts +2 -0
- package/server/modules/orchestration/a2a/routes.ts +6 -0
- package/server/modules/orchestration/index.ts +28 -0
- package/server/modules/orchestration/security/permission-policy.ts +401 -0
- package/server/modules/orchestration/workflows/workflow-runner.ts +141 -1
- package/server/modules/orchestration/workflows/workflow-templates.ts +272 -0
- package/server/modules/orchestration/workflows/workflow-trace.ts +54 -0
- package/server/modules/orchestration/workflows/workflow.routes.ts +165 -0
- package/server/modules/orchestration/workflows/workflow.types.ts +9 -1
|
@@ -6,9 +6,22 @@ import {
|
|
|
6
6
|
type WorkflowReplayScope,
|
|
7
7
|
buildWorkflowReplayPlan,
|
|
8
8
|
} from '@/modules/orchestration/workflows/workflow-replay.js';
|
|
9
|
+
import {
|
|
10
|
+
applyWorkflowTemplateToMetadata,
|
|
11
|
+
builtInWorkflowTemplates,
|
|
12
|
+
getWorkflowTemplate,
|
|
13
|
+
} from '@/modules/orchestration/workflows/workflow-templates.js';
|
|
9
14
|
import { workflowStore } from '@/modules/orchestration/workflows/workflow-store.js';
|
|
10
15
|
import { buildWorkflowTrace } from '@/modules/orchestration/workflows/workflow-trace.js';
|
|
11
16
|
import { findPixcodeAppRoot } from '@/modules/orchestration/workflows/workspace-target.js';
|
|
17
|
+
import {
|
|
18
|
+
DEFAULT_PERMISSION_POLICY,
|
|
19
|
+
PERMISSION_CAPABILITIES,
|
|
20
|
+
PERMISSION_POLICY_MODES,
|
|
21
|
+
PIXCODE_PERMISSION_POLICY_PROTOCOL,
|
|
22
|
+
evaluatePermissionRequest,
|
|
23
|
+
normalizePermissionPolicy,
|
|
24
|
+
} from '@/modules/orchestration/security/permission-policy.js';
|
|
12
25
|
|
|
13
26
|
const TERMINAL_RUN_STATES = new Set(['completed', 'failed', 'canceled']);
|
|
14
27
|
|
|
@@ -73,6 +86,36 @@ function replayOptions(req: express.Request): {
|
|
|
73
86
|
};
|
|
74
87
|
}
|
|
75
88
|
|
|
89
|
+
function readRunArray(run: { metadata?: Record<string, unknown> }, key: string): Array<Record<string, unknown>> {
|
|
90
|
+
const value = run.metadata?.[key];
|
|
91
|
+
return Array.isArray(value)
|
|
92
|
+
? value.filter((item): item is Record<string, unknown> => Boolean(item && typeof item === 'object'))
|
|
93
|
+
: [];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function updateApproval(
|
|
97
|
+
run: { metadata?: Record<string, unknown> },
|
|
98
|
+
requestId: string,
|
|
99
|
+
patch: Record<string, unknown>,
|
|
100
|
+
): boolean {
|
|
101
|
+
const approvals = readRunArray(run, 'pendingPermissionApprovals');
|
|
102
|
+
let changed = false;
|
|
103
|
+
const nextApprovals = approvals.map((approval) => {
|
|
104
|
+
if (approval.id !== requestId) return approval;
|
|
105
|
+
changed = true;
|
|
106
|
+
return {
|
|
107
|
+
...approval,
|
|
108
|
+
...patch,
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
if (!changed) return false;
|
|
112
|
+
run.metadata = {
|
|
113
|
+
...run.metadata,
|
|
114
|
+
pendingPermissionApprovals: nextApprovals,
|
|
115
|
+
};
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
76
119
|
function sendRunSnapshot(res: express.Response, runId: string): boolean {
|
|
77
120
|
const run = workflowStore.getRun(runId);
|
|
78
121
|
if (!run) {
|
|
@@ -92,6 +135,12 @@ export function createWorkflowRouter(): Router {
|
|
|
92
135
|
res.json({ workflows: workflowStore.listWorkflows() });
|
|
93
136
|
});
|
|
94
137
|
|
|
138
|
+
router.get('/workflows/templates', (_req, res) => {
|
|
139
|
+
res.json({
|
|
140
|
+
templates: builtInWorkflowTemplates,
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
95
144
|
router.get('/workflows/context', (_req, res) => {
|
|
96
145
|
res.json({
|
|
97
146
|
appRoot: findPixcodeAppRoot(),
|
|
@@ -162,6 +211,89 @@ export function createWorkflowRouter(): Router {
|
|
|
162
211
|
});
|
|
163
212
|
});
|
|
164
213
|
|
|
214
|
+
router.get('/workflows/permission-policy', (_req, res) => {
|
|
215
|
+
res.json({
|
|
216
|
+
protocol: PIXCODE_PERMISSION_POLICY_PROTOCOL,
|
|
217
|
+
capabilities: PERMISSION_CAPABILITIES,
|
|
218
|
+
modes: PERMISSION_POLICY_MODES,
|
|
219
|
+
defaultPolicy: DEFAULT_PERMISSION_POLICY,
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
router.post('/workflows/permission-policy/evaluate', (req, res) => {
|
|
224
|
+
try {
|
|
225
|
+
res.json({
|
|
226
|
+
decision: evaluatePermissionRequest({
|
|
227
|
+
policy: normalizePermissionPolicy(req.body?.policy),
|
|
228
|
+
request: req.body?.request ?? { source: 'api' },
|
|
229
|
+
}),
|
|
230
|
+
});
|
|
231
|
+
} catch (error) {
|
|
232
|
+
res.status(400).json({
|
|
233
|
+
error: {
|
|
234
|
+
code: 'PERMISSION_POLICY_INVALID',
|
|
235
|
+
message: error instanceof Error ? error.message : String(error),
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
router.get('/workflows/runs/:runId/permission-approvals', (req, res) => {
|
|
242
|
+
const run = workflowStore.getRun(req.params.runId);
|
|
243
|
+
if (!run) {
|
|
244
|
+
res.status(404).json({ error: { code: 'RUN_NOT_FOUND', message: req.params.runId } });
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
res.json({
|
|
249
|
+
runId: run.id,
|
|
250
|
+
pendingApprovals: readRunArray(run, 'pendingPermissionApprovals')
|
|
251
|
+
.filter((approval) => approval.status === 'pending'),
|
|
252
|
+
approvalHistory: readRunArray(run, 'pendingPermissionApprovals')
|
|
253
|
+
.filter((approval) => approval.status !== 'pending'),
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
router.post('/workflows/runs/:runId/permission-approvals/:requestId', (req, res) => {
|
|
258
|
+
const run = workflowStore.getRun(req.params.runId);
|
|
259
|
+
if (!run) {
|
|
260
|
+
res.status(404).json({ error: { code: 'RUN_NOT_FOUND', message: req.params.runId } });
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const allow = req.body?.allow === true;
|
|
265
|
+
const deny = req.body?.allow === false;
|
|
266
|
+
if (!allow && !deny) {
|
|
267
|
+
res.status(400).json({
|
|
268
|
+
error: {
|
|
269
|
+
code: 'PERMISSION_DECISION_REQUIRED',
|
|
270
|
+
message: 'Permission approval requires allow=true or allow=false.',
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const updated = updateApproval(run, req.params.requestId, {
|
|
277
|
+
status: allow ? 'allowed' : 'denied',
|
|
278
|
+
resolvedAt: Date.now(),
|
|
279
|
+
resolvedBy: readRequestUserId(req),
|
|
280
|
+
resolutionMessage: readOptionalString(req.body?.message),
|
|
281
|
+
});
|
|
282
|
+
if (!updated) {
|
|
283
|
+
res.status(404).json({ error: { code: 'APPROVAL_NOT_FOUND', message: req.params.requestId } });
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
workflowStore.setRun(run);
|
|
288
|
+
res.json({
|
|
289
|
+
runId: run.id,
|
|
290
|
+
pendingApprovals: readRunArray(run, 'pendingPermissionApprovals')
|
|
291
|
+
.filter((approval) => approval.status === 'pending'),
|
|
292
|
+
approvalHistory: readRunArray(run, 'pendingPermissionApprovals')
|
|
293
|
+
.filter((approval) => approval.status !== 'pending'),
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
165
297
|
router.get('/workflows/runs/:runId/replay-plan', (req, res) => {
|
|
166
298
|
const run = workflowStore.getRun(req.params.runId);
|
|
167
299
|
if (!run) {
|
|
@@ -322,5 +454,38 @@ export function createWorkflowRouter(): Router {
|
|
|
322
454
|
}
|
|
323
455
|
});
|
|
324
456
|
|
|
457
|
+
router.post('/workflows/templates/:templateId/runs', (req, res) => {
|
|
458
|
+
const template = getWorkflowTemplate(req.params.templateId);
|
|
459
|
+
if (!template) {
|
|
460
|
+
res.status(404).json({ error: { code: 'WORKFLOW_TEMPLATE_NOT_FOUND', message: req.params.templateId } });
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
const workflow = workflowStore.getWorkflow(template.workflowId);
|
|
464
|
+
if (!workflow) {
|
|
465
|
+
res.status(404).json({ error: { code: 'WORKFLOW_NOT_FOUND', message: template.workflowId } });
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
try {
|
|
470
|
+
const run = workflowRunner.start(
|
|
471
|
+
workflow,
|
|
472
|
+
typeof req.body?.input === 'string' ? req.body.input : '',
|
|
473
|
+
{
|
|
474
|
+
...applyWorkflowTemplateToMetadata(template, readMetadata(req.body)),
|
|
475
|
+
userId: readRequestUserId(req),
|
|
476
|
+
workflowName: workflow.name,
|
|
477
|
+
},
|
|
478
|
+
);
|
|
479
|
+
res.status(202).json(run);
|
|
480
|
+
} catch (error) {
|
|
481
|
+
res.status(400).json({
|
|
482
|
+
error: {
|
|
483
|
+
code: 'WORKFLOW_TEMPLATE_START_FAILED',
|
|
484
|
+
message: error instanceof Error ? error.message : String(error),
|
|
485
|
+
},
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
|
|
325
490
|
return router;
|
|
326
491
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { WorkflowContextPacket } from '@/modules/orchestration/workflows/context-packet.js';
|
|
2
2
|
import type { WorkflowFallbackTrigger } from '@/modules/orchestration/workflows/workflow-fallback-policy.js';
|
|
3
3
|
import type { WorkflowHandoffArtifact } from '@/modules/orchestration/workflows/handoff-artifact.js';
|
|
4
|
+
import type {
|
|
5
|
+
PermissionDecision,
|
|
6
|
+
PermissionPolicy,
|
|
7
|
+
} from '@/modules/orchestration/security/permission-policy.js';
|
|
4
8
|
|
|
5
9
|
export type WorkflowRunStatus = 'queued' | 'running' | 'completed' | 'failed' | 'canceled';
|
|
6
10
|
export type WorkflowNodeStatus = WorkflowRunStatus | 'skipped';
|
|
@@ -18,6 +22,8 @@ export interface WorkflowNode {
|
|
|
18
22
|
assignment?: string;
|
|
19
23
|
model?: string;
|
|
20
24
|
permissionMode?: string;
|
|
25
|
+
permissionPolicy?: PermissionPolicy;
|
|
26
|
+
permissionDecisions?: PermissionDecision[];
|
|
21
27
|
toolsSettings?: Record<string, unknown>;
|
|
22
28
|
isolation?: 'host' | 'worktree' | 'docker';
|
|
23
29
|
timeoutMs?: number;
|
|
@@ -44,6 +50,8 @@ export interface WorkflowNodeRun {
|
|
|
44
50
|
promptPreview?: string;
|
|
45
51
|
model?: string;
|
|
46
52
|
permissionMode?: string;
|
|
53
|
+
permissionPolicy?: PermissionPolicy;
|
|
54
|
+
permissionDecisions?: PermissionDecision[];
|
|
47
55
|
timeoutMs?: number;
|
|
48
56
|
stage?: string;
|
|
49
57
|
internal?: boolean;
|
|
@@ -84,7 +92,7 @@ export interface WorkflowRun {
|
|
|
84
92
|
|
|
85
93
|
export interface WorkflowTraceEvent {
|
|
86
94
|
id: string;
|
|
87
|
-
type: 'run' | 'node' | 'provider' | 'message' | 'artifact' | 'file' | 'error';
|
|
95
|
+
type: 'run' | 'node' | 'provider' | 'message' | 'artifact' | 'file' | 'error' | 'permission_policy';
|
|
88
96
|
severity: 'info' | 'warning' | 'error';
|
|
89
97
|
status: WorkflowRunStatus | WorkflowNodeStatus | 'submitted';
|
|
90
98
|
timestamp: number;
|