@pikku/cli 0.12.20 → 0.12.21
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/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 +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 +10 -1
- 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 +8 -2
- package/dist/.pikku/function/pikku-function-types.gen.js +4 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +276 -188
- package/dist/.pikku/function/pikku-functions.gen.js +9 -9
- 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.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-wirings.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.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/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +11 -7
- 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 -11
- package/dist/.pikku/schemas/schemas/PikkuCommandHTTPOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuCommandQueueOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/WorkflowRunStatus.schema.json +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 +9 -9
- 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/src/cli.wiring.js +12 -2
- package/dist/src/deploy/analyzer/manifest.d.ts +10 -0
- package/dist/src/deploy/build-pipeline.d.ts +2 -0
- package/dist/src/deploy/build-pipeline.js +44 -6
- package/dist/src/deploy/bundler/bundler.d.ts +2 -1
- package/dist/src/deploy/bundler/bundler.js +28 -5
- package/dist/src/deploy/bundler/dep-extractor.d.ts +5 -2
- package/dist/src/deploy/bundler/dep-extractor.js +103 -23
- package/dist/src/deploy/bundler/types.d.ts +5 -1
- package/dist/src/deploy/codegen/per-unit-codegen.d.ts +3 -1
- package/dist/src/deploy/codegen/per-unit-codegen.js +3 -1
- package/dist/src/deploy/plan/planner.js +25 -3
- package/dist/src/deploy/plan/provider.d.ts +2 -0
- package/dist/src/functions/commands/deploy-apply.js +6 -4
- package/dist/src/functions/commands/deploy-plan.js +7 -1
- package/dist/src/functions/commands/pikku-command-summary.js +4 -1
- package/dist/src/functions/commands/versions-update.js +4 -2
- package/dist/src/functions/wirings/channels/pikku-command-channels.d.ts +1 -1
- package/dist/src/functions/wirings/channels/pikku-command-channels.js +1 -1
- package/dist/src/functions/wirings/console/pikku-command-console-functions.js +5 -1
- package/dist/src/functions/wirings/functions/serialize-function-types.js +31 -1
- package/dist/src/functions/wirings/http/pikku-command-http-routes.d.ts +1 -1
- package/dist/src/functions/wirings/http/pikku-command-http-routes.js +1 -1
- package/dist/src/functions/wirings/queue/pikku-command-queue-map.d.ts +1 -1
- package/dist/src/functions/wirings/queue/pikku-command-queue-map.js +1 -1
- package/dist/src/functions/wirings/queue/pikku-command-queue.d.ts +1 -1
- package/dist/src/functions/wirings/queue/pikku-command-queue.js +1 -1
- package/dist/src/functions/wirings/rpc/pikku-command-public-rpc.js +5 -1
- package/dist/src/functions/wirings/rpc/pikku-command-remote-rpc.js +5 -1
- package/dist/src/functions/wirings/rpc/serialize-typed-rpc-map.js +16 -2
- package/dist/src/functions/wirings/workflow/serialize-workflow-routes.js +42 -0
- package/dist/src/functions/workflows/all.workflow.js +4 -4
- package/dist/src/scaffold/rpc-remote.gen.js +1 -1
- package/dist/src/scaffold/workflow-routes.gen.js +33 -1
- package/dist/src/services/cli-logger.service.d.ts +22 -2
- package/dist/src/services/cli-logger.service.js +97 -21
- package/dist/src/services.js +8 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +0 -10
- package/dist/.pikku/cli/pikku-cli-client.gen.js +0 -44
- /package/dist/.pikku/schemas/schemas/{PikkuChannelsOutput.schema.json → PikkuCommandChannelsOutput.schema.json} +0 -0
|
@@ -12,7 +12,7 @@ export const serializeFunctionTypes = (userSessionTypeImport, userSessionTypeNam
|
|
|
12
12
|
* Core function, middleware, and permission types for all wirings
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import type { CorePikkuMiddleware, CorePermissionGroup, PikkuWire, PickRequired } from '@pikku/core'
|
|
15
|
+
import type { CorePikkuMiddleware, CorePermissionGroup, ListInput, ListOutput, PikkuWire, PickRequired } from '@pikku/core'
|
|
16
16
|
import type { CorePikkuFunctionConfig, CorePikkuAuth, CorePikkuAuthConfig, CorePikkuPermission } from '@pikku/core/function'
|
|
17
17
|
import { pikkuAuth as pikkuAuthCore } from '@pikku/core/function'
|
|
18
18
|
import { addMiddleware as addMiddlewareCore, addPermission as addPermissionCore } from '@pikku/core/middleware'
|
|
@@ -338,10 +338,13 @@ export type PikkuFunctionConfigWithSchema<
|
|
|
338
338
|
RequiredWires extends keyof PikkuWire = never
|
|
339
339
|
> = {
|
|
340
340
|
name?: string
|
|
341
|
+
description?: string
|
|
341
342
|
tags?: string[]
|
|
342
343
|
expose?: boolean
|
|
343
344
|
mcp?: boolean
|
|
344
345
|
internal?: boolean
|
|
346
|
+
remote?: boolean
|
|
347
|
+
deploy?: 'serverless' | 'server' | 'auto'
|
|
345
348
|
approvalRequired?: boolean
|
|
346
349
|
approvalDescription?: InputSchema extends StandardSchemaV1 ? PikkuApprovalDescription<InferSchemaOutput<InputSchema>> : never
|
|
347
350
|
func: PikkuFunction<
|
|
@@ -415,6 +418,32 @@ export function pikkuFunc(func: any) {
|
|
|
415
418
|
return typeof func === 'function' ? { func } : func
|
|
416
419
|
}
|
|
417
420
|
|
|
421
|
+
export type PikkuListFunction<
|
|
422
|
+
F extends Record<string, unknown> = {},
|
|
423
|
+
Row = unknown,
|
|
424
|
+
S extends string = never
|
|
425
|
+
> =
|
|
426
|
+
| PikkuFunction<ListInput<F, S>, ListOutput<Row>, 'session' | 'rpc'>
|
|
427
|
+
| PikkuFunctionSessionless<
|
|
428
|
+
ListInput<F, S>,
|
|
429
|
+
ListOutput<Row>,
|
|
430
|
+
'session' | 'rpc'
|
|
431
|
+
>
|
|
432
|
+
|
|
433
|
+
export const pikkuListFunc = <
|
|
434
|
+
F extends Record<string, unknown> = {},
|
|
435
|
+
Row = unknown,
|
|
436
|
+
S extends string = never
|
|
437
|
+
>(
|
|
438
|
+
config: PikkuFunctionConfig<
|
|
439
|
+
ListInput<F, S>,
|
|
440
|
+
ListOutput<Row>,
|
|
441
|
+
'session' | 'rpc'
|
|
442
|
+
>
|
|
443
|
+
): PikkuFunctionConfig<ListInput<F, S>, ListOutput<Row>, 'session' | 'rpc'> => {
|
|
444
|
+
return pikkuFunc(config)
|
|
445
|
+
}
|
|
446
|
+
|
|
418
447
|
/**
|
|
419
448
|
* Configuration object for sessionless Pikku functions with Zod schema validation.
|
|
420
449
|
*/
|
|
@@ -430,6 +459,7 @@ export type PikkuFunctionSessionlessConfigWithSchema<
|
|
|
430
459
|
mcp?: boolean
|
|
431
460
|
internal?: boolean
|
|
432
461
|
remote?: boolean
|
|
462
|
+
deploy?: 'serverless' | 'server' | 'auto'
|
|
433
463
|
approvalRequired?: boolean
|
|
434
464
|
approvalDescription?: InputSchema extends StandardSchemaV1 ? PikkuApprovalDescription<InferSchemaOutput<InputSchema>> : never
|
|
435
465
|
func: PikkuFunctionSessionless<
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const pikkuCommandHTTP: import("#pikku").PikkuFunctionConfig<void, boolean | undefined, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<void, boolean | undefined, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<void, boolean | undefined, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
|
|
@@ -4,7 +4,7 @@ import { writeFileInDir } from '../../../utils/file-writer.js';
|
|
|
4
4
|
import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
|
|
5
5
|
import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
|
|
6
6
|
import { stripVerboseFields, hasVerboseFields, } from '../../../utils/strip-verbose-meta.js';
|
|
7
|
-
export const
|
|
7
|
+
export const pikkuCommandHTTP = pikkuSessionlessFunc({
|
|
8
8
|
func: async ({ logger, config, getInspectorState }) => {
|
|
9
9
|
const visitState = await getInspectorState();
|
|
10
10
|
const { httpWiringsFile, httpWiringMetaFile, httpWiringMetaJsonFile, packageMappings, schema, } = config;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const pikkuCommandQueueMap: import("#pikku").PikkuFunctionConfig<void, void, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<void, void, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<void, void, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
|
|
@@ -2,7 +2,7 @@ import { pikkuSessionlessFunc } from '#pikku';
|
|
|
2
2
|
import { writeFileInDir } from '../../../utils/file-writer.js';
|
|
3
3
|
import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
|
|
4
4
|
import { serializeQueueMap } from './serialize-queue-map.js';
|
|
5
|
-
export const
|
|
5
|
+
export const pikkuCommandQueueMap = pikkuSessionlessFunc({
|
|
6
6
|
func: async ({ logger, config, getInspectorState }) => {
|
|
7
7
|
const { queueWorkers, functions, resolvedIOTypes } = await getInspectorState();
|
|
8
8
|
const { queueMapDeclarationFile, packageMappings } = config;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const pikkuCommandQueue: import("#pikku").PikkuFunctionConfig<void, boolean | undefined, "session" | "rpc", import("#pikku").PikkuFunctionSessionless<void, boolean | undefined, "session" | "rpc", import("#pikku").Services> | import("#pikku").PikkuFunction<void, boolean | undefined, "session" | "rpc", import("#pikku").Services>, undefined, undefined>;
|
|
@@ -5,7 +5,7 @@ import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-
|
|
|
5
5
|
import { serializeQueueMeta, serializeQueueMetaTS, } from './serialize-queue-meta.js';
|
|
6
6
|
import { getFileImportRelativePath } from '../../../utils/file-import-path.js';
|
|
7
7
|
import { stripVerboseFields, hasVerboseFields, } from '../../../utils/strip-verbose-meta.js';
|
|
8
|
-
export const
|
|
8
|
+
export const pikkuCommandQueue = pikkuSessionlessFunc({
|
|
9
9
|
func: async ({ logger, config, getInspectorState }) => {
|
|
10
10
|
const visitState = await getInspectorState();
|
|
11
11
|
const { queueWorkersWiringFile, queueWorkersWiringMetaFile, queueWorkersWiringMetaJsonFile, packageMappings, schema, } = config;
|
|
@@ -4,7 +4,11 @@ import { writeFileInDir } from '../../../utils/file-writer.js';
|
|
|
4
4
|
import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
|
|
5
5
|
import { serializePublicRPC } from './serialize-public-rpc.js';
|
|
6
6
|
export const pikkuPublicRPC = pikkuSessionlessFunc({
|
|
7
|
-
func: async ({ logger, config }) => {
|
|
7
|
+
func: async ({ logger, config, variables }) => {
|
|
8
|
+
const deployCodegenFlag = await variables.get('PIKKU_DEPLOY_CODEGEN');
|
|
9
|
+
if (deployCodegenFlag === '1') {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
8
12
|
if (config.scaffold?.rpc) {
|
|
9
13
|
const pathToPikkuTypes = getFileImportRelativePath(config.publicRpcFile, config.typesDeclarationFile, config.packageMappings);
|
|
10
14
|
await writeFileInDir(logger, config.publicRpcFile, serializePublicRPC(pathToPikkuTypes, config.scaffold.rpc === 'auth', config.globalHTTPPrefix || ''));
|
|
@@ -4,7 +4,11 @@ import { writeFileInDir } from '../../../utils/file-writer.js';
|
|
|
4
4
|
import { logCommandInfoAndTime } from '../../../middleware/log-command-info-and-time.js';
|
|
5
5
|
import { serializeRemoteRPC } from './serialize-remote-rpc.js';
|
|
6
6
|
export const pikkuRemoteRPC = pikkuSessionlessFunc({
|
|
7
|
-
func: async ({ logger, config }) => {
|
|
7
|
+
func: async ({ logger, config, variables }) => {
|
|
8
|
+
const deployCodegenFlag = await variables.get('PIKKU_DEPLOY_CODEGEN');
|
|
9
|
+
if (deployCodegenFlag === '1') {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
8
12
|
if (config.remoteRpcWorkersFile) {
|
|
9
13
|
const pathToPikkuTypes = getFileImportRelativePath(config.remoteRpcWorkersFile, config.typesDeclarationFile, config.packageMappings);
|
|
10
14
|
await writeFileInDir(logger, config.remoteRpcWorkersFile, serializeRemoteRPC(pathToPikkuTypes));
|
|
@@ -41,13 +41,13 @@ ${addonImports}
|
|
|
41
41
|
${mergedRPCMap}
|
|
42
42
|
|
|
43
43
|
export type RPCInvoke = <Name extends keyof FlattenedRPCMap>(
|
|
44
|
-
...args: FlattenedRPCMap[Name]['input'] extends
|
|
44
|
+
...args: IsVoidishInput<FlattenedRPCMap[Name]['input']> extends true
|
|
45
45
|
? [name: Name]
|
|
46
46
|
: [name: Name, data: FlattenedRPCMap[Name]['input']]
|
|
47
47
|
) => Promise<FlattenedRPCMap[Name]['output']>
|
|
48
48
|
|
|
49
49
|
export type RPCRemote = <Name extends keyof FlattenedRPCMap>(
|
|
50
|
-
...args: FlattenedRPCMap[Name]['input'] extends
|
|
50
|
+
...args: IsVoidishInput<FlattenedRPCMap[Name]['input']> extends true
|
|
51
51
|
? [name: Name]
|
|
52
52
|
: [name: Name, data: FlattenedRPCMap[Name]['input']]
|
|
53
53
|
) => Promise<FlattenedRPCMap[Name]['output']>
|
|
@@ -117,6 +117,13 @@ function generateMergedRPCMap(wireAddonDeclarations) {
|
|
|
117
117
|
return `
|
|
118
118
|
// No addon packages, use RPCMap directly
|
|
119
119
|
export type FlattenedRPCMap = RPCMap
|
|
120
|
+
|
|
121
|
+
type IsAny<T> = 0 extends (1 & T) ? true : false
|
|
122
|
+
type IsVoidishInput<T> = IsAny<T> extends true
|
|
123
|
+
? false
|
|
124
|
+
: [T] extends [void | null | undefined]
|
|
125
|
+
? true
|
|
126
|
+
: false
|
|
120
127
|
`;
|
|
121
128
|
}
|
|
122
129
|
// TypeScript utility to flatten namespaced RPC maps
|
|
@@ -131,6 +138,13 @@ export type FlattenedRPCMap =
|
|
|
131
138
|
RPCMap${Array.from(wireAddonDeclarations.keys())
|
|
132
139
|
.map((namespace) => ` & PrefixKeys<${toPascalCase(namespace)}RPCMap, '${namespace}'>`)
|
|
133
140
|
.join('')}
|
|
141
|
+
|
|
142
|
+
type IsAny<T> = 0 extends (1 & T) ? true : false
|
|
143
|
+
type IsVoidishInput<T> = IsAny<T> extends true
|
|
144
|
+
? false
|
|
145
|
+
: [T] extends [void | null | undefined]
|
|
146
|
+
? true
|
|
147
|
+
: false
|
|
134
148
|
`;
|
|
135
149
|
return utilityTypes;
|
|
136
150
|
}
|
|
@@ -68,6 +68,7 @@ export const workflowStatusStream = pikkuSessionlessFunc<
|
|
|
68
68
|
|
|
69
69
|
const terminalStatuses = new Set(['completed', 'failed', 'cancelled'])
|
|
70
70
|
let lastHash = ''
|
|
71
|
+
let initSent = false
|
|
71
72
|
|
|
72
73
|
const poll = async () => {
|
|
73
74
|
const run = await workflowRunService.getRun(runId)
|
|
@@ -78,6 +79,26 @@ export const workflowStatusStream = pikkuSessionlessFunc<
|
|
|
78
79
|
|
|
79
80
|
const steps = await workflowRunService.getRunSteps(runId)
|
|
80
81
|
|
|
82
|
+
if (!initSent && run.deterministic) {
|
|
83
|
+
const statusByStep = new Map(
|
|
84
|
+
steps.map((s: { stepName: string; status: string }) => [
|
|
85
|
+
s.stepName,
|
|
86
|
+
s.status,
|
|
87
|
+
])
|
|
88
|
+
)
|
|
89
|
+
channel.send({
|
|
90
|
+
type: 'init',
|
|
91
|
+
deterministic: true,
|
|
92
|
+
steps: (run.plannedSteps ?? []).map(
|
|
93
|
+
(s: { stepName: string }) => ({
|
|
94
|
+
stepName: s.stepName,
|
|
95
|
+
status: statusByStep.get(s.stepName) ?? 'pending',
|
|
96
|
+
})
|
|
97
|
+
),
|
|
98
|
+
})
|
|
99
|
+
initSent = true
|
|
100
|
+
}
|
|
101
|
+
|
|
81
102
|
const hash = JSON.stringify({
|
|
82
103
|
s: run.status,
|
|
83
104
|
steps: steps.map((s: { stepName: string; status: string }) => [s.stepName, s.status]),
|
|
@@ -133,6 +154,7 @@ export const workflowStatusStreamFull = pikkuSessionlessFunc<
|
|
|
133
154
|
|
|
134
155
|
const terminalStatuses = new Set(['completed', 'failed', 'cancelled'])
|
|
135
156
|
let lastHash = ''
|
|
157
|
+
let initSent = false
|
|
136
158
|
|
|
137
159
|
const poll = async () => {
|
|
138
160
|
const run = await workflowRunService.getRun(runId)
|
|
@@ -143,6 +165,26 @@ export const workflowStatusStreamFull = pikkuSessionlessFunc<
|
|
|
143
165
|
|
|
144
166
|
const steps = await workflowRunService.getRunSteps(runId)
|
|
145
167
|
|
|
168
|
+
if (!initSent && run.deterministic) {
|
|
169
|
+
const statusByStep = new Map(
|
|
170
|
+
steps.map((s: { stepName: string; status: string }) => [
|
|
171
|
+
s.stepName,
|
|
172
|
+
s.status,
|
|
173
|
+
])
|
|
174
|
+
)
|
|
175
|
+
channel.send({
|
|
176
|
+
type: 'init',
|
|
177
|
+
deterministic: true,
|
|
178
|
+
steps: (run.plannedSteps ?? []).map(
|
|
179
|
+
(s: { stepName: string }) => ({
|
|
180
|
+
stepName: s.stepName,
|
|
181
|
+
status: statusByStep.get(s.stepName) ?? 'pending',
|
|
182
|
+
})
|
|
183
|
+
),
|
|
184
|
+
})
|
|
185
|
+
initSent = true
|
|
186
|
+
}
|
|
187
|
+
|
|
146
188
|
const hash = JSON.stringify({
|
|
147
189
|
s: run.status,
|
|
148
190
|
o: run.output,
|
|
@@ -128,7 +128,7 @@ export const allWorkflow = pikkuWorkflowComplexFunc({
|
|
|
128
128
|
}
|
|
129
129
|
if (!config.addon) {
|
|
130
130
|
const [http, scheduler, triggers] = await Promise.all([
|
|
131
|
-
workflow.do('HTTP', '
|
|
131
|
+
workflow.do('HTTP', 'pikkuCommandHTTP', null),
|
|
132
132
|
workflow.do('Scheduler', 'pikkuScheduler', null),
|
|
133
133
|
workflow.do('Trigger', 'pikkuTrigger', null),
|
|
134
134
|
]);
|
|
@@ -158,15 +158,15 @@ export const allWorkflow = pikkuWorkflowComplexFunc({
|
|
|
158
158
|
}
|
|
159
159
|
if (!config.addon) {
|
|
160
160
|
const [queues, channels, gateways, mcp, cli] = await Promise.all([
|
|
161
|
-
workflow.do('Queue', '
|
|
162
|
-
workflow.do('Channels', '
|
|
161
|
+
workflow.do('Queue', 'pikkuCommandQueue', null),
|
|
162
|
+
workflow.do('Channels', 'pikkuCommandChannels', null),
|
|
163
163
|
workflow.do('Gateway', 'pikkuGateway', null),
|
|
164
164
|
workflow.do('MCP', 'pikkuMCP', null),
|
|
165
165
|
workflow.do('CLI', 'pikkuCLI', null),
|
|
166
166
|
]);
|
|
167
167
|
if (queues) {
|
|
168
168
|
await Promise.all([
|
|
169
|
-
workflow.do('Queue map', '
|
|
169
|
+
workflow.do('Queue map', 'pikkuCommandQueueMap', null),
|
|
170
170
|
workflow.do('Queue service', 'pikkuQueueService', null),
|
|
171
171
|
]);
|
|
172
172
|
allImports.push(config.queueWorkersWiringMetaFile, config.queueWorkersWiringFile);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* This file was generated by @pikku/cli@0.12.
|
|
2
|
+
* This file was generated by @pikku/cli@0.12.21
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* Workflow HTTP catch-all routes
|
|
@@ -50,6 +50,7 @@ export const workflowStatusStream = pikkuSessionlessFunc({
|
|
|
50
50
|
return;
|
|
51
51
|
const terminalStatuses = new Set(['completed', 'failed', 'cancelled']);
|
|
52
52
|
let lastHash = '';
|
|
53
|
+
let initSent = false;
|
|
53
54
|
const poll = async () => {
|
|
54
55
|
const run = await workflowRunService.getRun(runId);
|
|
55
56
|
if (!run) {
|
|
@@ -57,6 +58,21 @@ export const workflowStatusStream = pikkuSessionlessFunc({
|
|
|
57
58
|
return false;
|
|
58
59
|
}
|
|
59
60
|
const steps = await workflowRunService.getRunSteps(runId);
|
|
61
|
+
if (!initSent && run.deterministic) {
|
|
62
|
+
const statusByStep = new Map(steps.map((s) => [
|
|
63
|
+
s.stepName,
|
|
64
|
+
s.status,
|
|
65
|
+
]));
|
|
66
|
+
channel.send({
|
|
67
|
+
type: 'init',
|
|
68
|
+
deterministic: true,
|
|
69
|
+
steps: (run.plannedSteps ?? []).map((s) => ({
|
|
70
|
+
stepName: s.stepName,
|
|
71
|
+
status: statusByStep.get(s.stepName) ?? 'pending',
|
|
72
|
+
})),
|
|
73
|
+
});
|
|
74
|
+
initSent = true;
|
|
75
|
+
}
|
|
60
76
|
const hash = JSON.stringify({
|
|
61
77
|
s: run.status,
|
|
62
78
|
steps: steps.map((s) => [s.stepName, s.status]),
|
|
@@ -105,6 +121,7 @@ export const workflowStatusStreamFull = pikkuSessionlessFunc({
|
|
|
105
121
|
return;
|
|
106
122
|
const terminalStatuses = new Set(['completed', 'failed', 'cancelled']);
|
|
107
123
|
let lastHash = '';
|
|
124
|
+
let initSent = false;
|
|
108
125
|
const poll = async () => {
|
|
109
126
|
const run = await workflowRunService.getRun(runId);
|
|
110
127
|
if (!run) {
|
|
@@ -112,6 +129,21 @@ export const workflowStatusStreamFull = pikkuSessionlessFunc({
|
|
|
112
129
|
return false;
|
|
113
130
|
}
|
|
114
131
|
const steps = await workflowRunService.getRunSteps(runId);
|
|
132
|
+
if (!initSent && run.deterministic) {
|
|
133
|
+
const statusByStep = new Map(steps.map((s) => [
|
|
134
|
+
s.stepName,
|
|
135
|
+
s.status,
|
|
136
|
+
]));
|
|
137
|
+
channel.send({
|
|
138
|
+
type: 'init',
|
|
139
|
+
deterministic: true,
|
|
140
|
+
steps: (run.plannedSteps ?? []).map((s) => ({
|
|
141
|
+
stepName: s.stepName,
|
|
142
|
+
status: statusByStep.get(s.stepName) ?? 'pending',
|
|
143
|
+
})),
|
|
144
|
+
});
|
|
145
|
+
initSent = true;
|
|
146
|
+
}
|
|
115
147
|
const hash = JSON.stringify({
|
|
116
148
|
s: run.status,
|
|
117
149
|
o: run.output,
|
|
@@ -1,26 +1,46 @@
|
|
|
1
1
|
import type { Logger } from '@pikku/core/services';
|
|
2
2
|
import { LogLevel } from '@pikku/core/services';
|
|
3
3
|
import type { ErrorCode } from '@pikku/inspector';
|
|
4
|
+
export type CLIOutputMode = 'text' | 'json';
|
|
4
5
|
export declare class CLILogger implements Logger {
|
|
5
6
|
private silent;
|
|
6
7
|
private level;
|
|
7
8
|
private criticalErrors;
|
|
9
|
+
private outputMode;
|
|
10
|
+
private jsonFlushHookRegistered;
|
|
8
11
|
constructor({ logLogo, silent, }: {
|
|
9
12
|
logLogo: boolean;
|
|
10
13
|
silent?: boolean;
|
|
11
14
|
});
|
|
12
15
|
setLevel(level: LogLevel): void;
|
|
13
16
|
setSilent(silent: boolean): void;
|
|
17
|
+
setOutputMode(mode: CLIOutputMode): void;
|
|
18
|
+
getOutputMode(): CLIOutputMode;
|
|
14
19
|
isSilent(): boolean;
|
|
20
|
+
private normalizeMessage;
|
|
21
|
+
private writeJSONLine;
|
|
22
|
+
private ensureJSONFlushHook;
|
|
23
|
+
flushJSONBuffer(): void;
|
|
24
|
+
private emit;
|
|
15
25
|
info(message: string | {
|
|
16
26
|
message: string;
|
|
17
27
|
type?: string;
|
|
28
|
+
data?: Record<string, unknown>;
|
|
29
|
+
}): void;
|
|
30
|
+
error(message: string | Error | {
|
|
31
|
+
message: string;
|
|
32
|
+
type?: string;
|
|
33
|
+
data?: Record<string, unknown>;
|
|
34
|
+
}): void;
|
|
35
|
+
warn(message: string | {
|
|
36
|
+
message: string;
|
|
37
|
+
type?: string;
|
|
38
|
+
data?: Record<string, unknown>;
|
|
18
39
|
}): void;
|
|
19
|
-
error(message: string): void;
|
|
20
|
-
warn(message: string): void;
|
|
21
40
|
debug(message: string | {
|
|
22
41
|
message: string;
|
|
23
42
|
type?: string;
|
|
43
|
+
data?: Record<string, unknown>;
|
|
24
44
|
}): void;
|
|
25
45
|
critical(code: ErrorCode, message: string): void;
|
|
26
46
|
hasCriticalErrors(): boolean;
|
|
@@ -9,10 +9,13 @@ const logo = `
|
|
|
9
9
|
|_| |_|_| _)_| _)____/
|
|
10
10
|
`;
|
|
11
11
|
const BASE_ERROR_URL = 'https://pikku.dev/docs/pikku-cli/errors';
|
|
12
|
+
const ANSI_ESCAPE_REGEX = /\x1B\[[0-?]*[ -/]*[@-~]/g;
|
|
12
13
|
export class CLILogger {
|
|
13
14
|
silent;
|
|
14
15
|
level = LogLevel.warn; // default to warn level
|
|
15
16
|
criticalErrors = [];
|
|
17
|
+
outputMode = 'text';
|
|
18
|
+
jsonFlushHookRegistered = false;
|
|
16
19
|
constructor({ logLogo, silent = false, }) {
|
|
17
20
|
this.silent = silent;
|
|
18
21
|
if (logLogo && !silent) {
|
|
@@ -25,49 +28,122 @@ export class CLILogger {
|
|
|
25
28
|
setSilent(silent) {
|
|
26
29
|
this.silent = silent;
|
|
27
30
|
}
|
|
31
|
+
setOutputMode(mode) {
|
|
32
|
+
this.outputMode = mode;
|
|
33
|
+
if (mode === 'json') {
|
|
34
|
+
this.ensureJSONFlushHook();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
getOutputMode() {
|
|
38
|
+
return this.outputMode;
|
|
39
|
+
}
|
|
28
40
|
isSilent() {
|
|
29
41
|
return this.silent;
|
|
30
42
|
}
|
|
43
|
+
normalizeMessage(message) {
|
|
44
|
+
const str = typeof message === 'string'
|
|
45
|
+
? message
|
|
46
|
+
: message instanceof Error
|
|
47
|
+
? (message.stack ?? message.message)
|
|
48
|
+
: typeof message === 'object' && message !== null
|
|
49
|
+
? JSON.stringify(message)
|
|
50
|
+
: String(message);
|
|
51
|
+
if (this.outputMode === 'json') {
|
|
52
|
+
return str.replace(ANSI_ESCAPE_REGEX, '');
|
|
53
|
+
}
|
|
54
|
+
return str;
|
|
55
|
+
}
|
|
56
|
+
writeJSONLine(payload) {
|
|
57
|
+
process.stdout.write(`${JSON.stringify(payload)}\n`);
|
|
58
|
+
}
|
|
59
|
+
ensureJSONFlushHook() {
|
|
60
|
+
if (this.jsonFlushHookRegistered)
|
|
61
|
+
return;
|
|
62
|
+
this.jsonFlushHookRegistered = true;
|
|
63
|
+
process.once('beforeExit', () => this.flushJSONBuffer());
|
|
64
|
+
process.once('exit', () => this.flushJSONBuffer());
|
|
65
|
+
}
|
|
66
|
+
// NDJSON records are written synchronously in `emit` so consumers can
|
|
67
|
+
// stream output; nothing is buffered. Kept as a no-op because the
|
|
68
|
+
// beforeExit/exit hooks installed by `ensureJSONFlushHook` still
|
|
69
|
+
// reference it, and external callers may rely on the signature.
|
|
70
|
+
flushJSONBuffer() { }
|
|
71
|
+
emit(level, message, type, code, data) {
|
|
72
|
+
const normalizedMessage = this.normalizeMessage(message);
|
|
73
|
+
if (this.outputMode === 'json') {
|
|
74
|
+
this.writeJSONLine({
|
|
75
|
+
level,
|
|
76
|
+
message: normalizedMessage,
|
|
77
|
+
...(type ? { type } : {}),
|
|
78
|
+
...(code ? { code } : {}),
|
|
79
|
+
...(code ? { url: `${BASE_ERROR_URL}/${code.toLowerCase()}` } : {}),
|
|
80
|
+
...(data ? { data } : {}),
|
|
81
|
+
timestamp: new Date().toISOString(),
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (level === 'error') {
|
|
86
|
+
console.error(chalk.red(normalizedMessage));
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (level === 'warn') {
|
|
90
|
+
console.error(chalk.yellow(normalizedMessage));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (level === 'critical') {
|
|
94
|
+
console.error(chalk.red.bold(normalizedMessage));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
let c = level === 'info' ? chalk.blue : chalk.gray;
|
|
98
|
+
if (type === 'success') {
|
|
99
|
+
c = chalk.green;
|
|
100
|
+
}
|
|
101
|
+
else if (type === 'timing' && level === 'info') {
|
|
102
|
+
c = chalk.gray;
|
|
103
|
+
}
|
|
104
|
+
console.log(c(normalizedMessage));
|
|
105
|
+
}
|
|
31
106
|
info(message) {
|
|
32
107
|
if (this.level > LogLevel.info || this.silent)
|
|
33
108
|
return;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
else if (message.type === 'timing') {
|
|
40
|
-
c = chalk.gray;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
console.log(c(typeof message === 'string' ? message : message.message));
|
|
109
|
+
const msg = typeof message === 'string' ? message : message.message;
|
|
110
|
+
const type = typeof message === 'string' ? undefined : message.type;
|
|
111
|
+
const data = typeof message === 'string' ? undefined : message.data;
|
|
112
|
+
this.emit('info', msg, type, undefined, data);
|
|
44
113
|
}
|
|
45
114
|
error(message) {
|
|
46
115
|
if (this.level > LogLevel.error)
|
|
47
116
|
return;
|
|
48
|
-
|
|
117
|
+
if (message instanceof Error) {
|
|
118
|
+
this.emit('error', message.stack ?? message.message);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const msg = typeof message === 'string' ? message : message.message;
|
|
122
|
+
const type = typeof message === 'string' ? undefined : message.type;
|
|
123
|
+
const data = typeof message === 'string' ? undefined : message.data;
|
|
124
|
+
this.emit('error', msg, type, undefined, data);
|
|
49
125
|
}
|
|
50
126
|
warn(message) {
|
|
51
127
|
if (this.level > LogLevel.warn)
|
|
52
128
|
return;
|
|
53
|
-
|
|
129
|
+
const msg = typeof message === 'string' ? message : message.message;
|
|
130
|
+
const type = typeof message === 'string' ? undefined : message.type;
|
|
131
|
+
const data = typeof message === 'string' ? undefined : message.data;
|
|
132
|
+
this.emit('warn', msg, type, undefined, data);
|
|
54
133
|
}
|
|
55
134
|
debug(message) {
|
|
56
135
|
if (this.level > LogLevel.debug || this.silent)
|
|
57
136
|
return;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
console.log(c(typeof message === 'string' ? message : message.message));
|
|
137
|
+
const msg = typeof message === 'string' ? message : message.message;
|
|
138
|
+
const type = typeof message === 'string' ? undefined : message.type;
|
|
139
|
+
const data = typeof message === 'string' ? undefined : message.data;
|
|
140
|
+
this.emit('debug', msg, type, undefined, data);
|
|
65
141
|
}
|
|
66
142
|
critical(code, message) {
|
|
67
143
|
const url = `${BASE_ERROR_URL}/${code.toLowerCase()}`;
|
|
68
144
|
const formattedMessage = `[${code}] ${message}\n → ${url}`;
|
|
69
145
|
this.criticalErrors.push(formattedMessage);
|
|
70
|
-
|
|
146
|
+
this.emit('critical', formattedMessage, undefined, code);
|
|
71
147
|
}
|
|
72
148
|
hasCriticalErrors() {
|
|
73
149
|
return this.criticalErrors.length > 0;
|
|
@@ -83,7 +159,7 @@ export class CLILogger {
|
|
|
83
159
|
}
|
|
84
160
|
primary(message) {
|
|
85
161
|
if (!this.silent) {
|
|
86
|
-
|
|
162
|
+
this.emit('info', message);
|
|
87
163
|
}
|
|
88
164
|
}
|
|
89
165
|
}
|
package/dist/src/services.js
CHANGED
|
@@ -103,6 +103,13 @@ export const createConfig = async (_variablesService, data) => {
|
|
|
103
103
|
// --silent > --loglevel > --verbose > --info > default (warn)
|
|
104
104
|
let logLevel = LogLevel.warn; // default
|
|
105
105
|
let isSilent = false;
|
|
106
|
+
// --output is constrained to 'text' | 'json' by the CLI parser
|
|
107
|
+
// (choices + default in cli.wiring.ts), so no runtime validation
|
|
108
|
+
// is needed here. --json is kept as an alias that forces 'json'.
|
|
109
|
+
const outputMode = data.json
|
|
110
|
+
? 'json'
|
|
111
|
+
: data.output;
|
|
112
|
+
logger.setOutputMode(outputMode);
|
|
106
113
|
if (data.silent) {
|
|
107
114
|
logLevel = LogLevel.critical;
|
|
108
115
|
isSilent = true;
|
|
@@ -125,7 +132,7 @@ export const createConfig = async (_variablesService, data) => {
|
|
|
125
132
|
logger.setLevel(logLevel);
|
|
126
133
|
logger.setSilent(isSilent);
|
|
127
134
|
// Display logo unless in silent mode
|
|
128
|
-
if (!isSilent) {
|
|
135
|
+
if (!isSilent && outputMode !== 'json') {
|
|
129
136
|
logger.logLogo();
|
|
130
137
|
}
|
|
131
138
|
const cliConfig = await getPikkuCLIConfig(logger, data.configFile, [], true, data.outDir);
|