@pixelbyte-software/pixcode 1.42.3 → 1.42.4
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-cTGs3Dvx.js} +72 -72
- 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 +1 -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-trace.js +32 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-trace.js.map +1 -1
- package/dist-server/server/modules/orchestration/workflows/workflow.routes.js +103 -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/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 +18 -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-trace.ts +32 -0
- package/server/modules/orchestration/workflows/workflow.routes.ts +121 -0
- package/server/modules/orchestration/workflows/workflow.types.ts +9 -1
|
@@ -9,6 +9,14 @@ import {
|
|
|
9
9
|
import { workflowStore } from '@/modules/orchestration/workflows/workflow-store.js';
|
|
10
10
|
import { buildWorkflowTrace } from '@/modules/orchestration/workflows/workflow-trace.js';
|
|
11
11
|
import { findPixcodeAppRoot } from '@/modules/orchestration/workflows/workspace-target.js';
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_PERMISSION_POLICY,
|
|
14
|
+
PERMISSION_CAPABILITIES,
|
|
15
|
+
PERMISSION_POLICY_MODES,
|
|
16
|
+
PIXCODE_PERMISSION_POLICY_PROTOCOL,
|
|
17
|
+
evaluatePermissionRequest,
|
|
18
|
+
normalizePermissionPolicy,
|
|
19
|
+
} from '@/modules/orchestration/security/permission-policy.js';
|
|
12
20
|
|
|
13
21
|
const TERMINAL_RUN_STATES = new Set(['completed', 'failed', 'canceled']);
|
|
14
22
|
|
|
@@ -73,6 +81,36 @@ function replayOptions(req: express.Request): {
|
|
|
73
81
|
};
|
|
74
82
|
}
|
|
75
83
|
|
|
84
|
+
function readRunArray(run: { metadata?: Record<string, unknown> }, key: string): Array<Record<string, unknown>> {
|
|
85
|
+
const value = run.metadata?.[key];
|
|
86
|
+
return Array.isArray(value)
|
|
87
|
+
? value.filter((item): item is Record<string, unknown> => Boolean(item && typeof item === 'object'))
|
|
88
|
+
: [];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function updateApproval(
|
|
92
|
+
run: { metadata?: Record<string, unknown> },
|
|
93
|
+
requestId: string,
|
|
94
|
+
patch: Record<string, unknown>,
|
|
95
|
+
): boolean {
|
|
96
|
+
const approvals = readRunArray(run, 'pendingPermissionApprovals');
|
|
97
|
+
let changed = false;
|
|
98
|
+
const nextApprovals = approvals.map((approval) => {
|
|
99
|
+
if (approval.id !== requestId) return approval;
|
|
100
|
+
changed = true;
|
|
101
|
+
return {
|
|
102
|
+
...approval,
|
|
103
|
+
...patch,
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
if (!changed) return false;
|
|
107
|
+
run.metadata = {
|
|
108
|
+
...run.metadata,
|
|
109
|
+
pendingPermissionApprovals: nextApprovals,
|
|
110
|
+
};
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
|
|
76
114
|
function sendRunSnapshot(res: express.Response, runId: string): boolean {
|
|
77
115
|
const run = workflowStore.getRun(runId);
|
|
78
116
|
if (!run) {
|
|
@@ -162,6 +200,89 @@ export function createWorkflowRouter(): Router {
|
|
|
162
200
|
});
|
|
163
201
|
});
|
|
164
202
|
|
|
203
|
+
router.get('/workflows/permission-policy', (_req, res) => {
|
|
204
|
+
res.json({
|
|
205
|
+
protocol: PIXCODE_PERMISSION_POLICY_PROTOCOL,
|
|
206
|
+
capabilities: PERMISSION_CAPABILITIES,
|
|
207
|
+
modes: PERMISSION_POLICY_MODES,
|
|
208
|
+
defaultPolicy: DEFAULT_PERMISSION_POLICY,
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
router.post('/workflows/permission-policy/evaluate', (req, res) => {
|
|
213
|
+
try {
|
|
214
|
+
res.json({
|
|
215
|
+
decision: evaluatePermissionRequest({
|
|
216
|
+
policy: normalizePermissionPolicy(req.body?.policy),
|
|
217
|
+
request: req.body?.request ?? { source: 'api' },
|
|
218
|
+
}),
|
|
219
|
+
});
|
|
220
|
+
} catch (error) {
|
|
221
|
+
res.status(400).json({
|
|
222
|
+
error: {
|
|
223
|
+
code: 'PERMISSION_POLICY_INVALID',
|
|
224
|
+
message: error instanceof Error ? error.message : String(error),
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
router.get('/workflows/runs/:runId/permission-approvals', (req, res) => {
|
|
231
|
+
const run = workflowStore.getRun(req.params.runId);
|
|
232
|
+
if (!run) {
|
|
233
|
+
res.status(404).json({ error: { code: 'RUN_NOT_FOUND', message: req.params.runId } });
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
res.json({
|
|
238
|
+
runId: run.id,
|
|
239
|
+
pendingApprovals: readRunArray(run, 'pendingPermissionApprovals')
|
|
240
|
+
.filter((approval) => approval.status === 'pending'),
|
|
241
|
+
approvalHistory: readRunArray(run, 'pendingPermissionApprovals')
|
|
242
|
+
.filter((approval) => approval.status !== 'pending'),
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
router.post('/workflows/runs/:runId/permission-approvals/:requestId', (req, res) => {
|
|
247
|
+
const run = workflowStore.getRun(req.params.runId);
|
|
248
|
+
if (!run) {
|
|
249
|
+
res.status(404).json({ error: { code: 'RUN_NOT_FOUND', message: req.params.runId } });
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const allow = req.body?.allow === true;
|
|
254
|
+
const deny = req.body?.allow === false;
|
|
255
|
+
if (!allow && !deny) {
|
|
256
|
+
res.status(400).json({
|
|
257
|
+
error: {
|
|
258
|
+
code: 'PERMISSION_DECISION_REQUIRED',
|
|
259
|
+
message: 'Permission approval requires allow=true or allow=false.',
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const updated = updateApproval(run, req.params.requestId, {
|
|
266
|
+
status: allow ? 'allowed' : 'denied',
|
|
267
|
+
resolvedAt: Date.now(),
|
|
268
|
+
resolvedBy: readRequestUserId(req),
|
|
269
|
+
resolutionMessage: readOptionalString(req.body?.message),
|
|
270
|
+
});
|
|
271
|
+
if (!updated) {
|
|
272
|
+
res.status(404).json({ error: { code: 'APPROVAL_NOT_FOUND', message: req.params.requestId } });
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
workflowStore.setRun(run);
|
|
277
|
+
res.json({
|
|
278
|
+
runId: run.id,
|
|
279
|
+
pendingApprovals: readRunArray(run, 'pendingPermissionApprovals')
|
|
280
|
+
.filter((approval) => approval.status === 'pending'),
|
|
281
|
+
approvalHistory: readRunArray(run, 'pendingPermissionApprovals')
|
|
282
|
+
.filter((approval) => approval.status !== 'pending'),
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
|
|
165
286
|
router.get('/workflows/runs/:runId/replay-plan', (req, res) => {
|
|
166
287
|
const run = workflowStore.getRun(req.params.runId);
|
|
167
288
|
if (!run) {
|
|
@@ -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;
|