@vimhead.dev/norn-cli 0.1.0-tip.35240723931.1 → 0.1.0-tip.35343816255.1
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/assets/README.md +2 -24
- package/assets/docs/README.md +3 -1
- package/assets/docs/agents.md +3 -3
- package/assets/docs/cli.md +7 -7
- package/assets/docs/composition.md +64 -34
- package/assets/docs/persistence.md +4 -2
- package/assets/docs/projects.md +3 -12
- package/assets/{setup → docs}/providers.md +4 -3
- package/assets/docs/resources.md +7 -7
- package/assets/docs/schemas.md +130 -0
- package/assets/docs/workflows.md +4 -3
- package/assets/examples/agent-then-analysis/README.md +1 -1
- package/assets/examples/agent-then-analysis/plugin.ts +16 -15
- package/assets/examples/caller-selected-continuation/README.md +75 -0
- package/assets/examples/caller-selected-continuation/caller.ts +47 -0
- package/assets/examples/caller-selected-continuation/input.json +9 -0
- package/assets/examples/caller-selected-continuation/norn.project.json +4 -0
- package/assets/examples/caller-selected-continuation/producer.ts +32 -0
- package/assets/examples/coordinating-multiple-agents/README.md +1 -1
- package/assets/examples/coordinating-multiple-agents/plugin.ts +10 -11
- package/assets/examples/coordinating-multiple-agents/queue-adapter.ts +3 -4
- package/assets/examples/coordinating-multiple-agents/work-queue.ts +18 -18
- package/assets/examples/minimal-workflow/plugin.ts +2 -2
- package/assets/examples/shared-state/README.md +1 -1
- package/assets/examples/shared-state/plugin.ts +6 -6
- package/assets/examples/worktree-development-loop/README.md +105 -44
- package/assets/examples/worktree-development-loop/norn.project.json +1 -1
- package/assets/examples/worktree-development-loop/state.ts +6 -6
- package/assets/examples/worktree-development-loop/workflows/development-loop/execute.ts +1 -1
- package/assets/examples/worktree-development-loop/workflows/development-loop/schema.ts +9 -9
- package/assets/examples/worktree-development-loop/workflows/implementation/execute.ts +1 -1
- package/assets/examples/worktree-development-loop/workflows/implementation/schema.ts +7 -7
- package/assets/examples/worktree-development-loop/workflows/planning/execute.ts +1 -1
- package/assets/examples/worktree-development-loop/workflows/planning/schema.ts +7 -7
- package/assets/examples/worktree-development-loop/workflows/review/execute.ts +1 -1
- package/assets/examples/worktree-development-loop/workflows/review/schema.ts +11 -11
- package/assets/examples/worktree-development-loop/workflows/review-router/execute.ts +1 -1
- package/assets/examples/worktree-development-loop/workflows/review-router/schema.ts +5 -5
- package/assets/package.json +1 -1
- package/assets/packages/cli/src/cli.ts +15 -32
- package/assets/packages/cli/src/client.ts +0 -7
- package/assets/packages/cli/src/generated-build-info.ts +2 -2
- package/assets/packages/cli/src/internal/agent-response-tool.ts +9 -10
- package/assets/packages/cli/src/internal/agents.ts +17 -16
- package/assets/packages/cli/src/internal/engine.ts +20 -18
- package/assets/packages/cli/src/internal/errors.ts +4 -10
- package/assets/packages/cli/src/internal/run-state.ts +4 -0
- package/assets/packages/cli/src/internal/run.ts +4 -7
- package/assets/packages/cli/src/internal/state-store.ts +22 -14
- package/assets/packages/cli/src/internal/workflow-registry.ts +27 -21
- package/assets/packages/cli/src/plugin-loader.ts +33 -45
- package/assets/packages/cli/src/resources.ts +14 -12
- package/assets/packages/core/src/workflow-transition.ts +4 -0
- package/assets/packages/sdk/src/api.ts +87 -131
- package/assets/packages/sdk/src/files.ts +11 -10
- package/assets/packages/sdk/src/index.ts +0 -1
- package/assets/packages/sdk/src/resources.ts +2 -2
- package/assets/packages/sdk/src/schema.ts +53 -29
- package/assets/packages/sdk/src/state-adapter.ts +4 -4
- package/assets/tests/workflow-ref.test.ts +121 -77
- package/dist/cli.js +20 -36
- package/dist/client.d.ts +0 -4
- package/dist/client.js +0 -3
- package/dist/generated-build-info.d.ts +2 -2
- package/dist/generated-build-info.js +2 -2
- package/dist/internal/agent-response-tool.d.ts +2 -2
- package/dist/internal/agent-response-tool.js +7 -7
- package/dist/internal/agents.d.ts +2 -2
- package/dist/internal/agents.js +10 -10
- package/dist/internal/engine.d.ts +1 -1
- package/dist/internal/engine.js +14 -12
- package/dist/internal/errors.d.ts +2 -1
- package/dist/internal/errors.js +5 -8
- package/dist/internal/run-state.js +4 -0
- package/dist/internal/run.d.ts +2 -2
- package/dist/internal/run.js +10 -6
- package/dist/internal/state-store.d.ts +8 -7
- package/dist/internal/state-store.js +15 -9
- package/dist/internal/workflow-registry.d.ts +14 -6
- package/dist/internal/workflow-registry.js +20 -15
- package/dist/plugin-loader.d.ts +15 -21
- package/dist/plugin-loader.js +35 -47
- package/dist/resources.d.ts +1 -1
- package/dist/resources.js +15 -13
- package/package.json +3 -4
- package/assets/packages/sdk/src/seer/config.ts +0 -62
- package/assets/packages/sdk/src/seer/index.ts +0 -7
- package/assets/setup/releases.md +0 -76
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { CreateAgentSessionOptions, EventBus, PromptOptions } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
2
|
+
import { Type, type Static, type StaticDecode, type StaticEncode, type TCodec, type TSchema } from "typebox";
|
|
3
|
+
import type { TLocalizedValidationError } from "typebox/error";
|
|
4
|
+
import { createWorkflowTransition } from "@vimhead.dev/norn-core/workflow-transition";
|
|
5
|
+
import { Value } from "typebox/value";
|
|
6
|
+
import { isPlainObject, jsonValueSchema } from "./schema.ts";
|
|
4
7
|
|
|
5
8
|
const WORKFLOW_DECLARATION_KIND = "norn.workflow";
|
|
6
9
|
|
|
@@ -18,24 +21,14 @@ export type NornWorkflowIsolation<Mode extends NornWorkflowIsolationMode = NornW
|
|
|
18
21
|
readonly mode: Mode;
|
|
19
22
|
};
|
|
20
23
|
|
|
21
|
-
declare const nornWorkflowRefParamsBrand: unique symbol;
|
|
22
|
-
declare const nornWorkflowRefForwardParamsBrand: unique symbol;
|
|
23
|
-
|
|
24
|
-
type NornWorkflowRefForwardParams = Record<string, unknown> & {
|
|
25
|
-
readonly [nornWorkflowRefForwardParamsBrand]: true;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export type NornWorkflowRef<ParamsSchema extends z.ZodType = z.ZodType, Id extends string = string, ForwardParams = unknown> = Id & {
|
|
29
|
-
readonly [nornWorkflowRefParamsBrand]: (params: z.input<ParamsSchema> & ForwardParams) => z.input<ParamsSchema> & ForwardParams;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
24
|
export type NornWorkflowDeclaration<
|
|
33
25
|
Id extends string = string,
|
|
34
|
-
ParamsSchema extends
|
|
26
|
+
ParamsSchema extends TSchema = TSchema,
|
|
35
27
|
IsolationMode extends NornWorkflowIsolationMode = NornWorkflowIsolationMode,
|
|
36
28
|
> = {
|
|
29
|
+
(params: StaticEncode<ParamsSchema>): NornRunNext;
|
|
37
30
|
readonly kind: typeof WORKFLOW_DECLARATION_KIND;
|
|
38
|
-
readonly id:
|
|
31
|
+
readonly id: Id;
|
|
39
32
|
readonly isEntrypoint: boolean;
|
|
40
33
|
readonly instructions?: string;
|
|
41
34
|
readonly params: ParamsSchema;
|
|
@@ -43,41 +36,22 @@ export type NornWorkflowDeclaration<
|
|
|
43
36
|
readonly isolation: NornWorkflowIsolation<IsolationMode>;
|
|
44
37
|
};
|
|
45
38
|
|
|
46
|
-
export type NornAnyWorkflowDeclaration = NornWorkflowDeclaration
|
|
47
|
-
export type
|
|
48
|
-
export type NornWorkflowRefSchemaInput<ParamsSchema extends z.ZodType = z.ZodType> = string | {
|
|
49
|
-
readonly id: NornWorkflowRef<ParamsSchema>;
|
|
50
|
-
readonly workflow?: never;
|
|
51
|
-
readonly forwardParams?: never;
|
|
52
|
-
};
|
|
53
|
-
export type NornWorkflowRefSchemaOptions<ParamsSchema extends z.ZodType = z.ZodType> = {
|
|
39
|
+
export type NornAnyWorkflowDeclaration = Pick<NornWorkflowDeclaration, keyof NornWorkflowDeclaration> & ((params: never) => NornRunNext);
|
|
40
|
+
export type NornWorkflowRefSchemaOptions<ParamsSchema extends TSchema = TSchema> = {
|
|
54
41
|
readonly params?: ParamsSchema;
|
|
55
42
|
};
|
|
56
|
-
export type NornWorkflowRefInput
|
|
57
|
-
|
|
58
|
-
| {
|
|
59
|
-
readonly workflow: NornWorkflowRefSchemaInput<z.ZodType<any, any>>;
|
|
60
|
-
readonly forwardParams: Record<string, unknown>;
|
|
61
|
-
};
|
|
62
|
-
export type NornWorkflowRefOutput<ParamsSchema extends z.ZodType> = {
|
|
63
|
-
readonly workflow: NornWorkflowRef<ParamsSchema, string, NornWorkflowRefForwardParams>;
|
|
64
|
-
readonly forwardParams: NornWorkflowRefForwardParams;
|
|
65
|
-
};
|
|
43
|
+
export type NornWorkflowRefInput = StaticEncode<typeof workflowReferenceInputSchema>;
|
|
44
|
+
export type NornWorkflowRefOutput<ParamsSchema extends TSchema> = (params: StaticEncode<ParamsSchema> & object) => NornRunNext;
|
|
66
45
|
|
|
67
|
-
export type NornWorkflowParamsInput<TWorkflow extends NornAnyWorkflowDeclaration> =
|
|
68
|
-
export type NornWorkflowParams<TWorkflow extends NornAnyWorkflowDeclaration> =
|
|
69
|
-
export type NornWorkflowTargetParamsInput<TWorkflow extends NornWorkflowTarget<any>> = TWorkflow extends NornWorkflowDeclaration<string, infer ParamsSchema>
|
|
70
|
-
? z.input<ParamsSchema>
|
|
71
|
-
: TWorkflow extends NornWorkflowRef<infer ParamsSchema, string, infer ForwardParams>
|
|
72
|
-
? z.input<ParamsSchema> & ForwardParams
|
|
73
|
-
: never;
|
|
46
|
+
export type NornWorkflowParamsInput<TWorkflow extends NornAnyWorkflowDeclaration> = StaticEncode<TWorkflow["params"]>;
|
|
47
|
+
export type NornWorkflowParams<TWorkflow extends NornAnyWorkflowDeclaration> = StaticDecode<TWorkflow["params"]>;
|
|
74
48
|
|
|
75
|
-
export type NornWorkflowGate<ParamsSchema extends
|
|
49
|
+
export type NornWorkflowGate<ParamsSchema extends TSchema> = unknown extends StaticEncode<ParamsSchema>
|
|
76
50
|
? NornWorkflowAnyGate
|
|
77
|
-
:
|
|
51
|
+
: StaticEncode<ParamsSchema> extends Record<string, unknown>
|
|
78
52
|
? {
|
|
79
53
|
readonly enabled: true;
|
|
80
|
-
readonly fields?: readonly Extract<keyof
|
|
54
|
+
readonly fields?: readonly Extract<keyof StaticEncode<ParamsSchema>, string>[];
|
|
81
55
|
}
|
|
82
56
|
: {
|
|
83
57
|
readonly enabled: true;
|
|
@@ -90,7 +64,7 @@ type NornWorkflowInstructions =
|
|
|
90
64
|
|
|
91
65
|
export type NornWorkflowDefinition<
|
|
92
66
|
Id extends string | undefined = string | undefined,
|
|
93
|
-
ParamsSchema extends
|
|
67
|
+
ParamsSchema extends TSchema = TSchema,
|
|
94
68
|
IsolationMode extends NornWorkflowIsolationMode = NornWorkflowIsolationMode,
|
|
95
69
|
> = {
|
|
96
70
|
readonly id?: Id;
|
|
@@ -101,26 +75,27 @@ export type NornWorkflowDefinition<
|
|
|
101
75
|
|
|
102
76
|
export type NornAnyWorkflowDefinition = {
|
|
103
77
|
readonly id?: string;
|
|
104
|
-
readonly params:
|
|
78
|
+
readonly params: TSchema;
|
|
105
79
|
readonly gate?: NornWorkflowAnyGate;
|
|
106
80
|
readonly isolation?: NornWorkflowIsolation;
|
|
107
81
|
} & NornWorkflowInstructions;
|
|
108
82
|
|
|
109
|
-
export type NornWorkflowStateDefinition<
|
|
83
|
+
export type NornWorkflowStateDefinition<Schema extends TSchema = TSchema, Id extends string = string> = {
|
|
110
84
|
readonly id: Id;
|
|
111
85
|
readonly description?: string;
|
|
112
|
-
readonly schema:
|
|
86
|
+
readonly schema: Schema;
|
|
113
87
|
};
|
|
114
88
|
|
|
115
|
-
export type NornWorkflowStateDefinitionInput<
|
|
89
|
+
export type NornWorkflowStateDefinitionInput<Schema extends TSchema = TSchema, Id extends string | undefined = string | undefined> = {
|
|
116
90
|
readonly id?: Id;
|
|
117
91
|
readonly description?: string;
|
|
118
|
-
readonly schema:
|
|
92
|
+
readonly schema: Schema;
|
|
119
93
|
};
|
|
120
94
|
|
|
121
95
|
export type NornWorkflowPluginWorkflows = Record<string, NornAnyWorkflowDefinition>;
|
|
122
96
|
export type NornWorkflowPluginStateTree = { readonly [key: string]: NornWorkflowPluginStateTreeNode };
|
|
123
|
-
|
|
97
|
+
type NornStateSchema = TSchema & ({ readonly "~kind": string } | { readonly "~unsafe": unknown });
|
|
98
|
+
export type NornWorkflowPluginStateTreeNode = NornStateSchema | NornWorkflowStateDefinitionInput | NornWorkflowPluginStateTree;
|
|
124
99
|
|
|
125
100
|
type JoinPath<Head extends string, Parts extends readonly string[]> = Parts extends readonly []
|
|
126
101
|
? Head
|
|
@@ -128,13 +103,13 @@ type JoinPath<Head extends string, Parts extends readonly string[]> = Parts exte
|
|
|
128
103
|
? JoinPath<`${Head}.${First}`, Rest>
|
|
129
104
|
: string;
|
|
130
105
|
|
|
131
|
-
type NornInvalidGateFields<TWorkflow> = TWorkflow extends { readonly params: infer ParamsSchema extends
|
|
132
|
-
? Exclude<Fields[number], Extract<keyof
|
|
106
|
+
type NornInvalidGateFields<TWorkflow> = TWorkflow extends { readonly params: infer ParamsSchema extends TSchema; readonly gate: { readonly fields: infer Fields extends readonly string[] } }
|
|
107
|
+
? Exclude<Fields[number], Extract<keyof StaticEncode<ParamsSchema>, string>>
|
|
133
108
|
: never;
|
|
134
109
|
|
|
135
110
|
type NornValidatedWorkflowGate<TWorkflow> = [NornInvalidGateFields<TWorkflow>] extends [never]
|
|
136
111
|
? unknown
|
|
137
|
-
: { readonly gate: { readonly fields: readonly Extract<keyof
|
|
112
|
+
: { readonly gate: { readonly fields: readonly Extract<keyof StaticEncode<TWorkflow extends { readonly params: infer ParamsSchema extends TSchema } ? ParamsSchema : TSchema>, string>[] } };
|
|
138
113
|
|
|
139
114
|
export type NornValidatedWorkflowGates<Workflows> = {
|
|
140
115
|
readonly [Key in keyof Workflows]: NornValidatedWorkflowGate<Workflows[Key]>;
|
|
@@ -144,7 +119,7 @@ export type NornQualifiedPluginWorkflow<
|
|
|
144
119
|
PluginId extends string,
|
|
145
120
|
WorkflowKey extends string,
|
|
146
121
|
TWorkflow extends NornAnyWorkflowDefinition,
|
|
147
|
-
> = TWorkflow extends { readonly params: infer ParamsSchema extends
|
|
122
|
+
> = TWorkflow extends { readonly params: infer ParamsSchema extends TSchema }
|
|
148
123
|
? NornWorkflowDeclaration<
|
|
149
124
|
TWorkflow extends { readonly id: infer ExplicitId extends string } ? ExplicitId : `${PluginId}.${WorkflowKey}`,
|
|
150
125
|
ParamsSchema,
|
|
@@ -157,13 +132,10 @@ export type NornQualifiedPluginWorkflows<PluginId extends string, Workflows exte
|
|
|
157
132
|
};
|
|
158
133
|
|
|
159
134
|
export type NornQualifiedPluginStates<PluginId extends string, States, Path extends readonly string[] = []> = {
|
|
160
|
-
readonly [Key in keyof States]: States[Key] extends
|
|
161
|
-
? NornWorkflowStateDefinition<
|
|
162
|
-
: States[Key] extends NornWorkflowStateDefinitionInput<infer
|
|
163
|
-
? NornWorkflowStateDefinition<
|
|
164
|
-
Value,
|
|
165
|
-
States[Key] extends { readonly id: infer ExplicitId extends string } ? ExplicitId : JoinPath<PluginId, [...Path, Key & string]>
|
|
166
|
-
>
|
|
135
|
+
readonly [Key in keyof States]: States[Key] extends NornStateSchema
|
|
136
|
+
? NornWorkflowStateDefinition<States[Key], JoinPath<PluginId, [...Path, Key & string]>>
|
|
137
|
+
: States[Key] extends NornWorkflowStateDefinitionInput<infer Schema extends NornStateSchema>
|
|
138
|
+
? NornWorkflowStateDefinition<Schema, States[Key] extends { readonly id: infer Id extends string } ? Id : JoinPath<PluginId, [...Path, Key & string]>>
|
|
167
139
|
: States[Key] extends NornWorkflowPluginStateTree
|
|
168
140
|
? NornQualifiedPluginStates<PluginId, States[Key], [...Path, Key & string]>
|
|
169
141
|
: never;
|
|
@@ -171,7 +143,7 @@ export type NornQualifiedPluginStates<PluginId extends string, States, Path exte
|
|
|
171
143
|
|
|
172
144
|
export type NornWorkflowPluginManifest<
|
|
173
145
|
PluginId extends string = string,
|
|
174
|
-
ConfigSchema extends
|
|
146
|
+
ConfigSchema extends TSchema | undefined = TSchema | undefined,
|
|
175
147
|
Workflows extends Record<string, NornAnyWorkflowDeclaration> = Record<string, NornAnyWorkflowDeclaration>,
|
|
176
148
|
States = undefined,
|
|
177
149
|
> = {
|
|
@@ -181,19 +153,19 @@ export type NornWorkflowPluginManifest<
|
|
|
181
153
|
readonly states: States;
|
|
182
154
|
};
|
|
183
155
|
|
|
184
|
-
export type NornAnyWorkflowPluginManifest = NornWorkflowPluginManifest<string,
|
|
156
|
+
export type NornAnyWorkflowPluginManifest = NornWorkflowPluginManifest<string, TSchema | undefined, Record<string, NornAnyWorkflowDeclaration>, unknown>;
|
|
185
157
|
|
|
186
|
-
export type NornWorkflowPluginConfigSchema<TManifest extends NornAnyWorkflowPluginManifest> = TManifest extends { readonly config?: infer ConfigSchema extends
|
|
158
|
+
export type NornWorkflowPluginConfigSchema<TManifest extends NornAnyWorkflowPluginManifest> = TManifest extends { readonly config?: infer ConfigSchema extends TSchema | undefined }
|
|
187
159
|
? ConfigSchema
|
|
188
160
|
: undefined;
|
|
189
161
|
|
|
190
|
-
export type NornWorkflowPluginConfig<TManifest extends NornAnyWorkflowPluginManifest> =
|
|
191
|
-
?
|
|
192
|
-
:
|
|
162
|
+
export type NornWorkflowPluginConfig<TManifest extends NornAnyWorkflowPluginManifest> = NornWorkflowPluginConfigSchema<TManifest> extends undefined
|
|
163
|
+
? undefined
|
|
164
|
+
: StaticDecode<NonNullable<NornWorkflowPluginConfigSchema<TManifest>>>;
|
|
193
165
|
|
|
194
166
|
export type NornDefinePluginManifestInput<
|
|
195
167
|
PluginId extends string,
|
|
196
|
-
ConfigSchema extends
|
|
168
|
+
ConfigSchema extends TSchema | undefined,
|
|
197
169
|
Workflows extends NornWorkflowPluginWorkflows,
|
|
198
170
|
States extends NornWorkflowPluginStateTree | undefined,
|
|
199
171
|
> = {
|
|
@@ -205,7 +177,7 @@ export type NornDefinePluginManifestInput<
|
|
|
205
177
|
|
|
206
178
|
export function definePluginManifest<
|
|
207
179
|
const PluginId extends string,
|
|
208
|
-
const ConfigSchema extends
|
|
180
|
+
const ConfigSchema extends TSchema | undefined = undefined,
|
|
209
181
|
const Workflows extends NornWorkflowPluginWorkflows = NornWorkflowPluginWorkflows,
|
|
210
182
|
const States extends NornWorkflowPluginStateTree | undefined = undefined,
|
|
211
183
|
>(
|
|
@@ -387,12 +359,12 @@ export type NornRunCheckpoint = {
|
|
|
387
359
|
};
|
|
388
360
|
|
|
389
361
|
export type NornWorkflowStateReader = {
|
|
390
|
-
get<
|
|
391
|
-
getOptional<
|
|
362
|
+
get<Schema extends TSchema>(state: NornWorkflowStateDefinition<Schema>): Promise<Static<Schema>>;
|
|
363
|
+
getOptional<Schema extends TSchema>(state: NornWorkflowStateDefinition<Schema>): Promise<Static<Schema> | undefined>;
|
|
392
364
|
};
|
|
393
365
|
|
|
394
366
|
export type NornWorkflowState = NornWorkflowStateReader & {
|
|
395
|
-
set<
|
|
367
|
+
set<Schema extends TSchema>(state: NornWorkflowStateDefinition<Schema>, value: NoInfer<Static<Schema>>): Promise<void>;
|
|
396
368
|
};
|
|
397
369
|
|
|
398
370
|
export type NornWorkflowPluginContext = {
|
|
@@ -434,46 +406,30 @@ export type NornCommandRunInput = {
|
|
|
434
406
|
readonly timeoutMs?: number;
|
|
435
407
|
};
|
|
436
408
|
|
|
437
|
-
export const artifactRefSchema =
|
|
438
|
-
path:
|
|
409
|
+
export const artifactRefSchema = Type.Object({
|
|
410
|
+
path: Type.String(),
|
|
439
411
|
});
|
|
440
412
|
|
|
441
|
-
export type NornArtifactRef =
|
|
442
|
-
|
|
443
|
-
const emptyWorkflowRefParamsSchema =
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
export function workflowRefSchema(options: {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const targetSchema = z.union([
|
|
462
|
-
z.string().min(1),
|
|
463
|
-
z.object({ id: z.string().min(1) }),
|
|
464
|
-
]).transform((target) => typeof target === "string" ? target : target.id);
|
|
465
|
-
return z.union([
|
|
466
|
-
targetSchema,
|
|
467
|
-
z.object({ workflow: targetSchema, forwardParams: z.record(z.string(), z.unknown()) }),
|
|
468
|
-
]).transform((reference) => typeof reference === "string"
|
|
469
|
-
? { workflow: reference, forwardParams: {} }
|
|
470
|
-
: reference).meta({
|
|
471
|
-
"x-norn-workflow-ref": {
|
|
472
|
-
get contributedParamsSchema() {
|
|
473
|
-
return z.toJSONSchema(contributedParams, { io: "input" });
|
|
474
|
-
},
|
|
475
|
-
},
|
|
476
|
-
});
|
|
413
|
+
export type NornArtifactRef = StaticDecode<typeof artifactRefSchema>;
|
|
414
|
+
|
|
415
|
+
const emptyWorkflowRefParamsSchema = Type.Object({});
|
|
416
|
+
const workflowReferenceInputSchema = Type.Union([
|
|
417
|
+
Type.String({ minLength: 1 }),
|
|
418
|
+
Type.Object({ workflow: Type.String({ minLength: 1 }), forwardParams: Type.Record(Type.String(), Type.Unknown()) }),
|
|
419
|
+
]);
|
|
420
|
+
|
|
421
|
+
export function workflowRefSchema<ParamsSchema extends TSchema = typeof emptyWorkflowRefParamsSchema>(options?: NornWorkflowRefSchemaOptions<ParamsSchema>): TCodec<typeof workflowReferenceInputSchema, NornWorkflowRefOutput<ParamsSchema>> {
|
|
422
|
+
const contributionSchema = options?.params ?? emptyWorkflowRefParamsSchema;
|
|
423
|
+
return Type.With(Type.Decode(workflowReferenceInputSchema, reference => {
|
|
424
|
+
const workflowId = typeof reference === "string" ? reference : reference.workflow;
|
|
425
|
+
const forwardParams = typeof reference === "string" ? {} : reference.forwardParams;
|
|
426
|
+
return (params: StaticEncode<ParamsSchema> & object): NornRunNext => {
|
|
427
|
+
Value.Assert(contributionSchema, params);
|
|
428
|
+
if (!isPlainObject(params)) throw new Error("Workflow reference contributions must be objects");
|
|
429
|
+
Value.Assert(jsonValueSchema, params);
|
|
430
|
+
return createWorkflowTransition({ workflowId, params: { ...forwardParams, ...params } });
|
|
431
|
+
};
|
|
432
|
+
}), { "x-norn-workflow-ref": { contributedParamsSchema: contributionSchema } });
|
|
477
433
|
}
|
|
478
434
|
|
|
479
435
|
export type NornLogRef = {
|
|
@@ -508,14 +464,14 @@ export type NornAgentCreateSessionInput = {
|
|
|
508
464
|
readonly appendSystemPrompt?: readonly string[];
|
|
509
465
|
};
|
|
510
466
|
|
|
511
|
-
export type NornAgentPromptInput<ResponseSchema extends
|
|
467
|
+
export type NornAgentPromptInput<ResponseSchema extends TSchema> = {
|
|
512
468
|
readonly prompt: string;
|
|
513
469
|
readonly response: ResponseSchema;
|
|
514
470
|
readonly maxAttempts?: number;
|
|
515
471
|
readonly options?: PromptOptions;
|
|
516
472
|
};
|
|
517
473
|
|
|
518
|
-
export type NornAgentSinglePromptInput<ResponseSchema extends
|
|
474
|
+
export type NornAgentSinglePromptInput<ResponseSchema extends TSchema> = NornAgentCreateSessionInput & NornAgentPromptInput<ResponseSchema>;
|
|
519
475
|
|
|
520
476
|
export type NornAgentSessionEvents = EventBus;
|
|
521
477
|
|
|
@@ -600,10 +556,10 @@ export type NornAgentRunRawAttempt = {
|
|
|
600
556
|
readonly error?: string;
|
|
601
557
|
};
|
|
602
558
|
|
|
603
|
-
export type NornAgentRunResult<ResponseSchema extends
|
|
559
|
+
export type NornAgentRunResult<ResponseSchema extends TSchema> = {
|
|
604
560
|
readonly label: string;
|
|
605
561
|
readonly cwd: string;
|
|
606
|
-
readonly response:
|
|
562
|
+
readonly response: StaticDecode<ResponseSchema>;
|
|
607
563
|
readonly usage: NornAgentUsage;
|
|
608
564
|
readonly raw: {
|
|
609
565
|
readonly text: string;
|
|
@@ -620,7 +576,7 @@ export type NornAgentSession = {
|
|
|
620
576
|
readonly label: string;
|
|
621
577
|
readonly cwd: string;
|
|
622
578
|
readonly events: NornAgentSessionEvents;
|
|
623
|
-
prompt<ResponseSchema extends
|
|
579
|
+
prompt<ResponseSchema extends TSchema>(input: NornAgentPromptInput<ResponseSchema>): Promise<StaticDecode<ResponseSchema>>;
|
|
624
580
|
dispose(): Promise<void>;
|
|
625
581
|
};
|
|
626
582
|
|
|
@@ -636,7 +592,7 @@ type NornRunBase = {
|
|
|
636
592
|
workspace: string;
|
|
637
593
|
cwd: string;
|
|
638
594
|
path(relativePath: string): string;
|
|
639
|
-
next
|
|
595
|
+
next(workflowId: string, params: unknown): NornRunNext;
|
|
640
596
|
complete(metadata?: NornRunOutcomeMetadata): NornRunComplete;
|
|
641
597
|
fail(metadata: NornRunOutcomeMetadata & { readonly summary: string }): NornRunFail;
|
|
642
598
|
resources: import("./resources.ts").NornResources;
|
|
@@ -653,7 +609,7 @@ type NornRunBase = {
|
|
|
653
609
|
};
|
|
654
610
|
agents: {
|
|
655
611
|
createSession(input: NornAgentCreateSessionInput): Promise<NornAgentSession>;
|
|
656
|
-
prompt<ResponseSchema extends
|
|
612
|
+
prompt<ResponseSchema extends TSchema>(input: NornAgentSinglePromptInput<ResponseSchema>): Promise<StaticDecode<ResponseSchema>>;
|
|
657
613
|
};
|
|
658
614
|
};
|
|
659
615
|
|
|
@@ -690,7 +646,7 @@ export type NornPluginDiagnostic = {
|
|
|
690
646
|
readonly workflowId: string | null;
|
|
691
647
|
readonly stage: "import" | "declaration" | "config" | "implementation" | "duplicate" | "schema";
|
|
692
648
|
readonly message: string;
|
|
693
|
-
readonly issues: readonly
|
|
649
|
+
readonly issues: readonly TLocalizedValidationError[];
|
|
694
650
|
};
|
|
695
651
|
|
|
696
652
|
export type NornProjectLoadStatus = {
|
|
@@ -723,7 +679,6 @@ export type NornProjectInfo = {
|
|
|
723
679
|
readonly configRoot: string;
|
|
724
680
|
readonly configFiles: readonly string[];
|
|
725
681
|
readonly plugins: readonly NornProjectPluginInfo[];
|
|
726
|
-
readonly seerMode: NornResolvedSeerModeConfig | null;
|
|
727
682
|
};
|
|
728
683
|
|
|
729
684
|
function assertLocalDeclarationId(id: string, kind: "plugin" | "workflow" | "state"): void {
|
|
@@ -752,20 +707,22 @@ function qualifyWorkflow<PluginId extends string, TWorkflow extends NornAnyWorkf
|
|
|
752
707
|
declaredIds: Set<string>,
|
|
753
708
|
): NornQualifiedPluginWorkflow<PluginId, string, TWorkflow> {
|
|
754
709
|
const id = resolveDeclarationId(pluginId, [key], workflow.id, "workflow", declaredIds);
|
|
755
|
-
|
|
710
|
+
const declaration = (params: unknown): NornRunNext => createWorkflowTransition({ workflowId: id, params });
|
|
711
|
+
return Object.assign(declaration, { ...workflow, kind: WORKFLOW_DECLARATION_KIND, id, isolation: workflow.isolation ?? { mode: "runWorkspace" } }) as unknown as NornQualifiedPluginWorkflow<PluginId, string, TWorkflow>;
|
|
756
712
|
}
|
|
757
713
|
|
|
758
|
-
function qualifyStateTree(pluginId: string, node:
|
|
759
|
-
if (
|
|
760
|
-
if (
|
|
761
|
-
if (isWorkflowStateDefinitionInput(node)) {
|
|
714
|
+
function qualifyStateTree(pluginId: string, node: unknown, path: readonly string[], declaredIds: Set<string>): unknown {
|
|
715
|
+
if (node === undefined) return undefined;
|
|
716
|
+
if (isTypeboxSchema(node)) return { id: resolveDeclarationId(pluginId, path, undefined, "state", declaredIds), schema: node };
|
|
717
|
+
if (path.length > 0 && isWorkflowStateDefinitionInput(node)) {
|
|
762
718
|
return { ...node, id: resolveDeclarationId(pluginId, path, node.id, "state", declaredIds) };
|
|
763
719
|
}
|
|
720
|
+
if (!isPlainObject(node)) throw new Error(`Invalid state declaration: ${[pluginId, ...path].join(".")}`);
|
|
764
721
|
return Object.fromEntries(Object.entries(node).map(([key, child]) => [key, qualifyStateTree(pluginId, child, [...path, key], declaredIds)]));
|
|
765
722
|
}
|
|
766
723
|
|
|
767
724
|
export function isWorkflowDeclaration(value: unknown): value is NornAnyWorkflowDeclaration {
|
|
768
|
-
if (
|
|
725
|
+
if (typeof value !== "function") return false;
|
|
769
726
|
const candidate = value as { kind?: unknown; id?: unknown; instructions?: unknown; isEntrypoint?: unknown; params?: unknown; isolation?: { mode?: unknown } };
|
|
770
727
|
return (
|
|
771
728
|
candidate.kind === WORKFLOW_DECLARATION_KIND &&
|
|
@@ -778,14 +735,13 @@ export function isWorkflowDeclaration(value: unknown): value is NornAnyWorkflowD
|
|
|
778
735
|
);
|
|
779
736
|
}
|
|
780
737
|
|
|
781
|
-
function
|
|
782
|
-
|
|
783
|
-
const candidate = value as { id?: unknown; schema?: unknown };
|
|
784
|
-
return (candidate.id === undefined || typeof candidate.id === "string") && isZodSchema(candidate.schema);
|
|
738
|
+
function isTypeboxSchema(value: unknown): value is NornStateSchema {
|
|
739
|
+
return Type.IsUnsafe(value) || Boolean(value && typeof value === "object" && "~kind" in value && typeof value["~kind"] === "string");
|
|
785
740
|
}
|
|
786
741
|
|
|
787
|
-
function
|
|
788
|
-
|
|
742
|
+
function isWorkflowStateDefinitionInput(value: unknown): value is NornWorkflowStateDefinitionInput {
|
|
743
|
+
if (!isPlainObject(value)) return false;
|
|
744
|
+
return (value.id === undefined || typeof value.id === "string") && isTypeboxSchema(value.schema);
|
|
789
745
|
}
|
|
790
746
|
|
|
791
747
|
export function isWorkflowPlugin(value: unknown): value is NornWorkflowPlugin {
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
+
import { writeTextAtomically } from "@vimhead.dev/norn-core/atomic-files";
|
|
2
|
+
import { isNodeError } from "@vimhead.dev/norn-core/errors";
|
|
1
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
4
|
import { lstat, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, rmdir, unlink, writeFile } from "node:fs/promises";
|
|
3
5
|
import { hostname } from "node:os";
|
|
4
6
|
import { basename, dirname, join, resolve } from "node:path";
|
|
5
7
|
import { setTimeout as delay } from "node:timers/promises";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { writeTextAtomically } from "@vimhead.dev/norn-core/atomic-files";
|
|
8
|
+
import { Type } from "typebox";
|
|
9
|
+
import { Value } from "typebox/value";
|
|
9
10
|
|
|
10
|
-
const ownerSchema =
|
|
11
|
-
token:
|
|
12
|
-
pid:
|
|
13
|
-
host:
|
|
14
|
-
target:
|
|
15
|
-
});
|
|
11
|
+
const ownerSchema = Type.Object({
|
|
12
|
+
token: Type.String({ format: "uuid" }),
|
|
13
|
+
pid: Type.Integer({ exclusiveMinimum: 0 }),
|
|
14
|
+
host: Type.String(),
|
|
15
|
+
target: Type.String(),
|
|
16
|
+
}, { additionalProperties: false });
|
|
16
17
|
|
|
17
18
|
export class NornFileCoordinator {
|
|
18
19
|
private readonly lockRoot: string;
|
|
@@ -103,7 +104,7 @@ export class NornFileCoordinator {
|
|
|
103
104
|
if (entries.length === 0) return;
|
|
104
105
|
if (entries.length !== 1) throw new Error(`Invalid file lock ownership: ${input.lockPath}`);
|
|
105
106
|
const marker = entries[0];
|
|
106
|
-
const owner =
|
|
107
|
+
const owner = Value.Parse(ownerSchema, JSON.parse(await readFile(join(input.lockPath, marker), "utf8")));
|
|
107
108
|
if (marker !== `${owner.token}.json` || owner.target !== input.target || owner.host !== hostname()) {
|
|
108
109
|
throw new Error(`Incompatible file lock ownership: ${input.lockPath}`);
|
|
109
110
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { z } from "zod";
|
|
2
1
|
import type { NornFileCoordinator } from "./files.ts";
|
|
2
|
+
import type { NornJsonValue } from "./schema.ts";
|
|
3
3
|
|
|
4
4
|
export type NornResourceContext = {
|
|
5
5
|
readonly mode: "create" | "open";
|
|
@@ -10,7 +10,7 @@ export type NornResourceContext = {
|
|
|
10
10
|
export type NornResourceDefinition<T> = {
|
|
11
11
|
readonly name: string;
|
|
12
12
|
readonly kind: string;
|
|
13
|
-
readonly configuration:
|
|
13
|
+
readonly configuration: NornJsonValue;
|
|
14
14
|
initialize(context: NornResourceContext): Promise<T>;
|
|
15
15
|
};
|
|
16
16
|
|
|
@@ -1,4 +1,46 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { Type, type Static, type TSchema } from "typebox";
|
|
2
|
+
import { Meta } from "typebox/schema";
|
|
3
|
+
import { Value } from "typebox/value";
|
|
4
|
+
import type { NornAnyWorkflowDeclaration, NornJsonSchema } from "./api.ts";
|
|
5
|
+
|
|
6
|
+
export const jsonValueSchema = Type.Cyclic({
|
|
7
|
+
Json: Type.Union([
|
|
8
|
+
Type.Null(), Type.Boolean(), Type.Number(), Type.String(),
|
|
9
|
+
Type.Array(Type.Ref("Json")),
|
|
10
|
+
Type.Refine(Type.Record(Type.String(), Type.Ref("Json")), value => Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null),
|
|
11
|
+
]),
|
|
12
|
+
}, "Json");
|
|
13
|
+
|
|
14
|
+
export type NornJsonValue = Static<typeof jsonValueSchema>;
|
|
15
|
+
|
|
16
|
+
export function inspectSchema(schema: TSchema): NornJsonSchema {
|
|
17
|
+
const inspected: unknown = JSON.parse(JSON.stringify(schema));
|
|
18
|
+
Value.Assert(Meta["https://json-schema.org/draft/2020-12/schema"], inspected);
|
|
19
|
+
if (!isPlainObject(inspected)) throw new Error("Norn inspection requires an object schema");
|
|
20
|
+
assertWorkflowReferenceAnnotations(inspected);
|
|
21
|
+
return inspected;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function assertWorkflowReferenceAnnotations(schema: unknown): void {
|
|
25
|
+
if (!isPlainObject(schema)) return;
|
|
26
|
+
if (Object.hasOwn(schema, "x-norn-workflow-ref")) {
|
|
27
|
+
const annotation = schema["x-norn-workflow-ref"];
|
|
28
|
+
if (!isPlainObject(annotation) || !Object.hasOwn(annotation, "contributedParamsSchema")) throw new Error("Invalid workflow reference annotation");
|
|
29
|
+
Value.Assert(Meta["https://json-schema.org/draft/2020-12/schema"], annotation.contributedParamsSchema);
|
|
30
|
+
assertWorkflowReferenceAnnotations(annotation.contributedParamsSchema);
|
|
31
|
+
}
|
|
32
|
+
for (const keyword of ["properties", "patternProperties", "$defs", "definitions", "dependentSchemas"]) {
|
|
33
|
+
const schemas = schema[keyword];
|
|
34
|
+
if (isPlainObject(schemas)) for (const child of Object.values(schemas)) assertWorkflowReferenceAnnotations(child);
|
|
35
|
+
}
|
|
36
|
+
for (const keyword of ["allOf", "anyOf", "oneOf", "prefixItems"]) {
|
|
37
|
+
const schemas = schema[keyword];
|
|
38
|
+
if (Array.isArray(schemas)) for (const child of schemas) assertWorkflowReferenceAnnotations(child);
|
|
39
|
+
}
|
|
40
|
+
for (const keyword of ["additionalProperties", "unevaluatedProperties", "propertyNames", "items", "contains", "not", "if", "then", "else", "unevaluatedItems", "contentSchema"]) {
|
|
41
|
+
assertWorkflowReferenceAnnotations(schema[keyword]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
2
44
|
|
|
3
45
|
export function assertWorkflowMetadata(workflow: NornAnyWorkflowDeclaration): void {
|
|
4
46
|
if (workflow.instructions !== undefined && (typeof workflow.instructions !== "string" || workflow.instructions.trim().length === 0)) {
|
|
@@ -9,40 +51,22 @@ export function assertWorkflowMetadata(workflow: NornAnyWorkflowDeclaration): vo
|
|
|
9
51
|
}
|
|
10
52
|
}
|
|
11
53
|
|
|
12
|
-
export function unwrapSchema(schema:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (["optional", "nullable", "default", "catch", "readonly", "prefault"].includes(def.type ?? "") && def.innerType) {
|
|
17
|
-
current = def.innerType;
|
|
18
|
-
continue;
|
|
19
|
-
}
|
|
20
|
-
return current;
|
|
21
|
-
}
|
|
54
|
+
export function unwrapSchema(schema: TSchema): TSchema {
|
|
55
|
+
if (!Type.IsUnion(schema)) return schema;
|
|
56
|
+
const members = schema.anyOf.filter(member => !Type.IsNull(member));
|
|
57
|
+
return members.length === 1 ? unwrapSchema(members[0]) : schema;
|
|
22
58
|
}
|
|
23
59
|
|
|
24
|
-
export function schemaShape(schema:
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
return typeof shape === "function" ? shape() as Record<string, unknown> : shape as Record<string, unknown>;
|
|
60
|
+
export function schemaShape(schema: TSchema): Record<string, TSchema> {
|
|
61
|
+
const unwrapped = unwrapSchema(schema);
|
|
62
|
+
return Type.IsObject(unwrapped) ? unwrapped.properties : {};
|
|
28
63
|
}
|
|
29
64
|
|
|
30
|
-
export function schemaType(schema:
|
|
31
|
-
|
|
65
|
+
export function schemaType(schema: TSchema): string | undefined {
|
|
66
|
+
const unwrapped = unwrapSchema(schema);
|
|
67
|
+
return "type" in unwrapped && typeof unwrapped.type === "string" ? unwrapped.type : undefined;
|
|
32
68
|
}
|
|
33
69
|
|
|
34
70
|
export function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
35
71
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
36
72
|
}
|
|
37
|
-
|
|
38
|
-
type ZodDef = {
|
|
39
|
-
readonly type?: string;
|
|
40
|
-
readonly innerType?: unknown;
|
|
41
|
-
readonly shape?: unknown;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
function schemaDef(schema: unknown): ZodDef {
|
|
45
|
-
if (!schema || typeof schema !== "object") return {};
|
|
46
|
-
const candidate = schema as { _def?: ZodDef; def?: ZodDef };
|
|
47
|
-
return candidate._def ?? candidate.def ?? {};
|
|
48
|
-
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
1
|
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
3
|
import { Type } from "typebox";
|
|
4
|
-
import { z } from "zod";
|
|
5
|
-
import type { NornWorkflowState, NornWorkflowStateDefinition } from "./api.ts";
|
|
6
4
|
import type { NornAgentResourceAdapter } from "./agent-resource-adapter.ts";
|
|
5
|
+
import type { NornWorkflowState, NornWorkflowStateDefinition } from "./api.ts";
|
|
6
|
+
import { inspectSchema } from "./schema.ts";
|
|
7
7
|
|
|
8
8
|
export type NornStateFieldAccess = {
|
|
9
9
|
readonly field: NornWorkflowStateDefinition;
|
|
@@ -34,7 +34,7 @@ export function StateAdapter(input: { readonly state: NornWorkflowState; readonl
|
|
|
34
34
|
description: "List only attached workflow-state field IDs, permissions and value schemas. JSON is paginated; use nextOffset until null.",
|
|
35
35
|
parameters: Type.Object(pageParameters),
|
|
36
36
|
async execute(_id, params) {
|
|
37
|
-
return serializePage({ value: [...fields.values()].map(({ field, access }) => ({ id: field.id, access, schema:
|
|
37
|
+
return serializePage({ value: [...fields.values()].map(({ field, access }) => ({ id: field.id, access, schema: inspectSchema(field.schema) })), ...params });
|
|
38
38
|
},
|
|
39
39
|
}),
|
|
40
40
|
defineTool({
|