@pikku/cli 0.7.7 → 0.8.0

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 (190) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/bin/pikku-all.ts +87 -48
  3. package/bin/pikku-fetch.ts +5 -37
  4. package/bin/pikku-nextjs.ts +7 -112
  5. package/bin/pikku-openapi.ts +6 -53
  6. package/bin/pikku-queue-service.ts +24 -0
  7. package/bin/pikku-schemas.ts +6 -32
  8. package/bin/pikku-websocket.ts +6 -40
  9. package/bin/pikku.ts +2 -0
  10. package/dist/bin/pikku-all.d.ts +1 -1
  11. package/dist/bin/pikku-all.js +68 -48
  12. package/dist/bin/pikku-fetch.d.ts +1 -3
  13. package/dist/bin/pikku-fetch.js +4 -14
  14. package/dist/bin/pikku-nextjs.d.ts +1 -4
  15. package/dist/bin/pikku-nextjs.js +5 -39
  16. package/dist/bin/pikku-openapi.d.ts +0 -3
  17. package/dist/bin/pikku-openapi.js +5 -23
  18. package/dist/bin/pikku-queue-service.d.ts +4 -0
  19. package/dist/bin/pikku-queue-service.js +15 -0
  20. package/dist/bin/pikku-schemas.d.ts +0 -3
  21. package/dist/bin/pikku-schemas.js +5 -11
  22. package/dist/bin/pikku-websocket.d.ts +1 -3
  23. package/dist/bin/pikku-websocket.js +4 -17
  24. package/dist/bin/pikku.js +2 -0
  25. package/dist/src/events/channels/pikku-channels.d.ts +2 -0
  26. package/dist/src/events/channels/pikku-channels.js +9 -0
  27. package/dist/src/events/channels/pikku-command-channels-map.d.ts +2 -0
  28. package/dist/src/events/channels/pikku-command-channels-map.js +8 -0
  29. package/dist/src/events/channels/pikku-command-channels.d.ts +2 -0
  30. package/dist/src/events/channels/pikku-command-channels.js +9 -0
  31. package/dist/src/events/channels/pikku-command-websocket-typed.d.ts +2 -0
  32. package/dist/src/events/channels/pikku-command-websocket-typed.js +15 -0
  33. package/dist/src/{serialize-typed-channel-map.js → events/channels/serialize-typed-channel-map.js} +2 -2
  34. package/dist/src/events/fetch/index.d.ts +2 -0
  35. package/dist/src/events/fetch/index.js +12 -0
  36. package/dist/src/events/functions/pikku-command-function-types.d.ts +2 -0
  37. package/dist/src/events/functions/pikku-command-function-types.js +13 -0
  38. package/dist/src/events/functions/pikku-command-functions.d.ts +6 -0
  39. package/dist/src/events/functions/pikku-command-functions.js +35 -0
  40. package/dist/src/events/functions/pikku-function-types.d.ts +2 -0
  41. package/dist/{bin → src/events/functions}/pikku-function-types.js +6 -6
  42. package/dist/src/events/functions/pikku-functions.d.ts +6 -0
  43. package/dist/{bin → src/events/functions}/pikku-functions.js +5 -5
  44. package/dist/src/events/http/pikku-command-http-map.d.ts +2 -0
  45. package/dist/src/events/http/pikku-command-http-map.js +8 -0
  46. package/dist/src/events/http/pikku-command-http-routes.d.ts +2 -0
  47. package/dist/src/events/http/pikku-command-http-routes.js +9 -0
  48. package/dist/src/events/http/pikku-command-nextjs.d.ts +2 -0
  49. package/dist/src/events/http/pikku-command-nextjs.js +36 -0
  50. package/dist/src/events/http/pikku-command-openapi.d.ts +2 -0
  51. package/dist/src/events/http/pikku-command-openapi.js +20 -0
  52. package/dist/src/events/http/pikku-http-routes.d.ts +2 -0
  53. package/dist/src/events/http/pikku-http-routes.js +9 -0
  54. package/dist/src/{serialize-typed-http-map.js → events/http/serialize-typed-http-map.js} +1 -1
  55. package/dist/src/events/mcp/pikku-command-mcp-json.d.ts +2 -0
  56. package/dist/src/events/mcp/pikku-command-mcp-json.js +13 -0
  57. package/dist/src/events/mcp/pikku-command-mcp.d.ts +2 -0
  58. package/dist/src/events/mcp/pikku-command-mcp.js +54 -0
  59. package/dist/src/events/mcp/serialize-mcp-json.d.ts +5 -0
  60. package/dist/src/events/mcp/serialize-mcp-json.js +101 -0
  61. package/dist/src/events/queue/pikku-command-queue-map.d.ts +2 -0
  62. package/dist/src/events/queue/pikku-command-queue-map.js +8 -0
  63. package/dist/src/events/queue/pikku-command-queue-service.d.ts +2 -0
  64. package/dist/src/events/queue/pikku-command-queue-service.js +12 -0
  65. package/dist/src/events/queue/pikku-command-queue.d.ts +2 -0
  66. package/dist/src/events/queue/pikku-command-queue.js +10 -0
  67. package/dist/src/events/queue/pikku-queue-map.d.ts +2 -0
  68. package/dist/src/events/queue/pikku-queue-map.js +8 -0
  69. package/dist/src/events/queue/pikku-queue.d.ts +2 -0
  70. package/dist/src/events/queue/pikku-queue.js +10 -0
  71. package/dist/src/events/queue/serialize-queue-map.d.ts +4 -0
  72. package/dist/src/events/queue/serialize-queue-map.js +77 -0
  73. package/dist/src/events/queue/serialize-queue-meta.d.ts +2 -0
  74. package/dist/src/events/queue/serialize-queue-meta.js +6 -0
  75. package/dist/src/events/queue/serialize-queue-wrapper.d.ts +1 -0
  76. package/dist/src/events/queue/serialize-queue-wrapper.js +35 -0
  77. package/dist/src/events/rpc/pikku-command-rpc-map.d.ts +2 -0
  78. package/dist/src/events/rpc/pikku-command-rpc-map.js +8 -0
  79. package/dist/src/events/rpc/pikku-command-rpc.d.ts +2 -0
  80. package/dist/src/events/rpc/pikku-command-rpc.js +6 -0
  81. package/dist/src/events/rpc/pikku-rpc.d.ts +2 -0
  82. package/dist/src/events/rpc/pikku-rpc.js +6 -0
  83. package/dist/src/{serialize-typed-rpc-map.d.ts → events/rpc/serialize-typed-rpc-map.d.ts} +1 -1
  84. package/dist/src/{serialize-typed-rpc-map.js → events/rpc/serialize-typed-rpc-map.js} +2 -2
  85. package/dist/src/events/scheduler/pikku-command-scheduler.d.ts +2 -0
  86. package/dist/src/events/scheduler/pikku-command-scheduler.js +10 -0
  87. package/dist/src/inspector-glob.d.ts +1 -1
  88. package/dist/src/inspector-glob.js +3 -3
  89. package/dist/src/pikku-cli-config.d.ts +8 -1
  90. package/dist/src/pikku-cli-config.js +59 -22
  91. package/dist/src/pikku-command-schemas.d.ts +2 -0
  92. package/dist/src/pikku-command-schemas.js +8 -0
  93. package/dist/src/runtimes/nextjs/pikku-command-nextjs.d.ts +2 -0
  94. package/dist/src/runtimes/nextjs/pikku-command-nextjs.js +36 -0
  95. package/dist/src/schema-generator.d.ts +3 -2
  96. package/dist/src/schema-generator.js +7 -7
  97. package/dist/src/schemas.d.ts +2 -0
  98. package/dist/src/schemas.js +8 -0
  99. package/dist/src/{utils/serialize-import-map.js → serialize-import-map.js} +3 -0
  100. package/dist/src/serialize-pikku-types.js +378 -1
  101. package/dist/src/types.d.ts +5 -0
  102. package/dist/src/types.js +1 -0
  103. package/dist/src/{utils/utils.d.ts → utils.d.ts} +17 -7
  104. package/dist/src/{utils/utils.js → utils.js} +47 -29
  105. package/dist/tsconfig.tsbuildinfo +1 -1
  106. package/package.json +3 -3
  107. package/{bin → src/events/channels}/pikku-channels.ts +8 -3
  108. package/src/events/channels/pikku-command-channels-map.ts +26 -0
  109. package/src/events/channels/pikku-command-channels.ts +38 -0
  110. package/src/events/channels/pikku-command-websocket-typed.ts +36 -0
  111. package/src/{serialize-typed-channel-map.ts → events/channels/serialize-typed-channel-map.ts} +2 -2
  112. package/src/events/fetch/index.ts +33 -0
  113. package/src/events/functions/pikku-command-function-types.ts +48 -0
  114. package/src/events/functions/pikku-command-functions.ts +84 -0
  115. package/{bin → src/events/functions}/pikku-function-types.ts +12 -15
  116. package/{bin → src/events/functions}/pikku-functions.ts +9 -6
  117. package/src/events/http/pikku-command-http-map.ts +27 -0
  118. package/src/events/http/pikku-command-http-routes.ts +40 -0
  119. package/src/events/http/pikku-command-nextjs.ts +111 -0
  120. package/src/events/http/pikku-command-openapi.ts +54 -0
  121. package/{bin → src/events/http}/pikku-http-routes.ts +8 -3
  122. package/src/{serialize-typed-http-map.ts → events/http/serialize-typed-http-map.ts} +1 -1
  123. package/src/events/mcp/pikku-command-mcp-json.ts +33 -0
  124. package/src/events/mcp/pikku-command-mcp.ts +110 -0
  125. package/src/events/mcp/serialize-mcp-json.ts +159 -0
  126. package/src/events/queue/pikku-command-queue-map.ts +26 -0
  127. package/src/events/queue/pikku-command-queue-service.ts +33 -0
  128. package/src/events/queue/pikku-command-queue.ts +42 -0
  129. package/src/events/queue/pikku-queue-map.ts +26 -0
  130. package/src/events/queue/pikku-queue.ts +40 -0
  131. package/src/events/queue/serialize-queue-map.ts +119 -0
  132. package/src/events/queue/serialize-queue-meta.ts +10 -0
  133. package/src/events/queue/serialize-queue-wrapper.ts +35 -0
  134. package/src/events/rpc/pikku-command-rpc-map.ts +26 -0
  135. package/src/events/rpc/pikku-command-rpc.ts +22 -0
  136. package/{bin → src/events/rpc}/pikku-rpc.ts +8 -6
  137. package/src/{serialize-typed-rpc-map.ts → events/rpc/serialize-typed-rpc-map.ts} +4 -3
  138. package/{bin/pikku-scheduler.ts → src/events/scheduler/pikku-command-scheduler.ts} +11 -8
  139. package/src/inspector-glob.ts +3 -1
  140. package/src/pikku-cli-config.ts +93 -32
  141. package/src/pikku-command-schemas.ts +33 -0
  142. package/src/runtimes/nextjs/pikku-command-nextjs.ts +110 -0
  143. package/src/schema-generator.ts +8 -3
  144. package/src/schemas.ts +33 -0
  145. package/src/{utils/serialize-import-map.ts → serialize-import-map.ts} +5 -0
  146. package/src/serialize-pikku-types.ts +378 -1
  147. package/src/types.ts +16 -0
  148. package/src/{utils/utils.ts → utils.ts} +55 -31
  149. package/tsconfig.json +1 -1
  150. package/bin/pikku-channels-map.ts +0 -25
  151. package/bin/pikku-http-map.ts +0 -26
  152. package/bin/pikku-nextjs.test.ts +0 -279
  153. package/bin/pikku-rpc-map.ts +0 -25
  154. package/dist/bin/pikku-channels-map.d.ts +0 -3
  155. package/dist/bin/pikku-channels-map.js +0 -8
  156. package/dist/bin/pikku-channels.d.ts +0 -3
  157. package/dist/bin/pikku-channels.js +0 -9
  158. package/dist/bin/pikku-function-types.d.ts +0 -4
  159. package/dist/bin/pikku-functions.d.ts +0 -7
  160. package/dist/bin/pikku-http-map.d.ts +0 -3
  161. package/dist/bin/pikku-http-map.js +0 -8
  162. package/dist/bin/pikku-http-routes.d.ts +0 -3
  163. package/dist/bin/pikku-http-routes.js +0 -9
  164. package/dist/bin/pikku-rpc-map.d.ts +0 -3
  165. package/dist/bin/pikku-rpc-map.js +0 -8
  166. package/dist/bin/pikku-rpc.d.ts +0 -3
  167. package/dist/bin/pikku-rpc.js +0 -6
  168. package/dist/bin/pikku-scheduler.d.ts +0 -3
  169. package/dist/bin/pikku-scheduler.js +0 -10
  170. /package/dist/src/{serialize-typed-channel-map.d.ts → events/channels/serialize-typed-channel-map.d.ts} +0 -0
  171. /package/dist/src/{serialize-websocket-wrapper.d.ts → events/channels/serialize-websocket-wrapper.d.ts} +0 -0
  172. /package/dist/src/{serialize-websocket-wrapper.js → events/channels/serialize-websocket-wrapper.js} +0 -0
  173. /package/dist/src/{openapi-spec-generator.d.ts → events/http/openapi-spec-generator.d.ts} +0 -0
  174. /package/dist/src/{openapi-spec-generator.js → events/http/openapi-spec-generator.js} +0 -0
  175. /package/dist/src/{serialize-fetch-wrapper.d.ts → events/http/serialize-fetch-wrapper.d.ts} +0 -0
  176. /package/dist/src/{serialize-fetch-wrapper.js → events/http/serialize-fetch-wrapper.js} +0 -0
  177. /package/dist/src/{serialize-typed-http-map.d.ts → events/http/serialize-typed-http-map.d.ts} +0 -0
  178. /package/dist/src/{serialize-scheduler-meta.d.ts → events/scheduler/serialize-scheduler-meta.d.ts} +0 -0
  179. /package/dist/src/{serialize-scheduler-meta.js → events/scheduler/serialize-scheduler-meta.js} +0 -0
  180. /package/dist/src/{serialize-nextjs-backend-wrapper.d.ts → runtimes/nextjs/serialize-nextjs-backend-wrapper.d.ts} +0 -0
  181. /package/dist/src/{serialize-nextjs-backend-wrapper.js → runtimes/nextjs/serialize-nextjs-backend-wrapper.js} +0 -0
  182. /package/dist/src/{serialize-nextjs-http-wrapper.d.ts → runtimes/nextjs/serialize-nextjs-http-wrapper.d.ts} +0 -0
  183. /package/dist/src/{serialize-nextjs-http-wrapper.js → runtimes/nextjs/serialize-nextjs-http-wrapper.js} +0 -0
  184. /package/dist/src/{utils/serialize-import-map.d.ts → serialize-import-map.d.ts} +0 -0
  185. /package/src/{serialize-websocket-wrapper.ts → events/channels/serialize-websocket-wrapper.ts} +0 -0
  186. /package/src/{openapi-spec-generator.ts → events/http/openapi-spec-generator.ts} +0 -0
  187. /package/src/{serialize-fetch-wrapper.ts → events/http/serialize-fetch-wrapper.ts} +0 -0
  188. /package/src/{serialize-scheduler-meta.ts → events/scheduler/serialize-scheduler-meta.ts} +0 -0
  189. /package/src/{serialize-nextjs-backend-wrapper.ts → runtimes/nextjs/serialize-nextjs-backend-wrapper.ts} +0 -0
  190. /package/src/{serialize-nextjs-http-wrapper.ts → runtimes/nextjs/serialize-nextjs-http-wrapper.ts} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { HTTPRoutesMeta } from '@pikku/core/http'
