@akira-tl/forgerelay 0.8.8 → 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 +12 -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 +116 -4202
- 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 -410
- 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 +68 -995
- 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-7AckaxIR.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-Bol1_mcs.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-BqJp0c5e.js +0 -1
- package/dist/ui/assets/scrollbar-CvE-I-jG.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-BLW7p6IZ.js +0 -114
- package/dist/ui/assets/workspace-app-BjNqR0en.js +0 -1
- package/dist/ui/assets/workspace-app-CmaYU4DW.js +0 -3
- package/dist/ui/assets/workspace-app-D2bJ5fjt.css +0 -1
- package/dist/ui/assets/workspace-lifecycle-app-BVbI2Ilf.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
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { runToolWithHooks } from "../../hooks/hooks.js";
|
|
2
|
+
import { toolResultIsError } from "./tool-support.js";
|
|
3
|
+
export function workspaceActivitySnapshot(workspace) {
|
|
4
|
+
return {
|
|
5
|
+
id: workspace.id,
|
|
6
|
+
root: workspace.root,
|
|
7
|
+
mode: workspace.mode,
|
|
8
|
+
...(workspace.sourceRoot ? { sourceRoot: workspace.sourceRoot } : {}),
|
|
9
|
+
...(workspace.worktree?.branch ? { branch: workspace.worktree.branch } : {}),
|
|
10
|
+
...(workspace.worktree?.targetBranch ? { targetBranch: workspace.worktree.targetBranch } : {}),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function activityFailureMessage(result) {
|
|
14
|
+
if (typeof result !== "object" || result === null)
|
|
15
|
+
return "Tool returned a failed result.";
|
|
16
|
+
const record = result;
|
|
17
|
+
if (Array.isArray(record.content)) {
|
|
18
|
+
const text = record.content
|
|
19
|
+
.map((entry) => {
|
|
20
|
+
if (typeof entry !== "object" || entry === null)
|
|
21
|
+
return "";
|
|
22
|
+
const value = entry.text;
|
|
23
|
+
return typeof value === "string" ? value : "";
|
|
24
|
+
})
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.join("\n");
|
|
27
|
+
if (text)
|
|
28
|
+
return text;
|
|
29
|
+
}
|
|
30
|
+
if (typeof record.structuredContent === "object" && record.structuredContent !== null) {
|
|
31
|
+
const value = record.structuredContent.result;
|
|
32
|
+
if (typeof value === "string" && value)
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
return "Tool returned a failed result.";
|
|
36
|
+
}
|
|
37
|
+
export function standardActivityOutcome(result) {
|
|
38
|
+
return toolResultIsError(result)
|
|
39
|
+
? { type: "failed", error: activityFailureMessage(result) }
|
|
40
|
+
: { type: "succeeded" };
|
|
41
|
+
}
|
|
42
|
+
export function activityRelationFor(context) {
|
|
43
|
+
return {
|
|
44
|
+
...(context.parentActivityId ? { parentActivityId: context.parentActivityId } : {}),
|
|
45
|
+
...(context.turnId ? { turnId: context.turnId } : {}),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function activityRequestFor(input, context) {
|
|
49
|
+
if (!context.activityMember || !input || typeof input !== "object" || Array.isArray(input))
|
|
50
|
+
return input;
|
|
51
|
+
return {
|
|
52
|
+
...input,
|
|
53
|
+
member: context.activityMember,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function runActivityTool(lifecycle, workspace, conversationScopeId, tool, request, operation, outcome = standardActivityOutcome, relation = {}, auditResult) {
|
|
57
|
+
return lifecycle.run({
|
|
58
|
+
tool,
|
|
59
|
+
workspace: workspaceActivitySnapshot(workspace),
|
|
60
|
+
conversationScopeId,
|
|
61
|
+
request,
|
|
62
|
+
operation,
|
|
63
|
+
outcome,
|
|
64
|
+
...(auditResult ? { auditResult } : {}),
|
|
65
|
+
...relation,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
export function runActivityToolWithHooks(lifecycle, hooks, workspace, conversationScopeId, request, hookOptions, relation = {}) {
|
|
69
|
+
return runActivityTool(lifecycle, workspace, conversationScopeId, hookOptions.tool, request, () => runToolWithHooks(hooks, hookOptions), standardActivityOutcome, relation);
|
|
70
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { markAdvertisedFileSourceActivated, resolveAdvertisedFileReadPath, } from "
|
|
3
|
+
import { markAdvertisedFileSourceActivated, resolveAdvertisedFileReadPath, } from "../../filesystem/advertised-files.js";
|
|
4
4
|
const CAPABILITY_GUIDE_DEFINITIONS = [
|
|
5
5
|
{
|
|
6
6
|
name: "lifecycle-hooks",
|
|
@@ -9,6 +9,7 @@ const CAPABILITY_GUIDE_DEFINITIONS = [
|
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
name: "managed-worktrees",
|
|
12
|
+
directory: "workspace/managed-worktrees",
|
|
12
13
|
description: "Managed-worktree lifecycle, close safety, and recovery.",
|
|
13
14
|
whenToRead: "Read for advanced mode=\"worktree\" flows.",
|
|
14
15
|
},
|
|
@@ -41,6 +42,7 @@ const CAPABILITY_GUIDE_DEFINITIONS = [
|
|
|
41
42
|
},
|
|
42
43
|
{
|
|
43
44
|
name: "workspace-tasks",
|
|
45
|
+
directory: "workspace/workspace-tasks",
|
|
44
46
|
description: "Persistent Task Lists owned by the current Workspace.",
|
|
45
47
|
whenToRead: "Read before creating or maintaining Workspace Tasks.",
|
|
46
48
|
},
|
|
@@ -52,14 +54,14 @@ const CAPABILITY_GUIDE_DEFINITIONS = [
|
|
|
52
54
|
},
|
|
53
55
|
];
|
|
54
56
|
function capabilityGuidesDir() {
|
|
55
|
-
return fileURLToPath(new URL("
|
|
57
|
+
return fileURLToPath(new URL("../../../../capabilities", import.meta.url));
|
|
56
58
|
}
|
|
57
59
|
export function loadCapabilityGuides(config) {
|
|
58
60
|
const root = capabilityGuidesDir();
|
|
59
61
|
return CAPABILITY_GUIDE_DEFINITIONS
|
|
60
62
|
.filter((definition) => definition.enabled?.(config) ?? true)
|
|
61
63
|
.map((definition) => {
|
|
62
|
-
const baseDir = join(root, definition.name);
|
|
64
|
+
const baseDir = join(root, definition.directory ?? definition.name);
|
|
63
65
|
return {
|
|
64
66
|
name: definition.name,
|
|
65
67
|
description: definition.description,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { MAX_CODE_INTELLIGENCE_RESULT_LIMIT, } from "
|
|
3
|
-
import { batchExecuteInputSchema, } from "
|
|
2
|
+
import { MAX_CODE_INTELLIGENCE_RESULT_LIMIT, } from "../../../lsp/code-intelligence-types.js";
|
|
3
|
+
import { batchExecuteInputSchema, } from "../../operations/batch/types.js";
|
|
4
4
|
export class CapabilityError extends Error {
|
|
5
5
|
code;
|
|
6
6
|
constructor(code, message) {
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { CapabilityError } from "./capability-registry.js";
|
|
2
|
+
import { formatPathForPrompt } from "../../../workspaces/resources/skills.js";
|
|
3
|
+
export function workspaceHookInvocation(workspace) {
|
|
4
|
+
return {
|
|
5
|
+
workspaceId: workspace.id,
|
|
6
|
+
workspaceRoot: workspace.root,
|
|
7
|
+
workspaceMode: workspace.mode,
|
|
8
|
+
sourceRoot: workspace.sourceRoot,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function capabilityContextFor(workspace) {
|
|
12
|
+
return {
|
|
13
|
+
workspaceId: workspace.id,
|
|
14
|
+
workspaceKind: "workspace",
|
|
15
|
+
workspaceRoot: workspace.root,
|
|
16
|
+
guides: workspace.capabilityGuides.map((guide) => ({
|
|
17
|
+
name: guide.name,
|
|
18
|
+
description: guide.description,
|
|
19
|
+
whenToRead: guide.whenToRead,
|
|
20
|
+
path: formatPathForPrompt(guide.filePath),
|
|
21
|
+
})),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function compositeCapabilityContext(workspaceId, guides) {
|
|
25
|
+
return {
|
|
26
|
+
workspaceId,
|
|
27
|
+
workspaceKind: "composite",
|
|
28
|
+
guides: guides.map((guide) => ({
|
|
29
|
+
name: guide.name,
|
|
30
|
+
description: guide.description,
|
|
31
|
+
whenToRead: guide.whenToRead,
|
|
32
|
+
path: formatPathForPrompt(guide.filePath),
|
|
33
|
+
})),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function requireCapabilityWorkspaceRoot(context) {
|
|
37
|
+
if (!context.workspaceRoot) {
|
|
38
|
+
throw new CapabilityError("capability_unavailable", `Capability execution requires a filesystem-backed Workspace; ${context.workspaceId} is ${context.workspaceKind}.`);
|
|
39
|
+
}
|
|
40
|
+
return context.workspaceRoot;
|
|
41
|
+
}
|
|
42
|
+
export function runWorkspaceTasksCapability(store, workspaceId, input) {
|
|
43
|
+
switch (input.operation) {
|
|
44
|
+
case "get":
|
|
45
|
+
if (input.level === "headers")
|
|
46
|
+
return store.readHeaders(workspaceId, input.listId);
|
|
47
|
+
if (input.level === "detail")
|
|
48
|
+
return store.readTaskDetail(workspaceId, input.listId, input.taskId);
|
|
49
|
+
return store.readSummary(workspaceId);
|
|
50
|
+
case "list.create":
|
|
51
|
+
store.createList(workspaceId, { name: input.name, position: input.position });
|
|
52
|
+
return store.readSummary(workspaceId);
|
|
53
|
+
case "list.update":
|
|
54
|
+
store.updateList(workspaceId, input.listId, {
|
|
55
|
+
name: input.name,
|
|
56
|
+
state: input.state,
|
|
57
|
+
position: input.position,
|
|
58
|
+
});
|
|
59
|
+
return store.readSummary(workspaceId);
|
|
60
|
+
case "list.delete":
|
|
61
|
+
store.deleteList(workspaceId, input.listId);
|
|
62
|
+
return store.readSummary(workspaceId);
|
|
63
|
+
case "task.create":
|
|
64
|
+
store.createTask(workspaceId, input.listId, {
|
|
65
|
+
subject: input.subject,
|
|
66
|
+
content: input.content,
|
|
67
|
+
status: input.status,
|
|
68
|
+
position: input.position,
|
|
69
|
+
});
|
|
70
|
+
return store.readHeaders(workspaceId, input.listId);
|
|
71
|
+
case "task.update":
|
|
72
|
+
store.updateTask(workspaceId, input.listId, input.taskId, {
|
|
73
|
+
subject: input.subject,
|
|
74
|
+
content: input.content,
|
|
75
|
+
status: input.status,
|
|
76
|
+
position: input.position,
|
|
77
|
+
});
|
|
78
|
+
return store.readHeaders(workspaceId, input.listId);
|
|
79
|
+
case "task.delete":
|
|
80
|
+
store.deleteTask(workspaceId, input.listId, input.taskId);
|
|
81
|
+
return store.readHeaders(workspaceId, input.listId);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export async function reviewWorkspaceChanges(reviewCheckpoints, workspace) {
|
|
85
|
+
return reviewCheckpoints.reviewChanges({
|
|
86
|
+
workspaceId: workspace.id,
|
|
87
|
+
root: workspace.root,
|
|
88
|
+
markReviewed: true,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import * as z from "zod/v4";
|
|
2
|
+
export function resultOutputSchema(extra = {}) {
|
|
3
|
+
return {
|
|
4
|
+
result: z
|
|
5
|
+
.string()
|
|
6
|
+
.describe("Model-readable result text for follow-up reasoning and plain MCP hosts."),
|
|
7
|
+
...extra,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export const workspaceSkillOutputSchema = z.object({
|
|
11
|
+
name: z.string(),
|
|
12
|
+
description: z.string(),
|
|
13
|
+
});
|
|
14
|
+
export const workspaceSkillDiagnosticOutputSchema = z.object({
|
|
15
|
+
type: z.enum(["warning", "error", "collision"]),
|
|
16
|
+
message: z.string(),
|
|
17
|
+
collision: z.object({
|
|
18
|
+
resourceType: z.enum(["extension", "skill", "prompt", "theme"]),
|
|
19
|
+
name: z.string(),
|
|
20
|
+
}).optional(),
|
|
21
|
+
});
|
|
22
|
+
export function redactSkillDiagnosticPaths(diagnostics) {
|
|
23
|
+
return diagnostics.map((diagnostic) => {
|
|
24
|
+
let message = diagnostic.message;
|
|
25
|
+
const hiddenPaths = [
|
|
26
|
+
diagnostic.path,
|
|
27
|
+
diagnostic.collision?.winnerPath,
|
|
28
|
+
diagnostic.collision?.loserPath,
|
|
29
|
+
].filter((path) => Boolean(path));
|
|
30
|
+
for (const path of hiddenPaths) {
|
|
31
|
+
message = message.split(path).join("<skill-path>");
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
type: diagnostic.type,
|
|
35
|
+
message,
|
|
36
|
+
...(diagnostic.collision
|
|
37
|
+
? {
|
|
38
|
+
collision: {
|
|
39
|
+
resourceType: diagnostic.collision.resourceType,
|
|
40
|
+
name: diagnostic.collision.name,
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
: {}),
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export const capabilityFingerprintOutputSchema = z.object({
|
|
48
|
+
version: z.string(),
|
|
49
|
+
toolMode: z.enum(["minimal", "full", "codex"]),
|
|
50
|
+
capabilities: z.array(z.string()),
|
|
51
|
+
});
|
|
52
|
+
export const capabilityGuideOutputSchema = z.object({
|
|
53
|
+
name: z.string(),
|
|
54
|
+
description: z.string(),
|
|
55
|
+
whenToRead: z.string(),
|
|
56
|
+
path: z.string(),
|
|
57
|
+
});
|
|
58
|
+
export const capabilityCatalogGuideOutputSchema = z.object({
|
|
59
|
+
name: z.string(),
|
|
60
|
+
path: z.string(),
|
|
61
|
+
readBeforeFirstUse: z.boolean(),
|
|
62
|
+
});
|
|
63
|
+
export const capabilityCatalogOutputSchema = z.object({
|
|
64
|
+
name: z.string(),
|
|
65
|
+
description: z.string(),
|
|
66
|
+
available: z.boolean(),
|
|
67
|
+
unavailableReason: z.string().optional(),
|
|
68
|
+
batchPolicy: z.enum(["parallel", "serial", "unsupported"]),
|
|
69
|
+
guide: capabilityCatalogGuideOutputSchema,
|
|
70
|
+
});
|
|
71
|
+
export const capabilityErrorOutputSchema = z.object({
|
|
72
|
+
code: z.string(),
|
|
73
|
+
message: z.string(),
|
|
74
|
+
});
|
|
75
|
+
export const workspaceAgentsFileOutputSchema = z.object({
|
|
76
|
+
path: z.string(),
|
|
77
|
+
content: z.string(),
|
|
78
|
+
});
|
|
79
|
+
export const workspaceLocalAgentOutputSchema = z.object({
|
|
80
|
+
name: z.string(),
|
|
81
|
+
description: z.string(),
|
|
82
|
+
provider: z.string(),
|
|
83
|
+
model: z.string().optional(),
|
|
84
|
+
thinking: z.string().optional(),
|
|
85
|
+
providerAvailable: z.boolean().optional(),
|
|
86
|
+
providerUnavailableReason: z.string().optional(),
|
|
87
|
+
});
|
|
88
|
+
export const workspaceSubagentProviderOutputSchema = z.object({
|
|
89
|
+
name: z.string(),
|
|
90
|
+
available: z.boolean(),
|
|
91
|
+
continuationSupported: z.boolean(),
|
|
92
|
+
reason: z.string().optional(),
|
|
93
|
+
});
|
|
94
|
+
export const workspaceAvailableAgentsFileOutputSchema = z.object({
|
|
95
|
+
path: z.string(),
|
|
96
|
+
});
|
|
97
|
+
export const workspaceInventoryEntryOutputSchema = z.object({
|
|
98
|
+
label: z.string(),
|
|
99
|
+
workspaceId: z.string(),
|
|
100
|
+
root: z.string(),
|
|
101
|
+
status: z.string(),
|
|
102
|
+
state: z.enum(["active", "stale", "invalid", "closed"]),
|
|
103
|
+
mode: z.enum(["checkout", "worktree"]),
|
|
104
|
+
sourceRoot: z.string().optional(),
|
|
105
|
+
branch: z.string().optional(),
|
|
106
|
+
targetBranch: z.string().optional(),
|
|
107
|
+
managed: z.boolean(),
|
|
108
|
+
createdAt: z.string(),
|
|
109
|
+
lastUsedAt: z.string(),
|
|
110
|
+
idleMs: z.number().nonnegative(),
|
|
111
|
+
rootValid: z.boolean(),
|
|
112
|
+
current: z.boolean(),
|
|
113
|
+
});
|
|
114
|
+
export const workspaceInventorySummaryOutputSchema = z.object({
|
|
115
|
+
total: z.number().int().nonnegative(),
|
|
116
|
+
matching: z.number().int().nonnegative(),
|
|
117
|
+
active: z.number().int().nonnegative(),
|
|
118
|
+
stale: z.number().int().nonnegative(),
|
|
119
|
+
invalid: z.number().int().nonnegative(),
|
|
120
|
+
closed: z.number().int().nonnegative(),
|
|
121
|
+
});
|
|
122
|
+
export const workspaceInventoryPageOutputSchema = z.object({
|
|
123
|
+
offset: z.number().int().nonnegative(),
|
|
124
|
+
limit: z.number().int().positive(),
|
|
125
|
+
hasMore: z.boolean(),
|
|
126
|
+
});
|
|
127
|
+
export const workspaceTaskInspectionSummaryOutputSchema = z.object({
|
|
128
|
+
level: z.literal("summary"),
|
|
129
|
+
version: z.literal(1),
|
|
130
|
+
revision: z.number().int().nonnegative(),
|
|
131
|
+
lists: z.array(z.object({
|
|
132
|
+
id: z.string(),
|
|
133
|
+
name: z.string(),
|
|
134
|
+
state: z.enum(["active", "archived"]),
|
|
135
|
+
revision: z.number().int().positive(),
|
|
136
|
+
taskCount: z.number().int().nonnegative(),
|
|
137
|
+
unfinishedTaskCount: z.number().int().nonnegative(),
|
|
138
|
+
})),
|
|
139
|
+
});
|
|
140
|
+
export const workspaceInspectionMemberOutputSchema = z.object({
|
|
141
|
+
name: z.string(),
|
|
142
|
+
purpose: z.string(),
|
|
143
|
+
workspaceId: z.string(),
|
|
144
|
+
known: z.boolean(),
|
|
145
|
+
location: z.enum(["local", "relay"]).optional(),
|
|
146
|
+
state: z.enum(["active", "stale", "invalid", "closed"]).optional(),
|
|
147
|
+
status: z.string().optional(),
|
|
148
|
+
routeState: z.literal("known").optional(),
|
|
149
|
+
mode: z.enum(["checkout", "worktree"]).optional(),
|
|
150
|
+
rootValid: z.boolean().optional(),
|
|
151
|
+
});
|
|
152
|
+
export const workspaceInspectionOutputSchema = z.union([
|
|
153
|
+
z.object({
|
|
154
|
+
workspaceId: z.string(),
|
|
155
|
+
kind: z.literal("workspace"),
|
|
156
|
+
location: z.literal("local"),
|
|
157
|
+
label: z.string(),
|
|
158
|
+
root: z.string(),
|
|
159
|
+
status: z.string(),
|
|
160
|
+
state: z.enum(["active", "stale", "invalid", "closed"]),
|
|
161
|
+
mode: z.enum(["checkout", "worktree"]),
|
|
162
|
+
sourceRoot: z.string().optional(),
|
|
163
|
+
branch: z.string().optional(),
|
|
164
|
+
targetBranch: z.string().optional(),
|
|
165
|
+
managed: z.boolean(),
|
|
166
|
+
createdAt: z.string(),
|
|
167
|
+
lastUsedAt: z.string(),
|
|
168
|
+
idleMs: z.number().nonnegative(),
|
|
169
|
+
rootValid: z.boolean(),
|
|
170
|
+
taskSummary: workspaceTaskInspectionSummaryOutputSchema.optional(),
|
|
171
|
+
}),
|
|
172
|
+
z.object({
|
|
173
|
+
workspaceId: z.string(),
|
|
174
|
+
kind: z.literal("workspace"),
|
|
175
|
+
location: z.literal("relay"),
|
|
176
|
+
root: z.string(),
|
|
177
|
+
routeState: z.literal("known"),
|
|
178
|
+
status: z.string().optional(),
|
|
179
|
+
state: z.enum(["active", "stale", "invalid", "closed"]).optional(),
|
|
180
|
+
mode: z.enum(["checkout", "worktree"]),
|
|
181
|
+
sourceRoot: z.string().optional(),
|
|
182
|
+
branch: z.string().optional(),
|
|
183
|
+
targetBranch: z.string().optional(),
|
|
184
|
+
managed: z.boolean().optional(),
|
|
185
|
+
createdAt: z.string().optional(),
|
|
186
|
+
lastUsedAt: z.string().optional(),
|
|
187
|
+
idleMs: z.number().nonnegative().optional(),
|
|
188
|
+
rootValid: z.boolean().optional(),
|
|
189
|
+
taskSummary: workspaceTaskInspectionSummaryOutputSchema.optional(),
|
|
190
|
+
relay: z.string(),
|
|
191
|
+
executionLocation: z.string(),
|
|
192
|
+
}),
|
|
193
|
+
z.object({
|
|
194
|
+
workspaceId: z.string(),
|
|
195
|
+
kind: z.literal("composite"),
|
|
196
|
+
name: z.string(),
|
|
197
|
+
status: z.enum(["active", "closed"]),
|
|
198
|
+
state: z.enum(["active", "closed"]),
|
|
199
|
+
createdAt: z.string(),
|
|
200
|
+
lastUsedAt: z.string(),
|
|
201
|
+
members: z.array(workspaceInspectionMemberOutputSchema),
|
|
202
|
+
taskSummary: workspaceTaskInspectionSummaryOutputSchema.optional(),
|
|
203
|
+
}),
|
|
204
|
+
]);
|
|
205
|
+
export const reviewFileOutputSchema = z.object({
|
|
206
|
+
path: z.string(),
|
|
207
|
+
previousPath: z.string().optional(),
|
|
208
|
+
type: z.enum(["change", "rename-pure", "rename-changed", "new", "deleted"]),
|
|
209
|
+
additions: z.number(),
|
|
210
|
+
removals: z.number(),
|
|
211
|
+
});
|
|
212
|
+
export const reviewSummaryOutputSchema = z.object({
|
|
213
|
+
files: z.number(),
|
|
214
|
+
additions: z.number(),
|
|
215
|
+
removals: z.number(),
|
|
216
|
+
});
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { commandPreview, logEvent, workspaceLogLabel } from "../../../runtime/logging/logger.js";
|
|
3
|
+
import { formatAgentsPath } from "../../../workspaces.js";
|
|
4
|
+
export function workspaceLogContext(workspace, _transportSessionId) {
|
|
5
|
+
return {
|
|
6
|
+
workspaceId: workspace.id,
|
|
7
|
+
workspace: workspaceLogLabel(workspace.root, workspace.id),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export function formatDiscoveredWorkspaceInstructions(files, workspaceRoot) {
|
|
11
|
+
return [
|
|
12
|
+
"Workspace instructions discovered for this path. Apply them to follow-up work under their directories:",
|
|
13
|
+
...files.flatMap((file) => [
|
|
14
|
+
`--- ${formatAgentsPath(file.path, workspaceRoot)} ---`,
|
|
15
|
+
file.content.trimEnd(),
|
|
16
|
+
]),
|
|
17
|
+
].join("\n");
|
|
18
|
+
}
|
|
19
|
+
export async function assertWorkspaceInstructionsLoadedBeforeSideEffect(workspaces, workspace, paths) {
|
|
20
|
+
const discovered = new Map();
|
|
21
|
+
for (const path of paths) {
|
|
22
|
+
const absolutePath = resolve(workspace.root, path);
|
|
23
|
+
for (const file of await workspaces.discoverPathInstructions(workspace, absolutePath)) {
|
|
24
|
+
discovered.set(file.path, file);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (discovered.size === 0)
|
|
28
|
+
return;
|
|
29
|
+
throw new Error([
|
|
30
|
+
formatDiscoveredWorkspaceInstructions([...discovered.values()], workspace.root),
|
|
31
|
+
"Apply these instructions, then retry this tool call. No mutation or command was executed.",
|
|
32
|
+
].join("\n"));
|
|
33
|
+
}
|
|
34
|
+
export function logToolCall(config, fields) {
|
|
35
|
+
if (!config.logging.toolCalls)
|
|
36
|
+
return;
|
|
37
|
+
const { command, ...safeFields } = fields;
|
|
38
|
+
logEvent(config.logging, fields.success ? "info" : "warn", "tool_call", {
|
|
39
|
+
...safeFields,
|
|
40
|
+
commandPreview: config.logging.shellCommands && command ? commandPreview(command) : undefined,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export function contentText(content) {
|
|
44
|
+
return content
|
|
45
|
+
.filter((item) => item.type === "text")
|
|
46
|
+
.map((item) => item.text)
|
|
47
|
+
.join("\n");
|
|
48
|
+
}
|
|
49
|
+
export function toolErrorPreview(content) {
|
|
50
|
+
const text = contentText(content).replace(/\s+/g, " ").trim();
|
|
51
|
+
if (!text)
|
|
52
|
+
return undefined;
|
|
53
|
+
return text.length > 240 ? `${text.slice(0, 237)}...` : text;
|
|
54
|
+
}
|
|
55
|
+
export function logFailedToolResponse(config, fields, content, startedAt) {
|
|
56
|
+
logToolCall(config, {
|
|
57
|
+
...fields,
|
|
58
|
+
success: false,
|
|
59
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
60
|
+
error: toolErrorPreview(content),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export function textBlock(text) {
|
|
64
|
+
return { type: "text", text };
|
|
65
|
+
}
|
|
66
|
+
export function attachWorkspaceTaskReminder(result, reminder) {
|
|
67
|
+
if (!reminder || toolResultIsError(result) || typeof result !== "object" || result === null)
|
|
68
|
+
return result;
|
|
69
|
+
const content = result.content;
|
|
70
|
+
if (!Array.isArray(content))
|
|
71
|
+
return result;
|
|
72
|
+
return {
|
|
73
|
+
...result,
|
|
74
|
+
content: [...content, textBlock(reminder)],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export function textSummary(content) {
|
|
78
|
+
const text = contentText(content);
|
|
79
|
+
return {
|
|
80
|
+
lines: text.length === 0 ? 0 : text.split("\n").length,
|
|
81
|
+
characters: text.length,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function contentLineCount(content) {
|
|
85
|
+
if (content.length === 0)
|
|
86
|
+
return 0;
|
|
87
|
+
return content.endsWith("\n")
|
|
88
|
+
? content.slice(0, -1).split("\n").length
|
|
89
|
+
: content.split("\n").length;
|
|
90
|
+
}
|
|
91
|
+
export function countDiffStats(diff) {
|
|
92
|
+
if (!diff)
|
|
93
|
+
return { additions: 0, removals: 0 };
|
|
94
|
+
let additions = 0;
|
|
95
|
+
let removals = 0;
|
|
96
|
+
for (const line of diff.split("\n")) {
|
|
97
|
+
if (line.startsWith("+") && !line.startsWith("+++"))
|
|
98
|
+
additions++;
|
|
99
|
+
if (line.startsWith("-") && !line.startsWith("---"))
|
|
100
|
+
removals++;
|
|
101
|
+
}
|
|
102
|
+
return { additions, removals };
|
|
103
|
+
}
|
|
104
|
+
export function newFilePatch(path, content) {
|
|
105
|
+
const lines = content.length === 0
|
|
106
|
+
? []
|
|
107
|
+
: content.endsWith("\n")
|
|
108
|
+
? content.slice(0, -1).split("\n")
|
|
109
|
+
: content.split("\n");
|
|
110
|
+
const hunkLength = lines.length;
|
|
111
|
+
const hunkRange = hunkLength === 0 ? "+0,0" : `+1,${hunkLength}`;
|
|
112
|
+
const body = lines.map((line) => `+${line}`).join("\n");
|
|
113
|
+
return [
|
|
114
|
+
`diff --git a/${path} b/${path}`,
|
|
115
|
+
"new file mode 100644",
|
|
116
|
+
"index 0000000..0000000",
|
|
117
|
+
"--- /dev/null",
|
|
118
|
+
`+++ b/${path}`,
|
|
119
|
+
`@@ -0,0 ${hunkRange} @@`,
|
|
120
|
+
body,
|
|
121
|
+
]
|
|
122
|
+
.filter((line) => line.length > 0)
|
|
123
|
+
.join("\n");
|
|
124
|
+
}
|
|
125
|
+
export function toolResultIsError(result) {
|
|
126
|
+
return typeof result === "object" && result !== null && result.isError === true;
|
|
127
|
+
}
|
|
128
|
+
export function toolResultText(result) {
|
|
129
|
+
if (typeof result !== "object" || result === null)
|
|
130
|
+
return String(result ?? "");
|
|
131
|
+
const record = result;
|
|
132
|
+
if (Array.isArray(record.content)) {
|
|
133
|
+
const text = record.content
|
|
134
|
+
.map((entry) => {
|
|
135
|
+
if (typeof entry !== "object" || entry === null)
|
|
136
|
+
return "";
|
|
137
|
+
const value = entry.text;
|
|
138
|
+
return typeof value === "string" ? value : "";
|
|
139
|
+
})
|
|
140
|
+
.filter(Boolean)
|
|
141
|
+
.join("\n");
|
|
142
|
+
if (text)
|
|
143
|
+
return text;
|
|
144
|
+
}
|
|
145
|
+
if (typeof record.structuredContent === "object" && record.structuredContent !== null) {
|
|
146
|
+
const value = record.structuredContent.result;
|
|
147
|
+
if (typeof value === "string")
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
return "";
|
|
151
|
+
}
|
|
152
|
+
export function toolResultContent(result) {
|
|
153
|
+
if (typeof result !== "object" || result === null)
|
|
154
|
+
return [];
|
|
155
|
+
const content = result.content;
|
|
156
|
+
return Array.isArray(content) ? content : [];
|
|
157
|
+
}
|
|
158
|
+
export function remapCompositeToolResult(result, executionWorkspaceId, compositeWorkspaceId, member) {
|
|
159
|
+
if (typeof result !== "object" || result === null)
|
|
160
|
+
return result;
|
|
161
|
+
const record = result;
|
|
162
|
+
const remapped = replaceWorkspaceIdentity(record, executionWorkspaceId, compositeWorkspaceId);
|
|
163
|
+
const meta = typeof remapped._meta === "object" && remapped._meta !== null
|
|
164
|
+
? { ...remapped._meta }
|
|
165
|
+
: undefined;
|
|
166
|
+
if (meta) {
|
|
167
|
+
const card = typeof meta.card === "object" && meta.card !== null
|
|
168
|
+
? { ...meta.card, workspaceId: compositeWorkspaceId, member }
|
|
169
|
+
: undefined;
|
|
170
|
+
if (card)
|
|
171
|
+
meta.card = card;
|
|
172
|
+
remapped._meta = meta;
|
|
173
|
+
}
|
|
174
|
+
const structured = typeof remapped.structuredContent === "object" && remapped.structuredContent !== null
|
|
175
|
+
? { ...remapped.structuredContent, member }
|
|
176
|
+
: undefined;
|
|
177
|
+
if (structured)
|
|
178
|
+
remapped.structuredContent = structured;
|
|
179
|
+
return remapped;
|
|
180
|
+
}
|
|
181
|
+
export function replaceWorkspaceIdentity(value, from, to) {
|
|
182
|
+
if (typeof value === "string")
|
|
183
|
+
return value.split(from).join(to);
|
|
184
|
+
if (Array.isArray(value))
|
|
185
|
+
return value.map((entry) => replaceWorkspaceIdentity(entry, from, to));
|
|
186
|
+
if (!value || typeof value !== "object")
|
|
187
|
+
return value;
|
|
188
|
+
return Object.fromEntries(Object.entries(value)
|
|
189
|
+
.map(([key, entry]) => [key, replaceWorkspaceIdentity(entry, from, to)]));
|
|
190
|
+
}
|
|
191
|
+
export function toolResultAgentsFiles(result) {
|
|
192
|
+
if (typeof result !== "object" || result === null)
|
|
193
|
+
return [];
|
|
194
|
+
const structured = result.structuredContent;
|
|
195
|
+
if (typeof structured !== "object" || structured === null)
|
|
196
|
+
return [];
|
|
197
|
+
const agentsFiles = structured.agentsFiles;
|
|
198
|
+
if (!Array.isArray(agentsFiles))
|
|
199
|
+
return [];
|
|
200
|
+
return agentsFiles.flatMap((entry) => {
|
|
201
|
+
if (typeof entry !== "object" || entry === null)
|
|
202
|
+
return [];
|
|
203
|
+
const path = entry.path;
|
|
204
|
+
const content = entry.content;
|
|
205
|
+
return typeof path === "string" && typeof content === "string" ? [{ path, content }] : [];
|
|
206
|
+
});
|
|
207
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
export const FORGERELAY_VERSION = readForgeRelayVersion();
|
|
3
|
+
function readForgeRelayVersion() {
|
|
4
|
+
const packageJson = JSON.parse(readFileSync(new URL("../../../../package.json", import.meta.url), "utf8"));
|
|
5
|
+
if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
|
|
6
|
+
throw new Error("Unable to read ForgeRelay package version.");
|
|
7
|
+
}
|
|
8
|
+
return packageJson.version;
|
|
9
|
+
}
|