@pikku/cli 0.12.127 → 0.12.128

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 (150) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/dist/.pikku/addon/index.d.ts +1 -1
  3. package/dist/.pikku/addon/index.js +1 -1
  4. package/dist/.pikku/addon/pikku-addon-types.gen.d.ts +1 -1
  5. package/dist/.pikku/addon/pikku-addon-types.gen.js +1 -1
  6. package/dist/.pikku/agent/index.d.ts +1 -1
  7. package/dist/.pikku/agent/index.js +1 -1
  8. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  9. package/dist/.pikku/agent/pikku-model-aliases.gen.js +1 -1
  10. package/dist/.pikku/auth/index.d.ts +1 -1
  11. package/dist/.pikku/auth/index.js +1 -1
  12. package/dist/.pikku/auth/pikku-auth-types.gen.d.ts +1 -1
  13. package/dist/.pikku/auth/pikku-auth-types.gen.js +1 -1
  14. package/dist/.pikku/channel/index.d.ts +1 -1
  15. package/dist/.pikku/channel/index.js +1 -1
  16. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  17. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  18. package/dist/.pikku/cli/index.d.ts +1 -1
  19. package/dist/.pikku/cli/index.js +1 -1
  20. package/dist/.pikku/cli/pikku-cli-channel.js +11 -1
  21. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  22. package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
  23. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.d.ts +1 -1
  24. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
  25. package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.json +21 -0
  26. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  27. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  28. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  29. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +37 -1
  30. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  31. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  32. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  33. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  34. package/dist/.pikku/error/index.d.ts +1 -1
  35. package/dist/.pikku/error/index.js +1 -1
  36. package/dist/.pikku/error/pikku-error-types.gen.d.ts +1 -1
  37. package/dist/.pikku/error/pikku-error-types.gen.js +1 -1
  38. package/dist/.pikku/function/index.d.ts +1 -1
  39. package/dist/.pikku/function/index.js +1 -1
  40. package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
  41. package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
  42. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  43. package/dist/.pikku/function/pikku-functions-meta.gen.json +42 -6
  44. package/dist/.pikku/function/pikku-functions.gen.js +1 -1
  45. package/dist/.pikku/gateway/index.d.ts +1 -1
  46. package/dist/.pikku/gateway/index.js +1 -1
  47. package/dist/.pikku/gateway/pikku-gateway-types.gen.d.ts +1 -1
  48. package/dist/.pikku/gateway/pikku-gateway-types.gen.js +1 -1
  49. package/dist/.pikku/http/index.d.ts +1 -1
  50. package/dist/.pikku/http/index.js +1 -1
  51. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  52. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  53. package/dist/.pikku/mcp/index.d.ts +1 -1
  54. package/dist/.pikku/mcp/index.js +1 -1
  55. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  56. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  57. package/dist/.pikku/middleware/index.d.ts +1 -1
  58. package/dist/.pikku/middleware/index.js +1 -1
  59. package/dist/.pikku/middleware/pikku-middleware-types.gen.d.ts +1 -1
  60. package/dist/.pikku/middleware/pikku-middleware-types.gen.js +1 -1
  61. package/dist/.pikku/pikku-bootstrap-scenarios.gen.d.ts +1 -1
  62. package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +1 -1
  63. package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
  64. package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
  65. package/dist/.pikku/pikku-services.gen.d.ts +1 -1
  66. package/dist/.pikku/queue/index.d.ts +1 -1
  67. package/dist/.pikku/queue/index.js +1 -1
  68. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  69. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  70. package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
  71. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
  72. package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
  73. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  74. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +2 -0
  75. package/dist/.pikku/scenarios/index.d.ts +1 -1
  76. package/dist/.pikku/scenarios/index.js +1 -1
  77. package/dist/.pikku/scenarios/pikku-personas.gen.js +1 -1
  78. package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
  79. package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
  80. package/dist/.pikku/scenarios/pikku-scenario-types.gen.d.ts +1 -1
  81. package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
  82. package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
  83. package/dist/.pikku/scenarios/schemas/register.gen.d.ts +1 -1
  84. package/dist/.pikku/scenarios/schemas/register.gen.js +1 -1
  85. package/dist/.pikku/scheduler/index.d.ts +1 -1
  86. package/dist/.pikku/scheduler/index.js +1 -1
  87. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  88. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  89. package/dist/.pikku/schemas/register.gen.js +7 -1
  90. package/dist/.pikku/schemas/schemas/FabricSecretsDeleteInput.schema.json +1 -0
  91. package/dist/.pikku/schemas/schemas/FabricSecretsDeleteOutput.schema.json +1 -0
  92. package/dist/.pikku/schemas/schemas/PikkuDistInput.schema.json +1 -0
  93. package/dist/.pikku/schemas/schemas/PikkuNewAddonInput.schema.json +1 -1
  94. package/dist/.pikku/scopes/index.d.ts +1 -1
  95. package/dist/.pikku/scopes/index.js +1 -1
  96. package/dist/.pikku/scopes/pikku-personas.gen.js +1 -1
  97. package/dist/.pikku/scopes/pikku-roles.gen.d.ts +1 -1
  98. package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
  99. package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
  100. package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
  101. package/dist/.pikku/secrets/index.d.ts +1 -1
  102. package/dist/.pikku/secrets/index.js +1 -1
  103. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  104. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  105. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  106. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  107. package/dist/.pikku/services/pikku-meta-service.gen.d.ts +1 -1
  108. package/dist/.pikku/services/pikku-meta-service.gen.js +1 -1
  109. package/dist/.pikku/setup/index.d.ts +1 -1
  110. package/dist/.pikku/setup/index.js +1 -1
  111. package/dist/.pikku/setup/pikku-setup-types.gen.d.ts +1 -1
  112. package/dist/.pikku/setup/pikku-setup-types.gen.js +1 -1
  113. package/dist/.pikku/trigger/index.d.ts +1 -1
  114. package/dist/.pikku/trigger/index.js +1 -1
  115. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  116. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  117. package/dist/.pikku/variables/index.d.ts +1 -1
  118. package/dist/.pikku/variables/index.js +1 -1
  119. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  120. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  121. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  122. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  123. package/dist/.pikku/workflow/index.d.ts +1 -1
  124. package/dist/.pikku/workflow/index.js +1 -1
  125. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
  126. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
  127. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  128. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  129. package/dist/bin/pikku-bin.mjs +2 -2
  130. package/dist/src/cli.wiring.js +16 -1
  131. package/dist/src/fabric/fabric-commands.d.ts +25 -0
  132. package/dist/src/fabric/fabric-commands.js +13 -0
  133. package/dist/src/fabric/functions/secrets-delete.function.d.ts +36 -0
  134. package/dist/src/fabric/functions/secrets-delete.function.js +51 -0
  135. package/dist/src/functions/commands/dev.js +2 -1
  136. package/dist/src/functions/commands/dist.d.ts +28 -0
  137. package/dist/src/functions/commands/dist.js +58 -0
  138. package/dist/src/functions/commands/new-addon.d.ts +30 -0
  139. package/dist/src/functions/commands/new-addon.js +81 -3
  140. package/dist/src/functions/commands/persona-sync.d.ts +5 -4
  141. package/dist/src/functions/commands/persona-sync.js +6 -5
  142. package/dist/src/functions/commands/persona.js +6 -2
  143. package/dist/src/functions/validate/auth-plugin-checks.js +3 -2
  144. package/dist/src/functions/validate/persona-checks.js +2 -1
  145. package/dist/src/utils/persona-credentials.d.ts +0 -2
  146. package/dist/src/utils/persona-credentials.js +1 -8
  147. package/dist/tsconfig.tsbuildinfo +1 -1
  148. package/package.json +5 -5
  149. package/snippets.json +1 -1
  150. package/surface.json +1292 -4907