2
- import { serializeImportMap } from './utils/serialize-import-map.js'
2
+ import { serializeImportMap } from '../../serialize-import-map.js'
3
3
  import { MetaInputTypes, TypesMap } from '@pikku/inspector'
4
4
  import { FunctionsMeta } from '@pikku/core'
5
5
 
@@ -0,0 +1,33 @@
1
+ import { logCommandInfoAndTime, writeFileInDir } from '../../utils.js'
2
+ import { serializeMCPJson } from './serialize-mcp-json.js'
3
+ import { PikkuCommand } from '../../types.js'
4
+
5
+ export const pikkuMCPJSON: PikkuCommand = async (
6
+ logger,
7
+ { mcpJsonFile, schemaDirectory },
8
+ { mcpEndpoints, functions }
9
+ ) => {
10
+ return await logCommandInfoAndTime(
11
+ logger,
12
+ 'Generating MCP JSON',
13
+ 'Generated MCP JSON',
14
+ [mcpEndpoints.files.size === 0 || !mcpJsonFile],
15
+ async () => {
16
+ // Generate MCP JSON file
17
+ if (mcpJsonFile) {
18
+ const mcpJson = await serializeMCPJson(
19
+ logger,
20
+ schemaDirectory,
21
+ functions.meta,
22
+ functions.typesMap,
23
+ mcpEndpoints.resourcesMeta,
24
+ mcpEndpoints.toolsMeta,
25
+ mcpEndpoints.promptsMeta
26
+ )
27
+ await writeFileInDir(logger, mcpJsonFile, mcpJson, {
28
+ ignoreModifyComment: true,
29
+ })
30
+ }
31
+ }
32
+ )
33
+ }
@@ -0,0 +1,110 @@
1
+ import {
2
+ logCommandInfoAndTime,
3
+ serializeFileImports,
4
+ writeFileInDir,
5
+ } from '../../utils.js'
6
+ import { PikkuCommand } from '../../types.js'
7
+ import { readFile } from 'fs/promises'
8
+ import { join } from 'path'
9
+
10
+ // Helper function to generate arguments from schema
11
+ const generateArgumentsFromSchema = async (
12
+ inputSchema: string | null,
13
+ schemaDirectory: string,
14
+ typesMap: any,
15
+ logger: any
16
+ ): Promise<Array<{ name: string; description: string; required: boolean }>> => {
17
+ if (!inputSchema) return []
18
+
19
+ if (
20
+ ['boolean', 'string', 'number', 'null', 'undefined', 'void'].includes(
21
+ inputSchema
22
+ )
23
+ ) {
24
+ return []
25
+ }
26
+
27
+ const uniqueName = typesMap.getUniqueName(inputSchema)
28
+ if (!uniqueName) return []
29
+
30
+ try {
31
+ const schemaPath = join(
32
+ schemaDirectory,
33
+ 'schemas',
34
+ `${uniqueName}.schema.json`
35
+ )
36
+ const schemaContent = await readFile(schemaPath, 'utf-8')
37
+ const schema = JSON.parse(schemaContent)
38
+
39
+ const argumentsArray: Array<{
40
+ name: string
41
+ description: string
42
+ required: boolean
43
+ }> = []
44
+ if (schema && typeof schema === 'object' && schema.properties) {
45
+ const properties = schema.properties as Record<string, any>
46
+ const required = (schema.required as string[]) || []
47
+
48
+ for (const [propName, propSchema] of Object.entries(properties)) {
49
+ argumentsArray.push({
50
+ name: propName,
51
+ description: propSchema.description || `${propName} parameter`,
52
+ required: required.includes(propName),
53
+ })
54
+ }
55
+ }
56
+ return argumentsArray
57
+ } catch (e) {
58
+ logger.warn(`Could not load schema for type: ${uniqueName}`)
59
+ return []
60
+ }
61
+ }
62
+
63
+ export const pikkuMCP: PikkuCommand = async (
64
+ logger,
65
+ { mcpEndpointsFile, mcpEndpointsMetaFile, packageMappings, schemaDirectory },
66
+ { mcpEndpoints, functions }
67
+ ) => {
68
+ return await logCommandInfoAndTime(
69
+ logger,
70
+ 'Finding MCP endpoints',
71
+ 'Found MCP endpoints',
72
+ [mcpEndpoints.files.size === 0],
73
+ async () => {
74
+ await writeFileInDir(
75
+ logger,
76
+ mcpEndpointsFile,
77
+ serializeFileImports(
78
+ 'addMCPResource or addMCPTool',
79
+ mcpEndpointsFile,
80
+ mcpEndpoints.files,
81
+ packageMappings
82
+ )
83
+ )
84
+
85
+ // Populate arguments for prompts meta before serializing
86
+ const promptsMetaWithArguments = { ...mcpEndpoints.promptsMeta }
87
+ for (const promptMeta of Object.values(promptsMetaWithArguments)) {
88
+ const functionMeta = functions.meta[promptMeta.pikkuFuncName]
89
+ if (functionMeta) {
90
+ const inputType = functionMeta.inputs?.[0]
91
+ promptMeta.arguments = await generateArgumentsFromSchema(
92
+ inputType || null,
93
+ schemaDirectory || '',
94
+ functions.typesMap,
95
+ logger
96
+ )
97
+ }
98
+ }
99
+
100
+ await writeFileInDir(
101
+ logger,
102
+ mcpEndpointsMetaFile,
103
+ `import { pikkuState } from '@pikku/core'
104
+ pikkuState('mcp', 'resourcesMeta', ${JSON.stringify(mcpEndpoints.resourcesMeta, null, 2)})
105
+ pikkuState('mcp', 'toolsMeta', ${JSON.stringify(mcpEndpoints.toolsMeta, null, 2)})
106
+ pikkuState('mcp', 'promptsMeta', ${JSON.stringify(promptsMetaWithArguments, null, 2)})`
107
+ )
108
+ }
109
+ )
110
+ }
@@ -0,0 +1,159 @@
1
+ import { readFile } from 'fs/promises'
2
+ import { join } from 'path'
3
+ import { MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from '@pikku/core'
4
+ import { FunctionsMeta, JSONValue } from '@pikku/core'
5
+ import { TypesMap } from '@pikku/inspector'
6
+ import { CLILogger } from '../../utils.js'
7
+
8
+ interface MCPEndpoint {
9
+ name: string
10
+ description?: string
11
+ parameters?: JSONValue
12
+ returns?: JSONValue
13
+ streaming?: boolean
14
+ }
15
+
16
+ export const serializeMCPJson = async (
17
+ logger: CLILogger,
18
+ schemaDirectory: string,
19
+ functionsMeta: FunctionsMeta,
20
+ typesMap: TypesMap,
21
+ mcpResourceMeta: MCPResourceMeta,
22
+ mcpToolMeta: MCPToolMeta,
23
+ mcpPromptMeta: MCPPromptMeta
24
+ ): Promise<string> => {
25
+ const tools: MCPEndpoint[] = []
26
+ const resources: MCPEndpoint[] = []
27
+ const prompts: any[] = []
28
+
29
+ // Helper function to load schema from file
30
+ const loadSchema = async (
31
+ typeName: string | undefined
32
+ ): Promise<JSONValue | undefined> => {
33
+ if (
34
+ !typeName ||
35
+ ['boolean', 'string', 'number', 'null', 'undefined', 'void'].includes(
36
+ typeName
37
+ )
38
+ ) {
39
+ return undefined
40
+ }
41
+
42
+ const uniqueName = typesMap.getUniqueName(typeName)
43
+ if (!uniqueName) {
44
+ return undefined
45
+ }
46
+
47
+ try {
48
+ const schemaPath = join(
49
+ schemaDirectory,
50
+ 'schemas',
51
+ `${uniqueName}.schema.json`
52
+ )
53
+ const schemaContent = await readFile(schemaPath, 'utf-8')
54
+ return JSON.parse(schemaContent)
55
+ } catch (e) {
56
+ logger.warn(`Could not load schema for type: ${uniqueName}`)
57
+ return undefined
58
+ }
59
+ }
60
+
61
+ // Process MCP resources
62
+ for (const [name, endpointMeta] of Object.entries(mcpResourceMeta)) {
63
+ const functionMeta = functionsMeta[endpointMeta.pikkuFuncName]
64
+ if (!functionMeta) {
65
+ logger.warn(
66
+ `Function ${endpointMeta.pikkuFuncName} not found in functionsMeta. Skipping resource ${name}.`
67
+ )
68
+ continue
69
+ }
70
+
71
+ const inputType = functionMeta.inputs?.[0]
72
+ const outputType = functionMeta.outputs?.[0]
73
+
74
+ const parameters = await loadSchema(inputType)
75
+ const returns = await loadSchema(outputType)
76
+
77
+ const endpoint = {
78
+ uri: name,
79
+ name,
80
+ description: endpointMeta.description,
81
+ ...(parameters && { parameters }),
82
+ ...(returns && { returns }),
83
+ ...(endpointMeta.streaming && { streaming: true }),
84
+ }
85
+
86
+ resources.push(endpoint)
87
+ }
88
+
89
+ // Process MCP tools
90
+ for (const [name, endpointMeta] of Object.entries(mcpToolMeta)) {
91
+ const functionMeta = functionsMeta[endpointMeta.pikkuFuncName]
92
+ if (!functionMeta) {
93
+ logger.warn(
94
+ `Function ${endpointMeta.pikkuFuncName} not found in functionsMeta. Skipping tool ${name}.`
95
+ )
96
+ continue
97
+ }
98
+
99
+ const inputType = functionMeta.inputs?.[0]
100
+ const outputType = functionMeta.outputs?.[0]
101
+
102
+ const parameters = await loadSchema(inputType)
103
+ const returns = await loadSchema(outputType)
104
+
105
+ const endpoint = {
106
+ name,
107
+ description: endpointMeta.description,
108
+ ...(parameters && { parameters }),
109
+ ...(returns && { returns }),
110
+ ...(endpointMeta.streaming && { streaming: true }),
111
+ }
112
+
113
+ tools.push(endpoint)
114
+ }
115
+
116
+ // Process MCP prompts
117
+ for (const [name, endpointMeta] of Object.entries(mcpPromptMeta)) {
118
+ const functionMeta = functionsMeta[endpointMeta.pikkuFuncName]
119
+ if (!functionMeta) {
120
+ logger.warn(
121
+ `Function ${endpointMeta.pikkuFuncName} not found in functionsMeta. Skipping prompt ${name}.`
122
+ )
123
+ continue
124
+ }
125
+
126
+ const inputType = functionMeta.inputs?.[0]
127
+ // TODO: this needs to be a json schema type, not any
128
+ const inputSchema: any = await loadSchema(inputType)
129
+
130
+ // Generate arguments from input schema
131
+ const argumentsArray: any[] = []
132
+ if (
133
+ inputSchema &&
134
+ typeof inputSchema === 'object' &&
135
+ inputSchema.properties
136
+ ) {
137
+ const properties = inputSchema.properties as Record<string, any>
138
+ const required = (inputSchema.required as string[]) || []
139
+
140
+ for (const [propName, propSchema] of Object.entries(properties)) {
141
+ argumentsArray.push({
142
+ name: propName,
143
+ description: propSchema.description || `${propName} parameter`,
144
+ required: required.includes(propName),
145
+ })
146
+ }
147
+ }
148
+
149
+ const prompt = {
150
+ name,
151
+ description: endpointMeta.description,
152
+ arguments: argumentsArray,
153
+ }
154
+
155
+ prompts.push(prompt)
156
+ }
157
+
158
+ return JSON.stringify({ tools, resources, prompts }, null, 2)
159
+ }
@@ -0,0 +1,26 @@
1
+ import { logCommandInfoAndTime, writeFileInDir } from '../../utils.js'
2
+ import { serializeQueueMap } from './serialize-queue-map.js'
3
+ import { PikkuCommand } from '../../types.js'
4
+
5
+ export const pikkuQueueMap: PikkuCommand = async (
6
+ logger,
7
+ { queueMapDeclarationFile, packageMappings },
8
+ { queueWorkers, functions }
9
+ ) => {
10
+ return await logCommandInfoAndTime(
11
+ logger,
12
+ 'Creating Queue map',
13
+ 'Created Queue map',
14
+ [queueWorkers.files.size === 0],
15
+ async () => {
16
+ const content = serializeQueueMap(
17
+ queueMapDeclarationFile,
18
+ packageMappings,
19
+ functions.typesMap,
20
+ functions.meta,
21
+ queueWorkers.meta
22
+ )
23
+ await writeFileInDir(logger, queueMapDeclarationFile, content)
24
+ }
25
+ )
26
+ }
@@ -0,0 +1,33 @@
1
+ import { serializeQueueWrapper } from './serialize-queue-wrapper.js'
2
+ import {
3
+ getFileImportRelativePath,
4
+ logCommandInfoAndTime,
5
+ writeFileInDir,
6
+ } from '../../utils.js'
7
+ import { PikkuCommandWithoutState } from '../../types.js'
8
+
9
+ export const pikkuQueueService: PikkuCommandWithoutState = async (
10
+ logger,
11
+ { queueFile, queueMapDeclarationFile, packageMappings }
12
+ ) => {
13
+ return await logCommandInfoAndTime(
14
+ logger,
15
+ 'Generating queue service wrapper',
16
+ 'Generated queue service wrapper',
17
+ [queueFile === undefined, "queueFile isn't set in the pikku config"],
18
+ async () => {
19
+ if (!queueFile) {
20
+ throw new Error("queueFile is isn't set in the pikku config")
21
+ }
22
+
23
+ const queueMapDeclarationPath = getFileImportRelativePath(
24
+ queueFile,
25
+ queueMapDeclarationFile,
26
+ packageMappings
27
+ )
28
+
29
+ const content = [serializeQueueWrapper(queueMapDeclarationPath)]
30
+ await writeFileInDir(logger, queueFile, content.join('\n'))
31
+ }
32
+ )
33
+ }
@@ -0,0 +1,42 @@
1
+ import { PikkuCLIConfig } from '../../pikku-cli-config.js'
2
+ import { InspectorState } from '@pikku/inspector'
3
+ import {
4
+ logCommandInfoAndTime,
5
+ serializeFileImports,
6
+ writeFileInDir,
7
+ } from '../../utils.js'
8
+ import { serializeQueueMeta } from './serialize-queue-meta.js'
9
+ import { PikkuCommand } from '../../types.js'
10
+
11
+ export const pikkuQueue: PikkuCommand = async (
12
+ logger,
13
+ cliConfig: PikkuCLIConfig,
14
+ visitState: InspectorState
15
+ ) => {
16
+ return await logCommandInfoAndTime(
17
+ logger,
18
+ 'Finding queues',
19
+ 'Found queue',
20
+ [visitState.queueWorkers.files.size === 0],
21
+ async () => {
22
+ const { queueWorkersFile, queueWorkersMetaFile, packageMappings } =
23
+ cliConfig
24
+ const { queueWorkers } = visitState
25
+ await writeFileInDir(
26
+ logger,
27
+ queueWorkersMetaFile,
28
+ serializeQueueMeta(queueWorkers.meta)
29
+ )
30
+ await writeFileInDir(
31
+ logger,
32
+ queueWorkersFile,
33
+ serializeFileImports(
34
+ 'addQueueWorkers',
35
+ queueWorkersFile,
36
+ queueWorkers.files,
37
+ packageMappings
38
+ )
39
+ )
40
+ }
41
+ )
42
+ }
@@ -0,0 +1,26 @@
1
+ import { logCommandInfoAndTime, writeFileInDir } from '../../utils.js'
2
+ import { serializeQueueMap } from './serialize-queue-map.js'
3
+ import { PikkuCommand } from '../../types.js'
4
+
5
+ export const pikkuQueueMap: PikkuCommand = async (
6
+ logger,
7
+ { queueMapDeclarationFile, packageMappings },
8
+ { queueWorkers, functions }
9
+ ) => {
10
+ return await logCommandInfoAndTime(
11
+ logger,
12
+ 'Creating Queue map',
13
+ 'Created Queue map',
14
+ [queueWorkers.files.size === 0],
15
+ async () => {
16
+ const content = serializeQueueMap(
17
+ queueMapDeclarationFile,
18
+ packageMappings,
19
+ functions.typesMap,
20
+ functions.meta,
21
+ queueWorkers.meta
22
+ )
23
+ await writeFileInDir(logger, queueMapDeclarationFile, content)
24
+ }
25
+ )
26
+ }
@@ -0,0 +1,40 @@
1
+ import {
2
+ logCommandInfoAndTime,
3
+ serializeFileImports,
4
+ writeFileInDir,
5
+ } from '../../utils.js'
6
+ import { serializeQueueMeta } from './serialize-queue-meta.js'
7
+ import { PikkuCommand } from '../../types.js'
8
+
9
+ export const pikkuQueue: PikkuCommand = async (
10
+ logger,
11
+ cliConfig,
12
+ visitState
13
+ ) => {
14
+ return await logCommandInfoAndTime(
15
+ logger,
16
+ 'Finding queues',
17
+ 'Found queue',
18
+ [visitState.queueWorkers.files.size === 0],
19
+ async () => {
20
+ const { queueWorkersFile, queueWorkersMetaFile, packageMappings } =
21
+ cliConfig
22
+ const { queueWorkers } = visitState
23
+ await writeFileInDir(
24
+ logger,
25
+ queueWorkersMetaFile,
26
+ serializeQueueMeta(queueWorkers.meta)
27
+ )
28
+ await writeFileInDir(
29
+ logger,
30
+ queueWorkersFile,
31
+ serializeFileImports(
32
+ 'addQueueWorkers',
33
+ queueWorkersFile,
34
+ queueWorkers.files,
35
+ packageMappings
36
+ )
37
+ )
38
+ }
39
+ )
40
+ }
@@ -0,0 +1,119 @@
1
+ import type { queueWorkersMeta } from '@pikku/core/queue'
2
+ import { serializeImportMap } from '../../serialize-import-map.js'
3
+ import { TypesMap } from '@pikku/inspector'
4
+ import { FunctionsMeta } from '@pikku/core'
5
+ import { generateCustomTypes } from '../../utils.js'
6
+
7
+ export const serializeQueueMap = (
8
+ relativeToPath: string,
9
+ packageMappings: Record<string, string>,
10
+ typesMap: TypesMap,
11
+ functionsMeta: FunctionsMeta,
12
+ queueWorkersMeta: queueWorkersMeta
13
+ ) => {
14
+ const requiredTypes = new Set<string>()
15
+ const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes)
16
+ const serializedQueues = generateQueues(
17
+ queueWorkersMeta,
18
+ functionsMeta,
19
+ typesMap,
20
+ requiredTypes
21
+ )
22
+
23
+ const serializedImportMap = serializeImportMap(
24
+ relativeToPath,
25
+ packageMappings,
26
+ typesMap,
27
+ requiredTypes
28
+ )
29
+
30
+ return `/**
31
+ * This provides the structure needed for typescript to be aware of Queue workers and their input/output types
32
+ */
33
+
34
+ ${serializedImportMap}
35
+ ${serializedCustomTypes}
36
+
37
+ import type { QueueJob } from '@pikku/core/queue'
38
+
39
+ interface QueueHandler<I, O> {
40
+ input: I;
41
+ output: O;
42
+ }
43
+
44
+ ${serializedQueues}
45
+
46
+ type QueueAdd = <Name extends keyof QueueMap>(
47
+ name: Name,
48
+ data: QueueMap[Name]['input'],
49
+ options?: {
50
+ priority?: number
51
+ delay?: number
52
+ attempts?: number
53
+ removeOnComplete?: number
54
+ removeOnFail?: number
55
+ jobId?: string
56
+ }
57
+ ) => Promise<string>
58
+
59
+ type QueueGetJob = <Name extends keyof QueueMap>(
60
+ name: Name,
61
+ jobId: string
62
+ ) => Promise<QueueJob<QueueMap[Name]['input'], QueueMap[Name]['output']> | null>
63
+
64
+ export type TypedPikkuQueue = {
65
+ add: QueueAdd;
66
+ getJob: QueueGetJob;
67
+ }
68
+ `
69
+ }
70
+
71
+ function generateQueues(
72
+ queueWorkersMeta: queueWorkersMeta,
73
+ functionsMeta: FunctionsMeta,
74
+ typesMap: TypesMap,
75
+ requiredTypes: Set<string>
76
+ ) {
77
+ // Initialize an object to collect queues
78
+ const queuesObj: Record<string, { inputType: string; outputType: string }> =
79
+ {}
80
+
81
+ // Iterate through Queue metadata
82
+ for (const [queueName, { pikkuFuncName }] of Object.entries(
83
+ queueWorkersMeta
84
+ )) {
85
+ const functionMeta = functionsMeta[pikkuFuncName]
86
+ if (!functionMeta) {
87
+ throw new Error(
88
+ `Function ${queueName} not found in functionsMeta. Please check your configuration.`
89
+ )
90
+ }
91
+
92
+ const input = functionMeta.inputs ? functionMeta.inputs[0] : undefined
93
+ const output = functionMeta.outputs ? functionMeta.outputs[0] : undefined
94
+
95
+ // Store the input and output types for QueueHandler
96
+ const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null'
97
+ const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null'
98
+
99
+ requiredTypes.add(inputType)
100
+ requiredTypes.add(outputType)
101
+
102
+ // Add Queue entry
103
+ queuesObj[queueName] = {
104
+ inputType,
105
+ outputType,
106
+ }
107
+ }
108
+
109
+ // Build the Queues object as a string
110
+ let queuesStr = 'export type QueueMap = {\n'
111
+
112
+ for (const [queueName, handler] of Object.entries(queuesObj)) {
113
+ queuesStr += ` readonly '${queueName}': QueueHandler<${handler.inputType}, ${handler.outputType}>,\n`
114
+ }
115
+
116
+ queuesStr += '};\n'
117
+
118
+ return queuesStr
119
+ }
@@ -0,0 +1,10 @@
1
+ import { queueWorkersMeta } from '@pikku/core'
2
+
3
+ export const serializeQueueMeta = (queueWorkersMeta: queueWorkersMeta) => {
4
+ const serializedOutput: string[] = []
5
+ serializedOutput.push("import { pikkuState } from '@pikku/core'")
6
+ serializedOutput.push(
7
+ `pikkuState('queue', 'meta', ${JSON.stringify(queueWorkersMeta, null, 2)})`
8
+ )
9
+ return serializedOutput.join('\n')
10
+ }
@@ -0,0 +1,35 @@
1
+ export const serializeQueueWrapper = (queueMapPath: string) => {
2
+ return `
3
+ import type { QueueService, QueueJob } from '@pikku/core/queue'
4
+ import type { QueueMap, TypedPikkuQueue } from '${queueMapPath}'
5
+
6
+ export class PikkuQueue implements TypedPikkuQueue {
7
+ constructor(private queueService: QueueService) {}
8
+
9
+ public async add<Name extends keyof QueueMap>(
10
+ queueName: Name,
11
+ data: QueueMap[Name]['input'],
12
+ options?: {
13
+ priority?: number
14
+ delay?: number
15
+ attempts?: number
16
+ removeOnComplete?: number
17
+ removeOnFail?: number
18
+ jobId?: string
19
+ }
20
+ ): Promise<string> {
21
+ return this.queueService.add(queueName as string, data, options);
22
+ }
23
+
24
+ public async getJob<Name extends keyof QueueMap>(
25
+ queueName: Name,
26
+ jobId: string
27
+ ): Promise<QueueJob<QueueMap[Name]['input'], QueueMap[Name]['output']> | null> {
28
+ return this.queueService.getJob<QueueMap[Name]['input'], QueueMap[Name]['output']>(
29
+ queueName as string,
30
+ jobId
31
+ );
32
+ }
33
+ }
34
+ `
35
+ }
@@ -0,0 +1,26 @@
1
+ import { logCommandInfoAndTime, writeFileInDir } from '../../utils.js'
2
+ import { serializeTypedRPCMap } from './serialize-typed-rpc-map.js'
3
+ import { PikkuCommand } from '../../types.js'
4
+
5
+ export const pikkuRPCMap: PikkuCommand = async (
6
+ logger,
7
+ { rpcMapDeclarationFile, packageMappings },
8
+ { functions, rpc }
9
+ ) => {
10
+ return await logCommandInfoAndTime(
11
+ logger,
12
+ 'Creating RPC map',
13
+ 'Created RPC map',
14
+ [false],
15
+ async () => {
16
+ const content = serializeTypedRPCMap(
17
+ rpcMapDeclarationFile,
18
+ packageMappings,
19
+ functions.typesMap,
20
+ functions.meta,
21
+ rpc.meta
22
+ )
23
+ await writeFileInDir(logger, rpcMapDeclarationFile, content)
24
+ }
25
+ )
26
+ }
@@ -0,0 +1,22 @@
1
+ import { logCommandInfoAndTime, writeFileInDir } from '../../utils.js'
2
+ import { PikkuCommand } from '../../types.js'
3
+
4
+ export const pikkuRPC: PikkuCommand = async (
5
+ logger,
6
+ { rpcMetaFile },
7
+ { rpc }
8
+ ) => {
9
+ return await logCommandInfoAndTime(
10
+ logger,
11
+ 'Finding RPCs tasks',
12
+ 'Found RPCs',
13
+ [false],
14
+ async () => {
15
+ await writeFileInDir(
16
+ logger,
17
+ rpcMetaFile,
18
+ `import { pikkuState } from '@pikku/core'\npikkuState('rpc', 'meta', ${JSON.stringify(rpc.meta, null, 2)})`
19
+ )
20
+ }
21
+ )
22
+ }