@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.
Files changed (88) hide show
  1. package/assets/README.md +2 -24
  2. package/assets/docs/README.md +3 -1
  3. package/assets/docs/agents.md +3 -3
  4. package/assets/docs/cli.md +7 -7
  5. package/assets/docs/composition.md +64 -34
  6. package/assets/docs/persistence.md +4 -2
  7. package/assets/docs/projects.md +3 -12
  8. package/assets/{setup → docs}/providers.md +4 -3
  9. package/assets/docs/resources.md +7 -7
  10. package/assets/docs/schemas.md +130 -0
  11. package/assets/docs/workflows.md +4 -3
  12. package/assets/examples/agent-then-analysis/README.md +1 -1
  13. package/assets/examples/agent-then-analysis/plugin.ts +16 -15
  14. package/assets/examples/caller-selected-continuation/README.md +75 -0
  15. package/assets/examples/caller-selected-continuation/caller.ts +47 -0
  16. package/assets/examples/caller-selected-continuation/input.json +9 -0
  17. package/assets/examples/caller-selected-continuation/norn.project.json +4 -0
  18. package/assets/examples/caller-selected-continuation/producer.ts +32 -0
  19. package/assets/examples/coordinating-multiple-agents/README.md +1 -1
  20. package/assets/examples/coordinating-multiple-agents/plugin.ts +10 -11
  21. package/assets/examples/coordinating-multiple-agents/queue-adapter.ts +3 -4
  22. package/assets/examples/coordinating-multiple-agents/work-queue.ts +18 -18
  23. package/assets/examples/minimal-workflow/plugin.ts +2 -2
  24. package/assets/examples/shared-state/README.md +1 -1
  25. package/assets/examples/shared-state/plugin.ts +6 -6
  26. package/assets/examples/worktree-development-loop/README.md +105 -44
  27. package/assets/examples/worktree-development-loop/norn.project.json +1 -1
  28. package/assets/examples/worktree-development-loop/state.ts +6 -6
  29. package/assets/examples/worktree-development-loop/workflows/development-loop/execute.ts +1 -1
  30. package/assets/examples/worktree-development-loop/workflows/development-loop/schema.ts +9 -9
  31. package/assets/examples/worktree-development-loop/workflows/implementation/execute.ts +1 -1
  32. package/assets/examples/worktree-development-loop/workflows/implementation/schema.ts +7 -7
  33. package/assets/examples/worktree-development-loop/workflows/planning/execute.ts +1 -1
  34. package/assets/examples/worktree-development-loop/workflows/planning/schema.ts +7 -7
  35. package/assets/examples/worktree-development-loop/workflows/review/execute.ts +1 -1
  36. package/assets/examples/worktree-development-loop/workflows/review/schema.ts +11 -11
  37. package/assets/examples/worktree-development-loop/workflows/review-router/execute.ts +1 -1
  38. package/assets/examples/worktree-development-loop/workflows/review-router/schema.ts +5 -5
  39. package/assets/package.json +1 -1
  40. package/assets/packages/cli/src/cli.ts +15 -32
  41. package/assets/packages/cli/src/client.ts +0 -7
  42. package/assets/packages/cli/src/generated-build-info.ts +2 -2
  43. package/assets/packages/cli/src/internal/agent-response-tool.ts +9 -10
  44. package/assets/packages/cli/src/internal/agents.ts +17 -16
  45. package/assets/packages/cli/src/internal/engine.ts +20 -18
  46. package/assets/packages/cli/src/internal/errors.ts +4 -10
  47. package/assets/packages/cli/src/internal/run-state.ts +4 -0
  48. package/assets/packages/cli/src/internal/run.ts +4 -7
  49. package/assets/packages/cli/src/internal/state-store.ts +22 -14
  50. package/assets/packages/cli/src/internal/workflow-registry.ts +27 -21
  51. package/assets/packages/cli/src/plugin-loader.ts +33 -45
  52. package/assets/packages/cli/src/resources.ts +14 -12
  53. package/assets/packages/core/src/workflow-transition.ts +4 -0
  54. package/assets/packages/sdk/src/api.ts +87 -131
  55. package/assets/packages/sdk/src/files.ts +11 -10
  56. package/assets/packages/sdk/src/index.ts +0 -1
  57. package/assets/packages/sdk/src/resources.ts +2 -2
  58. package/assets/packages/sdk/src/schema.ts +53 -29
  59. package/assets/packages/sdk/src/state-adapter.ts +4 -4
  60. package/assets/tests/workflow-ref.test.ts +121 -77
  61. package/dist/cli.js +20 -36
  62. package/dist/client.d.ts +0 -4
  63. package/dist/client.js +0 -3
  64. package/dist/generated-build-info.d.ts +2 -2
  65. package/dist/generated-build-info.js +2 -2
  66. package/dist/internal/agent-response-tool.d.ts +2 -2
  67. package/dist/internal/agent-response-tool.js +7 -7
  68. package/dist/internal/agents.d.ts +2 -2
  69. package/dist/internal/agents.js +10 -10
  70. package/dist/internal/engine.d.ts +1 -1
  71. package/dist/internal/engine.js +14 -12
  72. package/dist/internal/errors.d.ts +2 -1
  73. package/dist/internal/errors.js +5 -8
  74. package/dist/internal/run-state.js +4 -0
  75. package/dist/internal/run.d.ts +2 -2
  76. package/dist/internal/run.js +10 -6
  77. package/dist/internal/state-store.d.ts +8 -7
  78. package/dist/internal/state-store.js +15 -9
  79. package/dist/internal/workflow-registry.d.ts +14 -6
  80. package/dist/internal/workflow-registry.js +20 -15
  81. package/dist/plugin-loader.d.ts +15 -21
  82. package/dist/plugin-loader.js +35 -47
  83. package/dist/resources.d.ts +1 -1
  84. package/dist/resources.js +15 -13
  85. package/package.json +3 -4
  86. package/assets/packages/sdk/src/seer/config.ts +0 -62
  87. package/assets/packages/sdk/src/seer/index.ts +0 -7
  88. 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 { z } from "zod";
