@pikku/core 0.9.11 → 0.9.12-next.0
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/CHANGELOG.md +6 -0
- package/dist/function/function-runner.d.ts +13 -8
- package/dist/function/function-runner.js +49 -37
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/middleware-runner.d.ts +61 -40
- package/dist/middleware-runner.js +118 -66
- package/dist/permissions.js +1 -0
- package/dist/pikku-state.d.ts +26 -1
- package/dist/pikku-state.js +10 -1
- package/dist/services/content-service.d.ts +2 -3
- package/dist/services/index.d.ts +0 -1
- package/dist/services/index.js +0 -1
- package/dist/services/local-content.d.ts +2 -4
- package/dist/types/core.types.d.ts +51 -2
- package/dist/types/core.types.js +21 -0
- package/dist/wirings/channel/channel-handler.d.ts +2 -2
- package/dist/wirings/channel/channel-handler.js +12 -9
- package/dist/wirings/channel/channel-runner.d.ts +0 -2
- package/dist/wirings/channel/channel-runner.js +2 -3
- package/dist/wirings/channel/channel.types.d.ts +5 -3
- package/dist/wirings/channel/local/local-channel-runner.js +12 -12
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +7 -8
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +12 -0
- package/dist/wirings/cli/channel/cli-channel-runner.js +80 -0
- package/dist/wirings/cli/channel/index.d.ts +1 -0
- package/dist/wirings/cli/channel/index.js +1 -0
- package/dist/wirings/cli/cli-runner.d.ts +32 -0
- package/dist/wirings/cli/cli-runner.js +328 -0
- package/dist/wirings/cli/cli.types.d.ts +177 -0
- package/dist/wirings/cli/cli.types.js +1 -0
- package/dist/wirings/cli/command-parser.d.ts +19 -0
- package/dist/wirings/cli/command-parser.js +373 -0
- package/dist/wirings/cli/index.d.ts +5 -0
- package/dist/wirings/cli/index.js +5 -0
- package/dist/wirings/http/http-runner.d.ts +29 -10
- package/dist/wirings/http/http-runner.js +103 -131
- package/dist/wirings/http/http.types.d.ts +10 -10
- package/dist/wirings/http/index.d.ts +1 -1
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/http/pikku-fetch-http-response.js +3 -1
- package/dist/wirings/http/routers/http-router.d.ts +0 -2
- package/dist/wirings/http/routers/path-to-regex.d.ts +1 -1
- package/dist/wirings/http/routers/path-to-regex.js +5 -34
- package/dist/wirings/mcp/mcp-runner.d.ts +4 -5
- package/dist/wirings/mcp/mcp-runner.js +30 -34
- package/dist/wirings/mcp/mcp.types.d.ts +11 -8
- package/dist/wirings/queue/queue-runner.d.ts +2 -2
- package/dist/wirings/queue/queue-runner.js +25 -27
- package/dist/wirings/queue/queue.types.d.ts +6 -5
- package/dist/wirings/rpc/index.d.ts +1 -1
- package/dist/wirings/rpc/index.js +1 -1
- package/dist/wirings/rpc/rpc-runner.d.ts +6 -18
- package/dist/wirings/rpc/rpc-runner.js +13 -8
- package/dist/wirings/scheduler/scheduler-runner.d.ts +2 -2
- package/dist/wirings/scheduler/scheduler-runner.js +37 -35
- package/dist/wirings/scheduler/scheduler.types.d.ts +4 -3
- package/package.json +4 -3
- package/src/function/function-runner.test.ts +73 -23
- package/src/function/function-runner.ts +74 -55
- package/src/index.ts +8 -1
- package/src/middleware-runner.test.ts +24 -16
- package/src/middleware-runner.ts +136 -83
- package/src/permissions.ts +1 -0
- package/src/pikku-state.ts +47 -2
- package/src/services/content-service.ts +5 -4
- package/src/services/index.ts +0 -1
- package/src/services/local-content.ts +9 -4
- package/src/types/core.types.ts +74 -3
- package/src/wirings/channel/channel-handler.ts +9 -13
- package/src/wirings/channel/channel-runner.ts +2 -6
- package/src/wirings/channel/channel.types.ts +5 -1
- package/src/wirings/channel/local/local-channel-runner.ts +25 -15
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +15 -17
- package/src/wirings/cli/channel/cli-channel-runner.ts +118 -0
- package/src/wirings/cli/channel/index.ts +1 -0
- package/src/wirings/cli/cli-runner.test.ts +382 -0
- package/src/wirings/cli/cli-runner.ts +503 -0
- package/src/wirings/cli/cli.types.ts +320 -0
- package/src/wirings/cli/command-parser.test.ts +440 -0
- package/src/wirings/cli/command-parser.ts +470 -0
- package/src/wirings/cli/index.ts +12 -0
- package/src/wirings/http/http-runner.test.ts +8 -7
- package/src/wirings/http/http-runner.ts +126 -159
- package/src/wirings/http/http.types.ts +56 -11
- package/src/wirings/http/index.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +3 -1
- package/src/wirings/http/routers/http-router.ts +0 -2
- package/src/wirings/http/routers/path-to-regex.test.ts +4 -5
- package/src/wirings/http/routers/path-to-regex.ts +6 -43
- package/src/wirings/mcp/mcp-runner.ts +56 -55
- package/src/wirings/mcp/mcp.types.ts +23 -8
- package/src/wirings/queue/queue-runner.ts +44 -47
- package/src/wirings/queue/queue.types.ts +10 -6
- package/src/wirings/rpc/index.ts +1 -1
- package/src/wirings/rpc/rpc-runner.ts +27 -9
- package/src/wirings/scheduler/scheduler-runner.ts +57 -56
- package/src/wirings/scheduler/scheduler.types.ts +9 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -3,7 +3,6 @@ import { addFunction } from '../../function/function-runner.js'
|
|
|
3
3
|
import { pikkuState } from '../../pikku-state.js'
|
|
4
4
|
import { coerceTopLevelDataFromSchema, validateSchema } from '../../schema.js'
|
|
5
5
|
import { UserSessionService } from '../../services/user-session-service.js'
|
|
6
|
-
import { CorePikkuMiddleware } from '../../types/core.types.js'
|
|
7
6
|
import { httpRouter } from '../http/routers/http-router.js'
|
|
8
7
|
import {
|
|
9
8
|
ChannelMeta,
|
|
@@ -117,7 +116,6 @@ const getMatchingChannelConfig = (request: string) => {
|
|
|
117
116
|
channelConfig,
|
|
118
117
|
schemaName: channelMeta.input,
|
|
119
118
|
meta: channelMeta,
|
|
120
|
-
httpMiddleware: matchedPath.middleware,
|
|
121
119
|
}
|
|
122
120
|
}
|
|
123
121
|
|
|
@@ -133,7 +131,6 @@ export const openChannel = async ({
|
|
|
133
131
|
openingData: unknown
|
|
134
132
|
channelConfig: CoreChannel<unknown, any>
|
|
135
133
|
meta: ChannelMeta
|
|
136
|
-
httpMiddleware: CorePikkuMiddleware[] | undefined
|
|
137
134
|
}> => {
|
|
138
135
|
const matchingChannel = getMatchingChannelConfig(route)
|
|
139
136
|
if (!matchingChannel) {
|
|
@@ -141,8 +138,7 @@ export const openChannel = async ({
|
|
|
141
138
|
throw new NotFoundError(`Channel not found: ${route}`)
|
|
142
139
|
}
|
|
143
140
|
|
|
144
|
-
const { params, channelConfig, schemaName, meta
|
|
145
|
-
matchingChannel
|
|
141
|
+
const { params, channelConfig, schemaName, meta } = matchingChannel
|
|
146
142
|
|
|
147
143
|
const requiresSession = channelConfig.auth !== false
|
|
148
144
|
request?.setParams(params)
|
|
@@ -165,5 +161,5 @@ export const openChannel = async ({
|
|
|
165
161
|
)
|
|
166
162
|
}
|
|
167
163
|
|
|
168
|
-
return { openingData, channelConfig, meta
|
|
164
|
+
return { openingData, channelConfig, meta }
|
|
169
165
|
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
CoreSingletonServices,
|
|
10
10
|
CreateSessionServices,
|
|
11
11
|
CorePikkuMiddleware,
|
|
12
|
+
MiddlewareMetadata,
|
|
12
13
|
} from '../../types/core.types.js'
|
|
13
14
|
import {
|
|
14
15
|
CorePikkuFunction,
|
|
@@ -35,6 +36,7 @@ export type RunChannelParams<ChannelData> = {
|
|
|
35
36
|
export interface ChannelMessageMeta {
|
|
36
37
|
pikkuFuncName: string
|
|
37
38
|
docs?: PikkuDocs
|
|
39
|
+
middleware?: MiddlewareMetadata[]
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
export interface ChannelMeta {
|
|
@@ -50,6 +52,7 @@ export interface ChannelMeta {
|
|
|
50
52
|
messageWirings: Record<string, Record<string, ChannelMessageMeta>>
|
|
51
53
|
docs?: PikkuDocs
|
|
52
54
|
tags?: string[]
|
|
55
|
+
middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
export type ChannelsMeta = Record<string, ChannelMeta>
|
|
@@ -67,6 +70,7 @@ export type CoreChannel<
|
|
|
67
70
|
| CorePikkuFunction<unknown, unknown, ChannelData>
|
|
68
71
|
| CorePikkuFunctionSessionless<unknown, unknown, ChannelData>,
|
|
69
72
|
PikkuPermission = CorePikkuPermission<ChannelData>,
|
|
73
|
+
PikkuMiddleware = CorePikkuMiddleware,
|
|
70
74
|
> = {
|
|
71
75
|
name: string
|
|
72
76
|
route: Channel
|
|
@@ -91,7 +95,7 @@ export type CoreChannel<
|
|
|
91
95
|
}
|
|
92
96
|
>
|
|
93
97
|
>
|
|
94
|
-
middleware?:
|
|
98
|
+
middleware?: PikkuMiddleware[]
|
|
95
99
|
permissions?: Record<string, PikkuPermission[] | PikkuPermission>
|
|
96
100
|
auth?: boolean
|
|
97
101
|
docs?: Partial<{
|
|
@@ -8,7 +8,11 @@ import {
|
|
|
8
8
|
RunChannelParams,
|
|
9
9
|
} from '../channel.types.js'
|
|
10
10
|
import { PikkuLocalChannelHandler } from './local-channel-handler.js'
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
PikkuInteraction,
|
|
13
|
+
PikkuWiringTypes,
|
|
14
|
+
SessionServices,
|
|
15
|
+
} from '../../../types/core.types.js'
|
|
12
16
|
import { handleHTTPError } from '../../../handle-error.js'
|
|
13
17
|
import { combineMiddleware, runMiddleware } from '../../../middleware-runner.js'
|
|
14
18
|
import { PikkuUserSessionService } from '../../../services/user-session-service.js'
|
|
@@ -42,9 +46,9 @@ export const runLocalChannel = async ({
|
|
|
42
46
|
route = http?.request?.path()
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
let openingData, channelConfig, meta
|
|
49
|
+
let openingData, channelConfig, meta
|
|
46
50
|
try {
|
|
47
|
-
;({ openingData, channelConfig, meta
|
|
51
|
+
;({ openingData, channelConfig, meta } = await openChannel({
|
|
48
52
|
channelId,
|
|
49
53
|
createSessionServices,
|
|
50
54
|
respondWith404,
|
|
@@ -86,17 +90,24 @@ export const runLocalChannel = async ({
|
|
|
86
90
|
)
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
const getAllServices = (channel: any, requiresAuth?: boolean) =>
|
|
94
|
+
rpcService.injectRPCService(
|
|
95
|
+
{
|
|
96
|
+
...singletonServices,
|
|
97
|
+
...sessionServices,
|
|
98
|
+
userSession,
|
|
99
|
+
},
|
|
100
|
+
interaction,
|
|
101
|
+
requiresAuth
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
const interaction: PikkuInteraction = { channel }
|
|
94
105
|
|
|
95
106
|
channelHandler.registerOnOpen(() => {
|
|
96
107
|
if (channelConfig.onConnect && meta.connect) {
|
|
97
108
|
runPikkuFuncDirectly(
|
|
98
109
|
meta.connect.pikkuFuncName,
|
|
99
|
-
|
|
110
|
+
getAllServices(channel, false),
|
|
100
111
|
openingData
|
|
101
112
|
)
|
|
102
113
|
}
|
|
@@ -106,10 +117,11 @@ export const runLocalChannel = async ({
|
|
|
106
117
|
if (channelConfig.onDisconnect && meta.disconnect) {
|
|
107
118
|
runPikkuFuncDirectly(
|
|
108
119
|
meta.disconnect.pikkuFuncName,
|
|
109
|
-
|
|
120
|
+
getAllServices(channel, false),
|
|
110
121
|
openingData
|
|
111
122
|
)
|
|
112
123
|
}
|
|
124
|
+
|
|
113
125
|
if (sessionServices) {
|
|
114
126
|
await closeSessionServices(singletonServices.logger, sessionServices)
|
|
115
127
|
}
|
|
@@ -117,8 +129,7 @@ export const runLocalChannel = async ({
|
|
|
117
129
|
|
|
118
130
|
channelHandler.registerOnMessage(
|
|
119
131
|
processMessageHandlers(
|
|
120
|
-
|
|
121
|
-
session,
|
|
132
|
+
getAllServices(channel),
|
|
122
133
|
channelConfig as any,
|
|
123
134
|
channelHandler
|
|
124
135
|
)
|
|
@@ -147,9 +158,8 @@ export const runLocalChannel = async ({
|
|
|
147
158
|
},
|
|
148
159
|
{ http },
|
|
149
160
|
combineMiddleware(PikkuWiringTypes.channel, channelConfig.name, {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
httpMiddleware,
|
|
161
|
+
wireInheritedMiddleware: meta.middleware,
|
|
162
|
+
wireMiddleware: channelConfig.middleware,
|
|
153
163
|
}),
|
|
154
164
|
main
|
|
155
165
|
)
|
|
@@ -85,16 +85,15 @@ export const runChannelConnect = async ({
|
|
|
85
85
|
|
|
86
86
|
const userSession = new PikkuUserSessionService(channelStore, channelId)
|
|
87
87
|
|
|
88
|
-
const { channelConfig, openingData, meta
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
})
|
|
88
|
+
const { channelConfig, openingData, meta } = await openChannel({
|
|
89
|
+
channelId,
|
|
90
|
+
createSessionServices,
|
|
91
|
+
request,
|
|
92
|
+
route,
|
|
93
|
+
singletonServices,
|
|
94
|
+
coerceDataFromSchema,
|
|
95
|
+
userSession,
|
|
96
|
+
})
|
|
98
97
|
|
|
99
98
|
const main = async () => {
|
|
100
99
|
try {
|
|
@@ -148,9 +147,8 @@ export const runChannelConnect = async ({
|
|
|
148
147
|
},
|
|
149
148
|
{ http },
|
|
150
149
|
combineMiddleware(PikkuWiringTypes.channel, channelConfig.name, {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
httpMiddleware,
|
|
150
|
+
wireInheritedMiddleware: meta.middleware,
|
|
151
|
+
wireMiddleware: channelConfig.middleware,
|
|
154
152
|
}),
|
|
155
153
|
main
|
|
156
154
|
)
|
|
@@ -171,7 +169,7 @@ export const runChannelDisconnect = async ({
|
|
|
171
169
|
if (!sessionServices && params.createSessionServices) {
|
|
172
170
|
sessionServices = await params.createSessionServices(
|
|
173
171
|
singletonServices,
|
|
174
|
-
{},
|
|
172
|
+
{ channel },
|
|
175
173
|
session
|
|
176
174
|
)
|
|
177
175
|
}
|
|
@@ -195,7 +193,8 @@ export const runChannelMessage = async (
|
|
|
195
193
|
let sessionServices: SessionServices | undefined
|
|
196
194
|
const { openingData, channelName, session } =
|
|
197
195
|
await params.channelStore.getChannelAndSession(params.channelId)
|
|
198
|
-
|
|
196
|
+
|
|
197
|
+
const { channel, channelHandler, channelConfig } = getVariablesForChannel({
|
|
199
198
|
...params,
|
|
200
199
|
openingData,
|
|
201
200
|
channelName,
|
|
@@ -203,7 +202,7 @@ export const runChannelMessage = async (
|
|
|
203
202
|
if (params.createSessionServices) {
|
|
204
203
|
sessionServices = await params.createSessionServices(
|
|
205
204
|
singletonServices,
|
|
206
|
-
{},
|
|
205
|
+
{ channel },
|
|
207
206
|
session
|
|
208
207
|
)
|
|
209
208
|
}
|
|
@@ -211,7 +210,6 @@ export const runChannelMessage = async (
|
|
|
211
210
|
try {
|
|
212
211
|
const onMessage = processMessageHandlers(
|
|
213
212
|
{ ...singletonServices, ...sessionServices },
|
|
214
|
-
session,
|
|
215
213
|
channelConfig,
|
|
216
214
|
channelHandler
|
|
217
215
|
)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { pikkuState } from '../../../pikku-state.js'
|
|
2
|
+
import { CorePikkuCLIRender } from '../cli.types.js'
|
|
3
|
+
import { generateCommandHelp, parseCLIArguments } from '../command-parser.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Default JSON renderer for CLI output
|
|
7
|
+
*/
|
|
8
|
+
const defaultJSONRenderer: CorePikkuCLIRender<any> = (_services, data) => {
|
|
9
|
+
console.log(JSON.stringify(data, null, 2))
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Execute a CLI program via WebSocket channel
|
|
14
|
+
* This is the main entry point for CLI-over-Channel clients
|
|
15
|
+
*/
|
|
16
|
+
export async function executeCLIViaChannel({
|
|
17
|
+
programName,
|
|
18
|
+
pikkuWS,
|
|
19
|
+
args = process.argv.slice(2),
|
|
20
|
+
renderers = {},
|
|
21
|
+
defaultRenderer,
|
|
22
|
+
}: {
|
|
23
|
+
programName: string
|
|
24
|
+
pikkuWS: any // CorePikkuWebsocket instance
|
|
25
|
+
args?: string[]
|
|
26
|
+
renderers?: Record<string, CorePikkuCLIRender<any>>
|
|
27
|
+
defaultRenderer?: CorePikkuCLIRender<any>
|
|
28
|
+
}): Promise<void> {
|
|
29
|
+
// Get CLI metadata from state
|
|
30
|
+
const allCLIMeta = pikkuState('cli', 'meta') || {}
|
|
31
|
+
const programMeta = allCLIMeta[programName]
|
|
32
|
+
|
|
33
|
+
if (!programMeta) {
|
|
34
|
+
console.error(`Error: CLI program "${programName}" not found`)
|
|
35
|
+
process.exit(1)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Parse arguments for this specific program
|
|
39
|
+
const parsed = parseCLIArguments(args, programName, allCLIMeta)
|
|
40
|
+
|
|
41
|
+
// Handle help (check after parsing to support subcommand help)
|
|
42
|
+
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
|
|
43
|
+
const helpText = generateCommandHelp(
|
|
44
|
+
programName,
|
|
45
|
+
allCLIMeta,
|
|
46
|
+
parsed.commandPath
|
|
47
|
+
)
|
|
48
|
+
console.log(helpText)
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (parsed.errors.length > 0) {
|
|
53
|
+
// Check if any error is about an unknown command
|
|
54
|
+
const hasUnknownCommand = parsed.errors.some(
|
|
55
|
+
(error) =>
|
|
56
|
+
error.startsWith('Unknown command:') ||
|
|
57
|
+
error.startsWith('Command not found:')
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if (hasUnknownCommand) {
|
|
61
|
+
// Show help instead of error for unknown commands
|
|
62
|
+
const helpText = generateCommandHelp(
|
|
63
|
+
programName,
|
|
64
|
+
allCLIMeta,
|
|
65
|
+
parsed.commandPath
|
|
66
|
+
)
|
|
67
|
+
console.log(helpText)
|
|
68
|
+
process.exit(1)
|
|
69
|
+
} else {
|
|
70
|
+
// Show errors for other types of errors
|
|
71
|
+
console.error('Errors:')
|
|
72
|
+
parsed.errors.forEach((error) => console.error(` ${error}`))
|
|
73
|
+
process.exit(1)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Merge positionals and options into single data object
|
|
78
|
+
const data = { ...parsed.positionals, ...parsed.options }
|
|
79
|
+
|
|
80
|
+
// Get the renderer for this command
|
|
81
|
+
const commandId = parsed.commandPath.join('.')
|
|
82
|
+
const renderer =
|
|
83
|
+
renderers[commandId] || defaultRenderer || defaultJSONRenderer
|
|
84
|
+
|
|
85
|
+
return new Promise((resolve, reject) => {
|
|
86
|
+
// Subscribe to responses for this command
|
|
87
|
+
const commandRoute = pikkuWS.getRoute('command')
|
|
88
|
+
|
|
89
|
+
const responseHandler = (response: any) => {
|
|
90
|
+
// Call renderer for any output
|
|
91
|
+
renderer(null as any, response, undefined)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
commandRoute.subscribe(commandId, responseHandler)
|
|
95
|
+
|
|
96
|
+
// Handle connection close
|
|
97
|
+
pikkuWS.ws.addEventListener('close', () => {
|
|
98
|
+
commandRoute.unsubscribe(commandId, responseHandler)
|
|
99
|
+
resolve(undefined)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
pikkuWS.ws.addEventListener('error', (error: any) => {
|
|
103
|
+
commandRoute.unsubscribe(commandId, responseHandler)
|
|
104
|
+
reject(error)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// Send the command once connected
|
|
108
|
+
if (pikkuWS.ws.readyState === 1) {
|
|
109
|
+
// Already open
|
|
110
|
+
commandRoute.send(commandId, data)
|
|
111
|
+
} else {
|
|
112
|
+
// Wait for open
|
|
113
|
+
pikkuWS.ws.addEventListener('open', () => {
|
|
114
|
+
commandRoute.send(commandId, data)
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './cli-channel-runner.js'
|