@vimhead.dev/norn-cli 0.1.0-tip.35359392805.1 → 0.1.0-tip.35390859630.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 (111) hide show
  1. package/assets/README.md +17 -26
  2. package/assets/docs/README.md +3 -3
  3. package/assets/docs/agents.md +12 -1
  4. package/assets/docs/cli.md +5 -5
  5. package/assets/docs/composition.md +21 -21
  6. package/assets/docs/persistence.md +7 -10
  7. package/assets/docs/projects.md +30 -18
  8. package/assets/docs/providers.md +1 -1
  9. package/assets/docs/recovery.md +13 -9
  10. package/assets/docs/resources.md +4 -19
  11. package/assets/docs/schemas.md +1 -1
  12. package/assets/docs/workflows.md +95 -7
  13. package/assets/examples/agent-then-analysis/README.md +4 -4
  14. package/assets/examples/agent-then-analysis/input.json +1 -1
  15. package/assets/examples/agent-then-analysis/norn.project.json +1 -1
  16. package/assets/examples/agent-then-analysis/plugin.ts +55 -68
  17. package/assets/examples/caller-selected-continuation/README.md +5 -5
  18. package/assets/examples/caller-selected-continuation/caller.ts +35 -38
  19. package/assets/examples/caller-selected-continuation/input.json +2 -2
  20. package/assets/examples/caller-selected-continuation/norn.project.json +1 -1
  21. package/assets/examples/caller-selected-continuation/producer.ts +15 -23
  22. package/assets/examples/coordinating-multiple-agents/README.md +2 -2
  23. package/assets/examples/coordinating-multiple-agents/input.json +1 -1
  24. package/assets/examples/coordinating-multiple-agents/norn.project.json +1 -1
  25. package/assets/examples/coordinating-multiple-agents/plugin.ts +52 -56
  26. package/assets/examples/coordinating-multiple-agents/queue-adapter.ts +4 -4
  27. package/assets/examples/getting-started/norn.project.json +1 -1
  28. package/assets/examples/getting-started/plugin.ts +16 -26
  29. package/assets/examples/minimal-workflow/README.md +8 -8
  30. package/assets/examples/minimal-workflow/norn.project.json +1 -1
  31. package/assets/examples/minimal-workflow/plugin.ts +11 -25
  32. package/assets/examples/shared-state/README.md +10 -2
  33. package/assets/examples/shared-state/input.json +1 -1
  34. package/assets/examples/shared-state/norn.project.json +1 -1
  35. package/assets/examples/shared-state/plugin.ts +36 -41
  36. package/assets/examples/shared-state/shared-state.ts +75 -0
  37. package/assets/{packages/sdk/src → examples/shared-state}/state-adapter.ts +17 -16
  38. package/assets/examples/worktree-development-loop/README.md +6 -7
  39. package/assets/examples/worktree-development-loop/norn.project.json +1 -1
  40. package/assets/examples/worktree-development-loop/plugin.ts +6 -26
  41. package/assets/examples/worktree-development-loop/scope.ts +4 -0
  42. package/assets/examples/worktree-development-loop/workflows/development-loop/execute.ts +14 -15
  43. package/assets/examples/worktree-development-loop/workflows/development-loop/index.ts +3 -4
  44. package/assets/examples/worktree-development-loop/workflows/development-loop/schema.ts +2 -2
  45. package/assets/examples/worktree-development-loop/workflows/implementation/execute.ts +34 -33
  46. package/assets/examples/worktree-development-loop/workflows/implementation/index.ts +2 -3
  47. package/assets/examples/worktree-development-loop/workflows/implementation/schema.ts +7 -3
  48. package/assets/examples/worktree-development-loop/workflows/planning/execute.ts +23 -16
  49. package/assets/examples/worktree-development-loop/workflows/planning/index.ts +2 -3
  50. package/assets/examples/worktree-development-loop/workflows/planning/schema.ts +4 -2
  51. package/assets/examples/worktree-development-loop/workflows/review/execute.ts +40 -31
  52. package/assets/examples/worktree-development-loop/workflows/review/index.ts +3 -4
  53. package/assets/examples/worktree-development-loop/workflows/review/schema.ts +5 -4
  54. package/assets/examples/worktree-development-loop/workflows/review-router/execute.ts +49 -44
  55. package/assets/examples/worktree-development-loop/workflows/review-router/index.ts +2 -3
  56. package/assets/examples/worktree-development-loop/workflows/review-router/schema.ts +4 -3
  57. package/assets/package.json +1 -1
  58. package/assets/packages/cli/src/cli.ts +35 -34
  59. package/assets/packages/cli/src/client.ts +9 -16
  60. package/assets/packages/cli/src/documentation-intro.ts +1 -1
  61. package/assets/packages/cli/src/generated-build-info.ts +2 -2
  62. package/assets/packages/cli/src/internal/agent-response-tool.ts +3 -3
  63. package/assets/packages/cli/src/internal/engine.ts +38 -62
  64. package/assets/packages/cli/src/internal/errors.ts +4 -4
  65. package/assets/packages/cli/src/internal/launch-request.ts +6 -6
  66. package/assets/packages/cli/src/internal/run-state.ts +31 -21
  67. package/assets/packages/cli/src/internal/run.ts +2 -5
  68. package/assets/packages/cli/src/internal/workflow-registry.ts +114 -111
  69. package/assets/packages/cli/src/workflow-loader.ts +214 -0
  70. package/assets/packages/core/src/workflow-transition.ts +2 -2
  71. package/assets/packages/sdk/src/api.ts +133 -289
  72. package/assets/packages/sdk/src/index.ts +1 -1
  73. package/assets/packages/sdk/src/schema.ts +3 -3
  74. package/assets/tests/workflow-ref.test.ts +50 -51
  75. package/dist/cli.js +33 -32
  76. package/dist/client.d.ts +3 -4
  77. package/dist/client.js +3 -8
  78. package/dist/documentation-intro.js +1 -1
  79. package/dist/generated-build-info.d.ts +2 -2
  80. package/dist/generated-build-info.js +2 -2
  81. package/dist/internal/agent-response-tool.js +3 -3
  82. package/dist/internal/engine.d.ts +4 -8
  83. package/dist/internal/engine.js +36 -49
  84. package/dist/internal/errors.d.ts +3 -3
  85. package/dist/internal/errors.js +1 -1
  86. package/dist/internal/launch-request.d.ts +4 -4
  87. package/dist/internal/launch-request.js +2 -2
  88. package/dist/internal/run-state.d.ts +9 -8
  89. package/dist/internal/run-state.js +29 -20
  90. package/dist/internal/run.d.ts +1 -3
  91. package/dist/internal/run.js +3 -5
  92. package/dist/internal/workflow-registry.d.ts +25 -17
  93. package/dist/internal/workflow-registry.js +107 -72
  94. package/dist/{plugin-loader.d.ts → workflow-loader.d.ts} +7 -8
  95. package/dist/workflow-loader.js +235 -0
  96. package/package.json +2 -2
  97. package/assets/examples/worktree-development-loop/manifest.ts +0 -26
  98. package/assets/examples/worktree-development-loop/state.ts +0 -23
  99. package/assets/examples/worktree-development-loop/workflows/development-loop/declaration.ts +0 -8
  100. package/assets/examples/worktree-development-loop/workflows/implementation/declaration.ts +0 -8
  101. package/assets/examples/worktree-development-loop/workflows/planning/declaration.ts +0 -8
  102. package/assets/examples/worktree-development-loop/workflows/review/declaration.ts +0 -8
  103. package/assets/examples/worktree-development-loop/workflows/review-router/declaration.ts +0 -12
  104. package/assets/packages/cli/src/internal/run-resources.ts +0 -23
  105. package/assets/packages/cli/src/internal/state-store.ts +0 -83
  106. package/assets/packages/cli/src/plugin-loader.ts +0 -400
  107. package/dist/internal/run-resources.d.ts +0 -6
  108. package/dist/internal/run-resources.js +0 -26
  109. package/dist/internal/state-store.d.ts +0 -23
  110. package/dist/internal/state-store.js +0 -103
  111. package/dist/plugin-loader.js +0 -341
