@aria-cli/tools 1.0.9 → 1.0.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/package.json +9 -5
- package/src/__tests__/web-fetch-download.test.ts +0 -433
- package/src/__tests__/web-tools.test.ts +0 -619
- package/src/ask-user-interaction.ts +0 -33
- package/src/cache/web-cache.ts +0 -110
- package/src/definitions/arion.ts +0 -118
- package/src/definitions/browser/browser.ts +0 -502
- package/src/definitions/browser/index.ts +0 -5
- package/src/definitions/browser/pw-downloads.ts +0 -142
- package/src/definitions/browser/pw-interactions.ts +0 -282
- package/src/definitions/browser/pw-responses.ts +0 -98
- package/src/definitions/browser/pw-session.ts +0 -405
- package/src/definitions/browser/pw-shared.ts +0 -85
- package/src/definitions/browser/pw-snapshot.ts +0 -383
- package/src/definitions/browser/pw-state.ts +0 -101
- package/src/definitions/browser/types.ts +0 -203
- package/src/definitions/code-intelligence.ts +0 -526
- package/src/definitions/core.ts +0 -118
- package/src/definitions/delegation.ts +0 -567
- package/src/definitions/deploy.ts +0 -73
- package/src/definitions/filesystem.ts +0 -217
- package/src/definitions/frg.ts +0 -67
- package/src/definitions/index.ts +0 -28
- package/src/definitions/memory.ts +0 -150
- package/src/definitions/messaging.ts +0 -734
- package/src/definitions/meta.ts +0 -392
- package/src/definitions/network.ts +0 -179
- package/src/definitions/outlook.ts +0 -318
- package/src/definitions/patch/apply-patch.ts +0 -235
- package/src/definitions/patch/fuzzy-match.ts +0 -217
- package/src/definitions/patch/index.ts +0 -1
- package/src/definitions/patch/patch-parser.ts +0 -297
- package/src/definitions/patch/sandbox-paths.ts +0 -129
- package/src/definitions/process/index.ts +0 -5
- package/src/definitions/process/process-registry.ts +0 -303
- package/src/definitions/process/process.ts +0 -456
- package/src/definitions/process/pty-keys.ts +0 -298
- package/src/definitions/process/session-slug.ts +0 -147
- package/src/definitions/quip.ts +0 -225
- package/src/definitions/search.ts +0 -67
- package/src/definitions/session-history.ts +0 -79
- package/src/definitions/shell.ts +0 -202
- package/src/definitions/slack.ts +0 -211
- package/src/definitions/web.ts +0 -119
- package/src/executors/apply-patch.ts +0 -1035
- package/src/executors/arion.ts +0 -199
- package/src/executors/code-intelligence.ts +0 -1179
- package/src/executors/deploy.ts +0 -1066
- package/src/executors/filesystem.ts +0 -1428
- package/src/executors/frg-freshness.ts +0 -743
- package/src/executors/frg.ts +0 -394
- package/src/executors/index.ts +0 -280
- package/src/executors/learning-meta.ts +0 -1367
- package/src/executors/lsp-client.ts +0 -355
- package/src/executors/memory.ts +0 -978
- package/src/executors/meta.ts +0 -293
- package/src/executors/process-registry.ts +0 -570
- package/src/executors/pty-session-store.ts +0 -43
- package/src/executors/pty.ts +0 -342
- package/src/executors/restart.ts +0 -133
- package/src/executors/search-freshness.ts +0 -249
- package/src/executors/search-types.ts +0 -98
- package/src/executors/search.ts +0 -89
- package/src/executors/self-diagnose.ts +0 -552
- package/src/executors/session-history.ts +0 -435
- package/src/executors/shell-safety.ts +0 -519
- package/src/executors/shell.ts +0 -1243
- package/src/executors/utils.ts +0 -40
- package/src/executors/web.ts +0 -786
- package/src/extraction/content-extraction.ts +0 -281
- package/src/extraction/index.ts +0 -5
- package/src/headless-control-contract.ts +0 -1149
- package/src/index.ts +0 -788
- package/src/local-control-http-auth.ts +0 -2
- package/src/mcp/client.ts +0 -218
- package/src/mcp/connection.ts +0 -568
- package/src/mcp/index.ts +0 -11
- package/src/mcp/jsonrpc.ts +0 -195
- package/src/mcp/types.ts +0 -199
- package/src/network-control-adapter.ts +0 -88
- package/src/network-runtime/address-types.ts +0 -218
- package/src/network-runtime/db-owner-fencing.ts +0 -91
- package/src/network-runtime/delivery-receipts.ts +0 -372
- package/src/network-runtime/direct-endpoint-authority.ts +0 -35
- package/src/network-runtime/index.ts +0 -316
- package/src/network-runtime/local-control-contract.ts +0 -784
- package/src/network-runtime/node-store-contract.ts +0 -46
- package/src/network-runtime/pair-route-contract.ts +0 -97
- package/src/network-runtime/peer-capabilities.ts +0 -48
- package/src/network-runtime/peer-principal-ref.ts +0 -20
- package/src/network-runtime/peer-state-machine.ts +0 -160
- package/src/network-runtime/protocol-schemas.ts +0 -265
- package/src/network-runtime/runtime-bootstrap-contract.ts +0 -83
- package/src/outlook/desktop-session.ts +0 -409
- package/src/policy.ts +0 -171
- package/src/providers/brave.ts +0 -80
- package/src/providers/duckduckgo.ts +0 -199
- package/src/providers/exa.ts +0 -85
- package/src/providers/firecrawl.ts +0 -77
- package/src/providers/index.ts +0 -8
- package/src/providers/jina.ts +0 -70
- package/src/providers/router.ts +0 -121
- package/src/providers/search-provider.ts +0 -74
- package/src/providers/tavily.ts +0 -74
- package/src/quip/desktop-session.ts +0 -435
- package/src/registry/index.ts +0 -1
- package/src/registry/registry.ts +0 -905
- package/src/runtime-socket-local-control-client.ts +0 -632
- package/src/security/dns-normalization.ts +0 -34
- package/src/security/dns-pinning.ts +0 -138
- package/src/security/external-content.ts +0 -129
- package/src/security/ssrf.ts +0 -207
- package/src/slack/desktop-session.ts +0 -493
- package/src/tool-factory.ts +0 -91
- package/src/types.ts +0 -1341
- package/src/utils/retry.ts +0 -163
- package/src/utils/safe-parse-json.ts +0 -176
- package/src/utils/url.ts +0 -20
- package/tests/benchmarks/registry.bench.ts +0 -57
- package/tests/cache/web-cache.test.ts +0 -147
- package/tests/critical-integration.test.ts +0 -1465
- package/tests/definitions/apply-patch.test.ts +0 -586
- package/tests/definitions/browser.test.ts +0 -495
- package/tests/definitions/delegation-pause-resume.test.ts +0 -758
- package/tests/definitions/execution.test.ts +0 -671
- package/tests/definitions/messaging-inbox-scope.test.ts +0 -229
- package/tests/definitions/messaging.test.ts +0 -1468
- package/tests/definitions/outlook.test.ts +0 -30
- package/tests/definitions/process.test.ts +0 -469
- package/tests/definitions/slack.test.ts +0 -28
- package/tests/definitions/tool-inventory.test.ts +0 -218
- package/tests/e2e/delegation-quest-orchestration.e2e.test.ts +0 -433
- package/tests/e2e/memory-tool-discovery-contract.e2e.test.ts +0 -81
- package/tests/executors/apply-patch.test.ts +0 -538
- package/tests/executors/arion.test.ts +0 -309
- package/tests/executors/conversation-primitives.test.ts +0 -250
- package/tests/executors/deploy.test.ts +0 -746
- package/tests/executors/filesystem-tools.test.ts +0 -357
- package/tests/executors/filesystem.test.ts +0 -959
- package/tests/executors/frg-freshness.test.ts +0 -136
- package/tests/executors/frg-merge.test.ts +0 -70
- package/tests/executors/frg-session-content.test.ts +0 -40
- package/tests/executors/frg.test.ts +0 -56
- package/tests/executors/memory-bugfixes.test.ts +0 -257
- package/tests/executors/memory-real-memoria.integration.test.ts +0 -316
- package/tests/executors/memory.test.ts +0 -853
- package/tests/executors/meta-tools.test.ts +0 -411
- package/tests/executors/meta.test.ts +0 -683
- package/tests/executors/path-containment.test.ts +0 -51
- package/tests/executors/process-registry.test.ts +0 -505
- package/tests/executors/pty.test.ts +0 -664
- package/tests/executors/quest-security.test.ts +0 -249
- package/tests/executors/read-file-media.test.ts +0 -230
- package/tests/executors/recall-knowledge-schema.test.ts +0 -209
- package/tests/executors/recall-tags.test.ts +0 -278
- package/tests/executors/remember-null-safety.contract.test.ts +0 -41
- package/tests/executors/restart.test.ts +0 -67
- package/tests/executors/search-unified.test.ts +0 -381
- package/tests/executors/session-history.test.ts +0 -340
- package/tests/executors/session-transcript.test.ts +0 -561
- package/tests/executors/shell-abort.test.ts +0 -416
- package/tests/executors/shell-env-blocklist.test.ts +0 -648
- package/tests/executors/shell-env-process.test.ts +0 -245
- package/tests/executors/shell-process-registry.test.ts +0 -334
- package/tests/executors/shell-tools.test.ts +0 -393
- package/tests/executors/shell.test.ts +0 -690
- package/tests/executors/web-abort-vs-timeout.test.ts +0 -213
- package/tests/executors/web-integration.test.ts +0 -633
- package/tests/executors/web-symlink.test.ts +0 -18
- package/tests/executors/web.test.ts +0 -1400
- package/tests/executors/write-stdin.test.ts +0 -145
- package/tests/extraction/content-extraction.test.ts +0 -153
- package/tests/guards/tools-default-test-lane.integration.test.ts +0 -21
- package/tests/guards/tools-package-test-commands.e2e.test.ts +0 -43
- package/tests/guards/tools-test-lane-manifest.contract.test.ts +0 -76
- package/tests/guards/tools-vitest-workspace-alias.contract.test.ts +0 -63
- package/tests/helpers/async-waits.ts +0 -53
- package/tests/integration/headless-control-contract.integration.test.ts +0 -153
- package/tests/integration/memory-tool-schema-parity.integration.test.ts +0 -67
- package/tests/integration/meta-tools-round-trip.integration.test.ts +0 -506
- package/tests/integration/quest-round-trip.test.ts +0 -303
- package/tests/integration/registry-executor-flow.test.ts +0 -85
- package/tests/integration.test.ts +0 -177
- package/tests/loading-tier.test.ts +0 -126
- package/tests/mcp/client-reconnect.test.ts +0 -267
- package/tests/mcp/connection.test.ts +0 -846
- package/tests/mcp/injectable-logger.test.ts +0 -83
- package/tests/mcp/jsonrpc.test.ts +0 -109
- package/tests/mcp/lifecycle.test.ts +0 -879
- package/tests/network-runtime/address-types.contract.test.ts +0 -143
- package/tests/network-runtime/continuity-bind-schema.contract.test.ts +0 -203
- package/tests/network-runtime/local-control-contract.test.ts +0 -869
- package/tests/network-runtime/local-control-invite-token.contract.test.ts +0 -146
- package/tests/network-runtime/node-store-contract.test.ts +0 -11
- package/tests/network-runtime/pair-protocol-nodeid.contract.test.ts +0 -15
- package/tests/network-runtime/peer-state-machine.contract.test.ts +0 -148
- package/tests/network-runtime/protocol-schemas.contract.test.ts +0 -512
- package/tests/network-runtime/relay-pending-nodeid.contract.test.ts +0 -62
- package/tests/network-runtime/runtime-bootstrap-contract.test.ts +0 -227
- package/tests/network-runtime/runtime-socket-local-control-client.test.ts +0 -621
- package/tests/network-runtime/wait-for-message-script.test.ts +0 -288
- package/tests/parallel.test.ts +0 -71
- package/tests/policy.test.ts +0 -184
- package/tests/print-default-test-lane.ts +0 -14
- package/tests/print-test-lane-manifest.ts +0 -22
- package/tests/providers/brave.test.ts +0 -159
- package/tests/providers/duckduckgo.test.ts +0 -207
- package/tests/providers/exa.test.ts +0 -175
- package/tests/providers/firecrawl.test.ts +0 -168
- package/tests/providers/jina.test.ts +0 -144
- package/tests/providers/router.test.ts +0 -328
- package/tests/providers/tavily.test.ts +0 -165
- package/tests/registry/discovery.test.ts +0 -154
- package/tests/registry/injectable-logger.test.ts +0 -230
- package/tests/registry/input-validation.test.ts +0 -361
- package/tests/registry/interface-completeness.test.ts +0 -85
- package/tests/registry/mcp-integration.test.ts +0 -103
- package/tests/registry/mcp-read-only-hint.test.ts +0 -60
- package/tests/registry/memoria-discovery.test.ts +0 -390
- package/tests/registry/nested-validation.test.ts +0 -283
- package/tests/registry/pseudo-tool-filtering.test.ts +0 -258
- package/tests/registry/registration-lifecycle.test.ts +0 -133
- package/tests/registry-validation.test.ts +0 -424
- package/tests/registry.test.ts +0 -460
- package/tests/security/dns-pinning.test.ts +0 -162
- package/tests/security/external-content.test.ts +0 -144
- package/tests/security/ssrf.test.ts +0 -118
- package/tests/shell-safety-integration.test.ts +0 -32
- package/tests/shell-safety.test.ts +0 -365
- package/tests/slack/desktop-session.test.ts +0 -50
- package/tests/test-lane-manifest.ts +0 -440
- package/tests/test-utils.ts +0 -27
- package/tests/tool-factory.test.ts +0 -188
- package/tests/utils/retry.test.ts +0 -231
- package/tests/utils/url.test.ts +0 -63
- package/tsconfig.cjs.json +0 -24
- package/tsconfig.json +0 -12
- package/vitest.config.ts +0 -55
- package/vitest.e2e.config.ts +0 -24
- package/vitest.integration.config.ts +0 -24
- package/vitest.native.config.ts +0 -24
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @aria/tools - Tool inventory tests
|
|
3
|
-
*
|
|
4
|
-
* Validates the complete tool inventory: counts, names, categories,
|
|
5
|
-
* confirmation requirements, and loading tiers.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { describe, it, expect } from "vitest";
|
|
9
|
-
import {
|
|
10
|
-
CORE_TOOL_DEFINITIONS,
|
|
11
|
-
MEMORY_TOOL_DEFINITIONS,
|
|
12
|
-
WEB_TOOL_DEFINITIONS,
|
|
13
|
-
FILESYSTEM_TOOL_DEFINITIONS,
|
|
14
|
-
SHELL_TOOL_DEFINITIONS,
|
|
15
|
-
ARION_TOOL_DEFINITIONS,
|
|
16
|
-
DELEGATION_TOOL_DEFINITIONS,
|
|
17
|
-
META_TOOL_DEFINITIONS,
|
|
18
|
-
FRG_TOOL_DEFINITIONS,
|
|
19
|
-
} from "../../src/definitions/core.js";
|
|
20
|
-
|
|
21
|
-
describe("Tool Inventory", () => {
|
|
22
|
-
describe("total tool count", () => {
|
|
23
|
-
it("should have exactly 74 core tools", () => {
|
|
24
|
-
expect(CORE_TOOL_DEFINITIONS).toHaveLength(74);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
describe("tool names", () => {
|
|
29
|
-
const toolNames = () => CORE_TOOL_DEFINITIONS.map((t) => t.name);
|
|
30
|
-
|
|
31
|
-
it("should include new tools from refactoring", () => {
|
|
32
|
-
const names = toolNames();
|
|
33
|
-
expect(names).toContain("ask_user");
|
|
34
|
-
expect(names).toContain("quest_update");
|
|
35
|
-
expect(names).toContain("quest_list");
|
|
36
|
-
expect(names).toContain("apply_patch");
|
|
37
|
-
expect(names).toContain("write_stdin");
|
|
38
|
-
expect(names).toContain("ls");
|
|
39
|
-
expect(names).toContain("frg");
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("should include OpenClaw-forked tools", () => {
|
|
43
|
-
const names = toolNames();
|
|
44
|
-
expect(names).toContain("browser");
|
|
45
|
-
expect(names).toContain("process");
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it("should NOT include removed/consolidated tools", () => {
|
|
49
|
-
const names = toolNames();
|
|
50
|
-
expect(names).not.toContain("mkdir");
|
|
51
|
-
expect(names).not.toContain("cp");
|
|
52
|
-
expect(names).not.toContain("mv");
|
|
53
|
-
expect(names).not.toContain("rm");
|
|
54
|
-
expect(names).not.toContain("download");
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it("should have unique tool names (no duplicates)", () => {
|
|
58
|
-
const names = toolNames();
|
|
59
|
-
expect(new Set(names).size).toBe(names.length);
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe("requiresConfirmation", () => {
|
|
64
|
-
const findTool = (name: string) => CORE_TOOL_DEFINITIONS.find((t) => t.name === name);
|
|
65
|
-
|
|
66
|
-
it("forget requires confirmation", () => {
|
|
67
|
-
expect(findTool("forget")?.requiresConfirmation).toBe(true);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it("kill requires confirmation", () => {
|
|
71
|
-
expect(findTool("kill")?.requiresConfirmation).toBe(true);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("apply_patch requires confirmation", () => {
|
|
75
|
-
expect(findTool("apply_patch")?.requiresConfirmation).toBe(true);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("bash requires confirmation", () => {
|
|
79
|
-
expect(findTool("bash")?.requiresConfirmation).toBe(true);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it("hatch_arion requires confirmation", () => {
|
|
83
|
-
expect(findTool("hatch_arion")?.requiresConfirmation).toBe(true);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it("retire_arion requires confirmation", () => {
|
|
87
|
-
expect(findTool("retire_arion")?.requiresConfirmation).toBe(true);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("read-only tools do not require confirmation", () => {
|
|
91
|
-
const readOnlyTools = CORE_TOOL_DEFINITIONS.filter((t) => t.isReadOnly);
|
|
92
|
-
for (const tool of readOnlyTools) {
|
|
93
|
-
expect(
|
|
94
|
-
tool.requiresConfirmation,
|
|
95
|
-
`Read-only tool "${tool.name}" should not require confirmation`,
|
|
96
|
-
).toBeFalsy();
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
describe("loadingTier", () => {
|
|
102
|
-
it("every tool has a loadingTier defined", () => {
|
|
103
|
-
for (const tool of CORE_TOOL_DEFINITIONS) {
|
|
104
|
-
expect(
|
|
105
|
-
tool.loadingTier,
|
|
106
|
-
`Tool "${tool.name}" should have loadingTier defined`,
|
|
107
|
-
).toBeDefined();
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it("all core tools have loadingTier 'always' or 'deferred'", () => {
|
|
112
|
-
const ALLOWED_DEFERRED = new Set(["session_history", "frg"]);
|
|
113
|
-
for (const tool of CORE_TOOL_DEFINITIONS) {
|
|
114
|
-
if (ALLOWED_DEFERRED.has(tool.name)) {
|
|
115
|
-
expect(tool.loadingTier, `Tool "${tool.name}" should have loadingTier "deferred"`).toBe(
|
|
116
|
-
"deferred",
|
|
117
|
-
);
|
|
118
|
-
} else {
|
|
119
|
-
expect(tool.loadingTier, `Tool "${tool.name}" should have loadingTier "always"`).toBe(
|
|
120
|
-
"always",
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
describe("category counts", () => {
|
|
128
|
-
const countByCategory = (category: string) =>
|
|
129
|
-
CORE_TOOL_DEFINITIONS.filter((t) => t.category === category).length;
|
|
130
|
-
|
|
131
|
-
it("filesystem: 8 tools", () => {
|
|
132
|
-
expect(countByCategory("filesystem")).toBe(8);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("shell: 8 tools", () => {
|
|
136
|
-
expect(countByCategory("shell")).toBe(8);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it("web: 4 tools", () => {
|
|
140
|
-
expect(countByCategory("web")).toBe(4);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("memory: 6 tools", () => {
|
|
144
|
-
expect(countByCategory("memory")).toBe(6);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it("arion: 8 tools (4 lifecycle + delegate_arion + network + same-home client directory + deploy)", () => {
|
|
148
|
-
expect(countByCategory("arion")).toBe(8);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("meta: 17 tools (12 META_TOOL_DEFINITIONS + delegation tools)", () => {
|
|
152
|
-
expect(countByCategory("meta")).toBe(17);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it("messaging: 14 tools", () => {
|
|
156
|
-
expect(countByCategory("messaging")).toBe(14);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it("code: 9 tools (rg, ug, probe, sg, cbm, lsp, serena, fff, frg)", () => {
|
|
160
|
-
expect(countByCategory("code")).toBe(9);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it("category counts sum to total", () => {
|
|
164
|
-
const total =
|
|
165
|
-
countByCategory("filesystem") +
|
|
166
|
-
countByCategory("shell") +
|
|
167
|
-
countByCategory("web") +
|
|
168
|
-
countByCategory("memory") +
|
|
169
|
-
countByCategory("arion") +
|
|
170
|
-
countByCategory("meta") +
|
|
171
|
-
countByCategory("messaging") +
|
|
172
|
-
countByCategory("code");
|
|
173
|
-
expect(total).toBe(CORE_TOOL_DEFINITIONS.length);
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
describe("category definition arrays", () => {
|
|
178
|
-
it("MEMORY_TOOL_DEFINITIONS has 5 tools", () => {
|
|
179
|
-
expect(MEMORY_TOOL_DEFINITIONS).toHaveLength(5);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it("WEB_TOOL_DEFINITIONS has 3 tools", () => {
|
|
183
|
-
expect(WEB_TOOL_DEFINITIONS).toHaveLength(3);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it("FILESYSTEM_TOOL_DEFINITIONS has 7 tools", () => {
|
|
187
|
-
expect(FILESYSTEM_TOOL_DEFINITIONS).toHaveLength(7);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it("SHELL_TOOL_DEFINITIONS has 7 tools", () => {
|
|
191
|
-
expect(SHELL_TOOL_DEFINITIONS).toHaveLength(7);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it("ARION_TOOL_DEFINITIONS has 4 tools", () => {
|
|
195
|
-
expect(ARION_TOOL_DEFINITIONS).toHaveLength(4);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it("DELEGATION_TOOL_DEFINITIONS has 7 tools", () => {
|
|
199
|
-
expect(DELEGATION_TOOL_DEFINITIONS).toHaveLength(7);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it("META_TOOL_DEFINITIONS has 12 tools", () => {
|
|
203
|
-
expect(META_TOOL_DEFINITIONS).toHaveLength(12);
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
it("FRG_TOOL_DEFINITIONS has 1 tool", () => {
|
|
207
|
-
expect(FRG_TOOL_DEFINITIONS).toHaveLength(1);
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
describe("every tool has an execute function", () => {
|
|
212
|
-
it("all tools have execute as a function", () => {
|
|
213
|
-
for (const tool of CORE_TOOL_DEFINITIONS) {
|
|
214
|
-
expect(typeof tool.execute).toBe("function");
|
|
215
|
-
}
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
});
|
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { createToolRegistry } from "../../src/index.js";
|
|
3
|
-
import type {
|
|
4
|
-
DelegationEntryRef,
|
|
5
|
-
DelegationExecutorRef,
|
|
6
|
-
DelegationRegistryRef,
|
|
7
|
-
QuestStoreItem,
|
|
8
|
-
QuestStoreRef,
|
|
9
|
-
QuestStoreStatus,
|
|
10
|
-
Tool,
|
|
11
|
-
ToolContext,
|
|
12
|
-
} from "../../src/types.js";
|
|
13
|
-
|
|
14
|
-
interface InternalDelegationEntry extends DelegationEntryRef {
|
|
15
|
-
waiters: Array<(entry: DelegationEntryRef) => void>;
|
|
16
|
-
resolve: (result: string) => void;
|
|
17
|
-
reject: (error: Error) => void;
|
|
18
|
-
abortController: AbortController;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
class ControlledDelegationHarness implements DelegationExecutorRef, DelegationRegistryRef {
|
|
22
|
-
private readonly entries = new Map<string, InternalDelegationEntry>();
|
|
23
|
-
private sequence = 0;
|
|
24
|
-
|
|
25
|
-
get(id: string): DelegationEntryRef | undefined {
|
|
26
|
-
const entry = this.entries.get(id);
|
|
27
|
-
if (!entry) return undefined;
|
|
28
|
-
return this.toPublicEntry(entry);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
list(): DelegationEntryRef[] {
|
|
32
|
-
return Array.from(this.entries.values(), (entry) => this.toPublicEntry(entry));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async await(id: string, timeoutMs = 30_000): Promise<DelegationEntryRef> {
|
|
36
|
-
const entry = this.entries.get(id);
|
|
37
|
-
if (!entry) {
|
|
38
|
-
throw new Error(`Delegation not found: ${id}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (entry.status !== "running") {
|
|
42
|
-
return this.toPublicEntry(entry);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return new Promise<DelegationEntryRef>((resolve, reject) => {
|
|
46
|
-
const timeoutId = setTimeout(() => {
|
|
47
|
-
const idx = entry.waiters.indexOf(waiter);
|
|
48
|
-
if (idx !== -1) entry.waiters.splice(idx, 1);
|
|
49
|
-
reject(new Error("Delegation timed out"));
|
|
50
|
-
}, timeoutMs);
|
|
51
|
-
|
|
52
|
-
const waiter = (settled: DelegationEntryRef): void => {
|
|
53
|
-
clearTimeout(timeoutId);
|
|
54
|
-
resolve(settled);
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
entry.waiters.push(waiter);
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async delegateToArion(
|
|
62
|
-
arionName: string,
|
|
63
|
-
task: string,
|
|
64
|
-
_maxTurns?: number,
|
|
65
|
-
_tier?: string,
|
|
66
|
-
): Promise<string> {
|
|
67
|
-
return this.createEntry("arion", task, arionName);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async spawnWorker(
|
|
71
|
-
task: string,
|
|
72
|
-
_tools?: string[],
|
|
73
|
-
_maxTurns?: number,
|
|
74
|
-
_tier?: string,
|
|
75
|
-
): Promise<string> {
|
|
76
|
-
return this.createEntry("worker", task);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async spawnCliAgent(params: {
|
|
80
|
-
task: string;
|
|
81
|
-
driver: string;
|
|
82
|
-
workspace?: "cwd" | "tempdir" | "worktree";
|
|
83
|
-
model?: string;
|
|
84
|
-
resume?: string;
|
|
85
|
-
timeout?: number;
|
|
86
|
-
}): Promise<string> {
|
|
87
|
-
return this.createEntry("cli_agent", params.task, undefined, { driver: params.driver });
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
complete(id: string, result: string): void {
|
|
91
|
-
const entry = this.requireEntry(id);
|
|
92
|
-
entry.resolve(result);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
fail(id: string, error: string): void {
|
|
96
|
-
const entry = this.requireEntry(id);
|
|
97
|
-
entry.reject(new Error(error));
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
abort(id: string, error = "delegation aborted"): boolean {
|
|
101
|
-
const entry = this.entries.get(id);
|
|
102
|
-
if (!entry || entry.status !== "running") return false;
|
|
103
|
-
entry.abortController.abort();
|
|
104
|
-
entry.status = "aborted";
|
|
105
|
-
entry.error = error;
|
|
106
|
-
this.notify(entry);
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private createEntry(
|
|
111
|
-
type: DelegationEntryRef["type"],
|
|
112
|
-
task: string,
|
|
113
|
-
arionName?: string,
|
|
114
|
-
metadata?: DelegationEntryRef["metadata"],
|
|
115
|
-
): string {
|
|
116
|
-
const id = `quest_e2e${String(++this.sequence).padStart(6, "0")}`;
|
|
117
|
-
const abortController = new AbortController();
|
|
118
|
-
let resolve!: (result: string) => void;
|
|
119
|
-
let reject!: (error: Error) => void;
|
|
120
|
-
const promise = new Promise<string>((res, rej) => {
|
|
121
|
-
resolve = res;
|
|
122
|
-
reject = rej;
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
const entry: InternalDelegationEntry = {
|
|
126
|
-
id,
|
|
127
|
-
type,
|
|
128
|
-
arionName,
|
|
129
|
-
task,
|
|
130
|
-
status: "running",
|
|
131
|
-
metadata,
|
|
132
|
-
waiters: [],
|
|
133
|
-
resolve,
|
|
134
|
-
reject,
|
|
135
|
-
abortController,
|
|
136
|
-
};
|
|
137
|
-
this.entries.set(id, entry);
|
|
138
|
-
|
|
139
|
-
promise.then(
|
|
140
|
-
(result) => {
|
|
141
|
-
if (entry.status !== "running") return;
|
|
142
|
-
entry.status = "completed";
|
|
143
|
-
entry.result = result;
|
|
144
|
-
this.notify(entry);
|
|
145
|
-
},
|
|
146
|
-
(error: Error) => {
|
|
147
|
-
if (entry.status !== "running") return;
|
|
148
|
-
entry.status = "failed";
|
|
149
|
-
entry.error = error.message;
|
|
150
|
-
this.notify(entry);
|
|
151
|
-
},
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
return id;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private requireEntry(id: string): InternalDelegationEntry {
|
|
158
|
-
const entry = this.entries.get(id);
|
|
159
|
-
if (!entry) {
|
|
160
|
-
throw new Error(`Delegation not found: ${id}`);
|
|
161
|
-
}
|
|
162
|
-
return entry;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
private notify(entry: InternalDelegationEntry): void {
|
|
166
|
-
const publicEntry = this.toPublicEntry(entry);
|
|
167
|
-
const waiters = entry.waiters.splice(0);
|
|
168
|
-
for (const waiter of waiters) {
|
|
169
|
-
waiter(publicEntry);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private toPublicEntry(entry: InternalDelegationEntry): DelegationEntryRef {
|
|
174
|
-
return {
|
|
175
|
-
id: entry.id,
|
|
176
|
-
type: entry.type,
|
|
177
|
-
arionName: entry.arionName,
|
|
178
|
-
task: entry.task,
|
|
179
|
-
status: entry.status,
|
|
180
|
-
result: entry.result,
|
|
181
|
-
error: entry.error,
|
|
182
|
-
metadata: entry.metadata,
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
class InMemoryQuestStore implements QuestStoreRef {
|
|
188
|
-
private readonly quests = new Map<string, QuestStoreItem>();
|
|
189
|
-
|
|
190
|
-
createQuest(input: {
|
|
191
|
-
id: string;
|
|
192
|
-
title: string;
|
|
193
|
-
description?: string;
|
|
194
|
-
priority?: number;
|
|
195
|
-
status?: QuestStoreStatus;
|
|
196
|
-
progress?: string;
|
|
197
|
-
blockedBy?: string;
|
|
198
|
-
}): QuestStoreItem {
|
|
199
|
-
const now = Date.now();
|
|
200
|
-
const quest: QuestStoreItem = {
|
|
201
|
-
id: input.id,
|
|
202
|
-
title: input.title,
|
|
203
|
-
description: input.description,
|
|
204
|
-
priority: input.priority ?? 2,
|
|
205
|
-
status: input.status ?? "open",
|
|
206
|
-
progress: input.progress ?? "",
|
|
207
|
-
blockedBy: input.blockedBy,
|
|
208
|
-
attempts: 0,
|
|
209
|
-
createdAt: now,
|
|
210
|
-
updatedAt: now,
|
|
211
|
-
};
|
|
212
|
-
this.quests.set(quest.id, quest);
|
|
213
|
-
return quest;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
updateQuest(
|
|
217
|
-
id: string,
|
|
218
|
-
updates: Partial<{
|
|
219
|
-
title: string;
|
|
220
|
-
description: string;
|
|
221
|
-
priority: number;
|
|
222
|
-
status: QuestStoreStatus;
|
|
223
|
-
progress: string;
|
|
224
|
-
blockedBy: string;
|
|
225
|
-
}>,
|
|
226
|
-
): QuestStoreItem {
|
|
227
|
-
const existing = this.quests.get(id);
|
|
228
|
-
if (!existing) {
|
|
229
|
-
throw new Error(`Quest not found: ${id}`);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const updated: QuestStoreItem = { ...existing, updatedAt: Date.now() };
|
|
233
|
-
if (updates.title !== undefined) updated.title = updates.title;
|
|
234
|
-
if (updates.description !== undefined) updated.description = updates.description;
|
|
235
|
-
if (updates.priority !== undefined) updated.priority = updates.priority;
|
|
236
|
-
if (updates.status !== undefined) updated.status = updates.status;
|
|
237
|
-
if (updates.progress !== undefined) updated.progress = updates.progress;
|
|
238
|
-
if (updates.blockedBy !== undefined) updated.blockedBy = updates.blockedBy;
|
|
239
|
-
this.quests.set(id, updated);
|
|
240
|
-
return updated;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
getQuest(id: string): QuestStoreItem | null {
|
|
244
|
-
return this.quests.get(id) ?? null;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
listQuests(filter?: { status?: string }): QuestStoreItem[] {
|
|
248
|
-
const all = Array.from(this.quests.values());
|
|
249
|
-
if (filter?.status) {
|
|
250
|
-
return all.filter((quest) => quest.status === filter.status);
|
|
251
|
-
}
|
|
252
|
-
return all;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function getTool(registry: ReturnType<typeof createToolRegistry>, name: string): Tool {
|
|
257
|
-
const tool = registry.get(name);
|
|
258
|
-
if (!tool) throw new Error(`Missing tool in registry: ${name}`);
|
|
259
|
-
return tool;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function createE2EContext(
|
|
263
|
-
questStore: QuestStoreRef,
|
|
264
|
-
delegationHarness: ControlledDelegationHarness,
|
|
265
|
-
): ToolContext {
|
|
266
|
-
return {
|
|
267
|
-
workingDir: process.cwd(),
|
|
268
|
-
env: {},
|
|
269
|
-
confirm: async () => true,
|
|
270
|
-
questStore,
|
|
271
|
-
delegationExecutor: delegationHarness,
|
|
272
|
-
delegationRegistry: delegationHarness,
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
describe("Delegation + quest orchestration (E2E)", () => {
|
|
277
|
-
it("completes a delegated worker and closes the quest with the delegated result", async () => {
|
|
278
|
-
const registry = createToolRegistry();
|
|
279
|
-
const questStore = new InMemoryQuestStore();
|
|
280
|
-
const delegationHarness = new ControlledDelegationHarness();
|
|
281
|
-
const ctx = createE2EContext(questStore, delegationHarness);
|
|
282
|
-
|
|
283
|
-
const questUpdate = getTool(registry, "quest_update");
|
|
284
|
-
const questList = getTool(registry, "quest_list");
|
|
285
|
-
const spawnWorker = getTool(registry, "spawn_worker");
|
|
286
|
-
const checkDelegation = getTool(registry, "check_delegation");
|
|
287
|
-
|
|
288
|
-
const createQuestResult = await questUpdate.execute(
|
|
289
|
-
{
|
|
290
|
-
quests: [{ title: "Implement orchestration", status: "active" }],
|
|
291
|
-
},
|
|
292
|
-
ctx,
|
|
293
|
-
);
|
|
294
|
-
expect(createQuestResult.success).toBe(true);
|
|
295
|
-
const questId = (createQuestResult.data as { quests: Array<{ id: string }> }).quests[0]!.id;
|
|
296
|
-
|
|
297
|
-
const spawnResult = await spawnWorker.execute(
|
|
298
|
-
{
|
|
299
|
-
task: "Collect integration evidence",
|
|
300
|
-
maxTurns: 4,
|
|
301
|
-
tier: "fast",
|
|
302
|
-
},
|
|
303
|
-
ctx,
|
|
304
|
-
);
|
|
305
|
-
expect(spawnResult.success).toBe(true);
|
|
306
|
-
const delegationId = (spawnResult.data as { id: string }).id;
|
|
307
|
-
|
|
308
|
-
const waitResultPromise = checkDelegation.execute(
|
|
309
|
-
{ id: delegationId, wait: true, timeout: 5_000 },
|
|
310
|
-
ctx,
|
|
311
|
-
);
|
|
312
|
-
delegationHarness.complete(delegationId, "Worker finished with validated report");
|
|
313
|
-
const waitResult = await waitResultPromise;
|
|
314
|
-
|
|
315
|
-
expect(waitResult.success).toBe(true);
|
|
316
|
-
const waitData = waitResult.data as { status: string; result?: string };
|
|
317
|
-
expect(waitData.status).toBe("completed");
|
|
318
|
-
expect(waitData.result).toContain("validated report");
|
|
319
|
-
|
|
320
|
-
const closeQuestResult = await questUpdate.execute(
|
|
321
|
-
{
|
|
322
|
-
quests: [
|
|
323
|
-
{
|
|
324
|
-
id: questId,
|
|
325
|
-
status: "done",
|
|
326
|
-
notes: waitData.result,
|
|
327
|
-
},
|
|
328
|
-
],
|
|
329
|
-
},
|
|
330
|
-
ctx,
|
|
331
|
-
);
|
|
332
|
-
expect(closeQuestResult.success).toBe(true);
|
|
333
|
-
|
|
334
|
-
const doneList = await questList.execute({ status: "done" }, ctx);
|
|
335
|
-
expect(doneList.success).toBe(true);
|
|
336
|
-
const quests = (doneList.data as { quests: Array<{ id: string; notes: string }> }).quests;
|
|
337
|
-
const quest = quests.find((item) => item.id === questId);
|
|
338
|
-
expect(quest).toBeDefined();
|
|
339
|
-
expect(quest!.notes).toContain("validated report");
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
it("propagates delegated worker failures into quest status and notes", async () => {
|
|
343
|
-
const registry = createToolRegistry();
|
|
344
|
-
const questStore = new InMemoryQuestStore();
|
|
345
|
-
const delegationHarness = new ControlledDelegationHarness();
|
|
346
|
-
const ctx = createE2EContext(questStore, delegationHarness);
|
|
347
|
-
|
|
348
|
-
const questUpdate = getTool(registry, "quest_update");
|
|
349
|
-
const questList = getTool(registry, "quest_list");
|
|
350
|
-
const spawnWorker = getTool(registry, "spawn_worker");
|
|
351
|
-
const checkDelegation = getTool(registry, "check_delegation");
|
|
352
|
-
|
|
353
|
-
const createQuestResult = await questUpdate.execute(
|
|
354
|
-
{
|
|
355
|
-
quests: [{ title: "Run risky flow", status: "active" }],
|
|
356
|
-
},
|
|
357
|
-
ctx,
|
|
358
|
-
);
|
|
359
|
-
expect(createQuestResult.success).toBe(true);
|
|
360
|
-
const questId = (createQuestResult.data as { quests: Array<{ id: string }> }).quests[0]!.id;
|
|
361
|
-
|
|
362
|
-
const spawnResult = await spawnWorker.execute({ task: "Trigger failure path" }, ctx);
|
|
363
|
-
expect(spawnResult.success).toBe(true);
|
|
364
|
-
const delegationId = (spawnResult.data as { id: string }).id;
|
|
365
|
-
|
|
366
|
-
const waitResultPromise = checkDelegation.execute(
|
|
367
|
-
{ id: delegationId, wait: true, timeout: 5_000 },
|
|
368
|
-
ctx,
|
|
369
|
-
);
|
|
370
|
-
delegationHarness.fail(delegationId, "synthetic worker failure");
|
|
371
|
-
const waitResult = await waitResultPromise;
|
|
372
|
-
|
|
373
|
-
expect(waitResult.success).toBe(false);
|
|
374
|
-
const waitData = waitResult.data as { status: string; error?: string };
|
|
375
|
-
expect(waitData.status).toBe("failed");
|
|
376
|
-
expect(waitData.error).toContain("synthetic worker failure");
|
|
377
|
-
|
|
378
|
-
const blockQuestResult = await questUpdate.execute(
|
|
379
|
-
{
|
|
380
|
-
quests: [
|
|
381
|
-
{
|
|
382
|
-
id: questId,
|
|
383
|
-
status: "blocked",
|
|
384
|
-
notes: waitData.error,
|
|
385
|
-
},
|
|
386
|
-
],
|
|
387
|
-
},
|
|
388
|
-
ctx,
|
|
389
|
-
);
|
|
390
|
-
expect(blockQuestResult.success).toBe(true);
|
|
391
|
-
|
|
392
|
-
const blockedList = await questList.execute({ status: "blocked" }, ctx);
|
|
393
|
-
expect(blockedList.success).toBe(true);
|
|
394
|
-
const quests = (blockedList.data as { quests: Array<{ id: string; notes: string }> }).quests;
|
|
395
|
-
const quest = quests.find((item) => item.id === questId);
|
|
396
|
-
expect(quest).toBeDefined();
|
|
397
|
-
expect(quest!.notes).toContain("synthetic worker failure");
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
it("surfaces aborted delegation state when waiting on delegate_arion", async () => {
|
|
401
|
-
const registry = createToolRegistry();
|
|
402
|
-
const questStore = new InMemoryQuestStore();
|
|
403
|
-
const delegationHarness = new ControlledDelegationHarness();
|
|
404
|
-
const ctx = createE2EContext(questStore, delegationHarness);
|
|
405
|
-
|
|
406
|
-
const delegateArion = getTool(registry, "delegate_arion");
|
|
407
|
-
const checkDelegation = getTool(registry, "check_delegation");
|
|
408
|
-
|
|
409
|
-
const delegateResult = await delegateArion.execute(
|
|
410
|
-
{
|
|
411
|
-
arion: "Nova",
|
|
412
|
-
task: "Handle abort path",
|
|
413
|
-
maxTurns: 2,
|
|
414
|
-
},
|
|
415
|
-
ctx,
|
|
416
|
-
);
|
|
417
|
-
expect(delegateResult.success).toBe(true);
|
|
418
|
-
const delegationId = (delegateResult.data as { id: string }).id;
|
|
419
|
-
|
|
420
|
-
const waitResultPromise = checkDelegation.execute(
|
|
421
|
-
{ id: delegationId, wait: true, timeout: 5_000 },
|
|
422
|
-
ctx,
|
|
423
|
-
);
|
|
424
|
-
delegationHarness.abort(delegationId, "parent session aborted");
|
|
425
|
-
const waitResult = await waitResultPromise;
|
|
426
|
-
|
|
427
|
-
expect(waitResult.success).toBe(false);
|
|
428
|
-
const waitData = waitResult.data as { status: string; error?: string };
|
|
429
|
-
expect(waitData.status).toBe("aborted");
|
|
430
|
-
expect(waitData.error).toContain("parent session aborted");
|
|
431
|
-
expect(waitResult.message).toContain("parent session aborted");
|
|
432
|
-
});
|
|
433
|
-
});
|