@pikku/core 0.12.63 → 0.12.66
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 +368 -0
- package/dist/dev/hot-reload.js +13 -55
- package/dist/dev/module-runner.d.ts +14 -0
- package/dist/dev/module-runner.js +59 -0
- package/dist/dev/reload-meta.d.ts +13 -0
- package/dist/dev/reload-meta.js +22 -0
- package/dist/errors/errors.d.ts +12 -0
- package/dist/errors/errors.js +19 -0
- package/dist/function/function-runner.d.ts +5 -5
- package/dist/function/function-runner.js +39 -111
- package/dist/function/functions.types.d.ts +17 -7
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/middleware/auth-apikey.d.ts +1 -0
- package/dist/middleware/auth-bearer.d.ts +1 -0
- package/dist/middleware/auth-cookie.d.ts +1 -0
- package/dist/middleware/cors.d.ts +1 -0
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/remote-auth.d.ts +1 -0
- package/dist/middleware/telemetry.d.ts +2 -0
- package/dist/middleware/timeout.d.ts +1 -0
- package/dist/permissions.d.ts +42 -27
- package/dist/permissions.js +101 -203
- package/dist/pikku-state.js +0 -2
- package/dist/scopes.d.ts +17 -0
- package/dist/scopes.js +59 -0
- package/dist/services/ai-embedding-service.d.ts +31 -0
- package/dist/services/ai-embedding-service.js +1 -0
- package/dist/services/credential-wire-service.d.ts +3 -1
- package/dist/services/credential-wire-service.js +10 -4
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.js +2 -0
- package/dist/services/meta-service.d.ts +15 -2
- package/dist/services/meta-service.js +51 -1
- package/dist/services/queue-webhook-service.d.ts +55 -0
- package/dist/services/queue-webhook-service.js +136 -0
- package/dist/services/scope-service.d.ts +67 -0
- package/dist/services/scope-service.js +1 -0
- package/dist/services/typed-secret-service.d.ts +8 -0
- package/dist/services/typed-secret-service.js +39 -4
- package/dist/services/webhook-service.d.ts +140 -0
- package/dist/services/webhook-service.js +44 -0
- package/dist/services/workflow-service.d.ts +7 -0
- package/dist/testing/service-tests.js +37 -0
- package/dist/types/core.types.d.ts +34 -6
- package/dist/types/state.types.d.ts +20 -2
- package/dist/utils/hmac.d.ts +16 -0
- package/dist/utils/hmac.js +26 -0
- package/dist/utils/safe-fetch.d.ts +51 -0
- package/dist/utils/safe-fetch.js +192 -0
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +84 -0
- package/dist/wirings/ai-agent/ai-agent-agui.js +305 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +105 -1
- package/dist/wirings/ai-agent/ai-agent-prepare.js +249 -11
- package/dist/wirings/ai-agent/ai-agent-runner.js +10 -1
- package/dist/wirings/ai-agent/ai-agent-stream.js +88 -16
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +56 -2
- package/dist/wirings/ai-agent/index.d.ts +2 -1
- package/dist/wirings/ai-agent/index.js +2 -1
- package/dist/wirings/ai-agent/voice-input.d.ts +1 -0
- package/dist/wirings/ai-agent/voice-input.js +5 -41
- package/dist/wirings/ai-agent/voice-output.d.ts +1 -0
- package/dist/wirings/channel/channel-common.js +0 -1
- package/dist/wirings/channel/channel-handler.js +1 -4
- package/dist/wirings/channel/channel-middleware-runner.d.ts +12 -0
- package/dist/wirings/channel/channel-middleware-runner.js +34 -19
- package/dist/wirings/channel/channel.types.d.ts +2 -6
- package/dist/wirings/cli/cli-runner.js +3 -2
- package/dist/wirings/cli/cli.types.d.ts +1 -2
- package/dist/wirings/cli/command-parser.d.ts +2 -0
- package/dist/wirings/cli/command-parser.js +59 -2
- package/dist/wirings/credential/credential.types.d.ts +14 -0
- package/dist/wirings/credential/validate-credential-definitions.js +1 -0
- package/dist/wirings/gateway/gateway-runner.js +100 -50
- package/dist/wirings/gateway/gateway.types.d.ts +8 -5
- package/dist/wirings/http/http-routes.js +0 -3
- package/dist/wirings/http/http-runner.d.ts +9 -29
- package/dist/wirings/http/http-runner.js +9 -34
- package/dist/wirings/http/http.types.d.ts +4 -12
- package/dist/wirings/mcp/mcp-runner.js +0 -2
- package/dist/wirings/mcp/mcp.types.d.ts +5 -11
- package/dist/wirings/oauth2/index.d.ts +0 -3
- package/dist/wirings/oauth2/index.js +1 -2
- package/dist/wirings/rpc/addon-runner.d.ts +28 -0
- package/dist/wirings/rpc/addon-runner.js +173 -0
- package/dist/wirings/rpc/index.d.ts +5 -1
- package/dist/wirings/rpc/index.js +3 -1
- package/dist/wirings/rpc/remote-addon-auth.d.ts +26 -0
- package/dist/wirings/rpc/remote-addon-auth.js +43 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +19 -0
- package/dist/wirings/rpc/rpc-runner.js +109 -3
- package/dist/wirings/rpc/rpc-types.d.ts +15 -1
- package/dist/wirings/rpc/wire-addon.js +9 -0
- package/dist/wirings/rpc/wire-remote-addon.d.ts +47 -0
- package/dist/wirings/rpc/wire-remote-addon.js +19 -0
- package/dist/wirings/scope/index.d.ts +3 -0
- package/dist/wirings/scope/index.js +2 -0
- package/dist/wirings/scope/scope.types.d.ts +39 -0
- package/dist/wirings/scope/scope.types.js +1 -0
- package/dist/wirings/scope/validate-scope-definitions.d.ts +16 -0
- package/dist/wirings/scope/validate-scope-definitions.js +76 -0
- package/dist/wirings/scope/wire-scope.d.ts +33 -0
- package/dist/wirings/scope/wire-scope.js +32 -0
- package/dist/wirings/secret/secret.types.d.ts +14 -0
- package/dist/wirings/secret/validate-secret-definitions.js +2 -0
- package/dist/wirings/variable/validate-variable-definitions.js +2 -0
- package/dist/wirings/variable/variable.types.d.ts +14 -0
- package/dist/wirings/workflow/dsl/index.d.ts +1 -1
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +89 -7
- package/dist/wirings/workflow/graph/graph-node.d.ts +2 -0
- package/dist/wirings/workflow/graph/graph-runner.js +3 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +6 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.js +1 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +5 -0
- package/dist/wirings/workflow/index.d.ts +2 -2
- package/dist/wirings/workflow/index.js +1 -1
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +59 -1
- package/dist/wirings/workflow/pikku-workflow-service.js +187 -0
- package/dist/wirings/workflow/workflow.types.d.ts +1 -3
- package/package.json +6 -1
- package/run-tests.sh +1 -0
- package/src/dev/hot-reload.ts +13 -68
- package/src/dev/module-runner.test.ts +169 -0
- package/src/dev/module-runner.ts +103 -0
- package/src/dev/reload-meta.test.ts +31 -2
- package/src/dev/reload-meta.ts +26 -0
- package/src/errors/errors.ts +24 -0
- package/src/function/function-runner.test.ts +276 -142
- package/src/function/function-runner.ts +52 -145
- package/src/function/functions.types.ts +28 -38
- package/src/index.ts +8 -6
- package/src/middleware/index.ts +1 -5
- package/src/permissions.test.ts +160 -373
- package/src/permissions.ts +137 -279
- package/src/pikku-state.ts +0 -2
- package/src/scopes.test.ts +167 -0
- package/src/scopes.ts +69 -0
- package/src/services/ai-embedding-service.ts +31 -0
- package/src/services/credential-wire-service.ts +10 -4
- package/src/services/index.ts +20 -0
- package/src/services/meta-service.ts +68 -3
- package/src/services/queue-webhook-service.test.ts +408 -0
- package/src/services/queue-webhook-service.ts +182 -0
- package/src/services/scope-service.ts +75 -0
- package/src/services/typed-secret-service.test.ts +35 -0
- package/src/services/typed-secret-service.ts +39 -4
- package/src/services/webhook-service.ts +180 -0
- package/src/services/workflow-service.ts +7 -0
- package/src/testing/service-tests.ts +49 -0
- package/src/types/core.types.ts +42 -14
- package/src/types/state.types.ts +23 -3
- package/src/utils/hmac.ts +27 -0
- package/src/utils/safe-fetch.test.ts +373 -0
- package/src/utils/safe-fetch.ts +213 -0
- package/src/wirings/ai-agent/ai-agent-agui.test.ts +1127 -0
- package/src/wirings/ai-agent/ai-agent-agui.ts +386 -0
- package/src/wirings/ai-agent/ai-agent-authorization.test.ts +204 -0
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +483 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +324 -13
- package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +207 -0
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +48 -1
- package/src/wirings/ai-agent/ai-agent-runner.ts +28 -0
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +301 -10
- package/src/wirings/ai-agent/ai-agent-stream.ts +122 -16
- package/src/wirings/ai-agent/ai-agent.types.ts +57 -0
- package/src/wirings/ai-agent/index.ts +5 -0
- package/src/wirings/ai-agent/voice-input.test.ts +90 -0
- package/src/wirings/ai-agent/voice-input.ts +9 -40
- package/src/wirings/channel/channel-common.ts +0 -1
- package/src/wirings/channel/channel-handler.ts +1 -9
- package/src/wirings/channel/channel-middleware-runner.test.ts +28 -2
- package/src/wirings/channel/channel-middleware-runner.ts +39 -27
- package/src/wirings/channel/channel.types.ts +0 -6
- package/src/wirings/cli/cli-runner.ts +4 -2
- package/src/wirings/cli/cli.types.ts +0 -2
- package/src/wirings/cli/command-parser.test.ts +130 -0
- package/src/wirings/cli/command-parser.ts +80 -2
- package/src/wirings/credential/credential.types.ts +14 -0
- package/src/wirings/credential/validate-credential-definitions.ts +1 -0
- package/src/wirings/gateway/gateway-authorization.test.ts +444 -0
- package/src/wirings/gateway/gateway-runner.ts +114 -68
- package/src/wirings/gateway/gateway.types.ts +7 -9
- package/src/wirings/http/http-routes.ts +0 -3
- package/src/wirings/http/http-runner.test.ts +1 -11
- package/src/wirings/http/http-runner.ts +16 -39
- package/src/wirings/http/http.types.ts +7 -14
- package/src/wirings/mcp/mcp-runner.ts +0 -2
- package/src/wirings/mcp/mcp.types.ts +3 -11
- package/src/wirings/oauth2/index.ts +0 -3
- package/src/wirings/rpc/addon-runner.ts +233 -0
- package/src/wirings/rpc/index.ts +17 -1
- package/src/wirings/rpc/remote-addon-auth.ts +69 -0
- package/src/wirings/rpc/rpc-runner.test.ts +319 -16
- package/src/wirings/rpc/rpc-runner.ts +155 -3
- package/src/wirings/rpc/rpc-types.ts +16 -5
- package/src/wirings/rpc/wire-addon.test.ts +6 -3
- package/src/wirings/rpc/wire-addon.ts +9 -0
- package/src/wirings/rpc/wire-remote-addon.ts +57 -0
- package/src/wirings/scope/index.ts +14 -0
- package/src/wirings/scope/scope.test.ts +135 -0
- package/src/wirings/scope/scope.types.ts +44 -0
- package/src/wirings/scope/validate-scope-definitions.ts +110 -0
- package/src/wirings/scope/wire-scope.ts +34 -0
- package/src/wirings/secret/secret.types.ts +14 -0
- package/src/wirings/secret/validate-secret-definitions.ts +2 -0
- package/src/wirings/variable/validate-variable-definitions.ts +2 -0
- package/src/wirings/variable/variable.types.ts +14 -0
- package/src/wirings/workflow/dsl/index.ts +4 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +97 -6
- package/src/wirings/workflow/graph/graph-node.ts +2 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +58 -0
- package/src/wirings/workflow/graph/graph-runner.ts +3 -0
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +7 -0
- package/src/wirings/workflow/graph/workflow-graph.types.ts +5 -0
- package/src/wirings/workflow/index.ts +5 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +341 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +272 -0
- package/src/wirings/workflow/workflow-on-error.test.ts +154 -0
- package/src/wirings/workflow/workflow-step-session.test.ts +21 -5
- package/src/wirings/workflow/workflow.types.ts +4 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/src/wirings/oauth2/oauth2-client.test.ts +0 -930
- package/src/wirings/oauth2/oauth2-client.ts +0 -331
- package/src/wirings/oauth2/oauth2-routes.ts +0 -234
|
@@ -100,6 +100,19 @@ export interface AIAgentOutput {
|
|
|
100
100
|
runId: string;
|
|
101
101
|
}>;
|
|
102
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* How an agent's threads/runs are owned and partitioned.
|
|
105
|
+
* - `'user'` (default): owner is the authenticated `session.userId`; the caller's
|
|
106
|
+
* `resourceId` becomes a sub-partition within that user (`userId:resourceId`).
|
|
107
|
+
* - `'org'`: owner is the authenticated `session.orgId` (`orgId:resourceId`), so
|
|
108
|
+
* threads are shared across everyone in the org. Requires a session with an org
|
|
109
|
+
* (e.g. Better Auth's `organization` plugin) — otherwise access is denied.
|
|
110
|
+
*
|
|
111
|
+
* The trusted principal is always the prefix, so a client-supplied `resourceId`
|
|
112
|
+
* can sub-divide within the caller's own boundary but can never widen access to
|
|
113
|
+
* another user's or org's threads.
|
|
114
|
+
*/
|
|
115
|
+
export type SessionScope = 'user' | 'org';
|
|
103
116
|
export interface AIAgentToolDef {
|
|
104
117
|
name: string;
|
|
105
118
|
description: string;
|
|
@@ -107,6 +120,14 @@ export interface AIAgentToolDef {
|
|
|
107
120
|
execute: (input: unknown) => Promise<unknown>;
|
|
108
121
|
needsApproval?: boolean;
|
|
109
122
|
approvalDescriptionFn?: (input: unknown) => Promise<string>;
|
|
123
|
+
/**
|
|
124
|
+
* Set only by the framework on sub-agent delegating tools. Such a tool may
|
|
125
|
+
* legitimately return an `__approvalRequired` marker to forward a nested
|
|
126
|
+
* sub-agent approval. The marker is honored ONLY from a tool with this flag —
|
|
127
|
+
* a plain tool's output (which an attacker may influence) can never forge an
|
|
128
|
+
* approval request. See `checkForApprovals`.
|
|
129
|
+
*/
|
|
130
|
+
forwardsApproval?: boolean;
|
|
110
131
|
}
|
|
111
132
|
export interface PikkuAIMiddlewareHooks<State extends Record<string, unknown> = Record<string, unknown>, Services = any> {
|
|
112
133
|
modifyInput?: (services: Services, ctx: {
|
|
@@ -190,7 +211,7 @@ export type AIAgentMemoryConfig = {
|
|
|
190
211
|
lastMessages?: number;
|
|
191
212
|
workingMemory?: unknown;
|
|
192
213
|
};
|
|
193
|
-
export type CoreAIAgent<PikkuPermission = CorePikkuPermission<any, any>, PikkuMiddleware = CorePikkuMiddleware<any
|
|
214
|
+
export type CoreAIAgent<PikkuPermission = CorePikkuPermission<any, any>, PikkuMiddleware = CorePikkuMiddleware<any>, Scope extends string = string> = {
|
|
194
215
|
name: string;
|
|
195
216
|
description: string;
|
|
196
217
|
summary?: string;
|
|
@@ -200,8 +221,11 @@ export type CoreAIAgent<PikkuPermission = CorePikkuPermission<any, any>, PikkuMi
|
|
|
200
221
|
goal: string;
|
|
201
222
|
model: string;
|
|
202
223
|
temperature?: number;
|
|
224
|
+
/** Ownership/partitioning of this agent's threads and runs. Defaults to `'user'`. */
|
|
225
|
+
sessionScope?: SessionScope;
|
|
203
226
|
tools?: unknown[];
|
|
204
227
|
agents?: unknown[];
|
|
228
|
+
workflows?: unknown[];
|
|
205
229
|
agentMode?: 'delegate' | 'supervise';
|
|
206
230
|
memory?: AIAgentMemoryConfig;
|
|
207
231
|
maxSteps?: number;
|
|
@@ -220,6 +244,23 @@ export type CoreAIAgent<PikkuPermission = CorePikkuPermission<any, any>, PikkuMi
|
|
|
220
244
|
middleware?: PikkuMiddleware[];
|
|
221
245
|
channelMiddleware?: CorePikkuChannelMiddleware<any, any>[];
|
|
222
246
|
aiMiddleware?: PikkuAIMiddlewareHooks<any, any>[];
|
|
247
|
+
/**
|
|
248
|
+
* Whether a session is required to run this agent. Defaults to `false`, since
|
|
249
|
+
* agents are commonly invoked from an already-authenticated `pikkuFunc` or
|
|
250
|
+
* from genuinely sessionless contexts (crons, queue workers). Set `true` to
|
|
251
|
+
* require a session at the agent itself. `scopes` and `permissions` are
|
|
252
|
+
* enforced either way.
|
|
253
|
+
*/
|
|
254
|
+
auth?: boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Scopes the session must hold to run this agent. All of them are required
|
|
257
|
+
* (AND), and they are checked before `permissions` — unlike permissions,
|
|
258
|
+
* which OR together, a scope can only narrow access.
|
|
259
|
+
*
|
|
260
|
+
* Narrowed to the generated `ScopeId` union in a project's own
|
|
261
|
+
* `pikku-types.gen.ts`, so an undeclared scope is a compile error.
|
|
262
|
+
*/
|
|
263
|
+
scopes?: Scope[];
|
|
223
264
|
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
224
265
|
};
|
|
225
266
|
export type AIStreamEvent = {
|
|
@@ -267,6 +308,7 @@ export type AIStreamEvent = {
|
|
|
267
308
|
toolName: string;
|
|
268
309
|
args: unknown;
|
|
269
310
|
reason?: string;
|
|
311
|
+
runId?: string;
|
|
270
312
|
agent?: string;
|
|
271
313
|
session?: string;
|
|
272
314
|
} | {
|
|
@@ -388,6 +430,17 @@ export interface AgentRunService {
|
|
|
388
430
|
listThreads(options?: {
|
|
389
431
|
agentName?: string;
|
|
390
432
|
resourceId?: string;
|
|
433
|
+
/**
|
|
434
|
+
* Restrict results to threads owned by one of these session principals. A
|
|
435
|
+
* thread matches when its `resourceId` is the principal itself or one of its
|
|
436
|
+
* `principal:` sub-partitions, mirroring the composition
|
|
437
|
+
* `resolveOwnerResourceId` writes.
|
|
438
|
+
*
|
|
439
|
+
* Unlike `resourceId`, which is an optional exact-match filter, this is an
|
|
440
|
+
* authorization constraint: an empty array matches nothing. Callers exposing
|
|
441
|
+
* threads over the wire must derive it from the session, never from input.
|
|
442
|
+
*/
|
|
443
|
+
owners?: string[];
|
|
391
444
|
limit?: number;
|
|
392
445
|
offset?: number;
|
|
393
446
|
}): Promise<AIThread[]>;
|
|
@@ -397,9 +450,10 @@ export interface AgentRunService {
|
|
|
397
450
|
deleteThread(threadId: string): Promise<boolean>;
|
|
398
451
|
getDistinctAgentNames(): Promise<string[]>;
|
|
399
452
|
}
|
|
400
|
-
export type AIAgentMeta = Record<string, Omit<CoreAIAgent, 'input' | 'output' | 'tools' | 'agents' | 'middleware' | 'channelMiddleware' | 'aiMiddleware' | 'permissions'> & {
|
|
453
|
+
export type AIAgentMeta = Record<string, Omit<CoreAIAgent, 'input' | 'output' | 'tools' | 'agents' | 'workflows' | 'middleware' | 'channelMiddleware' | 'aiMiddleware' | 'permissions'> & {
|
|
401
454
|
tools?: string[];
|
|
402
455
|
agents?: string[];
|
|
456
|
+
workflows?: string[];
|
|
403
457
|
inputSchema: string | null;
|
|
404
458
|
outputSchema: string | null;
|
|
405
459
|
workingMemorySchema: string | null;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { agent, agentStream, agentResume, agentApprove, } from './ai-agent-helpers.js';
|
|
2
|
+
export { wrapChannelWithAGUI, type AGUIEvent } from './ai-agent-agui.js';
|
|
2
3
|
export { runAIAgent, resumeAIAgentSync } from './ai-agent-runner.js';
|
|
3
4
|
export { streamAIAgent, resumeAIAgent } from './ai-agent-stream.js';
|
|
4
5
|
export { voiceInput } from './voice-input.js';
|
|
5
6
|
export { voiceOutput } from './voice-output.js';
|
|
6
|
-
export { type RunAIAgentParams, type StreamAIAgentOptions, ToolApprovalRequired, ToolCredentialRequired, } from './ai-agent-prepare.js';
|
|
7
|
+
export { type RunAIAgentParams, type StreamAIAgentOptions, ToolApprovalRequired, ToolCredentialRequired, canAccessThread, isOwnedByPrincipal, sessionPrincipals, threadOwnerConstraint, } from './ai-agent-prepare.js';
|
|
7
8
|
export { addAIAgent, approveAIAgent, getAIAgents, getAIAgentsMeta, } from './ai-agent-registry.js';
|
|
8
9
|
export type { AIAgentInput, AIAgentInputAttachment, AIAgentMeta, AIAgentMemoryConfig, AIAgentStep, AIContentPart, AgentRunRow, AgentRunService, AgentRunState, AIMessage, AIStreamChannel, AIStreamEvent, AIThread, CoreAIAgent, PendingApproval, PikkuAIMiddlewareHooks, } from './ai-agent.types.js';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { agent, agentStream, agentResume, agentApprove, } from './ai-agent-helpers.js';
|
|
2
|
+
export { wrapChannelWithAGUI } from './ai-agent-agui.js';
|
|
2
3
|
export { runAIAgent, resumeAIAgentSync } from './ai-agent-runner.js';
|
|
3
4
|
export { streamAIAgent, resumeAIAgent } from './ai-agent-stream.js';
|
|
4
5
|
export { voiceInput } from './voice-input.js';
|
|
5
6
|
export { voiceOutput } from './voice-output.js';
|
|
6
|
-
export { ToolApprovalRequired, ToolCredentialRequired, } from './ai-agent-prepare.js';
|
|
7
|
+
export { ToolApprovalRequired, ToolCredentialRequired, canAccessThread, isOwnedByPrincipal, sessionPrincipals, threadOwnerConstraint, } from './ai-agent-prepare.js';
|
|
7
8
|
export { addAIAgent, approveAIAgent, getAIAgents, getAIAgentsMeta, } from './ai-agent-registry.js';
|
|
@@ -6,5 +6,6 @@ export declare const voiceInput: (config?: {
|
|
|
6
6
|
logLevel?: import("../../services/logger.js").LogLevel;
|
|
7
7
|
secrets?: {};
|
|
8
8
|
workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
|
|
9
|
+
webhook?: import("../../services/webhook-service.js").WebhookServiceConfig;
|
|
9
10
|
postgres?: import("../../types/core.types.js").PostgresConfig;
|
|
10
11
|
}>>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { pikkuAIMiddleware } from '../../types/core.types.js';
|
|
2
|
+
import { safeFetch } from '../../utils/safe-fetch.js';
|
|
2
3
|
function base64ToUint8Array(base64) {
|
|
3
4
|
const binary = atob(base64);
|
|
4
5
|
const bytes = new Uint8Array(binary.length);
|
|
@@ -8,45 +9,8 @@ function base64ToUint8Array(base64) {
|
|
|
8
9
|
return bytes;
|
|
9
10
|
}
|
|
10
11
|
const MAX_AUDIO_SIZE = 50 * 1024 * 1024;
|
|
11
|
-
// Portable SSRF guard: @pikku/core runs in edge runtimes (CF Workers) with no
|
|
12
|
-
// Node `dns`, so we cannot resolve hostnames to check for private targets.
|
|
13
|
-
// Reject the obvious internal literals; callers wanting stricter control pass
|
|
14
|
-
// an explicit `allowedAudioHosts` allowlist. (Does not defend against a public
|
|
15
|
-
// hostname that resolves to a private IP / DNS rebinding — out of reach here.)
|
|
16
|
-
function isPrivateHost(hostname) {
|
|
17
|
-
const host = hostname.replace(/^\[|\]$/g, '').toLowerCase();
|
|
18
|
-
if (host === 'localhost' || host === '0.0.0.0' || host === '::1')
|
|
19
|
-
return true;
|
|
20
|
-
if (host.startsWith('fe80:') || host.startsWith('fc') || host.startsWith('fd'))
|
|
21
|
-
return true;
|
|
22
|
-
const v4 = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.\d{1,3}$/);
|
|
23
|
-
if (v4) {
|
|
24
|
-
const [a, b] = [Number(v4[1]), Number(v4[2])];
|
|
25
|
-
if (a === 127 || a === 10 || a === 0)
|
|
26
|
-
return true;
|
|
27
|
-
if (a === 169 && b === 254)
|
|
28
|
-
return true; // link-local incl. cloud metadata
|
|
29
|
-
if (a === 172 && b >= 16 && b <= 31)
|
|
30
|
-
return true;
|
|
31
|
-
if (a === 192 && b === 168)
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
12
|
async function fetchAsUint8Array(url, allowedAudioHosts) {
|
|
37
|
-
const
|
|
38
|
-
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
39
|
-
throw new Error('Only HTTP(S) URLs are supported for audio');
|
|
40
|
-
}
|
|
41
|
-
if (allowedAudioHosts) {
|
|
42
|
-
if (!allowedAudioHosts.includes(parsed.hostname)) {
|
|
43
|
-
throw new Error(`Audio URL host is not allowed: ${parsed.hostname}`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
else if (isPrivateHost(parsed.hostname)) {
|
|
47
|
-
throw new Error(`Refusing to fetch audio from a private/internal host: ${parsed.hostname}`);
|
|
48
|
-
}
|
|
49
|
-
const response = await fetch(url);
|
|
13
|
+
const response = await safeFetch(url, {}, { allowedHosts: allowedAudioHosts });
|
|
50
14
|
const contentLength = response.headers.get('content-length');
|
|
51
15
|
if (contentLength && parseInt(contentLength, 10) > MAX_AUDIO_SIZE) {
|
|
52
16
|
throw new Error('Audio file exceeds maximum size');
|
|
@@ -59,8 +23,8 @@ async function fetchAsUint8Array(url, allowedAudioHosts) {
|
|
|
59
23
|
}
|
|
60
24
|
export const voiceInput = (config) => pikkuAIMiddleware({
|
|
61
25
|
modifyInput: async (services, { messages, instructions }) => {
|
|
62
|
-
const
|
|
63
|
-
if (!
|
|
26
|
+
const aiAgentRunner = services.aiAgentRunner;
|
|
27
|
+
if (!aiAgentRunner?.transcribe)
|
|
64
28
|
return { messages, instructions };
|
|
65
29
|
const last = messages[messages.length - 1];
|
|
66
30
|
if (!last || last.role !== 'user' || typeof last.content === 'string') {
|
|
@@ -87,7 +51,7 @@ export const voiceInput = (config) => pikkuAIMiddleware({
|
|
|
87
51
|
const audioData = p.data
|
|
88
52
|
? base64ToUint8Array(p.data)
|
|
89
53
|
: await fetchAsUint8Array(p.url, config.allowedAudioHosts);
|
|
90
|
-
const result = await
|
|
54
|
+
const result = await aiAgentRunner.transcribe({
|
|
91
55
|
model: config.model,
|
|
92
56
|
audio: audioData,
|
|
93
57
|
...(config.language
|
|
@@ -12,6 +12,7 @@ export declare const voiceOutput: (config?: {
|
|
|
12
12
|
logLevel?: import("../../services/logger.js").LogLevel;
|
|
13
13
|
secrets?: {};
|
|
14
14
|
workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
|
|
15
|
+
webhook?: import("../../services/webhook-service.js").WebhookServiceConfig;
|
|
15
16
|
postgres?: import("../../types/core.types.js").PostgresConfig;
|
|
16
17
|
}>>;
|
|
17
18
|
export {};
|
|
@@ -49,7 +49,7 @@ export const processMessageHandlers = (services, channelConfig, channelHandler,
|
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
const routeMeta = getRouteMeta(channelConfig.name, routingProperty, routerValue);
|
|
52
|
-
const { packageName, middleware: routeInheritedMiddleware
|
|
52
|
+
const { packageName, middleware: routeInheritedMiddleware } = routeMeta;
|
|
53
53
|
const pikkuFuncId = routeMeta.pikkuFuncId;
|
|
54
54
|
// Get wire middleware: channel-level middleware + message-specific middleware
|
|
55
55
|
const channelWireMiddleware = channelConfig.middleware || [];
|
|
@@ -68,7 +68,6 @@ export const processMessageHandlers = (services, channelConfig, channelHandler,
|
|
|
68
68
|
const wireMiddleware = [...channelWireMiddleware, ...messageWireMiddleware];
|
|
69
69
|
// Inherited middleware comes from metadata (tag groups, non-inline wire)
|
|
70
70
|
const inheritedMiddleware = routeInheritedMiddleware || [];
|
|
71
|
-
const wirePermissions = isWrapper ? onMessage.permissions : undefined;
|
|
72
71
|
// Create unique cache key that includes routing info to avoid cache collisions
|
|
73
72
|
// when multiple message handlers use the same function
|
|
74
73
|
const cacheKey = routingProperty
|
|
@@ -83,8 +82,6 @@ export const processMessageHandlers = (services, channelConfig, channelHandler,
|
|
|
83
82
|
wireMiddleware,
|
|
84
83
|
inheritedChannelMiddleware: channelMeta?.channelMiddleware,
|
|
85
84
|
wireChannelMiddleware: wireChannelMiddleware,
|
|
86
|
-
inheritedPermissions,
|
|
87
|
-
wirePermissions,
|
|
88
85
|
coerceDataFromSchema: true,
|
|
89
86
|
tags: channelConfig.tags,
|
|
90
87
|
sessionService: userSession,
|
|
@@ -2,6 +2,18 @@ import type { CoreSingletonServices, MiddlewareMetadata, PikkuRawWire } from '..
|
|
|
2
2
|
import type { CorePikkuChannelMiddleware } from './channel.types.js';
|
|
3
3
|
export declare const addChannelMiddleware: (tag: string, middleware: CorePikkuChannelMiddleware[], packageName?: string | null) => CorePikkuChannelMiddleware[];
|
|
4
4
|
export declare const clearChannelMiddlewareCache: () => void;
|
|
5
|
+
/**
|
|
6
|
+
* Combine the inherited (tag/named) channel middleware with any per-run
|
|
7
|
+
* middleware for a wiring.
|
|
8
|
+
*
|
|
9
|
+
* Only the statically-resolved inherited middleware is deterministic per `uid`
|
|
10
|
+
* and safe to cache. `wireChannelMiddleware` is a per-run set of closures (e.g.
|
|
11
|
+
* an AI agent's per-invocation stream middleware holding that run's
|
|
12
|
+
* thread/session state) and MUST NOT be cached — caching it lets a later run of
|
|
13
|
+
* the same `uid` reuse an earlier run's closures, leaking that run's state (and
|
|
14
|
+
* growing memory) across invocations. It is therefore appended fresh on every
|
|
15
|
+
* call after the cached inherited slice.
|
|
16
|
+
*/
|
|
5
17
|
export declare const combineChannelMiddleware: (wireType: string, uid: string, { wireInheritedChannelMiddleware, wireChannelMiddleware, packageName, }?: {
|
|
6
18
|
wireInheritedChannelMiddleware?: MiddlewareMetadata[];
|
|
7
19
|
wireChannelMiddleware?: CorePikkuChannelMiddleware[];
|
|
@@ -16,33 +16,48 @@ export const clearChannelMiddlewareCache = () => {
|
|
|
16
16
|
delete channelMiddlewareCache[key];
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* Combine the inherited (tag/named) channel middleware with any per-run
|
|
21
|
+
* middleware for a wiring.
|
|
22
|
+
*
|
|
23
|
+
* Only the statically-resolved inherited middleware is deterministic per `uid`
|
|
24
|
+
* and safe to cache. `wireChannelMiddleware` is a per-run set of closures (e.g.
|
|
25
|
+
* an AI agent's per-invocation stream middleware holding that run's
|
|
26
|
+
* thread/session state) and MUST NOT be cached — caching it lets a later run of
|
|
27
|
+
* the same `uid` reuse an earlier run's closures, leaking that run's state (and
|
|
28
|
+
* growing memory) across invocations. It is therefore appended fresh on every
|
|
29
|
+
* call after the cached inherited slice.
|
|
30
|
+
*/
|
|
19
31
|
export const combineChannelMiddleware = (wireType, uid, { wireInheritedChannelMiddleware, wireChannelMiddleware, packageName = null, } = {}) => {
|
|
20
32
|
const cacheKey = `${wireType}:${uid}`;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
let inherited = channelMiddlewareCache[cacheKey];
|
|
34
|
+
if (!inherited) {
|
|
35
|
+
const resolved = [];
|
|
36
|
+
if (wireInheritedChannelMiddleware) {
|
|
37
|
+
for (const meta of wireInheritedChannelMiddleware) {
|
|
38
|
+
if (meta.type === 'tag') {
|
|
39
|
+
const groups = getTagGroups(pikkuState(packageName, 'channelMiddleware', 'tagGroup'), meta.tag);
|
|
40
|
+
for (const group of groups) {
|
|
41
|
+
resolved.push(...group);
|
|
42
|
+
}
|
|
31
43
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
else if (meta.type === 'wire') {
|
|
45
|
+
const middleware = getChannelMiddlewareByName(meta.name);
|
|
46
|
+
if (middleware) {
|
|
47
|
+
resolved.push(middleware);
|
|
48
|
+
}
|
|
37
49
|
}
|
|
38
50
|
}
|
|
39
51
|
}
|
|
52
|
+
inherited = channelMiddlewareCache[cacheKey] = freezeDedupe(resolved);
|
|
40
53
|
}
|
|
41
|
-
if (wireChannelMiddleware) {
|
|
42
|
-
|
|
54
|
+
if (!wireChannelMiddleware?.length) {
|
|
55
|
+
return inherited;
|
|
43
56
|
}
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
return freezeDedupe([
|
|
58
|
+
...inherited,
|
|
59
|
+
...wireChannelMiddleware,
|
|
60
|
+
]);
|
|
46
61
|
};
|
|
47
62
|
export function wrapChannelWithMiddleware(wire, services, middlewares) {
|
|
48
63
|
if (middlewares.length === 0 || !wire.channel)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { HTTPFunctionMetaInputTypes, PikkuHTTPRequest, PikkuHTTPResponse } from '../http/http.types.js';
|
|
2
|
-
import type { CorePikkuMiddleware, MiddlewareMetadata
|
|
2
|
+
import type { CorePikkuMiddleware, MiddlewareMetadata } from '../../types/core.types.js';
|
|
3
3
|
export type BinaryData = ArrayBuffer | Uint8Array;
|
|
4
4
|
export type CorePikkuChannelMiddleware<Services = any, Event = unknown> = (services: Services, event: Event, next: (event: Event | Event[] | null) => Promise<void> | void) => Promise<void> | void;
|
|
5
5
|
export type CorePikkuChannelMiddlewareFactory<In = any, Services = any, Event = unknown> = (input: In) => CorePikkuChannelMiddleware<Services, Event>;
|
|
6
|
-
import type {
|
|
6
|
+
import type { CorePikkuFunction, CorePikkuFunctionConfig, CorePikkuFunctionSessionless, CorePikkuPermission } from '../../function/functions.types.js';
|
|
7
7
|
export type RunChannelOptions = Partial<{
|
|
8
8
|
skipUserSession: boolean;
|
|
9
9
|
respondWith404: boolean;
|
|
@@ -24,7 +24,6 @@ export interface ChannelMessageMeta {
|
|
|
24
24
|
errors?: string[];
|
|
25
25
|
tags?: string[];
|
|
26
26
|
middleware?: MiddlewareMetadata[];
|
|
27
|
-
permissions?: PermissionMetadata[];
|
|
28
27
|
}
|
|
29
28
|
export interface ChannelMeta {
|
|
30
29
|
name: string;
|
|
@@ -43,7 +42,6 @@ export interface ChannelMeta {
|
|
|
43
42
|
errors?: string[];
|
|
44
43
|
tags?: string[];
|
|
45
44
|
middleware?: MiddlewareMetadata[];
|
|
46
|
-
permissions?: PermissionMetadata[];
|
|
47
45
|
channelMiddleware?: MiddlewareMetadata[];
|
|
48
46
|
}
|
|
49
47
|
export type ChannelsMeta = Record<string, ChannelMeta>;
|
|
@@ -61,13 +59,11 @@ export type CoreChannel<ChannelData, Channel extends string, ChannelConnect = Co
|
|
|
61
59
|
onMessage?: ChannelFunctionMessage;
|
|
62
60
|
onMessageWiring?: Record<string, Record<string, ChannelFunctionMessage | {
|
|
63
61
|
func: ChannelFunctionMessage;
|
|
64
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
65
62
|
auth?: boolean;
|
|
66
63
|
middleware?: PikkuMiddleware[];
|
|
67
64
|
}>>;
|
|
68
65
|
middleware?: PikkuMiddleware[];
|
|
69
66
|
channelMiddleware?: Array<CorePikkuChannelMiddleware | CorePikkuChannelMiddlewareFactory>;
|
|
70
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
71
67
|
auth?: boolean;
|
|
72
68
|
binary?: boolean | null;
|
|
73
69
|
onBinaryMessage?: (services: any, data: BinaryData, channel: PikkuChannel<ChannelData, any>) => Promise<BinaryData | void> | BinaryData | void;
|
|
@@ -253,8 +253,6 @@ export async function runCLICommand({ program, commandPath, data, singletonServi
|
|
|
253
253
|
auth: false,
|
|
254
254
|
inheritedMiddleware: currentCommand.middleware,
|
|
255
255
|
wireMiddleware: allWireMiddleware,
|
|
256
|
-
inheritedPermissions: currentCommand.permissions,
|
|
257
|
-
wirePermissions: undefined,
|
|
258
256
|
coerceDataFromSchema: true,
|
|
259
257
|
tags: programData?.tags,
|
|
260
258
|
wire,
|
|
@@ -321,6 +319,9 @@ export async function executeCLI({ programName, args, createConfig, createSingle
|
|
|
321
319
|
console.log(helpText);
|
|
322
320
|
return;
|
|
323
321
|
}
|
|
322
|
+
// Non-fatal diagnostics (unknown options are still accepted) go to stderr
|
|
323
|
+
// so they never pollute a command's machine-readable stdout.
|
|
324
|
+
parsed.warnings.forEach((warning) => console.error(`Warning: ${warning}`));
|
|
324
325
|
if (parsed.errors.length > 0) {
|
|
325
326
|
// Check if any error is about an unknown command
|
|
326
327
|
const hasUnknownCommand = parsed.errors.some((error) => error.startsWith('Unknown command:') ||
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CorePikkuMiddleware, CoreSingletonServices, CoreUserSession, CoreServices, MiddlewareMetadata
|
|
1
|
+
import type { CorePikkuMiddleware, CoreSingletonServices, CoreUserSession, CoreServices, MiddlewareMetadata } from '../../types/core.types.js';
|
|
2
2
|
import type { CorePikkuFunctionConfig, CorePikkuPermission, CorePikkuFunction, CorePikkuFunctionSessionless } from '../../function/functions.types.js';
|
|
3
3
|
import type { PikkuChannel } from '../channel/channel.types.js';
|
|
4
4
|
/**
|
|
@@ -62,7 +62,6 @@ export interface CLICommandMeta {
|
|
|
62
62
|
tags?: string[];
|
|
63
63
|
subcommands?: Record<string, CLICommandMeta>;
|
|
64
64
|
middleware?: MiddlewareMetadata[];
|
|
65
|
-
permissions?: PermissionMetadata[];
|
|
66
65
|
isDefault?: boolean;
|
|
67
66
|
}
|
|
68
67
|
/**
|
|
@@ -8,6 +8,8 @@ export interface ParsedCommand {
|
|
|
8
8
|
positionals: Record<string, any>;
|
|
9
9
|
options: Record<string, any>;
|
|
10
10
|
errors: string[];
|
|
11
|
+
/** Non-fatal diagnostics (e.g. unknown options that were accepted+ignored) */
|
|
12
|
+
warnings: string[];
|
|
11
13
|
}
|
|
12
14
|
/**
|
|
13
15
|
* Parses raw CLI arguments into structured data for a specific program
|
|
@@ -8,6 +8,54 @@ function toCamelCase(str) {
|
|
|
8
8
|
function toKebabCase(str) {
|
|
9
9
|
return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
10
10
|
}
|
|
11
|
+
/** Options the runner handles itself — never reported as unknown. */
|
|
12
|
+
const RESERVED_OPTIONS = new Set(['help']);
|
|
13
|
+
/** Levenshtein distance, capped-free and dependency-free. Used only to suggest
|
|
14
|
+
* a near-miss option name, so the naive O(n*m) implementation is fine. */
|
|
15
|
+
function levenshtein(a, b) {
|
|
16
|
+
if (a === b)
|
|
17
|
+
return 0;
|
|
18
|
+
if (a.length === 0)
|
|
19
|
+
return b.length;
|
|
20
|
+
if (b.length === 0)
|
|
21
|
+
return a.length;
|
|
22
|
+
let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
23
|
+
for (let i = 1; i <= a.length; i++) {
|
|
24
|
+
const row = [i];
|
|
25
|
+
for (let j = 1; j <= b.length; j++) {
|
|
26
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
27
|
+
row[j] = Math.min(row[j - 1] + 1, prev[j] + 1, prev[j - 1] + cost);
|
|
28
|
+
}
|
|
29
|
+
prev = row;
|
|
30
|
+
}
|
|
31
|
+
return prev[b.length];
|
|
32
|
+
}
|
|
33
|
+
/** Finds the closest declared option (distance <= 2) to what the user typed.
|
|
34
|
+
* Compares against the kebab-case rendering, since that is what is typed. */
|
|
35
|
+
function suggestOption(typed, availableOptions) {
|
|
36
|
+
let best = null;
|
|
37
|
+
let bestDistance = 3;
|
|
38
|
+
for (const name of Object.keys(availableOptions)) {
|
|
39
|
+
const kebab = toKebabCase(name);
|
|
40
|
+
const distance = Math.min(levenshtein(typed, kebab), levenshtein(typed, name));
|
|
41
|
+
if (distance < bestDistance) {
|
|
42
|
+
bestDistance = distance;
|
|
43
|
+
best = kebab;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return best;
|
|
47
|
+
}
|
|
48
|
+
/** Records a warning that an unknown long option was accepted but ignored.
|
|
49
|
+
* Unknown options stay non-fatal for forward compatibility (a newer command
|
|
50
|
+
* version may understand them) — they are just no longer silent. */
|
|
51
|
+
function warnUnknownOption(typed, availableOptions, result) {
|
|
52
|
+
if (RESERVED_OPTIONS.has(toCamelCase(typed))) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const suggestion = suggestOption(typed, availableOptions);
|
|
56
|
+
result.warnings.push(`Unknown option: --${typed} (ignored)` +
|
|
57
|
+
(suggestion ? ` Did you mean --${suggestion}?` : ''));
|
|
58
|
+
}
|
|
11
59
|
/**
|
|
12
60
|
* Parses raw CLI arguments into structured data for a specific program
|
|
13
61
|
*/
|
|
@@ -18,6 +66,7 @@ export function parseCLIArguments(args, programName, allMeta) {
|
|
|
18
66
|
positionals: {},
|
|
19
67
|
options: {},
|
|
20
68
|
errors: [],
|
|
69
|
+
warnings: [],
|
|
21
70
|
};
|
|
22
71
|
const meta = allMeta.programs[programName];
|
|
23
72
|
if (!meta) {
|
|
@@ -106,7 +155,11 @@ export function parseCLIArguments(args, programName, allMeta) {
|
|
|
106
155
|
// --option=value format
|
|
107
156
|
const key = toCamelCase(arg.slice(2, equalIndex));
|
|
108
157
|
const optionDef = availableOptions[key];
|
|
109
|
-
// Unknown options are allowed for forward compatibility
|
|
158
|
+
// Unknown options are allowed for forward compatibility, but warned
|
|
159
|
+
// about so they are not silently dropped by the input schema.
|
|
160
|
+
if (!optionDef) {
|
|
161
|
+
warnUnknownOption(arg.slice(2, equalIndex), availableOptions, result);
|
|
162
|
+
}
|
|
110
163
|
const value = arg.slice(equalIndex + 1);
|
|
111
164
|
optionArgs[key] = parseOptionValue(value, optionDef);
|
|
112
165
|
}
|
|
@@ -114,7 +167,11 @@ export function parseCLIArguments(args, programName, allMeta) {
|
|
|
114
167
|
// --option value format
|
|
115
168
|
const key = toCamelCase(arg.slice(2));
|
|
116
169
|
const optionDef = availableOptions[key];
|
|
117
|
-
// Unknown options are allowed for forward compatibility
|
|
170
|
+
// Unknown options are allowed for forward compatibility, but warned
|
|
171
|
+
// about so they are not silently dropped by the input schema.
|
|
172
|
+
if (!optionDef) {
|
|
173
|
+
warnUnknownOption(arg.slice(2), availableOptions, result);
|
|
174
|
+
}
|
|
118
175
|
if (optionDef && optionDef.array) {
|
|
119
176
|
// Array option - collect all following non-flag values
|
|
120
177
|
currentIndex++;
|
|
@@ -5,6 +5,13 @@ export type CoreCredential<T = unknown> = {
|
|
|
5
5
|
description?: string;
|
|
6
6
|
type: 'singleton' | 'wire';
|
|
7
7
|
schema: T;
|
|
8
|
+
/**
|
|
9
|
+
* Link to documentation explaining how to obtain this value — a provider's
|
|
10
|
+
* API-key page, a setup guide, an internal runbook. Surfaced by consoles and
|
|
11
|
+
* deploy UIs so a user facing a missing value has somewhere to go instead of
|
|
12
|
+
* an opaque identifier.
|
|
13
|
+
*/
|
|
14
|
+
docsUrl?: string;
|
|
8
15
|
oauth2?: OAuth2CredentialConfig & {
|
|
9
16
|
appCredentialSecretId: string;
|
|
10
17
|
};
|
|
@@ -15,6 +22,13 @@ export type CredentialDefinitionMeta = {
|
|
|
15
22
|
description?: string;
|
|
16
23
|
type: 'singleton' | 'wire';
|
|
17
24
|
schema?: Record<string, unknown> | string;
|
|
25
|
+
/**
|
|
26
|
+
* Link to documentation explaining how to obtain this value — a provider's
|
|
27
|
+
* API-key page, a setup guide, an internal runbook. Surfaced by consoles and
|
|
28
|
+
* deploy UIs so a user facing a missing value has somewhere to go instead of
|
|
29
|
+
* an opaque identifier.
|
|
30
|
+
*/
|
|
31
|
+
docsUrl?: string;
|
|
18
32
|
oauth2?: OAuth2CredentialConfig & {
|
|
19
33
|
appCredentialSecretId: string;
|
|
20
34
|
};
|