@pikku/cli 0.12.15 → 0.12.16

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 (160) hide show
  1. package/cli.schema.json +1 -1
  2. package/console-app/assets/index-CzMWJFqj.js +700 -0
  3. package/console-app/index.html +1 -1
  4. package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
  5. package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
  6. package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
  7. package/dist/.pikku/cli/pikku-cli-channel.js +16 -1
  8. package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
  9. package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
  10. package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
  11. package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
  12. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
  13. package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +68 -5
  14. package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
  15. package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
  16. package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
  17. package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
  18. package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
  19. package/dist/.pikku/function/pikku-function-types.gen.d.ts +16 -19
  20. package/dist/.pikku/function/pikku-function-types.gen.js +15 -19
  21. package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
  22. package/dist/.pikku/function/pikku-functions-meta.gen.json +190 -107
  23. package/dist/.pikku/function/pikku-functions.gen.js +6 -2
  24. package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
  25. package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
  26. package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
  27. package/dist/.pikku/http/pikku-http-wirings-meta.gen.json +18 -1
  28. package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +2 -2
  29. package/dist/.pikku/http/pikku-http-wirings.gen.js +3 -3
  30. package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
  31. package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
  32. package/dist/.pikku/pikku-bootstrap.gen.d.ts +3 -10
  33. package/dist/.pikku/pikku-bootstrap.gen.js +1 -18
  34. package/dist/.pikku/pikku-meta-service.gen.d.ts +7 -0
  35. package/dist/.pikku/pikku-meta-service.gen.js +9 -0
  36. package/dist/.pikku/pikku-services.gen.d.ts +2 -1
  37. package/dist/.pikku/pikku-services.gen.js +1 -0
  38. package/dist/.pikku/pikku-types.gen.d.ts +1 -1
  39. package/dist/.pikku/pikku-types.gen.js +1 -1
  40. package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
  41. package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
  42. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
  43. package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +5 -1
  44. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
  45. package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
  46. package/dist/.pikku/schemas/register.gen.js +15 -7
  47. package/dist/.pikku/schemas/schemas/DeployApplyInput.schema.json +1 -0
  48. package/dist/.pikku/schemas/schemas/DeployPlanInput.schema.json +1 -0
  49. package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
  50. package/dist/.pikku/schemas/schemas/PikkuNewAddonInput.schema.json +1 -1
  51. package/dist/.pikku/schemas/schemas/PikkuWorkflowRoutesOutput.schema.json +1 -0
  52. package/dist/.pikku/schemas/schemas/RemoteRPCHandlerInput.schema.json +1 -0
  53. package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
  54. package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
  55. package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
  56. package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
  57. package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
  58. package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
  59. package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
  60. package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
  61. package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
  62. package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
  63. package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +3 -24
  64. package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -14
  65. package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
  66. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.d.ts +1 -1
  67. package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
  68. package/dist/src/cli.wiring.js +63 -4
  69. package/dist/src/deploy/analyzer/analyzer.d.ts +16 -0
  70. package/dist/src/deploy/analyzer/analyzer.js +557 -0
  71. package/dist/src/deploy/analyzer/index.d.ts +3 -0
  72. package/dist/src/deploy/analyzer/index.js +1 -0
  73. package/dist/src/deploy/analyzer/manifest.d.ts +112 -0
  74. package/dist/src/deploy/analyzer/manifest.js +8 -0
  75. package/dist/src/deploy/build-pipeline.d.ts +39 -0
  76. package/dist/src/deploy/build-pipeline.js +209 -0
  77. package/dist/src/deploy/bundler/bundler.d.ts +30 -0
  78. package/dist/src/deploy/bundler/bundler.js +196 -0
  79. package/dist/src/deploy/bundler/dep-extractor.d.ts +35 -0
  80. package/dist/src/deploy/bundler/dep-extractor.js +213 -0
  81. package/dist/src/deploy/bundler/index.d.ts +3 -0
  82. package/dist/src/deploy/bundler/index.js +2 -0
  83. package/dist/src/deploy/bundler/types.d.ts +21 -0
  84. package/dist/src/deploy/bundler/types.js +5 -0
  85. package/dist/src/deploy/codegen/index.d.ts +2 -0
  86. package/dist/src/deploy/codegen/index.js +1 -0
  87. package/dist/src/deploy/codegen/per-unit-codegen.d.ts +44 -0
  88. package/dist/src/deploy/codegen/per-unit-codegen.js +216 -0
  89. package/dist/src/deploy/plan/executor.d.ts +9 -0
  90. package/dist/src/deploy/plan/executor.js +49 -0
  91. package/dist/src/deploy/plan/formatter.d.ts +4 -0
  92. package/dist/src/deploy/plan/formatter.js +114 -0
  93. package/dist/src/deploy/plan/index.d.ts +5 -0
  94. package/dist/src/deploy/plan/index.js +3 -0
  95. package/dist/src/deploy/plan/planner.d.ts +4 -0
  96. package/dist/src/deploy/plan/planner.js +220 -0
  97. package/dist/src/deploy/plan/provider.d.ts +30 -0
  98. package/dist/src/deploy/plan/provider.js +1 -0
  99. package/dist/src/deploy/plan/types.d.ts +29 -0
  100. package/dist/src/deploy/plan/types.js +1 -0
  101. package/dist/src/deploy/provider-adapter.d.ts +111 -0
  102. package/dist/src/deploy/provider-adapter.js +10 -0
  103. package/dist/src/functions/commands/all.js +6 -2
  104. package/dist/src/functions/commands/deploy-apply.d.ts +22 -0
  105. package/dist/src/functions/commands/deploy-apply.js +206 -0
  106. package/dist/src/functions/commands/deploy-info.d.ts +1 -0
  107. package/dist/src/functions/commands/deploy-info.js +122 -0
  108. package/dist/src/functions/commands/deploy-plan.d.ts +10 -0
  109. package/dist/src/functions/commands/deploy-plan.js +96 -0
  110. package/dist/src/functions/commands/enable.js +1 -1
  111. package/dist/src/functions/commands/new-addon.d.ts +3 -0
  112. package/dist/src/functions/commands/new-addon.js +68 -2
  113. package/dist/src/functions/commands/pikku-command-bootstrap.js +30 -20
  114. package/dist/src/functions/runtimes/nextjs/pikku-command-nextjs.js +7 -3
  115. package/dist/src/functions/wirings/ai-agent/pikku-command-ai-agent.js +7 -5
  116. package/dist/src/functions/wirings/channels/pikku-channels.js +3 -0
  117. package/dist/src/functions/wirings/channels/pikku-command-channels.js +3 -0
  118. package/dist/src/functions/wirings/cli/pikku-command-cli.js +3 -0
  119. package/dist/src/functions/wirings/cli/serialize-channel-cli.js +2 -2
  120. package/dist/src/functions/wirings/console/serialize-console-functions.js +2 -2
  121. package/dist/src/functions/wirings/functions/pikku-command-services.d.ts +1 -1
  122. package/dist/src/functions/wirings/functions/pikku-command-services.js +9 -2
  123. package/dist/src/functions/wirings/functions/serialize-function-imports.js +5 -3
  124. package/dist/src/functions/wirings/functions/serialize-function-types.js +17 -19
  125. package/dist/src/functions/wirings/http/pikku-command-http-routes.js +3 -0
  126. package/dist/src/functions/wirings/http/pikku-http-routes.js +3 -0
  127. package/dist/src/functions/wirings/mcp/pikku-command-mcp.js +6 -0
  128. package/dist/src/functions/wirings/package/pikku-command-package.js +1 -1
  129. package/dist/src/functions/wirings/package/serialize-package.d.ts +1 -1
  130. package/dist/src/functions/wirings/package/serialize-package.js +5 -2
  131. package/dist/src/functions/wirings/queue/pikku-command-queue.js +4 -0
  132. package/dist/src/functions/wirings/queue/pikku-queue.js +4 -0
  133. package/dist/src/functions/wirings/queue/serialize-queue-map.js +4 -1
  134. package/dist/src/functions/wirings/rpc/pikku-command-rpc.js +10 -3
  135. package/dist/src/functions/wirings/rpc/serialize-public-rpc.js +5 -27
  136. package/dist/src/functions/wirings/rpc/serialize-remote-rpc.js +11 -14
  137. package/dist/src/functions/wirings/rpc/serialize-rpc-wrapper.js +28 -3
  138. package/dist/src/functions/wirings/rpc/serialize-typed-rpc-map.js +15 -5
  139. package/dist/src/functions/wirings/scheduler/pikku-command-scheduler.js +4 -0
  140. package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.d.ts +1 -0
  141. package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.js +21 -0
  142. package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +10 -9
  143. package/dist/src/functions/wirings/workflow/serialize-workflow-map.d.ts +6 -1
  144. package/dist/src/functions/wirings/workflow/serialize-workflow-map.js +42 -5
  145. package/dist/src/functions/wirings/workflow/serialize-workflow-registration.d.ts +1 -1
  146. package/dist/src/functions/wirings/workflow/serialize-workflow-registration.js +3 -2
  147. package/dist/src/functions/wirings/workflow/serialize-workflow-routes.d.ts +4 -0
  148. package/dist/src/functions/wirings/workflow/serialize-workflow-routes.js +139 -0
  149. package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +4 -51
  150. package/dist/src/scaffold/rpc-remote.gen.d.ts +10 -0
  151. package/dist/src/scaffold/rpc-remote.gen.js +22 -0
  152. package/dist/src/services.js +12 -7
  153. package/dist/src/utils/pikku-cli-config.d.ts +1 -1
  154. package/dist/src/utils/pikku-cli-config.js +30 -28
  155. package/dist/src/utils/strip-verbose-meta.js +2 -0
  156. package/dist/tsconfig.tsbuildinfo +1 -1
  157. package/package.json +8 -4
  158. package/console-app/assets/index-robZPL3O.js +0 -672
  159. package/dist/src/functions/wirings/workflow/serialize-workflow-workers.d.ts +0 -4
  160. package/dist/src/functions/wirings/workflow/serialize-workflow-workers.js +0 -47