@@ -1,9 +1,9 @@
1
1
  import type { CreateAgentSessionOptions, EventBus, PromptOptions } from "@earendil-works/pi-coding-agent";
2
- import { Type, type Static, type StaticDecode, type StaticEncode, type TCodec, type TSchema } from "typebox";
2
+ import { Type, type StaticDecode, type StaticEncode, type TCodec, type TSchema } from "typebox";
3
3
  import type { TLocalizedValidationError } from "typebox/error";
4
4
  import { createWorkflowTransition } from "@vimhead.dev/norn-core/workflow-transition";
5
5
  import { Value } from "typebox/value";
6
- import { isPlainObject, jsonValueSchema } from "./schema.ts";
6
+ import { assertWorkflowMetadata, isPlainObject, jsonValueSchema } from "./schema.ts";
7
7
 
8
8
  const WORKFLOW_DECLARATION_KIND = "norn.workflow";
9
9
 
@@ -23,35 +23,42 @@ export type NornWorkflowIsolation<Mode extends NornWorkflowIsolationMode = NornW
23
23
 
24
24
  export type NornWorkflowDeclaration<
25
25
  Id extends string = string,
26
- ParamsSchema extends TSchema = TSchema,
26
+ ArgsSchema extends TSchema = TSchema,
27
27
  IsolationMode extends NornWorkflowIsolationMode = NornWorkflowIsolationMode,
28
+ ConfigSchema extends TSchema | undefined = TSchema | undefined,
29
+ Scope extends NornWorkflowScopeInfo | undefined = NornWorkflowScopeInfo | undefined,
28
30
  > = {
29
- (params: StaticEncode<ParamsSchema>): NornRunNext;
31
+ (args: StaticEncode<ArgsSchema>): NornRunNext;
30
32
  readonly kind: typeof WORKFLOW_DECLARATION_KIND;
31
33
  readonly id: Id;
32
34
  readonly isEntrypoint: boolean;
33
35
  readonly instructions?: string;
34
- readonly params: ParamsSchema;
35
- readonly gate?: NornWorkflowAnyGate;
36
+ readonly args: ArgsSchema;
37
+ readonly gate?: NornWorkflowGate<ArgsSchema> & {
38
+ describe?(context: NornWorkflowContext<ArgsSchema, IsolationMode, ConfigSchema, Scope>): MaybePromise<string>;
39
+ };
36
40
  readonly isolation: NornWorkflowIsolation<IsolationMode>;
41
+ readonly config?: ConfigSchema;
42
+ readonly scope: Scope;
43
+ execute(context: NornWorkflowContext<ArgsSchema, IsolationMode, ConfigSchema, Scope>): MaybePromise<WorkflowResult>;
37
44
  };
38
45
 