@@ -1,4 +1,4 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.127
2
+ * This file was generated by @pikku/cli@0.12.128
3
3
  */
4
4
  export { defineVariable } from '@pikku/core/variable';
@@ -1,4 +1,4 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.127
2
+ * This file was generated by @pikku/cli@0.12.128
3
3
  */
4
4
  export { defineVariable } from '@pikku/core/variable';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.127
2
+ * This file was generated by @pikku/cli@0.12.128
3
3
  */
4
4
  import { TypedVariablesService as CoreTypedVariablesService } from '@pikku/core/services';
5
5
  import type { VariablesService } from '@pikku/core/services';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.127
2
+ * This file was generated by @pikku/cli@0.12.128
3
3
  */
4
4
  import { TypedVariablesService as CoreTypedVariablesService, } from '@pikku/core/services';
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.127
2
+ * This file was generated by @pikku/cli@0.12.128
3
3
  */
4
4
  /**
5
5
  * Subpath entry — `#pikku/workflow` resolves here.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.127
2
+ * This file was generated by @pikku/cli@0.12.128
3
3
  */
4
4
  /**
5
5
  * Subpath entry — `#pikku/workflow` resolves here.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.127
2
+ * This file was generated by @pikku/cli@0.12.128
3
3
  */
4
4
  import { WorkflowCancelledException } from '@pikku/core/workflow';
5
5
  import type { PikkuWorkflowGraphConfig, PikkuWorkflowGraphResult } from '@pikku/core/workflow';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.127
2
+ * This file was generated by @pikku/cli@0.12.128
3
3
  */
4
4
  import { WorkflowCancelledException } from '@pikku/core/workflow';
5
5
  import { pikkuWorkflowGraph as corePikkuWorkflowGraph } from '@pikku/core/workflow';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.127
2
+ * This file was generated by @pikku/cli@0.12.128
3
3
  */
4
4
  import { pikkuState } from '@pikku/core/state';
5
5
  import allWorkflowMeta from './meta/allWorkflow.gen.json' with { type: 'json' };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This file was generated by @pikku/cli@0.12.127
2
+ * This file was generated by @pikku/cli@0.12.128
3
3
  */
4
4
  import { addWorkflow } from '@pikku/core/workflow';
5
5
  import './pikku-workflow-wirings-meta.gen.js';
@@ -11,8 +11,8 @@ async function checkForUpdate() {
11
11
  })
12
12
  if (!res.ok) return