@@ -0,0 +1,114 @@
1
+ const ANSI = {
2
+ green: '\x1b[32m',
3
+ blue: '\x1b[34m',
4
+ red: '\x1b[31m',
5
+ yellow: '\x1b[33m',
6
+ dim: '\x1b[2m',
7
+ bold: '\x1b[1m',
8
+ reset: '\x1b[0m',
9
+ };
10
+ const ACTION_DISPLAY = {
11
+ create: { symbol: '+', color: ANSI.green, label: 'create' },
12
+ update: { symbol: '~', color: ANSI.blue, label: 'update' },
13
+ delete: { symbol: '-', color: ANSI.red, label: 'delete' },
14
+ drain: { symbol: '\u23F3', color: ANSI.yellow, label: 'drain' },
15
+ };
16
+ const ROLE_LABELS = {
17
+ http: 'HTTP',
18
+ rpc: 'RPC',
19
+ mcp: 'MCP',
20
+ 'queue-consumer': 'Queue Consumer',
21
+ scheduled: 'Cron',
22
+ agent: 'Agent',
23
+ channel: 'Channel',
24
+ 'workflow-orchestrator': 'Workflow',
25
+ 'workflow-step': 'Workflow Step',
26
+ };
27
+ const RESOURCE_LABELS = {
28
+ queue: 'Queue',
29
+ 'scheduled-task': 'Scheduled Task',
30
+ secret: 'Secret',
31
+ variable: 'Variable',
32
+ };
33
+ function padRight(str, len) {
34
+ return str + ' '.repeat(Math.max(0, len - str.length));
35
+ }
36
+ function getResourceLabel(change) {
37
+ if (change.resourceType === 'unit' && change.role) {
38
+ return ROLE_LABELS[change.role] ?? change.role;
39
+ }
40
+ return RESOURCE_LABELS[change.resourceType] ?? change.resourceType;
41
+ }
42
+ function formatChange(change) {
43
+ const display = ACTION_DISPLAY[change.action];
44
+ const typeLabel = padRight(getResourceLabel(change), 16);
45
+ const nameLabel = padRight(change.name, 28);
46
+ return ` ${display.color}${display.symbol} ${padRight(display.label, 8)}${ANSI.reset} ${typeLabel} ${ANSI.bold}${nameLabel}${ANSI.reset} ${ANSI.dim}${change.reason}${ANSI.reset}`;
47
+ }
48
+ export function formatPlan(plan) {
49
+ const lines = [];
50
+ lines.push(`${ANSI.bold}Deployment Plan${ANSI.reset}`);
51
+ lines.push('');
52
+ if (plan.changes.length === 0) {
53
+ lines.push(` ${ANSI.dim}No changes. Everything is up to date.${ANSI.reset}`);
54
+ return lines.join('\n');
55
+ }
56
+ // Group by action for clean output
57
+ const order = ['create', 'update', 'delete', 'drain'];
58
+ for (const action of order) {
59
+ const group = plan.changes.filter((c) => c.action === action);
60
+ for (const change of group) {
61
+ lines.push(formatChange(change));
62
+ }
63
+ }
64
+ if (plan.summary.unchanged > 0) {
65
+ lines.push(` ${ANSI.dim}= ${plan.summary.unchanged} resources unchanged${ANSI.reset}`);
66
+ }
67
+ lines.push('');
68
+ const parts = [];
69
+ if (plan.summary.create > 0)
70
+ parts.push(`${ANSI.green}${plan.summary.create} to create${ANSI.reset}`);
71
+ if (plan.summary.update > 0)
72
+ parts.push(`${ANSI.blue}${plan.summary.update} to update${ANSI.reset}`);
73
+ if (plan.summary.delete > 0)
74
+ parts.push(`${ANSI.red}${plan.summary.delete} to delete${ANSI.reset}`);
75
+ if (plan.summary.drain > 0)
76
+ parts.push(`${ANSI.yellow}${plan.summary.drain} to drain${ANSI.reset}`);
77
+ lines.push(`${ANSI.bold}Summary:${ANSI.reset} ${parts.join(', ')}`);
78
+ return lines.join('\n');
79
+ }
80
+ /** Plain text version without ANSI colors (for logs, storage) */
81
+ export function formatPlanPlain(plan) {
82
+ const lines = [];
83
+ lines.push('Deployment Plan');
84
+ lines.push('');
85
+ if (plan.changes.length === 0) {
86
+ lines.push(' No changes. Everything is up to date.');
87
+ return lines.join('\n');
88
+ }
89
+ const order = ['create', 'update', 'delete', 'drain'];
90
+ for (const action of order) {
91
+ const group = plan.changes.filter((c) => c.action === action);
92
+ for (const change of group) {
93
+ const display = ACTION_DISPLAY[change.action];
94
+ const typeLabel = padRight(getResourceLabel(change), 16);
95
+ const nameLabel = padRight(change.name, 28);
96
+ lines.push(` ${display.symbol} ${padRight(display.label, 8)} ${typeLabel} ${nameLabel} ${change.reason}`);
97
+ }
98
+ }
99
+ if (plan.summary.unchanged > 0) {
100
+ lines.push(` = ${plan.summary.unchanged} resources unchanged`);
101
+ }
102
+ lines.push('');
103
+ const parts = [];
104
+ if (plan.summary.create > 0)
105
+ parts.push(`${plan.summary.create} to create`);
106
+ if (plan.summary.update > 0)
107
+ parts.push(`${plan.summary.update} to update`);
108
+ if (plan.summary.delete > 0)
109
+ parts.push(`${plan.summary.delete} to delete`);
110
+ if (plan.summary.drain > 0)
111
+ parts.push(`${plan.summary.drain} to drain`);
112
+ lines.push(`Summary: ${parts.join(', ')}`);
113
+ return lines.join('\n');
114
+ }
@@ -0,0 +1,5 @@
1
+ export { generatePlan } from './planner.js';
2
+ export { applyPlan } from './executor.js';
3
+ export { formatPlan, formatPlanPlain } from './formatter.js';
4
+ export type { DeploymentPlan, PlanChange, ApplyResult, ChangeAction, ResourceType, } from './types.js';
5
+ export type { DeployProvider, CurrentState } from './provider.js';
@@ -0,0 +1,3 @@
1
+ export { generatePlan } from './planner.js';
2
+ export { applyPlan } from './executor.js';
3
+ export { formatPlan, formatPlanPlain } from './formatter.js';
@@ -0,0 +1,4 @@
1
+ import type { DeploymentManifest } from '../analyzer/manifest.js';
2
+ import type { CurrentState, DeployProvider } from './provider.js';
3
+ import type { DeploymentPlan } from './types.js';
4
+ export declare function generatePlan(manifest: DeploymentManifest, currentState: CurrentState, provider: DeployProvider): Promise<DeploymentPlan>;
@@ -0,0 +1,220 @@
1
+ function arraysEqual(a, b) {
2
+ if (a.length !== b.length)
3
+ return false;
4
+ const sorted1 = [...a].sort();
5
+ const sorted2 = [...b].sort();
6
+ return sorted1.every((v, i) => v === sorted2[i]);
7
+ }
8
+ function diffUnits(manifest, current, drainInfo) {
9
+ const changes = [];
10
+ const currentByName = new Map(current.units.map((u) => [u.name, u]));
11
+ const desiredByName = new Map(manifest.units.map((u) => [u.name, u]));
12
+ // Create or update
13
+ for (const desired of manifest.units) {
14
+ const existing = currentByName.get(desired.name);
15
+ if (!existing) {
16
+ changes.push({
17
+ action: 'create',
18
+ resourceType: 'unit',
19
+ name: desired.name,
20
+ role: desired.role,
21
+ reason: 'new function',
22
+ details: { functionIds: desired.functionIds },
23
+ });
24
+ }
25
+ else if (!arraysEqual(existing.functionIds, desired.functionIds) ||
26
+ existing.role !== desired.role) {
27
+ changes.push({
28
+ action: 'update',
29
+ resourceType: 'unit',
30
+ name: desired.name,
31
+ role: desired.role,
32
+ reason: 'code changed',
33
+ details: { functionIds: desired.functionIds },
34
+ });
35
+ }
36
+ }
37
+ // Delete or drain
38
+ for (const existing of current.units) {
39
+ if (!desiredByName.has(existing.name)) {
40
+ const pending = drainInfo.get(existing.name) ?? 0;
41
+ if (pending > 0) {
42
+ changes.push({
43
+ action: 'drain',
44
+ resourceType: 'unit',
45
+ name: existing.name,
46
+ reason: `removed, ${pending} pending workflows`,
47
+ details: { pendingCount: pending },
48
+ });
49
+ }
50
+ else {
51
+ changes.push({
52
+ action: 'delete',
53
+ resourceType: 'unit',
54
+ name: existing.name,
55
+ reason: 'removed, no active workflows',
56
+ });
57
+ }
58
+ }
59
+ }
60
+ return changes;
61
+ }
62
+ function diffSimpleResources(resourceType, desired, current) {
63
+ const changes = [];
64
+ const currentNames = new Set(current.map((r) => r.name));
65
+ const desiredNames = new Set(desired.map((r) => r.name));
66
+ for (const r of desired) {
67
+ if (!currentNames.has(r.name)) {
68
+ changes.push({
69
+ action: 'create',
70
+ resourceType,
71
+ name: r.name,
72
+ reason: 'new',
73
+ });
74
+ }
75
+ }
76
+ for (const r of current) {
77
+ if (!desiredNames.has(r.name)) {
78
+ changes.push({
79
+ action: 'delete',
80
+ resourceType,
81
+ name: r.name,
82
+ reason: 'removed',
83
+ });
84
+ }
85
+ }
86
+ return changes;
87
+ }
88
+ function diffScheduledTasks(desired, current) {
89
+ const changes = [];
90
+ const currentByUnit = new Map(current.map((t) => [t.unitName, t.schedule]));
91
+ const desiredByUnit = new Map(desired.map((t) => [t.unitName, t.schedule]));
92
+ for (const d of desired) {
93
+ const existingSchedule = currentByUnit.get(d.unitName);
94
+ if (existingSchedule === undefined) {
95
+ changes.push({
96
+ action: 'create',
97
+ resourceType: 'scheduled-task',
98
+ name: d.name,
99
+ reason: 'new scheduled task',
100
+ details: { schedule: d.schedule, unitName: d.unitName },
101
+ });
102
+ }
103
+ else if (existingSchedule !== d.schedule) {
104
+ changes.push({
105
+ action: 'update',
106
+ resourceType: 'scheduled-task',
107
+ name: d.name,
108
+ reason: 'schedule changed',
109
+ details: { oldSchedule: existingSchedule, newSchedule: d.schedule },
110
+ });
111
+ }
112
+ }
113
+ for (const c of current) {
114
+ if (!desiredByUnit.has(c.unitName)) {
115
+ changes.push({
116
+ action: 'delete',
117
+ resourceType: 'scheduled-task',
118
+ name: c.name ?? c.unitName,
119
+ reason: 'removed',
120
+ });
121
+ }
122
+ }
123
+ return changes;
124
+ }
125
+ function diffSecrets(desired, current) {
126
+ const changes = [];
127
+ const currentSet = new Set(current);
128
+ const desiredSet = new Set(desired);
129
+ for (const s of desired) {
130
+ if (!currentSet.has(s)) {
131
+ changes.push({
132
+ action: 'create',
133
+ resourceType: 'secret',
134
+ name: s,
135
+ reason: 'new secret',
136
+ });
137
+ }
138
+ }
139
+ for (const s of current) {
140
+ if (!desiredSet.has(s)) {
141
+ changes.push({
142
+ action: 'delete',
143
+ resourceType: 'secret',
144
+ name: s,
145
+ reason: 'removed',
146
+ });
147
+ }
148
+ }
149
+ return changes;
150
+ }
151
+ function diffVariables(desired, current) {
152
+ const changes = [];
153
+ for (const [key, value] of Object.entries(desired)) {
154
+ if (!(key in current)) {
155
+ changes.push({
156
+ action: 'create',
157
+ resourceType: 'variable',
158
+ name: key,
159
+ reason: 'new variable',
160
+ });
161
+ }
162
+ else if (current[key] !== value) {
163
+ changes.push({
164
+ action: 'update',
165
+ resourceType: 'variable',
166
+ name: key,
167
+ reason: 'value changed',
168
+ });
169
+ }
170
+ }
171
+ for (const key of Object.keys(current)) {
172
+ if (!(key in desired)) {
173
+ changes.push({
174
+ action: 'delete',
175
+ resourceType: 'variable',
176
+ name: key,
177
+ reason: 'removed',
178
+ });
179
+ }
180
+ }
181
+ return changes;
182
+ }
183
+ function countUnchanged(manifest, changes) {
184
+ const totalDesired = manifest.units.length +
185
+ manifest.queues.length +
186
+ manifest.scheduledTasks.length +
187
+ manifest.secrets.length +
188
+ manifest.variables.length;
189
+ // Rough count: total desired minus those that appear in changes
190
+ const createOrUpdate = changes.filter((c) => c.action === 'create' || c.action === 'update').length;
191
+ return Math.max(0, totalDesired - createOrUpdate);
192
+ }
193
+ export async function generatePlan(manifest, currentState, provider) {
194
+ // Check drain status for units being removed
195
+ const removedUnitNames = currentState.units
196
+ .filter((u) => !manifest.units.some((mu) => mu.name === u.name))
197
+ .map((u) => u.name);
198
+ const drainInfo = new Map();
199
+ for (const name of removedUnitNames) {
200
+ const { active, pendingCount } = await provider.hasActiveWork(name);
201
+ if (active) {
202
+ drainInfo.set(name, pendingCount);
203
+ }
204
+ }
205
+ const changes = [
206
+ ...diffUnits(manifest, currentState, drainInfo),
207
+ ...diffSimpleResources('queue', manifest.queues, currentState.queues),
208
+ ...diffScheduledTasks(manifest.scheduledTasks, currentState.scheduledTasks),
209
+ ...diffSecrets(manifest.secrets.map((s) => s.secretId), currentState.secrets),
210
+ ...diffVariables(Object.fromEntries(manifest.variables.map((v) => [v.variableId, v.displayName])), currentState.variables),
211
+ ];
212
+ const summary = {
213
+ create: changes.filter((c) => c.action === 'create').length,
214
+ update: changes.filter((c) => c.action === 'update').length,
215
+ delete: changes.filter((c) => c.action === 'delete').length,
216
+ drain: changes.filter((c) => c.action === 'drain').length,
217
+ unchanged: countUnchanged(manifest, changes),
218
+ };
219
+ return { changes, summary };
220
+ }
@@ -0,0 +1,30 @@
1
+ import type { DeploymentManifest } from '../analyzer/manifest.js';
2
+ import type { PlanChange } from './types.js';
3
+ export interface CurrentState {
4
+ units: Array<{
5
+ name: string;
6
+ functionIds: string[];
7
+ role: string;
8
+ }>;
9
+ queues: Array<{
10
+ name: string;
11
+ }>;
12
+ scheduledTasks: Array<{
13
+ unitName: string;
14
+ schedule: string;
15
+ name?: string;
16
+ }>;
17
+ secrets: string[];
18
+ variables: Record<string, string>;
19
+ }
20
+ export interface DeployProvider {
21
+ /** Get current deployed state for a project */
22
+ getCurrentState(projectId: string): Promise<CurrentState>;
23
+ /** Execute a single change from the plan */
24
+ applyChange(change: PlanChange, manifest: DeploymentManifest): Promise<void>;
25
+ /** Check if a resource has active work (for drain vs delete decisions) */
26
+ hasActiveWork(resourceName: string): Promise<{
27
+ active: boolean;
28
+ pendingCount: number;
29
+ }>;
30
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,29 @@
1
+ export type ChangeAction = 'create' | 'update' | 'delete' | 'drain';
2
+ export type ResourceType = 'unit' | 'queue' | 'scheduled-task' | 'secret' | 'variable';
3
+ export interface PlanChange {
4
+ action: ChangeAction;
5
+ resourceType: ResourceType;
6
+ name: string;
7
+ reason: string;
8
+ /** For units, the deployment role (http, agent, mcp, etc.) */
9
+ role?: string;
10
+ details?: Record<string, unknown>;
11
+ }
12
+ export interface DeploymentPlan {
13
+ changes: PlanChange[];
14
+ summary: {
15
+ create: number;
16
+ update: number;
17
+ delete: number;
18
+ drain: number;
19
+ unchanged: number;
20
+ };
21
+ }
22
+ export interface ApplyResult {
23
+ applied: Array<{
24
+ change: PlanChange;
25
+ status: 'done' | 'error';
26
+ error?: string;
27
+ }>;
28
+ success: boolean;
29
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Provider adapter interface for the deploy pipeline.
3
+ *
4
+ * Each provider (Cloudflare, AWS, etc.) implements this to handle
5
+ * the provider-specific parts of deployment: entry generation,
6
+ * infrastructure manifests, and config files.
7
+ *
8
+ * The generic pipeline handles: analysis, codegen, bundling, plan/apply.
9
+ */
10
+ import type { DeploymentManifest, DeploymentUnit } from './analyzer/manifest.js';
11
+ export interface EntryGenerationContext {
12
+ /** The unit being generated */
13
+ unit: DeploymentUnit;
14
+ /** Absolute path to the unit's output directory */
15
+ unitDir: string;
16
+ /** Relative path to the unit's pikku-bootstrap.gen.js */
17
+ bootstrapPath: string;
18
+ /** Import statement for createConfig */
19
+ configImport: string;
20
+ /** Variable name for createConfig */
21
+ configVar: string;
22
+ /** Import statement for createSingletonServices */
23
+ servicesImport: string;
24
+ /** Variable name for createSingletonServices */
25
+ servicesVar: string;
26
+ /** Import statement for SingletonServices type (or empty string) */
27
+ singletonServicesImport: string;
28
+ /** Type expression for Partial<SingletonServices> (or fallback) */
29
+ servicesType: string;
30
+ }
31
+ export interface ProviderAdapter {
32
+ /** Provider name (e.g. 'cloudflare', 'aws') */
33
+ readonly name: string;
34
+ /** Subdirectory name under .deploy/ (e.g. 'cloudflare') */
35
+ readonly deployDirName: string;
36
+ /**
37
+ * When true, skips per-unit decomposition and bundles everything
38
+ * into a single unit using the project's full .pikku/ directory.
39
+ * Used by standalone adapter.
40
+ */
41
+ readonly singleUnit?: boolean;
42
+ /**
43
+ * Generate the entry file source for a deployment unit.
44
+ * Called once per unit.
45
+ */
46
+ generateEntrySource(ctx: EntryGenerationContext): string;
47
+ /**
48
+ * Generate provider-specific config files per unit (e.g. wrangler.toml).
49
+ * Returns a map of filename → content to write into the unit directory.
50
+ */
51
+ generateUnitConfigs(unit: DeploymentUnit, manifest: DeploymentManifest, projectId: string): Map<string, string>;
52
+ /**
53
+ * Generate provider-level infrastructure manifest (e.g. infra.json).
54
+ * Returns file content, or null if not applicable.
55
+ */
56
+ generateInfraManifest(manifest: DeploymentManifest): string | null;
57
+ /**
58
+ * External modules for esbuild bundling.
59
+ * Defaults to ['node:*'] if not provided.
60
+ */
61
+ getExternals?(): string[];
62
+ /**
63
+ * Module aliases for esbuild bundling (e.g. { crypto: 'node:crypto' }).
64
+ * Used to remap bare imports to platform-compatible paths.
65
+ */
66
+ getAliases?(): Record<string, string>;
67
+ /**
68
+ * esbuild define map for compile-time constants (e.g. { 'process.env.NODE_ENV': '"production"' }).
69
+ */
70
+ getDefine?(): Record<string, string>;
71
+ /**
72
+ * esbuild platform target. Defaults to 'node'.
73
+ * Cloudflare Workers should use 'neutral'.
74
+ */
75
+ getPlatform?(): 'node' | 'neutral' | 'browser';
76
+ /**
77
+ * esbuild output format. Defaults to 'esm'.
78
+ * pkg requires 'cjs' for standalone binaries.
79
+ */
80
+ getFormat?(): 'esm' | 'cjs';
81
+ /**
82
+ * Generate additional provider-level config files (e.g. serverless.yml).
83
+ * Returns a map of filename → content to write into the deploy directory.
84
+ */
85
+ generateProviderConfigs?(manifest: DeploymentManifest): Map<string, string>;
86
+ /**
87
+ * Deploy the built artifacts to the provider.
88
+ * Optional — if not implemented, the CLI just outputs the build directory.
89
+ */
90
+ deploy?(options: {
91
+ buildDir: string;
92
+ logger: {
93
+ info(msg: string): void;
94
+ error(msg: string): void;
95
+ };
96
+ onProgress?: (step: string, detail: string) => void;
97
+ }): Promise<{
98
+ success: boolean;
99
+ workersDeployed?: Array<{
100
+ name: string;
101
+ }>;
102
+ resourcesCreated?: Array<{
103
+ type: string;
104
+ name: string;
105
+ }>;
106
+ errors: Array<{
107
+ step: string;
108
+ error: string;
109
+ }>;
110
+ }>;
111
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Provider adapter interface for the deploy pipeline.
3
+ *
4
+ * Each provider (Cloudflare, AWS, etc.) implements this to handle
5
+ * the provider-specific parts of deployment: entry generation,
6
+ * infrastructure manifests, and config files.
7
+ *
8
+ * The generic pipeline handles: analysis, codegen, bundling, plan/apply.
9
+ */
10
+ export {};
@@ -83,7 +83,6 @@ export const all = pikkuVoidFunc({
83
83
  }
84
84
  }
85
85
  await rpc.invoke('pikkuPublicRPC', null);
86
- await rpc.invoke('pikkuRPCClient', null);
87
86
  await rpc.invoke('pikkuConsoleFunctions', null);
88
87
  await rpc.invoke('pikkuNodeTypes', null);
89
88
  await rpc.invoke('pikkuSecretDefinitionTypes', null);
@@ -106,10 +105,14 @@ export const all = pikkuVoidFunc({
106
105
  await rpc.invoke('pikkuRPCExposedMap', null);
107
106
  const workflows = await rpc.invoke('pikkuWorkflow', null);
108
107
  let remoteRPC = false;
108
+ let workflowRoutes = false;
109
109
  if (!config.addon) {
110
110
  remoteRPC = await rpc.invoke('pikkuRemoteRPC', null);
111
+ if (workflows) {
112
+ workflowRoutes = await rpc.invoke('pikkuWorkflowRoutes', null);
113
+ }
111
114
  }
112
- if (workflows || remoteRPC) {
115
+ if (workflows || remoteRPC || workflowRoutes) {
113
116
  await getInspectorState(true);
114
117
  await rpc.invoke('pikkuSchemas', null);
115
118
  }
@@ -118,6 +121,7 @@ export const all = pikkuVoidFunc({
118
121
  if (http) {
119
122
  await rpc.invoke('pikkuHTTPMap', null);
120
123
  await rpc.invoke('pikkuFetch', null);
124
+ await rpc.invoke('pikkuRPCClient', null);
121
125
  allImports.push(config.httpWiringMetaFile, config.httpWiringsFile);
122
126
  }
123
127
  const scheduler = await rpc.invoke('pikkuScheduler', null);
@@ -0,0 +1,22 @@
1
+ import type { ProviderAdapter, EntryGenerationContext } from '../../deploy/provider-adapter.js';
2
+ import type { InspectorState } from '@pikku/inspector';
3
+ export declare function getEntryContext(unitDir: string, pikkuDir: string, unit: EntryGenerationContext['unit'], inspectorState: InspectorState): EntryGenerationContext;
4
+ export declare function resolveProvider(config?: {
5
+ deploy?: {
6
+ providers: Record<string, string>;
7
+ defaultProvider?: string;
8
+ };
9
+ }, providerName?: string): Promise<ProviderAdapter>;
10
+ export declare const deployApply: import("#pikku").PikkuFunctionConfig<{
11
+ fromPlan?: boolean;
12
+ provider?: string;
13
+ resultFile?: string;
14
+ }, void, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<{
15
+ fromPlan?: boolean;
16
+ provider?: string;
17
+ resultFile?: string;
18
+ }, void, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<{
19
+ fromPlan?: boolean;
20
+ provider?: string;
21
+ resultFile?: string;
22
+ }, void, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;