@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.
Files changed (35) hide show
  1. package/dist/assets/{index-BnaWRV1a.js → index-nefOyhzb.js} +168 -168
  2. package/dist/index.html +1 -1
  3. package/dist-server/server/claude-sdk.js +23 -2
  4. package/dist-server/server/claude-sdk.js.map +1 -1
  5. package/dist-server/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.js.map +1 -1
  6. package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js +2 -0
  7. package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js.map +1 -1
  8. package/dist-server/server/modules/orchestration/a2a/routes.js +2 -0
  9. package/dist-server/server/modules/orchestration/a2a/routes.js.map +1 -1
  10. package/dist-server/server/modules/orchestration/index.js +2 -0
  11. package/dist-server/server/modules/orchestration/index.js.map +1 -1
  12. package/dist-server/server/modules/orchestration/security/permission-policy.js +269 -0
  13. package/dist-server/server/modules/orchestration/security/permission-policy.js.map +1 -0
  14. package/dist-server/server/modules/orchestration/workflows/workflow-runner.js +115 -1
  15. package/dist-server/server/modules/orchestration/workflows/workflow-runner.js.map +1 -1
  16. package/dist-server/server/modules/orchestration/workflows/workflow-templates.js +242 -0
  17. package/dist-server/server/modules/orchestration/workflows/workflow-templates.js.map +1 -0
  18. package/dist-server/server/modules/orchestration/workflows/workflow-trace.js +53 -0
  19. package/dist-server/server/modules/orchestration/workflows/workflow-trace.js.map +1 -1
  20. package/dist-server/server/modules/orchestration/workflows/workflow.routes.js +137 -0
  21. package/dist-server/server/modules/orchestration/workflows/workflow.routes.js.map +1 -1
  22. package/package.json +1 -1
  23. package/scripts/smoke/permission-policy.mjs +50 -0
  24. package/scripts/smoke/workflow-templates.mjs +43 -0
  25. package/server/claude-sdk.js +24 -2
  26. package/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.ts +8 -0
  27. package/server/modules/orchestration/a2a/adapters/claude-code.adapter.ts +2 -0
  28. package/server/modules/orchestration/a2a/routes.ts +6 -0
  29. package/server/modules/orchestration/index.ts +28 -0
  30. package/server/modules/orchestration/security/permission-policy.ts +401 -0
  31. package/server/modules/orchestration/workflows/workflow-runner.ts +141 -1
  32. package/server/modules/orchestration/workflows/workflow-templates.ts +272 -0
  33. package/server/modules/orchestration/workflows/workflow-trace.ts +54 -0
  34. package/server/modules/orchestration/workflows/workflow.routes.ts +165 -0
  35. 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;