@enactprotocol/shared 1.2.13 → 2.0.1
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/README.md +44 -0
- package/dist/config.d.ts +164 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +386 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +15 -5
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +24 -8
- package/dist/constants.js.map +1 -0
- package/dist/execution/command.d.ts +102 -0
- package/dist/execution/command.d.ts.map +1 -0
- package/dist/execution/command.js +262 -0
- package/dist/execution/command.js.map +1 -0
- package/dist/execution/index.d.ts +12 -0
- package/dist/execution/index.d.ts.map +1 -0
- package/dist/execution/index.js +17 -0
- package/dist/execution/index.js.map +1 -0
- package/dist/execution/runtime.d.ts +82 -0
- package/dist/execution/runtime.d.ts.map +1 -0
- package/dist/execution/runtime.js +273 -0
- package/dist/execution/runtime.js.map +1 -0
- package/dist/execution/types.d.ts +306 -0
- package/dist/execution/types.d.ts.map +1 -0
- package/dist/execution/types.js +14 -0
- package/dist/execution/types.js.map +1 -0
- package/dist/execution/validation.d.ts +43 -0
- package/dist/execution/validation.d.ts.map +1 -0
- package/dist/execution/validation.js +430 -0
- package/dist/execution/validation.js.map +1 -0
- package/dist/index.d.ts +21 -21
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -25
- package/dist/index.js.map +1 -0
- package/dist/manifest/index.d.ts +7 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +10 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/loader.d.ts +76 -0
- package/dist/manifest/loader.d.ts.map +1 -0
- package/dist/manifest/loader.js +146 -0
- package/dist/manifest/loader.js.map +1 -0
- package/dist/manifest/parser.d.ts +64 -0
- package/dist/manifest/parser.d.ts.map +1 -0
- package/dist/manifest/parser.js +135 -0
- package/dist/manifest/parser.js.map +1 -0
- package/dist/manifest/validator.d.ts +95 -0
- package/dist/manifest/validator.d.ts.map +1 -0
- package/dist/manifest/validator.js +258 -0
- package/dist/manifest/validator.js.map +1 -0
- package/dist/paths.d.ts +57 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +93 -0
- package/dist/paths.js.map +1 -0
- package/dist/registry.d.ts +73 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +147 -0
- package/dist/registry.js.map +1 -0
- package/dist/resolver.d.ts +89 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/resolver.js +282 -0
- package/dist/resolver.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/manifest.d.ts +201 -0
- package/dist/types/manifest.d.ts.map +1 -0
- package/dist/types/manifest.js +13 -0
- package/dist/types/manifest.js.map +1 -0
- package/dist/types.d.ts +5 -132
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -3
- package/dist/types.js.map +1 -0
- package/dist/utils/fs.d.ts +105 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +233 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/logger.d.ts +102 -25
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +214 -57
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/version.d.ts +60 -2
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +255 -31
- package/dist/utils/version.js.map +1 -0
- package/package.json +16 -58
- package/src/config.ts +510 -0
- package/src/constants.ts +36 -0
- package/src/execution/command.ts +314 -0
- package/src/execution/index.ts +73 -0
- package/src/execution/runtime.ts +308 -0
- package/src/execution/types.ts +379 -0
- package/src/execution/validation.ts +508 -0
- package/src/index.ts +238 -30
- package/src/manifest/index.ts +36 -0
- package/src/manifest/loader.ts +187 -0
- package/src/manifest/parser.ts +173 -0
- package/src/manifest/validator.ts +309 -0
- package/src/paths.ts +108 -0
- package/src/registry.ts +219 -0
- package/src/resolver.ts +345 -0
- package/src/types/index.ts +30 -0
- package/src/types/manifest.ts +255 -0
- package/src/types.ts +5 -188
- package/src/utils/fs.ts +281 -0
- package/src/utils/logger.ts +270 -59
- package/src/utils/version.ts +304 -36
- package/tests/config.test.ts +515 -0
- package/tests/execution/command.test.ts +317 -0
- package/tests/execution/validation.test.ts +384 -0
- package/tests/fixtures/invalid-tool.yaml +4 -0
- package/tests/fixtures/valid-tool.md +62 -0
- package/tests/fixtures/valid-tool.yaml +40 -0
- package/tests/index.test.ts +8 -0
- package/tests/manifest/loader.test.ts +291 -0
- package/tests/manifest/parser.test.ts +345 -0
- package/tests/manifest/validator.test.ts +394 -0
- package/tests/manifest-types.test.ts +358 -0
- package/tests/paths.test.ts +153 -0
- package/tests/registry.test.ts +231 -0
- package/tests/resolver.test.ts +272 -0
- package/tests/utils/fs.test.ts +388 -0
- package/tests/utils/logger.test.ts +480 -0
- package/tests/utils/version.test.ts +390 -0
- package/tsconfig.json +12 -0
- package/dist/LocalToolResolver.d.ts +0 -84
- package/dist/LocalToolResolver.js +0 -353
- package/dist/api/enact-api.d.ts +0 -130
- package/dist/api/enact-api.js +0 -428
- package/dist/api/index.d.ts +0 -2
- package/dist/api/index.js +0 -2
- package/dist/api/types.d.ts +0 -103
- package/dist/api/types.js +0 -1
- package/dist/core/DaggerExecutionProvider.d.ts +0 -169
- package/dist/core/DaggerExecutionProvider.js +0 -1029
- package/dist/core/DirectExecutionProvider.d.ts +0 -23
- package/dist/core/DirectExecutionProvider.js +0 -406
- package/dist/core/EnactCore.d.ts +0 -162
- package/dist/core/EnactCore.js +0 -597
- package/dist/core/NativeExecutionProvider.d.ts +0 -9
- package/dist/core/NativeExecutionProvider.js +0 -16
- package/dist/core/index.d.ts +0 -3
- package/dist/core/index.js +0 -3
- package/dist/exec/index.d.ts +0 -3
- package/dist/exec/index.js +0 -3
- package/dist/exec/logger.d.ts +0 -11
- package/dist/exec/logger.js +0 -57
- package/dist/exec/validate.d.ts +0 -5
- package/dist/exec/validate.js +0 -167
- package/dist/lib/enact-direct.d.ts +0 -150
- package/dist/lib/enact-direct.js +0 -159
- package/dist/lib/index.d.ts +0 -1
- package/dist/lib/index.js +0 -1
- package/dist/security/index.d.ts +0 -3
- package/dist/security/index.js +0 -3
- package/dist/security/security.d.ts +0 -23
- package/dist/security/security.js +0 -137
- package/dist/security/sign.d.ts +0 -103
- package/dist/security/sign.js +0 -666
- package/dist/security/verification-enforcer.d.ts +0 -53
- package/dist/security/verification-enforcer.js +0 -204
- package/dist/services/McpCoreService.d.ts +0 -98
- package/dist/services/McpCoreService.js +0 -124
- package/dist/services/index.d.ts +0 -1
- package/dist/services/index.js +0 -1
- package/dist/utils/config.d.ts +0 -111
- package/dist/utils/config.js +0 -342
- package/dist/utils/env-loader.d.ts +0 -54
- package/dist/utils/env-loader.js +0 -270
- package/dist/utils/help.d.ts +0 -36
- package/dist/utils/help.js +0 -248
- package/dist/utils/index.d.ts +0 -7
- package/dist/utils/index.js +0 -7
- package/dist/utils/silent-monitor.d.ts +0 -67
- package/dist/utils/silent-monitor.js +0 -242
- package/dist/utils/timeout.d.ts +0 -5
- package/dist/utils/timeout.js +0 -23
- package/dist/web/env-manager-server.d.ts +0 -29
- package/dist/web/env-manager-server.js +0 -367
- package/dist/web/index.d.ts +0 -1
- package/dist/web/index.js +0 -1
- package/src/LocalToolResolver.ts +0 -424
- package/src/api/enact-api.ts +0 -604
- package/src/api/index.ts +0 -2
- package/src/api/types.ts +0 -114
- package/src/core/DaggerExecutionProvider.ts +0 -1357
- package/src/core/DirectExecutionProvider.ts +0 -484
- package/src/core/EnactCore.ts +0 -847
- package/src/core/index.ts +0 -3
- package/src/exec/index.ts +0 -3
- package/src/exec/logger.ts +0 -63
- package/src/exec/validate.ts +0 -238
- package/src/lib/enact-direct.ts +0 -254
- package/src/lib/index.ts +0 -1
- package/src/services/McpCoreService.ts +0 -201
- package/src/services/index.ts +0 -1
- package/src/utils/config.ts +0 -438
- package/src/utils/env-loader.ts +0 -370
- package/src/utils/help.ts +0 -257
- package/src/utils/index.ts +0 -7
- package/src/utils/silent-monitor.ts +0 -328
- package/src/utils/timeout.ts +0 -26
- package/src/web/env-manager-server.ts +0 -465
- package/src/web/index.ts +0 -1
- package/src/web/static/app.js +0 -663
- package/src/web/static/index.html +0 -117
- package/src/web/static/style.css +0 -291
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the local tool registry (tools.json management)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
6
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import {
|
|
9
|
+
addToolToRegistry,
|
|
10
|
+
getInstalledVersion,
|
|
11
|
+
getToolCachePath,
|
|
12
|
+
getToolsJsonPath,
|
|
13
|
+
isToolInstalled,
|
|
14
|
+
listInstalledTools,
|
|
15
|
+
loadToolsRegistry,
|
|
16
|
+
removeToolFromRegistry,
|
|
17
|
+
saveToolsRegistry,
|
|
18
|
+
} from "../src/registry";
|
|
19
|
+
|
|
20
|
+
const TEST_DIR = join(import.meta.dir, "temp-registry-test");
|
|
21
|
+
const PROJECT_DIR = join(TEST_DIR, "project");
|
|
22
|
+
const PROJECT_ENACT_DIR = join(PROJECT_DIR, ".enact");
|
|
23
|
+
|
|
24
|
+
describe("registry", () => {
|
|
25
|
+
beforeAll(() => {
|
|
26
|
+
// Create test directory structure
|
|
27
|
+
mkdirSync(PROJECT_ENACT_DIR, { recursive: true });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterAll(() => {
|
|
31
|
+
// Clean up test directories
|
|
32
|
+
if (existsSync(TEST_DIR)) {
|
|
33
|
+
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe("getToolsJsonPath", () => {
|
|
38
|
+
test("returns path for global scope", () => {
|
|
39
|
+
const path = getToolsJsonPath("global");
|
|
40
|
+
expect(path).not.toBeNull();
|
|
41
|
+
expect(path).toContain(".enact");
|
|
42
|
+
expect(path).toEndWith("tools.json");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("returns path for project scope when .enact exists", () => {
|
|
46
|
+
const path = getToolsJsonPath("project", PROJECT_DIR);
|
|
47
|
+
expect(path).not.toBeNull();
|
|
48
|
+
expect(path).toContain(PROJECT_ENACT_DIR);
|
|
49
|
+
expect(path).toEndWith("tools.json");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("returns null for project scope when no .enact", () => {
|
|
53
|
+
const path = getToolsJsonPath("project", "/tmp/nonexistent-test-path");
|
|
54
|
+
expect(path).toBeNull();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe("loadToolsRegistry", () => {
|
|
59
|
+
test("returns empty registry when file does not exist", () => {
|
|
60
|
+
// Ensure tools.json doesn't exist from previous tests
|
|
61
|
+
const toolsJsonPath = join(PROJECT_ENACT_DIR, "tools.json");
|
|
62
|
+
if (existsSync(toolsJsonPath)) {
|
|
63
|
+
rmSync(toolsJsonPath);
|
|
64
|
+
}
|
|
65
|
+
const registry = loadToolsRegistry("project", PROJECT_DIR);
|
|
66
|
+
expect(registry.tools).toEqual({});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("loads existing registry", () => {
|
|
70
|
+
// Create a test registry file
|
|
71
|
+
const registryPath = join(PROJECT_ENACT_DIR, "tools.json");
|
|
72
|
+
writeFileSync(
|
|
73
|
+
registryPath,
|
|
74
|
+
JSON.stringify({
|
|
75
|
+
tools: {
|
|
76
|
+
"test/tool": "1.0.0",
|
|
77
|
+
"other/tool": "2.0.0",
|
|
78
|
+
},
|
|
79
|
+
})
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const registry = loadToolsRegistry("project", PROJECT_DIR);
|
|
83
|
+
expect(registry.tools["test/tool"]).toBe("1.0.0");
|
|
84
|
+
expect(registry.tools["other/tool"]).toBe("2.0.0");
|
|
85
|
+
|
|
86
|
+
// Clean up
|
|
87
|
+
rmSync(registryPath);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("returns empty registry on parse error", () => {
|
|
91
|
+
const registryPath = join(PROJECT_ENACT_DIR, "tools.json");
|
|
92
|
+
writeFileSync(registryPath, "invalid json");
|
|
93
|
+
|
|
94
|
+
const registry = loadToolsRegistry("project", PROJECT_DIR);
|
|
95
|
+
expect(registry.tools).toEqual({});
|
|
96
|
+
|
|
97
|
+
// Clean up
|
|
98
|
+
rmSync(registryPath);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe("saveToolsRegistry", () => {
|
|
103
|
+
test("saves registry to file", () => {
|
|
104
|
+
const registry = {
|
|
105
|
+
tools: {
|
|
106
|
+
"test/save": "1.0.0",
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
saveToolsRegistry(registry, "project", PROJECT_DIR);
|
|
111
|
+
|
|
112
|
+
const registryPath = join(PROJECT_ENACT_DIR, "tools.json");
|
|
113
|
+
expect(existsSync(registryPath)).toBe(true);
|
|
114
|
+
|
|
115
|
+
const loaded = loadToolsRegistry("project", PROJECT_DIR);
|
|
116
|
+
expect(loaded.tools["test/save"]).toBe("1.0.0");
|
|
117
|
+
|
|
118
|
+
// Clean up
|
|
119
|
+
rmSync(registryPath);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe("addToolToRegistry", () => {
|
|
124
|
+
test("adds tool to registry", () => {
|
|
125
|
+
addToolToRegistry("test/add", "1.0.0", "project", PROJECT_DIR);
|
|
126
|
+
|
|
127
|
+
const registry = loadToolsRegistry("project", PROJECT_DIR);
|
|
128
|
+
expect(registry.tools["test/add"]).toBe("1.0.0");
|
|
129
|
+
|
|
130
|
+
// Clean up
|
|
131
|
+
rmSync(join(PROJECT_ENACT_DIR, "tools.json"));
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("updates existing tool version", () => {
|
|
135
|
+
addToolToRegistry("test/update", "1.0.0", "project", PROJECT_DIR);
|
|
136
|
+
addToolToRegistry("test/update", "2.0.0", "project", PROJECT_DIR);
|
|
137
|
+
|
|
138
|
+
const registry = loadToolsRegistry("project", PROJECT_DIR);
|
|
139
|
+
expect(registry.tools["test/update"]).toBe("2.0.0");
|
|
140
|
+
|
|
141
|
+
// Clean up
|
|
142
|
+
rmSync(join(PROJECT_ENACT_DIR, "tools.json"));
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe("removeToolFromRegistry", () => {
|
|
147
|
+
test("removes tool from registry", () => {
|
|
148
|
+
addToolToRegistry("test/remove", "1.0.0", "project", PROJECT_DIR);
|
|
149
|
+
const removed = removeToolFromRegistry("test/remove", "project", PROJECT_DIR);
|
|
150
|
+
|
|
151
|
+
expect(removed).toBe(true);
|
|
152
|
+
|
|
153
|
+
const registry = loadToolsRegistry("project", PROJECT_DIR);
|
|
154
|
+
expect(registry.tools["test/remove"]).toBeUndefined();
|
|
155
|
+
|
|
156
|
+
// Clean up
|
|
157
|
+
rmSync(join(PROJECT_ENACT_DIR, "tools.json"));
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("returns false for non-existent tool", () => {
|
|
161
|
+
const removed = removeToolFromRegistry("nonexistent/tool", "project", PROJECT_DIR);
|
|
162
|
+
expect(removed).toBe(false);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe("isToolInstalled", () => {
|
|
167
|
+
test("returns true for installed tool", () => {
|
|
168
|
+
addToolToRegistry("test/installed", "1.0.0", "project", PROJECT_DIR);
|
|
169
|
+
expect(isToolInstalled("test/installed", "project", PROJECT_DIR)).toBe(true);
|
|
170
|
+
|
|
171
|
+
// Clean up
|
|
172
|
+
rmSync(join(PROJECT_ENACT_DIR, "tools.json"));
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("returns false for non-installed tool", () => {
|
|
176
|
+
expect(isToolInstalled("not/installed", "project", PROJECT_DIR)).toBe(false);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe("getInstalledVersion", () => {
|
|
181
|
+
test("returns version for installed tool", () => {
|
|
182
|
+
addToolToRegistry("test/version", "3.0.0", "project", PROJECT_DIR);
|
|
183
|
+
const version = getInstalledVersion("test/version", "project", PROJECT_DIR);
|
|
184
|
+
expect(version).toBe("3.0.0");
|
|
185
|
+
|
|
186
|
+
// Clean up
|
|
187
|
+
rmSync(join(PROJECT_ENACT_DIR, "tools.json"));
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test("returns null for non-installed tool", () => {
|
|
191
|
+
const version = getInstalledVersion("not/installed", "project", PROJECT_DIR);
|
|
192
|
+
expect(version).toBeNull();
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe("getToolCachePath", () => {
|
|
197
|
+
test("returns cache path with version", () => {
|
|
198
|
+
const path = getToolCachePath("org/tool", "1.0.0");
|
|
199
|
+
expect(path).toContain(".enact");
|
|
200
|
+
expect(path).toContain("cache");
|
|
201
|
+
expect(path).toContain("org/tool");
|
|
202
|
+
expect(path).toContain("v1.0.0");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test("normalizes version prefix", () => {
|
|
206
|
+
const pathWithV = getToolCachePath("org/tool", "v1.0.0");
|
|
207
|
+
const pathWithoutV = getToolCachePath("org/tool", "1.0.0");
|
|
208
|
+
expect(pathWithV).toBe(pathWithoutV);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe("listInstalledTools", () => {
|
|
213
|
+
test("returns list of installed tools", () => {
|
|
214
|
+
addToolToRegistry("test/list1", "1.0.0", "project", PROJECT_DIR);
|
|
215
|
+
addToolToRegistry("test/list2", "2.0.0", "project", PROJECT_DIR);
|
|
216
|
+
|
|
217
|
+
const tools = listInstalledTools("project", PROJECT_DIR);
|
|
218
|
+
expect(tools.length).toBe(2);
|
|
219
|
+
expect(tools.find((t) => t.name === "test/list1")).toBeTruthy();
|
|
220
|
+
expect(tools.find((t) => t.name === "test/list2")).toBeTruthy();
|
|
221
|
+
|
|
222
|
+
// Clean up
|
|
223
|
+
rmSync(join(PROJECT_ENACT_DIR, "tools.json"));
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("returns empty list when no tools installed", () => {
|
|
227
|
+
const tools = listInstalledTools("project", PROJECT_DIR);
|
|
228
|
+
expect(tools.length).toBe(0);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
});
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import {
|
|
5
|
+
ToolResolveError,
|
|
6
|
+
getToolPath,
|
|
7
|
+
getToolSearchPaths,
|
|
8
|
+
normalizeToolName,
|
|
9
|
+
resolveTool,
|
|
10
|
+
resolveToolAuto,
|
|
11
|
+
resolveToolFromPath,
|
|
12
|
+
toolNameToPath,
|
|
13
|
+
tryResolveTool,
|
|
14
|
+
} from "../src/resolver";
|
|
15
|
+
|
|
16
|
+
const TEST_DIR = join(import.meta.dir, "temp-resolver-test");
|
|
17
|
+
const PROJECT_DIR = join(TEST_DIR, "project");
|
|
18
|
+
const PROJECT_ENACT_DIR = join(PROJECT_DIR, ".enact");
|
|
19
|
+
|
|
20
|
+
describe("tool resolver", () => {
|
|
21
|
+
beforeAll(() => {
|
|
22
|
+
// Create test directories
|
|
23
|
+
mkdirSync(join(PROJECT_ENACT_DIR, "tools", "test", "project-tool"), { recursive: true });
|
|
24
|
+
|
|
25
|
+
// Create a project-level tool
|
|
26
|
+
writeFileSync(
|
|
27
|
+
join(PROJECT_ENACT_DIR, "tools", "test", "project-tool", "enact.yaml"),
|
|
28
|
+
`
|
|
29
|
+
name: test/project-tool
|
|
30
|
+
description: A project-level test tool
|
|
31
|
+
version: "1.0.0"
|
|
32
|
+
`,
|
|
33
|
+
"utf-8"
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// Create a direct tool directory for path-based resolution
|
|
37
|
+
mkdirSync(join(TEST_DIR, "direct-tool"), { recursive: true });
|
|
38
|
+
writeFileSync(
|
|
39
|
+
join(TEST_DIR, "direct-tool", "enact.yaml"),
|
|
40
|
+
`
|
|
41
|
+
name: test/direct-tool
|
|
42
|
+
description: A directly referenced tool
|
|
43
|
+
version: "2.0.0"
|
|
44
|
+
`,
|
|
45
|
+
"utf-8"
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// Create a tool with enact.md
|
|
49
|
+
mkdirSync(join(TEST_DIR, "md-tool"), { recursive: true });
|
|
50
|
+
writeFileSync(
|
|
51
|
+
join(TEST_DIR, "md-tool", "enact.md"),
|
|
52
|
+
`---
|
|
53
|
+
name: test/md-tool
|
|
54
|
+
description: A markdown tool
|
|
55
|
+
version: "3.0.0"
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
# MD Tool
|
|
59
|
+
|
|
60
|
+
Documentation here.
|
|
61
|
+
`,
|
|
62
|
+
"utf-8"
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
afterAll(() => {
|
|
67
|
+
// Cleanup
|
|
68
|
+
if (existsSync(TEST_DIR)) {
|
|
69
|
+
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe("utility functions", () => {
|
|
74
|
+
describe("normalizeToolName", () => {
|
|
75
|
+
test("lowercases name", () => {
|
|
76
|
+
expect(normalizeToolName("Acme/Utils/Greeter")).toBe("acme/utils/greeter");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("converts backslashes to forward slashes", () => {
|
|
80
|
+
expect(normalizeToolName("acme\\utils\\greeter")).toBe("acme/utils/greeter");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("trims whitespace", () => {
|
|
84
|
+
expect(normalizeToolName(" acme/tool ")).toBe("acme/tool");
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("toolNameToPath", () => {
|
|
89
|
+
test("returns path-like string", () => {
|
|
90
|
+
expect(toolNameToPath("acme/utils/greeter")).toBe("acme/utils/greeter");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("normalizes backslashes", () => {
|
|
94
|
+
expect(toolNameToPath("acme\\utils")).toBe("acme/utils");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("getToolPath", () => {
|
|
99
|
+
test("joins tools dir and tool name", () => {
|
|
100
|
+
const result = getToolPath("/home/user/.enact/tools", "acme/greeter");
|
|
101
|
+
expect(result).toContain("acme");
|
|
102
|
+
expect(result).toContain("greeter");
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe("getToolSearchPaths", () => {
|
|
107
|
+
test("returns array of paths", () => {
|
|
108
|
+
const paths = getToolSearchPaths("test/tool", { startDir: PROJECT_DIR });
|
|
109
|
+
expect(Array.isArray(paths)).toBe(true);
|
|
110
|
+
expect(paths.length).toBeGreaterThan(0);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("respects skipProject option", () => {
|
|
114
|
+
const withProject = getToolSearchPaths("test/tool", { startDir: PROJECT_DIR });
|
|
115
|
+
const withoutProject = getToolSearchPaths("test/tool", {
|
|
116
|
+
startDir: PROJECT_DIR,
|
|
117
|
+
skipProject: true,
|
|
118
|
+
});
|
|
119
|
+
expect(withoutProject.length).toBeLessThan(withProject.length);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("respects skipUser option", () => {
|
|
123
|
+
// skipUser only affects global tools that are registered in tools.json
|
|
124
|
+
// Since no tools are installed globally, both should return the same paths
|
|
125
|
+
// This tests that skipUser doesn't add extra paths when no global tools exist
|
|
126
|
+
const withUser = getToolSearchPaths("test/tool", { skipCache: true });
|
|
127
|
+
const withoutUser = getToolSearchPaths("test/tool", { skipUser: true, skipCache: true });
|
|
128
|
+
expect(withoutUser.length).toBeLessThanOrEqual(withUser.length);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe("resolveToolFromPath", () => {
|
|
134
|
+
test("resolves tool from directory", () => {
|
|
135
|
+
const toolDir = join(TEST_DIR, "direct-tool");
|
|
136
|
+
const result = resolveToolFromPath(toolDir);
|
|
137
|
+
|
|
138
|
+
expect(result.manifest.name).toBe("test/direct-tool");
|
|
139
|
+
expect(result.location).toBe("file");
|
|
140
|
+
expect(result.sourceDir).toBe(toolDir);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("resolves tool from manifest file directly", () => {
|
|
144
|
+
const manifestPath = join(TEST_DIR, "direct-tool", "enact.yaml");
|
|
145
|
+
const result = resolveToolFromPath(manifestPath);
|
|
146
|
+
|
|
147
|
+
expect(result.manifest.name).toBe("test/direct-tool");
|
|
148
|
+
expect(result.manifestPath).toBe(manifestPath);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("resolves markdown tool", () => {
|
|
152
|
+
const toolDir = join(TEST_DIR, "md-tool");
|
|
153
|
+
const result = resolveToolFromPath(toolDir);
|
|
154
|
+
|
|
155
|
+
expect(result.manifest.name).toBe("test/md-tool");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("throws ToolResolveError for non-existent path", () => {
|
|
159
|
+
expect(() => resolveToolFromPath("/non/existent/path")).toThrow(ToolResolveError);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("throws ToolResolveError for directory without manifest", () => {
|
|
163
|
+
const emptyDir = join(TEST_DIR, "empty-dir");
|
|
164
|
+
mkdirSync(emptyDir, { recursive: true });
|
|
165
|
+
|
|
166
|
+
expect(() => resolveToolFromPath(emptyDir)).toThrow(ToolResolveError);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe("resolveTool", () => {
|
|
171
|
+
test("resolves tool from project", () => {
|
|
172
|
+
const result = resolveTool("test/project-tool", { startDir: PROJECT_DIR });
|
|
173
|
+
|
|
174
|
+
expect(result.manifest.name).toBe("test/project-tool");
|
|
175
|
+
expect(result.location).toBe("project");
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("throws ToolResolveError for non-existent tool", () => {
|
|
179
|
+
expect(() =>
|
|
180
|
+
resolveTool("non-existent/tool", { startDir: PROJECT_DIR, skipUser: true, skipCache: true })
|
|
181
|
+
).toThrow(ToolResolveError);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("error includes searched locations", () => {
|
|
185
|
+
try {
|
|
186
|
+
resolveTool("non-existent/tool", { startDir: PROJECT_DIR });
|
|
187
|
+
expect.unreachable("Should have thrown");
|
|
188
|
+
} catch (error) {
|
|
189
|
+
expect(error).toBeInstanceOf(ToolResolveError);
|
|
190
|
+
expect((error as ToolResolveError).searchedLocations).toBeDefined();
|
|
191
|
+
expect((error as ToolResolveError).searchedLocations?.length).toBeGreaterThan(0);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("normalizes tool name", () => {
|
|
196
|
+
const result = resolveTool("TEST/PROJECT-TOOL", { startDir: PROJECT_DIR });
|
|
197
|
+
expect(result.manifest.name).toBe("test/project-tool");
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe("tryResolveTool", () => {
|
|
202
|
+
test("returns result on success", () => {
|
|
203
|
+
const result = tryResolveTool("test/project-tool", { startDir: PROJECT_DIR });
|
|
204
|
+
expect(result).not.toBeNull();
|
|
205
|
+
expect(result?.manifest.name).toBe("test/project-tool");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("returns null on failure", () => {
|
|
209
|
+
const result = tryResolveTool("non-existent/tool", {
|
|
210
|
+
startDir: PROJECT_DIR,
|
|
211
|
+
skipUser: true,
|
|
212
|
+
skipCache: true,
|
|
213
|
+
});
|
|
214
|
+
expect(result).toBeNull();
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test("handles path input", () => {
|
|
218
|
+
const toolDir = join(TEST_DIR, "direct-tool");
|
|
219
|
+
const result = tryResolveTool(toolDir);
|
|
220
|
+
expect(result).not.toBeNull();
|
|
221
|
+
expect(result?.manifest.name).toBe("test/direct-tool");
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("handles relative path with ./", () => {
|
|
225
|
+
// This would need the cwd to be set appropriately
|
|
226
|
+
// For now, just verify it doesn't crash
|
|
227
|
+
const result = tryResolveTool("./non-existent");
|
|
228
|
+
expect(result).toBeNull();
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
describe("resolveToolAuto", () => {
|
|
233
|
+
test("resolves path starting with /", () => {
|
|
234
|
+
const toolDir = join(TEST_DIR, "direct-tool");
|
|
235
|
+
const result = resolveToolAuto(toolDir);
|
|
236
|
+
expect(result.manifest.name).toBe("test/direct-tool");
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test("resolves path starting with ./", () => {
|
|
240
|
+
// Use an absolute path that exists
|
|
241
|
+
const toolDir = join(TEST_DIR, "direct-tool");
|
|
242
|
+
const result = resolveToolAuto(toolDir);
|
|
243
|
+
expect(result.manifest.name).toBe("test/direct-tool");
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("resolves tool name", () => {
|
|
247
|
+
const result = resolveToolAuto("test/project-tool", { startDir: PROJECT_DIR });
|
|
248
|
+
expect(result.manifest.name).toBe("test/project-tool");
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test("throws for non-existent", () => {
|
|
252
|
+
expect(() =>
|
|
253
|
+
resolveToolAuto("completely/non-existent", {
|
|
254
|
+
startDir: PROJECT_DIR,
|
|
255
|
+
skipUser: true,
|
|
256
|
+
skipCache: true,
|
|
257
|
+
})
|
|
258
|
+
).toThrow(ToolResolveError);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
describe("ToolResolveError", () => {
|
|
263
|
+
test("has correct properties", () => {
|
|
264
|
+
const error = new ToolResolveError("Test error", "test/tool", ["/path/1", "/path/2"]);
|
|
265
|
+
|
|
266
|
+
expect(error.name).toBe("ToolResolveError");
|
|
267
|
+
expect(error.message).toBe("Test error");
|
|
268
|
+
expect(error.toolPath).toBe("test/tool");
|
|
269
|
+
expect(error.searchedLocations).toEqual(["/path/1", "/path/2"]);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|