@pikku/cli 0.12.6 → 0.12.8

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 (117) hide show
  1. package/cli.schema.json +1 -1
  2. package/console-app/assets/{index-AX4YS8AA.js → index-DOk9fqHB.js} +49 -49
  3. package/console-app/index.html +1 -1
  4. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +6 -6
  5. package/dist/.pikku/agent/pikku-agent-wirings-meta.gen.js +1 -1
  6. package/dist/.pikku/agent/pikku-agent-wirings.gen.d.ts +1 -1
  7. package/dist/.pikku/agent/pikku-agent-wirings.gen.js +1 -1
  8. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  9. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  10. package/dist/.pikku/channel/pikku-channels-meta.gen.js +1 -1
  11. package/dist/.pikku/channel/pikku-channels.gen.d.ts +1 -1
  12. package/dist/.pikku/channel/pikku-channels.gen.js +1 -1
  13. package/dist/.pikku/cli/pikku-cli-channel.js +1 -1
  14. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  15. package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
  16. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  17. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  18. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  19. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +1 -1
  20. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  21. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  22. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  23. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  24. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  25. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  26. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  27. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  28. package/dist/.pikku/function/pikku-functions-meta.gen.json +160 -160
  29. package/dist/.pikku/function/pikku-functions.gen.js +1 -1
  30. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  31. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  32. package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
  33. package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
  34. package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
  35. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  36. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  37. package/dist/.pikku/mcp/pikku-mcp-wirings-meta.gen.js +1 -1
  38. package/dist/.pikku/mcp/pikku-mcp-wirings.gen.d.ts +1 -1
  39. package/dist/.pikku/mcp/pikku-mcp-wirings.gen.js +1 -1
  40. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  41. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  42. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  43. package/dist/.pikku/pikku-types.gen.js +1 -1
  44. package/dist/.pikku/pikku-websocket.gen.d.ts +1 -1
  45. package/dist/.pikku/pikku-websocket.gen.js +1 -1
  46. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  47. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  48. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  49. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  50. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  51. package/dist/.pikku/rpc/pikku-remote-rpc-workers.gen.js +1 -1
  52. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  53. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +2 -2
  54. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  55. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  56. package/dist/.pikku/scheduler/pikku-schedulers-wirings-meta.gen.js +1 -1
  57. package/dist/.pikku/scheduler/pikku-schedulers-wirings.gen.d.ts +1 -1
  58. package/dist/.pikku/scheduler/pikku-schedulers-wirings.gen.js +1 -1
  59. package/dist/.pikku/schemas/register.gen.js +9 -9
  60. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  61. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  62. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  63. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  64. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  65. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  66. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  67. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  68. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  69. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  70. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  71. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +35 -5
  72. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +5 -5
  73. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  74. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.d.ts +1 -1
  75. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  76. package/dist/src/cli.wiring.js +1 -1
  77. package/dist/src/functions/commands/all.js +16 -1
  78. package/dist/src/functions/commands/new-addon.js +20 -6
  79. package/dist/src/functions/commands/versions-check.js +4 -4
  80. package/dist/src/functions/commands/versions-init.js +1 -1
  81. package/dist/src/functions/commands/versions-update.js +1 -1
  82. package/dist/src/functions/runtimes/nextjs/pikku-command-nextjs.js +2 -2
  83. package/dist/src/functions/runtimes/nextjs/serialize-nextjs-backend-wrapper.d.ts +1 -1
  84. package/dist/src/functions/runtimes/nextjs/serialize-nextjs-backend-wrapper.js +2 -2
  85. package/dist/src/functions/runtimes/nextjs/serialize-nextjs-http-wrapper.d.ts +1 -1
  86. package/dist/src/functions/runtimes/nextjs/serialize-nextjs-http-wrapper.js +2 -2
  87. package/dist/src/functions/wirings/ai-agent/pikku-command-public-agent.js +1 -1
  88. package/dist/src/functions/wirings/ai-agent/serialize-ai-agent-types.js +12 -6
  89. package/dist/src/functions/wirings/ai-agent/serialize-public-agent.d.ts +1 -1
  90. package/dist/src/functions/wirings/ai-agent/serialize-public-agent.js +5 -5
  91. package/dist/src/functions/wirings/cli/pikku-command-cli-entry.js +1 -1
  92. package/dist/src/functions/wirings/cli/serialize-channel-cli.d.ts +1 -1
  93. package/dist/src/functions/wirings/cli/serialize-channel-cli.js +2 -2
  94. package/dist/src/functions/wirings/console/pikku-command-console-functions.js +1 -1
  95. package/dist/src/functions/wirings/console/serialize-console-functions.d.ts +1 -1
  96. package/dist/src/functions/wirings/console/serialize-console-functions.js +2 -2
  97. package/dist/src/functions/wirings/middleware/serialize-middleware-imports.js +22 -0
  98. package/dist/src/functions/wirings/permissions/serialize-permissions-imports.js +22 -0
  99. package/dist/src/functions/wirings/rpc/pikku-command-public-rpc.js +1 -1
  100. package/dist/src/functions/wirings/rpc/pikku-command-rpc-client.js +1 -1
  101. package/dist/src/functions/wirings/rpc/serialize-public-rpc.d.ts +1 -1
  102. package/dist/src/functions/wirings/rpc/serialize-public-rpc.js +4 -4
  103. package/dist/src/functions/wirings/rpc/serialize-rpc-wrapper.d.ts +1 -1
  104. package/dist/src/functions/wirings/rpc/serialize-rpc-wrapper.js +6 -6
  105. package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +64 -8
  106. package/dist/src/services.js +5 -1
  107. package/dist/src/utils/pikku-cli-config.js +1 -0
  108. package/dist/tsconfig.tsbuildinfo +1 -1
  109. package/package.json +6 -5
  110. package/dist/src/utils/openapi/codegen.d.ts +0 -20
  111. package/dist/src/utils/openapi/codegen.js +0 -442
  112. package/dist/src/utils/openapi/naming.d.ts +0 -30
  113. package/dist/src/utils/openapi/naming.js +0 -167
  114. package/dist/src/utils/openapi/parse-openapi.d.ts +0 -61
  115. package/dist/src/utils/openapi/parse-openapi.js +0 -306
  116. package/dist/src/utils/openapi/zod-codegen.d.ts +0 -1
  117. package/dist/src/utils/openapi/zod-codegen.js +0 -1