3
- import type { NornResolvedSeerModeConfig } from "./seer/config.ts";
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 z.ZodType = z.ZodType,
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: NornWorkflowRef<ParamsSchema, 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<string, z.ZodType<any, any>>;
47
- export type NornWorkflowTarget<ParamsSchema extends z.ZodType = z.ZodType> = NornWorkflowDeclaration<string, ParamsSchema> | NornWorkflowRef<ParamsSchema>;
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<ParamsSchema extends z.ZodType> =
57
- | NornWorkflowRefSchemaInput<ParamsSchema>
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> = z.input<TWorkflow["params"]>;
68
- export type NornWorkflowParams<TWorkflow extends NornAnyWorkflowDeclaration> = z.output<TWorkflow["params"]>;
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 z.ZodType> = unknown extends z.input<ParamsSchema>
49
+ export type NornWorkflowGate<ParamsSchema extends TSchema> = unknown extends StaticEncode<ParamsSchema>
76
50
  ? NornWorkflowAnyGate
77
- : z.input<ParamsSchema> extends Record<string, unknown>
51
+ : StaticEncode<ParamsSchema> extends Record<string, unknown>
78
52
  ? {
79
53
  readonly enabled: true;
80
- readonly fields?: readonly Extract<keyof z.input<ParamsSchema>, string>[];
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 z.ZodType = z.ZodType,
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: z.ZodType;
78
+ readonly params: TSchema;
105
79
  readonly gate?: NornWorkflowAnyGate;
106
80
  readonly isolation?: NornWorkflowIsolation;
107
81
  } & NornWorkflowInstructions;
108
82
 
109
- export type NornWorkflowStateDefinition<T = unknown, Id extends string = string> = {
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: z.ZodType<T>;
86
+ readonly schema: Schema;
113
87
  };
114
88
 
