@boostecom/provider 0.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.
Files changed (70) hide show
  1. package/README.md +90 -0
  2. package/dist/index.cjs +2522 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +848 -0
  5. package/dist/index.d.ts +848 -0
  6. package/dist/index.js +2484 -0
  7. package/dist/index.js.map +1 -0
  8. package/docs/content/README.md +337 -0
  9. package/docs/content/agent-teams.mdx +324 -0
  10. package/docs/content/api.mdx +757 -0
  11. package/docs/content/best-practices.mdx +624 -0
  12. package/docs/content/examples.mdx +675 -0
  13. package/docs/content/guide.mdx +516 -0
  14. package/docs/content/index.mdx +99 -0
  15. package/docs/content/installation.mdx +246 -0
  16. package/docs/content/skills.mdx +548 -0
  17. package/docs/content/troubleshooting.mdx +588 -0
  18. package/docs/examples/README.md +499 -0
  19. package/docs/examples/abort-signal.ts +125 -0
  20. package/docs/examples/agent-teams.ts +122 -0
  21. package/docs/examples/basic-usage.ts +73 -0
  22. package/docs/examples/check-cli.ts +51 -0
  23. package/docs/examples/conversation-history.ts +69 -0
  24. package/docs/examples/custom-config.ts +90 -0
  25. package/docs/examples/generate-object-constraints.ts +209 -0
  26. package/docs/examples/generate-object.ts +211 -0
  27. package/docs/examples/hooks-callbacks.ts +63 -0
  28. package/docs/examples/images.ts +76 -0
  29. package/docs/examples/integration-test.ts +241 -0
  30. package/docs/examples/limitations.ts +150 -0
  31. package/docs/examples/logging-custom-logger.ts +99 -0
  32. package/docs/examples/logging-default.ts +55 -0
  33. package/docs/examples/logging-disabled.ts +74 -0
  34. package/docs/examples/logging-verbose.ts +64 -0
  35. package/docs/examples/long-running-tasks.ts +179 -0
  36. package/docs/examples/message-injection.ts +210 -0
  37. package/docs/examples/mid-stream-injection.ts +126 -0
  38. package/docs/examples/run-all-examples.sh +48 -0
  39. package/docs/examples/sdk-tools-callbacks.ts +49 -0
  40. package/docs/examples/skills-discovery.ts +144 -0
  41. package/docs/examples/skills-management.ts +140 -0
  42. package/docs/examples/stream-object.ts +80 -0
  43. package/docs/examples/streaming.ts +52 -0
  44. package/docs/examples/structured-output-repro.ts +227 -0
  45. package/docs/examples/tool-management.ts +215 -0
  46. package/docs/examples/tool-streaming.ts +132 -0
  47. package/docs/examples/zod4-compatibility-test.ts +290 -0
  48. package/docs/src/claude-code-language-model.test.ts +3883 -0
  49. package/docs/src/claude-code-language-model.ts +2586 -0
  50. package/docs/src/claude-code-provider.test.ts +97 -0
  51. package/docs/src/claude-code-provider.ts +179 -0
  52. package/docs/src/convert-to-claude-code-messages.images.test.ts +104 -0
  53. package/docs/src/convert-to-claude-code-messages.test.ts +193 -0
  54. package/docs/src/convert-to-claude-code-messages.ts +419 -0
  55. package/docs/src/errors.test.ts +213 -0
  56. package/docs/src/errors.ts +216 -0
  57. package/docs/src/index.test.ts +49 -0
  58. package/docs/src/index.ts +98 -0
  59. package/docs/src/logger.integration.test.ts +164 -0
  60. package/docs/src/logger.test.ts +184 -0
  61. package/docs/src/logger.ts +65 -0
  62. package/docs/src/map-claude-code-finish-reason.test.ts +120 -0
  63. package/docs/src/map-claude-code-finish-reason.ts +60 -0
  64. package/docs/src/mcp-helpers.test.ts +71 -0
  65. package/docs/src/mcp-helpers.ts +123 -0
  66. package/docs/src/message-injection.test.ts +460 -0
  67. package/docs/src/types.ts +447 -0
  68. package/docs/src/validation.test.ts +558 -0
  69. package/docs/src/validation.ts +360 -0
  70. package/package.json +124 -0
