@akira-tl/forgerelay 0.8.7 → 0.8.9
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/CHANGELOG.md +18 -0
- package/README.md +10 -18
- package/capabilities/host-integration/GUIDE.md +2 -2
- package/dist/activity/{audit-store.js → history/audit-store.js} +129 -21
- package/dist/activity/history/bash-output-store.js +250 -0
- package/dist/activity/{host-turn-store.js → history/host-turn-store.js} +4 -1
- package/dist/activity/{query-service.js → history/query-service.js} +13 -7
- package/dist/activity/{lifecycle.js → runtime/lifecycle.js} +1 -1
- package/dist/activity/{mcp-query-tools.js → runtime/mcp-query-tools.js} +3 -3
- package/dist/activity/storage/history.js +12 -0
- package/dist/activity/storage/paths.js +56 -0
- package/dist/activity/storage/segmented-log.js +149 -0
- package/dist/cli/setup-support.js +116 -0
- package/dist/cli.js +18 -126
- package/dist/lsp/code-intelligence.js +1 -1
- package/dist/lsp/test-support/server-fixture.js +9 -9
- package/dist/mcp/filesystem/filesystem-tools.js +245 -0
- package/dist/mcp/hooks/command-runner.js +79 -0
- package/dist/{hook-cli.js → mcp/hooks/hook-cli.js} +1 -1
- package/dist/{hooks.js → mcp/hooks/hooks.js} +3 -80
- package/dist/{oauth-provider.js → mcp/oauth/oauth-provider.js} +1 -1
- package/dist/{oauth-store.js → mcp/oauth/oauth-store.js} +5 -4
- package/dist/{operations → mcp/operations}/native-bulk-mutations.js +2 -2
- package/dist/mcp/panel/app.js +143 -0
- package/dist/{mcp-app-template.js → mcp/panel/mcp-app-template.js} +2 -38
- package/dist/mcp/process/runtime.js +257 -0
- package/dist/mcp/process/tools.js +346 -0
- package/dist/mcp/server/core/activity-support.js +70 -0
- package/dist/{capabilities.js → mcp/server/core/capabilities.js} +5 -3
- package/dist/{capability-registry.js → mcp/server/core/capability-registry.js} +2 -2
- package/dist/mcp/server/core/capability-support.js +90 -0
- package/dist/mcp/server/core/schemas.js +216 -0
- package/dist/mcp/server/core/tool-support.js +207 -0
- package/dist/mcp/server/core/version.js +9 -0
- package/dist/mcp/server/operations/runtime/filesystem-tools.js +400 -0
- package/dist/mcp/server/operations/runtime/operation-runtime.js +523 -0
- package/dist/mcp/server/transport/http-server.js +301 -0
- package/dist/mcp/server/transport/http-support.js +43 -0
- package/dist/mcp/server/workspace/runtime/workspace-open-presentation.js +222 -0
- package/dist/mcp/server/workspace/runtime/workspace-open-schema.js +187 -0
- package/dist/mcp/server/workspace/runtime/workspace-open.js +552 -0
- package/dist/mcp/server/workspace/runtime/workspace-tools.js +601 -0
- package/dist/{config.js → runtime/config/config.js} +3 -3
- package/dist/{user-config.js → runtime/config/user-config.js} +14 -54
- package/dist/{db → runtime/state/db}/client.js +1 -1
- package/dist/{db → runtime/state/db}/migrations.js +34 -3
- package/dist/runtime/state/lock/file-lock.js +130 -0
- package/dist/runtime/testing/server-fixture.js +190 -0
- package/dist/server.js +139 -4192
- package/dist/subagents/providers/adapters/claude.js +86 -52
- package/dist/subagents/providers/adapters/codex.js +103 -39
- package/dist/subagents/providers/adapters/opencode.js +114 -84
- package/dist/subagents/providers/adapters/pi.js +59 -8
- package/dist/subagents/providers/availability.js +15 -30
- package/dist/subagents/providers/runtime/external-command.js +56 -0
- package/dist/subagents/sessions/capability.js +1 -1
- package/dist/subagents/sessions/execution.js +1 -1
- package/dist/subagents/sessions/mcp/activity-audit-test-support.js +30 -0
- package/dist/subagents/sessions/store.js +1 -1
- package/dist/ui/.vite/manifest.json +342 -409
- package/dist/ui/activity-panel-app.html +2 -4
- package/dist/ui/assets/activity-panel-app-7Xe0alhm.css +1 -0
- package/dist/ui/assets/activity-panel-app-Sl1Jro8v.js +115 -0
- package/dist/ui/assets/angular-html-B_yn91wW.js +1 -0
- package/dist/ui/assets/{angular-ts-Bxh4-O1-.js → angular-ts-DSgtloKz.js} +1 -1
- package/dist/ui/assets/{apl-BmYHKQ6m.js → apl-NatWtF8X.js} +1 -1
- package/dist/ui/assets/{astro-C51vqDKq.js → astro-BYFEVBuN.js} +1 -1
- package/dist/ui/assets/{blade-CdhVsmwq.js → blade-DoO7yvMR.js} +1 -1
- package/dist/ui/assets/c-Rl2hMCcg.js +1 -0
- package/dist/ui/assets/{cobol-Cf6azoN_.js → cobol-ByC5mWiB.js} +1 -1
- package/dist/ui/assets/{coffee-vVdGzlmt.js → coffee-Dez77Qov.js} +1 -1
- package/dist/ui/assets/cpp-DtaAQT9h.js +1 -0
- package/dist/ui/assets/{crystal-5UZy6KIX.js → crystal-Bgmbf8ec.js} +1 -1
- package/dist/ui/assets/css-C1tjBtVN.js +1 -0
- package/dist/ui/assets/{edge-CESgo4ia.js → edge-DeH6u8Wg.js} +1 -1
- package/dist/ui/assets/{elixir-9FKfw4cJ.js → elixir-_H3KnmWT.js} +1 -1
- package/dist/ui/assets/{elm-Dv7A0aLa.js → elm-CsCe3U28.js} +1 -1
- package/dist/ui/assets/{erb-DHFmDvM0.js → erb-CbM-L2g8.js} +1 -1
- package/dist/ui/assets/{git-rebase-utbU6CzV.js → git-rebase-D0s5pDh9.js} +1 -1
- package/dist/ui/assets/{glimmer-js-t2kiCkyB.js → glimmer-js-BfOToq_A.js} +1 -1
- package/dist/ui/assets/{glimmer-ts-F0Jv5okV.js → glimmer-ts-CCUOkL2K.js} +1 -1
- package/dist/ui/assets/glsl-DH4ec9dE.js +1 -0
- package/dist/ui/assets/graphql-DilAMBoI.js +1 -0
- package/dist/ui/assets/{hack-8yjdbaSA.js → hack-BDkNDZlF.js} +1 -1
- package/dist/ui/assets/haml-D_QBp6K7.js +1 -0
- package/dist/ui/assets/{handlebars-BBFEg4Lo.js → handlebars-DePUrTpC.js} +1 -1
- package/dist/ui/assets/heavy-payload-DOwZpO6n.js +290 -0
- package/dist/ui/assets/html-By4dNnM4.js +1 -0
- package/dist/ui/assets/{html-derivative-DJAQcZyc.js → html-derivative-DDw9Ef4Q.js} +1 -1
- package/dist/ui/assets/{http-Dg5LSYRK.js → http-B0QxWc9M.js} +1 -1
- package/dist/ui/assets/{hurl-Y5uYzMZR.js → hurl-vMQ4lda1.js} +1 -1
- package/dist/ui/assets/java-DYRe2lWG.js +1 -0
- package/dist/ui/assets/javascript-CxyGqwcL.js +1 -0
- package/dist/ui/assets/{jinja-Bt30h8Ik.js → jinja-JUwV-fZt.js} +1 -1
- package/dist/ui/assets/{jison-D5uZ1Nyo.js → jison-7ZqCEvS8.js} +1 -1
- package/dist/ui/assets/json-dbltgiiA.js +1 -0
- package/dist/ui/assets/jsx-oDopT7YQ.js +1 -0
- package/dist/ui/assets/{julia-76hRaaGz.js → julia-CkKiNSav.js} +1 -1
- package/dist/ui/assets/{just-CDE7W0vW.js → just-DuqCAKJ3.js} +1 -1
- package/dist/ui/assets/{latex-CVO2Byab.js → latex-sudcRDSn.js} +1 -1
- package/dist/ui/assets/{liquid-CA-AS3EX.js → liquid-Di-08Js7.js} +1 -1
- package/dist/ui/assets/lua-YlqdMoV0.js +1 -0
- package/dist/ui/assets/{marko-_BWrPfny.js → marko-CJRNyJDb.js} +1 -1
- package/dist/ui/assets/{mdc-PyJv85eS.js → mdc-t12CzZHs.js} +1 -1
- package/dist/ui/assets/{nginx-DAWVw8yu.js → nginx-57-b4XwT.js} +1 -1
- package/dist/ui/assets/{nim-CKE1dzpU.js → nim-BzrswYQa.js} +1 -1
- package/dist/ui/assets/{perl-BBhWva19.js → perl-D9JR_iIh.js} +1 -1
- package/dist/ui/assets/{php-ChIeaAoF.js → php-Py2gFHil.js} +1 -1
- package/dist/ui/assets/{pug-CMgI5afi.js → pug-PzLLy0h1.js} +1 -1
- package/dist/ui/assets/{qml-CjxTkcFH.js → qml-By8fwgV4.js} +1 -1
- package/dist/ui/assets/r-CcezTbLq.js +1 -0
- package/dist/ui/assets/{razor-i4DbHr8p.js → razor-dG-vdhL_.js} +1 -1
- package/dist/ui/assets/regexp-BlsQ-N_8.js +1 -0
- package/dist/ui/assets/{rst-oy_97Kl4.js → rst-C2awDCat.js} +1 -1
- package/dist/ui/assets/{ruby-C5zYZIyl.js → ruby-zA2W_49d.js} +1 -1
- package/dist/ui/assets/{sas-BnMEh2S3.js → sas-D49bhyaN.js} +1 -1
- package/dist/ui/assets/scss-BQb-cp01.js +1 -0
- package/dist/ui/assets/shellscript-Dga4H_Ni.js +1 -0
- package/dist/ui/assets/{shellsession-BpE5o7_3.js → shellsession-n3-5CqcF.js} +1 -1
- package/dist/ui/assets/{soy-COesmhTY.js → soy-XYBOf_BA.js} +1 -1
- package/dist/ui/assets/sql-ET4u5Cpl.js +1 -0
- package/dist/ui/assets/{stata-CGQEuSZq.js → stata-CLHcJHO_.js} +1 -1
- package/dist/ui/assets/{surrealql-Bz4JbU-9.js → surrealql-BdjQ60T4.js} +1 -1
- package/dist/ui/assets/{svelte-1jM2ejXj.js → svelte-B2RPtKJe.js} +1 -1
- package/dist/ui/assets/{templ-C-VwELcp.js → templ-CrByPW_W.js} +1 -1
- package/dist/ui/assets/{tex-t1rUiQCm.js → tex-DZBkg363.js} +1 -1
- package/dist/ui/assets/{ts-tags-Bewoa6pS.js → ts-tags-DJR3Gphb.js} +1 -1
- package/dist/ui/assets/tsx-CajzROyy.js +1 -0
- package/dist/ui/assets/{twig-DVg-vELl.js → twig-BZjk5Zda.js} +1 -1
- package/dist/ui/assets/typescript-B-EWToLj.js +1 -0
- package/dist/ui/assets/{vue-wPQ7UlMy.js → vue-D_rHCCr8.js} +1 -1
- package/dist/ui/assets/{vue-html-BHtJ8geX.js → vue-html-CC4WlvVt.js} +1 -1
- package/dist/ui/assets/{vue-vine-CNSGAWwc.js → vue-vine-BgNMVgpk.js} +1 -1
- package/dist/ui/assets/xml-BI86-WbH.js +1 -0
- package/dist/ui/assets/{xsl-3_vJ27aE.js → xsl-DXeLZV4J.js} +1 -1
- package/dist/ui/assets/yaml-60_PFlWa.js +1 -0
- package/dist/workspaces/bootstrap.js +72 -0
- package/dist/workspaces/context.js +302 -0
- package/dist/workspaces/conversation-test-support.js +86 -0
- package/dist/{git-worktrees.js → workspaces/git/git-worktrees.js} +1 -1
- package/dist/workspaces/inventory.js +131 -0
- package/dist/workspaces/paths.js +55 -0
- package/dist/{remote-auth.js → workspaces/relay/auth/remote-auth.js} +2 -2
- package/dist/workspaces/relay/result-support.js +111 -0
- package/dist/workspaces/relay/tests/test-support.js +203 -0
- package/dist/{remote-mcp-connection-pool.js → workspaces/relay/transport/remote-mcp-connection-pool.js} +1 -1
- package/dist/workspaces/relay/types.js +1 -0
- package/dist/{remote-workspace-relay.js → workspaces/relay/workspace-relay.js} +23 -172
- package/dist/workspaces/resources/skills.js +285 -0
- package/dist/{review-checkpoints.js → workspaces/review/review-checkpoints.js} +2 -2
- package/dist/workspaces/sessions.js +457 -0
- package/dist/{workspace-store.js → workspaces/state/workspace-store.js} +2 -2
- package/dist/workspaces.js +69 -991
- package/docs/chatgpt-coding-workflow.md +3 -11
- package/docs/configuration.md +12 -25
- package/docs/gotchas.md +0 -30
- package/docs/roadmap.md +6 -10
- package/docs/security.md +1 -5
- package/docs/setup.md +0 -11
- package/package.json +6 -8
- package/scripts/ci/architecture.mjs +109 -0
- package/scripts/ci/verify.mjs +5 -0
- package/scripts/debug/accept/bootstrap.mjs +326 -0
- package/scripts/debug/accept/harness.mjs +76 -0
- package/scripts/debug/accept/support.mjs +432 -0
- package/scripts/debug/accept.mjs +43 -806
- package/scripts/debug/relay-accept/support.mjs +135 -0
- package/scripts/debug/relay-accept.mjs +26 -115
- package/scripts/debug/traffic/support.mjs +167 -0
- package/scripts/debug/traffic/traffic-audit.mjs +4 -161
- package/scripts/{lsp-interop-support.test.mjs → lsp/interop-support.test.mjs} +1 -1
- package/scripts/{lsp-interop.mjs → lsp/interop.mjs} +3 -3
- package/scripts/wiki/sync.mjs +21 -10
- package/dist/activity/bash-output-store.js +0 -127
- package/dist/pi-tools.js +0 -110
- package/dist/skills.js +0 -127
- package/dist/ui/assets/activity-panel-app-CUAN6zyW.js +0 -2
- package/dist/ui/assets/angular-html-BkgDQl-G.js +0 -1
- package/dist/ui/assets/c-IBzBpxAO.js +0 -1
- package/dist/ui/assets/chunk-EyZ2wyi3.js +0 -1
- package/dist/ui/assets/cpp-CVHeO-Jk.js +0 -1
- package/dist/ui/assets/css-DEfus9J5.js +0 -1
- package/dist/ui/assets/glsl-_ooCjaeB.js +0 -1
- package/dist/ui/assets/graphql-B9LqP-cY.js +0 -1
- package/dist/ui/assets/haml-BU5EoZBn.js +0 -1
- package/dist/ui/assets/heavy-payload-CgzrutLm.js +0 -4
- package/dist/ui/assets/html-D-C6YZk4.js +0 -1
- package/dist/ui/assets/java-ppHvycj5.js +0 -1
- package/dist/ui/assets/javascript-DDTjKLlQ.js +0 -1
- package/dist/ui/assets/json-Cw91r8h1.js +0 -1
- package/dist/ui/assets/jsx-04X2FT_1.js +0 -1
- package/dist/ui/assets/lua-CiyBp52Y.js +0 -1
- package/dist/ui/assets/r-DfFga4si.js +0 -1
- package/dist/ui/assets/regexp-iC9_nbSI.js +0 -1
- package/dist/ui/assets/review-payload-BrLbezbq.js +0 -1
- package/dist/ui/assets/scrollbar-CbhpdW05.js +0 -287
- package/dist/ui/assets/scss-BfZXsAWQ.js +0 -1
- package/dist/ui/assets/shellscript-BC2srNaB.js +0 -1
- package/dist/ui/assets/sql-Ccv_yeUm.js +0 -1
- package/dist/ui/assets/tsx-CTXzrBkN.js +0 -1
- package/dist/ui/assets/typescript--ElHoFkw.js +0 -1
- package/dist/ui/assets/workspace-app-Bhj96tsR.js +0 -1
- package/dist/ui/assets/workspace-app-CxwJuZyS.js +0 -111
- package/dist/ui/assets/workspace-app-D6UR0AFl.js +0 -5
- package/dist/ui/assets/workspace-app-ldjBmCJR.css +0 -1
- package/dist/ui/assets/workspace-lifecycle-app-Cqfhx9pV.js +0 -1
- package/dist/ui/assets/xml-JnmX6vyS.js +0 -1
- package/dist/ui/assets/yaml-OAcZkP-w.js +0 -1
- package/dist/ui/workspace-app.html +0 -18
- package/dist/ui/workspace-lifecycle-app.html +0 -18
- package/docs/agent-profile-schema.md +0 -114
- package/docs/artifact-exchange.md +0 -65
- package/docs/versioning.md +0 -205
- /package/capabilities/{managed-worktrees → workspace/managed-worktrees}/GUIDE.md +0 -0
- /package/capabilities/{workspace-tasks → workspace/workspace-tasks}/GUIDE.md +0 -0
- /package/dist/activity/{process-output-audit.js → runtime/process-output-audit.js} +0 -0
- /package/dist/{artifact-error.js → mcp/artifacts/artifact-error.js} +0 -0
- /package/dist/{artifact-tools.js → mcp/artifacts/artifact-tools.js} +0 -0
- /package/dist/{incoming-artifacts.js → mcp/artifacts/incoming-artifacts.js} +0 -0
- /package/dist/{advertised-files.js → mcp/filesystem/advertised-files.js} +0 -0
- /package/dist/{apply-patch.js → mcp/filesystem/apply-patch.js} +0 -0
- /package/dist/{file-mutations.js → mcp/filesystem/file-mutations.js} +0 -0
- /package/dist/{roots.js → mcp/filesystem/roots.js} +0 -0
- /package/dist/{oauth → mcp/oauth}/public-url.js +0 -0
- /package/dist/{oauth → mcp/oauth}/router.js +0 -0
- /package/dist/{operations → mcp/operations}/batch/executor.js +0 -0
- /package/dist/{operations → mcp/operations}/batch/scheduler.js +0 -0
- /package/dist/{operations → mcp/operations}/batch/types.js +0 -0
- /package/dist/{operations → mcp/operations}/bulk-mutation.js +0 -0
- /package/dist/{operations → mcp/operations}/bulk-read.js +0 -0
- /package/dist/{operations → mcp/operations}/core-operation-executor.js +0 -0
- /package/dist/{process-platform.js → mcp/process/process-platform.js} +0 -0
- /package/dist/{process-sessions.js → mcp/process/process-sessions.js} +0 -0
- /package/dist/{request-meta.js → mcp/request-meta.js} +0 -0
- /package/dist/{mcp-sessions.js → mcp/server/transport/mcp-sessions.js} +0 -0
- /package/dist/{server-shutdown.js → mcp/server/transport/server-shutdown.js} +0 -0
- /package/dist/{logger.js → runtime/logging/logger.js} +0 -0
- /package/dist/{db → runtime/state/db}/schema.js +0 -0
- /package/dist/{composite-activity.js → workspaces/composite/composite-activity.js} +0 -0
- /package/dist/{composite-workspaces.js → workspaces/composite/composite-workspaces.js} +0 -0
- /package/dist/{git.js → workspaces/git/git.js} +0 -0
- /package/dist/{workspace-presentation.js → workspaces/presentation/workspace-presentation.js} +0 -0
- /package/dist/{remote-transport.js → workspaces/relay/transport/remote-transport.js} +0 -0
- /package/dist/{workspace-task-reminders.js → workspaces/tasks/workspace-task-reminders.js} +0 -0
- /package/dist/{workspace-tasks.js → workspaces/tasks/workspace-tasks.js} +0 -0
- /package/scripts/{lsp-interop-support.mjs → lsp/interop-support.mjs} +0 -0
|
@@ -2,6 +2,10 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { removeForgeRelayNodeModulesBinFromPath } from "../path.js";
|
|
3
3
|
import { asRecord, assertPipedChild, errorMessage, readArray, readNestedString, requireFinalResponse, terminateChildOnAbort, unwrapProviderPayload, } from "../shared.js";
|
|
4
4
|
const PI_AGENT_TIMEOUT_MS = 120_000;
|
|
5
|
+
const PI_RPC_MAX_LINE_BYTES = 8 * 1024 * 1024;
|
|
6
|
+
const PI_RPC_STDERR_TAIL_BYTES = 128 * 1024;
|
|
7
|
+
const PI_STREAMING_TEXT_MAX_BYTES = 8 * 1024 * 1024;
|
|
8
|
+
const PI_ERROR_PREVIEW_BYTES = 4 * 1024;
|
|
5
9
|
export class PiRpcSubagentAdapter {
|
|
6
10
|
provider = "pi";
|
|
7
11
|
async run(input) {
|
|
@@ -22,14 +26,23 @@ export class PiRpcSubagentAdapter {
|
|
|
22
26
|
const detachAbort = terminateChildOnAbort(child, input.signal);
|
|
23
27
|
const rpc = new JsonLineRpc(child);
|
|
24
28
|
let streamingText = "";
|
|
29
|
+
let streamingTextBytes = 0;
|
|
25
30
|
let streamingProviderError = "";
|
|
26
31
|
rpc.onEvent((event) => {
|
|
27
32
|
const text = extractPiStreamingText([event]);
|
|
28
|
-
if (text)
|
|
33
|
+
if (text) {
|
|
34
|
+
const nextBytes = streamingTextBytes + Buffer.byteLength(text, "utf8");
|
|
35
|
+
if (nextBytes > PI_STREAMING_TEXT_MAX_BYTES) {
|
|
36
|
+
rpc.fail(new Error(`Pi streaming response exceeded ${PI_STREAMING_TEXT_MAX_BYTES} bytes.`));
|
|
37
|
+
child.kill();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
29
40
|
streamingText += text;
|
|
41
|
+
streamingTextBytes = nextBytes;
|
|
42
|
+
}
|
|
30
43
|
const providerError = extractPiProviderError(event);
|
|
31
44
|
if (providerError)
|
|
32
|
-
streamingProviderError = providerError;
|
|
45
|
+
streamingProviderError = boundedUtf8Tail(providerError, PI_RPC_STDERR_TAIL_BYTES);
|
|
33
46
|
});
|
|
34
47
|
try {
|
|
35
48
|
const state = await rpc.request({ type: "get_state" });
|
|
@@ -72,11 +85,13 @@ export function piCommandEnvironment(env) {
|
|
|
72
85
|
PATH: removeForgeRelayNodeModulesBinFromPath(path),
|
|
73
86
|
};
|
|
74
87
|
}
|
|
75
|
-
class JsonLineRpc {
|
|
88
|
+
export class JsonLineRpc {
|
|
76
89
|
child;
|
|
77
90
|
pending = new Map();
|
|
78
91
|
eventSubscribers = new Set();
|
|
92
|
+
failureSubscribers = new Set();
|
|
79
93
|
buffer = "";
|
|
94
|
+
bufferBytes = 0;
|
|
80
95
|
nextId = 1;
|
|
81
96
|
stderr = "";
|
|
82
97
|
fatalError;
|
|
@@ -84,7 +99,7 @@ class JsonLineRpc {
|
|
|
84
99
|
this.child = child;
|
|
85
100
|
child.stdout.on("data", (chunk) => this.handleStdout(chunk.toString("utf8")));
|
|
86
101
|
child.stderr.on("data", (chunk) => {
|
|
87
|
-
this.stderr
|
|
102
|
+
this.stderr = boundedUtf8Tail(`${this.stderr}${chunk.toString("utf8")}`, PI_RPC_STDERR_TAIL_BYTES);
|
|
88
103
|
});
|
|
89
104
|
child.on("exit", (code, signal) => {
|
|
90
105
|
this.failAll(new Error(`Pi RPC process exited with code ${code ?? "null"} and signal ${signal ?? "null"}\n${this.stderr}`.trim()));
|
|
@@ -105,11 +120,15 @@ class JsonLineRpc {
|
|
|
105
120
|
this.eventSubscribers.add(callback);
|
|
106
121
|
return () => this.eventSubscribers.delete(callback);
|
|
107
122
|
}
|
|
123
|
+
fail(error) {
|
|
124
|
+
this.failAll(error);
|
|
125
|
+
}
|
|
108
126
|
waitForEvent(predicate, timeoutMs, signal) {
|
|
109
127
|
return new Promise((resolve, reject) => {
|
|
110
128
|
const finish = (callback) => {
|
|
111
129
|
clearTimeout(timer);
|
|
112
130
|
unsubscribe();
|
|
131
|
+
unsubscribeFailure();
|
|
113
132
|
signal?.removeEventListener("abort", abort);
|
|
114
133
|
callback();
|
|
115
134
|
};
|
|
@@ -126,6 +145,7 @@ class JsonLineRpc {
|
|
|
126
145
|
return;
|
|
127
146
|
finish(() => resolve(event));
|
|
128
147
|
});
|
|
148
|
+
const unsubscribeFailure = this.onFailure((error) => finish(() => reject(error)));
|
|
129
149
|
if (signal?.aborted)
|
|
130
150
|
abort();
|
|
131
151
|
else
|
|
@@ -134,21 +154,38 @@ class JsonLineRpc {
|
|
|
134
154
|
}
|
|
135
155
|
handleStdout(chunk) {
|
|
136
156
|
this.buffer += chunk;
|
|
157
|
+
this.bufferBytes += Buffer.byteLength(chunk, "utf8");
|
|
137
158
|
for (;;) {
|
|
138
159
|
const newline = this.buffer.indexOf("\n");
|
|
139
|
-
if (newline === -1)
|
|
160
|
+
if (newline === -1) {
|
|
161
|
+
if (this.bufferBytes > PI_RPC_MAX_LINE_BYTES) {
|
|
162
|
+
const error = new Error(`Pi RPC line exceeded ${PI_RPC_MAX_LINE_BYTES} bytes.`);
|
|
163
|
+
this.failAll(error);
|
|
164
|
+
this.child.kill();
|
|
165
|
+
}
|
|
140
166
|
return;
|
|
141
|
-
|
|
167
|
+
}
|
|
168
|
+
const consumed = this.buffer.slice(0, newline + 1);
|
|
169
|
+
const line = consumed.slice(0, -1).trim();
|
|
142
170
|
this.buffer = this.buffer.slice(newline + 1);
|
|
171
|
+
this.bufferBytes = Math.max(0, this.bufferBytes - Buffer.byteLength(consumed, "utf8"));
|
|
143
172
|
if (!line)
|
|
144
173
|
continue;
|
|
174
|
+
if (Buffer.byteLength(line, "utf8") > PI_RPC_MAX_LINE_BYTES) {
|
|
175
|
+
const error = new Error(`Pi RPC line exceeded ${PI_RPC_MAX_LINE_BYTES} bytes.`);
|
|
176
|
+
this.failAll(error);
|
|
177
|
+
this.child.kill();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
145
180
|
let message;
|
|
146
181
|
try {
|
|
147
182
|
message = JSON.parse(line);
|
|
148
183
|
}
|
|
149
184
|
catch {
|
|
150
|
-
|
|
151
|
-
this.
|
|
185
|
+
const preview = boundedUtf8Tail(line, PI_ERROR_PREVIEW_BYTES);
|
|
186
|
+
this.stderr = boundedUtf8Tail(`${this.stderr}${preview}\n`, PI_RPC_STDERR_TAIL_BYTES);
|
|
187
|
+
this.failAll(new Error(`Pi RPC emitted malformed JSON on stdout: ${preview}`));
|
|
188
|
+
this.child.kill();
|
|
152
189
|
return;
|
|
153
190
|
}
|
|
154
191
|
if (message.type !== "response") {
|
|
@@ -171,14 +208,28 @@ class JsonLineRpc {
|
|
|
171
208
|
}
|
|
172
209
|
}
|
|
173
210
|
}
|
|
211
|
+
onFailure(callback) {
|
|
212
|
+
this.failureSubscribers.add(callback);
|
|
213
|
+
return () => this.failureSubscribers.delete(callback);
|
|
214
|
+
}
|
|
174
215
|
failAll(error) {
|
|
216
|
+
if (this.fatalError)
|
|
217
|
+
return;
|
|
175
218
|
this.fatalError = error;
|
|
176
219
|
for (const pending of this.pending.values()) {
|
|
177
220
|
pending.reject(error);
|
|
178
221
|
}
|
|
179
222
|
this.pending.clear();
|
|
223
|
+
for (const subscriber of [...this.failureSubscribers])
|
|
224
|
+
subscriber(error);
|
|
180
225
|
}
|
|
181
226
|
}
|
|
227
|
+
function boundedUtf8Tail(value, maxBytes) {
|
|
228
|
+
const bytes = Buffer.from(value, "utf8");
|
|
229
|
+
if (bytes.length <= maxBytes)
|
|
230
|
+
return value;
|
|
231
|
+
return bytes.subarray(bytes.length - maxBytes).toString("utf8");
|
|
232
|
+
}
|
|
182
233
|
export function extractPiFinalResponse(value) {
|
|
183
234
|
const root = unwrapProviderPayload(value);
|
|
184
235
|
const messages = Array.isArray(root) ? root : readArray(root, "messages");
|
|
@@ -9,19 +9,25 @@ export function getSubagentProviderAvailabilitySnapshot(env = process.env) {
|
|
|
9
9
|
export function checkSubagentProviderAvailability(provider, env = process.env) {
|
|
10
10
|
switch (provider) {
|
|
11
11
|
case "codex":
|
|
12
|
-
return
|
|
12
|
+
return commandAvailability(provider, env.CODEX_COMMAND ?? "codex", {
|
|
13
|
+
env: externalProviderEnvironment(env, "CODEX_COMMAND"),
|
|
14
|
+
});
|
|
13
15
|
case "claude":
|
|
14
|
-
return
|
|
16
|
+
return commandAvailability(provider, env.CLAUDE_COMMAND ?? "claude", {
|
|
17
|
+
env: externalProviderEnvironment(env, "CLAUDE_COMMAND"),
|
|
18
|
+
});
|
|
15
19
|
case "opencode":
|
|
16
|
-
return
|
|
20
|
+
return commandAvailability(provider, env.OPENCODE_COMMAND ?? "opencode", {
|
|
21
|
+
env: externalProviderEnvironment(env, "OPENCODE_COMMAND"),
|
|
22
|
+
});
|
|
17
23
|
case "pi":
|
|
18
24
|
return commandAvailability(provider, env.PI_COMMAND ?? "pi", {
|
|
19
|
-
env:
|
|
25
|
+
env: externalProviderEnvironment(env, "PI_COMMAND"),
|
|
20
26
|
});
|
|
21
27
|
case "cursor":
|
|
22
|
-
return commandAvailability(provider, "cursor-agent");
|
|
28
|
+
return commandAvailability(provider, "cursor-agent", { env });
|
|
23
29
|
case "copilot":
|
|
24
|
-
return commandAvailability(provider, "copilot");
|
|
30
|
+
return commandAvailability(provider, "copilot", { env });
|
|
25
31
|
}
|
|
26
32
|
}
|
|
27
33
|
export function assertSubagentProviderAvailable(provider, env = process.env) {
|
|
@@ -45,24 +51,6 @@ export function formatSubagentProviderAvailabilitySummary(providers) {
|
|
|
45
51
|
unavailable.length > 0 ? `unavailable: ${unavailable.join(", ")}` : undefined,
|
|
46
52
|
].filter(Boolean).join("; ");
|
|
47
53
|
}
|
|
48
|
-
function packageAvailability(provider, packageName) {
|
|
49
|
-
try {
|
|
50
|
-
import.meta.resolve(packageName);
|
|
51
|
-
return {
|
|
52
|
-
name: provider,
|
|
53
|
-
available: true,
|
|
54
|
-
continuationSupported: subagentProviderContinuationSupported(provider),
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
return {
|
|
59
|
-
name: provider,
|
|
60
|
-
available: false,
|
|
61
|
-
continuationSupported: subagentProviderContinuationSupported(provider),
|
|
62
|
-
reason: `${packageName} package not found`,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
54
|
function commandAvailability(provider, command, options = {}) {
|
|
67
55
|
const executable = resolveCommand(command, options.env);
|
|
68
56
|
if (!executable) {
|
|
@@ -120,14 +108,11 @@ function executableExists(command, env) {
|
|
|
120
108
|
: undefined;
|
|
121
109
|
return code !== "ENOENT";
|
|
122
110
|
}
|
|
123
|
-
function
|
|
124
|
-
if (env.
|
|
125
|
-
return env;
|
|
126
|
-
const path = env.PATH;
|
|
127
|
-
if (!path)
|
|
111
|
+
function externalProviderEnvironment(env, explicitCommandKey) {
|
|
112
|
+
if (env[explicitCommandKey] || !env.PATH)
|
|
128
113
|
return env;
|
|
129
114
|
return {
|
|
130
115
|
...env,
|
|
131
|
-
PATH: removeForgeRelayNodeModulesBinFromPath(
|
|
116
|
+
PATH: removeForgeRelayNodeModulesBinFromPath(env.PATH),
|
|
132
117
|
};
|
|
133
118
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { assertPipedChild, errorMessage, terminateChildOnAbort } from "../shared.js";
|
|
3
|
+
export const runExternalCommand = async (request) => {
|
|
4
|
+
request.signal?.throwIfAborted();
|
|
5
|
+
const child = spawn(request.command, request.args, {
|
|
6
|
+
cwd: request.cwd,
|
|
7
|
+
env: request.env,
|
|
8
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
9
|
+
windowsHide: true,
|
|
10
|
+
});
|
|
11
|
+
assertPipedChild(child);
|
|
12
|
+
let stdout = "";
|
|
13
|
+
let stderr = "";
|
|
14
|
+
child.stdout.on("data", (chunk) => {
|
|
15
|
+
stdout += chunk.toString("utf8");
|
|
16
|
+
});
|
|
17
|
+
child.stderr.on("data", (chunk) => {
|
|
18
|
+
stderr += chunk.toString("utf8");
|
|
19
|
+
});
|
|
20
|
+
const detachAbort = terminateChildOnAbort(child, request.signal);
|
|
21
|
+
try {
|
|
22
|
+
const exitCode = await new Promise((resolve, reject) => {
|
|
23
|
+
child.once("error", (error) => reject(error));
|
|
24
|
+
child.once("exit", (code, signal) => {
|
|
25
|
+
if (request.signal?.aborted) {
|
|
26
|
+
const aborted = new Error(`${request.label} command cancelled.`);
|
|
27
|
+
aborted.name = "AbortError";
|
|
28
|
+
reject(aborted);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (signal) {
|
|
32
|
+
reject(new Error(`${request.label} command terminated by ${signal}${stderr ? `\n${stderr.trim()}` : ""}`));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
resolve(code ?? 0);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
if (exitCode !== 0) {
|
|
39
|
+
throw new Error(`${request.label} command exited with code ${exitCode}${stderr ? `\n${stderr.trim()}` : ""}`);
|
|
40
|
+
}
|
|
41
|
+
return { stdout, stderr, exitCode };
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (request.signal?.aborted && !(error instanceof Error && error.name === "AbortError")) {
|
|
45
|
+
const aborted = new Error(`${request.label} command cancelled: ${errorMessage(error)}`);
|
|
46
|
+
aborted.name = "AbortError";
|
|
47
|
+
throw aborted;
|
|
48
|
+
}
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
detachAbort();
|
|
53
|
+
if (!child.killed && child.exitCode === null)
|
|
54
|
+
child.kill();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CapabilityError, } from "../../capability-registry.js";
|
|
1
|
+
import { CapabilityError, } from "../../mcp/server/core/capability-registry.js";
|
|
2
2
|
import { isSubagentProvider } from "../profiles.js";
|
|
3
3
|
import { subagentProviderContinuationSupported } from "../providers/continuation.js";
|
|
4
4
|
import { SubagentDeliveryMailbox } from "./delivery-mailbox.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HookRunner } from "../../hooks.js";
|
|
1
|
+
import { HookRunner } from "../../mcp/hooks/hooks.js";
|
|
2
2
|
import { isSubagentProvider, loadSubagentProfiles, } from "../profiles.js";
|
|
3
3
|
import { runSubagentProvider } from "../providers/registry.js";
|
|
4
4
|
import { SubagentDeliveryMailbox } from "./delivery-mailbox.js";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { openDatabase } from "../../../runtime/state/db/client.js";
|
|
3
|
+
export function readActivityAuditSnapshot(stateDir, auditStore) {
|
|
4
|
+
const database = openDatabase(stateDir);
|
|
5
|
+
try {
|
|
6
|
+
const rows = database.sqlite.prepare(`select activity_id, event_type, tool, request_json, result_json, error,
|
|
7
|
+
payload_file, payload_offset, payload_length
|
|
8
|
+
from activity_audit_events
|
|
9
|
+
order by rowid`).all();
|
|
10
|
+
for (const row of rows) {
|
|
11
|
+
assert.equal(row.request_json, null, "Activity request payload must not be stored in SQLite.");
|
|
12
|
+
assert.equal(row.result_json, null, "Activity result payload must not be stored in SQLite.");
|
|
13
|
+
assert.equal(row.error, null, "Activity error payload must not be stored in SQLite.");
|
|
14
|
+
}
|
|
15
|
+
const activityIds = [...new Set(rows.map((row) => row.activity_id))];
|
|
16
|
+
return {
|
|
17
|
+
rows,
|
|
18
|
+
events: activityIds.flatMap((activityId) => auditStore.listEvents(activityId)),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
database.close();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function activityEventsForTool(snapshot, tool) {
|
|
26
|
+
const activityIds = new Set(snapshot.rows
|
|
27
|
+
.filter((row) => row.tool === tool)
|
|
28
|
+
.map((row) => row.activity_id));
|
|
29
|
+
return snapshot.events.filter((event) => activityIds.has(event.activityId));
|
|
30
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import { openDatabase } from "../../db/client.js";
|
|
3
|
+
import { openDatabase } from "../../runtime/state/db/client.js";
|
|
4
4
|
export class SubagentSessionStore {
|
|
5
5
|
database;
|
|
6
6
|
constructor(stateDir) {
|