@@ -1,9 +1,9 @@
1
1
  import { existsSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { mkdir, writeFile } from 'fs/promises';
4
+ import { createEmptyManifest, saveManifest, } from '../../utils/contract-versions.js';
4
5
  import { pikkuSessionlessFunc } from '#pikku';
5
- import { parseOpenAPISpec } from '../../utils/openapi/parse-openapi.js';
6
- import { generateAddonFromOpenAPI } from '../../utils/openapi/codegen.js';
6
+ import { parseOpenAPISpec, computeContractHash, generateAddonFromOpenAPI, } from '@pikku/openapi-parser';
7
7
  function toCamelCase(str) {
8
8
  return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
9
9
  }
@@ -31,14 +31,15 @@ function getAddonFiles(vars, flags) {
31
31
  types: './dist/src/index.d.ts',
32
32
  import: './dist/src/index.js',
33
33
  },
34
- './.pikku/*': './.pikku/*',
35
- './.pikku/pikku-metadata.gen.json': './.pikku/pikku-metadata.gen.json',
34
+ './.pikku/*': './dist/.pikku/*',
35
+ './.pikku/pikku-metadata.gen.json': './dist/.pikku/pikku-metadata.gen.json',
36
36
  './.pikku/rpc/pikku-rpc-wirings-map.internal.gen.js': {
37
- types: './.pikku/rpc/pikku-rpc-wirings-map.internal.gen.d.ts',
37
+ types: './dist/.pikku/rpc/pikku-rpc-wirings-map.internal.gen.d.ts',
38
38
  },
39
39
  },
40
- files: ['dist', '.pikku'],
40
+ files: ['dist'],
41
41
  scripts: {
42
+ prepublishOnly: 'yarn build',
42
43
  prebuild: 'pikku all',
43
44
  build: 'tsc && cp -r .pikku dist/',
44
45
  pikku: 'pikku all',
@@ -613,6 +614,16 @@ export const pikkuNewAddon = pikkuSessionlessFunc({
613
614
  mcp,
614
615
  });
615
616
  Object.assign(addonFiles, openapiFiles);
617
+ // Inject openapi metadata into pikku.config.json
618
+ const config = JSON.parse(addonFiles['pikku.config.json']);
619
+ if (typeof config.addon === 'boolean' || !config.addon) {
620
+ config.addon = {};
621
+ }
622
+ config.addon.openapi = {
623
+ version: spec.info.version,
624
+ hash: computeContractHash(spec),
625
+ };
626
+ addonFiles['pikku.config.json'] = JSON.stringify(config, null, 2);
616
627
  }
617
628
  const written = await writeFiles(addonDir, addonFiles);
618
629
  // Test harness