@@ -0,0 +1,360 @@
1
+ import { z } from 'zod';
2
+ import { existsSync } from 'fs';
3
+
4
+ /**
5
+ * Validation schemas and utilities for Claude Code provider inputs.
6
+ * Uses Zod for type-safe validation following AI SDK patterns.
7
+ */
8
+
9
+ // Helper for Zod v3/v4 compatibility
10
+ // Use a simple z.any() for functions to work with both versions
11
+ const loggerFunctionSchema = z.object({
12
+ debug: z.any().refine((val) => typeof val === 'function', {
13
+ message: 'debug must be a function',
14
+ }),
15
+ info: z.any().refine((val) => typeof val === 'function', {
16
+ message: 'info must be a function',
17
+ }),
18
+ warn: z.any().refine((val) => typeof val === 'function', {
19
+ message: 'warn must be a function',
20
+ }),
21
+ error: z.any().refine((val) => typeof val === 'function', {
22
+ message: 'error must be a function',
23
+ }),
24
+ });
25
+
26
+ /**
27
+ * Schema for validating Claude Code settings.
28
+ * Ensures all settings are within acceptable ranges and formats.
29
+ */
30
+ export const claudeCodeSettingsSchema = z
31
+ .object({
32
+ pathToClaudeCodeExecutable: z.string().optional(),
33
+ customSystemPrompt: z.string().optional(),
34
+ appendSystemPrompt: z.string().optional(),
35
+ systemPrompt: z
36
+ .union([
37
+ z.string(),
38
+ z.object({
39
+ type: z.literal('preset'),
40
+ preset: z.literal('claude_code'),
41
+ append: z.string().optional(),
42
+ }),
43
+ ])
44
+ .optional(),
45
+ maxTurns: z.number().int().min(1).max(100).optional(),
46
+ maxThinkingTokens: z.number().int().positive().max(100000).optional(),
47
+ cwd: z
48
+ .string()
49
+ .refine(
50
+ (val) => {
51
+ // Skip directory validation in non-Node environments
52
+ if (typeof process === 'undefined' || !process.versions?.node) {
53
+ return true;
54
+ }
55
+ return !val || existsSync(val);
56
+ },
57
+ { message: 'Working directory must exist' }
58
+ )
59
+ .optional(),
60
+ executable: z.enum(['bun', 'deno', 'node']).optional(),
61
+ executableArgs: z.array(z.string()).optional(),
62
+ permissionMode: z
63
+ .enum(['default', 'acceptEdits', 'bypassPermissions', 'plan', 'delegate', 'dontAsk'])
64
+ .optional(),
65
+ permissionPromptToolName: z.string().optional(),
66
+ continue: z.boolean().optional(),
67
+ resume: z.string().optional(),
68
+ sessionId: z.string().optional(),
69
+ allowedTools: z.array(z.string()).optional(),
70
+ disallowedTools: z.array(z.string()).optional(),
71
+ betas: z.array(z.string()).optional(),
72
+ allowDangerouslySkipPermissions: z.boolean().optional(),
73
+ enableFileCheckpointing: z.boolean().optional(),
74
+ maxBudgetUsd: z.number().min(0).optional(),
75
+ plugins: z
76
+ .array(
77
+ z
78
+ .object({
79
+ type: z.string(),
80
+ path: z.string(),
81
+ })
82
+ .passthrough()
83
+ )
84
+ .optional(),
85
+ resumeSessionAt: z.string().optional(),
86
+ sandbox: z
87
+ .any()
88
+ .refine((val) => val === undefined || typeof val === 'object', {
89
+ message: 'sandbox must be an object',
90
+ })
91
+ .optional(),
92
+ tools: z
93
+ .union([
94
+ z.array(z.string()),
95
+ z.object({
96
+ type: z.literal('preset'),
97
+ preset: z.literal('claude_code'),
98
+ }),
99
+ ])
100
+ .optional(),
101
+ settingSources: z.array(z.enum(['user', 'project', 'local'])).optional(),
102
+ streamingInput: z.enum(['auto', 'always', 'off']).optional(),
103
+ // Hooks and tool-permission callback (permissive validation of shapes)
104
+ canUseTool: z
105
+ .any()
106
+ .refine((v) => v === undefined || typeof v === 'function', {
107
+ message: 'canUseTool must be a function',
108
+ })
109
+ .optional(),
110
+ hooks: z
111
+ .record(
112
+ z.string(),
113
+ z.array(
114
+ z.object({
115
+ matcher: z.string().optional(),
116
+ hooks: z.array(z.any()).nonempty(),
117
+ })
118
+ )
119
+ )
120
+ .optional(),
121
+ mcpServers: z
122
+ .record(
123
+ z.string(),
124
+ z.union([
125
+ // McpStdioServerConfig
126
+ z.object({
127
+ type: z.literal('stdio').optional(),
128
+ command: z.string(),
129
+ args: z.array(z.string()).optional(),
130
+ env: z.record(z.string(), z.string()).optional(),
131
+ }),
132
+ // McpSSEServerConfig
133
+ z.object({
134
+ type: z.literal('sse'),
135
+ url: z.string(),
136
+ headers: z.record(z.string(), z.string()).optional(),
137
+ }),
138
+ // McpHttpServerConfig
139
+ z.object({
140
+ type: z.literal('http'),
141
+ url: z.string(),
142
+ headers: z.record(z.string(), z.string()).optional(),
143
+ }),
144
+ // McpSdkServerConfig (in-process custom tools)
145
+ z.object({
146
+ type: z.literal('sdk'),
147
+ name: z.string(),
148
+ instance: z.any(),
149
+ }),
150
+ ])
151
+ )
152
+ .optional(),
153
+ verbose: z.boolean().optional(),
154
+ debug: z.boolean().optional(),
155
+ debugFile: z.string().optional(),
156
+ logger: z.union([z.literal(false), loggerFunctionSchema]).optional(),
157
+ env: z.record(z.string(), z.string().optional()).optional(),
158
+ additionalDirectories: z.array(z.string()).optional(),
159
+ agents: z
160
+ .record(
161
+ z.string(),
162
+ z
163
+ .object({
164
+ description: z.string(),
165
+ tools: z.array(z.string()).optional(),
166
+ disallowedTools: z.array(z.string()).optional(),
167
+ prompt: z.string(),
168
+ model: z.enum(['sonnet', 'opus', 'haiku', 'inherit']).optional(),
169
+ mcpServers: z
170
+ .array(
171
+ z.union([
172
+ z.string(),
173
+ z.record(z.string(), z.any()), // McpServerConfigForProcessTransport
174
+ ])
175
+ )
176
+ .optional(),
177
+ criticalSystemReminder_EXPERIMENTAL: z.string().optional(),
178
+ })
179
+ .passthrough()
180
+ )
181
+ .optional(),
182
+ includePartialMessages: z.boolean().optional(),
183
+ fallbackModel: z.string().optional(),
184
+ forkSession: z.boolean().optional(),
185
+ stderr: z
186
+ .any()
187
+ .refine((val) => val === undefined || typeof val === 'function', {
188
+ message: 'stderr must be a function',
189
+ })
190
+ .optional(),
191
+ strictMcpConfig: z.boolean().optional(),
192
+ extraArgs: z.record(z.string(), z.union([z.string(), z.null()])).optional(),
193
+ persistSession: z.boolean().optional(),
194
+ spawnClaudeCodeProcess: z
195
+ .any()
196
+ .refine((val) => val === undefined || typeof val === 'function', {
197
+ message: 'spawnClaudeCodeProcess must be a function',
198
+ })
199
+ .optional(),
200
+ sdkOptions: z.record(z.string(), z.any()).optional(),
201
+ maxToolResultSize: z.number().int().min(100).max(1000000).optional(),
202
+ // Callback invoked when Query object is created - for mid-stream injection via streamInput()
203
+ onQueryCreated: z
204
+ .any()
205
+ .refine((val) => val === undefined || typeof val === 'function', {
206
+ message: 'onQueryCreated must be a function',
207
+ })
208
+ .optional(),
209
+ onStreamStart: z
210
+ .any()
211
+ .refine((val) => val === undefined || typeof val === 'function', {
212
+ message: 'onStreamStart must be a function',
213
+ })
214
+ .optional(),
215
+ })
216
+ .strict();
217
+
218
+ /**
219
+ * Validates a model ID and returns warnings if needed.
220
+ *
221
+ * @param modelId - The model ID to validate
222
+ * @returns Warning message if model is unknown, undefined otherwise
223
+ */
224
+ export function validateModelId(modelId: string): string | undefined {
225
+ const knownModels = ['opus', 'sonnet', 'haiku'];
226
+
227
+ // Check for empty or whitespace-only
228
+ if (!modelId || modelId.trim() === '') {
229
+ throw new Error('Model ID cannot be empty');
230
+ }
231
+
232
+ // Warn about unknown models but allow them
233
+ if (!knownModels.includes(modelId)) {
234
+ return `Unknown model ID: '${modelId}'. Proceeding with custom model. Known models are: ${knownModels.join(', ')}`;
235
+ }
236
+
237
+ return undefined;
238
+ }
239
+
240
+ /**
241
+ * Validates Claude Code settings and returns validation results.
242
+ *
243
+ * @param settings - The settings object to validate
244
+ * @returns Object with validation results and any warnings
245
+ */
246
+ export function validateSettings(settings: unknown): {
247
+ valid: boolean;
248
+ warnings: string[];
249
+ errors: string[];
250
+ } {
251
+ const warnings: string[] = [];
252
+ const errors: string[] = [];
253
+
254
+ try {
255
+ // Parse with Zod schema
256
+ const result = claudeCodeSettingsSchema.safeParse(settings);
257
+
258
+ if (!result.success) {
259
+ // Extract user-friendly error messages
260
+ // Support both Zod v3 (errors) and v4 (issues)
261
+ const errorObject = result.error as {
262
+ errors?: Array<{ path: string[]; message: string }>;
263
+ issues?: Array<{ path: string[]; message: string }>;
264
+ };
265
+ const issues = errorObject.errors || errorObject.issues || [];
266
+ issues.forEach((err: { path: string[]; message: string }) => {
267
+ const path = err.path.join('.');
268
+ errors.push(`${path ? `${path}: ` : ''}${err.message}`);
269
+ });
270
+ return { valid: false, warnings, errors };
271
+ }
272
+
273
+ // Additional validation warnings
274
+ const validSettings = result.data;
275
+
276
+ // Warn about high turn limits
277
+ if (validSettings.maxTurns && validSettings.maxTurns > 20) {
278
+ warnings.push(
279
+ `High maxTurns value (${validSettings.maxTurns}) may lead to long-running conversations`
280
+ );
281
+ }
282
+
283
+ // Warn about very high thinking tokens
284
+ if (validSettings.maxThinkingTokens && validSettings.maxThinkingTokens > 50000) {
285
+ warnings.push(
286
+ `Very high maxThinkingTokens (${validSettings.maxThinkingTokens}) may increase response time`
287
+ );
288
+ }
289
+
290
+ // Check if both allowedTools and disallowedTools are specified
291
+ if (validSettings.allowedTools && validSettings.disallowedTools) {
292
+ warnings.push(
293
+ 'Both allowedTools and disallowedTools are specified. Only allowedTools will be used.'
294
+ );
295
+ }
296
+
297
+ // Validate tool name format
298
+ const validateToolNames = (tools: string[], type: string) => {
299
+ tools.forEach((tool) => {
300
+ // Basic validation - tool names should be alphanumeric with optional specifiers
301
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*(\([^)]*\))?$/.test(tool) && !tool.startsWith('mcp__')) {
302
+ warnings.push(`Unusual ${type} tool name format: '${tool}'`);
303
+ }
304
+ });
305
+ };
306
+
307
+ if (validSettings.allowedTools) {
308
+ validateToolNames(validSettings.allowedTools, 'allowed');
309
+ }
310
+
311
+ if (validSettings.disallowedTools) {
312
+ validateToolNames(validSettings.disallowedTools, 'disallowed');
313
+ }
314
+
315
+ // Warn about Skills configuration issues
316
+ if (validSettings.allowedTools?.includes('Skill') && !validSettings.settingSources) {
317
+ warnings.push(
318
+ "allowedTools includes 'Skill' but settingSources is not set. Skills require settingSources (e.g., ['user', 'project']) to load skill definitions."
319
+ );
320
+ }
321
+
322
+ return { valid: true, warnings, errors };
323
+ } catch (error) {
324
+ errors.push(`Validation error: ${error instanceof Error ? error.message : String(error)}`);
325
+ return { valid: false, warnings, errors };
326
+ }
327
+ }
328
+
329
+ /**
330
+ * Validates prompt length and format.
331
+ *
332
+ * @param prompt - The prompt to validate
333
+ * @returns Warning message if prompt might cause issues
334
+ */
335
+ export function validatePrompt(prompt: string): string | undefined {
336
+ // Very long prompts might cause issues
337
+ const MAX_PROMPT_LENGTH = 100000; // ~25k tokens
338
+
339
+ if (prompt.length > MAX_PROMPT_LENGTH) {
340
+ return `Very long prompt (${prompt.length} characters) may cause performance issues or timeouts`;
341
+ }
342
+
343
+ return undefined;
344
+ }
345
+
346
+ /**
347
+ * Validates session ID format.
348
+ *
349
+ * @param sessionId - The session ID to validate
350
+ * @returns Warning message if format is unusual
351
+ */
352
+ export function validateSessionId(sessionId: string): string | undefined {
353
+ // Session IDs from Claude Code are typically UUID-like
354
+ // But we don't want to be too strict as format might change
355
+ if (sessionId && !/^[a-zA-Z0-9-_]+$/.test(sessionId)) {
356
+ return `Unusual session ID format. This may cause issues with session resumption.`;
357
+ }
358
+
359
+ return undefined;
360
+ }
package/package.json ADDED
@@ -0,0 +1,124 @@
1
+ {
2
+ "name": "@boostecom/provider",
3
+ "version": "0.0.1",
4
+ "description": "AI SDK v6 provider for Claude via Claude Agent SDK (use Pro/Max subscription)",
5
+ "keywords": [
6
+ "ai-sdk",
7
+ "claude-agent-sdk",
8
+ "anthropic",
9
+ "cli",
10
+ "language-model",
11
+ "llm"
12
+ ],
13
+ "homepage": "https://github.com/BoostEcom/ThemeCopilotAI",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/BoostEcom/ThemeCopilotAI.git"
17
+ },
18
+ "bugs": {
19
+ "url": "https://github.com/BoostEcom/ThemeCopilotAI/issues"
20
+ },
21
+ "license": "MIT",
22
+ "author": "Christopher Lasgi <dev@boostecom.dev>",
23
+ "type": "module",
24
+ "sideEffects": false,
25
+ "main": "./dist/index.cjs",
26
+ "module": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ "./package.json": "./package.json",
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js",
33
+ "require": "./dist/index.cjs"
34
+ }
35
+ },
36
+ "files": [
37
+ "dist/**/*",
38
+ "README.md",
39
+ "docs/**/*",
40
+ "LICENSE"
41
+ ],
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "build:lib": "tsup",
45
+ "build:docs": "next build",
46
+ "clean": "rm -rf dist",
47
+ "dev": "next dev",
48
+ "dev:lib": "tsup --watch",
49
+ "start": "next start",
50
+ "lint": "eslint src",
51
+ "lint:all": "eslint .",
52
+ "format": "prettier --write .",
53
+ "format:check": "prettier --check .",
54
+ "ci": "npm run typecheck && npm run lint:all && npm run test",
55
+ "prepare": "npm run build",
56
+ "prepublishOnly": "npm run clean && npm run build",
57
+ "test": "vitest run",
58
+ "test:coverage": "vitest run --coverage",
59
+ "test:edge": "vitest run --project=edge",
60
+ "test:node": "vitest run --project=node",
61
+ "test:watch": "vitest",
62
+ "test:integration": "npm run build && npx tsx examples/integration-test.ts",
63
+ "typecheck": "tsc --noEmit",
64
+ "example:basic": "npm run build && npx tsx examples/basic-usage.ts",
65
+ "example:streaming": "npm run build && npx tsx examples/streaming.ts",
66
+ "example:conversation": "npm run build && npx tsx examples/conversation-history.ts",
67
+ "example:config": "npm run build && npx tsx examples/custom-config.ts",
68
+ "example:object": "npm run build && npx tsx examples/generate-object.ts",
69
+ "example:object:constraints": "npm run build && npx tsx examples/generate-object-constraints.ts",
70
+ "example:tools": "npm run build && npx tsx examples/tool-management.ts",
71
+ "example:timeout": "npm run build && npx tsx examples/long-running-tasks.ts",
72
+ "example:zod4": "npm run build && npx tsx examples/zod4-compatibility-test.ts",
73
+ "example:structured-repro": "npx tsx examples/structured-output-repro.ts",
74
+ "example:agent-teams": "npm run build && npx tsx examples/agent-teams.ts",
75
+ "example:skills-discovery": "npm run build && npx tsx examples/skills-discovery.ts",
76
+ "example:all": "npm run build && npm run example:basic && npm run example:streaming && npm run example:conversation && npm run example:config && npm run example:object && npm run example:object:constraints && npm run example:tools && npm run example:timeout"
77
+ },
78
+ "dependencies": {
79
+ "@ai-sdk/provider": "^3.0.0",
80
+ "@ai-sdk/provider-utils": "^4.0.1",
81
+ "@anthropic-ai/claude-agent-sdk": "^0.2.33"
82
+ },
83
+ "devDependencies": {
84
+ "@edge-runtime/vm": "5.0.0",
85
+ "@eslint/js": "9.28.0",
86
+ "@tailwindcss/postcss": "^4.1.18",
87
+ "@tailwindcss/typography": "^0.5.19",
88
+ "@types/node": "^20.19.0",
89
+ "@types/react": "^19.0.0",
90
+ "@types/react-dom": "^19.0.0",
91
+ "@typescript-eslint/eslint-plugin": "8.34.0",
92
+ "@typescript-eslint/parser": "8.34.0",
93
+ "@vitest/coverage-v8": "^3.2.4",
94
+ "ai": "^6.0.3",
95
+ "autoprefixer": "^10.4.20",
96
+ "clsx": "^2.1.1",
97
+ "eslint": "9.28.0",
98
+ "globals": "16.2.0",
99
+ "lucide-react": "^0.468.0",
100
+ "next": "^16.0.0",
101
+ "postcss": "^8.4.49",
102
+ "prettier": "^3.6.2",
103
+ "react": "^19.0.0",
104
+ "react-dom": "^19.0.0",
105
+ "react-markdown": "^9.0.1",
106
+ "remark-gfm": "^4.0.0",
107
+ "tailwind-merge": "^3.0.0",
108
+ "tailwindcss": "^4.0.0",
109
+ "tailwindcss-animate": "^1.0.7",
110
+ "tsup": "8.5.0",
111
+ "typescript": "5.6.3",
112
+ "vitest": "3.2.4",
113
+ "zod": "^4.1.12"
114
+ },
115
+ "peerDependencies": {
116
+ "zod": "^4.0.0"
117
+ },
118
+ "engines": {
119
+ "node": ">=18"
120
+ },
121
+ "publishConfig": {
122
+ "access": "public"
123
+ }
124
+ }