@pixelbyte-software/pixcode 1.54.10 → 1.54.11
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/CODE_OF_CONDUCT.md +41 -41
- package/CONTRIBUTING.md +156 -156
- package/LICENSE +21 -718
- package/README.de.md +169 -169
- package/README.ja.md +167 -167
- package/README.ko.md +167 -167
- package/README.md +435 -418
- package/README.ru.md +169 -169
- package/README.tr.md +298 -298
- package/README.zh-CN.md +167 -167
- package/SECURITY.md +46 -46
- package/dist/api-automation.html +110 -110
- package/dist/api-docs.html +548 -548
- package/dist/assets/{index-DWOW_Jn0.js → index-Bcqs_1vc.js} +114 -114
- package/dist/clear-cache.html +85 -85
- package/dist/convert-icons.md +52 -52
- package/dist/docs.html +308 -308
- package/dist/features.html +133 -133
- package/dist/generate-icons.js +48 -48
- package/dist/humans.txt +15 -15
- package/dist/icons/codex-white.svg +3 -3
- package/dist/icons/codex.svg +3 -3
- package/dist/icons/cursor-white.svg +11 -11
- package/dist/icons/qwen-logo.svg +14 -14
- package/dist/index.html +58 -58
- package/dist/landing.html +268 -268
- package/dist/llms-full.txt +119 -119
- package/dist/llms.txt +53 -53
- package/dist/manifest.json +60 -60
- package/dist/openapi.yaml +1696 -1696
- package/dist/orchestration.html +125 -125
- package/dist/robots.txt +4 -4
- package/dist/site.css +692 -692
- package/dist/sitemap.xml +51 -51
- package/dist/sw.js +132 -132
- package/dist-server/server/cli.js +100 -100
- package/dist-server/server/daemon/manager.js +33 -33
- package/dist-server/server/daemon-manager.js +64 -64
- package/dist-server/server/routes/commands.js +25 -25
- package/dist-server/server/routes/git.js +17 -17
- package/dist-server/server/routes/live-view.js +46 -46
- package/dist-server/server/services/public-api-manifest.js +51 -51
- package/package.json +224 -224
- package/scripts/fix-node-pty.js +67 -67
- package/scripts/github/create-v1.38-issues.mjs +351 -351
- package/scripts/github/create-vscode-workbench-issues.mjs +121 -121
- package/scripts/smoke/backend-resource-bounds.mjs +152 -152
- package/scripts/smoke/changes-panel-layout.mjs +48 -48
- package/scripts/smoke/chat-composer-fixed-layout.mjs +55 -55
- package/scripts/smoke/chat-message-timeline-order.mjs +41 -41
- package/scripts/smoke/chat-realtime-hydration.mjs +44 -44
- package/scripts/smoke/chat-session-provider-pools.mjs +35 -35
- package/scripts/smoke/chat-session-state.mjs +19 -19
- package/scripts/smoke/code-editor-theme.mjs +55 -55
- package/scripts/smoke/code-editor-vscode-engine.mjs +91 -91
- package/scripts/smoke/command-center-agent-writes.mjs +79 -79
- package/scripts/smoke/command-center-non-git.mjs +46 -46
- package/scripts/smoke/context-packet.mjs +43 -43
- package/scripts/smoke/control-room-ux-redesign.mjs +91 -91
- package/scripts/smoke/daemon-entrypoint.mjs +20 -20
- package/scripts/smoke/default-landing-routing.mjs +33 -33
- package/scripts/smoke/desktop-native-notifications.mjs +30 -30
- package/scripts/smoke/desktop-tray-icon.mjs +33 -33
- package/scripts/smoke/discord-release-workflow.mjs +24 -24
- package/scripts/smoke/git-install-update.mjs +255 -255
- package/scripts/smoke/handoff-artifact-protocol.mjs +50 -50
- package/scripts/smoke/live-view-diagnostics.mjs +53 -53
- package/scripts/smoke/live-view-environment.mjs +92 -92
- package/scripts/smoke/live-view-integration.mjs +450 -450
- package/scripts/smoke/mac-desktop-runtime.mjs +37 -37
- package/scripts/smoke/mobile-tunnel-guidance.mjs +29 -29
- package/scripts/smoke/mobile-ux.mjs +76 -76
- package/scripts/smoke/model-registry.mjs +36 -36
- package/scripts/smoke/multi-project-ui.mjs +45 -45
- package/scripts/smoke/multi-worker-slots.mjs +42 -42
- package/scripts/smoke/notification-center.mjs +87 -87
- package/scripts/smoke/notification-inapp-preference.mjs +23 -23
- package/scripts/smoke/notification-taxonomy.mjs +58 -58
- package/scripts/smoke/orchestration-api.mjs +172 -172
- package/scripts/smoke/orchestration-execution-dashboard.mjs +33 -33
- package/scripts/smoke/orchestration-live-run.mjs +176 -176
- package/scripts/smoke/orchestration-mobile-scroll.mjs +29 -29
- package/scripts/smoke/orchestration-model-sync.mjs +30 -30
- package/scripts/smoke/orchestration-permission-fallback.mjs +34 -34
- package/scripts/smoke/orchestration-runtime-guards.mjs +48 -48
- package/scripts/smoke/orchestration-user-facing-output.mjs +25 -25
- package/scripts/smoke/permission-policy.mjs +50 -50
- package/scripts/smoke/pixcode-workbench-1-48.mjs +167 -167
- package/scripts/smoke/provider-models-opencode-live.mjs +66 -66
- package/scripts/smoke/provider-rest-api.mjs +124 -124
- package/scripts/smoke/provider-selection-status.mjs +52 -52
- package/scripts/smoke/run-state-refresh.mjs +52 -52
- package/scripts/smoke/runtime-manager.mjs +99 -99
- package/scripts/smoke/shell-manual-disconnect.mjs +30 -30
- package/scripts/smoke/side-panel-editor-layout.mjs +34 -34
- package/scripts/smoke/static-root-routing.mjs +21 -21
- package/scripts/smoke/strict-handoff-compact.mjs +60 -60
- package/scripts/smoke/taskmaster-config.mjs +24 -24
- package/scripts/smoke/taskmaster-execution-telegram.mjs +3 -3
- package/scripts/smoke/taskmaster-onboarding.mjs +3 -3
- package/scripts/smoke/taskmaster-run-graph.mjs +3 -3
- package/scripts/smoke/telegram-control.mjs +331 -331
- package/scripts/smoke/tunnel-persistence.mjs +56 -56
- package/scripts/smoke/update-issue-progress.mjs +69 -69
- package/scripts/smoke/update-ux.mjs +55 -55
- package/scripts/smoke/v138-completion.mjs +132 -132
- package/scripts/smoke/v138-desktop-release-hardening.mjs +69 -69
- package/scripts/smoke/v138-diagnostics.mjs +63 -63
- package/scripts/smoke/v138-issue-planner.mjs +33 -33
- package/scripts/smoke/v143-remote-control.mjs +76 -76
- package/scripts/smoke/v144-production-loop.mjs +47 -47
- package/scripts/smoke/v145-platformization.mjs +46 -46
- package/scripts/smoke/v146-control-room-ui.mjs +150 -150
- package/scripts/smoke/version-modal-autoshow.mjs +29 -29
- package/scripts/smoke/vscode-workbench-layout.mjs +63 -63
- package/scripts/smoke/vscode-workbench-polish.mjs +461 -461
- package/scripts/smoke/workflow-fallback-replay.mjs +56 -56
- package/scripts/smoke/workflow-templates.mjs +43 -43
- package/scripts/smoke/workflow-trace-timeline.mjs +46 -46
- package/scripts/update-git-install.mjs +298 -298
- package/server/claude-sdk.js +927 -927
- package/server/cli.js +1106 -1106
- package/server/constants/config.js +4 -4
- package/server/cursor-cli.js +344 -344
- package/server/daemon/manager.js +563 -563
- package/server/daemon-manager.js +964 -964
- package/server/database/db.js +988 -988
- package/server/database/json-store.js +197 -197
- package/server/gemini-cli.js +550 -550
- package/server/gemini-response-handler.js +79 -79
- package/server/index.js +5671 -5671
- package/server/load-env.js +35 -35
- package/server/middleware/account-lockout.js +112 -112
- package/server/middleware/auth.js +277 -277
- package/server/middleware/rate-limiter.js +87 -87
- package/server/modules/orchestration/a2a/adapter-registry.ts +108 -108
- package/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.ts +63 -63
- package/server/modules/orchestration/a2a/adapters/claude-code.adapter.ts +286 -286
- package/server/modules/orchestration/a2a/adapters/codex.adapter.ts +244 -244
- package/server/modules/orchestration/a2a/adapters/cursor.adapter.ts +249 -249
- package/server/modules/orchestration/a2a/adapters/gemini.adapter.ts +248 -248
- package/server/modules/orchestration/a2a/adapters/json-event.adapter.test.ts +60 -60
- package/server/modules/orchestration/a2a/adapters/json-event.adapter.ts +101 -101
- package/server/modules/orchestration/a2a/adapters/opencode.adapter.ts +248 -248
- package/server/modules/orchestration/a2a/adapters/qwen.adapter.ts +248 -248
- package/server/modules/orchestration/a2a/agent-card.ts +55 -55
- package/server/modules/orchestration/a2a/auth.middleware.ts +29 -29
- package/server/modules/orchestration/a2a/bus.ts +46 -46
- package/server/modules/orchestration/a2a/routes.ts +586 -586
- package/server/modules/orchestration/a2a/task-dispatcher.ts +345 -345
- package/server/modules/orchestration/a2a/task-store.ts +178 -178
- package/server/modules/orchestration/a2a/types.ts +126 -126
- package/server/modules/orchestration/a2a/validator.ts +113 -113
- package/server/modules/orchestration/index.ts +99 -99
- package/server/modules/orchestration/preview/port-watcher.ts +112 -112
- package/server/modules/orchestration/preview/preview-proxy.ts +60 -60
- package/server/modules/orchestration/preview/types.ts +19 -19
- package/server/modules/orchestration/security/permission-policy.ts +401 -401
- package/server/modules/orchestration/tasks/orchestration-task-store.ts +41 -41
- package/server/modules/orchestration/tasks/orchestration-task.routes.ts +81 -81
- package/server/modules/orchestration/tasks/orchestration-task.service.ts +201 -201
- package/server/modules/orchestration/tasks/orchestration-task.types.ts +40 -40
- package/server/modules/orchestration/tasks/task-run-graph.ts +155 -155
- package/server/modules/orchestration/workflows/approval-queue.ts +106 -106
- package/server/modules/orchestration/workflows/built-in-workflows.ts +127 -127
- package/server/modules/orchestration/workflows/context-packet.ts +186 -186
- package/server/modules/orchestration/workflows/handoff-artifact.ts +175 -175
- package/server/modules/orchestration/workflows/workflow-fallback-policy.ts +161 -161
- package/server/modules/orchestration/workflows/workflow-replay.ts +254 -254
- package/server/modules/orchestration/workflows/workflow-runner.ts +2062 -2062
- package/server/modules/orchestration/workflows/workflow-store.ts +97 -97
- package/server/modules/orchestration/workflows/workflow-templates.ts +272 -272
- package/server/modules/orchestration/workflows/workflow-trace.ts +424 -424
- package/server/modules/orchestration/workflows/workflow.routes.ts +586 -586
- package/server/modules/orchestration/workflows/workflow.types.ts +111 -111
- package/server/modules/orchestration/workflows/workspace-target.ts +122 -122
- package/server/modules/orchestration/workspace/docker-workspace.ts +136 -136
- package/server/modules/orchestration/workspace/path-safety.ts +55 -55
- package/server/modules/orchestration/workspace/types.ts +52 -52
- package/server/modules/orchestration/workspace/workspace-manager.ts +102 -102
- package/server/modules/orchestration/workspace/worktree-workspace.ts +126 -126
- package/server/modules/providers/index.ts +2 -2
- package/server/modules/providers/list/claude/claude-auth.provider.ts +146 -146
- package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -135
- package/server/modules/providers/list/claude/claude-sessions.provider.ts +306 -306
- package/server/modules/providers/list/claude/claude.provider.ts +15 -15
- package/server/modules/providers/list/codex/codex-auth.provider.ts +117 -117
- package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -135
- package/server/modules/providers/list/codex/codex-sessions.provider.ts +319 -319
- package/server/modules/providers/list/codex/codex.provider.ts +15 -15
- package/server/modules/providers/list/cursor/cursor-auth.provider.ts +147 -147
- package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -108
- package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +421 -421
- package/server/modules/providers/list/cursor/cursor.provider.ts +15 -15
- package/server/modules/providers/list/gemini/gemini-auth.provider.ts +173 -173
- package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -110
- package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +227 -227
- package/server/modules/providers/list/gemini/gemini.provider.ts +15 -15
- package/server/modules/providers/list/opencode/opencode-auth.provider.ts +131 -131
- package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +286 -286
- package/server/modules/providers/list/qwen/qwen-auth.provider.ts +146 -146
- package/server/modules/providers/list/qwen/qwen-sessions.provider.ts +265 -265
- package/server/modules/providers/provider.registry.ts +40 -40
- package/server/modules/providers/provider.routes.ts +982 -982
- package/server/modules/providers/services/mcp.service.ts +86 -86
- package/server/modules/providers/services/provider-auth.service.ts +26 -26
- package/server/modules/providers/services/sessions.service.ts +45 -45
- package/server/modules/providers/shared/base/abstract.provider.ts +20 -20
- package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -151
- package/server/modules/providers/tests/mcp.test.ts +293 -293
- package/server/openai-codex.js +468 -468
- package/server/opencode-cli.js +491 -491
- package/server/opencode-response-handler.js +111 -111
- package/server/projects.js +3135 -3135
- package/server/qwen-code-cli.js +410 -410
- package/server/routes/agent.js +1462 -1462
- package/server/routes/auth.js +298 -298
- package/server/routes/codex.js +20 -20
- package/server/routes/commands.js +581 -581
- package/server/routes/cursor.js +61 -61
- package/server/routes/diagnostics.js +44 -44
- package/server/routes/gemini.js +25 -25
- package/server/routes/git.js +1822 -1822
- package/server/routes/live-view.js +434 -434
- package/server/routes/mcp-utils.js +13 -13
- package/server/routes/messages.js +97 -97
- package/server/routes/network.js +143 -143
- package/server/routes/platformization.js +231 -231
- package/server/routes/plugins.js +690 -690
- package/server/routes/production-agent-loop.js +90 -90
- package/server/routes/projects.js +918 -918
- package/server/routes/public-api.js +34 -34
- package/server/routes/qwen.js +27 -27
- package/server/routes/remote.js +56 -56
- package/server/routes/settings.js +321 -321
- package/server/routes/telegram.js +163 -163
- package/server/routes/user.js +125 -125
- package/server/routes/webhooks.js +63 -63
- package/server/services/control-room.js +102 -102
- package/server/services/diagnostics.js +165 -165
- package/server/services/external-access.js +403 -403
- package/server/services/install-jobs.js +715 -715
- package/server/services/live-view.js +956 -956
- package/server/services/managed-runtimes.js +493 -493
- package/server/services/model-registry.js +144 -144
- package/server/services/notification-orchestrator.js +365 -365
- package/server/services/notification-taxonomy.js +204 -204
- package/server/services/platformization.js +1052 -1052
- package/server/services/production-agent-loop.js +248 -248
- package/server/services/provider-cli-versions.js +149 -149
- package/server/services/provider-credentials.js +189 -189
- package/server/services/provider-models.js +396 -396
- package/server/services/public-api-manifest.js +181 -181
- package/server/services/qr-login.js +126 -126
- package/server/services/remote-connection.js +127 -127
- package/server/services/runtime-manager.js +323 -323
- package/server/services/startup-update.js +259 -259
- package/server/services/telegram/bot.js +393 -393
- package/server/services/telegram/control-center.js +2453 -2453
- package/server/services/telegram/telegram-gateway.js +314 -314
- package/server/services/telegram/telegram-http-client.js +201 -201
- package/server/services/telegram/translations.js +470 -470
- package/server/services/webhooks.js +216 -216
- package/server/sessionManager.js +225 -225
- package/server/setup-wizard.js +283 -283
- package/server/shared/interfaces.ts +54 -54
- package/server/shared/types.ts +172 -172
- package/server/shared/utils.ts +193 -193
- package/server/tsconfig.json +36 -36
- package/server/utils/colors.js +21 -21
- package/server/utils/commandParser.js +305 -305
- package/server/utils/frontmatter.js +18 -18
- package/server/utils/gitConfig.js +34 -34
- package/server/utils/plugin-loader.js +461 -461
- package/server/utils/plugin-process-manager.js +185 -185
- package/server/utils/port-access.js +227 -227
- package/server/utils/runtime-paths.js +37 -37
- package/server/utils/security-log.js +84 -84
- package/server/utils/url-detection.js +71 -71
- package/server/vite-daemon.js +79 -79
- package/shared/modelConstants.js +161 -161
- package/shared/networkHosts.js +22 -22
|
@@ -1,87 +1,87 @@
|
|
|
1
|
-
import { securityLog, getClientIp } from '../utils/security-log.js';
|
|
2
|
-
|
|
3
|
-
function createRateLimiter(options = {}) {
|
|
4
|
-
const {
|
|
5
|
-
windowMs = 15 * 60 * 1000,
|
|
6
|
-
max = 100,
|
|
7
|
-
keyGenerator = (req) => getClientIp(req),
|
|
8
|
-
message = 'Too many requests from this IP, please try again later.',
|
|
9
|
-
statusCode = 429,
|
|
10
|
-
skip = (_req) => false,
|
|
11
|
-
} = options;
|
|
12
|
-
|
|
13
|
-
const hits = new Map();
|
|
14
|
-
|
|
15
|
-
function cleanupExpired() {
|
|
16
|
-
const now = Date.now();
|
|
17
|
-
for (const [key, entry] of hits.entries()) {
|
|
18
|
-
if (entry.resetTime <= now) {
|
|
19
|
-
hits.delete(key);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const cleanupInterval = setInterval(cleanupExpired, windowMs);
|
|
25
|
-
cleanupInterval.unref();
|
|
26
|
-
|
|
27
|
-
return (req, res, next) => {
|
|
28
|
-
if (skip(req)) {
|
|
29
|
-
return next();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const key = keyGenerator(req);
|
|
33
|
-
const now = Date.now();
|
|
34
|
-
|
|
35
|
-
let entry = hits.get(key);
|
|
36
|
-
if (!entry || entry.resetTime <= now) {
|
|
37
|
-
entry = {
|
|
38
|
-
count: 0,
|
|
39
|
-
resetTime: now + windowMs,
|
|
40
|
-
};
|
|
41
|
-
hits.set(key, entry);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
entry.count += 1;
|
|
45
|
-
|
|
46
|
-
res.setHeader('X-RateLimit-Limit', String(max));
|
|
47
|
-
res.setHeader('X-RateLimit-Remaining', String(Math.max(0, max - entry.count)));
|
|
48
|
-
res.setHeader('X-RateLimit-Reset', String(Math.ceil(entry.resetTime / 1000)));
|
|
49
|
-
|
|
50
|
-
if (entry.count > max) {
|
|
51
|
-
securityLog('rate_limit_exceeded', {
|
|
52
|
-
ip: getClientIp(req),
|
|
53
|
-
endpoint: req.path,
|
|
54
|
-
method: req.method,
|
|
55
|
-
userAgent: req.headers['user-agent'],
|
|
56
|
-
});
|
|
57
|
-
return res.status(statusCode).json({
|
|
58
|
-
success: false,
|
|
59
|
-
error: {
|
|
60
|
-
code: 'RATE_LIMIT_EXCEEDED',
|
|
61
|
-
message,
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
next();
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export const authRateLimiter = createRateLimiter({
|
|
71
|
-
windowMs: 15 * 60 * 1000,
|
|
72
|
-
max: 10,
|
|
73
|
-
message: 'Too many authentication attempts. Please try again in 15 minutes.',
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// API rate limiter: only limits state-changing operations (POST/PUT/DELETE/PATCH).
|
|
77
|
-
// GET requests (polling, fetching sessions, file trees, update-state, etc.) are
|
|
78
|
-
// exempt — the frontend polls several endpoints frequently and 120/min was
|
|
79
|
-
// too low, causing false "rate limit" errors on active sessions.
|
|
80
|
-
export const apiRateLimiter = createRateLimiter({
|
|
81
|
-
windowMs: 60 * 1000,
|
|
82
|
-
max: 300,
|
|
83
|
-
message: 'Too many API requests. Please slow down.',
|
|
84
|
-
skip: (req) => req.method === 'GET' || req.method === 'HEAD' || req.method === 'OPTIONS',
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
export { createRateLimiter };
|
|
1
|
+
import { securityLog, getClientIp } from '../utils/security-log.js';
|
|
2
|
+
|
|
3
|
+
function createRateLimiter(options = {}) {
|
|
4
|
+
const {
|
|
5
|
+
windowMs = 15 * 60 * 1000,
|
|
6
|
+
max = 100,
|
|
7
|
+
keyGenerator = (req) => getClientIp(req),
|
|
8
|
+
message = 'Too many requests from this IP, please try again later.',
|
|
9
|
+
statusCode = 429,
|
|
10
|
+
skip = (_req) => false,
|
|
11
|
+
} = options;
|
|
12
|
+
|
|
13
|
+
const hits = new Map();
|
|
14
|
+
|
|
15
|
+
function cleanupExpired() {
|
|
16
|
+
const now = Date.now();
|
|
17
|
+
for (const [key, entry] of hits.entries()) {
|
|
18
|
+
if (entry.resetTime <= now) {
|
|
19
|
+
hits.delete(key);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const cleanupInterval = setInterval(cleanupExpired, windowMs);
|
|
25
|
+
cleanupInterval.unref();
|
|
26
|
+
|
|
27
|
+
return (req, res, next) => {
|
|
28
|
+
if (skip(req)) {
|
|
29
|
+
return next();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const key = keyGenerator(req);
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
|
|
35
|
+
let entry = hits.get(key);
|
|
36
|
+
if (!entry || entry.resetTime <= now) {
|
|
37
|
+
entry = {
|
|
38
|
+
count: 0,
|
|
39
|
+
resetTime: now + windowMs,
|
|
40
|
+
};
|
|
41
|
+
hits.set(key, entry);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
entry.count += 1;
|
|
45
|
+
|
|
46
|
+
res.setHeader('X-RateLimit-Limit', String(max));
|
|
47
|
+
res.setHeader('X-RateLimit-Remaining', String(Math.max(0, max - entry.count)));
|
|
48
|
+
res.setHeader('X-RateLimit-Reset', String(Math.ceil(entry.resetTime / 1000)));
|
|
49
|
+
|
|
50
|
+
if (entry.count > max) {
|
|
51
|
+
securityLog('rate_limit_exceeded', {
|
|
52
|
+
ip: getClientIp(req),
|
|
53
|
+
endpoint: req.path,
|
|
54
|
+
method: req.method,
|
|
55
|
+
userAgent: req.headers['user-agent'],
|
|
56
|
+
});
|
|
57
|
+
return res.status(statusCode).json({
|
|
58
|
+
success: false,
|
|
59
|
+
error: {
|
|
60
|
+
code: 'RATE_LIMIT_EXCEEDED',
|
|
61
|
+
message,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
next();
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const authRateLimiter = createRateLimiter({
|
|
71
|
+
windowMs: 15 * 60 * 1000,
|
|
72
|
+
max: 10,
|
|
73
|
+
message: 'Too many authentication attempts. Please try again in 15 minutes.',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// API rate limiter: only limits state-changing operations (POST/PUT/DELETE/PATCH).
|
|
77
|
+
// GET requests (polling, fetching sessions, file trees, update-state, etc.) are
|
|
78
|
+
// exempt — the frontend polls several endpoints frequently and 120/min was
|
|
79
|
+
// too low, causing false "rate limit" errors on active sessions.
|
|
80
|
+
export const apiRateLimiter = createRateLimiter({
|
|
81
|
+
windowMs: 60 * 1000,
|
|
82
|
+
max: 300,
|
|
83
|
+
message: 'Too many API requests. Please slow down.',
|
|
84
|
+
skip: (req) => req.method === 'GET' || req.method === 'HEAD' || req.method === 'OPTIONS',
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
export { createRateLimiter };
|
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
// server/modules/orchestration/a2a/adapter-registry.ts
|
|
2
|
-
// In-process registry mapping adapter ids to AbstractA2AAdapter
|
|
3
|
-
// instances. Resolution supports three id forms:
|
|
4
|
-
// - "claude-code" explicit
|
|
5
|
-
// - "skill:<skillId>" first REGISTERED adapter advertising that skill
|
|
6
|
-
// (Map iteration is insertion-ordered per ES spec).
|
|
7
|
-
// - "auto" first registered adapter (deterministic fallback
|
|
8
|
-
// until smarter routing arrives in a later plan)
|
|
9
|
-
|
|
10
|
-
import type { AbstractA2AAdapter } from '@/modules/orchestration/a2a/adapters/abstract-a2a.adapter.js';
|
|
11
|
-
import type { AgentCard } from '@/modules/orchestration/a2a/types.js';
|
|
12
|
-
|
|
13
|
-
interface ResolveAdapterOptions {
|
|
14
|
-
preferredAdapterId?: string;
|
|
15
|
-
preferredProvider?: string;
|
|
16
|
-
preferredSkillId?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
class AdapterRegistry {
|
|
20
|
-
// Map iteration order is insertion-ordered (ES spec); auto and skill: resolution depend on this.
|
|
21
|
-
private readonly byId = new Map<string, AbstractA2AAdapter>();
|
|
22
|
-
|
|
23
|
-
register(adapter: AbstractA2AAdapter): void {
|
|
24
|
-
if (this.byId.has(adapter.id)) {
|
|
25
|
-
throw new Error(`A2A adapter already registered: ${adapter.id}`);
|
|
26
|
-
}
|
|
27
|
-
this.byId.set(adapter.id, adapter);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
get(id: string): AbstractA2AAdapter | undefined {
|
|
31
|
-
return this.byId.get(id);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
resolve(idOrSelector: string, options: ResolveAdapterOptions = {}): AbstractA2AAdapter | undefined {
|
|
35
|
-
const normalizedSelector = idOrSelector.trim();
|
|
36
|
-
if (!normalizedSelector) {
|
|
37
|
-
return undefined;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (normalizedSelector === 'auto') {
|
|
41
|
-
return this.pickPreferred(this.list(), options);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (normalizedSelector.startsWith('skill:')) {
|
|
45
|
-
const skill = normalizedSelector.slice('skill:'.length);
|
|
46
|
-
const matches = this.list().filter((adapter) =>
|
|
47
|
-
adapter.agentCard.skills.some((s) => s.id === skill),
|
|
48
|
-
);
|
|
49
|
-
if (matches.length === 0) {
|
|
50
|
-
return undefined;
|
|
51
|
-
}
|
|
52
|
-
return this.pickPreferred(matches, {
|
|
53
|
-
...options,
|
|
54
|
-
preferredSkillId: options.preferredSkillId ?? skill,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return this.byId.get(normalizedSelector);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
list(): AbstractA2AAdapter[] {
|
|
62
|
-
return [...this.byId.values()];
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
agentCards(): AgentCard[] {
|
|
66
|
-
return this.list().map((a) => a.agentCard);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
private pickPreferred(
|
|
70
|
-
adapters: AbstractA2AAdapter[],
|
|
71
|
-
options: ResolveAdapterOptions,
|
|
72
|
-
): AbstractA2AAdapter | undefined {
|
|
73
|
-
const {
|
|
74
|
-
preferredAdapterId,
|
|
75
|
-
preferredProvider,
|
|
76
|
-
preferredSkillId,
|
|
77
|
-
} = options;
|
|
78
|
-
|
|
79
|
-
if (preferredAdapterId) {
|
|
80
|
-
const byAdapterId = adapters.find((adapter) => adapter.id === preferredAdapterId);
|
|
81
|
-
if (byAdapterId) {
|
|
82
|
-
return byAdapterId;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (preferredProvider) {
|
|
87
|
-
const normalizedProvider = preferredProvider.trim().toLowerCase();
|
|
88
|
-
const byProvider = adapters.find((adapter) => adapter.id === normalizedProvider);
|
|
89
|
-
if (byProvider) {
|
|
90
|
-
return byProvider;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (preferredSkillId) {
|
|
95
|
-
const bySkill = adapters.find((adapter) =>
|
|
96
|
-
adapter.agentCard.skills.some((skill) => skill.id === preferredSkillId),
|
|
97
|
-
);
|
|
98
|
-
if (bySkill) {
|
|
99
|
-
return bySkill;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return adapters[0];
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export const adapterRegistry = new AdapterRegistry();
|
|
108
|
-
export type { AdapterRegistry, ResolveAdapterOptions };
|
|
1
|
+
// server/modules/orchestration/a2a/adapter-registry.ts
|
|
2
|
+
// In-process registry mapping adapter ids to AbstractA2AAdapter
|
|
3
|
+
// instances. Resolution supports three id forms:
|
|
4
|
+
// - "claude-code" explicit
|
|
5
|
+
// - "skill:<skillId>" first REGISTERED adapter advertising that skill
|
|
6
|
+
// (Map iteration is insertion-ordered per ES spec).
|
|
7
|
+
// - "auto" first registered adapter (deterministic fallback
|
|
8
|
+
// until smarter routing arrives in a later plan)
|
|
9
|
+
|
|
10
|
+
import type { AbstractA2AAdapter } from '@/modules/orchestration/a2a/adapters/abstract-a2a.adapter.js';
|
|
11
|
+
import type { AgentCard } from '@/modules/orchestration/a2a/types.js';
|
|
12
|
+
|
|
13
|
+
interface ResolveAdapterOptions {
|
|
14
|
+
preferredAdapterId?: string;
|
|
15
|
+
preferredProvider?: string;
|
|
16
|
+
preferredSkillId?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class AdapterRegistry {
|
|
20
|
+
// Map iteration order is insertion-ordered (ES spec); auto and skill: resolution depend on this.
|
|
21
|
+
private readonly byId = new Map<string, AbstractA2AAdapter>();
|
|
22
|
+
|
|
23
|
+
register(adapter: AbstractA2AAdapter): void {
|
|
24
|
+
if (this.byId.has(adapter.id)) {
|
|
25
|
+
throw new Error(`A2A adapter already registered: ${adapter.id}`);
|
|
26
|
+
}
|
|
27
|
+
this.byId.set(adapter.id, adapter);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get(id: string): AbstractA2AAdapter | undefined {
|
|
31
|
+
return this.byId.get(id);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
resolve(idOrSelector: string, options: ResolveAdapterOptions = {}): AbstractA2AAdapter | undefined {
|
|
35
|
+
const normalizedSelector = idOrSelector.trim();
|
|
36
|
+
if (!normalizedSelector) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (normalizedSelector === 'auto') {
|
|
41
|
+
return this.pickPreferred(this.list(), options);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (normalizedSelector.startsWith('skill:')) {
|
|
45
|
+
const skill = normalizedSelector.slice('skill:'.length);
|
|
46
|
+
const matches = this.list().filter((adapter) =>
|
|
47
|
+
adapter.agentCard.skills.some((s) => s.id === skill),
|
|
48
|
+
);
|
|
49
|
+
if (matches.length === 0) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
return this.pickPreferred(matches, {
|
|
53
|
+
...options,
|
|
54
|
+
preferredSkillId: options.preferredSkillId ?? skill,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return this.byId.get(normalizedSelector);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
list(): AbstractA2AAdapter[] {
|
|
62
|
+
return [...this.byId.values()];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
agentCards(): AgentCard[] {
|
|
66
|
+
return this.list().map((a) => a.agentCard);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private pickPreferred(
|
|
70
|
+
adapters: AbstractA2AAdapter[],
|
|
71
|
+
options: ResolveAdapterOptions,
|
|
72
|
+
): AbstractA2AAdapter | undefined {
|
|
73
|
+
const {
|
|
74
|
+
preferredAdapterId,
|
|
75
|
+
preferredProvider,
|
|
76
|
+
preferredSkillId,
|
|
77
|
+
} = options;
|
|
78
|
+
|
|
79
|
+
if (preferredAdapterId) {
|
|
80
|
+
const byAdapterId = adapters.find((adapter) => adapter.id === preferredAdapterId);
|
|
81
|
+
if (byAdapterId) {
|
|
82
|
+
return byAdapterId;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (preferredProvider) {
|
|
87
|
+
const normalizedProvider = preferredProvider.trim().toLowerCase();
|
|
88
|
+
const byProvider = adapters.find((adapter) => adapter.id === normalizedProvider);
|
|
89
|
+
if (byProvider) {
|
|
90
|
+
return byProvider;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (preferredSkillId) {
|
|
95
|
+
const bySkill = adapters.find((adapter) =>
|
|
96
|
+
adapter.agentCard.skills.some((skill) => skill.id === preferredSkillId),
|
|
97
|
+
);
|
|
98
|
+
if (bySkill) {
|
|
99
|
+
return bySkill;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return adapters[0];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const adapterRegistry = new AdapterRegistry();
|
|
108
|
+
export type { AdapterRegistry, ResolveAdapterOptions };
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
// server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.ts
|
|
2
|
-
// Base class every CLI adapter extends. Adapters wrap the
|
|
3
|
-
// existing per-CLI runtime files (claude-sdk.js, openai-codex.js, ...)
|
|
4
|
-
// and translate between A2A messages and the CLI's native I/O.
|
|
5
|
-
|
|
6
|
-
import { a2aBus } from '@/modules/orchestration/a2a/bus.js';
|
|
7
|
-
import type {
|
|
8
|
-
AgentCard,
|
|
9
|
-
Artifact,
|
|
10
|
-
Message,
|
|
11
|
-
Task,
|
|
12
|
-
TaskError,
|
|
13
|
-
TaskState,
|
|
14
|
-
} from '@/modules/orchestration/a2a/types.js';
|
|
15
|
-
import type { WorkspaceHandle } from '@/modules/orchestration/workspace/types.js';
|
|
16
|
-
import type {
|
|
17
|
-
PermissionPolicy,
|
|
18
|
-
PermissionPolicyContext,
|
|
19
|
-
} from '@/modules/orchestration/security/permission-policy.js';
|
|
20
|
-
|
|
21
|
-
export interface AdapterContext {
|
|
22
|
-
/** Isolated execution workspace for the task. */
|
|
23
|
-
workspace: WorkspaceHandle;
|
|
24
|
-
/** Compatibility alias while legacy adapters still accept cwd directly. */
|
|
25
|
-
cwd: string;
|
|
26
|
-
/** pixcode permission mode passed through to the underlying CLI. */
|
|
27
|
-
permissionMode?: string;
|
|
28
|
-
/** Provider-independent permission/sandbox policy evaluated before runtime tool use. */
|
|
29
|
-
permissionPolicy?: PermissionPolicy;
|
|
30
|
-
/** Run context preserved when the policy needs a human approval. */
|
|
31
|
-
permissionPolicyContext?: PermissionPolicyContext;
|
|
32
|
-
/** Provider model selected by the user in Pixcode. */
|
|
33
|
-
model?: string;
|
|
34
|
-
/** Provider-specific tool / permission settings from Pixcode Settings. */
|
|
35
|
-
toolsSettings?: Record<string, unknown>;
|
|
36
|
-
/** Optional parent task id when this adapter is invoked inside a workflow. */
|
|
37
|
-
parentTaskId?: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface TaskHandle {
|
|
41
|
-
cancel(): Promise<void>;
|
|
42
|
-
finished: Promise<void>;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export abstract class AbstractA2AAdapter {
|
|
46
|
-
abstract readonly id: string;
|
|
47
|
-
abstract readonly agentCard: AgentCard;
|
|
48
|
-
|
|
49
|
-
abstract submitTask(task: Task, ctx: AdapterContext): Promise<TaskHandle>;
|
|
50
|
-
abstract cancelTask(taskId: string): Promise<void>;
|
|
51
|
-
|
|
52
|
-
protected emitState(taskId: string, state: TaskState, error?: TaskError): void {
|
|
53
|
-
a2aBus.publish({ kind: 'task-state', taskId, state, error });
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
protected emitMessage(taskId: string, message: Message): void {
|
|
57
|
-
a2aBus.publish({ kind: 'message', taskId, message });
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
protected emitArtifact(taskId: string, artifact: Artifact): void {
|
|
61
|
-
a2aBus.publish({ kind: 'artifact', taskId, artifact });
|
|
62
|
-
}
|
|
63
|
-
}
|
|
1
|
+
// server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.ts
|
|
2
|
+
// Base class every CLI adapter extends. Adapters wrap the
|
|
3
|
+
// existing per-CLI runtime files (claude-sdk.js, openai-codex.js, ...)
|
|
4
|
+
// and translate between A2A messages and the CLI's native I/O.
|
|
5
|
+
|
|
6
|
+
import { a2aBus } from '@/modules/orchestration/a2a/bus.js';
|
|
7
|
+
import type {
|
|
8
|
+
AgentCard,
|
|
9
|
+
Artifact,
|
|
10
|
+
Message,
|
|
11
|
+
Task,
|
|
12
|
+
TaskError,
|
|
13
|
+
TaskState,
|
|
14
|
+
} from '@/modules/orchestration/a2a/types.js';
|
|
15
|
+
import type { WorkspaceHandle } from '@/modules/orchestration/workspace/types.js';
|
|
16
|
+
import type {
|
|
17
|
+
PermissionPolicy,
|
|
18
|
+
PermissionPolicyContext,
|
|
19
|
+
} from '@/modules/orchestration/security/permission-policy.js';
|
|
20
|
+
|
|
21
|
+
export interface AdapterContext {
|
|
22
|
+
/** Isolated execution workspace for the task. */
|
|
23
|
+
workspace: WorkspaceHandle;
|
|
24
|
+
/** Compatibility alias while legacy adapters still accept cwd directly. */
|
|
25
|
+
cwd: string;
|
|
26
|
+
/** pixcode permission mode passed through to the underlying CLI. */
|
|
27
|
+
permissionMode?: string;
|
|
28
|
+
/** Provider-independent permission/sandbox policy evaluated before runtime tool use. */
|
|
29
|
+
permissionPolicy?: PermissionPolicy;
|
|
30
|
+
/** Run context preserved when the policy needs a human approval. */
|
|
31
|
+
permissionPolicyContext?: PermissionPolicyContext;
|
|
32
|
+
/** Provider model selected by the user in Pixcode. */
|
|
33
|
+
model?: string;
|
|
34
|
+
/** Provider-specific tool / permission settings from Pixcode Settings. */
|
|
35
|
+
toolsSettings?: Record<string, unknown>;
|
|
36
|
+
/** Optional parent task id when this adapter is invoked inside a workflow. */
|
|
37
|
+
parentTaskId?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface TaskHandle {
|
|
41
|
+
cancel(): Promise<void>;
|
|
42
|
+
finished: Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export abstract class AbstractA2AAdapter {
|
|
46
|
+
abstract readonly id: string;
|
|
47
|
+
abstract readonly agentCard: AgentCard;
|
|
48
|
+
|
|
49
|
+
abstract submitTask(task: Task, ctx: AdapterContext): Promise<TaskHandle>;
|
|
50
|
+
abstract cancelTask(taskId: string): Promise<void>;
|
|
51
|
+
|
|
52
|
+
protected emitState(taskId: string, state: TaskState, error?: TaskError): void {
|
|
53
|
+
a2aBus.publish({ kind: 'task-state', taskId, state, error });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
protected emitMessage(taskId: string, message: Message): void {
|
|
57
|
+
a2aBus.publish({ kind: 'message', taskId, message });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
protected emitArtifact(taskId: string, artifact: Artifact): void {
|
|
61
|
+
a2aBus.publish({ kind: 'artifact', taskId, artifact });
|
|
62
|
+
}
|
|
63
|
+
}
|