@pikku/cli 0.12.91 → 0.12.93
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/LICENSE +106 -0
- package/console-app/assets/{index-D0HG8q0B.css → index-BYj7ZbUU.css} +1 -1
- package/console-app/assets/{index-CpkvmAGb.js → index-CmAplHjZ.js} +151 -149
- package/console-app/index.html +2 -2
- 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-contracts-meta.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-contracts-meta.gen.json +15 -0
- 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 +48 -0
- 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 +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +73 -40
- package/dist/.pikku/function/pikku-functions.gen.js +1 -3
- 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/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-scenarios.gen.d.ts +2 -1
- package/dist/.pikku/pikku-bootstrap-scenarios.gen.js +2 -1
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +1 -1
- 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/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.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 +3 -1
- package/dist/.pikku/scenarios/pikku-scenario-functions-meta.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-functions.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-wirings-meta.gen.js +1 -1
- package/dist/.pikku/scenarios/pikku-scenario-wirings.gen.d.ts +1 -1
- package/dist/.pikku/scenarios/schemas/register.gen.d.ts +4 -0
- package/dist/.pikku/scenarios/schemas/register.gen.js +4 -0
- 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 +13 -3
- package/dist/.pikku/schemas/schemas/FabricSecretsListOutput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/FabricSecretsRotateInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/FabricSecretsRotateOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/FabricSecretsSetOutput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/KnowledgeIndexInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/KnowledgeIndexOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/KnowledgeValidateInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/KnowledgeValidateOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/ScenarioRunInput.schema.json +1 -1
- package/dist/.pikku/scopes/pikku-scope-types.gen.d.ts +1 -1
- package/dist/.pikku/scopes/pikku-scope-types.gen.js +1 -1
- package/dist/.pikku/scopes/pikku-scopes.gen.d.ts +1 -1
- 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/meta/allWorkflow.gen.json +2 -8
- package/dist/.pikku/workflow/pikku-scenario-actors.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-scenario-actors.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/src/cli.wiring.js +29 -0
- package/dist/src/deploy/analyzer/analyzer.js +22 -5
- package/dist/src/deploy/build-pipeline.js +5 -1
- package/dist/src/fabric/fabric-commands.d.ts +37 -9
- package/dist/src/fabric/fabric-commands.js +12 -0
- package/dist/src/fabric/functions/domains-add.function.d.ts +4 -4
- package/dist/src/fabric/functions/secrets-list.function.d.ts +16 -4
- package/dist/src/fabric/functions/secrets-list.function.js +12 -10
- package/dist/src/fabric/functions/secrets-rotate.function.d.ts +24 -0
- package/dist/src/fabric/functions/secrets-rotate.function.js +36 -0
- package/dist/src/fabric/functions/secrets-set.function.d.ts +8 -4
- package/dist/src/fabric/functions/secrets-set.function.js +18 -7
- package/dist/src/fabric/functions/validate.function.js +16 -7
- package/dist/src/fabric/lib/http.d.ts +7 -1
- package/dist/src/fabric/lib/sealed-box.d.ts +16 -0
- package/dist/src/fabric/lib/sealed-box.js +72 -0
- package/dist/src/functions/commands/dev.js +9 -0
- package/dist/src/functions/commands/knowledge-index.d.ts +30 -0
- package/dist/src/functions/commands/knowledge-index.js +11 -0
- package/dist/src/functions/commands/knowledge-validate.d.ts +33 -0
- package/dist/src/functions/commands/knowledge-validate.js +11 -0
- package/dist/src/functions/commands/new-addon.d.ts +18 -0
- package/dist/src/functions/commands/new-addon.js +40 -24
- package/dist/src/functions/commands/pikku-command-bootstrap.js +1 -0
- package/dist/src/functions/commands/scenario-browser.d.ts +17 -2
- package/dist/src/functions/commands/scenario-browser.js +16 -8
- package/dist/src/functions/commands/scenario-environment.d.ts +32 -0
- package/dist/src/functions/commands/scenario-environment.js +61 -0
- package/dist/src/functions/commands/scenario.d.ts +6 -0
- package/dist/src/functions/commands/scenario.js +14 -9
- package/dist/src/functions/commands/skills.js +27 -61
- package/dist/src/functions/db/db-codegen.d.ts +6 -0
- package/dist/src/functions/db/db-codegen.js +9 -0
- package/dist/src/functions/db/db-migrator.js +14 -0
- package/dist/src/functions/db/local-db.d.ts +8 -0
- package/dist/src/functions/db/local-db.js +24 -2
- package/dist/src/functions/db/migration-identifiers.d.ts +58 -0
- package/dist/src/functions/db/migration-identifiers.js +262 -0
- package/dist/src/functions/db/migration-provenance.d.ts +35 -0
- package/dist/src/functions/db/migration-provenance.js +80 -0
- package/dist/src/functions/db/schema-sql.d.ts +43 -0
- package/dist/src/functions/db/schema-sql.js +135 -0
- package/dist/src/functions/db/sqlite/sqlite-kysely.js +22 -2
- package/dist/src/functions/knowledge/render.d.ts +3 -0
- package/dist/src/functions/knowledge/render.js +66 -0
- package/dist/src/functions/knowledge/schemas.d.ts +51 -0
- package/dist/src/functions/knowledge/schemas.js +25 -0
- package/dist/src/functions/wirings/credentials/serialize-credentials-types.js +8 -1
- package/dist/src/functions/wirings/functions/schemas.js +13 -1
- package/dist/src/functions/wirings/rpc/pikku-command-rpc.js +6 -1
- package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.d.ts +10 -0
- package/dist/src/functions/wirings/scenarios/register-scenario-instrumentation.js +102 -0
- package/dist/src/functions/wirings/scenarios/scenario-partition.d.ts +13 -0
- package/dist/src/functions/wirings/scenarios/scenario-partition.js +15 -2
- package/dist/src/functions/wirings/scenarios/scenario-schema-partition.d.ts +33 -0
- package/dist/src/functions/wirings/scenarios/scenario-schema-partition.js +49 -0
- package/dist/src/functions/wirings/secrets/serialize-secrets-types.js +10 -3
- package/dist/src/functions/wirings/variables/serialize-variables-types.js +8 -1
- package/dist/src/functions/workflows/all.workflow.js +2 -7
- package/dist/src/utils/file-writer.js +14 -2
- package/dist/src/utils/pikku-cli-config.d.ts +14 -0
- package/dist/src/utils/pikku-cli-config.js +34 -0
- package/dist/src/utils/remove-legacy-scaffold-file.d.ts +14 -0
- package/dist/src/utils/remove-legacy-scaffold-file.js +23 -0
- package/dist/src/utils/serialize-schemas.d.ts +3 -1
- package/dist/src/utils/serialize-schemas.js +39 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -9
- package/dist/.pikku/schemas/schemas/PikkuScenarioFunctionsOutput.schema.json +0 -1
- package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.d.ts +0 -1
- package/dist/src/functions/wirings/scenarios/pikku-command-scenario-functions.js +0 -31
- package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.d.ts +0 -10
- package/dist/src/functions/wirings/scenarios/serialize-scenario-functions.js +0 -104
- package/skills/pikku-addon/SKILL.md +0 -243
- package/skills/pikku-addon/references/addon-package-manifest.md +0 -63
- package/skills/pikku-ai-agent/SKILL.md +0 -231
- package/skills/pikku-ai-vercel/SKILL.md +0 -82
- package/skills/pikku-ai-voice/SKILL.md +0 -88
- package/skills/pikku-audit/SKILL.md +0 -175
- package/skills/pikku-aws/SKILL.md +0 -111
- package/skills/pikku-backblaze/SKILL.md +0 -71
- package/skills/pikku-better-auth/SKILL.md +0 -298
- package/skills/pikku-cli/SKILL.md +0 -198
- package/skills/pikku-cli/references/complete-example.md +0 -82
- package/skills/pikku-concepts/SKILL.md +0 -250
- package/skills/pikku-concepts/references/concept-mapping.md +0 -556
- package/skills/pikku-concepts/references/packages.md +0 -29
- package/skills/pikku-config/SKILL.md +0 -212
- package/skills/pikku-cron/SKILL.md +0 -214
- package/skills/pikku-deploy-azure/SKILL.md +0 -71
- package/skills/pikku-deploy-cloudflare/SKILL.md +0 -82
- package/skills/pikku-deploy-express/SKILL.md +0 -86
- package/skills/pikku-deploy-fastify/SKILL.md +0 -73
- package/skills/pikku-deploy-lambda/SKILL.md +0 -110
- package/skills/pikku-deploy-nextjs/SKILL.md +0 -78
- package/skills/pikku-deploy-uws/SKILL.md +0 -88
- package/skills/pikku-deps/SKILL.md +0 -98
- package/skills/pikku-emails/SKILL.md +0 -163
- package/skills/pikku-fabric/SKILL.md +0 -318
- package/skills/pikku-fabric-debug/SKILL.md +0 -112
- package/skills/pikku-feature/SKILL.md +0 -258
- package/skills/pikku-gateway-slack/SKILL.md +0 -115
- package/skills/pikku-http/SKILL.md +0 -220
- package/skills/pikku-http/references/http-options.md +0 -55
- package/skills/pikku-i18n/SKILL.md +0 -137
- package/skills/pikku-info/SKILL.md +0 -100
- package/skills/pikku-jose/SKILL.md +0 -105
- package/skills/pikku-kysely/SKILL.md +0 -219
- package/skills/pikku-machine-auth/SKILL.md +0 -183
- package/skills/pikku-mcp/SKILL.md +0 -241
- package/skills/pikku-middleware/SKILL.md +0 -231
- package/skills/pikku-middleware/references/middleware-patterns.md +0 -61
- package/skills/pikku-mongodb/SKILL.md +0 -105
- package/skills/pikku-n8n-import/SKILL.md +0 -109
- package/skills/pikku-n8n-import/SPEC.md +0 -84
- package/skills/pikku-n8n-import/references/addon-mapping.md +0 -121
- package/skills/pikku-n8n-import/references/code-translation.md +0 -121
- package/skills/pikku-n8n-import/references/loops-and-control.md +0 -87
- package/skills/pikku-paraglide/SKILL.md +0 -117
- package/skills/pikku-permissions/SKILL.md +0 -192
- package/skills/pikku-pino/SKILL.md +0 -79
- package/skills/pikku-product-second-opinion/README.md +0 -43
- package/skills/pikku-product-second-opinion/SKILL.md +0 -158
- package/skills/pikku-product-second-opinion/example/sample-report.md +0 -90
- package/skills/pikku-product-second-opinion/references/report-template.md +0 -73
- package/skills/pikku-queue/SKILL.md +0 -240
- package/skills/pikku-react/SKILL.md +0 -212
- package/skills/pikku-react-query/SKILL.md +0 -242
- package/skills/pikku-realtime/SKILL.md +0 -236
- package/skills/pikku-realtime/references/other-routes.md +0 -23
- package/skills/pikku-redis/SKILL.md +0 -90
- package/skills/pikku-rpc/SKILL.md +0 -171
- package/skills/pikku-rtl/SKILL.md +0 -219
- package/skills/pikku-scenario/SKILL.md +0 -382
- package/skills/pikku-schedule/SKILL.md +0 -57
- package/skills/pikku-schema-ajv/SKILL.md +0 -62
- package/skills/pikku-schema-cfworker/SKILL.md +0 -63
- package/skills/pikku-security/SKILL.md +0 -108
- package/skills/pikku-services/SKILL.md +0 -248
- package/skills/pikku-services/references/audit-wire-service.md +0 -34
- package/skills/pikku-software-archaeology/README.md +0 -70
- package/skills/pikku-software-archaeology/SKILL.md +0 -186
- package/skills/pikku-software-archaeology/references/blueprint.schema.json +0 -625
- package/skills/pikku-software-archaeology/references/pikku-mapping.md +0 -49
- package/skills/pikku-software-archaeology/scripts/validate.mjs +0 -173
- package/skills/pikku-tag-middleware/SKILL.md +0 -13
- package/skills/pikku-template-clone/SKILL.md +0 -40
- package/skills/pikku-trigger/SKILL.md +0 -181
- package/skills/pikku-versioning/SKILL.md +0 -173
- package/skills/pikku-websocket/SKILL.md +0 -243
- package/skills/pikku-workflow/SKILL.md +0 -172
- package/skills/pikku-workflow/references/workflow-reference.md +0 -63
- package/skills/pikku-workflows-client/SKILL.md +0 -150
- package/skills/pikku-ws/SKILL.md +0 -47
package/dist/src/cli.wiring.js
CHANGED
|
@@ -29,6 +29,8 @@ import { scopesAudit } from './functions/commands/scopes-audit.js';
|
|
|
29
29
|
import { scopesPrune } from './functions/commands/scopes-prune.js';
|
|
30
30
|
import { pikkuAudit } from './functions/commands/audit.js';
|
|
31
31
|
import { workspaceValidate, renderWorkspaceValidate, } from './functions/commands/workspace-validate.js';
|
|
32
|
+
import { knowledgeValidate, renderKnowledgeValidate, } from './functions/commands/knowledge-validate.js';
|
|
33
|
+
import { knowledgeIndex, renderKnowledgeIndex, } from './functions/commands/knowledge-index.js';
|
|
32
34
|
import { scenarioRun, scenarioList } from './functions/commands/scenario.js';
|
|
33
35
|
import { pikkuVersionsInit } from './functions/commands/versions-init.js';
|
|
34
36
|
import { pikkuEmailsInit } from './functions/commands/emails-init.js';
|
|
@@ -375,6 +377,27 @@ wireCLI({
|
|
|
375
377
|
}),
|
|
376
378
|
},
|
|
377
379
|
},
|
|
380
|
+
knowledge: {
|
|
381
|
+
description: 'Inspect and maintain the knowledge base — what this app is, in the language its users use',
|
|
382
|
+
subcommands: {
|
|
383
|
+
validate: pikkuCLICommand({
|
|
384
|
+
func: knowledgeValidate,
|
|
385
|
+
render: renderKnowledgeValidate,
|
|
386
|
+
description: 'Check the knowledge base against the app-project profile, including every resource: reference',
|
|
387
|
+
}),
|
|
388
|
+
index: pikkuCLICommand({
|
|
389
|
+
func: knowledgeIndex,
|
|
390
|
+
render: renderKnowledgeIndex,
|
|
391
|
+
description: 'Refresh every index.md so each section lists the notes actually in it',
|
|
392
|
+
options: {
|
|
393
|
+
check: {
|
|
394
|
+
description: 'Report stale indexes without writing anything, for use as a CI gate',
|
|
395
|
+
default: false,
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
}),
|
|
399
|
+
},
|
|
400
|
+
},
|
|
378
401
|
workspace: {
|
|
379
402
|
description: 'Workspace-level validation and maintenance commands',
|
|
380
403
|
subcommands: {
|
|
@@ -427,6 +450,12 @@ wireCLI({
|
|
|
427
450
|
description: 'Keep every stack frame on a failure. Without it, only the project’s own frames are shown',
|
|
428
451
|
default: false,
|
|
429
452
|
},
|
|
453
|
+
apiUrl: {
|
|
454
|
+
description: "Override the environment's apiUrl for this run — for a target that only exists at run time, such as a freshly deployed sandbox",
|
|
455
|
+
},
|
|
456
|
+
appUrl: {
|
|
457
|
+
description: "Override the environment's appUrl for this run (the frontend browser steps navigate against)",
|
|
458
|
+
},
|
|
430
459
|
},
|
|
431
460
|
}),
|
|
432
461
|
list: pikkuCLICommand({
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Workflow orchestrators dispatch to step units via queue or RPC (inline).
|
|
8
8
|
*/
|
|
9
9
|
import { resolveDeployTarget, } from '@pikku/inspector';
|
|
10
|
+
import { isScenarioFunction, withoutScenarios, withoutScenarioWorkflows, } from '../../functions/wirings/scenarios/scenario-partition.js';
|
|
10
11
|
export function analyzeDeployment(state, options) {
|
|
11
12
|
const serverlessIncompatible = new Set(options.serverlessIncompatible ?? []);
|
|
12
13
|
const defaultTarget = options.defaultTarget ?? 'serverless';
|
|
@@ -18,7 +19,13 @@ export function analyzeDeployment(state, options) {
|
|
|
18
19
|
const agents = [];
|
|
19
20
|
const mcpEndpoints = [];
|
|
20
21
|
const workflows = [];
|
|
21
|
-
|
|
22
|
+
// Scenarios, features and steps are test artifacts that happen to be built out
|
|
23
|
+
// of functions and workflows, so without this they analyze like application
|
|
24
|
+
// code: every scenario became its own unit, its own `WorkflowDefinition` and —
|
|
25
|
+
// because a scenario IS a workflow — a `wf-orchestrator-<scenario>` queue that
|
|
26
|
+
// a provider would then create in production.
|
|
27
|
+
const functionsMeta = withoutScenarios(state.functions.meta);
|
|
28
|
+
const graphMeta = withoutScenarioWorkflows(state.workflows.graphMeta);
|
|
22
29
|
const httpMeta = state.http.meta;
|
|
23
30
|
// ── Step 1: Create function units ──────────────────────────────────
|
|
24
31
|
// Each function gets one unit. Collect all its triggers.
|
|
@@ -190,9 +197,19 @@ export function analyzeDeployment(state, options) {
|
|
|
190
197
|
});
|
|
191
198
|
}
|
|
192
199
|
// ── Step 3: MCP gateway ────────────────────────────────────────────
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
200
|
+
// The MCP metas are keyed by wiring, not by function, so they are the one
|
|
201
|
+
// place a scenario or step id can still arrive from raw state. A gateway that
|
|
202
|
+
// lists one would depend on a unit that was never emitted.
|
|
203
|
+
const deployableFuncId = (funcId) => !isScenarioFunction(state.functions.meta[funcId]);
|
|
204
|
+
const mcpToolIds = values(state.mcpEndpoints.toolsMeta)
|
|
205
|
+
.map((t) => t.pikkuFuncId)
|
|
206
|
+
.filter(deployableFuncId);
|
|
207
|
+
const mcpResourceIds = values(state.mcpEndpoints.resourcesMeta)
|
|
208
|
+
.map((r) => r.pikkuFuncId)
|
|
209
|
+
.filter(deployableFuncId);
|
|
210
|
+
const mcpPromptIds = values(state.mcpEndpoints.promptsMeta)
|
|
211
|
+
.map((p) => p.pikkuFuncId)
|
|
212
|
+
.filter(deployableFuncId);
|
|
196
213
|
// Include functions explicitly marked mcp: true
|
|
197
214
|
for (const [funcId, funcMeta] of entries(functionsMeta)) {
|
|
198
215
|
if (funcMeta.mcp &&
|
|
@@ -248,7 +265,7 @@ export function analyzeDeployment(state, options) {
|
|
|
248
265
|
});
|
|
249
266
|
}
|
|
250
267
|
// ── Step 5: Workflows ──────────────────────────────────────────────
|
|
251
|
-
buildWorkflows(
|
|
268
|
+
buildWorkflows(graphMeta, functionsMeta, { ...state.rpc?.exposedMeta, ...state.rpc?.internalMeta }, httpMeta, units, workflows, queues, workflowQueues);
|
|
252
269
|
// ── Step 6: Ensure function units exist for gateway dependencies ───
|
|
253
270
|
// Gateways depend on function units. If a function is only used via
|
|
254
271
|
// a gateway (not directly wired to HTTP/queue/cron), it still needs
|
|
@@ -8,6 +8,7 @@ import { join } from 'node:path';
|
|
|
8
8
|
import { existsSync } from 'node:fs';
|
|
9
9
|
import { mkdir, writeFile, copyFile } from 'node:fs/promises';
|
|
10
10
|
import { analyzeDeployment } from './analyzer/index.js';
|
|
11
|
+
import { withoutScenarios } from '../functions/wirings/scenarios/scenario-partition.js';
|
|
11
12
|
import { generatePerUnitCodegen } from './codegen/per-unit-codegen.js';
|
|
12
13
|
import { generateServerEntrySource, SERVER_DOCKERFILE, SERVER_DOCKERIGNORE, } from './server-entry.js';
|
|
13
14
|
const MERGED_SERVER_UNIT_NAME = 'pikku-server-container';
|
|
@@ -63,7 +64,10 @@ export async function runBuildPipeline(options) {
|
|
|
63
64
|
name: unitName,
|
|
64
65
|
role: 'function',
|
|
65
66
|
target: 'serverless',
|
|
66
|
-
|
|
67
|
+
// Scenarios and steps are excluded for the same reason the analyzer drops
|
|
68
|
+
// them: a single-unit bundle is still a deployment, and a test harness has
|
|
69
|
+
// no business inside one.
|
|
70
|
+
functionIds: Object.keys(withoutScenarios(inspectorState.functions.meta)),
|
|
67
71
|
services: [],
|
|
68
72
|
dependsOn: [],
|
|
69
73
|
handlers: [],
|
|
@@ -451,37 +451,65 @@ export declare const fabricCommands: {
|
|
|
451
451
|
value?: string | undefined;
|
|
452
452
|
force?: boolean | undefined;
|
|
453
453
|
}, {
|
|
454
|
-
|
|
454
|
+
name: string;
|
|
455
|
+
keyId: string;
|
|
455
456
|
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").PikkuFunctionSessionless<{
|
|
456
457
|
name: string;
|
|
457
458
|
branch: string;
|
|
458
459
|
value?: string | undefined;
|
|
459
460
|
force?: boolean | undefined;
|
|
460
461
|
}, {
|
|
461
|
-
|
|
462
|
+
name: string;
|
|
463
|
+
keyId: string;
|
|
462
464
|
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").WiredServices> | import("../../.pikku/pikku-types.gen.js").PikkuFunction<{
|
|
463
465
|
name: string;
|
|
464
466
|
branch: string;
|
|
465
467
|
value?: string | undefined;
|
|
466
468
|
force?: boolean | undefined;
|
|
467
469
|
}, {
|
|
468
|
-
|
|
470
|
+
name: string;
|
|
471
|
+
keyId: string;
|
|
469
472
|
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").WiredServices>, undefined, undefined>, import("../../.pikku/pikku-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>;
|
|
470
473
|
list: import("@pikku/core/cli").CoreCLICommandConfig<import("../../.pikku/pikku-types.gen.js").PikkuFunctionConfig<{
|
|
471
474
|
branch: string;
|
|
472
475
|
json?: boolean | undefined;
|
|
473
476
|
}, {
|
|
474
|
-
|
|
477
|
+
secrets: {
|
|
478
|
+
name: string;
|
|
479
|
+
updatedAt: string;
|
|
480
|
+
}[];
|
|
475
481
|
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").PikkuFunctionSessionless<{
|
|
476
482
|
branch: string;
|
|
477
483
|
json?: boolean | undefined;
|
|
478
484
|
}, {
|
|
479
|
-
|
|
485
|
+
secrets: {
|
|
486
|
+
name: string;
|
|
487
|
+
updatedAt: string;
|
|
488
|
+
}[];
|
|
480
489
|
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").WiredServices> | import("../../.pikku/pikku-types.gen.js").PikkuFunction<{
|
|
481
490
|
branch: string;
|
|
482
491
|
json?: boolean | undefined;
|
|
483
492
|
}, {
|
|
484
|
-
|
|
493
|
+
secrets: {
|
|
494
|
+
name: string;
|
|
495
|
+
updatedAt: string;
|
|
496
|
+
}[];
|
|
497
|
+
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").WiredServices>, undefined, undefined>, import("../../.pikku/pikku-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>;
|
|
498
|
+
rotate: import("@pikku/core/cli").CoreCLICommandConfig<import("../../.pikku/pikku-types.gen.js").PikkuFunctionConfig<{
|
|
499
|
+
branch: string;
|
|
500
|
+
force?: boolean | undefined;
|
|
501
|
+
}, {
|
|
502
|
+
retiredKeyId: string;
|
|
503
|
+
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").PikkuFunctionSessionless<{
|
|
504
|
+
branch: string;
|
|
505
|
+
force?: boolean | undefined;
|
|
506
|
+
}, {
|
|
507
|
+
retiredKeyId: string;
|
|
508
|
+
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").WiredServices> | import("../../.pikku/pikku-types.gen.js").PikkuFunction<{
|
|
509
|
+
branch: string;
|
|
510
|
+
force?: boolean | undefined;
|
|
511
|
+
}, {
|
|
512
|
+
retiredKeyId: string;
|
|
485
513
|
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").WiredServices>, undefined, undefined>, import("../../.pikku/pikku-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>;
|
|
486
514
|
};
|
|
487
515
|
};
|
|
@@ -622,21 +650,21 @@ export declare const fabricCommands: {
|
|
|
622
650
|
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").WiredServices>, undefined, undefined>, import("../../.pikku/pikku-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>;
|
|
623
651
|
add: import("@pikku/core/cli").CoreCLICommandConfig<import("../../.pikku/pikku-types.gen.js").PikkuFunctionConfig<{
|
|
624
652
|
hostname: string;
|
|
625
|
-
target?: "
|
|
653
|
+
target?: "app" | "api" | undefined;
|
|
626
654
|
apiUrl?: string | undefined;
|
|
627
655
|
}, {
|
|
628
656
|
hostname: string;
|
|
629
657
|
cnameTarget: string;
|
|
630
658
|
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").PikkuFunctionSessionless<{
|
|
631
659
|
hostname: string;
|
|
632
|
-
target?: "
|
|
660
|
+
target?: "app" | "api" | undefined;
|
|
633
661
|
apiUrl?: string | undefined;
|
|
634
662
|
}, {
|
|
635
663
|
hostname: string;
|
|
636
664
|
cnameTarget: string;
|
|
637
665
|
}, "rpc" | "session", import("../../.pikku/pikku-types.gen.js").WiredServices> | import("../../.pikku/pikku-types.gen.js").PikkuFunction<{
|
|
638
666
|
hostname: string;
|
|
639
|
-
target?: "
|
|
667
|
+
target?: "app" | "api" | undefined;
|
|
640
668
|
apiUrl?: string | undefined;
|
|
641
669
|
}, {
|
|
642
670
|
hostname: string;
|
|
@@ -31,6 +31,7 @@ import { FabricDbSchema, renderDbSchema, } from './functions/db-schema.function.
|
|
|
31
31
|
import { FabricRollback } from './functions/rollback.function.js';
|
|
32
32
|
import { FabricSecretsSet } from './functions/secrets-set.function.js';
|
|
33
33
|
import { FabricSecretsList } from './functions/secrets-list.function.js';
|
|
34
|
+
import { FabricSecretsRotate } from './functions/secrets-rotate.function.js';
|
|
34
35
|
import { FabricLogs } from './functions/logs.function.js';
|
|
35
36
|
import { FabricMetrics } from './functions/metrics.function.js';
|
|
36
37
|
import { FabricTrace } from './functions/trace.function.js';
|
|
@@ -241,6 +242,17 @@ export const fabricCommands = defineCLICommands({
|
|
|
241
242
|
json: { description: 'Machine-readable output', default: false },
|
|
242
243
|
},
|
|
243
244
|
}),
|
|
245
|
+
rotate: pikkuCLICommand({
|
|
246
|
+
func: FabricSecretsRotate,
|
|
247
|
+
description: "Retire a stage's sealing key (secrets must be set again)",
|
|
248
|
+
options: {
|
|
249
|
+
branch: { description: 'Target branch', short: 'b' },
|
|
250
|
+
force: {
|
|
251
|
+
description: 'Confirm that existing secrets become unreadable',
|
|
252
|
+
default: false,
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
}),
|
|
244
256
|
},
|
|
245
257
|
},
|
|
246
258
|
logs: pikkuCLICommand({
|
|
@@ -2,8 +2,8 @@ import { z } from 'zod';
|
|
|
2
2
|
export declare const FabricDomainsAddInput: z.ZodObject<{
|
|
3
3
|
hostname: z.ZodString;
|
|
4
4
|
target: z.ZodOptional<z.ZodEnum<{
|
|
5
|
-
api: "api";
|
|
6
5
|
app: "app";
|
|
6
|
+
api: "api";
|
|
7
7
|
}>>;
|
|
8
8
|
apiUrl: z.ZodOptional<z.ZodString>;
|
|
9
9
|
}, z.core.$strip>;
|
|
@@ -13,21 +13,21 @@ export declare const FabricDomainsAddOutput: z.ZodObject<{
|
|
|
13
13
|
}, z.core.$strip>;
|
|
14
14
|
export declare const FabricDomainsAdd: import("../../../.pikku/pikku-types.gen.js").PikkuFunctionConfig<{
|
|
15
15
|
hostname: string;
|
|
16
|
-
target?: "
|
|
16
|
+
target?: "app" | "api" | undefined;
|
|
17
17
|
apiUrl?: string | undefined;
|
|
18
18
|
}, {
|
|
19
19
|
hostname: string;
|
|
20
20
|
cnameTarget: string;
|
|
21
21
|
}, "rpc" | "session", import("../../../.pikku/pikku-types.gen.js").PikkuFunctionSessionless<{
|
|
22
22
|
hostname: string;
|
|
23
|
-
target?: "
|
|
23
|
+
target?: "app" | "api" | undefined;
|
|
24
24
|
apiUrl?: string | undefined;
|
|
25
25
|
}, {
|
|
26
26
|
hostname: string;
|
|
27
27
|
cnameTarget: string;
|
|
28
28
|
}, "rpc" | "session", import("../../../.pikku/pikku-types.gen.js").WiredServices> | import("../../../.pikku/pikku-types.gen.js").PikkuFunction<{
|
|
29
29
|
hostname: string;
|
|
30
|
-
target?: "
|
|
30
|
+
target?: "app" | "api" | undefined;
|
|
31
31
|
apiUrl?: string | undefined;
|
|
32
32
|
}, {
|
|
33
33
|
hostname: string;
|
|
@@ -4,21 +4,33 @@ export declare const FabricSecretsListInput: z.ZodObject<{
|
|
|
4
4
|
json: z.ZodOptional<z.ZodBoolean>;
|
|
5
5
|
}, z.core.$strip>;
|
|
6
6
|
export declare const FabricSecretsListOutput: z.ZodObject<{
|
|
7
|
-
|
|
7
|
+
secrets: z.ZodArray<z.ZodObject<{
|
|
8
|
+
name: z.ZodString;
|
|
9
|
+
updatedAt: z.ZodString;
|
|
10
|
+
}, z.core.$strip>>;
|
|
8
11
|
}, z.core.$strip>;
|
|
9
12
|
export declare const FabricSecretsList: import("../../../.pikku/pikku-types.gen.js").PikkuFunctionConfig<{
|
|
10
13
|
branch: string;
|
|
11
14
|
json?: boolean | undefined;
|
|
12
15
|
}, {
|
|
13
|
-
|
|
16
|
+
secrets: {
|
|
17
|
+
name: string;
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
}[];
|
|
14
20
|
}, "rpc" | "session", import("../../../.pikku/pikku-types.gen.js").PikkuFunctionSessionless<{
|
|
15
21
|
branch: string;
|
|
16
22
|
json?: boolean | undefined;
|
|
17
23
|
}, {
|
|
18
|
-
|
|
24
|
+
secrets: {
|
|
25
|
+
name: string;
|
|
26
|
+
updatedAt: string;
|
|
27
|
+
}[];
|
|
19
28
|
}, "rpc" | "session", import("../../../.pikku/pikku-types.gen.js").WiredServices> | import("../../../.pikku/pikku-types.gen.js").PikkuFunction<{
|
|
20
29
|
branch: string;
|
|
21
30
|
json?: boolean | undefined;
|
|
22
31
|
}, {
|
|
23
|
-
|
|
32
|
+
secrets: {
|
|
33
|
+
name: string;
|
|
34
|
+
updatedAt: string;
|
|
35
|
+
}[];
|
|
24
36
|
}, "rpc" | "session", import("../../../.pikku/pikku-types.gen.js").WiredServices>, undefined, undefined>;
|
|
@@ -2,13 +2,16 @@ import { z } from 'zod';
|
|
|
2
2
|
import { pikkuSessionlessFunc } from '../../../.pikku/pikku-types.gen.js';
|
|
3
3
|
import { resolveApiContext } from '../lib/config.js';
|
|
4
4
|
import { getFabricRPC } from '../lib/http.js';
|
|
5
|
+
import { resolveStageId } from '../lib/stage.js';
|
|
5
6
|
export const FabricSecretsListInput = z.object({
|
|
6
7
|
branch: z.string(),
|
|
7
8
|
json: z.boolean().optional(),
|
|
8
9
|
});
|
|
9
|
-
export const FabricSecretsListOutput = z.object({
|
|
10
|
+
export const FabricSecretsListOutput = z.object({
|
|
11
|
+
secrets: z.array(z.object({ name: z.string(), updatedAt: z.string() })),
|
|
12
|
+
});
|
|
10
13
|
export const FabricSecretsList = pikkuSessionlessFunc({
|
|
11
|
-
description: 'List
|
|
14
|
+
description: 'List the secrets set on a stage, by name. Values are sealed to the stage and never leave it.',
|
|
12
15
|
input: FabricSecretsListInput,
|
|
13
16
|
output: FabricSecretsListOutput,
|
|
14
17
|
func: async (_services, { branch, json }) => {
|
|
@@ -18,19 +21,18 @@ export const FabricSecretsList = pikkuSessionlessFunc({
|
|
|
18
21
|
if (!ctx.projectId)
|
|
19
22
|
throw new Error('No fabric project linked. Run `pikku fabric link` first.');
|
|
20
23
|
const rpc = getFabricRPC({ apiUrl: ctx.apiUrl, token: ctx.token });
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
branch,
|
|
24
|
-
});
|
|
24
|
+
const stageId = await resolveStageId(rpc, ctx.projectId, branch);
|
|
25
|
+
const result = await rpc.invoke('listStageSecretNames', { stageId });
|
|
25
26
|
if (json) {
|
|
26
|
-
console.log(JSON.stringify({ branch,
|
|
27
|
+
console.log(JSON.stringify({ branch, secrets: result.secrets }, null, 2));
|
|
27
28
|
}
|
|
28
|
-
else if (result.
|
|
29
|
+
else if (result.secrets.length === 0) {
|
|
29
30
|
console.log(`[fabric] no secrets set on ${branch}`);
|
|
30
31
|
}
|
|
31
32
|
else {
|
|
32
|
-
for (const name of result.
|
|
33
|
-
console.log(name);
|
|
33
|
+
for (const { name, updatedAt } of result.secrets) {
|
|
34
|
+
console.log(`${name}\t${updatedAt}`);
|
|
35
|
+
}
|
|
34
36
|
}
|
|
35
37
|
return result;
|
|
36
38
|
},
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const FabricSecretsRotateInput: z.ZodObject<{
|
|
3
|
+
branch: z.ZodString;
|
|
4
|
+
force: z.ZodOptional<z.ZodBoolean>;
|
|
5
|
+
}, z.core.$strip>;
|
|
6
|
+
export declare const FabricSecretsRotateOutput: z.ZodObject<{
|
|
7
|
+
retiredKeyId: z.ZodString;
|
|
8
|
+
}, z.core.$strip>;
|
|
9
|
+
export declare const FabricSecretsRotate: import("../../../.pikku/pikku-types.gen.js").PikkuFunctionConfig<{
|
|
10
|
+
branch: string;
|
|
11
|
+
force?: boolean | undefined;
|
|
12
|
+
}, {
|
|
13
|
+
retiredKeyId: string;
|
|
14
|
+
}, "rpc" | "session", import("../../../.pikku/pikku-types.gen.js").PikkuFunctionSessionless<{
|
|
15
|
+
branch: string;
|
|
16
|
+
force?: boolean | undefined;
|
|
17
|
+
}, {
|
|
18
|
+
retiredKeyId: string;
|
|
19
|
+
}, "rpc" | "session", import("../../../.pikku/pikku-types.gen.js").WiredServices> | import("../../../.pikku/pikku-types.gen.js").PikkuFunction<{
|
|
20
|
+
branch: string;
|
|
21
|
+
force?: boolean | undefined;
|
|
22
|
+
}, {
|
|
23
|
+
retiredKeyId: string;
|
|
24
|
+
}, "rpc" | "session", import("../../../.pikku/pikku-types.gen.js").WiredServices>, undefined, undefined>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { pikkuSessionlessFunc } from '../../../.pikku/pikku-types.gen.js';
|
|
3
|
+
import { resolveApiContext } from '../lib/config.js';
|
|
4
|
+
import { getFabricRPC } from '../lib/http.js';
|
|
5
|
+
import { resolveStageId } from '../lib/stage.js';
|
|
6
|
+
export const FabricSecretsRotateInput = z.object({
|
|
7
|
+
branch: z.string(),
|
|
8
|
+
force: z.boolean().optional(),
|
|
9
|
+
});
|
|
10
|
+
export const FabricSecretsRotateOutput = z.object({
|
|
11
|
+
retiredKeyId: z.string(),
|
|
12
|
+
});
|
|
13
|
+
export const FabricSecretsRotate = pikkuSessionlessFunc({
|
|
14
|
+
description: "Retire a stage's sealing key so the next deploy issues a new one. Secrets sealed to the old key must be set again.",
|
|
15
|
+
input: FabricSecretsRotateInput,
|
|
16
|
+
output: FabricSecretsRotateOutput,
|
|
17
|
+
func: async (_services, { branch, force }) => {
|
|
18
|
+
const ctx = await resolveApiContext();
|
|
19
|
+
if (!ctx.token)
|
|
20
|
+
throw new Error('Not logged in. Run `pikku fabric login` first.');
|
|
21
|
+
if (!ctx.projectId)
|
|
22
|
+
throw new Error('No fabric project linked. Run `pikku fabric link` first.');
|
|
23
|
+
if (!force) {
|
|
24
|
+
// Not a confirmation for politeness — this is the one operation here
|
|
25
|
+
// that destroys access to data. Fabric cannot read the sealed values, so
|
|
26
|
+
// it cannot carry them over, and nobody can undo it afterwards.
|
|
27
|
+
throw new Error(`Rotating the sealing key on ${branch} makes every secret already set on it unreadable — fabric cannot re-seal values it cannot open, so each one must be set again after the next deploy. Re-run with --force if that is what you want.`);
|
|
28
|
+
}
|
|
29
|
+
const rpc = getFabricRPC({ apiUrl: ctx.apiUrl, token: ctx.token });
|
|
30
|
+
const stageId = await resolveStageId(rpc, ctx.projectId, branch);
|
|
31
|
+
const result = await rpc.invoke('rotateStageSealingKey', { stageId });
|
|
32
|
+
console.log(`[fabric] retired sealing key ${result.retiredKeyId} on ${branch}`);
|
|
33
|
+
console.log('[fabric] deploy the stage to issue a new key, then set its secrets again');
|
|
34
|
+
return result;
|
|
35
|
+
},
|
|
36
|
+
});
|
|
@@ -6,7 +6,8 @@ export declare const FabricSecretsSetInput: z.ZodObject<{
|
|
|
6
6
|
force: z.ZodOptional<z.ZodBoolean>;
|
|
7
7
|
}, z.core.$strip>;
|
|
8
8
|
export declare const FabricSecretsSetOutput: z.ZodObject<{
|
|
9
|
-
|
|
9
|
+
name: z.ZodString;
|
|
10
|
+
keyId: z.ZodString;
|
|
10
11
|
}, z.core.$strip>;
|
|
11
12
|
export declare const FabricSecretsSet: import("../../../.pikku/pikku-types.gen.js").PikkuFunctionConfig<{
|
|
12
13
|
name: string;
|
|
@@ -14,19 +15,22 @@ export declare const FabricSecretsSet: import("../../../.pikku/pikku-types.gen.j
|
|
|
14
15
|
value?: string | undefined;
|
|
15
16
|
force?: boolean | undefined;
|
|
16
17
|
}, {
|
|
17
|
-
|
|
18
|
+
name: string;
|
|
19
|
+
keyId: string;
|
|
18
20
|
}, "rpc" | "session", import("../../../.pikku/pikku-types.gen.js").PikkuFunctionSessionless<{
|
|
19
21
|
name: string;
|
|
20
22
|
branch: string;
|
|
21
23
|
value?: string | undefined;
|
|
22
24
|
force?: boolean | undefined;
|
|
23
25
|
}, {
|
|
24
|
-
|
|
26
|
+
name: string;
|
|
27
|
+
keyId: string;
|
|
25
28
|
}, "rpc" | "session", import("../../../.pikku/pikku-types.gen.js").WiredServices> | import("../../../.pikku/pikku-types.gen.js").PikkuFunction<{
|
|
26
29
|
name: string;
|
|
27
30
|
branch: string;
|
|
28
31
|
value?: string | undefined;
|
|
29
32
|
force?: boolean | undefined;
|
|
30
33
|
}, {
|
|
31
|
-
|
|
34
|
+
name: string;
|
|
35
|
+
keyId: string;
|
|
32
36
|
}, "rpc" | "session", import("../../../.pikku/pikku-types.gen.js").WiredServices>, undefined, undefined>;
|
|
@@ -3,15 +3,20 @@ import { pikkuSessionlessFunc } from '../../../.pikku/pikku-types.gen.js';
|
|
|
3
3
|
import { resolveApiContext } from '../lib/config.js';
|
|
4
4
|
import { getFabricRPC } from '../lib/http.js';
|
|
5
5
|
import { promptSecret } from '../lib/prompt.js';
|
|
6
|
+
import { resolveStageId } from '../lib/stage.js';
|
|
7
|
+
import { seal, serializeSealedValue } from '../lib/sealed-box.js';
|
|
6
8
|
export const FabricSecretsSetInput = z.object({
|
|
7
9
|
name: z.string(),
|
|
8
10
|
branch: z.string(),
|
|
9
11
|
value: z.string().optional(),
|
|
10
12
|
force: z.boolean().optional(),
|
|
11
13
|
});
|
|
12
|
-
export const FabricSecretsSetOutput = z.object({
|
|
14
|
+
export const FabricSecretsSetOutput = z.object({
|
|
15
|
+
name: z.string(),
|
|
16
|
+
keyId: z.string(),
|
|
17
|
+
});
|
|
13
18
|
export const FabricSecretsSet = pikkuSessionlessFunc({
|
|
14
|
-
description: 'Set a stage-scoped secret.
|
|
19
|
+
description: 'Set a stage-scoped secret. Sealed here to the stage public key — the plaintext never leaves this machine.',
|
|
15
20
|
input: FabricSecretsSetInput,
|
|
16
21
|
output: FabricSecretsSetOutput,
|
|
17
22
|
func: async (_services, { name, branch, value }) => {
|
|
@@ -24,13 +29,19 @@ export const FabricSecretsSet = pikkuSessionlessFunc({
|
|
|
24
29
|
if (!plaintext)
|
|
25
30
|
throw new Error('Empty secret value — aborting.');
|
|
26
31
|
const rpc = getFabricRPC({ apiUrl: ctx.apiUrl, token: ctx.token });
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
const stageId = await resolveStageId(rpc, ctx.projectId, branch);
|
|
33
|
+
// Fabric holds only the public half of this keypair. The private half went
|
|
34
|
+
// to the stage's worker at deploy time and was dropped there, so the value
|
|
35
|
+
// sealed below can be opened by that worker and by nothing else — including
|
|
36
|
+
// by the fabric process that stores it.
|
|
37
|
+
const key = await rpc.invoke('getStageSealingKey', { stageId });
|
|
38
|
+
const sealed = seal(key.publicKey, key.keyId, plaintext);
|
|
39
|
+
const result = await rpc.invoke('setStageSealedSecret', {
|
|
40
|
+
stageId,
|
|
30
41
|
name,
|
|
31
|
-
|
|
42
|
+
sealedValue: serializeSealedValue(sealed),
|
|
32
43
|
});
|
|
33
|
-
console.log(`[fabric] ${name} set on ${branch}.`);
|
|
44
|
+
console.log(`[fabric] ${name} sealed to ${result.keyId} and set on ${branch}.`);
|
|
34
45
|
return result;
|
|
35
46
|
},
|
|
36
47
|
});
|
|
@@ -6,6 +6,7 @@ import { createRequire } from 'node:module';
|
|
|
6
6
|
import { pikkuSessionlessFunc } from '../../../.pikku/pikku-types.gen.js';
|
|
7
7
|
import { added, changed, removed, dim } from '../lib/output.js';
|
|
8
8
|
import { typeCheckFrontends } from '../lib/frontend-typecheck.js';
|
|
9
|
+
import { runKnowledgeValidate } from '@pikku/knowledge';
|
|
9
10
|
const FindingSchema = z.object({
|
|
10
11
|
id: z.string(),
|
|
11
12
|
severity: z.enum(['error', 'warn', 'info']),
|
|
@@ -312,16 +313,21 @@ export async function runValidate(startDir = process.cwd(), opts = {}) {
|
|
|
312
313
|
// ── required project files ────────────────────────────────────────────
|
|
313
314
|
// These files must exist and be committed — they are seeded from the sandbox
|
|
314
315
|
// but belong to the project so the AI agent can read and update them.
|
|
315
|
-
for (const relPath of [
|
|
316
|
-
'db/annotations.ts',
|
|
317
|
-
'knowledge/design-language.md',
|
|
318
|
-
'knowledge/security.md',
|
|
319
|
-
'knowledge/technology.md',
|
|
320
|
-
]) {
|
|
316
|
+
for (const relPath of ['db/annotations.ts']) {
|
|
321
317
|
if (!existsSync(join(root, relPath))) {
|
|
322
318
|
w(`missing-required-file-${relPath.replace(/[^a-z0-9]/gi, '-')}`, `${relPath} is missing — this file must be committed to the project`, join(root, relPath), lines(`Create ${relPath} and commit it.`, 'The starter-template ships a stub you can copy as a starting point.'));
|
|
323
319
|
}
|
|
324
320
|
}
|
|
321
|
+
// ── knowledge base ─────────────────────────────────────────────────────
|
|
322
|
+
// Delegated to the shared checker rather than asserting a list of filenames.
|
|
323
|
+
// The three flat files this used to require (design-language.md, security.md,
|
|
324
|
+
// technology.md) are not a knowledge base — they are three documents nothing
|
|
325
|
+
// can link into, and the profile now organises the same content into sections
|
|
326
|
+
// of notes. Fabric adds decisions/design/ on top of what is checked here.
|
|
327
|
+
const knowledge = await runKnowledgeValidate(root, join(root, typeof pikkuConfig?.outDir === 'string' ? pikkuConfig.outDir : '.pikku'));
|
|
328
|
+
for (const finding of knowledge.findings) {
|
|
329
|
+
findings.push({ ...finding, path: join(root, finding.path) });
|
|
330
|
+
}
|
|
325
331
|
const rootPkgPath = join(root, 'package.json');
|
|
326
332
|
const rootPkg = await readJsonSafe(rootPkgPath);
|
|
327
333
|
if (!rootPkg) {
|
|
@@ -671,7 +677,10 @@ export async function runValidate(startDir = process.cwd(), opts = {}) {
|
|
|
671
677
|
// nothing — flagging it told every fresh scaffold to import a dialect it
|
|
672
678
|
// must not use.
|
|
673
679
|
const constructsKysely = /new\s+Kysely\s*[<(]/.test(servicesText);
|
|
674
|
-
if (dbEngine !== 'postgres' &&
|
|
680
|
+
if (dbEngine !== 'postgres' &&
|
|
681
|
+
usesKysely &&
|
|
682
|
+
constructsKysely &&
|
|
683
|
+
!usesLibsql) {
|
|
675
684
|
e('services-wrong-db-adapter', 'services.ts uses Kysely but not LibsqlWebDialect — Fabric injects a Turso/libSQL DATABASE_URL at runtime, not a PostgreSQL URL', servicesPath, 'Import LibsqlWebDialect from @pikku/kysely-sqlite and replace the dialect: new Kysely({ dialect: new LibsqlWebDialect({ url: databaseUrl }) })');
|
|
676
685
|
}
|
|
677
686
|
if (usesProcessEnv) {
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-safe RPC client backed by the snapshot SDK in `../sdk/`. The map is
|
|
3
|
+
* a copy of fabric's generated rpc-map at the time of the addon's last
|
|
4
|
+
* release — versioning bumps are taken by republishing this package.
|
|
5
|
+
*/
|
|
6
|
+
import { PikkuRPC } from '../sdk/pikku-rpc.gen.js';
|
|
1
7
|
export declare function getFabricRPC(opts: {
|
|
2
8
|
apiUrl: string;
|
|
3
9
|
token: string | null;
|
|
4
|
-
}):
|
|
10
|
+
}): PikkuRPC;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Algorithm tag carried by every sealed value. Must match fabric's. */
|
|
2
|
+
export declare const SEALED_BOX_ALGORITHM = "sealed-x25519-v1";
|
|
3
|
+
export interface SealedValue {
|
|
4
|
+
alg: typeof SEALED_BOX_ALGORITHM;
|
|
5
|
+
/** The `encryption_key` row whose public key sealed this. */
|
|
6
|
+
kid: string;
|
|
7
|
+
/** Ephemeral public key, SPKI DER as base64. */
|
|
8
|
+
epk: string;
|
|
9
|
+
iv: string;
|
|
10
|
+
ct: string;
|
|
11
|
+
tag: string;
|
|
12
|
+
}
|
|
13
|
+
/** Seal a value to a stage's public key. */
|
|
14
|
+
export declare function seal(publicKey: string, keyId: string, plaintext: string): SealedValue;
|
|
15
|
+
/** Wire form. Fabric stores exactly this string. */
|
|
16
|
+
export declare function serializeSealedValue(sealed: SealedValue): string;
|