@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.
- package/cli.schema.json +1 -1
- package/console-app/assets/index-CzMWJFqj.js +700 -0
- package/console-app/index.html +1 -1
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.js +16 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +68 -5
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +16 -19
- package/dist/.pikku/function/pikku-function-types.gen.js +15 -19
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +190 -107
- package/dist/.pikku/function/pikku-functions.gen.js +6 -2
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings-meta.gen.json +18 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +2 -2
- package/dist/.pikku/http/pikku-http-wirings.gen.js +3 -3
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +3 -10
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -18
- package/dist/.pikku/pikku-meta-service.gen.d.ts +7 -0
- package/dist/.pikku/pikku-meta-service.gen.js +9 -0
- package/dist/.pikku/pikku-services.gen.d.ts +2 -1
- package/dist/.pikku/pikku-services.gen.js +1 -0
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +5 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +15 -7
- package/dist/.pikku/schemas/schemas/DeployApplyInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/DeployPlanInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuNewAddonInput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuWorkflowRoutesOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/RemoteRPCHandlerInput.schema.json +1 -0
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +3 -24
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -14
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/src/cli.wiring.js +63 -4
- package/dist/src/deploy/analyzer/analyzer.d.ts +16 -0
- package/dist/src/deploy/analyzer/analyzer.js +557 -0
- package/dist/src/deploy/analyzer/index.d.ts +3 -0
- package/dist/src/deploy/analyzer/index.js +1 -0
- package/dist/src/deploy/analyzer/manifest.d.ts +112 -0
- package/dist/src/deploy/analyzer/manifest.js +8 -0
- package/dist/src/deploy/build-pipeline.d.ts +39 -0
- package/dist/src/deploy/build-pipeline.js +209 -0
- package/dist/src/deploy/bundler/bundler.d.ts +30 -0
- package/dist/src/deploy/bundler/bundler.js +196 -0
- package/dist/src/deploy/bundler/dep-extractor.d.ts +35 -0
- package/dist/src/deploy/bundler/dep-extractor.js +213 -0
- package/dist/src/deploy/bundler/index.d.ts +3 -0
- package/dist/src/deploy/bundler/index.js +2 -0
- package/dist/src/deploy/bundler/types.d.ts +21 -0
- package/dist/src/deploy/bundler/types.js +5 -0
- package/dist/src/deploy/codegen/index.d.ts +2 -0
- package/dist/src/deploy/codegen/index.js +1 -0
- package/dist/src/deploy/codegen/per-unit-codegen.d.ts +44 -0
- package/dist/src/deploy/codegen/per-unit-codegen.js +216 -0
- package/dist/src/deploy/plan/executor.d.ts +9 -0
- package/dist/src/deploy/plan/executor.js +49 -0
- package/dist/src/deploy/plan/formatter.d.ts +4 -0
- package/dist/src/deploy/plan/formatter.js +114 -0
- package/dist/src/deploy/plan/index.d.ts +5 -0
- package/dist/src/deploy/plan/index.js +3 -0
- package/dist/src/deploy/plan/planner.d.ts +4 -0
- package/dist/src/deploy/plan/planner.js +220 -0
- package/dist/src/deploy/plan/provider.d.ts +30 -0
- package/dist/src/deploy/plan/provider.js +1 -0
- package/dist/src/deploy/plan/types.d.ts +29 -0
- package/dist/src/deploy/plan/types.js +1 -0
- package/dist/src/deploy/provider-adapter.d.ts +111 -0
- package/dist/src/deploy/provider-adapter.js +10 -0
- package/dist/src/functions/commands/all.js +6 -2
- package/dist/src/functions/commands/deploy-apply.d.ts +22 -0
- package/dist/src/functions/commands/deploy-apply.js +206 -0
- package/dist/src/functions/commands/deploy-info.d.ts +1 -0
- package/dist/src/functions/commands/deploy-info.js +122 -0
- package/dist/src/functions/commands/deploy-plan.d.ts +10 -0
- package/dist/src/functions/commands/deploy-plan.js +96 -0
- package/dist/src/functions/commands/enable.js +1 -1
- package/dist/src/functions/commands/new-addon.d.ts +3 -0
- package/dist/src/functions/commands/new-addon.js +68 -2
- package/dist/src/functions/commands/pikku-command-bootstrap.js +30 -20
- package/dist/src/functions/runtimes/nextjs/pikku-command-nextjs.js +7 -3
- package/dist/src/functions/wirings/ai-agent/pikku-command-ai-agent.js +7 -5
- package/dist/src/functions/wirings/channels/pikku-channels.js +3 -0
- package/dist/src/functions/wirings/channels/pikku-command-channels.js +3 -0
- package/dist/src/functions/wirings/cli/pikku-command-cli.js +3 -0
- package/dist/src/functions/wirings/cli/serialize-channel-cli.js +2 -2
- package/dist/src/functions/wirings/console/serialize-console-functions.js +2 -2
- package/dist/src/functions/wirings/functions/pikku-command-services.d.ts +1 -1
- package/dist/src/functions/wirings/functions/pikku-command-services.js +9 -2
- package/dist/src/functions/wirings/functions/serialize-function-imports.js +5 -3
- package/dist/src/functions/wirings/functions/serialize-function-types.js +17 -19
- package/dist/src/functions/wirings/http/pikku-command-http-routes.js +3 -0
- package/dist/src/functions/wirings/http/pikku-http-routes.js +3 -0
- package/dist/src/functions/wirings/mcp/pikku-command-mcp.js +6 -0
- package/dist/src/functions/wirings/package/pikku-command-package.js +1 -1
- package/dist/src/functions/wirings/package/serialize-package.d.ts +1 -1
- package/dist/src/functions/wirings/package/serialize-package.js +5 -2
- package/dist/src/functions/wirings/queue/pikku-command-queue.js +4 -0
- package/dist/src/functions/wirings/queue/pikku-queue.js +4 -0
- package/dist/src/functions/wirings/queue/serialize-queue-map.js +4 -1
- package/dist/src/functions/wirings/rpc/pikku-command-rpc.js +10 -3
- package/dist/src/functions/wirings/rpc/serialize-public-rpc.js +5 -27
- package/dist/src/functions/wirings/rpc/serialize-remote-rpc.js +11 -14
- package/dist/src/functions/wirings/rpc/serialize-rpc-wrapper.js +28 -3
- package/dist/src/functions/wirings/rpc/serialize-typed-rpc-map.js +15 -5
- package/dist/src/functions/wirings/scheduler/pikku-command-scheduler.js +4 -0
- package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.d.ts +1 -0
- package/dist/src/functions/wirings/workflow/pikku-command-workflow-routes.js +21 -0
- package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +10 -9
- package/dist/src/functions/wirings/workflow/serialize-workflow-map.d.ts +6 -1
- package/dist/src/functions/wirings/workflow/serialize-workflow-map.js +42 -5
- package/dist/src/functions/wirings/workflow/serialize-workflow-registration.d.ts +1 -1
- package/dist/src/functions/wirings/workflow/serialize-workflow-registration.js +3 -2
- package/dist/src/functions/wirings/workflow/serialize-workflow-routes.d.ts +4 -0
- package/dist/src/functions/wirings/workflow/serialize-workflow-routes.js +139 -0
- package/dist/src/functions/wirings/workflow/serialize-workflow-types.js +4 -51
- package/dist/src/scaffold/rpc-remote.gen.d.ts +10 -0
- package/dist/src/scaffold/rpc-remote.gen.js +22 -0
- package/dist/src/services.js +12 -7
- package/dist/src/utils/pikku-cli-config.d.ts +1 -1
- package/dist/src/utils/pikku-cli-config.js +30 -28
- package/dist/src/utils/strip-verbose-meta.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -4
- package/console-app/assets/index-robZPL3O.js +0 -672
- package/dist/src/functions/wirings/workflow/serialize-workflow-workers.d.ts +0 -4
- package/dist/src/functions/wirings/workflow/serialize-workflow-workers.js +0 -47
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-agnostic deployment analyzer.
|
|
3
|
+
*
|
|
4
|
+
* Core principle: one function = one deployment unit.
|
|
5
|
+
* Each function gets its own unit with all its triggers (HTTP, queue, cron).
|
|
6
|
+
* Gateways (MCP, agents, channels) dispatch to function units via RPC.
|
|
7
|
+
* Workflow orchestrators dispatch to step units via queue or RPC (inline).
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Determine deploy target for a function based on its explicit flag
|
|
11
|
+
* and service compatibility.
|
|
12
|
+
*/
|
|
13
|
+
function resolveDeployTarget(funcMeta, serverlessIncompatible) {
|
|
14
|
+
// Explicit flag takes priority
|
|
15
|
+
if (funcMeta.deploy === 'serverless')
|
|
16
|
+
return 'serverless';
|
|
17
|
+
if (funcMeta.deploy === 'server')
|
|
18
|
+
return 'server';
|
|
19
|
+
// Auto: check if any service is serverless-incompatible
|
|
20
|
+
if (funcMeta.services?.services) {
|
|
21
|
+
for (const svc of funcMeta.services.services) {
|
|
22
|
+
if (serverlessIncompatible.has(svc))
|
|
23
|
+
return 'server';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return 'serverless';
|
|
27
|
+
}
|
|
28
|
+
export function analyzeDeployment(state, options) {
|
|
29
|
+
const serverlessIncompatible = new Set(options.serverlessIncompatible ?? []);
|
|
30
|
+
const units = [];
|
|
31
|
+
const queues = [];
|
|
32
|
+
const scheduledTasks = [];
|
|
33
|
+
const channels = [];
|
|
34
|
+
const agents = [];
|
|
35
|
+
const mcpEndpoints = [];
|
|
36
|
+
const workflows = [];
|
|
37
|
+
const functionsMeta = state.functions.meta;
|
|
38
|
+
const httpMeta = state.http.meta;
|
|
39
|
+
// ── Step 1: Create function units ──────────────────────────────────
|
|
40
|
+
// Each function gets one unit. Collect all its triggers.
|
|
41
|
+
for (const [funcId, funcMeta] of entries(functionsMeta)) {
|
|
42
|
+
// Skip platform functions — their routes/queues are handled by gateway units
|
|
43
|
+
if (funcId.startsWith('agentRun:') ||
|
|
44
|
+
funcId.startsWith('agentStream:') ||
|
|
45
|
+
funcId.startsWith('agentApprove:') ||
|
|
46
|
+
funcId.startsWith('agentResume:') ||
|
|
47
|
+
funcId.startsWith('workflowStart:') ||
|
|
48
|
+
funcId.startsWith('workflow:') ||
|
|
49
|
+
funcId.startsWith('workflowStatus:') ||
|
|
50
|
+
funcId.startsWith('pikkuWorkflowWorker:') ||
|
|
51
|
+
funcId.startsWith('pikkuWorkflowOrchestrator:')) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
// Skip scaffold catch-all functions — they're bundled into units that need them
|
|
55
|
+
if (funcId.startsWith('http:') ||
|
|
56
|
+
funcId === 'agentCaller' ||
|
|
57
|
+
funcId === 'agentStreamCaller' ||
|
|
58
|
+
funcId === 'agentApproveCaller' ||
|
|
59
|
+
funcId === 'agentResumeCaller') {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const handlers = [];
|
|
63
|
+
// HTTP routes for this function
|
|
64
|
+
const routes = collectHttpRoutes(httpMeta, funcId);
|
|
65
|
+
if (routes.length > 0) {
|
|
66
|
+
handlers.push({ type: 'fetch', routes });
|
|
67
|
+
}
|
|
68
|
+
// Queue consumer for this function
|
|
69
|
+
for (const [queueName, queueMeta] of entries(state.queueWorkers.meta)) {
|
|
70
|
+
if (queueMeta.pikkuFuncId === funcId) {
|
|
71
|
+
handlers.push({ type: 'queue', queueName: queueMeta.name ?? queueName });
|
|
72
|
+
queues.push({
|
|
73
|
+
name: queueMeta.name ?? queueName,
|
|
74
|
+
consumerUnit: toKebab(funcId),
|
|
75
|
+
consumerFunctionId: funcId,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Scheduled task for this function
|
|
80
|
+
for (const [_schedName, schedMeta] of entries(state.scheduledTasks.meta)) {
|
|
81
|
+
if (schedMeta.pikkuFuncId === funcId) {
|
|
82
|
+
handlers.push({
|
|
83
|
+
type: 'scheduled',
|
|
84
|
+
schedule: schedMeta.schedule,
|
|
85
|
+
taskName: schedMeta.name,
|
|
86
|
+
});
|
|
87
|
+
scheduledTasks.push({
|
|
88
|
+
name: schedMeta.name,
|
|
89
|
+
schedule: schedMeta.schedule,
|
|
90
|
+
unitName: toKebab(funcId),
|
|
91
|
+
functionId: funcId,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Exposed/remote functions get concrete routes via the catch-all
|
|
96
|
+
if (funcMeta.expose) {
|
|
97
|
+
const funcName = funcMeta.name ?? funcId;
|
|
98
|
+
const rpcRoute = {
|
|
99
|
+
method: 'post',
|
|
100
|
+
route: `/rpc/${funcName}`,
|
|
101
|
+
pikkuFuncId: funcId,
|
|
102
|
+
};
|
|
103
|
+
const fetchHandler = handlers.find((h) => h.type === 'fetch');
|
|
104
|
+
if (fetchHandler) {
|
|
105
|
+
fetchHandler.routes.push(rpcRoute);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
handlers.push({ type: 'fetch', routes: [rpcRoute] });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (funcMeta.remote) {
|
|
112
|
+
const funcName = funcMeta.name ?? funcId;
|
|
113
|
+
const remoteRoute = {
|
|
114
|
+
method: 'post',
|
|
115
|
+
route: `/remote/rpc/${funcName}`,
|
|
116
|
+
pikkuFuncId: funcId,
|
|
117
|
+
};
|
|
118
|
+
const fetchHandler = handlers.find((h) => h.type === 'fetch');
|
|
119
|
+
if (fetchHandler) {
|
|
120
|
+
fetchHandler.routes.push(remoteRoute);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
handlers.push({ type: 'fetch', routes: [remoteRoute] });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Skip functions with no triggers (they'll be accessed via gateways)
|
|
127
|
+
// unless they're explicitly exposed/remote
|
|
128
|
+
if (handlers.length === 0) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
units.push({
|
|
132
|
+
name: toKebab(funcId),
|
|
133
|
+
role: 'function',
|
|
134
|
+
target: resolveDeployTarget(funcMeta, serverlessIncompatible),
|
|
135
|
+
functionIds: [funcId],
|
|
136
|
+
services: collectServicesForFunction(funcMeta),
|
|
137
|
+
dependsOn: [],
|
|
138
|
+
handlers,
|
|
139
|
+
tags: funcMeta.tags ?? [],
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// ── Step 2: Agent gateways ─────────────────────────────────────────
|
|
143
|
+
for (const [agentName, agentMeta] of entries(state.agents.agentsMeta)) {
|
|
144
|
+
const toolIds = agentMeta.tools ?? [];
|
|
145
|
+
const subAgentNames = agentMeta.agents ?? [];
|
|
146
|
+
const unitName = `agent-${toKebab(agentName)}`;
|
|
147
|
+
// Agent gateway depends on its tool function units
|
|
148
|
+
const toolUnitNames = toolIds.map((id) => toKebab(id));
|
|
149
|
+
const subAgentUnitNames = subAgentNames.map((sa) => `agent-${toKebab(sa)}`);
|
|
150
|
+
// Agent needs AI services
|
|
151
|
+
const agentServices = [
|
|
152
|
+
{ capability: 'ai-model', sourceServiceName: 'aiAgentRunner' },
|
|
153
|
+
{ capability: 'ai-storage', sourceServiceName: 'aiStorage' },
|
|
154
|
+
];
|
|
155
|
+
// Concrete routes for this agent via catch-all
|
|
156
|
+
const agentRoutes = [
|
|
157
|
+
{
|
|
158
|
+
method: 'post',
|
|
159
|
+
route: `/rpc/agent/${agentName}`,
|
|
160
|
+
pikkuFuncId: `agentRun:${agentName}`,
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
method: 'post',
|
|
164
|
+
route: `/rpc/agent/${agentName}/stream`,
|
|
165
|
+
pikkuFuncId: `agentStream:${agentName}`,
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
method: 'post',
|
|
169
|
+
route: `/rpc/agent/${agentName}/approve`,
|
|
170
|
+
pikkuFuncId: `agentApprove:${agentName}`,
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
method: 'post',
|
|
174
|
+
route: `/rpc/agent/${agentName}/resume`,
|
|
175
|
+
pikkuFuncId: `agentResume:${agentName}`,
|
|
176
|
+
},
|
|
177
|
+
];
|
|
178
|
+
units.push({
|
|
179
|
+
name: unitName,
|
|
180
|
+
role: 'agent',
|
|
181
|
+
target: 'serverless',
|
|
182
|
+
functionIds: [],
|
|
183
|
+
services: agentServices,
|
|
184
|
+
dependsOn: [...toolUnitNames, ...subAgentUnitNames],
|
|
185
|
+
handlers: [{ type: 'fetch', routes: agentRoutes }],
|
|
186
|
+
tags: agentMeta.tags ?? [],
|
|
187
|
+
});
|
|
188
|
+
agents.push({
|
|
189
|
+
name: agentMeta.name,
|
|
190
|
+
unitName,
|
|
191
|
+
toolFunctionIds: toolIds,
|
|
192
|
+
subAgentNames,
|
|
193
|
+
model: agentMeta.model,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
// ── Step 3: MCP gateway ────────────────────────────────────────────
|
|
197
|
+
const mcpToolIds = values(state.mcpEndpoints.toolsMeta).map((t) => t.pikkuFuncId);
|
|
198
|
+
const mcpResourceIds = values(state.mcpEndpoints.resourcesMeta).map((r) => r.pikkuFuncId);
|
|
199
|
+
const mcpPromptIds = values(state.mcpEndpoints.promptsMeta).map((p) => p.pikkuFuncId);
|
|
200
|
+
// Include functions explicitly marked mcp: true
|
|
201
|
+
for (const [funcId, funcMeta] of entries(functionsMeta)) {
|
|
202
|
+
if (funcMeta.mcp &&
|
|
203
|
+
!mcpToolIds.includes(funcId) &&
|
|
204
|
+
!mcpResourceIds.includes(funcId) &&
|
|
205
|
+
!mcpPromptIds.includes(funcId)) {
|
|
206
|
+
mcpToolIds.push(funcId);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const allMcpIds = [...mcpToolIds, ...mcpResourceIds, ...mcpPromptIds];
|
|
210
|
+
if (allMcpIds.length > 0) {
|
|
211
|
+
const unitName = 'mcp-server';
|
|
212
|
+
const mcpFuncUnitNames = allMcpIds.map((id) => toKebab(id));
|
|
213
|
+
units.push({
|
|
214
|
+
name: unitName,
|
|
215
|
+
role: 'mcp',
|
|
216
|
+
target: 'serverless',
|
|
217
|
+
functionIds: [], // No function code bundled
|
|
218
|
+
services: [],
|
|
219
|
+
dependsOn: mcpFuncUnitNames,
|
|
220
|
+
handlers: [{ type: 'fetch', routes: [] }],
|
|
221
|
+
tags: collectTags(allMcpIds, functionsMeta),
|
|
222
|
+
});
|
|
223
|
+
mcpEndpoints.push({
|
|
224
|
+
unitName,
|
|
225
|
+
toolFunctionIds: mcpToolIds,
|
|
226
|
+
resourceFunctionIds: mcpResourceIds,
|
|
227
|
+
promptFunctionIds: mcpPromptIds,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
// ── Step 4: Channel gateways ───────────────────────────────────────
|
|
231
|
+
for (const [channelName, channelMeta] of entries(state.channels.meta)) {
|
|
232
|
+
const funcIds = collectChannelFunctionIds(channelMeta);
|
|
233
|
+
if (funcIds.length === 0)
|
|
234
|
+
continue;
|
|
235
|
+
const unitName = `channel-${toKebab(channelName)}`;
|
|
236
|
+
const funcUnitNames = funcIds.map((id) => toKebab(id));
|
|
237
|
+
units.push({
|
|
238
|
+
name: unitName,
|
|
239
|
+
role: 'channel',
|
|
240
|
+
target: 'serverless',
|
|
241
|
+
functionIds: [], // No function code bundled
|
|
242
|
+
services: [],
|
|
243
|
+
dependsOn: funcUnitNames,
|
|
244
|
+
handlers: [{ type: 'fetch', routes: [] }],
|
|
245
|
+
tags: channelMeta.tags ?? [],
|
|
246
|
+
});
|
|
247
|
+
channels.push({
|
|
248
|
+
name: channelMeta.name,
|
|
249
|
+
route: channelMeta.route,
|
|
250
|
+
unitName,
|
|
251
|
+
functionIds: funcIds,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
// ── Step 5: Workflows ──────────────────────────────────────────────
|
|
255
|
+
buildWorkflows(state.workflows.graphMeta, functionsMeta, httpMeta, units, workflows, queues);
|
|
256
|
+
// ── Step 6: Ensure function units exist for gateway dependencies ───
|
|
257
|
+
// Gateways depend on function units. If a function is only used via
|
|
258
|
+
// a gateway (not directly wired to HTTP/queue/cron), it still needs
|
|
259
|
+
// a unit with a fetch handler for RPC access.
|
|
260
|
+
const existingUnitNames = new Set(units.map((u) => u.name));
|
|
261
|
+
const unitsSnapshot = Array.from(units);
|
|
262
|
+
for (const unit of unitsSnapshot) {
|
|
263
|
+
for (const dep of unit.dependsOn) {
|
|
264
|
+
if (!existingUnitNames.has(dep)) {
|
|
265
|
+
// Find the function ID for this dependency
|
|
266
|
+
const funcId = fromKebab(dep);
|
|
267
|
+
const funcMeta = functionsMeta[funcId];
|
|
268
|
+
if (funcMeta) {
|
|
269
|
+
units.push({
|
|
270
|
+
name: dep,
|
|
271
|
+
role: 'function',
|
|
272
|
+
target: resolveDeployTarget(funcMeta, serverlessIncompatible),
|
|
273
|
+
functionIds: [funcId],
|
|
274
|
+
services: collectServicesForFunction(funcMeta),
|
|
275
|
+
dependsOn: [],
|
|
276
|
+
handlers: [{ type: 'fetch', routes: [] }],
|
|
277
|
+
tags: funcMeta.tags ?? [],
|
|
278
|
+
});
|
|
279
|
+
existingUnitNames.add(dep);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// ── Step 7: Wire queues to their consumer units ──
|
|
285
|
+
// All queues (user-defined + workflow-generated) now have consumerUnit set.
|
|
286
|
+
// Wire the queue handler onto the unit and add workflow services if needed.
|
|
287
|
+
for (const queue of queues) {
|
|
288
|
+
const unit = units.find((u) => u.name === queue.consumerUnit);
|
|
289
|
+
if (!unit)
|
|
290
|
+
continue;
|
|
291
|
+
// Add queue handler if not already present
|
|
292
|
+
const hasQueueHandler = unit.handlers.some((h) => h.type === 'queue' && h.queueName === queue.name);
|
|
293
|
+
if (!hasQueueHandler) {
|
|
294
|
+
unit.handlers.push({ type: 'queue', queueName: queue.name });
|
|
295
|
+
}
|
|
296
|
+
// Workflow step workers need D1 for step state + queue for re-queuing orchestrator
|
|
297
|
+
if (queue.consumerFunctionId.startsWith('pikkuWorkflowWorker:')) {
|
|
298
|
+
if (!unit.services.some((s) => s.capability === 'workflow-state')) {
|
|
299
|
+
unit.services.push({
|
|
300
|
+
capability: 'workflow-state',
|
|
301
|
+
sourceServiceName: 'workflowService',
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
if (!unit.services.some((s) => s.capability === 'queue')) {
|
|
305
|
+
unit.services.push({
|
|
306
|
+
capability: 'queue',
|
|
307
|
+
sourceServiceName: 'queueService',
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// ── Secrets & Variables ────────────────────────────────────────────
|
|
313
|
+
const secrets = state.secrets.definitions.map((s) => ({
|
|
314
|
+
secretId: s.secretId,
|
|
315
|
+
displayName: s.displayName,
|
|
316
|
+
description: s.description,
|
|
317
|
+
}));
|
|
318
|
+
const variables = state.variables.definitions.map((v) => ({
|
|
319
|
+
variableId: v.variableId,
|
|
320
|
+
displayName: v.displayName,
|
|
321
|
+
description: v.description,
|
|
322
|
+
}));
|
|
323
|
+
return {
|
|
324
|
+
projectId: options.projectId,
|
|
325
|
+
manifestVersion: 1,
|
|
326
|
+
units,
|
|
327
|
+
queues,
|
|
328
|
+
scheduledTasks,
|
|
329
|
+
channels,
|
|
330
|
+
agents,
|
|
331
|
+
mcpEndpoints,
|
|
332
|
+
workflows,
|
|
333
|
+
secrets,
|
|
334
|
+
variables,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
// ---------------------------------------------------------------------------
|
|
338
|
+
// Workflow builder
|
|
339
|
+
// ---------------------------------------------------------------------------
|
|
340
|
+
function buildWorkflows(graphMeta, _functionsMeta, _httpMeta, units, workflows, queues) {
|
|
341
|
+
for (const [_wfName, graph] of entries(graphMeta)) {
|
|
342
|
+
const steps = [];
|
|
343
|
+
const stepUnitNames = [];
|
|
344
|
+
for (const [nodeId, node] of Object.entries(graph.nodes)) {
|
|
345
|
+
if ('flow' in node)
|
|
346
|
+
continue;
|
|
347
|
+
if (!('rpcName' in node))
|
|
348
|
+
continue;
|
|
349
|
+
const stepUnitName = toKebab(node.rpcName);
|
|
350
|
+
const isAsync = node.options?.async === true;
|
|
351
|
+
const isInline = !isAsync && graph.inline === true;
|
|
352
|
+
steps.push({
|
|
353
|
+
name: node.stepName ?? nodeId,
|
|
354
|
+
inline: isInline,
|
|
355
|
+
functionId: node.rpcName,
|
|
356
|
+
unitName: stepUnitName,
|
|
357
|
+
});
|
|
358
|
+
stepUnitNames.push(stepUnitName);
|
|
359
|
+
}
|
|
360
|
+
// Build orchestrator unit — no function code, just orchestration
|
|
361
|
+
const orchUnitName = `wf-${toKebab(graph.name)}`;
|
|
362
|
+
const orchServices = [
|
|
363
|
+
{ capability: 'workflow-state', sourceServiceName: 'workflowService' },
|
|
364
|
+
{ capability: 'queue', sourceServiceName: 'queueService' },
|
|
365
|
+
];
|
|
366
|
+
// Concrete routes for this workflow via catch-all
|
|
367
|
+
const wfRoutes = [
|
|
368
|
+
{
|
|
369
|
+
method: 'post',
|
|
370
|
+
route: `/workflow/${graph.name}/start`,
|
|
371
|
+
pikkuFuncId: `workflowStart:${graph.name}`,
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
method: 'post',
|
|
375
|
+
route: `/workflow/${graph.name}/run`,
|
|
376
|
+
pikkuFuncId: `workflow:${graph.name}`,
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
method: 'get',
|
|
380
|
+
route: `/workflow/${graph.name}/status/:runId`,
|
|
381
|
+
pikkuFuncId: `workflowStatus:${graph.name}`,
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
method: 'post',
|
|
385
|
+
route: `/workflow/${graph.name}/graph/:nodeId`,
|
|
386
|
+
pikkuFuncId: `graphStart:${graph.name}`,
|
|
387
|
+
},
|
|
388
|
+
];
|
|
389
|
+
// Orchestrator queue — the orchestrator consumes from this
|
|
390
|
+
const orchQueueName = `wf-orchestrator-${toKebab(graph.name)}`;
|
|
391
|
+
const orchHandlers = [
|
|
392
|
+
{ type: 'fetch', routes: wfRoutes },
|
|
393
|
+
{ type: 'queue', queueName: orchQueueName },
|
|
394
|
+
];
|
|
395
|
+
units.push({
|
|
396
|
+
name: orchUnitName,
|
|
397
|
+
role: 'workflow',
|
|
398
|
+
target: 'serverless',
|
|
399
|
+
functionIds: [],
|
|
400
|
+
services: orchServices,
|
|
401
|
+
dependsOn: stepUnitNames,
|
|
402
|
+
handlers: orchHandlers,
|
|
403
|
+
tags: [],
|
|
404
|
+
});
|
|
405
|
+
queues.push({
|
|
406
|
+
name: orchQueueName,
|
|
407
|
+
consumerUnit: orchUnitName,
|
|
408
|
+
consumerFunctionId: `pikkuWorkflowOrchestrator:${graph.name}`,
|
|
409
|
+
});
|
|
410
|
+
// Per-step queues — each step function worker consumes its own queue.
|
|
411
|
+
// The step units may not exist yet (created in step 6), so we just
|
|
412
|
+
// create queue definitions here. Step 7 wires them to units.
|
|
413
|
+
for (const step of steps) {
|
|
414
|
+
if (step.inline || !step.functionId)
|
|
415
|
+
continue;
|
|
416
|
+
const stepQueueName = `wf-step-${toKebab(step.functionId)}`;
|
|
417
|
+
queues.push({
|
|
418
|
+
name: stepQueueName,
|
|
419
|
+
consumerUnit: toKebab(step.functionId),
|
|
420
|
+
consumerFunctionId: `pikkuWorkflowWorker:${step.functionId}`,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
workflows.push({
|
|
424
|
+
name: graph.name,
|
|
425
|
+
pikkuFuncId: graph.pikkuFuncId,
|
|
426
|
+
orchestratorUnit: orchUnitName,
|
|
427
|
+
steps,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
// ---------------------------------------------------------------------------
|
|
432
|
+
// Service mapping
|
|
433
|
+
// ---------------------------------------------------------------------------
|
|
434
|
+
const SERVICE_CAPABILITY_MAP = {
|
|
435
|
+
kysely: 'database',
|
|
436
|
+
database: 'database',
|
|
437
|
+
db: 'database',
|
|
438
|
+
contentService: 'object-storage',
|
|
439
|
+
content: 'object-storage',
|
|
440
|
+
storage: 'object-storage',
|
|
441
|
+
queueService: 'queue',
|
|
442
|
+
aiAgentRunner: 'ai-model',
|
|
443
|
+
ai: 'ai-model',
|
|
444
|
+
aiStorage: 'ai-storage',
|
|
445
|
+
workflowService: 'workflow-state',
|
|
446
|
+
workflow: 'workflow-state',
|
|
447
|
+
credentialService: 'credential-store',
|
|
448
|
+
credentials: 'credential-store',
|
|
449
|
+
schedulerService: 'scheduler',
|
|
450
|
+
};
|
|
451
|
+
function mapServiceToRequirement(serviceName) {
|
|
452
|
+
const capability = SERVICE_CAPABILITY_MAP[serviceName];
|
|
453
|
+
if (!capability)
|
|
454
|
+
return null;
|
|
455
|
+
return { capability, sourceServiceName: serviceName };
|
|
456
|
+
}
|
|
457
|
+
function collectServicesForFunction(funcMeta) {
|
|
458
|
+
if (!funcMeta?.services?.services)
|
|
459
|
+
return [];
|
|
460
|
+
const requirements = [];
|
|
461
|
+
const seen = new Set();
|
|
462
|
+
for (const svc of funcMeta.services.services) {
|
|
463
|
+
const req = mapServiceToRequirement(svc);
|
|
464
|
+
if (req && !seen.has(req.capability)) {
|
|
465
|
+
requirements.push(req);
|
|
466
|
+
seen.add(req.capability);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return requirements;
|
|
470
|
+
}
|
|
471
|
+
// ---------------------------------------------------------------------------
|
|
472
|
+
// HTTP route helpers
|
|
473
|
+
// ---------------------------------------------------------------------------
|
|
474
|
+
const HTTP_METHODS = [
|
|
475
|
+
'get',
|
|
476
|
+
'post',
|
|
477
|
+
'put',
|
|
478
|
+
'delete',
|
|
479
|
+
'head',
|
|
480
|
+
'patch',
|
|
481
|
+
'options',
|
|
482
|
+
];
|
|
483
|
+
function collectHttpRoutes(httpMeta, funcId) {
|
|
484
|
+
const routes = [];
|
|
485
|
+
for (const method of HTTP_METHODS) {
|
|
486
|
+
const methodRoutes = httpMeta[method];
|
|
487
|
+
if (!methodRoutes)
|
|
488
|
+
continue;
|
|
489
|
+
for (const routeMeta of values(methodRoutes)) {
|
|
490
|
+
if (routeMeta.pikkuFuncId === funcId) {
|
|
491
|
+
routes.push({
|
|
492
|
+
method: method.toUpperCase(),
|
|
493
|
+
route: routeMeta.route,
|
|
494
|
+
pikkuFuncId: funcId,
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return routes;
|
|
500
|
+
}
|
|
501
|
+
// ---------------------------------------------------------------------------
|
|
502
|
+
// Channel helpers
|
|
503
|
+
// ---------------------------------------------------------------------------
|
|
504
|
+
function collectChannelFunctionIds(channelMeta) {
|
|
505
|
+
const ids = [];
|
|
506
|
+
if (channelMeta.connect?.pikkuFuncId)
|
|
507
|
+
ids.push(channelMeta.connect.pikkuFuncId);
|
|
508
|
+
if (channelMeta.disconnect?.pikkuFuncId)
|
|
509
|
+
ids.push(channelMeta.disconnect.pikkuFuncId);
|
|
510
|
+
if (channelMeta.message?.pikkuFuncId)
|
|
511
|
+
ids.push(channelMeta.message.pikkuFuncId);
|
|
512
|
+
if (channelMeta.messageWirings) {
|
|
513
|
+
for (const commandGroup of values(channelMeta.messageWirings)) {
|
|
514
|
+
for (const wiring of values(commandGroup)) {
|
|
515
|
+
if (wiring.pikkuFuncId) {
|
|
516
|
+
ids.push(wiring.pikkuFuncId);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return [...new Set(ids)];
|
|
522
|
+
}
|
|
523
|
+
// ---------------------------------------------------------------------------
|
|
524
|
+
// Naming helpers
|
|
525
|
+
// ---------------------------------------------------------------------------
|
|
526
|
+
function toKebab(str) {
|
|
527
|
+
return str
|
|
528
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
529
|
+
.replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
|
|
530
|
+
.toLowerCase();
|
|
531
|
+
}
|
|
532
|
+
function fromKebab(str) {
|
|
533
|
+
return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
534
|
+
}
|
|
535
|
+
// ---------------------------------------------------------------------------
|
|
536
|
+
// Tag helpers
|
|
537
|
+
// ---------------------------------------------------------------------------
|
|
538
|
+
function collectTags(funcIds, functionsMeta) {
|
|
539
|
+
const tags = new Set();
|
|
540
|
+
for (const id of funcIds) {
|
|
541
|
+
const meta = functionsMeta[id];
|
|
542
|
+
if (meta?.tags) {
|
|
543
|
+
for (const tag of meta.tags)
|
|
544
|
+
tags.add(tag);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return [...tags];
|
|
548
|
+
}
|
|
549
|
+
// ---------------------------------------------------------------------------
|
|
550
|
+
// Typed iteration helpers
|
|
551
|
+
// ---------------------------------------------------------------------------
|
|
552
|
+
function entries(record) {
|
|
553
|
+
return Object.entries(record);
|
|
554
|
+
}
|
|
555
|
+
function values(record) {
|
|
556
|
+
return Object.values(record);
|
|
557
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { analyzeDeployment } from './analyzer.js';
|
|
2
|
+
export type { AnalyzerOptions } from './analyzer.js';
|
|
3
|
+
export type { DeploymentManifest, DeploymentUnit, DeploymentUnitRole, ServiceCapability, ServiceRequirement, HttpRouteInfo, QueueDefinition, ScheduledTaskDefinition, ChannelDefinition, AgentDefinition, MCPEndpointDefinition, WorkflowStepDefinition, WorkflowDefinition, SecretDeclaration, VariableDeclaration, } from './manifest.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { analyzeDeployment } from './analyzer.js';
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-agnostic deployment manifest types.
|
|
3
|
+
*
|
|
4
|
+
* Core principle: one function = one deployment unit.
|
|
5
|
+
* Gateways (MCP, agents, channels, workflow orchestrators)
|
|
6
|
+
* don't bundle function code — they dispatch via RPC.
|
|
7
|
+
*/
|
|
8
|
+
/** What kind of deployment entry */
|
|
9
|
+
export type DeploymentUnitRole = 'function' | 'mcp' | 'agent' | 'channel' | 'workflow' | 'workflow-step';
|
|
10
|
+
/** What handlers a unit needs to export */
|
|
11
|
+
export type DeploymentHandler = {
|
|
12
|
+
type: 'fetch';
|
|
13
|
+
routes: HttpRouteInfo[];
|
|
14
|
+
} | {
|
|
15
|
+
type: 'queue';
|
|
16
|
+
queueName: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'scheduled';
|
|
19
|
+
schedule: string;
|
|
20
|
+
taskName: string;
|
|
21
|
+
};
|
|
22
|
+
/** Abstract infrastructure capability */
|
|
23
|
+
export type ServiceCapability = 'database' | 'object-storage' | 'queue' | 'kv' | 'ai-model' | 'ai-storage' | 'scheduler' | 'workflow-state' | 'credential-store';
|
|
24
|
+
export interface ServiceRequirement {
|
|
25
|
+
capability: ServiceCapability;
|
|
26
|
+
/** Original service name from code (e.g. 'kysely', 'contentService') */
|
|
27
|
+
sourceServiceName: string;
|
|
28
|
+
}
|
|
29
|
+
export interface HttpRouteInfo {
|
|
30
|
+
method: string;
|
|
31
|
+
route: string;
|
|
32
|
+
pikkuFuncId: string;
|
|
33
|
+
}
|
|
34
|
+
export interface DeploymentUnit {
|
|
35
|
+
name: string;
|
|
36
|
+
role: DeploymentUnitRole;
|
|
37
|
+
/** Deploy target: serverless (CF Worker / Lambda) or server (container) */
|
|
38
|
+
target: 'serverless' | 'server';
|
|
39
|
+
/** Functions bundled in this unit (for function/workflow-step units) */
|
|
40
|
+
functionIds: string[];
|
|
41
|
+
services: ServiceRequirement[];
|
|
42
|
+
/** Other unit names this unit calls via RPC / service bindings */
|
|
43
|
+
dependsOn: string[];
|
|
44
|
+
/** What runtime handlers this unit needs to export */
|
|
45
|
+
handlers: DeploymentHandler[];
|
|
46
|
+
tags: string[];
|
|
47
|
+
}
|
|
48
|
+
export interface QueueDefinition {
|
|
49
|
+
name: string;
|
|
50
|
+
consumerUnit: string;
|
|
51
|
+
consumerFunctionId: string;
|
|
52
|
+
}
|
|
53
|
+
export interface ScheduledTaskDefinition {
|
|
54
|
+
name: string;
|
|
55
|
+
schedule: string;
|
|
56
|
+
unitName: string;
|
|
57
|
+
functionId: string;
|
|
58
|
+
}
|
|
59
|
+
export interface ChannelDefinition {
|
|
60
|
+
name: string;
|
|
61
|
+
route: string;
|
|
62
|
+
unitName: string;
|
|
63
|
+
functionIds: string[];
|
|
64
|
+
}
|
|
65
|
+
export interface AgentDefinition {
|
|
66
|
+
name: string;
|
|
67
|
+
unitName: string;
|
|
68
|
+
toolFunctionIds: string[];
|
|
69
|
+
subAgentNames: string[];
|
|
70
|
+
model: string;
|
|
71
|
+
}
|
|
72
|
+
export interface MCPEndpointDefinition {
|
|
73
|
+
unitName: string;
|
|
74
|
+
toolFunctionIds: string[];
|
|
75
|
+
resourceFunctionIds: string[];
|
|
76
|
+
promptFunctionIds: string[];
|
|
77
|
+
}
|
|
78
|
+
export interface WorkflowStepDefinition {
|
|
79
|
+
name: string;
|
|
80
|
+
inline: boolean;
|
|
81
|
+
functionId?: string;
|
|
82
|
+
unitName?: string;
|
|
83
|
+
}
|
|
84
|
+
export interface WorkflowDefinition {
|
|
85
|
+
name: string;
|
|
86
|
+
pikkuFuncId: string;
|
|
87
|
+
orchestratorUnit: string;
|
|
88
|
+
steps: WorkflowStepDefinition[];
|
|
89
|
+
}
|
|
90
|
+
export interface SecretDeclaration {
|
|
91
|
+
secretId: string;
|
|
92
|
+
displayName: string;
|
|
93
|
+
description?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface VariableDeclaration {
|
|
96
|
+
variableId: string;
|
|
97
|
+
displayName: string;
|
|
98
|
+
description?: string;
|
|
99
|
+
}
|
|
100
|
+
export interface DeploymentManifest {
|
|
101
|
+
projectId: string;
|
|
102
|
+
manifestVersion: 1;
|
|
103
|
+
units: DeploymentUnit[];
|
|
104
|
+
queues: QueueDefinition[];
|
|
105
|
+
scheduledTasks: ScheduledTaskDefinition[];
|
|
106
|
+
channels: ChannelDefinition[];
|
|
107
|
+
agents: AgentDefinition[];
|
|
108
|
+
mcpEndpoints: MCPEndpointDefinition[];
|
|
109
|
+
workflows: WorkflowDefinition[];
|
|
110
|
+
secrets: SecretDeclaration[];
|
|
111
|
+
variables: VariableDeclaration[];
|
|
112
|
+
}
|