13
13
  const { version: latest } = await res.json()
14
- if (latest !== '0.12.127') {
15
- process.stderr.write(`\n Update available 0.12.127 → ${latest}\n brew upgrade pikku or npm install -g @pikku/cli\n\n`)
14
+ if (latest !== '0.12.128') {
15
+ process.stderr.write(`\n Update available 0.12.128 → ${latest}\n brew upgrade pikku or npm install -g @pikku/cli\n\n`)
16
16
  }
17
17
  } catch {}
18
18
  }
@@ -12,6 +12,7 @@ import { pikkuCLICommand, wireCLI } from '../.pikku/cli/pikku-cli-types.gen.js';
12
12
  import { fabricCommands } from './fabric/fabric-commands.js';
13
13
  import { all } from './functions/commands/all.js';
14
14
  import { bootstrap } from './functions/commands/bootstrap.js';
15
+ import { pikkuDist } from './functions/commands/dist.js';
15
16
  import { watch } from './functions/commands/watch.js';
16
17
  import { login, logout, whoami } from './functions/commands/login.js';
17
18
  import { dev } from './functions/commands/dev.js';
@@ -231,6 +232,16 @@ wireCLI({
231
232
  func: bootstrap,
232
233
  description: 'Generate only type files (setup phase only)',
233
234
  }),
235
+ dist: pikkuCLICommand({
236
+ func: pikkuDist,
237
+ description: "Copy the generated files tsc cannot emit — the .gen.json meta, and hand-authored .d.ts — into the build output. Run it after tsc, as a package's build script",
238
+ options: {
239
+ distDir: {
240
+ description: "Where to copy to. Defaults to the tsconfig's compilerOptions.outDir",
241
+ type: 'string',
242
+ },
243
+ },
244
+ }),
234
245
  audit: pikkuCLICommand({
235
246
  func: pikkuAudit,
236
247
  description: 'Audit dependencies for security advisories (always) and available updates (--outdated); writes .pikku/audit.json',
@@ -635,7 +646,7 @@ wireCLI({
635
646
  }),
636
647
  sync: pikkuCLICommand({
637
648
  func: personaSync,
638
- description: "Report which personas an environment will provision, with which roles, and why any of them were skipped. The provisioning itself happens in the deployment — call provisionPersonas from '@pikku/better-auth' in your server lifecycle — because the CLI has no connection to a deployed environment's database.",
649
+ description: "Report which personas an environment will provision, with which roles, and why any of them were skipped. The provisioning itself happens in the deployment — pass the generated personas to pikkuFabric from '@pikku/better-auth' — because the CLI has no connection to a deployed environment's database.",
639
650
  parameters: '<environment>',
640
651
  }),
641
652
  list: pikkuCLICommand({
@@ -829,6 +840,10 @@ wireCLI({
829
840
  description: 'Convert snake_case property names to camelCase in generated Zod schemas',
830
841
  default: false,
831
842
  },
843
+ build: {
844
+ description: 'Install and build the generated addon (an unbuilt addon exports a dist/ that does not exist yet, so every ref() into it is dead at runtime)',
845
+ default: true,
846
+ },
832
847
  },
833
848
  }),
834
849
  },
@@ -611,6 +611,31 @@ export declare const fabricCommands: {
611
611
  updatedAt: string;
612
612
  }[];
613
613
  }, "rpc" | "session", import("../../.pikku/function/pikku-function-types.gen.js").WiredServices>, undefined, undefined>, import("../../.pikku/middleware/pikku-middleware-types.gen.js").PikkuMiddleware, (services: import("../../types/application-types.js").SingletonServices, data: any, session?: import("../../types/application-types.js").UserSession | undefined) => void | Promise<void>, string>;
614
+ delete: import("@pikku/core/cli").CoreCLICommandConfig<import("../../.pikku/function/pikku-function-types.gen.js").PikkuFunctionConfig<{
615
+ name: string;
616
+ branch?: string | undefined;
617
+ force?: boolean | undefined;
618
+ }, {
619
+ name: string;
620
+ runId: string | null;
621
+ deploymentId: string | null;
622
+ }, "rpc" | "session", import("../../.pikku/function/pikku-function-types.gen.js").PikkuFunctionSessionless<{
623
+ name: string;
624
+ branch?: string | undefined;
625
+ force?: boolean | undefined;
626
+ }, {
627
+ name: string;
628
+ runId: string | null;
629
+ deploymentId: string | null;
630
+ }, "rpc" | "session", import("../../.pikku/function/pikku-function-types.gen.js").WiredServices, unknown> | import("../../.pikku/function/pikku-function-types.gen.js").PikkuFunction<{
631
+ name: string;
632
+ branch?: string | undefined;
633
+ force?: boolean | undefined;
634
+ }, {
635
+ name: string;
636
+ runId: string | null;
637
+ deploymentId: string | null;
638
+ }, "rpc" | "session", import("../../.pikku/function/pikku-function-types.gen.js").WiredServices>, undefined, undefined>, import("../../.pikku/middleware/pikku-middleware-types.gen.js").PikkuMiddleware, (services: import("../../types/application-types.js").SingletonServices, data: any, session?: import("../../types/application-types.js").UserSession | undefined) => void | Promise<void>, string>;
614
639
  rotate: import("@pikku/core/cli").CoreCLICommandConfig<import("../../.pikku/function/pikku-function-types.gen.js").PikkuFunctionConfig<{
615
640
  branch?: string | undefined;
616
641
  force?: boolean | undefined;
@@ -32,6 +32,7 @@ import { FabricDbSchema, renderDbSchema, } from './functions/db-schema.function.
32
32
  import { FabricRollback } from './functions/rollback.function.js';
33
33
  import { FabricSecretsSet } from './functions/secrets-set.function.js';
34
34
  import { FabricSecretsList } from './functions/secrets-list.function.js';
35
+ import { FabricSecretsDelete } from './functions/secrets-delete.function.js';
35
36
  import { FabricSecretsRotate } from './functions/secrets-rotate.function.js';
36
37
  import { FabricVariablesSet } from './functions/variables-set.function.js';
37
38
  import { FabricVariablesGet } from './functions/variables-get.function.js';
@@ -254,6 +255,18 @@ export const fabricCommands = defineCLICommands({
254
255
  json: { description: 'Machine-readable output', default: false },
255
256
  },
256
257
  }),