@@ -621,6 +632,9 @@ export const pikkuNewAddon = pikkuSessionlessFunc({
621
632
  const testWritten = await writeFiles(join(addonDir, 'test'), testFiles);
622
633
  written.push(...testWritten);
623
634
  }
635
+ // Initialize version manifest
636
+ const manifestPath = join(addonDir, 'versions.pikku.json');
637
+ await saveManifest(manifestPath, createEmptyManifest());
624
638
  logger.info(`Created addon at ${addonDir}`);
625
639
  for (const f of written) {
626
640
  logger.debug({ message: ` ${f}`, type: 'success' });
@@ -13,7 +13,7 @@ export const pikkuVersionsCheck = pikkuSessionlessFunc({
13
13
  func: async ({ logger, config, getInspectorState }) => {
14
14
  const visitState = await getInspectorState();
15
15
  if (!visitState.manifest.initial) {
16
- const manifestPath = join(config.outDir, 'versions.json');
16
+ const manifestPath = join(config.rootDir, 'versions.pikku.json');
17
17
  throw new Error(`[${ErrorCode.MANIFEST_MISSING}] Version manifest not found at ${manifestPath}. Run 'pikku versions init' to create one.`);
18
18
  }
19
19
  if (visitState.manifest.errors.length > 0) {
@@ -50,9 +50,9 @@ export const pikkuVersionsCheck = pikkuSessionlessFunc({
50
50
  if (error.latestVersion !== undefined) {
51
51
  logger.info(` Latest recorded version: ${error.latestVersion}`);
52
52
  }
53
- logger.info(` Version ${error.version} exists in code but not in versions.json`);
53
+ logger.info(` Version ${error.version} exists in code but not in versions.pikku.json`);
54
54
  logger.info(``);
55
- logger.info(` This usually means a merge conflict in versions.json.`);
55
+ logger.info(` This usually means a merge conflict in versions.pikku.json.`);
56
56
  logger.info(` Resolve the conflict, then run:`);
57
57
  logger.info(` npx pikku versions-update`);
58
58
  }
@@ -76,7 +76,7 @@ export const pikkuVersionsCheck = pikkuSessionlessFunc({
76
76
  }
77
77
  else if (error.code === ErrorCode.MANIFEST_INTEGRITY_ERROR &&
78
78
  error.functionKey) {
79
- logger.info(`✗ ${error.functionKey} — versions.json integrity error`);
79
+ logger.info(`✗ ${error.functionKey} — versions.pikku.json integrity error`);
80
80
  if (error.latestVersion !== undefined) {
81
81
  logger.info(` "latest" field: ${error.latestVersion}`);
82
82
  }
@@ -4,7 +4,7 @@ import { pikkuSessionlessFunc } from '#pikku';
4
4
  import { createEmptyManifest, saveManifest, } from '../../utils/contract-versions.js';
5
5
  export const pikkuVersionsInit = pikkuSessionlessFunc({
6
6
  func: async ({ logger, config }, { force }) => {
7
- const manifestPath = join(config.outDir, 'versions.json');
7
+ const manifestPath = join(config.rootDir, 'versions.pikku.json');
8
8
  if (existsSync(manifestPath) && !force) {
9
9
  logger.error(`Version manifest already exists at ${manifestPath}. Use --force to overwrite.`);
10
10
  process.exit(1);
@@ -4,7 +4,7 @@ import { ErrorCode } from '@pikku/inspector';
4
4
  import { saveManifest } from '../../utils/contract-versions.js';
5
5
  export const pikkuVersionsUpdate = pikkuSessionlessFunc({
6
6
  func: async ({ logger, config, getInspectorState }) => {
7
- const manifestPath = join(config.outDir, 'versions.json');
7
+ const manifestPath = join(config.rootDir, 'versions.pikku.json');
8
8
  const visitState = await getInspectorState();
9
9
  if (!visitState.manifest.initial) {
10
10
  throw new Error(`Version manifest not found at ${manifestPath}. Run 'pikku versions init' to create one.`);
@@ -43,14 +43,14 @@ export const pikkuNext = pikkuSessionlessFunc({
43
43
  const bootstrapPath = getFileImportRelativePath(nextBackendFile, config.bootstrapFile, packageMappings);
44
44
  const routesMapDeclarationPath = getFileImportRelativePath(nextBackendFile, httpMapDeclarationFile, packageMappings);
45
45
  const rpcMapDeclarationPath = getFileImportRelativePath(nextBackendFile, rpcMapDeclarationFile, packageMappings);
46
- const content = serializeNextBackendWrapper(bootstrapPath, routesMapDeclarationPath, rpcMapDeclarationPath, pikkuConfigImport, singletonServicesImport, wireServicesImport);
46
+ const content = serializeNextBackendWrapper(bootstrapPath, routesMapDeclarationPath, rpcMapDeclarationPath, pikkuConfigImport, singletonServicesImport, wireServicesImport, config.globalHTTPPrefix || '');
47
47
  await writeFileInDir(logger, nextBackendFile, content);
48
48
  }
49
49
  if (nextHTTPFile && fetchFile) {
50
50
  const routesMapDeclarationPath = getFileImportRelativePath(nextHTTPFile, httpMapDeclarationFile, packageMappings);
51
51
  const rpcMapDeclarationPath = getFileImportRelativePath(nextHTTPFile, rpcMapDeclarationFile, packageMappings);
52
52
  const fetchPath = getFileImportRelativePath(nextHTTPFile, fetchFile, packageMappings);
53
- const content = serializeNextHTTPWrapper(routesMapDeclarationPath, rpcMapDeclarationPath, fetchPath);
53
+ const content = serializeNextHTTPWrapper(routesMapDeclarationPath, rpcMapDeclarationPath, fetchPath, config.globalHTTPPrefix || '');
54
54
  await writeFileInDir(logger, nextHTTPFile, content);
55
55
  }
56
56
  },
@@ -1 +1 @@
1
- export declare const serializeNextJsBackendWrapper: (bootstrapPath: string, routesMapPath: string, rpcMapPath: string, configImport: string, singleServicesFactoryImport: string, wireServicesImport: string | undefined) => string;
1
+ export declare const serializeNextJsBackendWrapper: (bootstrapPath: string, routesMapPath: string, rpcMapPath: string, configImport: string, singleServicesFactoryImport: string, wireServicesImport: string | undefined, globalHTTPPrefix?: string) => string;
@@ -1,4 +1,4 @@
1
- export const serializeNextJsBackendWrapper = (bootstrapPath, routesMapPath, rpcMapPath, configImport, singleServicesFactoryImport, wireServicesImport) => {
1
+ export const serializeNextJsBackendWrapper = (bootstrapPath, routesMapPath, rpcMapPath, configImport, singleServicesFactoryImport, wireServicesImport, globalHTTPPrefix = '') => {
2
2
  return `'server-only'
3
3
 
4
4
  /**
@@ -194,7 +194,7 @@ export const pikku = (_options?: any) => {
194
194
  rpcName: Name,
195
195
  data: FlattenedRPCMap[Name]['input']
196
196
  ): Promise<FlattenedRPCMap[Name]['output']> => {
197
- return dynamicActionRequest('/rpc/:rpcName' as '/rpc/:rpcName', 'POST', { rpcName, data: data ?? null }) as unknown as FlattenedRPCMap[Name]['output']
197
+ return dynamicActionRequest('${globalHTTPPrefix}/rpc/:rpcName' as '${globalHTTPPrefix}/rpc/:rpcName', 'POST', { rpcName, data: data ?? null }) as unknown as FlattenedRPCMap[Name]['output']
198
198
  }
199
199
 
200
200
  /**
@@ -1 +1 @@
1
- export declare const serializeNextJsHTTPWrapper: (routesMapPath: string, rpcMapPath: string, pikkuFetchImport: string) => string;
1
+ export declare const serializeNextJsHTTPWrapper: (routesMapPath: string, rpcMapPath: string, pikkuFetchImport: string, globalHTTPPrefix?: string) => string;
@@ -1,4 +1,4 @@
1
- export const serializeNextJsHTTPWrapper = (routesMapPath, rpcMapPath, pikkuFetchImport) => {
1
+ export const serializeNextJsHTTPWrapper = (routesMapPath, rpcMapPath, pikkuFetchImport, globalHTTPPrefix = '') => {
2
2
  return `'server-only'
3
3
 
4
4
  /**
@@ -173,7 +173,7 @@ export const pikku = (options?: CorePikkuFetchOptions) => {
173
173
  rpcName: Name,
174
174
  data: FlattenedRPCMap[Name]['input']
175
175
  ): Promise<FlattenedRPCMap[Name]['output']> => {
176
- return dynamicActionRequest('/rpc/:rpcName' as '/rpc/:rpcName', 'POST', { rpcName, data: data ?? null }) as unknown as FlattenedRPCMap[Name]['output']
176
+ return dynamicActionRequest('${globalHTTPPrefix}/rpc/:rpcName' as '${globalHTTPPrefix}/rpc/:rpcName', 'POST', { rpcName, data: data ?? null }) as unknown as FlattenedRPCMap[Name]['output']
177
177
  }
178
178
 
179
179
  /**
@@ -7,7 +7,7 @@ export const pikkuPublicAgent = pikkuSessionlessFunc({
7
7
  func: async ({ logger, config }) => {
8
8
  if (config.scaffold?.agent) {
9
9
  const pathToPikkuTypes = getFileImportRelativePath(config.publicAgentFile, config.typesDeclarationFile, config.packageMappings);
10
- await writeFileInDir(logger, config.publicAgentFile, serializePublicAgent(pathToPikkuTypes, config.scaffold.agent === 'auth'));
10
+ await writeFileInDir(logger, config.publicAgentFile, serializePublicAgent(pathToPikkuTypes, config.scaffold.agent === 'auth', config.globalHTTPPrefix || ''));
11
11
  return true;
12
12
  }
13
13
  return false;
@@ -14,16 +14,22 @@ import type { StandardSchemaV1 } from '@standard-schema/spec'
14
14
  import type { AIAgentMemoryConfig, AIAgentInput } from '@pikku/core/ai-agent'
15
15
  import type { AgentMap } from '${agentMapImportPath}'
16
16
 
17
- type AIAgentConfig = Omit<CoreAIAgent<PikkuPermission, PikkuMiddleware>, 'tools' | 'agents' | 'memory'> & {
18
- input?: StandardSchemaV1
19
- output?: StandardSchemaV1
17
+ type AIAgentConfig<
18
+ InputSchema extends StandardSchemaV1 | undefined = undefined,
19
+ OutputSchema extends StandardSchemaV1 | undefined = undefined
20
+ > = Omit<CoreAIAgent<PikkuPermission, PikkuMiddleware>, 'tools' | 'agents' | 'memory' | 'input' | 'output'> & {
21
+ input?: InputSchema
22
+ output?: OutputSchema
20
23
  memory?: Omit<AIAgentMemoryConfig, 'workingMemory'> & { workingMemory?: StandardSchemaV1 }
21
24
  tools?: object[]
22
- agents?: AIAgentConfig[]
25
+ agents?: AIAgentConfig<StandardSchemaV1 | undefined, StandardSchemaV1 | undefined>[]
23
26
  }
24
27
 
25
- export const pikkuAIAgent = (
26
- agent: AIAgentConfig
28
+ export const pikkuAIAgent = <
29
+ InputSchema extends StandardSchemaV1 | undefined = undefined,
30
+ OutputSchema extends StandardSchemaV1 | undefined = undefined
31
+ >(
32
+ agent: AIAgentConfig<InputSchema, OutputSchema>
27
33
  ) => {
28
34
  return agent
29
35
  }
@@ -1 +1 @@
1
- export declare const serializePublicAgent: (pathToPikkuTypes: string, requireAuth?: boolean) => string;
1
+ export declare const serializePublicAgent: (pathToPikkuTypes: string, requireAuth?: boolean, globalHTTPPrefix?: string) => string;
@@ -1,4 +1,4 @@
1
- export const serializePublicAgent = (pathToPikkuTypes, requireAuth = true) => {
1
+ export const serializePublicAgent = (pathToPikkuTypes, requireAuth = true, globalHTTPPrefix = '') => {
2
2
  const authFlag = requireAuth ? 'true' : 'false';
3
3
  return `import { pikkuSessionlessFunc, defineHTTPRoutes, wireHTTPRoutes } from '${pathToPikkuTypes}'
4
4
 
@@ -58,23 +58,23 @@ export const agentRoutes = defineHTTPRoutes({
58
58
  tags: ['pikku:public'],
59
59
  routes: {
60
60
  agentRun: {
61
- route: '/rpc/agent/:agentName',
61
+ route: '${globalHTTPPrefix}/rpc/agent/:agentName',
62
62
  method: 'post',
63
63
  func: agentCaller,
64
64
  },
65
65
  agentStream: {
66
- route: '/rpc/agent/:agentName/stream',
66
+ route: '${globalHTTPPrefix}/rpc/agent/:agentName/stream',
67
67
  method: 'post',
68
68
  sse: true,
69
69
  func: agentStreamCaller,
70
70
  },
71
71
  agentApprove: {
72
- route: '/rpc/agent/:agentName/approve',
72
+ route: '${globalHTTPPrefix}/rpc/agent/:agentName/approve',
73
73
  method: 'post',
74
74
  func: agentApproveCaller,
75
75
  },
76
76
  agentResume: {
77
- route: '/rpc/agent/:agentName/resume',
77
+ route: '${globalHTTPPrefix}/rpc/agent/:agentName/resume',
78
78
  method: 'post',
79
79
  sse: true,
80
80
  func: agentResumeCaller,
@@ -56,7 +56,7 @@ export const pikkuCLIEntry = pikkuSessionlessFunc({
56
56
  `Move it to a source directory like "src/wirings/cli-channel.gen.ts".`);
57
57
  }
58
58
  const channelWireFile = resolvedWirePath;
59
- const channelCode = serializeChannelCLI(programName, programMeta, channelWireFile, visitState.functions.files, config.packageMappings, config.channelsTypesFile, config.functionTypesFile, channelName, channelRoute);
59
+ const channelCode = serializeChannelCLI(programName, programMeta, channelWireFile, visitState.functions.files, config.packageMappings, config.channelsTypesFile, config.functionTypesFile, channelName, channelRoute, config.globalHTTPPrefix || '');
60
60
  await writeFileInDir(logger, channelWireFile, channelCode);
61
61
  logger.debug(`Serialized CLI channel for ${programName}: ${channelWireFile}`);
62
62
  // Generate client code if clientPath is provided
@@ -6,4 +6,4 @@ import type { CLIProgramMeta } from '@pikku/core/cli';
6
6
  export declare function serializeChannelCLI(programName: string, programMeta: CLIProgramMeta, channelFile: string, functionFiles: Map<string, {
7
7
  path: string;
8
8
  exportedName: string;
9
- }>, packageMappings: Record<string, string>, channelTypesFile: string, functionTypesFile: string, channelName?: string, channelRoute?: string): string;
9
+ }>, packageMappings: Record<string, string>, channelTypesFile: string, functionTypesFile: string, channelName?: string, channelRoute?: string, globalHTTPPrefix?: string): string;
@@ -3,9 +3,9 @@ import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
3
3
  * Serializes a wireChannel call from CLI metadata
4
4
  * This creates a WebSocket backend for all CLI commands
5
5
  */
6
- export function serializeChannelCLI(programName, programMeta, channelFile, functionFiles, packageMappings, channelTypesFile, functionTypesFile, channelName, channelRoute) {
6
+ export function serializeChannelCLI(programName, programMeta, channelFile, functionFiles, packageMappings, channelTypesFile, functionTypesFile, channelName, channelRoute, globalHTTPPrefix = '') {
7
7
  const finalChannelName = channelName || `${programName}-cli`;
8
- const finalChannelRoute = channelRoute || `/cli/${programName}`;
8
+ const finalChannelRoute = channelRoute || `${globalHTTPPrefix}/cli/${programName}`;
9
9
  // Flatten all commands into a single routing map
10
10
  const commandMap = {};
11
11
  const collectCommands = (commands, path = []) => {
@@ -8,7 +8,7 @@ export const pikkuConsoleFunctions = pikkuSessionlessFunc({
8
8
  if (config.scaffold?.console) {
9
9
  const pathToPikkuTypes = getFileImportRelativePath(config.consoleFunctionsFile, config.typesDeclarationFile, config.packageMappings);
10
10
  const pathToAgentTypes = getFileImportRelativePath(config.consoleFunctionsFile, config.agentTypesFile, config.packageMappings);
11
- await writeFileInDir(logger, config.consoleFunctionsFile, serializeConsoleFunctions(pathToPikkuTypes, pathToAgentTypes));
11
+ await writeFileInDir(logger, config.consoleFunctionsFile, serializeConsoleFunctions(pathToPikkuTypes, pathToAgentTypes, config.globalHTTPPrefix || ''));
12
12
  return true;
13
13
  }
14
14
  return false;
@@ -1 +1 @@
1
- export declare const serializeConsoleFunctions: (pathToPikkuTypes: string, _pathToAgentTypes: string) => string;
1
+ export declare const serializeConsoleFunctions: (pathToPikkuTypes: string, _pathToAgentTypes: string, globalHTTPPrefix?: string) => string;
@@ -1,4 +1,4 @@
1
- export const serializeConsoleFunctions = (pathToPikkuTypes, _pathToAgentTypes) => {
1
+ export const serializeConsoleFunctions = (pathToPikkuTypes, _pathToAgentTypes, globalHTTPPrefix = '') => {
2
2
  return `import { pikkuSessionlessFunc, defineHTTPRoutes, wireHTTPRoutes, addon, wireAddon } from '${pathToPikkuTypes}'
3
3
 
4
4
  export const pikkuConsoleSetSecret = pikkuSessionlessFunc<{
@@ -98,6 +98,6 @@ export const consoleRoutes = defineHTTPRoutes({
98
98
  })
99
99
 
100
100
  wireAddon({ name: 'console', package: '@pikku/addon-console' })
101
- wireHTTPRoutes({ basePath: '/api', routes: { console: consoleRoutes } })
101
+ wireHTTPRoutes({ basePath: '${globalHTTPPrefix}', routes: { console: consoleRoutes } })
102
102
  `;
103
103
  };
@@ -20,11 +20,33 @@ export const serializeMiddlewareImports = (outputPath, middlewareState, httpStat
20
20
  const channelMiddlewareFactories = fullState
21
21
  ? collectFactories(fullState.channelMiddleware.tagMiddleware, outputPath, packageMappings)
22
22
  : new Map();
23
+ // Collect direct (non-factory) side-effect imports
24
+ const directImports = new Set();
25
+ const collectDirectImports = (groupMap) => {
26
+ for (const [, groupMeta] of groupMap.entries()) {
27
+ if (!groupMeta.isFactory) {
28
+ const filePath = getFileImportRelativePath(outputPath, groupMeta.sourceFile, packageMappings);
29
+ directImports.add(filePath);
30
+ }
31
+ }
32
+ };
33
+ collectDirectImports(httpState.routeMiddleware);
34
+ collectDirectImports(middlewareState.tagMiddleware);
35
+ if (fullState) {
36
+ collectDirectImports(fullState.channelMiddleware.tagMiddleware);
37
+ }
23
38
  const allFactories = new Map([
24
39
  ...httpFactories,
25
40
  ...tagFactories,
26
41
  ...channelMiddlewareFactories,
27
42
  ]);
43
+ // Add direct side-effect imports (non-factory addHTTPMiddleware / addMiddleware calls)
44
+ if (directImports.size > 0) {
45
+ serializedImports.push('/* Side-effect imports for direct middleware registration calls */');
46
+ for (const filePath of directImports) {
47
+ serializedImports.push(`import '${filePath}'`);
48
+ }
49
+ }
28
50
  if (allFactories.size > 0) {
29
51
  serializedImports.push('/* Call middleware group factories to register at module evaluation */');
30
52
  for (const [exportName, { filePath }] of allFactories) {
@@ -24,8 +24,30 @@ export const serializePermissionsImports = (outputPath, permissionsState, httpSt
24
24
  });
25
25
  }
26
26
  }
27
+ // Collect direct (non-factory) side-effect imports for HTTP permission groups
28
+ const directImports = new Set();
29
+ for (const [, groupMeta] of httpState.routePermissions.entries()) {
30
+ if (!groupMeta.isFactory) {
31
+ const filePath = getFileImportRelativePath(outputPath, groupMeta.sourceFile, packageMappings);
32
+ directImports.add(filePath);
33
+ }
34
+ }
35
+ // Collect direct (non-factory) side-effect imports for tag permission groups
36
+ for (const [, groupMeta] of permissionsState.tagPermissions.entries()) {
37
+ if (!groupMeta.isFactory) {
38
+ const filePath = getFileImportRelativePath(outputPath, groupMeta.sourceFile, packageMappings);
39
+ directImports.add(filePath);
40
+ }
41
+ }
27
42
  // Combine all factories and deduplicate by exportName (same factory might be used in multiple groups)
28
43
  const allFactories = new Map([...httpFactories, ...tagFactories]);
44
+ // Add direct side-effect imports (non-factory addPermission calls)
45
+ if (directImports.size > 0) {
46
+ serializedImports.push('/* Side-effect imports for direct addPermission calls */');
47
+ for (const filePath of directImports) {
48
+ serializedImports.push(`import '${filePath}'`);
49
+ }
50
+ }
29
51
  // Add factory imports and calls
30
52
  if (allFactories.size > 0) {
31
53
  serializedImports.push('/* Call permission group factories to register at module evaluation */');
@@ -7,7 +7,7 @@ export const pikkuPublicRPC = pikkuSessionlessFunc({
7
7
  func: async ({ logger, config }) => {
8
8
  if (config.scaffold?.rpc) {
9
9
  const pathToPikkuTypes = getFileImportRelativePath(config.publicRpcFile, config.typesDeclarationFile, config.packageMappings);
10
- await writeFileInDir(logger, config.publicRpcFile, serializePublicRPC(pathToPikkuTypes, config.scaffold.rpc === 'auth'));
10
+ await writeFileInDir(logger, config.publicRpcFile, serializePublicRPC(pathToPikkuTypes, config.scaffold.rpc === 'auth', config.globalHTTPPrefix || ''));
11
11
  return true;
12
12
  }
13
13
  return false;
@@ -16,7 +16,7 @@ export const pikkuRPCClient = pikkuSessionlessFunc({
16
16
  return;
17
17
  }
18
18
  const rpcMapDeclarationPath = getFileImportRelativePath(rpcWiringsFile, rpcMapDeclarationFile, packageMappings);
19
- const content = [serializeRPCWrapper(rpcMapDeclarationPath)];
19
+ const content = [serializeRPCWrapper(rpcMapDeclarationPath, config.globalHTTPPrefix || '')];
20
20
  await writeFileInDir(logger, rpcWiringsFile, content.join('\n'));
21
21
  },
22
22
  middleware: [
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * Generate public RPC HTTP endpoint
3
3
  */
4
- export declare const serializePublicRPC: (pathToPikkuTypes: string, requireAuth?: boolean) => string;
4
+ export declare const serializePublicRPC: (pathToPikkuTypes: string, requireAuth?: boolean, globalHTTPPrefix?: string) => string;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Generate public RPC HTTP endpoint
3
3
  */
4
- export const serializePublicRPC = (pathToPikkuTypes, requireAuth = true) => {
4
+ export const serializePublicRPC = (pathToPikkuTypes, requireAuth = true, globalHTTPPrefix = '') => {
5
5
  const authFlag = requireAuth ? 'true' : 'false';
6
6
  return `/**
7
7
  * Auto-generated public RPC HTTP endpoint
@@ -25,7 +25,7 @@ export const workflowCaller = pikkuSessionlessFunc<
25
25
  >({
26
26
  auth: ${authFlag},
27
27
  func: async (_services, { workflowName, input }, { rpc }) => {
28
- return await rpc.startWorkflow(workflowName, input || {})
28
+ return await (rpc.startWorkflow as Function)(workflowName, input || {})
29
29
  },
30
30
  })
31
31
 
@@ -34,12 +34,12 @@ export const rpcRoutes = defineHTTPRoutes({
34
34
  tags: ['pikku:public'],
35
35
  routes: {
36
36
  rpc: {
37
- route: '/rpc/:rpcName',
37
+ route: '${globalHTTPPrefix}/rpc/:rpcName',
38
38
  method: 'post',
39
39
  func: rpcCaller,
40
40
  },
41
41
  workflow: {
42
- route: '/rpc/workflow/:workflowName',
42
+ route: '${globalHTTPPrefix}/rpc/workflow/:workflowName',
43
43
  method: 'post',
44
44
  func: workflowCaller,
45
45
  },
@@ -1 +1 @@
1
- export declare const serializeRPCWrapper: (rpcMapPath: string) => string;
1
+ export declare const serializeRPCWrapper: (rpcMapPath: string, globalHTTPPrefix?: string) => string;
@@ -1,4 +1,4 @@
1
- export const serializeRPCWrapper = (rpcMapPath) => {
1
+ export const serializeRPCWrapper = (rpcMapPath, globalHTTPPrefix = '') => {
2
2
  return `
3
3
  import { PikkuFetch } from "./pikku-fetch.gen.js"
4
4
  import type { RPCInvoke, TypedAgentRun, TypedStartWorkflow } from '${rpcMapPath}'
@@ -59,7 +59,7 @@ export class PikkuRPC {
59
59
  * @returns A promise that resolves with the function's return value
60
60
  */
61
61
  invoke: RPCInvoke = async (rpcName, data) => {
62
- return await this.pikkuFetch.post(\`/rpc/\${String(rpcName)}\` as never, { rpcName: String(rpcName), data }) as any
62
+ return await this.pikkuFetch.post(\`${globalHTTPPrefix}/rpc/\${String(rpcName)}\` as never, { rpcName: String(rpcName), data }) as any
63
63
  }
64
64
 
65
65
  /**
@@ -71,7 +71,7 @@ export class PikkuRPC {
71
71
  * @returns A promise that resolves with the new run ID
72
72
  */
73
73
  startWorkflow: TypedStartWorkflow = async (workflowName, input) => {
74
- return await this.pikkuFetch.post(\`/rpc/workflow/\${String(workflowName)}\` as never, { workflowName: String(workflowName), input }) as any
74
+ return await this.pikkuFetch.post(\`${globalHTTPPrefix}/rpc/workflow/\${String(workflowName)}\` as never, { workflowName: String(workflowName), input }) as any
75
75
  }
76
76
 
77
77
  /**
@@ -87,7 +87,7 @@ export class PikkuRPC {
87
87
  * @returns A promise with runId, result, and token usage
88
88
  */
89
89
  run: (async (agentName, input) => {
90
- return await this.pikkuFetch.post(\`/rpc/agent/\${String(agentName)}\` as never, input) as any
90
+ return await this.pikkuFetch.post(\`${globalHTTPPrefix}/rpc/agent/\${String(agentName)}\` as never, input) as any
91
91
  }) as TypedAgentRun,
92
92
  /**
93
93
  * Streams agent responses via SSE. Used for real-time chat interfaces.
@@ -96,7 +96,7 @@ export class PikkuRPC {
96
96
  * @param input - The agent input (message, threadId, resourceId)
97
97
  */
98
98
  stream: async (agentName: string, input: Record<string, unknown>) => {
99
- return await this.pikkuFetch.post(\`/rpc/agent/\${String(agentName)}/stream\` as never, input) as any
99
+ return await this.pikkuFetch.post(\`${globalHTTPPrefix}/rpc/agent/\${String(agentName)}/stream\` as never, input) as any
100
100
  },
101
101
  /**
102
102
  * Approves or denies pending tool calls for an agent run.
@@ -105,7 +105,7 @@ export class PikkuRPC {
105
105
  * @param input - The approval payload (runId, approvals array)
106
106
  */
107
107
  approve: async (agentName: string, input: Record<string, unknown>) => {
108
- return await this.pikkuFetch.post(\`/rpc/agent/\${String(agentName)}/approve\` as never, input) as any
108
+ return await this.pikkuFetch.post(\`${globalHTTPPrefix}/rpc/agent/\${String(agentName)}/approve\` as never, input) as any
109
109
  },
110
110
  }
111
111
  }
@@ -16,18 +16,25 @@ import type { PikkuWorkflowWire, WorkflowStepOptions } from '@pikku/core/workflo
16
16
 
17
17
  export { WorkflowCancelledException }
18
18
  import type { PikkuFunctionSessionless, PikkuFunctionConfig } from '${functionTypesImportPath}'
19
- import type { RPCMap, FlattenedRPCMap } from '${rpcMapImportPath}'
19
+ import type { FlattenedRPCMap } from '${rpcMapImportPath}'
20
20
  import type { WorkflowMap, GraphsMap } from '${workflowMapImportPath}'
21
21
 
22
22
  export { template }
23
23
 
24
24
  export interface TypedWorkflow extends PikkuWorkflowWire {
25
- do<K extends keyof RPCMap>(
25
+ do<K extends keyof FlattenedRPCMap>(
26
26
  stepName: string,
27
27
  rpcName: K,
28
- data: RPCMap[K]['input'],
28
+ data: FlattenedRPCMap[K]['input'],
29
29
  options?: WorkflowStepOptions
30
- ): Promise<RPCMap[K]['output']>
30
+ ): Promise<FlattenedRPCMap[K]['output']>
31
+
32
+ do<K extends keyof WorkflowMap>(
33
+ stepName: string,
34
+ workflowName: K,
35
+ data: WorkflowMap[K]['input'],
36
+ options?: WorkflowStepOptions
37
+ ): Promise<WorkflowMap[K]['output']>
31
38
 
32
39
  do<T>(
33
40
  stepName: string,
@@ -36,24 +43,73 @@ export interface TypedWorkflow extends PikkuWorkflowWire {
36
43
  ): Promise<T>
37
44
  }
38
45
 
46
+ import type { StandardSchemaV1 } from '@standard-schema/spec'
47
+ import type { InferSchemaOutput, PikkuPermission, PikkuMiddleware, NodeConfig, PikkuApprovalDescription } from '${functionTypesImportPath}'
48
+ import { PikkuError } from '@pikku/core/errors'
49
+ import type { CorePermissionGroup } from '@pikku/core'
50
+
39
51
  export type PikkuFunctionWorkflow<
40
52
  In = unknown,
41
53
  Out = never
42
54
  > = PikkuFunctionSessionless<In, Out, 'workflow'>
43
55
 
44
- export const pikkuWorkflowFunc = <In, Out = unknown>(
56
+ export type PikkuWorkflowConfigWithSchema<
57
+ InputSchema extends StandardSchemaV1 | undefined = undefined,
58
+ OutputSchema extends StandardSchemaV1 | undefined = undefined
59
+ > = {
60
+ title?: string
61
+ description?: string
62
+ tags?: string[]
63
+ expose?: boolean
64
+ internal?: boolean
65
+ override?: string
66
+ version?: number
67
+ remote?: boolean
68
+ mcp?: boolean
69
+ readonly?: boolean
70
+ approvalRequired?: boolean
71
+ approvalDescription?: InputSchema extends StandardSchemaV1 ? PikkuApprovalDescription<InferSchemaOutput<InputSchema>> : never
72
+ func: PikkuFunctionWorkflow<
73
+ InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown,
74
+ OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown
75
+ >
76
+ auth?: boolean
77
+ permissions?: InputSchema extends StandardSchemaV1 ? CorePermissionGroup<PikkuPermission<InferSchemaOutput<InputSchema>>> : undefined
78
+ middleware?: PikkuMiddleware[]
79
+ input?: InputSchema
80
+ output?: OutputSchema
81
+ node?: NodeConfig
82
+ errors?: Array<typeof PikkuError>
83
+ inline?: boolean
84
+ }
85
+
86
+ export function pikkuWorkflowFunc<
87
+ InputSchema extends StandardSchemaV1 | undefined = undefined,
88
+ OutputSchema extends StandardSchemaV1 | undefined = undefined
89
+ >(
90
+ config: PikkuWorkflowConfigWithSchema<InputSchema, OutputSchema>
91
+ ): PikkuFunctionConfig<InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown, OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown, 'workflow', PikkuFunctionWorkflow<InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown, OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown>, InputSchema, OutputSchema>
92
+ export function pikkuWorkflowFunc<In, Out = unknown>(
45
93
  func:
46
94
  | PikkuFunctionWorkflow<In, Out>
47
95
  | PikkuFunctionConfig<In, Out, 'workflow', PikkuFunctionWorkflow<In, Out>>
48
- ) => {
96
+ ): PikkuFunctionConfig<In, Out, 'workflow'>
97
+ export function pikkuWorkflowFunc(func: any) {
49
98
  return typeof func === 'function' ? { func } : func
50
99
  }
51
100
 
52
- export const pikkuWorkflowComplexFunc = <In, Out = unknown>(
101
+ export function pikkuWorkflowComplexFunc<
102
+ InputSchema extends StandardSchemaV1 | undefined = undefined,
103
+ OutputSchema extends StandardSchemaV1 | undefined = undefined
104
+ >(
105
+ config: PikkuWorkflowConfigWithSchema<InputSchema, OutputSchema>
106
+ ): PikkuFunctionConfig<InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown, OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown, 'workflow', PikkuFunctionWorkflow<InputSchema extends StandardSchemaV1 ? InferSchemaOutput<InputSchema> : unknown, OutputSchema extends StandardSchemaV1 ? InferSchemaOutput<OutputSchema> : unknown>, InputSchema, OutputSchema>
107
+ export function pikkuWorkflowComplexFunc<In, Out = unknown>(
53
108
  func:
54
109
  | PikkuFunctionWorkflow<In, Out>
55
110
  | PikkuFunctionConfig<In, Out, 'workflow', PikkuFunctionWorkflow<In, Out>>
56
- ) => {
111
+ ): PikkuFunctionConfig<In, Out, 'workflow'>
112
+ export function pikkuWorkflowComplexFunc(func: any) {
57
113
  return typeof func === 'function' ? { func } : func
58
114
  }
59
115
 
@@ -215,13 +215,16 @@ export const createSingletonServices = async (config) => {
215
215
  }
216
216
  }
217
217
  const manifest = !setupOnly
218
- ? ((await loadManifest(join(config.outDir, 'versions.json'))) ??
218
+ ? ((await loadManifest(join(config.rootDir, 'versions.pikku.json'))) ??
219
219
  undefined)
220
220
  : undefined;
221
+ const oldProgram = unfilteredState?.program ?? undefined;
222
+ const inspectStart = Date.now();
221
223
  unfilteredState = await inspect(logger, wiringFiles, {
222
224
  setupOnly,
223
225
  rootDir,
224
226
  isAddon: !!config.addon,
227
+ oldProgram,
225
228
  types: {
226
229
  configFileType: config.configFile,
227
230
  userSessionType: config.userSessionType,
@@ -248,6 +251,7 @@ export const createSingletonServices = async (config) => {
248
251
  }
249
252
  : undefined,
250
253
  });
254
+ logger.debug(`Inspector took ${Date.now() - inspectStart}ms`);
251
255
  if ('diagnostics' in unfilteredState &&
252
256
  unfilteredState.diagnostics.length > 0) {
253
257
  processDiagnostics(unfilteredState.diagnostics, config.lint);