@kya-os/create-mcpi-app 1.7.19 ā 1.7.20
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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test$colon$coverage.log +315 -0
- package/.turbo/turbo-test.log +95 -0
- package/CHANGELOG.md +372 -0
- package/IMPLEMENTATION_SUMMARY.md +108 -0
- package/REMEDIATION_PLAN.md +99 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +252 -0
- package/coverage/config-builder.ts.html +580 -0
- package/coverage/coverage-final.json +7 -0
- package/coverage/favicon.png +0 -0
- package/coverage/fetch-cloudflare-mcpi-template.ts.html +7006 -0
- package/coverage/generate-config.ts.html +436 -0
- package/coverage/generate-identity.ts.html +574 -0
- package/coverage/index.html +191 -0
- package/coverage/install.ts.html +322 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/validate-project-structure.ts.html +466 -0
- package/package.json +14 -7
- package/scripts/prepare-pack.js +47 -0
- package/scripts/validate-no-workspace.js +79 -0
- package/src/__tests__/cloudflare-template.test.ts +488 -0
- package/src/__tests__/helpers/fetch-cloudflare-mcpi-template.test.ts +337 -0
- package/src/__tests__/helpers/generate-config.test.ts +312 -0
- package/src/__tests__/helpers/generate-identity.test.ts +271 -0
- package/src/__tests__/helpers/install.test.ts +362 -0
- package/src/__tests__/helpers/validate-project-structure.test.ts +467 -0
- package/src/__tests__.bak/regression.test.ts +434 -0
- package/src/effects/index.ts +80 -0
- package/src/helpers/__tests__/config-builder.spec.ts +231 -0
- package/src/helpers/apply-identity-preset.ts +209 -0
- package/src/helpers/config-builder.ts +165 -0
- package/src/helpers/copy-template.ts +11 -0
- package/src/helpers/create.ts +239 -0
- package/src/helpers/fetch-cloudflare-mcpi-template.ts +2311 -0
- package/src/helpers/fetch-cloudflare-template.ts +361 -0
- package/src/helpers/fetch-mcpi-template.ts +236 -0
- package/src/helpers/fetch-xmcp-template.ts +153 -0
- package/src/helpers/generate-config.ts +117 -0
- package/src/helpers/generate-identity.ts +163 -0
- package/src/helpers/identity-manager.ts +186 -0
- package/src/helpers/install.ts +79 -0
- package/src/helpers/rename.ts +17 -0
- package/src/helpers/validate-project-structure.ts +127 -0
- package/src/index.ts +480 -0
- package/src/utils/check-node.ts +17 -0
- package/src/utils/is-folder-empty.ts +60 -0
- package/src/utils/validate-project-name.ts +132 -0
- package/test-cloudflare/README.md +164 -0
- package/test-cloudflare/package.json +28 -0
- package/test-cloudflare/src/index.ts +340 -0
- package/test-cloudflare/src/tools/greet.ts +19 -0
- package/test-cloudflare/tests/cache-invalidation.test.ts +410 -0
- package/test-cloudflare/tests/cors-security.test.ts +349 -0
- package/test-cloudflare/tests/delegation.test.ts +335 -0
- package/test-cloudflare/tests/do-routing.test.ts +314 -0
- package/test-cloudflare/tests/integration.test.ts +205 -0
- package/test-cloudflare/tests/session-management.test.ts +359 -0
- package/test-cloudflare/tsconfig.json +22 -0
- package/test-cloudflare/vitest.config.ts +9 -0
- package/test-cloudflare/wrangler.toml +37 -0
- package/test-node/README.md +44 -0
- package/test-node/package.json +23 -0
- package/test-node/src/tools/greet.ts +25 -0
- package/test-node/xmcp.config.ts +20 -0
- package/tsconfig.json +26 -0
- package/vitest.config.ts +14 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression Tests - Preventing Known Issues
|
|
3
|
+
*
|
|
4
|
+
* These tests specifically verify that bugs we've encountered and fixed
|
|
5
|
+
* do not re-occur. Each test documents the original issue, what broke,
|
|
6
|
+
* and how we prevent it from happening again.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
10
|
+
import { existsSync } from "fs";
|
|
11
|
+
import { mkdir, rmdir, readFile, readdir } from "fs/promises";
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
import { execa } from "execa";
|
|
14
|
+
|
|
15
|
+
describe("Regression Tests", () => {
|
|
16
|
+
let tempDir: string;
|
|
17
|
+
const originalCwd = process.cwd();
|
|
18
|
+
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
tempDir = join(process.cwd(), ".test-regression");
|
|
21
|
+
await mkdir(tempDir, { recursive: true });
|
|
22
|
+
process.chdir(tempDir);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(async () => {
|
|
26
|
+
process.chdir(originalCwd);
|
|
27
|
+
try {
|
|
28
|
+
if (existsSync(tempDir)) {
|
|
29
|
+
await rmdir(tempDir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
} catch (error) {
|
|
32
|
+
// Ignore cleanup errors
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("Regression #1: workspace:* Dependencies Not Resolved", () => {
|
|
37
|
+
/**
|
|
38
|
+
* WHAT BROKE: v1.2.0 was published with workspace:* dependencies
|
|
39
|
+
* IMPACT: npm couldn't install the package - 404 errors
|
|
40
|
+
* ROOT CAUSE: Build process didn't rewrite workspace protocol
|
|
41
|
+
* FIX: Ensured dependencies use proper semver versions
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
it("should NOT contain workspace:* in dependencies", async () => {
|
|
45
|
+
const packageJson = JSON.parse(
|
|
46
|
+
await readFile(join(__dirname, "../../package.json"), "utf-8")
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const allDeps = {
|
|
50
|
+
...packageJson.dependencies,
|
|
51
|
+
...packageJson.devDependencies,
|
|
52
|
+
...packageJson.peerDependencies,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
for (const [name, version] of Object.entries(allDeps)) {
|
|
56
|
+
expect(version).not.toMatch(
|
|
57
|
+
/workspace:/,
|
|
58
|
+
`Dependency ${name} should not use workspace: protocol in published package`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should use valid semver for @kya-os/* dependencies", async () => {
|
|
64
|
+
const packageJson = JSON.parse(
|
|
65
|
+
await readFile(join(__dirname, "../../package.json"), "utf-8")
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const deps = packageJson.dependencies || {};
|
|
69
|
+
|
|
70
|
+
if (deps["@kya-os/mcp-i"]) {
|
|
71
|
+
expect(deps["@kya-os/mcp-i"]).toMatch(
|
|
72
|
+
/^\^?\d+\.\d+\.\d+$/,
|
|
73
|
+
"@kya-os/mcp-i should use valid semver"
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (deps["@kya-os/cli"]) {
|
|
78
|
+
expect(deps["@kya-os/cli"]).toMatch(
|
|
79
|
+
/^\^?\d+\.\d+\.\d+$/,
|
|
80
|
+
"@kya-os/cli should use valid semver"
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe("Regression #2: Invalid Config Field Generated", () => {
|
|
87
|
+
/**
|
|
88
|
+
* WHAT BROKE: xmcp.config.ts had identity: { enabled: true }
|
|
89
|
+
* IMPACT: TypeScript compilation errors in generated projects
|
|
90
|
+
* ROOT CAUSE: Template included field that doesn't exist in type
|
|
91
|
+
* FIX: Removed invalid identity field from config generator
|
|
92
|
+
*/
|
|
93
|
+
|
|
94
|
+
it("should NOT generate identity field in xmcp.config.ts", async () => {
|
|
95
|
+
// Simulate config generation
|
|
96
|
+
const { generateXmcpConfig } = await import("../helpers/generate-config.js");
|
|
97
|
+
|
|
98
|
+
const config = await generateXmcpConfig({
|
|
99
|
+
transports: ["stdio"],
|
|
100
|
+
projectName: "test-project",
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
expect(config).not.toMatch(/identity:\s*{/);
|
|
104
|
+
expect(config).not.toMatch(/enabled:\s*true/);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("generated config should be valid TypeScript", async () => {
|
|
108
|
+
const { generateXmcpConfig } = await import("../helpers/generate-config.js");
|
|
109
|
+
|
|
110
|
+
const config = await generateXmcpConfig({
|
|
111
|
+
transports: ["http"],
|
|
112
|
+
projectName: "test-project",
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Write to temp file
|
|
116
|
+
const configPath = join(tempDir, "xmcp.config.ts");
|
|
117
|
+
await import("fs/promises").then((fs) =>
|
|
118
|
+
fs.writeFile(configPath, config)
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Should have no typescript errors
|
|
122
|
+
try {
|
|
123
|
+
await execa("npx", ["tsc", "--noEmit", configPath], {
|
|
124
|
+
cwd: process.cwd(),
|
|
125
|
+
});
|
|
126
|
+
// If no error thrown, test passes
|
|
127
|
+
expect(true).toBe(true);
|
|
128
|
+
} catch (error: any) {
|
|
129
|
+
// If typescript finds errors, fail the test
|
|
130
|
+
throw new Error(`TypeScript compilation failed: ${error.stderr}`);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe("Regression #3: Wrong Package Names in Templates", () => {
|
|
136
|
+
/**
|
|
137
|
+
* WHAT BROKE: Templates used "mcp-i" instead of "@kya-os/mcp-i"
|
|
138
|
+
* IMPACT: npm 404 errors - package doesn't exist
|
|
139
|
+
* ROOT CAUSE: Forgot to update package names after scoping
|
|
140
|
+
* FIX: Updated all templates to use scoped package names
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
it("should use scoped @kya-os/* package names", async () => {
|
|
144
|
+
const { applyIdentityPreset } = await import(
|
|
145
|
+
"../helpers/apply-identity-preset.js"
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
// Create a mock project
|
|
149
|
+
const projectPath = join(tempDir, "test-project");
|
|
150
|
+
await mkdir(projectPath, { recursive: true });
|
|
151
|
+
|
|
152
|
+
// Create basic package.json
|
|
153
|
+
await import("fs/promises").then((fs) =>
|
|
154
|
+
fs.writeFile(
|
|
155
|
+
join(projectPath, "package.json"),
|
|
156
|
+
JSON.stringify({
|
|
157
|
+
name: "test-project",
|
|
158
|
+
version: "0.1.0",
|
|
159
|
+
dependencies: {},
|
|
160
|
+
})
|
|
161
|
+
)
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// Apply identity preset
|
|
165
|
+
await applyIdentityPreset({
|
|
166
|
+
projectPath,
|
|
167
|
+
projectName: "test-project",
|
|
168
|
+
transports: ["stdio"],
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Read generated package.json
|
|
172
|
+
const packageJson = JSON.parse(
|
|
173
|
+
await readFile(join(projectPath, "package.json"), "utf-8")
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// Should have scoped names
|
|
177
|
+
expect(packageJson.dependencies["@kya-os/mcp-i"]).toBeDefined();
|
|
178
|
+
expect(packageJson.dependencies["@kya-os/cli"]).toBeDefined();
|
|
179
|
+
|
|
180
|
+
// Should NOT have unscoped names
|
|
181
|
+
expect(packageJson.dependencies["mcp-i"]).toBeUndefined();
|
|
182
|
+
expect(packageJson.dependencies["cli"]).toBeUndefined();
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe("Regression #4: Wrong Binary Names in Scripts", () => {
|
|
187
|
+
/**
|
|
188
|
+
* WHAT BROKE: Scripts used "mcp-i" but binary is "mcpi"
|
|
189
|
+
* IMPACT: Command not found errors
|
|
190
|
+
* ROOT CAUSE: Binary was renamed but scripts weren't updated
|
|
191
|
+
* FIX: Updated all scripts to use correct binary name
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
it("should use correct mcpi binary in all scripts", async () => {
|
|
195
|
+
const { applyIdentityPreset } = await import(
|
|
196
|
+
"../helpers/apply-identity-preset.js"
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const projectPath = join(tempDir, "test-project");
|
|
200
|
+
await mkdir(projectPath, { recursive: true });
|
|
201
|
+
|
|
202
|
+
await import("fs/promises").then((fs) =>
|
|
203
|
+
fs.writeFile(
|
|
204
|
+
join(projectPath, "package.json"),
|
|
205
|
+
JSON.stringify({
|
|
206
|
+
name: "test-project",
|
|
207
|
+
version: "0.1.0",
|
|
208
|
+
scripts: {},
|
|
209
|
+
})
|
|
210
|
+
)
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
await applyIdentityPreset({
|
|
214
|
+
projectPath,
|
|
215
|
+
projectName: "test-project",
|
|
216
|
+
transports: ["http"],
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const packageJson = JSON.parse(
|
|
220
|
+
await readFile(join(projectPath, "package.json"), "utf-8")
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const scripts = packageJson.scripts;
|
|
224
|
+
|
|
225
|
+
// Verify all scripts use "mcpi"
|
|
226
|
+
expect(scripts.dev).toBe("mcpi dev");
|
|
227
|
+
expect(scripts.build).toBe("mcpi build");
|
|
228
|
+
expect(scripts.init).toBe("mcpi init");
|
|
229
|
+
expect(scripts.register).toBe("mcpi register");
|
|
230
|
+
expect(scripts.status).toBe("mcpi status");
|
|
231
|
+
|
|
232
|
+
// Verify NO scripts use old "mcp-i" binary
|
|
233
|
+
for (const [name, script] of Object.entries(scripts)) {
|
|
234
|
+
expect(script).not.toMatch(
|
|
235
|
+
/\bmcp-i\b/,
|
|
236
|
+
`Script ${name} should not use old mcp-i binary`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("should have exactly 8 scripts as specified", async () => {
|
|
242
|
+
const { applyIdentityPreset } = await import(
|
|
243
|
+
"../helpers/apply-identity-preset.js"
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
const projectPath = join(tempDir, "test-project");
|
|
247
|
+
await mkdir(projectPath, { recursive: true });
|
|
248
|
+
|
|
249
|
+
await import("fs/promises").then((fs) =>
|
|
250
|
+
fs.writeFile(
|
|
251
|
+
join(projectPath, "package.json"),
|
|
252
|
+
JSON.stringify({
|
|
253
|
+
name: "test-project",
|
|
254
|
+
version: "0.1.0",
|
|
255
|
+
scripts: {},
|
|
256
|
+
})
|
|
257
|
+
)
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
await applyIdentityPreset({
|
|
261
|
+
projectPath,
|
|
262
|
+
projectName: "test-project",
|
|
263
|
+
transports: ["stdio"],
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const packageJson = JSON.parse(
|
|
267
|
+
await readFile(join(projectPath, "package.json"), "utf-8")
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const scriptNames = Object.keys(packageJson.scripts);
|
|
271
|
+
expect(scriptNames).toHaveLength(8);
|
|
272
|
+
|
|
273
|
+
expect(scriptNames).toContain("dev");
|
|
274
|
+
expect(scriptNames).toContain("build");
|
|
275
|
+
expect(scriptNames).toContain("start");
|
|
276
|
+
expect(scriptNames).toContain("init");
|
|
277
|
+
expect(scriptNames).toContain("register");
|
|
278
|
+
expect(scriptNames).toContain("keys:rotate");
|
|
279
|
+
expect(scriptNames).toContain("identity:clean");
|
|
280
|
+
expect(scriptNames).toContain("status");
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe("Regression #5: Reference Error in Callbacks", () => {
|
|
285
|
+
/**
|
|
286
|
+
* WHAT BROKE: onProgress callback accessed 'result' before definition
|
|
287
|
+
* IMPACT: Runtime error during identity creation
|
|
288
|
+
* ROOT CAUSE: Trying to access Promise result inside callback
|
|
289
|
+
* FIX: Moved effect calls outside the callback, after result available
|
|
290
|
+
*/
|
|
291
|
+
|
|
292
|
+
it("should not have reference to unavailable variables in templates", async () => {
|
|
293
|
+
// This is tested more thoroughly in CLI tests
|
|
294
|
+
// Here we just verify the template doesn't have obvious issues
|
|
295
|
+
|
|
296
|
+
const { applyIdentityPreset } = await import(
|
|
297
|
+
"../helpers/apply-identity-preset.js"
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
const projectPath = join(tempDir, "test-project");
|
|
301
|
+
await mkdir(projectPath, { recursive: true });
|
|
302
|
+
await mkdir(join(projectPath, "src"), { recursive: true });
|
|
303
|
+
|
|
304
|
+
await applyIdentityPreset({
|
|
305
|
+
projectPath,
|
|
306
|
+
projectName: "test-project",
|
|
307
|
+
transports: ["stdio"],
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Check that middleware.ts was created
|
|
311
|
+
const middlewarePath = join(projectPath, "src", "middleware.ts");
|
|
312
|
+
expect(existsSync(middlewarePath)).toBe(true);
|
|
313
|
+
|
|
314
|
+
const middlewareContent = await readFile(middlewarePath, "utf-8");
|
|
315
|
+
|
|
316
|
+
// Should not have obvious reference errors
|
|
317
|
+
expect(middlewareContent).toContain("createMCPIRuntime");
|
|
318
|
+
expect(middlewareContent).toContain("identityMiddleware");
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
describe("Regression #6: .gitignore Missing Identity Files", () => {
|
|
323
|
+
/**
|
|
324
|
+
* WHAT BROKE: .mcpi directory could be committed to git
|
|
325
|
+
* IMPACT: Private keys exposed in version control
|
|
326
|
+
* ROOT CAUSE: .gitignore not updated
|
|
327
|
+
* FIX: Ensured .mcpi/ is always gitignored
|
|
328
|
+
*/
|
|
329
|
+
|
|
330
|
+
it("should add .mcpi to .gitignore", async () => {
|
|
331
|
+
const { applyIdentityPreset } = await import(
|
|
332
|
+
"../helpers/apply-identity-preset.js"
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
const projectPath = join(tempDir, "test-project");
|
|
336
|
+
await mkdir(projectPath, { recursive: true });
|
|
337
|
+
|
|
338
|
+
await applyIdentityPreset({
|
|
339
|
+
projectPath,
|
|
340
|
+
projectName: "test-project",
|
|
341
|
+
transports: ["stdio"],
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
const gitignorePath = join(projectPath, ".gitignore");
|
|
345
|
+
expect(existsSync(gitignorePath)).toBe(true);
|
|
346
|
+
|
|
347
|
+
const gitignoreContent = await readFile(gitignorePath, "utf-8");
|
|
348
|
+
|
|
349
|
+
expect(gitignoreContent).toContain(".mcpi/");
|
|
350
|
+
expect(gitignoreContent).toContain(".env.local");
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it("should preserve existing .gitignore entries", async () => {
|
|
354
|
+
const { applyIdentityPreset } = await import(
|
|
355
|
+
"../helpers/apply-identity-preset.js"
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
const projectPath = join(tempDir, "test-project");
|
|
359
|
+
await mkdir(projectPath, { recursive: true });
|
|
360
|
+
|
|
361
|
+
// Create existing .gitignore
|
|
362
|
+
const existingContent = "node_modules/\ndist/\n.DS_Store\n";
|
|
363
|
+
await import("fs/promises").then((fs) =>
|
|
364
|
+
fs.writeFile(join(projectPath, ".gitignore"), existingContent)
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
await applyIdentityPreset({
|
|
368
|
+
projectPath,
|
|
369
|
+
projectName: "test-project",
|
|
370
|
+
transports: ["stdio"],
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
const gitignoreContent = await readFile(
|
|
374
|
+
join(projectPath, ".gitignore"),
|
|
375
|
+
"utf-8"
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
// Should have both old and new entries
|
|
379
|
+
expect(gitignoreContent).toContain("node_modules/");
|
|
380
|
+
expect(gitignoreContent).toContain("dist/");
|
|
381
|
+
expect(gitignoreContent).toContain(".DS_Store");
|
|
382
|
+
expect(gitignoreContent).toContain(".mcpi/");
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
describe("Regression #7: Project Structure Validation", () => {
|
|
387
|
+
/**
|
|
388
|
+
* WHAT BROKE: Missing directories caused file write errors
|
|
389
|
+
* IMPACT: Scaffolding failed midway through
|
|
390
|
+
* ROOT CAUSE: Didn't ensure parent directories existed
|
|
391
|
+
* FIX: Use ensureDir before writing files
|
|
392
|
+
*/
|
|
393
|
+
|
|
394
|
+
it("should create all necessary directories", async () => {
|
|
395
|
+
const { applyIdentityPreset } = await import(
|
|
396
|
+
"../helpers/apply-identity-preset.js"
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
const projectPath = join(tempDir, "test-project");
|
|
400
|
+
await mkdir(projectPath, { recursive: true });
|
|
401
|
+
|
|
402
|
+
await applyIdentityPreset({
|
|
403
|
+
projectPath,
|
|
404
|
+
projectName: "test-project",
|
|
405
|
+
transports: ["http"],
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Verify directories exist
|
|
409
|
+
expect(existsSync(join(projectPath, "src"))).toBe(true);
|
|
410
|
+
expect(existsSync(join(projectPath, "src", "tools"))).toBe(true);
|
|
411
|
+
expect(existsSync(join(projectPath, ".mcpi"))).toBe(true);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
it("should handle existing directories gracefully", async () => {
|
|
415
|
+
const { applyIdentityPreset } = await import(
|
|
416
|
+
"../helpers/apply-identity-preset.js"
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
const projectPath = join(tempDir, "test-project");
|
|
420
|
+
await mkdir(projectPath, { recursive: true });
|
|
421
|
+
await mkdir(join(projectPath, "src"), { recursive: true });
|
|
422
|
+
await mkdir(join(projectPath, "src", "tools"), { recursive: true });
|
|
423
|
+
|
|
424
|
+
// Should not throw
|
|
425
|
+
await expect(
|
|
426
|
+
applyIdentityPreset({
|
|
427
|
+
projectPath,
|
|
428
|
+
projectName: "test-project",
|
|
429
|
+
transports: ["stdio"],
|
|
430
|
+
})
|
|
431
|
+
).resolves.not.toThrow();
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BlackholeEffect,
|
|
3
|
+
EffectRunner,
|
|
4
|
+
createSuccessBox,
|
|
5
|
+
createWelcomeBanner,
|
|
6
|
+
createGradientText,
|
|
7
|
+
createAgentTable
|
|
8
|
+
} from "@kya-os/cli-effects";
|
|
9
|
+
|
|
10
|
+
export { BlackholeEffect, EffectRunner, createSuccessBox, createWelcomeBanner, createGradientText };
|
|
11
|
+
|
|
12
|
+
export async function showBlackholeAnimation(
|
|
13
|
+
text: string,
|
|
14
|
+
options?: any,
|
|
15
|
+
skipExitPrompt: boolean = false
|
|
16
|
+
): Promise<void> {
|
|
17
|
+
const runner = new EffectRunner();
|
|
18
|
+
const effect = new BlackholeEffect(options);
|
|
19
|
+
await runner.run({
|
|
20
|
+
effect: effect as any,
|
|
21
|
+
text,
|
|
22
|
+
skipExitPrompt
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Display the claim URL as the success message
|
|
27
|
+
export function createSuccessMessage(claimUrl?: string): string {
|
|
28
|
+
if (claimUrl) {
|
|
29
|
+
// Format the claim URL for display
|
|
30
|
+
return `
|
|
31
|
+
š Claim Your Agent Identity:
|
|
32
|
+
|
|
33
|
+
${claimUrl}
|
|
34
|
+
|
|
35
|
+
Your agent is ready to be claimed!`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Fallback if no claim URL
|
|
39
|
+
return createSuccessBox(
|
|
40
|
+
"XMCP-I INITIALIZED",
|
|
41
|
+
"Your AI agent now has a verifiable decentralized identity"
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Use the package's createWelcomeBanner for banners
|
|
46
|
+
export async function createKYAOSBanner(): Promise<string> {
|
|
47
|
+
return await createWelcomeBanner("XMCP-I");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Wrapper function that maps our field names to the package's expected names
|
|
51
|
+
export function createIdentityTable(data: {
|
|
52
|
+
agentName: string;
|
|
53
|
+
description: string;
|
|
54
|
+
did: string;
|
|
55
|
+
profileUrl: string;
|
|
56
|
+
privateKey: string;
|
|
57
|
+
claimUrl?: string;
|
|
58
|
+
}): string {
|
|
59
|
+
// Map field names to match the package's AgentData interface
|
|
60
|
+
const agentData = {
|
|
61
|
+
name: data.agentName, // Map agentName to name
|
|
62
|
+
description: data.description,
|
|
63
|
+
did: data.did,
|
|
64
|
+
publicKey: undefined, // Not used in our implementation
|
|
65
|
+
privateKey: data.privateKey,
|
|
66
|
+
agentSlug: undefined, // Not used, profileUrl is provided directly
|
|
67
|
+
claimUrl: data.claimUrl,
|
|
68
|
+
profileUrl: data.profileUrl
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Use the package's createAgentTable
|
|
72
|
+
let tableOutput = createAgentTable(agentData);
|
|
73
|
+
|
|
74
|
+
// Add claim URL below the table if it exists (since package doesn't show it)
|
|
75
|
+
if (data.claimUrl) {
|
|
76
|
+
tableOutput += "\n\nš Claim URL (clickable):\n" + data.claimUrl;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return tableOutput;
|
|
80
|
+
}
|