@aprovan/patchwork-utcp 0.1.0-dev.6bd527d → 0.1.0-dev.78c0b14

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.84 KB
14
- ESM dist/index.js.map 5.48 KB
15
- ESM ⚡️ Build success in 49ms
16
- CJS dist/index.cjs 2.88 KB
17
- CJS dist/index.cjs.map 5.49 KB
18
- CJS ⚡️ Build success in 49ms
13
+ CJS dist/index.cjs 2.90 KB
14
+ CJS dist/index.cjs.map 5.67 KB
15
+ CJS ⚡️ Build success in 71ms
16
+ ESM dist/index.js 1.87 KB
17
+ ESM dist/index.js.map 5.65 KB
18
+ ESM ⚡️ Build success in 71ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 2675ms
21
- DTS dist/index.d.ts 1.44 KB
22
- DTS dist/index.d.cts 1.44 KB
20
+ DTS ⚡️ Build success in 3878ms
21
+ DTS dist/index.d.ts 1.48 KB
22
+ DTS dist/index.d.cts 1.48 KB
package/dist/index.cjs CHANGED
@@ -55,7 +55,8 @@ async function createUtcpBackend(utcpOptions, cwd) {
55
55
  namespace: sanitizedNamespace,
56
56
  procedure,
57
57
  description: tool.description,
58
- parameters: tool.inputs
58
+ parameters: tool.inputs,
59
+ outputs: tool.outputs
59
60
  });
60
61
  }
61
62
  const backend = {
@@ -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 }>;\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 }> = [];\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 }>\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 });\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,KAWC;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,YAMD,CAAC;AAGN,QAAM,QAAQ,MACZ,OASA,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,IACnB,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.d.cts CHANGED
@@ -46,6 +46,7 @@ declare function createUtcpBackend(utcpOptions: UtcpClientConfig, cwd?: string):
46
46
  procedure: string;
47
47
  description?: string;
48
48
  parameters?: Record<string, unknown>;
49
+ outputs?: Record<string, unknown>;
49
50
  }>;
50
51
  }>;
51
52
 
package/dist/index.d.ts CHANGED
@@ -46,6 +46,7 @@ declare function createUtcpBackend(utcpOptions: UtcpClientConfig, cwd?: string):
46
46
  procedure: string;
47
47
  description?: string;
48
48
  parameters?: Record<string, unknown>;
49
+ outputs?: Record<string, unknown>;
49
50
  }>;
50
51
  }>;
51
52
 
package/dist/index.js CHANGED
@@ -35,7 +35,8 @@ async function createUtcpBackend(utcpOptions, cwd) {
35
35
  namespace: sanitizedNamespace,
36
36
  procedure,
37
37
  description: tool.description,
38
- parameters: tool.inputs
38
+ parameters: tool.inputs,
39
+ outputs: tool.outputs
39
40
  });
40
41
  }
41
42
  const backend = {
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 }>;\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 }> = [];\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 }>\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 });\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,KAWC;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,YAMD,CAAC;AAGN,QAAM,QAAQ,MACZ,OASA,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,IACnB,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.6bd527d",
3
+ "version": "0.1.0-dev.78c0b14",
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
@@ -68,6 +67,7 @@ export async function createUtcpBackend(
68
67
  procedure: string;
69
68
  description?: string;
70
69
  parameters?: Record<string, unknown>;
70
+ outputs?: Record<string, unknown>;
71
71
  }>;
72
72
  }> {
73
73
  const utcpConfig = new UtcpClientConfigSerializer().validateDict(
@@ -86,6 +86,7 @@ export async function createUtcpBackend(
86
86
  procedure: string;
87
87
  description?: string;
88
88
  parameters?: Record<string, unknown>;
89
+ outputs?: Record<string, unknown>;
89
90
  }> = [];
90
91
 
91
92
  // Access internal getTools method - Tool has name, description, inputs, outputs, tags
@@ -96,6 +97,7 @@ export async function createUtcpBackend(
96
97
  name: string;
97
98
  description?: string;
98
99
  inputs?: Record<string, unknown>;
100
+ outputs?: Record<string, unknown>;
99
101
  }>
100
102
  >;
101
103
  }
@@ -125,6 +127,7 @@ export async function createUtcpBackend(
125
127
  procedure,
126
128
  description: tool.description,
127
129
  parameters: tool.inputs,
130
+ outputs: tool.outputs,
128
131
  });
129
132
  }
130
133