115
- export type NornWorkflowStateDefinitionInput<T = unknown, Id extends string | undefined = string | undefined> = {
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: z.ZodType<T>;
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
- export type NornWorkflowPluginStateTreeNode = z.ZodType | NornWorkflowStateDefinitionInput | NornWorkflowPluginStateTree;
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 z.ZodType; readonly gate: { readonly fields: infer Fields extends readonly string[] } }
132
- ? Exclude<Fields[number], Extract<keyof z.input<ParamsSchema>, string>>
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 z.input<TWorkflow extends { readonly params: infer ParamsSchema extends z.ZodType } ? ParamsSchema : z.ZodType>, string>[] } };
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 z.ZodType }
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 z.ZodType
161
- ? NornWorkflowStateDefinition<z.output<States[Key]>, JoinPath<PluginId, [...Path, Key & string]>>
162
- : States[Key] extends NornWorkflowStateDefinitionInput<infer Value>
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 z.ZodType | undefined = z.ZodType | undefined,
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, z.ZodType | undefined, Record<string, NornAnyWorkflowDeclaration>, unknown>;
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 z.ZodType | undefined }
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> = NonNullable<NornWorkflowPluginConfigSchema<TManifest>> extends z.ZodType
191
- ? z.output<NonNullable<NornWorkflowPluginConfigSchema<TManifest>>>
192
- : undefined;
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 z.ZodType | undefined,
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 z.ZodType | undefined = undefined,
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<T>(state: NornWorkflowStateDefinition<T>): Promise<T>;
391
- getOptional<T>(state: NornWorkflowStateDefinition<T>): Promise<T | undefined>;
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<T>(state: NornWorkflowStateDefinition<T>, value: T): Promise<void>;
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 = z.object({
438
- path: z.string(),
409
+ export const artifactRefSchema = Type.Object({
410
+ path: Type.String(),
439
411
  });
440
412
 
441
- export type NornArtifactRef = z.output<typeof artifactRefSchema>;
442
-
443
- const emptyWorkflowRefParamsSchema = z.object({});
444
-
445
- export function workflowRefSchema(): z.ZodType<
446
- NornWorkflowRefOutput<typeof emptyWorkflowRefParamsSchema>,
447
- NornWorkflowRefInput<typeof emptyWorkflowRefParamsSchema>
448
- >;
449
- export function workflowRefSchema(options: {
450
- readonly params?: undefined;
451
- }): z.ZodType<
452
- NornWorkflowRefOutput<typeof emptyWorkflowRefParamsSchema>,
453
- NornWorkflowRefInput<typeof emptyWorkflowRefParamsSchema>
454
- >;
455
- export function workflowRefSchema<ParamsSchema extends z.ZodType>(options: NornWorkflowRefSchemaOptions<ParamsSchema>): z.ZodType<
456
- NornWorkflowRefOutput<ParamsSchema>,
457
- NornWorkflowRefInput<ParamsSchema>
458
- >;
459
- export function workflowRefSchema(options?: NornWorkflowRefSchemaOptions): z.ZodType {
460
- const contributedParams = options?.params ?? emptyWorkflowRefParamsSchema;
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 z.ZodType> = {
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 z.ZodType> = NornAgentCreateSessionInput & NornAgentPromptInput<ResponseSchema>;
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 z.ZodType> = {
559
+ export type NornAgentRunResult<ResponseSchema extends TSchema> = {
604
560
  readonly label: string;
605
561
  readonly cwd: string;
606
- readonly response: z.output<ResponseSchema>;
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 z.ZodType>(input: NornAgentPromptInput<ResponseSchema>): Promise<z.output<ResponseSchema>>;
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<TWorkflow extends NornWorkflowTarget<any>>(workflow: TWorkflow, params: NornWorkflowTargetParamsInput<TWorkflow>): NornRunNext;
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 z.ZodType>(input: NornAgentSinglePromptInput<ResponseSchema>): Promise<z.output<ResponseSchema>>;
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 { readonly path: readonly (string | number)[]; readonly code: string; readonly message: string }[];
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
- return { kind: WORKFLOW_DECLARATION_KIND, ...workflow, id, isolation: workflow.isolation ?? { mode: "runWorkspace" } } as unknown as NornQualifiedPluginWorkflow<PluginId, string, TWorkflow>;
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: NornWorkflowPluginStateTreeNode | undefined, path: readonly string[], declaredIds: Set<string>): unknown {
759
- if (!node) return undefined;
760
- if (isZodSchema(node)) return { id: resolveDeclarationId(pluginId, path, undefined, "state", declaredIds), schema: node };
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 (!value || typeof value !== "object") return false;
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 isWorkflowStateDefinitionInput(value: unknown): value is NornWorkflowStateDefinitionInput<unknown> {
782
- if (!value || typeof value !== "object") return false;
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 isZodSchema(value: unknown): value is z.ZodType {
788
- return Boolean(value && typeof value === "object" && typeof (value as { safeParse?: unknown }).safeParse === "function");
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 { z } from "zod";
7
- import { isNodeError } from "@vimhead.dev/norn-core/errors";
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 = z.strictObject({
11
- token: z.uuid(),
12
- pid: z.number().int().positive(),
13
- host: z.string(),
14
- target: z.string(),
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 = ownerSchema.parse(JSON.parse(await readFile(join(input.lockPath, marker), "utf8")));
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
  }
@@ -3,4 +3,3 @@ export { NornFileCoordinator } from "./files.ts";
3
3
  export * from "./resources.ts";
4
4
  export * from "./agent-resource-adapter.ts";
5
5
  export * from "./state-adapter.ts";
6
- export * from "./seer/index.ts";
@@ -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: z.infer<ReturnType<typeof z.json>>;
13
+ readonly configuration: NornJsonValue;
14
14
  initialize(context: NornResourceContext): Promise<T>;
15
15
  };
16
16
 
@@ -1,4 +1,46 @@
1
- import type { NornAnyWorkflowDeclaration } from "./api.ts";
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: unknown): unknown {
13
- let current = schema;
14
- while (true) {
15
- const def = schemaDef(current);
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: unknown): Record<string, unknown> {
25
- const shape = schemaDef(unwrapSchema(schema)).shape;
26
- if (!shape) return {};
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: unknown): string | undefined {
31
- return schemaDef(unwrapSchema(schema)).type;
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: z.toJSONSchema(field.schema, { io: "input" }) })), ...params });
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({