@kya-os/create-mcpi-app 1.7.17 → 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.
Files changed (98) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-test$colon$coverage.log +315 -0
  3. package/.turbo/turbo-test.log +95 -0
  4. package/CHANGELOG.md +372 -0
  5. package/IMPLEMENTATION_SUMMARY.md +108 -0
  6. package/REMEDIATION_PLAN.md +99 -0
  7. package/coverage/base.css +224 -0
  8. package/coverage/block-navigation.js +87 -0
  9. package/coverage/clover.xml +252 -0
  10. package/coverage/config-builder.ts.html +580 -0
  11. package/coverage/coverage-final.json +7 -0
  12. package/coverage/favicon.png +0 -0
  13. package/coverage/fetch-cloudflare-mcpi-template.ts.html +7006 -0
  14. package/coverage/generate-config.ts.html +436 -0
  15. package/coverage/generate-identity.ts.html +574 -0
  16. package/coverage/index.html +191 -0
  17. package/coverage/install.ts.html +322 -0
  18. package/coverage/prettify.css +1 -0
  19. package/coverage/prettify.js +2 -0
  20. package/coverage/sort-arrow-sprite.png +0 -0
  21. package/coverage/sorter.js +210 -0
  22. package/coverage/validate-project-structure.ts.html +466 -0
  23. package/dist/.tsbuildinfo +1 -1
  24. package/dist/helpers/__tests__/config-builder.spec.d.ts +8 -0
  25. package/dist/helpers/__tests__/config-builder.spec.d.ts.map +1 -0
  26. package/dist/helpers/__tests__/config-builder.spec.js +182 -0
  27. package/dist/helpers/__tests__/config-builder.spec.js.map +1 -0
  28. package/dist/helpers/config-builder.d.ts +58 -0
  29. package/dist/helpers/config-builder.d.ts.map +1 -0
  30. package/dist/helpers/config-builder.js +102 -0
  31. package/dist/helpers/config-builder.js.map +1 -0
  32. package/dist/helpers/create.d.ts +1 -0
  33. package/dist/helpers/create.d.ts.map +1 -1
  34. package/dist/helpers/create.js +2 -1
  35. package/dist/helpers/create.js.map +1 -1
  36. package/dist/helpers/fetch-cloudflare-mcpi-template.d.ts +1 -0
  37. package/dist/helpers/fetch-cloudflare-mcpi-template.d.ts.map +1 -1
  38. package/dist/helpers/fetch-cloudflare-mcpi-template.js +209 -174
  39. package/dist/helpers/fetch-cloudflare-mcpi-template.js.map +1 -1
  40. package/dist/helpers/fetch-mcpi-template.d.ts.map +1 -1
  41. package/dist/helpers/fetch-mcpi-template.js +18 -3
  42. package/dist/helpers/fetch-mcpi-template.js.map +1 -1
  43. package/dist/helpers/generate-config.d.ts.map +1 -1
  44. package/dist/helpers/generate-config.js +27 -40
  45. package/dist/helpers/generate-config.js.map +1 -1
  46. package/dist/helpers/install.js +5 -0
  47. package/dist/helpers/install.js.map +1 -1
  48. package/dist/index.js +2 -0
  49. package/dist/index.js.map +1 -1
  50. package/package.json +18 -9
  51. package/scripts/prepare-pack.js +47 -0
  52. package/scripts/validate-no-workspace.js +79 -0
  53. package/src/__tests__/cloudflare-template.test.ts +488 -0
  54. package/src/__tests__/helpers/fetch-cloudflare-mcpi-template.test.ts +337 -0
  55. package/src/__tests__/helpers/generate-config.test.ts +312 -0
  56. package/src/__tests__/helpers/generate-identity.test.ts +271 -0
  57. package/src/__tests__/helpers/install.test.ts +362 -0
  58. package/src/__tests__/helpers/validate-project-structure.test.ts +467 -0
  59. package/src/__tests__.bak/regression.test.ts +434 -0
  60. package/src/effects/index.ts +80 -0
  61. package/src/helpers/__tests__/config-builder.spec.ts +231 -0
  62. package/src/helpers/apply-identity-preset.ts +209 -0
  63. package/src/helpers/config-builder.ts +165 -0
  64. package/src/helpers/copy-template.ts +11 -0
  65. package/src/helpers/create.ts +239 -0
  66. package/src/helpers/fetch-cloudflare-mcpi-template.ts +2311 -0
  67. package/src/helpers/fetch-cloudflare-template.ts +361 -0
  68. package/src/helpers/fetch-mcpi-template.ts +236 -0
  69. package/src/helpers/fetch-xmcp-template.ts +153 -0
  70. package/src/helpers/generate-config.ts +117 -0
  71. package/src/helpers/generate-identity.ts +163 -0
  72. package/src/helpers/identity-manager.ts +186 -0
  73. package/src/helpers/install.ts +79 -0
  74. package/src/helpers/rename.ts +17 -0
  75. package/src/helpers/validate-project-structure.ts +127 -0
  76. package/src/index.ts +480 -0
  77. package/src/utils/check-node.ts +17 -0
  78. package/src/utils/is-folder-empty.ts +60 -0
  79. package/src/utils/validate-project-name.ts +132 -0
  80. package/test-cloudflare/README.md +164 -0
  81. package/test-cloudflare/package.json +28 -0
  82. package/test-cloudflare/src/index.ts +340 -0
  83. package/test-cloudflare/src/tools/greet.ts +19 -0
  84. package/test-cloudflare/tests/cache-invalidation.test.ts +410 -0
  85. package/test-cloudflare/tests/cors-security.test.ts +349 -0
  86. package/test-cloudflare/tests/delegation.test.ts +335 -0
  87. package/test-cloudflare/tests/do-routing.test.ts +314 -0
  88. package/test-cloudflare/tests/integration.test.ts +205 -0
  89. package/test-cloudflare/tests/session-management.test.ts +359 -0
  90. package/test-cloudflare/tsconfig.json +22 -0
  91. package/test-cloudflare/vitest.config.ts +9 -0
  92. package/test-cloudflare/wrangler.toml +37 -0
  93. package/test-node/README.md +44 -0
  94. package/test-node/package.json +23 -0
  95. package/test-node/src/tools/greet.ts +25 -0
  96. package/test-node/xmcp.config.ts +20 -0
  97. package/tsconfig.json +26 -0
  98. package/vitest.config.ts +14 -0
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Tests for Configuration Builder Utilities
3
+ *
4
+ * Validates that config builders generate correct configurations
5
+ * and handle remote fetching correctly.
6
+ */
7
+
8
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
9
+ import {
10
+ buildBaseConfig,
11
+ buildConfigWithRemote,
12
+ type ConfigBuilderOptions
13
+ } from '../config-builder.js';
14
+ import type { MCPIConfig } from '@kya-os/contracts/config';
15
+ import type { RemoteConfigCache } from '@kya-os/mcp-i-core';
16
+
17
+ describe('buildBaseConfig', () => {
18
+ it('should generate valid base config with defaults', () => {
19
+ const env = {};
20
+ const config = buildBaseConfig(env);
21
+
22
+ expect(config.environment).toBe('development');
23
+ expect(config.identity?.enabled).toBe(true);
24
+ expect(config.proofing?.enabled).toBe(true);
25
+ expect(config.delegation?.enabled).toBe(true);
26
+ expect(config.audit?.enabled).toBe(true);
27
+ });
28
+
29
+ it('should use environment variables when provided', () => {
30
+ const env = {
31
+ MCPI_ENV: 'production',
32
+ AGENTSHIELD_API_URL: 'https://custom.example.com',
33
+ AGENTSHIELD_API_KEY: 'custom-key'
34
+ };
35
+
36
+ const config = buildBaseConfig(env);
37
+
38
+ expect(config.environment).toBe('production');
39
+ expect(config.identity?.environment).toBe('production');
40
+ expect(config.proofing?.batchQueue?.destinations?.[0].apiUrl).toBe('https://custom.example.com');
41
+ expect(config.delegation?.verifier?.apiUrl).toBe('https://custom.example.com');
42
+ });
43
+
44
+ it('should include all required config sections', () => {
45
+ const env = {};
46
+ const config = buildBaseConfig(env);
47
+
48
+ expect(config).toHaveProperty('environment');
49
+ expect(config).toHaveProperty('identity');
50
+ expect(config).toHaveProperty('proofing');
51
+ expect(config).toHaveProperty('delegation');
52
+ expect(config).toHaveProperty('audit');
53
+ expect(config).toHaveProperty('session');
54
+ });
55
+
56
+ it('should set debug mode based on environment', () => {
57
+ const devConfig = buildBaseConfig({ MCPI_ENV: 'development' });
58
+ const prodConfig = buildBaseConfig({ MCPI_ENV: 'production' });
59
+
60
+ expect(devConfig.proofing?.batchQueue?.debug).toBe(true);
61
+ expect(prodConfig.proofing?.batchQueue?.debug).toBe(false);
62
+ });
63
+ });
64
+
65
+ describe('buildConfigWithRemote', () => {
66
+ let mockFetch: ReturnType<typeof vi.fn>;
67
+ let mockCache: RemoteConfigCache;
68
+
69
+ beforeEach(() => {
70
+ mockFetch = vi.fn();
71
+ mockCache = {
72
+ get: vi.fn(),
73
+ set: vi.fn()
74
+ };
75
+ });
76
+
77
+ it('should use remote config when API key is provided', async () => {
78
+ const remoteConfig: MCPIConfig = {
79
+ environment: 'production',
80
+ identity: { enabled: true, environment: 'production' }
81
+ };
82
+
83
+ vi.mocked(mockCache.get).mockResolvedValue(null);
84
+ mockFetch.mockResolvedValue({
85
+ ok: true,
86
+ json: async () => ({ success: true, data: remoteConfig })
87
+ } as Response);
88
+
89
+ const options: ConfigBuilderOptions = {
90
+ env: {
91
+ AGENTSHIELD_API_KEY: 'test-key',
92
+ AGENTSHIELD_API_URL: 'https://kya.vouched.id'
93
+ },
94
+ fetchProvider: mockFetch,
95
+ cache: mockCache,
96
+ agentDid: 'did:key:test'
97
+ };
98
+
99
+ const config = await buildConfigWithRemote(options);
100
+
101
+ expect(config).toEqual(remoteConfig);
102
+ expect(mockFetch).toHaveBeenCalled();
103
+ });
104
+
105
+ it('should fallback to local config when remote fetch fails', async () => {
106
+ vi.mocked(mockCache.get).mockResolvedValue(null);
107
+ mockFetch.mockResolvedValue({
108
+ ok: false,
109
+ status: 500
110
+ } as Response);
111
+
112
+ const options: ConfigBuilderOptions = {
113
+ env: {
114
+ AGENTSHIELD_API_KEY: 'test-key',
115
+ MCPI_ENV: 'production'
116
+ },
117
+ fetchProvider: mockFetch,
118
+ cache: mockCache
119
+ };
120
+
121
+ const config = await buildConfigWithRemote(options);
122
+
123
+ expect(config.environment).toBe('production');
124
+ expect(config).toHaveProperty('identity');
125
+ expect(config).toHaveProperty('proofing');
126
+ });
127
+
128
+ it('should fallback to local config when API key not provided', async () => {
129
+ const options: ConfigBuilderOptions = {
130
+ env: {
131
+ MCPI_ENV: 'development'
132
+ },
133
+ fetchProvider: mockFetch,
134
+ cache: mockCache
135
+ };
136
+
137
+ const config = await buildConfigWithRemote(options);
138
+
139
+ expect(config.environment).toBe('development');
140
+ expect(mockFetch).not.toHaveBeenCalled();
141
+ });
142
+
143
+ it('should fallback to local config when fetch provider not provided', async () => {
144
+ const options: ConfigBuilderOptions = {
145
+ env: {
146
+ AGENTSHIELD_API_KEY: 'test-key',
147
+ MCPI_ENV: 'development'
148
+ },
149
+ cache: mockCache
150
+ // fetchProvider not provided
151
+ };
152
+
153
+ const config = await buildConfigWithRemote(options);
154
+
155
+ expect(config.environment).toBe('development');
156
+ expect(mockFetch).not.toHaveBeenCalled();
157
+ });
158
+
159
+ it('should use projectId when provided', async () => {
160
+ const remoteConfig: MCPIConfig = {
161
+ environment: 'production'
162
+ };
163
+
164
+ vi.mocked(mockCache.get).mockResolvedValue(null);
165
+ mockFetch.mockResolvedValue({
166
+ ok: true,
167
+ json: async () => ({ success: true, data: remoteConfig })
168
+ } as Response);
169
+
170
+ const options: ConfigBuilderOptions = {
171
+ env: {
172
+ AGENTSHIELD_API_KEY: 'test-key',
173
+ AGENTSHIELD_PROJECT_ID: 'test-project'
174
+ },
175
+ fetchProvider: mockFetch,
176
+ cache: mockCache
177
+ };
178
+
179
+ const config = await buildConfigWithRemote(options);
180
+
181
+ expect(config).toEqual(remoteConfig);
182
+ // Verify fetch was called with projectId endpoint
183
+ expect(mockFetch).toHaveBeenCalled();
184
+ });
185
+
186
+ it('should handle cache hit from remote config', async () => {
187
+ const cachedConfig: MCPIConfig = {
188
+ environment: 'production',
189
+ identity: { enabled: true, environment: 'production' }
190
+ };
191
+
192
+ vi.mocked(mockCache.get).mockResolvedValue(
193
+ JSON.stringify({
194
+ config: cachedConfig,
195
+ expiresAt: Date.now() + 60000
196
+ })
197
+ );
198
+
199
+ const options: ConfigBuilderOptions = {
200
+ env: {
201
+ AGENTSHIELD_API_KEY: 'test-key',
202
+ AGENTSHIELD_PROJECT_ID: 'test-project'
203
+ },
204
+ fetchProvider: mockFetch,
205
+ cache: mockCache
206
+ };
207
+
208
+ const config = await buildConfigWithRemote(options);
209
+
210
+ expect(config).toEqual(cachedConfig);
211
+ expect(mockFetch).not.toHaveBeenCalled();
212
+ });
213
+ });
214
+
215
+ describe('Environment variable parsing', () => {
216
+ it('should handle different environment variable names', () => {
217
+ const config1 = buildBaseConfig({ MCPI_ENV: 'production' });
218
+ const config2 = buildBaseConfig({ ENVIRONMENT: 'production' });
219
+
220
+ expect(config1.environment).toBe('production');
221
+ expect(config2.environment).toBe('production');
222
+ });
223
+
224
+ it('should default to development when no env var provided', () => {
225
+ const config = buildBaseConfig({});
226
+
227
+ expect(config.environment).toBe('development');
228
+ expect(config.identity?.environment).toBe('development');
229
+ });
230
+ });
231
+
@@ -0,0 +1,209 @@
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+ import chalk from "chalk";
4
+
5
+ interface IdentityPresetOptions {
6
+ projectPath: string;
7
+ projectName: string;
8
+ transports: string[];
9
+ noIdentity?: boolean;
10
+ }
11
+
12
+ /**
13
+ * Apply identity preset to an XMCP project
14
+ * This enhances the upstream XMCP template with identity features
15
+ * If noIdentity is true, leaves the XMCP project unchanged
16
+ */
17
+ export async function applyIdentityPreset(
18
+ options: IdentityPresetOptions
19
+ ): Promise<void> {
20
+ const { projectPath, projectName, transports, noIdentity = false } = options;
21
+
22
+ if (noIdentity) {
23
+ console.log(
24
+ chalk.blue("📦 Keeping plain XMCP project (--no-identity flag)")
25
+ );
26
+ return;
27
+ }
28
+
29
+ console.log(chalk.blue("🔐 Applying identity preset..."));
30
+
31
+ const srcDir = path.join(projectPath, "src");
32
+ const toolsDir = path.join(srcDir, "tools");
33
+
34
+ // Skip middleware creation for now since xmcp has issues with middleware imports
35
+ // The identity features will be integrated differently in the future
36
+ // TODO: Once xmcp supports middleware properly, we can re-enable this
37
+ /*
38
+ const middlewarePath = path.join(srcDir, "middleware.ts");
39
+ if (await fs.pathExists(middlewarePath)) {
40
+ // Enhance existing middleware.ts with identity features
41
+ console.log(
42
+ chalk.gray(
43
+ "📝 Enhancing existing middleware.ts with identity features..."
44
+ )
45
+ );
46
+ // ... middleware enhancement code ...
47
+ } else {
48
+ // Create middleware.ts with identity features
49
+ // ... middleware creation code ...
50
+ }
51
+ */
52
+
53
+ // Enhance existing tools or create identity-aware tools
54
+ if (await fs.pathExists(toolsDir)) {
55
+ console.log(
56
+ chalk.gray("🔧 Enhancing existing tools with identity features...")
57
+ );
58
+
59
+ // Check for existing tools and enhance them
60
+ const toolFiles = await fs.readdir(toolsDir);
61
+ const tsFiles = toolFiles.filter(
62
+ (f) => f.endsWith(".ts") && f !== "index.ts"
63
+ );
64
+
65
+ if (tsFiles.length > 0) {
66
+ // Enhance existing tools
67
+ for (const toolFile of tsFiles) {
68
+ const toolPath = path.join(toolsDir, toolFile);
69
+ let toolContent = await fs.readFile(toolPath, "utf-8");
70
+
71
+ // Add identity comment to existing tools
72
+ const identityComment = `// Enhanced with XMCP-I identity features\n`;
73
+ toolContent = identityComment + toolContent;
74
+
75
+ await fs.writeFile(toolPath, toolContent);
76
+ }
77
+ } else {
78
+ // Create identity-aware hello tool if no tools exist
79
+ await createIdentityHelloTool(toolsDir);
80
+ }
81
+ } else {
82
+ // Create tools directory and identity-aware tools
83
+ await fs.ensureDir(toolsDir);
84
+ await createIdentityHelloTool(toolsDir);
85
+ }
86
+
87
+ // Update package.json with identity dependencies and scripts
88
+ await updatePackageJsonForIdentity(projectPath, projectName, transports);
89
+
90
+ // Create .mcpi directory for identity files
91
+ const mcpiDir = path.join(projectPath, ".mcpi");
92
+ await fs.ensureDir(mcpiDir);
93
+
94
+ // Create .gitignore with identity-specific entries
95
+ await updateGitignore(projectPath);
96
+
97
+ console.log(chalk.green("✅ Identity preset applied"));
98
+ }
99
+
100
+ async function createIdentityHelloTool(toolsDir: string): Promise<void> {
101
+ // Create tools/hello.ts with identity features
102
+ const helloToolContent = `// Enhanced with XMCP-I identity features
103
+ import { z } from "zod";
104
+
105
+ export const hello = {
106
+ name: "hello",
107
+ description: "Say hello with identity verification",
108
+ inputSchema: z.object({
109
+ name: z.string().describe("Name to greet"),
110
+ }),
111
+ handler: async ({ name }: { name: string }) => {
112
+ return {
113
+ content: [
114
+ {
115
+ type: "text" as const,
116
+ text: \`Hello, \${name}! This message is cryptographically signed.\`,
117
+ },
118
+ ],
119
+ };
120
+ },
121
+ };
122
+ `;
123
+
124
+ await fs.writeFile(path.join(toolsDir, "hello.ts"), helloToolContent);
125
+
126
+ // Create or update tools/index.ts
127
+ const indexPath = path.join(toolsDir, "index.ts");
128
+ let indexContent = "";
129
+
130
+ if (await fs.pathExists(indexPath)) {
131
+ indexContent = await fs.readFile(indexPath, "utf-8");
132
+ }
133
+
134
+ // Add hello export if not already present (no .js extension for TypeScript)
135
+ if (!indexContent.includes("hello")) {
136
+ indexContent += `\nexport * from "./hello";`;
137
+ await fs.writeFile(indexPath, indexContent);
138
+ }
139
+ }
140
+
141
+ async function updatePackageJsonForIdentity(
142
+ projectPath: string,
143
+ projectName: string,
144
+ transports: string[]
145
+ ): Promise<void> {
146
+ const packageJsonPath = path.join(projectPath, "package.json");
147
+ const packageJson = await fs.readJson(packageJsonPath);
148
+
149
+ // Add identity dependencies
150
+ // Use workspace dependencies for local testing, published versions for production
151
+ const useWorkspace = process.env.MCPI_USE_WORKSPACE === "true";
152
+
153
+ // Add @kya-os dependencies - packages are now published!
154
+ if (useWorkspace) {
155
+ packageJson.dependencies = {
156
+ ...packageJson.dependencies,
157
+ "@kya-os/mcp-i": "workspace:*",
158
+ "@kya-os/cli": "workspace:*",
159
+ };
160
+ } else {
161
+ // Add published packages
162
+ packageJson.dependencies = {
163
+ ...packageJson.dependencies,
164
+ "@kya-os/mcp-i": "^1.2.7",
165
+ "@kya-os/cli": "^1.2.7",
166
+ };
167
+ }
168
+
169
+ // Add exactly 8 scripts as required by spec
170
+ // Now using actual mcpi commands since @kya-os/cli is published
171
+ packageJson.scripts = {
172
+ dev: "xmcp dev",
173
+ build: "xmcp build",
174
+ start: "xmcp start",
175
+ init: "mcpi init",
176
+ register: "mcpi register",
177
+ "keys:rotate": "mcpi rotate",
178
+ "identity:clean": "rm -rf .mcpi",
179
+ status: "mcpi status",
180
+ };
181
+
182
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
183
+ }
184
+
185
+ async function updateGitignore(projectPath: string): Promise<void> {
186
+ const gitignorePath = path.join(projectPath, ".gitignore");
187
+ let gitignoreContent = "";
188
+
189
+ if (await fs.pathExists(gitignorePath)) {
190
+ gitignoreContent = await fs.readFile(gitignorePath, "utf-8");
191
+ }
192
+
193
+ // Add identity-specific gitignore entries if not already present
194
+ const identityEntries = [
195
+ "# MCP-I Identity",
196
+ ".mcpi/",
197
+ ".env.local",
198
+ "generated-identity.json",
199
+ ".mcp-identity.json",
200
+ ];
201
+
202
+ for (const entry of identityEntries) {
203
+ if (!gitignoreContent.includes(entry)) {
204
+ gitignoreContent += `\n${entry}`;
205
+ }
206
+ }
207
+
208
+ await fs.writeFile(gitignorePath, gitignoreContent);
209
+ }
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Configuration Builder Utilities
3
+ *
4
+ * Shared utilities for building MCP-I configuration that works across
5
+ * all platforms (Node.js, Cloudflare Workers, etc.).
6
+ *
7
+ * @module @kya-os/create-mcpi-app/config-builder
8
+ */
9
+
10
+ import type {
11
+ MCPIConfig,
12
+ RuntimeIdentityConfig,
13
+ ProofingConfig,
14
+ DelegationConfig,
15
+ ProofBatchQueueConfig,
16
+ ProofDestination,
17
+ DelegationVerifierConfig,
18
+ AuthorizationConfig
19
+ } from '@kya-os/contracts/config';
20
+
21
+ import {
22
+ fetchRemoteConfig,
23
+ type RemoteConfigOptions,
24
+ type RemoteConfigCache
25
+ } from '@kya-os/mcp-i-core';
26
+
27
+ /**
28
+ * Options for building configuration with remote fetching support
29
+ */
30
+ export interface ConfigBuilderOptions {
31
+ /**
32
+ * Environment variables object
33
+ * Works with process.env (Node.js) or Cloudflare env bindings
34
+ */
35
+ env: Record<string, any>;
36
+
37
+ /**
38
+ * Fetch provider function
39
+ * Platform-agnostic fetch implementation
40
+ * Required for remote config fetching
41
+ */
42
+ fetchProvider?: (url: string, options: RequestInit) => Promise<Response>;
43
+
44
+ /**
45
+ * Cache implementation for remote config
46
+ * Optional, but recommended for performance
47
+ */
48
+ cache?: RemoteConfigCache;
49
+
50
+ /**
51
+ * Agent DID for agent-scoped config fetching
52
+ * Used when projectId is not available
53
+ */
54
+ agentDid?: string;
55
+ }
56
+
57
+ /**
58
+ * Build base MCPIConfig that works across all platforms
59
+ *
60
+ * Creates a platform-agnostic configuration object with sensible defaults
61
+ * for identity, proofing, delegation, audit, and session management.
62
+ *
63
+ * @param env - Environment variables object (works with process.env or Cloudflare env)
64
+ * @returns Complete MCPIConfig object
65
+ */
66
+ export function buildBaseConfig(env: Record<string, any>): MCPIConfig {
67
+ const environment = (env.MCPI_ENV || env.ENVIRONMENT || 'development') as 'development' | 'production';
68
+ const isDevelopment = environment === 'development';
69
+
70
+ const baseConfig: MCPIConfig = {
71
+ environment,
72
+
73
+ identity: {
74
+ enabled: true,
75
+ environment,
76
+ devIdentityPath: '.mcpi/identity.json'
77
+ } as RuntimeIdentityConfig,
78
+
79
+ proofing: {
80
+ enabled: true,
81
+ batchQueue: {
82
+ destinations: [
83
+ {
84
+ type: 'agentshield' as const,
85
+ apiUrl: env.AGENTSHIELD_API_URL || 'https://kya.vouched.id',
86
+ apiKey: env.AGENTSHIELD_API_KEY || ''
87
+ }
88
+ ],
89
+ maxBatchSize: 10,
90
+ flushIntervalMs: 5000,
91
+ maxRetries: 3,
92
+ debug: isDevelopment
93
+ }
94
+ } as ProofingConfig,
95
+
96
+ delegation: {
97
+ enabled: true,
98
+ enforceDelegations: true,
99
+ verifier: {
100
+ type: 'agentshield' as const,
101
+ apiUrl: env.AGENTSHIELD_API_URL || 'https://kya.vouched.id',
102
+ apiKey: env.AGENTSHIELD_API_KEY || '',
103
+ cacheTtl: 60000, // 1 minute cache
104
+ debug: isDevelopment
105
+ } as DelegationVerifierConfig,
106
+ authorization: {
107
+ authorizationUrl: env.AUTHORIZATION_URL || `${env.AGENTSHIELD_API_URL || 'https://kya.vouched.id'}/authorize`,
108
+ resumeTokenTtl: 600000, // 10 minutes
109
+ minReputationScore: 76
110
+ } as AuthorizationConfig
111
+ } as DelegationConfig,
112
+
113
+ audit: {
114
+ enabled: true,
115
+ includeProofHashes: false,
116
+ includePayloads: false
117
+ },
118
+
119
+ session: {
120
+ timestampSkewSeconds: 120,
121
+ ttlMinutes: 30
122
+ }
123
+ };
124
+
125
+ return baseConfig;
126
+ }
127
+
128
+ /**
129
+ * Build config with remote fetching support
130
+ *
131
+ * Attempts to fetch configuration from remote API (AgentShield dashboard)
132
+ * first, then falls back to local environment-based configuration if remote
133
+ * fetch fails or is not configured.
134
+ *
135
+ * @param options - Configuration builder options
136
+ * @returns Promise resolving to MCPIConfig
137
+ */
138
+ export async function buildConfigWithRemote(
139
+ options: ConfigBuilderOptions
140
+ ): Promise<MCPIConfig> {
141
+ const { env, fetchProvider, cache, agentDid } = options;
142
+
143
+ // Try remote fetch first if API key and fetch provider are configured
144
+ if (env.AGENTSHIELD_API_KEY && fetchProvider) {
145
+ const remote = await fetchRemoteConfig(
146
+ {
147
+ apiUrl: env.AGENTSHIELD_API_URL || 'https://kya.vouched.id',
148
+ apiKey: env.AGENTSHIELD_API_KEY,
149
+ projectId: env.AGENTSHIELD_PROJECT_ID,
150
+ agentDid,
151
+ cacheTtl: 300000, // 5 minutes
152
+ fetchProvider
153
+ },
154
+ cache
155
+ );
156
+
157
+ if (remote) {
158
+ return remote;
159
+ }
160
+ }
161
+
162
+ // Fallback to local env-based config
163
+ return buildBaseConfig(env);
164
+ }
165
+
@@ -0,0 +1,11 @@
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+
4
+ export function copyTemplate(templateDir: string, projectPath: string): void {
5
+ fs.copySync(templateDir, projectPath, {
6
+ filter: (src: string) => {
7
+ const basename = path.basename(src);
8
+ return !basename.startsWith(".");
9
+ },
10
+ });
11
+ }