@aprovan/patchwork-utcp 0.1.0-dev.3afec03 → 0.1.0-dev.4d82df8

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.
@@ -10,13 +10,13 @@
10
10
  CLI Cleaning output folder
11
11
  ESM Build start
12
12
  CJS Build start
13
- ESM dist/index.js 1.87 KB
14
- ESM dist/index.js.map 5.65 KB
15
- ESM ⚡️ Build success in 59ms
16
13
  CJS dist/index.cjs 2.90 KB
17
14
  CJS dist/index.cjs.map 5.67 KB
18
- CJS ⚡️ Build success in 59ms
15
+ CJS ⚡️ Build success in 57ms
16
+ ESM dist/index.js 1.87 KB
17
+ ESM dist/index.js.map 5.65 KB
18
+ ESM ⚡️ Build success in 57ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 2192ms
20
+ DTS ⚡️ Build success in 3957ms
21
21
  DTS dist/index.d.ts 1.48 KB
22
22
  DTS dist/index.d.cts 1.48 KB
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @aprovan/patchwork-utcp\n *\n * UTCP backend integration for Patchwork.\n * Provides a ServiceBackend implementation that routes service calls through UTCP.\n */\n\nimport '@utcp/http';\nimport '@utcp/text';\nimport '@utcp/mcp';\n\nimport {\n UtcpClient,\n ensureCorePluginsInitialized,\n UtcpClientConfigSerializer,\n UtcpClientConfig,\n} from '@utcp/sdk';\n\nimport type { ServiceBackend } from '@aprovan/patchwork';\n\n// Ensure plugins are loaded\nensureCorePluginsInitialized();\n\n/**\n * Sanitize a string for use as a JavaScript identifier\n */\nfunction sanitizeIdentifier(s: string): string {\n return s.replace(/[^a-zA-Z0-9_]/g, '_').replace(/^[0-9]/, '_$&');\n}\n\n/**\n * Create a UTCP-backed ServiceBackend for patchwork\n *\n * This is the integration point between UTCP and patchwork's service system.\n * Widgets call `github.repos_list_for_user()` → patchwork routes to this backend → UTCP executes.\n *\n * @example\n * ```typescript\n * import { createUtcpBackend } from '@aprovan/patchwork-utcp';\n * import { setServiceBackend } from '@aprovan/patchwork';\n *\n * const { backend, client } = await createUtcpBackend({\n * cwd: __dirname,\n * manual_call_templates: [{\n * name: 'github',\n * call_template_type: 'http',\n * url: 'https://raw.githubusercontent.com/.../api.github.com.json',\n * http_method: 'GET',\n * }],\n * });\n *\n * setServiceBackend(backend);\n *\n * // ... run widgets ...\n *\n * await client.close();\n * ```\n */\nexport async function createUtcpBackend(\n utcpOptions: UtcpClientConfig,\n cwd?: string,\n): Promise<{\n backend: ServiceBackend;\n client: UtcpClient;\n toolInfos: Array<{\n name: string;\n namespace: string;\n procedure: string;\n description?: string;\n parameters?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }>;\n}> {\n const utcpConfig = new UtcpClientConfigSerializer().validateDict(\n utcpOptions as unknown as Record<string, unknown>,\n );\n const client = await UtcpClient.create(cwd ?? process.cwd(), utcpConfig);\n\n // Build tool registry from discovered UTCP tools\n const toolRegistry = new Map<\n string,\n (args: Record<string, unknown>) => Promise<unknown>\n >();\n const toolInfos: Array<{\n name: string;\n namespace: string;\n procedure: string;\n description?: string;\n parameters?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }> = [];\n\n // Access internal getTools method - Tool has name, description, inputs, outputs, tags\n const tools = await (\n client as {\n getTools(): Promise<\n Array<{\n name: string;\n description?: string;\n inputs?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }>\n >;\n }\n )['getTools']();\n\n for (const tool of tools) {\n if (!tool.name.includes('.')) continue;\n\n const [namespace, ...parts] = tool.name.split('.');\n const sanitizedNamespace = sanitizeIdentifier(namespace!);\n let procedure = parts.map(sanitizeIdentifier).join('_');\n\n // Strip duplicate namespace prefix from procedure names\n // e.g., \"weather_get_forecast\" -> \"get_forecast\" when namespace is \"weather\"\n const namespacePrefix = `${sanitizedNamespace}_`;\n if (procedure.startsWith(namespacePrefix)) {\n procedure = procedure.slice(namespacePrefix.length);\n }\n\n const key = `${sanitizedNamespace}.${procedure}`;\n\n toolRegistry.set(key, client.callTool.bind(client, tool.name));\n\n toolInfos.push({\n name: key,\n namespace: sanitizedNamespace,\n procedure,\n description: tool.description,\n parameters: tool.inputs,\n outputs: tool.outputs,\n });\n }\n\n const backend: ServiceBackend = {\n call: async (service: string, procedure: string, args: unknown[]) => {\n const key = `${service}.${procedure}`;\n const toolFn = toolRegistry.get(key);\n\n if (!toolFn) {\n throw new Error(\n `UTCP tool not found: ${key}. Available tools: ${Array.from(\n toolRegistry.keys(),\n )\n .slice(0, 10)\n .join(', ')}...`,\n );\n }\n\n return toolFn((args[0] as Record<string, unknown>) ?? {});\n },\n };\n\n return { backend, client, toolInfos };\n}\n\nexport type { ServiceBackend };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,kBAAO;AACP,kBAAO;AACP,iBAAO;AAEP,iBAKO;AAAA,IAKP,yCAA6B;AAK7B,SAAS,mBAAmB,GAAmB;AAC7C,SAAO,EAAE,QAAQ,kBAAkB,GAAG,EAAE,QAAQ,UAAU,KAAK;AACjE;AA8BA,eAAsB,kBACpB,aACA,KAYC;AACD,QAAM,aAAa,IAAI,sCAA2B,EAAE;AAAA,IAClD;AAAA,EACF;AACA,QAAM,SAAS,MAAM,sBAAW,OAAO,OAAO,QAAQ,IAAI,GAAG,UAAU;AAGvE,QAAM,eAAe,oBAAI,IAGvB;AACF,QAAM,YAOD,CAAC;AAGN,QAAM,QAAQ,MACZ,OAUA,UAAU,EAAE;AAEd,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,KAAK,KAAK,SAAS,GAAG,EAAG;AAE9B,UAAM,CAAC,WAAW,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,GAAG;AACjD,UAAM,qBAAqB,mBAAmB,SAAU;AACxD,QAAI,YAAY,MAAM,IAAI,kBAAkB,EAAE,KAAK,GAAG;AAItD,UAAM,kBAAkB,GAAG,kBAAkB;AAC7C,QAAI,UAAU,WAAW,eAAe,GAAG;AACzC,kBAAY,UAAU,MAAM,gBAAgB,MAAM;AAAA,IACpD;AAEA,UAAM,MAAM,GAAG,kBAAkB,IAAI,SAAS;AAE9C,iBAAa,IAAI,KAAK,OAAO,SAAS,KAAK,QAAQ,KAAK,IAAI,CAAC;AAE7D,cAAU,KAAK;AAAA,MACb,MAAM;AAAA,MACN,WAAW;AAAA,MACX;AAAA,MACA,aAAa,KAAK;AAAA,MAClB,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,QAAM,UAA0B;AAAA,IAC9B,MAAM,OAAO,SAAiB,WAAmB,SAAoB;AACnE,YAAM,MAAM,GAAG,OAAO,IAAI,SAAS;AACnC,YAAM,SAAS,aAAa,IAAI,GAAG;AAEnC,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI;AAAA,UACR,wBAAwB,GAAG,sBAAsB,MAAM;AAAA,YACrD,aAAa,KAAK;AAAA,UACpB,EACG,MAAM,GAAG,EAAE,EACX,KAAK,IAAI,CAAC;AAAA,QACf;AAAA,MACF;AAEA,aAAO,OAAQ,KAAK,CAAC,KAAiC,CAAC,CAAC;AAAA,IAC1D;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,QAAQ,UAAU;AACtC;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @aprovan/patchwork-utcp\n *\n * UTCP backend integration for Patchwork.\n * Provides a ServiceBackend implementation that routes service calls through UTCP.\n */\n\nimport '@utcp/http';\nimport '@utcp/text';\nimport '@utcp/mcp';\n\nimport {\n UtcpClient,\n ensureCorePluginsInitialized,\n UtcpClientConfigSerializer,\n type UtcpClientConfig,\n} from '@utcp/sdk';\nimport type { ServiceBackend } from '@aprovan/patchwork';\n\n// Ensure plugins are loaded\nensureCorePluginsInitialized();\n\n/**\n * Sanitize a string for use as a JavaScript identifier\n */\nfunction sanitizeIdentifier(s: string): string {\n return s.replace(/[^a-zA-Z0-9_]/g, '_').replace(/^[0-9]/, '_$&');\n}\n\n/**\n * Create a UTCP-backed ServiceBackend for patchwork\n *\n * This is the integration point between UTCP and patchwork's service system.\n * Widgets call `github.repos_list_for_user()` → patchwork routes to this backend → UTCP executes.\n *\n * @example\n * ```typescript\n * import { createUtcpBackend } from '@aprovan/patchwork-utcp';\n * import { setServiceBackend } from '@aprovan/patchwork';\n *\n * const { backend, client } = await createUtcpBackend({\n * cwd: __dirname,\n * manual_call_templates: [{\n * name: 'github',\n * call_template_type: 'http',\n * url: 'https://raw.githubusercontent.com/.../api.github.com.json',\n * http_method: 'GET',\n * }],\n * });\n *\n * setServiceBackend(backend);\n *\n * // ... run widgets ...\n *\n * await client.close();\n * ```\n */\nexport async function createUtcpBackend(\n utcpOptions: UtcpClientConfig,\n cwd?: string,\n): Promise<{\n backend: ServiceBackend;\n client: UtcpClient;\n toolInfos: Array<{\n name: string;\n namespace: string;\n procedure: string;\n description?: string;\n parameters?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }>;\n}> {\n const utcpConfig = new UtcpClientConfigSerializer().validateDict(\n utcpOptions as unknown as Record<string, unknown>,\n );\n const client = await UtcpClient.create(cwd ?? process.cwd(), utcpConfig);\n\n // Build tool registry from discovered UTCP tools\n const toolRegistry = new Map<\n string,\n (args: Record<string, unknown>) => Promise<unknown>\n >();\n const toolInfos: Array<{\n name: string;\n namespace: string;\n procedure: string;\n description?: string;\n parameters?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }> = [];\n\n // Access internal getTools method - Tool has name, description, inputs, outputs, tags\n const tools = await (\n client as {\n getTools(): Promise<\n Array<{\n name: string;\n description?: string;\n inputs?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }>\n >;\n }\n )['getTools']();\n\n for (const tool of tools) {\n if (!tool.name.includes('.')) continue;\n\n const [namespace, ...parts] = tool.name.split('.');\n const sanitizedNamespace = sanitizeIdentifier(namespace!);\n let procedure = parts.map(sanitizeIdentifier).join('_');\n\n // Strip duplicate namespace prefix from procedure names\n // e.g., \"weather_get_forecast\" -> \"get_forecast\" when namespace is \"weather\"\n const namespacePrefix = `${sanitizedNamespace}_`;\n if (procedure.startsWith(namespacePrefix)) {\n procedure = procedure.slice(namespacePrefix.length);\n }\n\n const key = `${sanitizedNamespace}.${procedure}`;\n\n toolRegistry.set(key, client.callTool.bind(client, tool.name));\n\n toolInfos.push({\n name: key,\n namespace: sanitizedNamespace,\n procedure,\n description: tool.description,\n parameters: tool.inputs,\n outputs: tool.outputs,\n });\n }\n\n const backend: ServiceBackend = {\n call: async (service: string, procedure: string, args: unknown[]) => {\n const key = `${service}.${procedure}`;\n const toolFn = toolRegistry.get(key);\n\n if (!toolFn) {\n throw new Error(\n `UTCP tool not found: ${key}. Available tools: ${Array.from(\n toolRegistry.keys(),\n )\n .slice(0, 10)\n .join(', ')}...`,\n );\n }\n\n return toolFn((args[0] as Record<string, unknown>) ?? {});\n },\n };\n\n return { backend, client, toolInfos };\n}\n\nexport type { ServiceBackend };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,kBAAO;AACP,kBAAO;AACP,iBAAO;AAEP,iBAKO;AAAA,IAIP,yCAA6B;AAK7B,SAAS,mBAAmB,GAAmB;AAC7C,SAAO,EAAE,QAAQ,kBAAkB,GAAG,EAAE,QAAQ,UAAU,KAAK;AACjE;AA8BA,eAAsB,kBACpB,aACA,KAYC;AACD,QAAM,aAAa,IAAI,sCAA2B,EAAE;AAAA,IAClD;AAAA,EACF;AACA,QAAM,SAAS,MAAM,sBAAW,OAAO,OAAO,QAAQ,IAAI,GAAG,UAAU;AAGvE,QAAM,eAAe,oBAAI,IAGvB;AACF,QAAM,YAOD,CAAC;AAGN,QAAM,QAAQ,MACZ,OAUA,UAAU,EAAE;AAEd,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,KAAK,KAAK,SAAS,GAAG,EAAG;AAE9B,UAAM,CAAC,WAAW,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,GAAG;AACjD,UAAM,qBAAqB,mBAAmB,SAAU;AACxD,QAAI,YAAY,MAAM,IAAI,kBAAkB,EAAE,KAAK,GAAG;AAItD,UAAM,kBAAkB,GAAG,kBAAkB;AAC7C,QAAI,UAAU,WAAW,eAAe,GAAG;AACzC,kBAAY,UAAU,MAAM,gBAAgB,MAAM;AAAA,IACpD;AAEA,UAAM,MAAM,GAAG,kBAAkB,IAAI,SAAS;AAE9C,iBAAa,IAAI,KAAK,OAAO,SAAS,KAAK,QAAQ,KAAK,IAAI,CAAC;AAE7D,cAAU,KAAK;AAAA,MACb,MAAM;AAAA,MACN,WAAW;AAAA,MACX;AAAA,MACA,aAAa,KAAK;AAAA,MAClB,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,QAAM,UAA0B;AAAA,IAC9B,MAAM,OAAO,SAAiB,WAAmB,SAAoB;AACnE,YAAM,MAAM,GAAG,OAAO,IAAI,SAAS;AACnC,YAAM,SAAS,aAAa,IAAI,GAAG;AAEnC,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI;AAAA,UACR,wBAAwB,GAAG,sBAAsB,MAAM;AAAA,YACrD,aAAa,KAAK;AAAA,UACpB,EACG,MAAM,GAAG,EAAE,EACX,KAAK,IAAI,CAAC;AAAA,QACf;AAAA,MACF;AAEA,aAAO,OAAQ,KAAK,CAAC,KAAiC,CAAC,CAAC;AAAA,IAC1D;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,QAAQ,UAAU;AACtC;","names":[]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @aprovan/patchwork-utcp\n *\n * UTCP backend integration for Patchwork.\n * Provides a ServiceBackend implementation that routes service calls through UTCP.\n */\n\nimport '@utcp/http';\nimport '@utcp/text';\nimport '@utcp/mcp';\n\nimport {\n UtcpClient,\n ensureCorePluginsInitialized,\n UtcpClientConfigSerializer,\n UtcpClientConfig,\n} from '@utcp/sdk';\n\nimport type { ServiceBackend } from '@aprovan/patchwork';\n\n// Ensure plugins are loaded\nensureCorePluginsInitialized();\n\n/**\n * Sanitize a string for use as a JavaScript identifier\n */\nfunction sanitizeIdentifier(s: string): string {\n return s.replace(/[^a-zA-Z0-9_]/g, '_').replace(/^[0-9]/, '_$&');\n}\n\n/**\n * Create a UTCP-backed ServiceBackend for patchwork\n *\n * This is the integration point between UTCP and patchwork's service system.\n * Widgets call `github.repos_list_for_user()` → patchwork routes to this backend → UTCP executes.\n *\n * @example\n * ```typescript\n * import { createUtcpBackend } from '@aprovan/patchwork-utcp';\n * import { setServiceBackend } from '@aprovan/patchwork';\n *\n * const { backend, client } = await createUtcpBackend({\n * cwd: __dirname,\n * manual_call_templates: [{\n * name: 'github',\n * call_template_type: 'http',\n * url: 'https://raw.githubusercontent.com/.../api.github.com.json',\n * http_method: 'GET',\n * }],\n * });\n *\n * setServiceBackend(backend);\n *\n * // ... run widgets ...\n *\n * await client.close();\n * ```\n */\nexport async function createUtcpBackend(\n utcpOptions: UtcpClientConfig,\n cwd?: string,\n): Promise<{\n backend: ServiceBackend;\n client: UtcpClient;\n toolInfos: Array<{\n name: string;\n namespace: string;\n procedure: string;\n description?: string;\n parameters?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }>;\n}> {\n const utcpConfig = new UtcpClientConfigSerializer().validateDict(\n utcpOptions as unknown as Record<string, unknown>,\n );\n const client = await UtcpClient.create(cwd ?? process.cwd(), utcpConfig);\n\n // Build tool registry from discovered UTCP tools\n const toolRegistry = new Map<\n string,\n (args: Record<string, unknown>) => Promise<unknown>\n >();\n const toolInfos: Array<{\n name: string;\n namespace: string;\n procedure: string;\n description?: string;\n parameters?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }> = [];\n\n // Access internal getTools method - Tool has name, description, inputs, outputs, tags\n const tools = await (\n client as {\n getTools(): Promise<\n Array<{\n name: string;\n description?: string;\n inputs?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }>\n >;\n }\n )['getTools']();\n\n for (const tool of tools) {\n if (!tool.name.includes('.')) continue;\n\n const [namespace, ...parts] = tool.name.split('.');\n const sanitizedNamespace = sanitizeIdentifier(namespace!);\n let procedure = parts.map(sanitizeIdentifier).join('_');\n\n // Strip duplicate namespace prefix from procedure names\n // e.g., \"weather_get_forecast\" -> \"get_forecast\" when namespace is \"weather\"\n const namespacePrefix = `${sanitizedNamespace}_`;\n if (procedure.startsWith(namespacePrefix)) {\n procedure = procedure.slice(namespacePrefix.length);\n }\n\n const key = `${sanitizedNamespace}.${procedure}`;\n\n toolRegistry.set(key, client.callTool.bind(client, tool.name));\n\n toolInfos.push({\n name: key,\n namespace: sanitizedNamespace,\n procedure,\n description: tool.description,\n parameters: tool.inputs,\n outputs: tool.outputs,\n });\n }\n\n const backend: ServiceBackend = {\n call: async (service: string, procedure: string, args: unknown[]) => {\n const key = `${service}.${procedure}`;\n const toolFn = toolRegistry.get(key);\n\n if (!toolFn) {\n throw new Error(\n `UTCP tool not found: ${key}. Available tools: ${Array.from(\n toolRegistry.keys(),\n )\n .slice(0, 10)\n .join(', ')}...`,\n );\n }\n\n return toolFn((args[0] as Record<string, unknown>) ?? {});\n },\n };\n\n return { backend, client, toolInfos };\n}\n\nexport type { ServiceBackend };\n"],"mappings":";AAOA,OAAO;AACP,OAAO;AACP,OAAO;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAKP,6BAA6B;AAK7B,SAAS,mBAAmB,GAAmB;AAC7C,SAAO,EAAE,QAAQ,kBAAkB,GAAG,EAAE,QAAQ,UAAU,KAAK;AACjE;AA8BA,eAAsB,kBACpB,aACA,KAYC;AACD,QAAM,aAAa,IAAI,2BAA2B,EAAE;AAAA,IAClD;AAAA,EACF;AACA,QAAM,SAAS,MAAM,WAAW,OAAO,OAAO,QAAQ,IAAI,GAAG,UAAU;AAGvE,QAAM,eAAe,oBAAI,IAGvB;AACF,QAAM,YAOD,CAAC;AAGN,QAAM,QAAQ,MACZ,OAUA,UAAU,EAAE;AAEd,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,KAAK,KAAK,SAAS,GAAG,EAAG;AAE9B,UAAM,CAAC,WAAW,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,GAAG;AACjD,UAAM,qBAAqB,mBAAmB,SAAU;AACxD,QAAI,YAAY,MAAM,IAAI,kBAAkB,EAAE,KAAK,GAAG;AAItD,UAAM,kBAAkB,GAAG,kBAAkB;AAC7C,QAAI,UAAU,WAAW,eAAe,GAAG;AACzC,kBAAY,UAAU,MAAM,gBAAgB,MAAM;AAAA,IACpD;AAEA,UAAM,MAAM,GAAG,kBAAkB,IAAI,SAAS;AAE9C,iBAAa,IAAI,KAAK,OAAO,SAAS,KAAK,QAAQ,KAAK,IAAI,CAAC;AAE7D,cAAU,KAAK;AAAA,MACb,MAAM;AAAA,MACN,WAAW;AAAA,MACX;AAAA,MACA,aAAa,KAAK;AAAA,MAClB,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,QAAM,UAA0B;AAAA,IAC9B,MAAM,OAAO,SAAiB,WAAmB,SAAoB;AACnE,YAAM,MAAM,GAAG,OAAO,IAAI,SAAS;AACnC,YAAM,SAAS,aAAa,IAAI,GAAG;AAEnC,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI;AAAA,UACR,wBAAwB,GAAG,sBAAsB,MAAM;AAAA,YACrD,aAAa,KAAK;AAAA,UACpB,EACG,MAAM,GAAG,EAAE,EACX,KAAK,IAAI,CAAC;AAAA,QACf;AAAA,MACF;AAEA,aAAO,OAAQ,KAAK,CAAC,KAAiC,CAAC,CAAC;AAAA,IAC1D;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,QAAQ,UAAU;AACtC;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @aprovan/patchwork-utcp\n *\n * UTCP backend integration for Patchwork.\n * Provides a ServiceBackend implementation that routes service calls through UTCP.\n */\n\nimport '@utcp/http';\nimport '@utcp/text';\nimport '@utcp/mcp';\n\nimport {\n UtcpClient,\n ensureCorePluginsInitialized,\n UtcpClientConfigSerializer,\n type UtcpClientConfig,\n} from '@utcp/sdk';\nimport type { ServiceBackend } from '@aprovan/patchwork';\n\n// Ensure plugins are loaded\nensureCorePluginsInitialized();\n\n/**\n * Sanitize a string for use as a JavaScript identifier\n */\nfunction sanitizeIdentifier(s: string): string {\n return s.replace(/[^a-zA-Z0-9_]/g, '_').replace(/^[0-9]/, '_$&');\n}\n\n/**\n * Create a UTCP-backed ServiceBackend for patchwork\n *\n * This is the integration point between UTCP and patchwork's service system.\n * Widgets call `github.repos_list_for_user()` → patchwork routes to this backend → UTCP executes.\n *\n * @example\n * ```typescript\n * import { createUtcpBackend } from '@aprovan/patchwork-utcp';\n * import { setServiceBackend } from '@aprovan/patchwork';\n *\n * const { backend, client } = await createUtcpBackend({\n * cwd: __dirname,\n * manual_call_templates: [{\n * name: 'github',\n * call_template_type: 'http',\n * url: 'https://raw.githubusercontent.com/.../api.github.com.json',\n * http_method: 'GET',\n * }],\n * });\n *\n * setServiceBackend(backend);\n *\n * // ... run widgets ...\n *\n * await client.close();\n * ```\n */\nexport async function createUtcpBackend(\n utcpOptions: UtcpClientConfig,\n cwd?: string,\n): Promise<{\n backend: ServiceBackend;\n client: UtcpClient;\n toolInfos: Array<{\n name: string;\n namespace: string;\n procedure: string;\n description?: string;\n parameters?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }>;\n}> {\n const utcpConfig = new UtcpClientConfigSerializer().validateDict(\n utcpOptions as unknown as Record<string, unknown>,\n );\n const client = await UtcpClient.create(cwd ?? process.cwd(), utcpConfig);\n\n // Build tool registry from discovered UTCP tools\n const toolRegistry = new Map<\n string,\n (args: Record<string, unknown>) => Promise<unknown>\n >();\n const toolInfos: Array<{\n name: string;\n namespace: string;\n procedure: string;\n description?: string;\n parameters?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }> = [];\n\n // Access internal getTools method - Tool has name, description, inputs, outputs, tags\n const tools = await (\n client as {\n getTools(): Promise<\n Array<{\n name: string;\n description?: string;\n inputs?: Record<string, unknown>;\n outputs?: Record<string, unknown>;\n }>\n >;\n }\n )['getTools']();\n\n for (const tool of tools) {\n if (!tool.name.includes('.')) continue;\n\n const [namespace, ...parts] = tool.name.split('.');\n const sanitizedNamespace = sanitizeIdentifier(namespace!);\n let procedure = parts.map(sanitizeIdentifier).join('_');\n\n // Strip duplicate namespace prefix from procedure names\n // e.g., \"weather_get_forecast\" -> \"get_forecast\" when namespace is \"weather\"\n const namespacePrefix = `${sanitizedNamespace}_`;\n if (procedure.startsWith(namespacePrefix)) {\n procedure = procedure.slice(namespacePrefix.length);\n }\n\n const key = `${sanitizedNamespace}.${procedure}`;\n\n toolRegistry.set(key, client.callTool.bind(client, tool.name));\n\n toolInfos.push({\n name: key,\n namespace: sanitizedNamespace,\n procedure,\n description: tool.description,\n parameters: tool.inputs,\n outputs: tool.outputs,\n });\n }\n\n const backend: ServiceBackend = {\n call: async (service: string, procedure: string, args: unknown[]) => {\n const key = `${service}.${procedure}`;\n const toolFn = toolRegistry.get(key);\n\n if (!toolFn) {\n throw new Error(\n `UTCP tool not found: ${key}. Available tools: ${Array.from(\n toolRegistry.keys(),\n )\n .slice(0, 10)\n .join(', ')}...`,\n );\n }\n\n return toolFn((args[0] as Record<string, unknown>) ?? {});\n },\n };\n\n return { backend, client, toolInfos };\n}\n\nexport type { ServiceBackend };\n"],"mappings":";AAOA,OAAO;AACP,OAAO;AACP,OAAO;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAIP,6BAA6B;AAK7B,SAAS,mBAAmB,GAAmB;AAC7C,SAAO,EAAE,QAAQ,kBAAkB,GAAG,EAAE,QAAQ,UAAU,KAAK;AACjE;AA8BA,eAAsB,kBACpB,aACA,KAYC;AACD,QAAM,aAAa,IAAI,2BAA2B,EAAE;AAAA,IAClD;AAAA,EACF;AACA,QAAM,SAAS,MAAM,WAAW,OAAO,OAAO,QAAQ,IAAI,GAAG,UAAU;AAGvE,QAAM,eAAe,oBAAI,IAGvB;AACF,QAAM,YAOD,CAAC;AAGN,QAAM,QAAQ,MACZ,OAUA,UAAU,EAAE;AAEd,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,KAAK,KAAK,SAAS,GAAG,EAAG;AAE9B,UAAM,CAAC,WAAW,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,GAAG;AACjD,UAAM,qBAAqB,mBAAmB,SAAU;AACxD,QAAI,YAAY,MAAM,IAAI,kBAAkB,EAAE,KAAK,GAAG;AAItD,UAAM,kBAAkB,GAAG,kBAAkB;AAC7C,QAAI,UAAU,WAAW,eAAe,GAAG;AACzC,kBAAY,UAAU,MAAM,gBAAgB,MAAM;AAAA,IACpD;AAEA,UAAM,MAAM,GAAG,kBAAkB,IAAI,SAAS;AAE9C,iBAAa,IAAI,KAAK,OAAO,SAAS,KAAK,QAAQ,KAAK,IAAI,CAAC;AAE7D,cAAU,KAAK;AAAA,MACb,MAAM;AAAA,MACN,WAAW;AAAA,MACX;AAAA,MACA,aAAa,KAAK;AAAA,MAClB,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,QAAM,UAA0B;AAAA,IAC9B,MAAM,OAAO,SAAiB,WAAmB,SAAoB;AACnE,YAAM,MAAM,GAAG,OAAO,IAAI,SAAS;AACnC,YAAM,SAAS,aAAa,IAAI,GAAG;AAEnC,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI;AAAA,UACR,wBAAwB,GAAG,sBAAsB,MAAM;AAAA,YACrD,aAAa,KAAK;AAAA,UACpB,EACG,MAAM,GAAG,EAAE,EACX,KAAK,IAAI,CAAC;AAAA,QACf;AAAA,MACF;AAEA,aAAO,OAAQ,KAAK,CAAC,KAAiC,CAAC,CAAC;AAAA,IAC1D;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,QAAQ,UAAU;AACtC;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aprovan/patchwork-utcp",
3
- "version": "0.1.0-dev.3afec03",
3
+ "version": "0.1.0-dev.4d82df8",
4
4
  "description": "UTCP backend integration for Patchwork",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
package/src/index.ts CHANGED
@@ -13,9 +13,8 @@ import {
13
13
  UtcpClient,
14
14
  ensureCorePluginsInitialized,
15
15
  UtcpClientConfigSerializer,
16
- UtcpClientConfig,
16
+ type UtcpClientConfig,
17
17
  } from '@utcp/sdk';
18
-
19
18
  import type { ServiceBackend } from '@aprovan/patchwork';
20
19
 
21
20
  // Ensure plugins are loaded