39
- export type NornAnyWorkflowDeclaration = Pick<NornWorkflowDeclaration, keyof NornWorkflowDeclaration> & ((params: never) => NornRunNext);
40
- export type NornWorkflowRefSchemaOptions<ParamsSchema extends TSchema = TSchema> = {
41
- readonly params?: ParamsSchema;
46
+ export type NornAnyWorkflowDeclaration = Pick<NornWorkflowDeclaration, keyof NornWorkflowDeclaration> & ((args: never) => NornRunNext);
47
+ export type NornWorkflowRefSchemaOptions<ArgsSchema extends TSchema = TSchema> = {
48
+ readonly args?: ArgsSchema;
42
49
  };
43
50
  export type NornWorkflowRefInput = StaticEncode<typeof workflowReferenceInputSchema>;
44
- export type NornWorkflowRefOutput<ParamsSchema extends TSchema> = (params: StaticEncode<ParamsSchema> & object) => NornRunNext;
51
+ export type NornWorkflowRefOutput<ArgsSchema extends TSchema> = (args: StaticEncode<ArgsSchema> & object) => NornRunNext;
45
52
 
46
- export type NornWorkflowParamsInput<TWorkflow extends NornAnyWorkflowDeclaration> = StaticEncode<TWorkflow["params"]>;
47
- export type NornWorkflowParams<TWorkflow extends NornAnyWorkflowDeclaration> = StaticDecode<TWorkflow["params"]>;
53
+ export type NornWorkflowArgsInput<TWorkflow extends NornAnyWorkflowDeclaration> = StaticEncode<TWorkflow["args"]>;
54
+ export type NornWorkflowArgs<TWorkflow extends NornAnyWorkflowDeclaration> = StaticDecode<TWorkflow["args"]>;
48
55
 
49
- export type NornWorkflowGate<ParamsSchema extends TSchema> = unknown extends StaticEncode<ParamsSchema>
56
+ export type NornWorkflowGate<ArgsSchema extends TSchema> = unknown extends StaticEncode<ArgsSchema>
50
57
  ? NornWorkflowAnyGate
51
- : StaticEncode<ParamsSchema> extends Record<string, unknown>
58
+ : StaticEncode<ArgsSchema> extends Record<string, unknown>
52
59
  ? {
53
60
  readonly enabled: true;
54
- readonly fields?: readonly Extract<keyof StaticEncode<ParamsSchema>, string>[];
61
+ readonly fields?: readonly Extract<keyof StaticEncode<ArgsSchema>, string>[];
55
62
  }
56
63
  : {
57
64
  readonly enabled: true;
@@ -62,149 +69,96 @@ type NornWorkflowInstructions =
62
69
  | { readonly isEntrypoint: true; readonly instructions: string }
63
70
  | { readonly isEntrypoint: false; readonly instructions?: string };
64
71
 
72
+ type RunForIsolation<Mode extends NornWorkflowIsolationMode> = Mode extends "project" ? NornProjectRun : NornRun;
73
+ type WorkflowConfig<Schema extends TSchema | undefined> = Schema extends TSchema ? StaticDecode<Schema> : undefined;
74
+
75
+ export type NornWorkflowContext<
76
+ ArgsSchema extends TSchema = TSchema,
77
+ Mode extends NornWorkflowIsolationMode = NornWorkflowIsolationMode,
78
+ ConfigSchema extends TSchema | undefined = TSchema | undefined,
79
+ Scope extends NornWorkflowScopeInfo | undefined = NornWorkflowScopeInfo | undefined,
80
+ > = {
81
+ readonly args: StaticDecode<ArgsSchema>;
82
+ readonly config: WorkflowConfig<ConfigSchema>;
83
+ readonly run: RunForIsolation<Mode>;
84
+ } & (Scope extends NornWorkflowScopeInfo ? {
85
+ readonly scope: { readonly id: Scope["id"]; readonly config: WorkflowConfig<Scope["config"]> };
86
+ } : {});
87
+
65
88
  export type NornWorkflowDefinition<
66
- Id extends string | undefined = string | undefined,
67
- ParamsSchema extends TSchema = TSchema,
89
+ Id extends string = string,
90
+ ArgsSchema extends TSchema = TSchema,
68
91
  IsolationMode extends NornWorkflowIsolationMode = NornWorkflowIsolationMode,
92
+ ConfigSchema extends TSchema | undefined = undefined,
93
+ Scope extends NornWorkflowScopeInfo | undefined = undefined,
69
94
  > = {
70
- readonly id?: Id;
71
- readonly params: ParamsSchema;
72
- readonly gate?: NornWorkflowGate<ParamsSchema>;
95
+ readonly id: Id;
96
+ readonly args: ArgsSchema;
97
+ readonly config?: ConfigSchema;
73
98
  readonly isolation?: NornWorkflowIsolation<IsolationMode>;
99
+ readonly gate?: NornWorkflowGate<ArgsSchema> & {
100
+ describe?(context: NornWorkflowContext<ArgsSchema, IsolationMode, ConfigSchema, Scope>): MaybePromise<string>;
101
+ };
102
+ execute(context: NornWorkflowContext<ArgsSchema, IsolationMode, ConfigSchema, Scope>): MaybePromise<WorkflowResult>;
74
103
  } & NornWorkflowInstructions;
75
104
 
76
- export type NornAnyWorkflowDefinition = {
77
- readonly id?: string;
78
- readonly params: TSchema;
79
- readonly gate?: NornWorkflowAnyGate;
80
- readonly isolation?: NornWorkflowIsolation;
81
- } & NornWorkflowInstructions;
82
-
83
- export type NornWorkflowStateDefinition<Schema extends TSchema = TSchema, Id extends string = string> = {
84
- readonly id: Id;
85
- readonly description?: string;
86
- readonly schema: Schema;
87
- };
88
-
89
- export type NornWorkflowStateDefinitionInput<Schema extends TSchema = TSchema, Id extends string | undefined = string | undefined> = {
90
- readonly id?: Id;
91
- readonly description?: string;
92
- readonly schema: Schema;
93
- };
94
-
95
- export type NornWorkflowPluginWorkflows = Record<string, NornAnyWorkflowDefinition>;
96
- export type NornWorkflowPluginStateTree = { readonly [key: string]: NornWorkflowPluginStateTreeNode };
97
- type NornStateSchema = TSchema & ({ readonly "~kind": string } | { readonly "~unsafe": unknown });
98
- export type NornWorkflowPluginStateTreeNode = NornStateSchema | NornWorkflowStateDefinitionInput | NornWorkflowPluginStateTree;
99
-
100
- type JoinPath<Head extends string, Parts extends readonly string[]> = Parts extends readonly []
101
- ? Head
102
- : Parts extends readonly [infer First extends string, ...infer Rest extends string[]]
103
- ? JoinPath<`${Head}.${First}`, Rest>
104
- : string;
105
-
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>>
108
- : never;
109
-
110
- type NornValidatedWorkflowGate<TWorkflow> = [NornInvalidGateFields<TWorkflow>] extends [never]
111
- ? unknown
112
- : { readonly gate: { readonly fields: readonly Extract<keyof StaticEncode<TWorkflow extends { readonly params: infer ParamsSchema extends TSchema } ? ParamsSchema : TSchema>, string>[] } };
113
-
114
- export type NornValidatedWorkflowGates<Workflows> = {
115
- readonly [Key in keyof Workflows]: NornValidatedWorkflowGate<Workflows[Key]>;
116
- };
117
-
118
- export type NornQualifiedPluginWorkflow<
119
- PluginId extends string,
120
- WorkflowKey extends string,
121
- TWorkflow extends NornAnyWorkflowDefinition,
122
- > = TWorkflow extends { readonly params: infer ParamsSchema extends TSchema }
123
- ? NornWorkflowDeclaration<
124
- TWorkflow extends { readonly id: infer ExplicitId extends string } ? ExplicitId : `${PluginId}.${WorkflowKey}`,
125
- ParamsSchema,
126
- TWorkflow extends { readonly isolation: { readonly mode: infer IsolationMode extends NornWorkflowIsolationMode } } ? IsolationMode : "runWorkspace"
127
- >
128
- : never;
129
-
130
- export type NornQualifiedPluginWorkflows<PluginId extends string, Workflows extends NornWorkflowPluginWorkflows> = {
131
- readonly [Key in keyof Workflows]: NornQualifiedPluginWorkflow<PluginId, Key & string, Workflows[Key]>;
132
- };
133
-
134
- export type NornQualifiedPluginStates<PluginId extends string, States, Path extends readonly string[] = []> = {
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]>>
139
- : States[Key] extends NornWorkflowPluginStateTree
140
- ? NornQualifiedPluginStates<PluginId, States[Key], [...Path, Key & string]>
141
- : never;
142
- };
143
-
144
- export type NornWorkflowPluginManifest<
145
- PluginId extends string = string,
146
- ConfigSchema extends TSchema | undefined = TSchema | undefined,
147
- Workflows extends Record<string, NornAnyWorkflowDeclaration> = Record<string, NornAnyWorkflowDeclaration>,
148
- States = undefined,
149
- > = {
150
- readonly id: PluginId;
151
- readonly config?: ConfigSchema;
152
- readonly workflows: Workflows;
153
- readonly states: States;
105
+ export type NornWorkflowScopeInfo = {
106
+ readonly id: string;
107
+ readonly config?: TSchema;
154
108
  };
155
109
 
156
- export type NornAnyWorkflowPluginManifest = NornWorkflowPluginManifest<string, TSchema | undefined, Record<string, NornAnyWorkflowDeclaration>, unknown>;
157
-
158
- export type NornWorkflowPluginConfigSchema<TManifest extends NornAnyWorkflowPluginManifest> = TManifest extends { readonly config?: infer ConfigSchema extends TSchema | undefined }
159
- ? ConfigSchema
160
- : undefined;
110
+ export type NornWorkflowScope<Id extends string, ConfigSchema extends TSchema | undefined> = {
111
+ readonly id: Id;
112
+ readonly config: ConfigSchema;
113
+ workflow<const LocalId extends string, ArgsSchema extends TSchema, const Mode extends NornWorkflowIsolationMode = "runWorkspace", LocalConfig extends TSchema | undefined = undefined>(
114
+ definition: NornWorkflowDefinition<LocalId, ArgsSchema, Mode, LocalConfig, { readonly id: Id; readonly config: ConfigSchema }>,
115
+ ): NornWorkflowDeclaration<`${Id}.${LocalId}`, ArgsSchema, Mode, LocalConfig, { readonly id: Id; readonly config: ConfigSchema }>;
116
+ };
117
+
118
+ export function workflow<
119
+ const Id extends string,
120
+ ArgsSchema extends TSchema,
121
+ const Mode extends NornWorkflowIsolationMode = "runWorkspace",
122
+ ConfigSchema extends TSchema | undefined = undefined,
123
+ >(definition: NornWorkflowDefinition<Id, ArgsSchema, Mode, ConfigSchema>): NornWorkflowDeclaration<Id, ArgsSchema, Mode, ConfigSchema, undefined> {
124
+ return createWorkflow({ definition, scope: undefined });
125
+ }
161
126
 
162
- export type NornWorkflowPluginConfig<TManifest extends NornAnyWorkflowPluginManifest> = NornWorkflowPluginConfigSchema<TManifest> extends undefined
163
- ? undefined
164
- : StaticDecode<NonNullable<NornWorkflowPluginConfigSchema<TManifest>>>;
127
+ function createWorkflow<Id extends string, ArgsSchema extends TSchema, Mode extends NornWorkflowIsolationMode, ConfigSchema extends TSchema | undefined, Scope extends NornWorkflowScopeInfo | undefined>(
128
+ input: { readonly definition: NornWorkflowDefinition<Id, ArgsSchema, Mode, ConfigSchema, Scope>; readonly scope: Scope },
129
+ ): NornWorkflowDeclaration<Id, ArgsSchema, Mode, ConfigSchema, Scope> {
130
+ const { definition, scope } = input;
131
+ assertDeclarationId(definition.id);
132
+ const callable = (args: StaticEncode<ArgsSchema>): NornRunNext => createWorkflowTransition({ workflowId: definition.id, args });
133
+ const result = Object.assign(callable, definition, {
134
+ kind: WORKFLOW_DECLARATION_KIND,
135
+ scope,
136
+ isolation: definition.isolation ?? { mode: "runWorkspace" },
137
+ }) as NornWorkflowDeclaration<Id, ArgsSchema, Mode, ConfigSchema, Scope>;
138
+ if (!isWorkflowDeclaration(result)) throw new Error(`Invalid workflow definition: ${definition.id}`);
139
+ assertWorkflowMetadata(result);
140
+ return result;
141
+ }
165
142
 
166
- export type NornDefinePluginManifestInput<
167
- PluginId extends string,
168
- ConfigSchema extends TSchema | undefined,
169
- Workflows extends NornWorkflowPluginWorkflows,
170
- States extends NornWorkflowPluginStateTree | undefined,
171
- > = {
172
- readonly id: PluginId;
173
- readonly config?: ConfigSchema;
174
- readonly workflows: Workflows & NornValidatedWorkflowGates<Workflows>;
175
- readonly states?: States;
176
- };
177
-
178
- export function definePluginManifest<
179
- const PluginId extends string,
180
- const ConfigSchema extends TSchema | undefined = undefined,
181
- const Workflows extends NornWorkflowPluginWorkflows = NornWorkflowPluginWorkflows,
182
- const States extends NornWorkflowPluginStateTree | undefined = undefined,
183
- >(
184
- input: NornDefinePluginManifestInput<PluginId, ConfigSchema, Workflows, States>,
185
- ): NornWorkflowPluginManifest<
186
- PluginId,
187
- ConfigSchema,
188
- NornQualifiedPluginWorkflows<PluginId, Workflows>,
189
- States extends NornWorkflowPluginStateTree ? NornQualifiedPluginStates<PluginId, States> : undefined
190
- > {
191
- assertLocalDeclarationId(input.id, "plugin");
192
- const declaredIds = new Set<string>();
193
- const workflows = Object.fromEntries(
194
- Object.entries(input.workflows).map(([key, workflow]) => [key, qualifyWorkflow(input.id, key, workflow, declaredIds)]),
195
- ) as NornQualifiedPluginWorkflows<PluginId, Workflows>;
143
+ export function workflowScope<const Id extends string, ConfigSchema extends TSchema | undefined = undefined>(
144
+ input: { readonly id: Id; readonly config?: ConfigSchema },
145
+ ): NornWorkflowScope<Id, ConfigSchema> {
146
+ assertDeclarationId(input.id);
147
+ const scope = { id: input.id, config: input.config as ConfigSchema };
196
148
  return {
197
149
  id: input.id,
198
- config: input.config,
199
- workflows,
200
- states: qualifyStateTree(input.id, input.states, [], declaredIds) as States extends NornWorkflowPluginStateTree ? NornQualifiedPluginStates<PluginId, States> : undefined,
150
+ config: input.config as ConfigSchema,
151
+ workflow(definition) {
152
+ assertDeclarationId(definition.id);
153
+ return createWorkflow({ definition: { ...definition, id: `${input.id}.${definition.id}` }, scope });
154
+ },
201
155
  };
202
156
  }
203
157
 
204
158
  export type NornRunNext = {
205
159
  readonly type: "next";
206
160
  readonly workflowId: string;
207
- readonly params: unknown;
161
+ readonly args: unknown;
208
162
  };
209
163
 
210
164
  export type NornRunOutcomeMetadata = {
@@ -224,29 +178,12 @@ export type NornRunFail = {
224
178
  readonly metadata: NornRunOutcomeMetadata & { readonly summary: string };
225
179
  };
226
180
 
227
- export type NornWorkflowExecutionResult = NornRunNext | NornRunComplete | NornRunFail;
181
+ export type WorkflowResult = NornRunNext | NornRunComplete | NornRunFail;
228
182
 
229
183
  export type NornRunFor<TWorkflow extends NornAnyWorkflowDeclaration> = TWorkflow extends { readonly isolation: { readonly mode: "project" } }
230
184
  ? NornProjectRun
231
185
  : NornRun;
232
186
 
233
- export type NornWorkflowGateImplementation<TWorkflow extends NornAnyWorkflowDeclaration, TConfig> = {
234
- describe(
235
- run: NornRunFor<TWorkflow>,
236
- params: NornWorkflowParams<TWorkflow>,
237
- config: TConfig,
238
- ): MaybePromise<string>;
239
- };
240
-
241
- export type NornWorkflowImplementation<TWorkflow extends NornAnyWorkflowDeclaration, TConfig = unknown> = {
242
- readonly gate?: NornWorkflowGateImplementation<TWorkflow, TConfig>;
243
- execute(
244
- run: NornRunFor<TWorkflow>,
245
- params: NornWorkflowParams<TWorkflow>,
246
- config: TConfig,
247
- ): MaybePromise<NornWorkflowExecutionResult>;
248
- };
249
-
250
187
  export type NornRunStartOptions = {
251
188
  readonly id?: string;
252
189
  readonly name?: string;
@@ -294,7 +231,7 @@ export type NornStoppedRunResult = {
294
231
 
295
232
  export type NornRunInterruption = {
296
233
  readonly workflowId: string;
297
- readonly params: unknown;
234
+ readonly args: unknown;
298
235
  readonly description: string;
299
236
  readonly fields?: readonly string[];
300
237
  };
@@ -358,46 +295,6 @@ export type NornRunCheckpoint = {
358
295
  readonly createdAt: string;
359
296
  };
360
297
 
361
- export type NornWorkflowStateReader = {
362
- get<Schema extends TSchema>(state: NornWorkflowStateDefinition<Schema>): Promise<Static<Schema>>;
363
- getOptional<Schema extends TSchema>(state: NornWorkflowStateDefinition<Schema>): Promise<Static<Schema> | undefined>;
364
- };
365
-
366
- export type NornWorkflowState = NornWorkflowStateReader & {
367
- set<Schema extends TSchema>(state: NornWorkflowStateDefinition<Schema>, value: NoInfer<Static<Schema>>): Promise<void>;
368
- };
369
-
370
- export type NornWorkflowPluginContext = {
371
- readonly cwd: string;
372
- readonly state: NornWorkflowState;
373
- };
374
-
375
- export type NornWorkflowPluginImplementation<TManifest extends NornAnyWorkflowPluginManifest> = {
376
- readonly workflows: {
377
- readonly [Key in keyof TManifest["workflows"]]: NornWorkflowImplementation<TManifest["workflows"][Key], NornWorkflowPluginConfig<TManifest>>;
378
- };
379
- };
380
-
381
- export type NornWorkflowPluginImplementationFactory<TManifest extends NornAnyWorkflowPluginManifest> = (
382
- context: NornWorkflowPluginContext,
383
- ) => NornWorkflowPluginImplementation<TManifest>;
384
-
385
- export type NornWorkflowPluginImplementationInput<TManifest extends NornAnyWorkflowPluginManifest> =
386
- | NornWorkflowPluginImplementation<TManifest>
387
- | NornWorkflowPluginImplementationFactory<TManifest>;
388
-
389
- export type NornWorkflowPlugin<TManifest extends NornAnyWorkflowPluginManifest = NornAnyWorkflowPluginManifest> = {
390
- readonly manifest: TManifest;
391
- readonly implementation: NornWorkflowPluginImplementationInput<TManifest>;
392
- };
393
-
394
- export function definePlugin<TManifest extends NornAnyWorkflowPluginManifest>(
395
- manifest: TManifest,
396
- implementation: NornWorkflowPluginImplementationInput<TManifest>,
397
- ): NornWorkflowPlugin<TManifest> {
398
- return { manifest, implementation };
399
- }
400
-
401
298
  export type NornCommandRunInput = {
402
299
  readonly label: string;
403
300
  readonly command: string | readonly [string, ...string[]];
@@ -412,24 +309,24 @@ export const artifactRefSchema = Type.Object({
412
309
 
413
310
  export type NornArtifactRef = StaticDecode<typeof artifactRefSchema>;
414
311
 
415
- const emptyWorkflowRefParamsSchema = Type.Object({});
312
+ const emptyWorkflowRefArgsSchema = Type.Object({});
416
313
  const workflowReferenceInputSchema = Type.Union([
417
314
  Type.String({ minLength: 1 }),
418
- Type.Object({ workflow: Type.String({ minLength: 1 }), forwardParams: Type.Record(Type.String(), Type.Unknown()) }),
315
+ Type.Object({ workflow: Type.String({ minLength: 1 }), forwardArgs: Type.Record(Type.String(), Type.Unknown()) }),
419
316
  ]);
420
317
 
421
- export function workflowRefSchema<ParamsSchema extends TSchema = typeof emptyWorkflowRefParamsSchema>(options?: NornWorkflowRefSchemaOptions<ParamsSchema>): TCodec<typeof workflowReferenceInputSchema, NornWorkflowRefOutput<ParamsSchema>> {
422
- const contributionSchema = options?.params ?? emptyWorkflowRefParamsSchema;
318
+ export function workflowRefSchema<ArgsSchema extends TSchema = typeof emptyWorkflowRefArgsSchema>(options?: NornWorkflowRefSchemaOptions<ArgsSchema>): TCodec<typeof workflowReferenceInputSchema, NornWorkflowRefOutput<ArgsSchema>> {
319
+ const contributionSchema = options?.args ?? emptyWorkflowRefArgsSchema;
423
320
  return Type.With(Type.Decode(workflowReferenceInputSchema, reference => {
424
321
  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 } });
322
+ const forwardArgs = typeof reference === "string" ? {} : reference.forwardArgs;
323
+ return (args: StaticEncode<ArgsSchema> & object): NornRunNext => {
324
+ Value.Assert(contributionSchema, args);
325
+ if (!isPlainObject(args)) throw new Error("Workflow reference contributions must be objects");
326
+ Value.Assert(jsonValueSchema, args);
327
+ return createWorkflowTransition({ workflowId, args: { ...forwardArgs, ...args } });
431
328
  };
432
- }), { "x-norn-workflow-ref": { contributedParamsSchema: contributionSchema } });
329
+ }), { "x-norn-workflow-ref": { contributedArgsSchema: contributionSchema } });
433
330
  }
434
331
 
435
332
  export type NornLogRef = {
@@ -592,11 +489,10 @@ type NornRunBase = {
592
489
  workspace: string;
593
490
  cwd: string;
594
491
  path(relativePath: string): string;
595
- next(workflowId: string, params: unknown): NornRunNext;
492
+ next(workflowId: string, args: unknown): NornRunNext;
596
493
  complete(metadata?: NornRunOutcomeMetadata): NornRunComplete;
597
494
  fail(metadata: NornRunOutcomeMetadata & { readonly summary: string }): NornRunFail;
598
495
  resources: import("./resources.ts").NornResources;
599
- state: NornWorkflowState;
600
496
  artifacts: {
601
497
  write(path: string, content: string): Promise<NornArtifactRef>;
602
498
  read(ref: NornArtifactRef): Promise<string>;
@@ -613,10 +509,9 @@ type NornRunBase = {
613
509
  };
614
510
  };
615
511
 
616
- export type NornWorkflowPluginInfo = {
617
- readonly id: string;
618
- readonly path?: string;
619
- readonly configPath?: string;
512
+ export type NornWorkflowSource = {
513
+ readonly path: string;
514
+ readonly configPath: string;
620
515
  };
621
516
 
622
517
  export type NornJsonSchema = Record<string, unknown>;
@@ -631,27 +526,31 @@ export type NornRegisteredWorkflowInfo = {
631
526
  readonly instructions?: string;
632
527
  readonly isEntrypoint: boolean;
633
528
  readonly isolation: NornWorkflowIsolation;
634
- readonly plugin?: NornWorkflowPluginInfo;
529
+ readonly scope?: { readonly id: string };
530
+ readonly source?: NornWorkflowSource;
531
+ readonly configKey: string;
635
532
  };
636
533
 
637
534
  export type NornInspectedWorkflowInfo = NornRegisteredWorkflowInfo & {
638
- readonly paramsSchema: NornJsonSchema;
535
+ readonly scope?: { readonly id: string; readonly configKey: string; readonly configSchema: NornJsonSchema | null };
536
+ readonly argsSchema: NornJsonSchema;
537
+ readonly configSchema: NornJsonSchema | null;
639
538
  readonly gate: NornWorkflowGateInfo | null;
640
539
  };
641
540
 
642
- export type NornPluginDiagnostic = {
541
+ export type NornWorkflowDiagnostic = {
643
542
  readonly configPath: string;
644
- readonly pluginPath: string;
645
- readonly pluginId: string | null;
543
+ readonly modulePath: string;
544
+ readonly scopeId: string | null;
646
545
  readonly workflowId: string | null;
647
- readonly stage: "import" | "declaration" | "config" | "implementation" | "duplicate" | "schema";
546
+ readonly stage: "import" | "declaration" | "config" | "duplicate" | "schema";
648
547
  readonly message: string;
649
548
  readonly issues: readonly TLocalizedValidationError[];
650
549
  };
651
550
 
652
551
  export type NornProjectLoadStatus = {
653
552
  readonly isComplete: boolean;
654
- readonly diagnostics: readonly NornPluginDiagnostic[];
553
+ readonly diagnostics: readonly NornWorkflowDiagnostic[];
655
554
  };
656
555
 
657
556
  export type NornWorkflowCatalogInfo = NornProjectLoadStatus & {
@@ -666,7 +565,9 @@ export type NornProjectInspection = NornProjectLoadStatus & {
666
565
  readonly project: NornProjectInfo;
667
566
  };
668
567
 
669
- export type NornProjectPluginInfo = NornWorkflowPluginInfo & {
568
+ export type NornProjectConfigurationInfo = {
569
+ readonly key: string;
570
+ readonly scopeId: string | null;
670
571
  readonly configSchema: NornJsonSchema | null;
671
572
  readonly config: unknown;
672
573
  };
@@ -678,89 +579,32 @@ export type NornProjectInfo = {
678
579
  readonly configPath: string;
679
580
  readonly configRoot: string;
680
581
  readonly configFiles: readonly string[];
681
- readonly plugins: readonly NornProjectPluginInfo[];
582
+ readonly configurations: readonly NornProjectConfigurationInfo[];
583
+ readonly modules: readonly NornWorkflowSource[];
682
584
  };
683
585
 
684
- function assertLocalDeclarationId(id: string, kind: "plugin" | "workflow" | "state"): void {
685
- if (id.length === 0) throw new Error(`Workflow ${kind} id must not be empty`);
686
- if (id.includes(".")) throw new Error(`Workflow ${kind} id must not contain dots: ${id}`);
687
- }
688
-
689
- function resolveDeclarationId(pluginId: string, path: readonly string[], explicitId: string | undefined, kind: "workflow" | "state", declaredIds: Set<string>): string {
690
- for (const segment of path) assertLocalDeclarationId(segment, kind);
691
- const id = explicitId ?? [pluginId, ...path].join(".");
692
- if (explicitId !== undefined) assertPluginQualifiedId(pluginId, explicitId, kind);
693
- if (declaredIds.has(id)) throw new Error(`Duplicate Norn ${kind} id: ${id}`);
694
- declaredIds.add(id);
695
- return id;
696
- }
697
-
698
- function assertPluginQualifiedId(pluginId: string, id: string, kind: "workflow" | "state"): void {
699
- if (!id.startsWith(`${pluginId}.`)) throw new Error(`Explicit Norn ${kind} id must start with ${pluginId}.: ${id}`);
700
- if (id.length === pluginId.length + 1) throw new Error(`Explicit Norn ${kind} id must not be empty after ${pluginId}.`);
701
- }
702
-
703
- function qualifyWorkflow<PluginId extends string, TWorkflow extends NornAnyWorkflowDefinition>(
704
- pluginId: PluginId,
705
- key: string,
706
- workflow: TWorkflow,
707
- declaredIds: Set<string>,
708
- ): NornQualifiedPluginWorkflow<PluginId, string, TWorkflow> {
709
- const id = resolveDeclarationId(pluginId, [key], workflow.id, "workflow", declaredIds);
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>;
712
- }
713
-
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)) {
718
- return { ...node, id: resolveDeclarationId(pluginId, path, node.id, "state", declaredIds) };
719
- }
720
- if (!isPlainObject(node)) throw new Error(`Invalid state declaration: ${[pluginId, ...path].join(".")}`);
721
- return Object.fromEntries(Object.entries(node).map(([key, child]) => [key, qualifyStateTree(pluginId, child, [...path, key], declaredIds)]));
586
+ function assertDeclarationId(id: string): void {
587
+ if (typeof id !== "string" || id.trim().length === 0 || id.split(".").some(segment => segment.length === 0)) throw new Error(`Invalid workflow or scope id: ${id}`);
722
588
  }
723
589
 
724
590
  export function isWorkflowDeclaration(value: unknown): value is NornAnyWorkflowDeclaration {
725
591
  if (typeof value !== "function") return false;
726
- const candidate = value as { kind?: unknown; id?: unknown; instructions?: unknown; isEntrypoint?: unknown; params?: unknown; isolation?: { mode?: unknown } };
592
+ const candidate = value as { kind?: unknown; id?: unknown; instructions?: unknown; isEntrypoint?: unknown; args?: unknown; execute?: unknown; isolation?: { mode?: unknown } };
727
593
  return (
728
594
  candidate.kind === WORKFLOW_DECLARATION_KIND &&
729
595
  typeof candidate.id === "string" &&
730
596
  candidate.id.length > 0 &&
731
597
  (candidate.instructions === undefined || typeof candidate.instructions === "string") &&
732
598
  typeof candidate.isEntrypoint === "boolean" &&
733
- Boolean(candidate.params) &&
599
+ Boolean(candidate.args) &&
600
+ typeof candidate.execute === "function" &&
734
601
  (candidate.isolation?.mode === "runWorkspace" || candidate.isolation?.mode === "project")
735
602
  );
736
603
  }
737
604
 
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");
740
- }
741
-
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);
745
- }
746
-
747
- export function isWorkflowPlugin(value: unknown): value is NornWorkflowPlugin {
748
- if (!value || typeof value !== "object") return false;
749
- const candidate = value as { manifest?: unknown; implementation?: unknown };
750
- return isWorkflowPluginManifest(candidate.manifest) && Boolean(candidate.implementation);
751
- }
752
-
753
- export function isWorkflowPluginManifest(value: unknown): value is NornAnyWorkflowPluginManifest {
754
- if (!value || typeof value !== "object") return false;
755
- const candidate = value as { id?: unknown; workflows?: unknown };
756
- if (typeof candidate.id !== "string" || candidate.id.length === 0) return false;
757
- if (!candidate.workflows || typeof candidate.workflows !== "object") return false;
758
- return Object.values(candidate.workflows).every(isWorkflowDeclaration);
759
- }
760
-
761
605
  export function isWorkflowNext(value: unknown): value is NornRunNext {
762
606
  if (!value || typeof value !== "object") return false;
763
- const candidate = value as { type?: unknown; workflowId?: unknown; params?: unknown };
607
+ const candidate = value as { type?: unknown; workflowId?: unknown; args?: unknown };
764
608
  return candidate.type === "next" && typeof candidate.workflowId === "string" && candidate.workflowId.length > 0;
765
609
  }
766
610
 
@@ -1,5 +1,5 @@
1
+ export type { CreateAgentSessionOptions, EventBus, PromptOptions, ToolDefinition } from "@earendil-works/pi-coding-agent";
1
2
  export * from "./api.ts";
2
3
  export { NornFileCoordinator } from "./files.ts";
3
4
  export * from "./resources.ts";
4
5
  export * from "./agent-resource-adapter.ts";
5
- export * from "./state-adapter.ts";
@@ -25,9 +25,9 @@ function assertWorkflowReferenceAnnotations(schema: unknown): void {
25
25
  if (!isPlainObject(schema)) return;
26
26
  if (Object.hasOwn(schema, "x-norn-workflow-ref")) {
27
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);
28
+ if (!isPlainObject(annotation) || !Object.hasOwn(annotation, "contributedArgsSchema")) throw new Error("Invalid workflow reference annotation");
29
+ Value.Assert(Meta["https://json-schema.org/draft/2020-12/schema"], annotation.contributedArgsSchema);
30
+ assertWorkflowReferenceAnnotations(annotation.contributedArgsSchema);
31
31
  }
32
32
  for (const keyword of ["properties", "patternProperties", "$defs", "definitions", "dependentSchemas"]) {
33
33
  const schemas = schema[keyword];