258
+ delete: pikkuCLICommand({
259
+ parameters: '<name>',
260
+ func: FabricSecretsDelete,
261
+ description: 'Delete a single stage-scoped secret',
262
+ options: {
263
+ branch: { description: 'Target branch', short: 'b' },
264
+ force: {
265
+ description: 'Delete without confirmation',
266
+ default: false,
267
+ },
268
+ },
269
+ }),
257
270
  rotate: pikkuCLICommand({
258
271
  func: FabricSecretsRotate,
259
272
  description: "Retire a stage's sealing key (secrets must be set again)",
@@ -0,0 +1,36 @@
1
+ import { z } from 'zod';
2
+ export declare const FabricSecretsDeleteInput: z.ZodObject<{
3
+ name: z.ZodString;
4
+ branch: z.ZodOptional<z.ZodString>;
5
+ force: z.ZodOptional<z.ZodBoolean>;
6
+ }, z.core.$strip>;
7
+ export declare const FabricSecretsDeleteOutput: z.ZodObject<{
8
+ name: z.ZodString;
9
+ runId: z.ZodNullable<z.ZodString>;
10
+ deploymentId: z.ZodNullable<z.ZodString>;
11
+ }, z.core.$strip>;
12
+ export declare const FabricSecretsDelete: import("../../../.pikku/function/pikku-function-types.gen.js").PikkuFunctionConfig<{
13
+ name: string;
14
+ branch?: string | undefined;
15
+ force?: boolean | undefined;
16
+ }, {
17
+ name: string;
18
+ runId: string | null;
19
+ deploymentId: string | null;
20
+ }, "rpc" | "session", import("../../../.pikku/function/pikku-function-types.gen.js").PikkuFunctionSessionless<{
21
+ name: string;
22
+ branch?: string | undefined;
23
+ force?: boolean | undefined;
24
+ }, {
25
+ name: string;
26
+ runId: string | null;
27
+ deploymentId: string | null;
28
+ }, "rpc" | "session", import("../../../.pikku/function/pikku-function-types.gen.js").WiredServices, unknown> | import("../../../.pikku/function/pikku-function-types.gen.js").PikkuFunction<{
29
+ name: string;
30
+ branch?: string | undefined;
31
+ force?: boolean | undefined;
32
+ }, {
33
+ name: string;
34
+ runId: string | null;
35
+ deploymentId: string | null;
36
+ }, "rpc" | "session", import("../../../.pikku/function/pikku-function-types.gen.js").WiredServices>, undefined, undefined>;
@@ -0,0 +1,51 @@
1
+ import { z } from 'zod';
2
+ import { pikkuSessionlessFunc } from '../../../.pikku/function/index.js';
3
+ import { resolveApiContext } from '../lib/config.js';
4
+ import { getFabricRPC } from '../lib/http.js';
5
+ import { promptConfirm } from '../lib/prompt.js';
6
+ import { resolveStage } from '../lib/stage.js';
7
+ export const FabricSecretsDeleteInput = z.object({
8
+ name: z.string(),
9
+ branch: z.string().optional(),
10
+ force: z.boolean().optional(),
11
+ });
12
+ export const FabricSecretsDeleteOutput = z.object({
13
+ name: z.string(),
14
+ runId: z.string().nullable(),
15
+ deploymentId: z.string().nullable(),
16
+ });
17
+ export const FabricSecretsDelete = pikkuSessionlessFunc({
18
+ description: 'Remove a single stage-scoped secret. Unlike `secrets rotate`, the rest of the stage keeps its sealing key and its other secrets.',
19
+ input: FabricSecretsDeleteInput,
20
+ output: FabricSecretsDeleteOutput,
21
+ func: async (_services, { name, branch: requested, force }) => {
22
+ const ctx = await resolveApiContext();
23
+ if (!ctx.token)
24
+ throw new Error('Not logged in. Run `pikku fabric login` first.');
25
+ if (!ctx.projectId)
26
+ throw new Error('No fabric project linked. Run `pikku fabric link` first.');
27
+ // Resolved before the prompt so the confirmation names the stage that
28
+ // would actually lose the secret, not an argument that may be absent.
29
+ const rpc = getFabricRPC({ apiUrl: ctx.apiUrl, token: ctx.token });
30
+ const { stageId, branch } = await resolveStage(rpc, ctx.projectId, requested);
31
+ if (!force) {
32
+ if (!process.stdin.isTTY) {
33
+ throw new Error(`Refusing to delete ${name} from ${branch} without confirmation — re-run with --force to delete non-interactively.`);
34
+ }
35
+ // Fabric cannot read the sealed value back, so this is not recoverable
36
+ // by re-reading it — the plaintext has to be supplied again.
37
+ if (!(await promptConfirm(`Delete ${name} from ${branch}? It cannot be recovered — the value must be set again.`))) {
38
+ throw new Error('Delete aborted.');
39
+ }
40
+ }
41
+ const result = await rpc.invoke('deleteStageSecret', { stageId, name });
42
+ console.log(`[fabric] deleted ${result.name} from ${branch}`);
43
+ if (result.runId) {
44
+ console.log(`[fabric] republishing the stage as run ${result.runId} — units serve the old value until it lands`);
45
+ }
46
+ else {
47
+ console.log('[fabric] deploy the stage to stop its units serving the old value');
48
+ }
49
+ return result;
50
+ },
51
+ });
@@ -4,7 +4,7 @@ import { pikkuSessionlessFunc } from '#pikku/function';
4
4
  import chokidar from 'chokidar';
5
5
  import { pikkuDevReloader, reloadGeneratedMeta, reconcileAddonRegistry, } from '@pikku/core/dev';
6
6
  import { InMemoryQueueService, QueueWebhookService } from '@pikku/core/services';
7
- import { ConsoleLogger, LocalEmailService, spy, InMemoryAgentRunStateService, } from '@pikku/core/services';
7
+ import { ConsoleLogger, LocalEmailService, LocalCredentialService, spy, InMemoryAgentRunStateService, } from '@pikku/core/services';
8
8
  import { InMemoryTriggerService } from '@pikku/core/services';
9
9
  import { InMemoryWorkflowService } from '@pikku/core/services';
10
10
  import { KyselyAgentStorageService, KyselyAgentRunStateService, KyselyAgentRunService, } from '@pikku/kysely';
@@ -230,6 +230,7 @@ export const dev = pikkuSessionlessFunc({
230
230
  workflowService,
231
231
  workflowRunService: workflowService,
232
232
  triggerService: new InMemoryTriggerService(),
233
+ credentialService: new LocalCredentialService(),
233
234
  agentStorage,
234
235
  agentRunState,
235
236
  agentRunService,
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Carry into the build output the files `tsc` compiles around but never emits.
3
+ *
4
+ * `tsc` turns the generated `.ts` under the pikku out dir into JavaScript, so
5
+ * that half arrives on its own. Two kinds of file do not:
6
+ *
7
+ * - the `*.gen.json` meta pikku writes beside them. `resolveJsonModule` lets
8
+ * TypeScript *read* a json, it never copies one to `outDir`, and the meta is
9
+ * read off disk at runtime — `MetaService` opens it by path — so a package
10
+ * that ships only tsc's output answers every meta lookup with nothing.
11
+ * - a hand-authored `.d.ts` such as `types/application-types.d.ts`. A
12
+ * declaration file is an input, and `declaration: true` does not re-emit it.
13
+ *
14
+ * Packages used to do this with `cp -r .pikku types dist/`, which also dumped
15
+ * every `.ts` source into the published output and needed a POSIX shell.
16
+ */
17
+ export type DistCopy = {
18
+ from: string;
19
+ to: string;
20
+ };
21
+ export declare const planDistCopies: (rootDir: string, distDir: string, files: string[]) => DistCopy[];
22
+ export declare const pikkuDist: import("#pikku/function").PikkuFunctionConfig<{
23
+ distDir?: string;
24
+ }, void, "rpc" | "session", import("#pikku/function").PikkuFunctionSessionless<{
25
+ distDir?: string;
26
+ }, void, "rpc" | "session", import("#pikku/function").WiredServices, unknown> | import("#pikku/function").PikkuFunction<{
27
+ distDir?: string;
28
+ }, void, "rpc" | "session", import("#pikku/function").WiredServices>, undefined, undefined>;
@@ -0,0 +1,58 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { cp, mkdir, readdir } from 'node:fs/promises';
3
+ import { dirname, join, relative, resolve } from 'node:path';
4
+ import ts from 'typescript';
5
+ import { pikkuSessionlessFunc } from '#pikku/function';
6
+ /**
7
+ * `tsc` compiles a `.ts` and emits it. Everything else it either reads without
8
+ * emitting — a `.d.ts` is an input, `declaration: true` does not re-emit one —
9
+ * or ignores entirely, like the generated json.
10
+ */
11
+ const tscEmitsIt = (file) => file.endsWith('.ts') && !file.endsWith('.d.ts');
12
+ const walk = async (dir) => {
13
+ if (!existsSync(dir)) {
14
+ return [];
15
+ }
16
+ const entries = await readdir(dir, { withFileTypes: true });
17
+ const files = await Promise.all(entries.map(async (entry) => {
18
+ const path = join(dir, entry.name);
19
+ return entry.isDirectory() ? walk(path) : [path];
20
+ }));
21
+ return files.flat();
22
+ };
23
+ export const planDistCopies = (rootDir, distDir, files) => {
24
+ return files
25
+ .filter((file) => !tscEmitsIt(file))
26
+ .map((from) => ({
27
+ from,
28
+ to: join(distDir, relative(rootDir, from)),
29
+ }));
30
+ };
31
+ const readTsOutDir = (tsconfig) => {
32
+ const parsed = ts.getParsedCommandLineOfConfigFile(tsconfig, {}, {
33
+ ...ts.sys,
34
+ onUnRecoverableConfigFileDiagnostic: () => { },
35
+ });
36
+ return parsed?.options.outDir;
37
+ };
38
+ export const pikkuDist = pikkuSessionlessFunc({
39
+ func: async ({ logger, config }, data) => {
40
+ const { rootDir, outDir, srcDirectories, tsconfig } = config;
41
+ const distDir = data.distDir
42
+ ? resolve(rootDir, data.distDir)
43
+ : readTsOutDir(resolve(rootDir, tsconfig));
44
+ if (!distDir) {
45
+ logger.error(`${tsconfig} sets no compilerOptions.outDir, so there is nowhere to copy to. Set one, or pass --dist-dir.`);
46
+ process.exit(1);
47
+ }
48
+ const copies = planDistCopies(rootDir, distDir, [
49
+ ...(await walk(outDir)),
50
+ ...(await Promise.all(srcDirectories.map((dir) => walk(resolve(rootDir, dir))))).flat(),
51
+ ]);
52
+ for (const { from, to } of copies) {
53
+ await mkdir(dirname(to), { recursive: true });
54
+ await cp(from, to);
55
+ }
56
+ logger.info(`Copied ${copies.length} generated file(s) into ${relative(rootDir, distDir) || distDir}`);
57
+ },
58
+ });
@@ -28,6 +28,33 @@ export declare function getAddonFiles(vars: AddonVars, flags: {
28
28
  delegated?: boolean;
29
29
  }): Record<string, string>;
30
30
  export declare function getTestFiles(vars: AddonVars): Record<string, string>;
31
+ /**
32
+ * Does `root`'s `workspaces` field cover `dir`?
33
+ *
34
+ * Declaring workspaces is not enough — a root with `packages/*` does not own an
35
+ * addon written to `addons/crm`, and yarn, npm and pnpm all skip a nested
36
+ * package they were never told about.
37
+ */
38
+ export declare function workspaceCovers(root: string, dir: string): boolean;
39
+ /**
40
+ * An addon that has not been built is dead at runtime.
41
+ *
42
+ * The generated package exports `./dist/...` — that is what an installed
43
+ * consumer resolves, and what the app's own `pikku-bootstrap.gen.ts` imports.
44
+ * Until `build` has run, every `ref('<addon>:...')` resolves to nothing and the
45
+ * app fails at boot with PKU340 plus an ERR_MODULE_NOT_FOUND on a dist path
46
+ * nobody wrote. Nothing about the generated files shows the problem, so the
47
+ * generator finishes the job: install at the root that owns the lockfile, then
48
+ * run the addon's own `build` script (whose `prebuild` is `pikku all`).
49
+ */
50
+ export type AddonBuildRunner = (command: string, args: string[], cwd: string) => {
51
+ status: number | null;
52
+ error?: Error;
53
+ };
54
+ export declare const buildGeneratedAddon: (addonDir: string, logger: {
55
+ info: (message: string) => void;
56
+ error: (message: string) => void;
57
+ }, run?: AddonBuildRunner) => boolean;
31
58
  export declare const pikkuNewAddon: import("#pikku/function").PikkuFunctionConfig<{
32
59
  name: string;
33
60
  displayName?: string;
@@ -43,6 +70,7 @@ export declare const pikkuNewAddon: import("#pikku/function").PikkuFunctionConfi
43
70
  authConfig?: string;
44
71
  mcp?: boolean;
45
72
  camelCase?: boolean;
73
+ build?: boolean;
46
74
  }, void, "rpc" | "session", import("#pikku/function").PikkuFunctionSessionless<{
47
75
  name: string;
48
76
  displayName?: string;
@@ -58,6 +86,7 @@ export declare const pikkuNewAddon: import("#pikku/function").PikkuFunctionConfi
58
86
  authConfig?: string;
59
87
  mcp?: boolean;
60
88
  camelCase?: boolean;
89
+ build?: boolean;
61
90
  }, void, "rpc" | "session", import("#pikku/function").WiredServices, unknown> | import("#pikku/function").PikkuFunction<{
62
91
  name: string;
63
92
  displayName?: string;
@@ -73,4 +102,5 @@ export declare const pikkuNewAddon: import("#pikku/function").PikkuFunctionConfi
73
102
  authConfig?: string;
74
103
  mcp?: boolean;
75
104
  camelCase?: boolean;
105
+ build?: boolean;
76
106
  }, void, "rpc" | "session", import("#pikku/function").WiredServices>, undefined, undefined>;
@@ -1,6 +1,8 @@
1
1
  import { existsSync, readFileSync } from 'fs';
2
- import { dirname, join } from 'path';
2
+ import { dirname, join, relative as relativePath, sep } from 'path';
3
3
  import { mkdir, writeFile } from 'fs/promises';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { findInstallRoot } from './update.js';
4
6
  import { createEmptyManifest, saveManifest, } from '../../utils/contract-versions.js';
5
7
  import { pikkuSessionlessFunc } from '#pikku/function';
6
8
  import { parseOpenAPISpec, computeContractHash, generateAddonFromOpenAPI, loadAuthConfig, } from '@pikku/openapi-parser';
@@ -159,7 +161,7 @@ export function getAddonFiles(vars, flags) {
159
161
  scripts: {
160
162
  prepublishOnly: 'yarn build',
161
163
  prebuild: 'pikku all',
162
- build: 'tsc && cp -r .pikku types dist/',
164
+ build: 'tsc && pikku dist',
163
165
  pikku: 'pikku all',
164
166
  },
165
167
  peerDependencies: {
@@ -851,8 +853,81 @@ async function writeFiles(baseDir, files) {
851
853
  }
852
854
  return written;
853
855
  }
856
+ /**
857
+ * Does `root`'s `workspaces` field cover `dir`?
858
+ *
859
+ * Declaring workspaces is not enough — a root with `packages/*` does not own an
860
+ * addon written to `addons/crm`, and yarn, npm and pnpm all skip a nested
861
+ * package they were never told about.
862
+ */
863
+ export function workspaceCovers(root, dir) {
864
+ const relative = relativePath(root, dir).split(sep).join('/');
865
+ if (relative === '' || relative.startsWith('..')) {
866
+ return false;
867
+ }
868
+ let patterns;
869
+ try {
870
+ const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
871
+ patterns = Array.isArray(manifest.workspaces)
872
+ ? manifest.workspaces
873
+ : manifest.workspaces?.packages;
874
+ }
875
+ catch {
876
+ return false;
877
+ }
878
+ if (!Array.isArray(patterns)) {
879
+ return false;
880
+ }
881
+ return patterns.some((pattern) => {
882
+ if (typeof pattern !== 'string') {
883
+ return false;
884
+ }
885
+ const source = pattern
886
+ .split('/')
887
+ .map((segment) => segment === '**'
888
+ ? '.*'
889
+ : segment.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '[^/]*'))
890
+ .join('/');
891
+ return new RegExp(`^${source}$`).test(relative);
892
+ });
893
+ }
894
+ const spawnAddonBuildStep = (command, args, cwd) => {
895
+ const { status, error } = spawnSync(command, args, {
896
+ cwd,
897
+ stdio: 'inherit',
898
+ shell: process.platform === 'win32',
899
+ });
900
+ return { status, error };
901
+ };
902
+ export const buildGeneratedAddon = (addonDir, logger, run = spawnAddonBuildStep) => {
903
+ const { dir: installDir, packageManager } = findInstallRoot(addonDir);
904
+ if (packageManager === 'unknown') {
905
+ logger.error(`Could not tell which package manager owns ${addonDir} — the addon is generated but NOT built. Run install, then the addon's build script, in ${addonDir} before using it.`);
906
+ return false;
907
+ }
908
+ // A root install only reaches the addon when the root's workspace patterns
909
+ // cover it. A root that owns the lockfile but not this package installs
910
+ // nothing for it, so its devDependencies — `@pikku/cli` and `typescript`,
911
+ // which the build script needs — would never arrive.
912
+ const installIn = workspaceCovers(installDir, addonDir)
913
+ ? installDir
914
+ : addonDir;
915
+ const steps = [
916
+ [installIn, ['install']],
917
+ [addonDir, ['run', 'build']],
918
+ ];
919
+ for (const [cwd, args] of steps) {
920
+ logger.info(`${packageManager} ${args.join(' ')} (${cwd})`);
921
+ const result = run(packageManager, args, cwd);
922
+ if (result.status !== 0) {
923
+ logger.error(`${packageManager} ${args.join(' ')} failed in ${cwd}: ${result.error?.message ?? `exit ${result.status}`}`);
924
+ return false;
925
+ }
926
+ }
927
+ return true;
928
+ };
854
929
  export const pikkuNewAddon = pikkuSessionlessFunc({
855
- func: async ({ logger, config }, { name, displayName, description, category = 'General', dir, secret = false, variable = false, oauth = false, credential, test = true, openapi, authConfig, mcp = false, camelCase = false, }) => {
930
+ func: async ({ logger, config }, { name, displayName, description, category = 'General', dir, secret = false, variable = false, oauth = false, credential, test = true, openapi, authConfig, mcp = false, camelCase = false, build = true, }) => {
856
931
  name = sanitizeAddonName(name);
857
932
  if (!/^[a-z][a-z0-9_-]*$/.test(name)) {
858
933
  logger.error(`Invalid addon name "${name}": must start with a lowercase letter and contain only lowercase alphanumerics, hyphens, and underscores`);
@@ -949,6 +1024,9 @@ export const pikkuNewAddon = pikkuSessionlessFunc({
949
1024
  for (const f of written) {
950
1025
  logger.debug({ message: ` ${f}`, type: 'success' });
951
1026
  }
1027
+ if (build && !buildGeneratedAddon(addonDir, logger)) {
1028
+ process.exit(1);
1029
+ }
952
1030
  console.log(addonDir);
953
1031
  },
954
1032
  });
@@ -9,10 +9,11 @@
9
9
  * config and write through it, which provisioned a local stage correctly and
10
10
  * silently provisioned the wrong database for every other environment.
11
11
  *
12
- * So the deployment provisions itself: an app calls `provisionPersonas` from
13
- * `@pikku/better-auth` in its server lifecycle, where the database connection
14
- * and better-auth's own adapter are both already open, and a deploy carries its
15
- * personas with it. What is left here is the half that needs no database — the
12
+ * So the deployment provisions itself: an app hands its personas to
13
+ * `pikkuFabric` from `@pikku/better-auth`, and the plugin creates a missing one
14
+ * on the operator handshake that asks for it, where the database connection and
15
+ * better-auth's own adapter are both already open. What is left here is the
16
+ * half that needs no database — the
16
17
  * declaration, and the environment rule applied to it — which is what tells you
17
18
  * before a deploy whether the accounts you expect will appear.
18
19
  */
@@ -12,10 +12,11 @@ import { resolvePersonas } from '../../utils/resolve-personas.js';
12
12
  * config and write through it, which provisioned a local stage correctly and
13
13
  * silently provisioned the wrong database for every other environment.
14
14
  *
15
- * So the deployment provisions itself: an app calls `provisionPersonas` from
16
- * `@pikku/better-auth` in its server lifecycle, where the database connection
17
- * and better-auth's own adapter are both already open, and a deploy carries its
18
- * personas with it. What is left here is the half that needs no database — the
15
+ * So the deployment provisions itself: an app hands its personas to
16
+ * `pikkuFabric` from `@pikku/better-auth`, and the plugin creates a missing one
17
+ * on the operator handshake that asks for it, where the database connection and
18
+ * better-auth's own adapter are both already open. What is left here is the
19
+ * half that needs no database — the
19
20
  * declaration, and the environment rule applied to it — which is what tells you
20
21
  * before a deploy whether the accounts you expect will appear.
21
22
  */
@@ -65,6 +66,6 @@ export const personaSync = pikkuSessionlessFunc({
65
66
  for (const refusal of skipped) {
66
67
  logger.info(` skipped: ${refusal}`);
67
68
  }
68
- logger.info(" Provisioning runs in the deployment: call `provisionPersonas` from '@pikku/better-auth' in your server lifecycle, passing `personaConfigs` and `personaEnvironments` from the generated personas file.");
69
+ logger.info(" Provisioning runs in the deployment: pass `personas: { personas: personaConfigs, environments: personaEnvironments }` from the generated personas file to `pikkuFabric` from '@pikku/better-auth'.");
69
70
  },
70
71
  });
@@ -4,6 +4,7 @@ import { pikkuSessionlessFunc } from '#pikku/function';
4
4
  import { createHttpPersonas, deriveActorSecret, personaEnvironmentRefusal, roleMismatchMessage, verifyPersonaRoles, } from '@pikku/core/persona';
5
5
  import { personaVirtualUserTarget, runVirtualUser, catalogueClassification, DISPOSITIONS, prepareVirtualUserRun, } from '@pikku/core/virtual-user';
6
6
  import { getSingletonServices, setSingletonServices } from '@pikku/core/state';
7
+ import { PikkuError } from '@pikku/core/errors';
7
8
  import { resolvePersonas } from '../../utils/resolve-personas.js';
8
9
  import { ACTOR_SECRET_VARIABLE, PERSONA_SECRETS_VARIABLE, resolvePersonaCredentials, } from '../../utils/persona-credentials.js';
9
10
  import { resolveEnvironment } from './environment.js';
@@ -108,7 +109,7 @@ export const personaRun = pikkuSessionlessFunc({
108
109
  agentsMeta: state.agents?.agentsMeta ?? {},
109
110
  });
110
111
  if (catalogue.length === 0) {
111
- throw new Error('This project exposes no RPCs, so there is nothing for a virtual user to do.');
112
+ throw new PikkuError('This project exposes no RPCs, so there is nothing for a virtual user to do.');
112
113
  }
113
114
  const signedIn = createHttpPersonas({
114
115
  apiUrl: env.apiUrl,
@@ -132,7 +133,10 @@ export const personaRun = pikkuSessionlessFunc({
132
133
  else {
133
134
  const message = roleMismatchMessage(verifyPersonaRoles(personaId, persona.roles, actual));
134
135
  if (message) {
135
- throw new Error(message);
136
+ // A refusal, not a crash: `PikkuError` is what tells the CLI to print
137
+ // the message on its own, since the seed drift it names is the whole
138
+ // finding and the frames underneath it are noise.
139
+ throw new PikkuError(message);
136
140
  }
137
141
  }
138
142
  }