@vimhead.dev/norn 0.1.0-tip.35359392805.1 → 0.1.0-tip.35436871363.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/dist/api.d.ts CHANGED
@@ -1,5 +1,5 @@
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";
1
+ import type { CreateAgentSessionOptions, EventBus, PromptOptions, ToolDefinition } from "@earendil-works/pi-coding-agent";
2
+ import { Type, type StaticDecode, type StaticEncode, type TCodec, type TSchema } from "typebox";
3
3
  import type { TLocalizedValidationError } from "typebox/error";
4
4
  declare const WORKFLOW_DECLARATION_KIND = "norn.workflow";
5
5
  export type MaybePromise<T> = T | Promise<T>;
@@ -8,31 +8,37 @@ export type NornWorkflowAnyGate = {
8
8
  readonly enabled: true;
9
9
  readonly fields?: readonly string[];
10
10
  };
11
- export type NornWorkflowIsolationMode = "runWorkspace" | "project";
12
- export type NornWorkflowIsolation<Mode extends NornWorkflowIsolationMode = NornWorkflowIsolationMode> = {
13
- readonly mode: Mode;
11
+ export type NornWorkflowPaths = {
12
+ /** Absolute project root. Excluded from run checkpoints and rollback. */
13
+ readonly project: string;
14
+ /** Absolute, initially empty workspace. Saved in run checkpoints and restored on rollback. */
15
+ readonly workspace: string;
14
16
  };
15
- export type NornWorkflowDeclaration<Id extends string = string, ParamsSchema extends TSchema = TSchema, IsolationMode extends NornWorkflowIsolationMode = NornWorkflowIsolationMode> = {
16
- (params: StaticEncode<ParamsSchema>): NornRunNext;
17
+ export type NornWorkflowDeclaration<Id extends string = string, ArgsSchema extends TSchema = TSchema, ConfigSchema extends TSchema | undefined = TSchema | undefined, Scope extends NornWorkflowScopeInfo | undefined = NornWorkflowScopeInfo | undefined> = {
18
+ (args: StaticEncode<ArgsSchema>): NornRunNext;
17
19
  readonly kind: typeof WORKFLOW_DECLARATION_KIND;
18
20
  readonly id: Id;
19
21
  readonly isEntrypoint: boolean;
20
22
  readonly instructions?: string;
21
- readonly params: ParamsSchema;
22
- readonly gate?: NornWorkflowAnyGate;
23
- readonly isolation: NornWorkflowIsolation<IsolationMode>;
23
+ readonly args: ArgsSchema;
24
+ readonly gate?: NornWorkflowGate<ArgsSchema> & {
25
+ describe?(context: NornWorkflowContext<ArgsSchema, ConfigSchema, Scope>): MaybePromise<string>;
26
+ };
27
+ readonly config?: ConfigSchema;
28
+ readonly scope: Scope;
29
+ execute(context: NornWorkflowContext<ArgsSchema, ConfigSchema, Scope>): MaybePromise<WorkflowResult>;
24
30
  };
25
- export type NornAnyWorkflowDeclaration = Pick<NornWorkflowDeclaration, keyof NornWorkflowDeclaration> & ((params: never) => NornRunNext);
26
- export type NornWorkflowRefSchemaOptions<ParamsSchema extends TSchema = TSchema> = {
27
- readonly params?: ParamsSchema;
31
+ export type NornAnyWorkflowDeclaration = Pick<NornWorkflowDeclaration, keyof NornWorkflowDeclaration> & ((args: never) => NornRunNext);
32
+ export type NornWorkflowRefSchemaOptions<ArgsSchema extends TSchema = TSchema> = {
33
+ readonly args?: ArgsSchema;
28
34
  };
29
35
  export type NornWorkflowRefInput = StaticEncode<typeof workflowReferenceInputSchema>;
30
- export type NornWorkflowRefOutput<ParamsSchema extends TSchema> = (params: StaticEncode<ParamsSchema> & object) => NornRunNext;
31
- export type NornWorkflowParamsInput<TWorkflow extends NornAnyWorkflowDeclaration> = StaticEncode<TWorkflow["params"]>;
32
- export type NornWorkflowParams<TWorkflow extends NornAnyWorkflowDeclaration> = StaticDecode<TWorkflow["params"]>;
33
- export type NornWorkflowGate<ParamsSchema extends TSchema> = unknown extends StaticEncode<ParamsSchema> ? NornWorkflowAnyGate : StaticEncode<ParamsSchema> extends Record<string, unknown> ? {
36
+ export type NornWorkflowRefOutput<ArgsSchema extends TSchema> = (args: StaticEncode<ArgsSchema> & object) => NornRunNext;
37
+ export type NornWorkflowArgsInput<TWorkflow extends NornAnyWorkflowDeclaration> = StaticEncode<TWorkflow["args"]>;
38
+ export type NornWorkflowArgs<TWorkflow extends NornAnyWorkflowDeclaration> = StaticDecode<TWorkflow["args"]>;
39
+ export type NornWorkflowGate<ArgsSchema extends TSchema> = unknown extends StaticEncode<ArgsSchema> ? NornWorkflowAnyGate : StaticEncode<ArgsSchema> extends Record<string, unknown> ? {
34
40
  readonly enabled: true;
35
- readonly fields?: readonly Extract<keyof StaticEncode<ParamsSchema>, string>[];
41
+ readonly fields?: readonly Extract<keyof StaticEncode<ArgsSchema>, string>[];
36
42
  } : {
37
43
  readonly enabled: true;
38
44
  readonly fields?: never;
@@ -44,98 +50,54 @@ type NornWorkflowInstructions = {
44
50
  readonly isEntrypoint: false;
45
51
  readonly instructions?: string;
46
52
  };
47
- export type NornWorkflowDefinition<Id extends string | undefined = string | undefined, ParamsSchema extends TSchema = TSchema, IsolationMode extends NornWorkflowIsolationMode = NornWorkflowIsolationMode> = {
48
- readonly id?: Id;
49
- readonly params: ParamsSchema;
50
- readonly gate?: NornWorkflowGate<ParamsSchema>;
51
- readonly isolation?: NornWorkflowIsolation<IsolationMode>;
52
- } & NornWorkflowInstructions;
53
- export type NornAnyWorkflowDefinition = {
54
- readonly id?: string;
55
- readonly params: TSchema;
56
- readonly gate?: NornWorkflowAnyGate;
57
- readonly isolation?: NornWorkflowIsolation;
58
- } & NornWorkflowInstructions;
59
- export type NornWorkflowStateDefinition<Schema extends TSchema = TSchema, Id extends string = string> = {
60
- readonly id: Id;
61
- readonly description?: string;
62
- readonly schema: Schema;
63
- };
64
- export type NornWorkflowStateDefinitionInput<Schema extends TSchema = TSchema, Id extends string | undefined = string | undefined> = {
65
- readonly id?: Id;
66
- readonly description?: string;
67
- readonly schema: Schema;
68
- };
69
- export type NornWorkflowPluginWorkflows = Record<string, NornAnyWorkflowDefinition>;
70
- export type NornWorkflowPluginStateTree = {
71
- readonly [key: string]: NornWorkflowPluginStateTreeNode;
72
- };
73
- type NornStateSchema = TSchema & ({
74
- readonly "~kind": string;
75
- } | {
76
- readonly "~unsafe": unknown;
77
- });
78
- export type NornWorkflowPluginStateTreeNode = NornStateSchema | NornWorkflowStateDefinitionInput | NornWorkflowPluginStateTree;
79
- type JoinPath<Head extends string, Parts extends readonly string[]> = Parts extends readonly [] ? Head : Parts extends readonly [infer First extends string, ...infer Rest extends string[]] ? JoinPath<`${Head}.${First}`, Rest> : string;
80
- type NornInvalidGateFields<TWorkflow> = TWorkflow extends {
81
- readonly params: infer ParamsSchema extends TSchema;
82
- readonly gate: {
83
- readonly fields: infer Fields extends readonly string[];
53
+ type WorkflowConfig<Schema extends TSchema | undefined> = Schema extends TSchema ? StaticDecode<Schema> : undefined;
54
+ export type NornWorkflowContext<ArgsSchema extends TSchema = TSchema, ConfigSchema extends TSchema | undefined = TSchema | undefined, Scope extends NornWorkflowScopeInfo | undefined = NornWorkflowScopeInfo | undefined> = {
55
+ readonly args: StaticDecode<ArgsSchema>;
56
+ readonly config: WorkflowConfig<ConfigSchema>;
57
+ readonly paths: NornWorkflowPaths;
58
+ readonly run: NornRun;
59
+ } & (Scope extends NornWorkflowScopeInfo ? {
60
+ readonly scope: {
61
+ readonly id: Scope["id"];
62
+ readonly config: WorkflowConfig<Scope["config"]>;
84
63
  };
85
- } ? Exclude<Fields[number], Extract<keyof StaticEncode<ParamsSchema>, string>> : never;
86
- type NornValidatedWorkflowGate<TWorkflow> = [NornInvalidGateFields<TWorkflow>] extends [never] ? unknown : {
87
- readonly gate: {
88
- readonly fields: readonly Extract<keyof StaticEncode<TWorkflow extends {
89
- readonly params: infer ParamsSchema extends TSchema;
90
- } ? ParamsSchema : TSchema>, string>[];
91
- };
92
- };
93
- export type NornValidatedWorkflowGates<Workflows> = {
94
- readonly [Key in keyof Workflows]: NornValidatedWorkflowGate<Workflows[Key]>;
95
- };
96
- export type NornQualifiedPluginWorkflow<PluginId extends string, WorkflowKey extends string, TWorkflow extends NornAnyWorkflowDefinition> = TWorkflow extends {
97
- readonly params: infer ParamsSchema extends TSchema;
98
- } ? NornWorkflowDeclaration<TWorkflow extends {
99
- readonly id: infer ExplicitId extends string;
100
- } ? ExplicitId : `${PluginId}.${WorkflowKey}`, ParamsSchema, TWorkflow extends {
101
- readonly isolation: {
102
- readonly mode: infer IsolationMode extends NornWorkflowIsolationMode;
64
+ } : {});
65
+ export type NornWorkflowDefinition<Id extends string = string, ArgsSchema extends TSchema = TSchema, ConfigSchema extends TSchema | undefined = undefined, Scope extends NornWorkflowScopeInfo | undefined = undefined> = {
66
+ readonly id: Id;
67
+ readonly args: ArgsSchema;
68
+ readonly config?: ConfigSchema;
69
+ readonly gate?: NornWorkflowGate<ArgsSchema> & {
70
+ describe?(context: NornWorkflowContext<ArgsSchema, ConfigSchema, Scope>): MaybePromise<string>;
103
71
  };
104
- } ? IsolationMode : "runWorkspace"> : never;
105
- export type NornQualifiedPluginWorkflows<PluginId extends string, Workflows extends NornWorkflowPluginWorkflows> = {
106
- readonly [Key in keyof Workflows]: NornQualifiedPluginWorkflow<PluginId, Key & string, Workflows[Key]>;
107
- };
108
- export type NornQualifiedPluginStates<PluginId extends string, States, Path extends readonly string[] = []> = {
109
- readonly [Key in keyof States]: States[Key] extends NornStateSchema ? NornWorkflowStateDefinition<States[Key], JoinPath<PluginId, [...Path, Key & string]>> : States[Key] extends NornWorkflowStateDefinitionInput<infer Schema extends NornStateSchema> ? NornWorkflowStateDefinition<Schema, States[Key] extends {
110
- readonly id: infer Id extends string;
111
- } ? Id : JoinPath<PluginId, [...Path, Key & string]>> : States[Key] extends NornWorkflowPluginStateTree ? NornQualifiedPluginStates<PluginId, States[Key], [...Path, Key & string]> : never;
72
+ execute(context: NornWorkflowContext<ArgsSchema, ConfigSchema, Scope>): MaybePromise<WorkflowResult>;
73
+ } & NornWorkflowInstructions;
74
+ export type NornWorkflowScopeInfo = {
75
+ readonly id: string;
76
+ readonly config?: TSchema;
112
77
  };
113
- export type NornWorkflowPluginManifest<PluginId extends string = string, ConfigSchema extends TSchema | undefined = TSchema | undefined, Workflows extends Record<string, NornAnyWorkflowDeclaration> = Record<string, NornAnyWorkflowDeclaration>, States = undefined> = {
114
- readonly id: PluginId;
115
- readonly config?: ConfigSchema;
116
- readonly workflows: Workflows;
117
- readonly states: States;
118
- };
119
- export type NornAnyWorkflowPluginManifest = NornWorkflowPluginManifest<string, TSchema | undefined, Record<string, NornAnyWorkflowDeclaration>, unknown>;
120
- export type NornWorkflowPluginConfigSchema<TManifest extends NornAnyWorkflowPluginManifest> = TManifest extends {
121
- readonly config?: infer ConfigSchema extends TSchema | undefined;
122
- } ? ConfigSchema : undefined;
123
- export type NornWorkflowPluginConfig<TManifest extends NornAnyWorkflowPluginManifest> = NornWorkflowPluginConfigSchema<TManifest> extends undefined ? undefined : StaticDecode<NonNullable<NornWorkflowPluginConfigSchema<TManifest>>>;
124
- export type NornDefinePluginManifestInput<PluginId extends string, ConfigSchema extends TSchema | undefined, Workflows extends NornWorkflowPluginWorkflows, States extends NornWorkflowPluginStateTree | undefined> = {
125
- readonly id: PluginId;
78
+ export type NornWorkflowScope<Id extends string, ConfigSchema extends TSchema | undefined> = {
79
+ readonly id: Id;
80
+ readonly config: ConfigSchema;
81
+ workflow<const LocalId extends string, ArgsSchema extends TSchema, LocalConfig extends TSchema | undefined = undefined>(definition: NornWorkflowDefinition<LocalId, ArgsSchema, LocalConfig, {
82
+ readonly id: Id;
83
+ readonly config: ConfigSchema;
84
+ }>): NornWorkflowDeclaration<`${Id}.${LocalId}`, ArgsSchema, LocalConfig, {
85
+ readonly id: Id;
86
+ readonly config: ConfigSchema;
87
+ }>;
88
+ };
89
+ export declare function workflow<const Id extends string, ArgsSchema extends TSchema, ConfigSchema extends TSchema | undefined = undefined>(definition: NornWorkflowDefinition<Id, ArgsSchema, ConfigSchema>): NornWorkflowDeclaration<Id, ArgsSchema, ConfigSchema, undefined>;
90
+ export declare function workflowScope<const Id extends string, ConfigSchema extends TSchema | undefined = undefined>(input: {
91
+ readonly id: Id;
126
92
  readonly config?: ConfigSchema;
127
- readonly workflows: Workflows & NornValidatedWorkflowGates<Workflows>;
128
- readonly states?: States;
129
- };
130
- export declare function definePluginManifest<const PluginId extends string, const ConfigSchema extends TSchema | undefined = undefined, const Workflows extends NornWorkflowPluginWorkflows = NornWorkflowPluginWorkflows, const States extends NornWorkflowPluginStateTree | undefined = undefined>(input: NornDefinePluginManifestInput<PluginId, ConfigSchema, Workflows, States>): NornWorkflowPluginManifest<PluginId, ConfigSchema, NornQualifiedPluginWorkflows<PluginId, Workflows>, States extends NornWorkflowPluginStateTree ? NornQualifiedPluginStates<PluginId, States> : undefined>;
93
+ }): NornWorkflowScope<Id, ConfigSchema>;
131
94
  export type NornRunNext = {
132
95
  readonly type: "next";
133
96
  readonly workflowId: string;
134
- readonly params: unknown;
97
+ readonly args: unknown;
135
98
  };
136
99
  export type NornRunOutcomeMetadata = {
137
100
  readonly summary?: string;
138
- readonly artifacts?: Record<string, NornArtifactRef>;
139
101
  readonly logs?: Record<string, NornLogRef>;
140
102
  readonly data?: Record<string, unknown>;
141
103
  };
@@ -149,19 +111,7 @@ export type NornRunFail = {
149
111
  readonly summary: string;
150
112
  };
151
113
  };
152
- export type NornWorkflowExecutionResult = NornRunNext | NornRunComplete | NornRunFail;
153
- export type NornRunFor<TWorkflow extends NornAnyWorkflowDeclaration> = TWorkflow extends {
154
- readonly isolation: {
155
- readonly mode: "project";
156
- };
157
- } ? NornProjectRun : NornRun;
158
- export type NornWorkflowGateImplementation<TWorkflow extends NornAnyWorkflowDeclaration, TConfig> = {
159
- describe(run: NornRunFor<TWorkflow>, params: NornWorkflowParams<TWorkflow>, config: TConfig): MaybePromise<string>;
160
- };
161
- export type NornWorkflowImplementation<TWorkflow extends NornAnyWorkflowDeclaration, TConfig = unknown> = {
162
- readonly gate?: NornWorkflowGateImplementation<TWorkflow, TConfig>;
163
- execute(run: NornRunFor<TWorkflow>, params: NornWorkflowParams<TWorkflow>, config: TConfig): MaybePromise<NornWorkflowExecutionResult>;
164
- };
114
+ export type WorkflowResult = NornRunNext | NornRunComplete | NornRunFail;
165
115
  export type NornRunStartOptions = {
166
116
  readonly id?: string;
167
117
  readonly name?: string;
@@ -206,7 +156,7 @@ export type NornStoppedRunResult = {
206
156
  };
207
157
  export type NornRunInterruption = {
208
158
  readonly workflowId: string;
209
- readonly params: unknown;
159
+ readonly args: unknown;
210
160
  readonly description: string;
211
161
  readonly fields?: readonly string[];
212
162
  };
@@ -239,6 +189,7 @@ export type NornRunInfo = {
239
189
  readonly id: string;
240
190
  readonly name: string;
241
191
  readonly path: string;
192
+ readonly paths: NornWorkflowPaths;
242
193
  readonly entrypointWorkflowId: string;
243
194
  readonly currentWorkflowId?: string;
244
195
  readonly status: NornRunStatus;
@@ -261,46 +212,19 @@ export type NornRunCheckpoint = {
261
212
  readonly message: string;
262
213
  readonly createdAt: string;
263
214
  };
264
- export type NornWorkflowStateReader = {
265
- get<Schema extends TSchema>(state: NornWorkflowStateDefinition<Schema>): Promise<Static<Schema>>;
266
- getOptional<Schema extends TSchema>(state: NornWorkflowStateDefinition<Schema>): Promise<Static<Schema> | undefined>;
267
- };
268
- export type NornWorkflowState = NornWorkflowStateReader & {
269
- set<Schema extends TSchema>(state: NornWorkflowStateDefinition<Schema>, value: NoInfer<Static<Schema>>): Promise<void>;
270
- };
271
- export type NornWorkflowPluginContext = {
272
- readonly cwd: string;
273
- readonly state: NornWorkflowState;
274
- };
275
- export type NornWorkflowPluginImplementation<TManifest extends NornAnyWorkflowPluginManifest> = {
276
- readonly workflows: {
277
- readonly [Key in keyof TManifest["workflows"]]: NornWorkflowImplementation<TManifest["workflows"][Key], NornWorkflowPluginConfig<TManifest>>;
278
- };
279
- };
280
- export type NornWorkflowPluginImplementationFactory<TManifest extends NornAnyWorkflowPluginManifest> = (context: NornWorkflowPluginContext) => NornWorkflowPluginImplementation<TManifest>;
281
- export type NornWorkflowPluginImplementationInput<TManifest extends NornAnyWorkflowPluginManifest> = NornWorkflowPluginImplementation<TManifest> | NornWorkflowPluginImplementationFactory<TManifest>;
282
- export type NornWorkflowPlugin<TManifest extends NornAnyWorkflowPluginManifest = NornAnyWorkflowPluginManifest> = {
283
- readonly manifest: TManifest;
284
- readonly implementation: NornWorkflowPluginImplementationInput<TManifest>;
285
- };
286
- export declare function definePlugin<TManifest extends NornAnyWorkflowPluginManifest>(manifest: TManifest, implementation: NornWorkflowPluginImplementationInput<TManifest>): NornWorkflowPlugin<TManifest>;
287
215
  export type NornCommandRunInput = {
288
216
  readonly label: string;
289
217
  readonly command: string | readonly [string, ...string[]];
290
- readonly cwd?: string;
218
+ readonly cwd: string;
291
219
  readonly env?: Record<string, string>;
292
220
  readonly timeoutMs?: number;
293
221
  };
294
- export declare const artifactRefSchema: Type.TObject<{
295
- path: Type.TString;
296
- }>;
297
- export type NornArtifactRef = StaticDecode<typeof artifactRefSchema>;
298
- declare const emptyWorkflowRefParamsSchema: Type.TObject<{}>;
222
+ declare const emptyWorkflowRefArgsSchema: Type.TObject<{}>;
299
223
  declare const workflowReferenceInputSchema: Type.TUnion<[Type.TString, Type.TObject<{
300
224
  workflow: Type.TString;
301
- forwardParams: Type.TRecord<"^.*$", Type.TUnknown>;
225
+ forwardArgs: Type.TRecord<"^.*$", Type.TUnknown>;
302
226
  }>]>;
303
- export declare function workflowRefSchema<ParamsSchema extends TSchema = typeof emptyWorkflowRefParamsSchema>(options?: NornWorkflowRefSchemaOptions<ParamsSchema>): TCodec<typeof workflowReferenceInputSchema, NornWorkflowRefOutput<ParamsSchema>>;
227
+ export declare function workflowRefSchema<ArgsSchema extends TSchema = typeof emptyWorkflowRefArgsSchema>(options?: NornWorkflowRefSchemaOptions<ArgsSchema>): TCodec<typeof workflowReferenceInputSchema, NornWorkflowRefOutput<ArgsSchema>>;
304
228
  export type NornLogRef = {
305
229
  readonly id: string;
306
230
  };
@@ -319,9 +243,9 @@ export type NornAgentBeforeSessionStartContext = {
319
243
  readonly events: EventBus;
320
244
  };
321
245
  export type NornAgentCreateSessionInput = {
322
- readonly resourceAdapters?: readonly import("./agent-resource-adapter.ts").NornAgentResourceAdapter[];
246
+ readonly customTools?: readonly ToolDefinition[];
323
247
  readonly label: string;
324
- readonly cwd?: string;
248
+ readonly cwd: string;
325
249
  readonly tools?: string[];
326
250
  readonly beforeSessionStart?: (context: NornAgentBeforeSessionStartContext) => MaybePromise<void>;
327
251
  readonly model?: CreateAgentSessionOptions["model"];
@@ -433,27 +357,13 @@ export type NornAgentSession = {
433
357
  prompt<ResponseSchema extends TSchema>(input: NornAgentPromptInput<ResponseSchema>): Promise<StaticDecode<ResponseSchema>>;
434
358
  dispose(): Promise<void>;
435
359
  };
436
- export type NornRun = NornRunBase;
437
- export type NornProjectRun = NornRunBase & {
438
- projectRoot: string;
439
- projectPath(relativePath: string): string;
440
- };
441
- type NornRunBase = {
360
+ export type NornRun = {
442
361
  id: string;
443
- workspace: string;
444
- cwd: string;
445
- path(relativePath: string): string;
446
- next(workflowId: string, params: unknown): NornRunNext;
362
+ next(workflowId: string, args: unknown): NornRunNext;
447
363
  complete(metadata?: NornRunOutcomeMetadata): NornRunComplete;
448
364
  fail(metadata: NornRunOutcomeMetadata & {
449
365
  readonly summary: string;
450
366
  }): NornRunFail;
451
- resources: import("./resources.ts").NornResources;
452
- state: NornWorkflowState;
453
- artifacts: {
454
- write(path: string, content: string): Promise<NornArtifactRef>;
455
- read(ref: NornArtifactRef): Promise<string>;
456
- };
457
367
  logs: {
458
368
  read(log: NornLogRef): Promise<string>;
459
369
  };
@@ -465,10 +375,9 @@ type NornRunBase = {
465
375
  prompt<ResponseSchema extends TSchema>(input: NornAgentSinglePromptInput<ResponseSchema>): Promise<StaticDecode<ResponseSchema>>;
466
376
  };
467
377
  };
468
- export type NornWorkflowPluginInfo = {
469
- readonly id: string;
470
- readonly path?: string;
471
- readonly configPath?: string;
378
+ export type NornWorkflowSource = {
379
+ readonly path: string;
380
+ readonly configPath: string;
472
381
  };
473
382
  export type NornJsonSchema = Record<string, unknown>;
474
383
  export type NornWorkflowGateInfo = {
@@ -479,25 +388,34 @@ export type NornRegisteredWorkflowInfo = {
479
388
  readonly id: string;
480
389
  readonly instructions?: string;
481
390
  readonly isEntrypoint: boolean;
482
- readonly isolation: NornWorkflowIsolation;
483
- readonly plugin?: NornWorkflowPluginInfo;
391
+ readonly scope?: {
392
+ readonly id: string;
393
+ };
394
+ readonly source?: NornWorkflowSource;
395
+ readonly configKey: string;
484
396
  };
485
397
  export type NornInspectedWorkflowInfo = NornRegisteredWorkflowInfo & {
486
- readonly paramsSchema: NornJsonSchema;
398
+ readonly scope?: {
399
+ readonly id: string;
400
+ readonly configKey: string;
401
+ readonly configSchema: NornJsonSchema | null;
402
+ };
403
+ readonly argsSchema: NornJsonSchema;
404
+ readonly configSchema: NornJsonSchema | null;
487
405
  readonly gate: NornWorkflowGateInfo | null;
488
406
  };
489
- export type NornPluginDiagnostic = {
407
+ export type NornWorkflowDiagnostic = {
490
408
  readonly configPath: string;
491
- readonly pluginPath: string;
492
- readonly pluginId: string | null;
409
+ readonly modulePath: string;
410
+ readonly scopeId: string | null;
493
411
  readonly workflowId: string | null;
494
- readonly stage: "import" | "declaration" | "config" | "implementation" | "duplicate" | "schema";
412
+ readonly stage: "import" | "declaration" | "config" | "duplicate" | "schema";
495
413
  readonly message: string;
496
414
  readonly issues: readonly TLocalizedValidationError[];
497
415
  };
498
416
  export type NornProjectLoadStatus = {
499
417
  readonly isComplete: boolean;
500
- readonly diagnostics: readonly NornPluginDiagnostic[];
418
+ readonly diagnostics: readonly NornWorkflowDiagnostic[];
501
419
  };
502
420
  export type NornWorkflowCatalogInfo = NornProjectLoadStatus & {
503
421
  readonly workflows: readonly NornRegisteredWorkflowInfo[];
@@ -508,7 +426,9 @@ export type NornWorkflowInspection = NornProjectLoadStatus & {
508
426
  export type NornProjectInspection = NornProjectLoadStatus & {
509
427
  readonly project: NornProjectInfo;
510
428
  };
511
- export type NornProjectPluginInfo = NornWorkflowPluginInfo & {
429
+ export type NornProjectConfigurationInfo = {
430
+ readonly key: string;
431
+ readonly scopeId: string | null;
512
432
  readonly configSchema: NornJsonSchema | null;
513
433
  readonly config: unknown;
514
434
  };
@@ -519,11 +439,10 @@ export type NornProjectInfo = {
519
439
  readonly configPath: string;
520
440
  readonly configRoot: string;
521
441
  readonly configFiles: readonly string[];
522
- readonly plugins: readonly NornProjectPluginInfo[];
442
+ readonly configurations: readonly NornProjectConfigurationInfo[];
443
+ readonly modules: readonly NornWorkflowSource[];
523
444
  };
524
445
  export declare function isWorkflowDeclaration(value: unknown): value is NornAnyWorkflowDeclaration;
525
- export declare function isWorkflowPlugin(value: unknown): value is NornWorkflowPlugin;
526
- export declare function isWorkflowPluginManifest(value: unknown): value is NornAnyWorkflowPluginManifest;
527
446
  export declare function isWorkflowNext(value: unknown): value is NornRunNext;
528
447
  export declare function isWorkflowComplete(value: unknown): value is NornRunComplete;
529
448
  export declare function isWorkflowFail(value: unknown): value is NornRunFail;
package/dist/api.js CHANGED
@@ -4,103 +4,65 @@ import { Type } from "typebox";
4
4
  // ../core/src/workflow-transition.ts
5
5
  function createWorkflowTransition(input) {
6
6
  if (typeof input.workflowId !== "string" || input.workflowId.trim().length === 0) throw new Error("Workflow transition requires a nonempty workflow ID");
7
- return { type: "next", workflowId: input.workflowId, params: input.params };
7
+ return { type: "next", workflowId: input.workflowId, args: input.args };
8
8
  }
9
9
 
10
10
  // src/api.ts
11
11
  import { Value } from "typebox/value";
12
- import { isPlainObject, jsonValueSchema } from "./schema.js";
12
+ import { assertWorkflowMetadata, isPlainObject, jsonValueSchema } from "./schema.js";
13
13
  var WORKFLOW_DECLARATION_KIND = "norn.workflow";
14
- function definePluginManifest(input) {
15
- assertLocalDeclarationId(input.id, "plugin");
16
- const declaredIds = /* @__PURE__ */ new Set();
17
- const workflows = Object.fromEntries(
18
- Object.entries(input.workflows).map(([key, workflow]) => [key, qualifyWorkflow(input.id, key, workflow, declaredIds)])
19
- );
14
+ function workflow(definition) {
15
+ return createWorkflow({ definition, scope: void 0 });
16
+ }
17
+ function createWorkflow(input) {
18
+ const { definition, scope } = input;
19
+ assertDeclarationId(definition.id);
20
+ const callable = (args) => createWorkflowTransition({ workflowId: definition.id, args });
21
+ const result = Object.assign(callable, definition, {
22
+ kind: WORKFLOW_DECLARATION_KIND,
23
+ scope
24
+ });
25
+ if (!isWorkflowDeclaration(result)) throw new Error(`Invalid workflow definition: ${definition.id}`);
26
+ assertWorkflowMetadata(result);
27
+ return result;
28
+ }
29
+ function workflowScope(input) {
30
+ assertDeclarationId(input.id);
31
+ const scope = { id: input.id, config: input.config };
20
32
  return {
21
33
  id: input.id,
22
34
  config: input.config,
23
- workflows,
24
- states: qualifyStateTree(input.id, input.states, [], declaredIds)
35
+ workflow(definition) {
36
+ assertDeclarationId(definition.id);
37
+ return createWorkflow({ definition: { ...definition, id: `${input.id}.${definition.id}` }, scope });
38
+ }
25
39
  };
26
40
  }
27
- function definePlugin(manifest, implementation) {
28
- return { manifest, implementation };
29
- }
30
- var artifactRefSchema = Type.Object({
31
- path: Type.String()
32
- });
33
- var emptyWorkflowRefParamsSchema = Type.Object({});
41
+ var emptyWorkflowRefArgsSchema = Type.Object({});
34
42
  var workflowReferenceInputSchema = Type.Union([
35
43
  Type.String({ minLength: 1 }),
36
- Type.Object({ workflow: Type.String({ minLength: 1 }), forwardParams: Type.Record(Type.String(), Type.Unknown()) })
44
+ Type.Object({ workflow: Type.String({ minLength: 1 }), forwardArgs: Type.Record(Type.String(), Type.Unknown()) })
37
45
  ]);
38
46
  function workflowRefSchema(options) {
39
- const contributionSchema = options?.params ?? emptyWorkflowRefParamsSchema;
47
+ const contributionSchema = options?.args ?? emptyWorkflowRefArgsSchema;
40
48
  return Type.With(Type.Decode(workflowReferenceInputSchema, (reference) => {
41
49
  const workflowId = typeof reference === "string" ? reference : reference.workflow;
42
- const forwardParams = typeof reference === "string" ? {} : reference.forwardParams;
43
- return (params) => {
44
- Value.Assert(contributionSchema, params);
45
- if (!isPlainObject(params)) throw new Error("Workflow reference contributions must be objects");
46
- Value.Assert(jsonValueSchema, params);
47
- return createWorkflowTransition({ workflowId, params: { ...forwardParams, ...params } });
50
+ const forwardArgs = typeof reference === "string" ? {} : reference.forwardArgs;
51
+ return (args) => {
52
+ Value.Assert(contributionSchema, args);
53
+ if (!isPlainObject(args)) throw new Error("Workflow reference contributions must be objects");
54
+ Value.Assert(jsonValueSchema, args);
55
+ return createWorkflowTransition({ workflowId, args: { ...forwardArgs, ...args } });
48
56
  };
49
- }), { "x-norn-workflow-ref": { contributedParamsSchema: contributionSchema } });
50
- }
51
- function assertLocalDeclarationId(id, kind) {
52
- if (id.length === 0) throw new Error(`Workflow ${kind} id must not be empty`);
53
- if (id.includes(".")) throw new Error(`Workflow ${kind} id must not contain dots: ${id}`);
54
- }
55
- function resolveDeclarationId(pluginId, path, explicitId, kind, declaredIds) {
56
- for (const segment of path) assertLocalDeclarationId(segment, kind);
57
- const id = explicitId ?? [pluginId, ...path].join(".");
58
- if (explicitId !== void 0) assertPluginQualifiedId(pluginId, explicitId, kind);
59
- if (declaredIds.has(id)) throw new Error(`Duplicate Norn ${kind} id: ${id}`);
60
- declaredIds.add(id);
61
- return id;
62
- }
63
- function assertPluginQualifiedId(pluginId, id, kind) {
64
- if (!id.startsWith(`${pluginId}.`)) throw new Error(`Explicit Norn ${kind} id must start with ${pluginId}.: ${id}`);
65
- if (id.length === pluginId.length + 1) throw new Error(`Explicit Norn ${kind} id must not be empty after ${pluginId}.`);
57
+ }), { "x-norn-workflow-ref": { contributedArgsSchema: contributionSchema } });
66
58
  }
67
- function qualifyWorkflow(pluginId, key, workflow, declaredIds) {
68
- const id = resolveDeclarationId(pluginId, [key], workflow.id, "workflow", declaredIds);
69
- const declaration = (params) => createWorkflowTransition({ workflowId: id, params });
70
- return Object.assign(declaration, { ...workflow, kind: WORKFLOW_DECLARATION_KIND, id, isolation: workflow.isolation ?? { mode: "runWorkspace" } });
71
- }
72
- function qualifyStateTree(pluginId, node, path, declaredIds) {
73
- if (node === void 0) return void 0;
74
- if (isTypeboxSchema(node)) return { id: resolveDeclarationId(pluginId, path, void 0, "state", declaredIds), schema: node };
75
- if (path.length > 0 && isWorkflowStateDefinitionInput(node)) {
76
- return { ...node, id: resolveDeclarationId(pluginId, path, node.id, "state", declaredIds) };
77
- }
78
- if (!isPlainObject(node)) throw new Error(`Invalid state declaration: ${[pluginId, ...path].join(".")}`);
79
- return Object.fromEntries(Object.entries(node).map(([key, child]) => [key, qualifyStateTree(pluginId, child, [...path, key], declaredIds)]));
59
+ function assertDeclarationId(id) {
60
+ if (typeof id !== "string" || id.trim().length === 0 || id.split(".").some((segment) => segment.length === 0)) throw new Error(`Invalid workflow or scope id: ${id}`);
80
61
  }
81
62
  function isWorkflowDeclaration(value) {
82
63
  if (typeof value !== "function") return false;
83
64
  const candidate = value;
84
- return candidate.kind === WORKFLOW_DECLARATION_KIND && typeof candidate.id === "string" && candidate.id.length > 0 && (candidate.instructions === void 0 || typeof candidate.instructions === "string") && typeof candidate.isEntrypoint === "boolean" && Boolean(candidate.params) && (candidate.isolation?.mode === "runWorkspace" || candidate.isolation?.mode === "project");
85
- }
86
- function isTypeboxSchema(value) {
87
- return Type.IsUnsafe(value) || Boolean(value && typeof value === "object" && "~kind" in value && typeof value["~kind"] === "string");
88
- }
89
- function isWorkflowStateDefinitionInput(value) {
90
- if (!isPlainObject(value)) return false;
91
- return (value.id === void 0 || typeof value.id === "string") && isTypeboxSchema(value.schema);
92
- }
93
- function isWorkflowPlugin(value) {
94
- if (!value || typeof value !== "object") return false;
95
- const candidate = value;
96
- return isWorkflowPluginManifest(candidate.manifest) && Boolean(candidate.implementation);
97
- }
98
- function isWorkflowPluginManifest(value) {
99
- if (!value || typeof value !== "object") return false;
100
- const candidate = value;
101
- if (typeof candidate.id !== "string" || candidate.id.length === 0) return false;
102
- if (!candidate.workflows || typeof candidate.workflows !== "object") return false;
103
- return Object.values(candidate.workflows).every(isWorkflowDeclaration);
65
+ return candidate.kind === WORKFLOW_DECLARATION_KIND && typeof candidate.id === "string" && candidate.id.length > 0 && (candidate.instructions === void 0 || typeof candidate.instructions === "string") && typeof candidate.isEntrypoint === "boolean" && Boolean(candidate.args) && typeof candidate.execute === "function";
104
66
  }
105
67
  function isWorkflowNext(value) {
106
68
  if (!value || typeof value !== "object") return false;
@@ -118,14 +80,11 @@ function isWorkflowFail(value) {
118
80
  return candidate.type === "fail" && typeof candidate.metadata?.summary === "string" && candidate.metadata.summary.length > 0;
119
81
  }
120
82
  export {
121
- artifactRefSchema,
122
- definePlugin,
123
- definePluginManifest,
124
83
  isWorkflowComplete,
125
84
  isWorkflowDeclaration,
126
85
  isWorkflowFail,
127
86
  isWorkflowNext,
128
- isWorkflowPlugin,
129
- isWorkflowPluginManifest,
130
- workflowRefSchema
87
+ workflow,
88
+ workflowRefSchema,
89
+ workflowScope
131
90
  };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,2 @@
1
+ export type { CreateAgentSessionOptions, EventBus, PromptOptions, ToolDefinition } from "@earendil-works/pi-coding-agent";
1
2
  export * from "./api.ts";
2
- export { NornFileCoordinator } from "./files.ts";
3
- export * from "./resources.ts";
4
- export * from "./agent-resource-adapter.ts";
5
- export * from "./state-adapter.ts";
package/dist/index.js CHANGED
@@ -1,9 +1,2 @@
1
1
  // src/index.ts
2
2
  export * from "./api.js";
3
- import { NornFileCoordinator } from "./files.js";
4
- export * from "./resources.js";
5
- export * from "./agent-resource-adapter.js";
6
- export * from "./state-adapter.js";
7
- export {
8
- NornFileCoordinator
9
- };
package/dist/schema.js CHANGED
@@ -23,9 +23,9 @@ function assertWorkflowReferenceAnnotations(schema) {
23
23
  if (!isPlainObject(schema)) return;
24
24
  if (Object.hasOwn(schema, "x-norn-workflow-ref")) {
25
25
  const annotation = schema["x-norn-workflow-ref"];
26
- if (!isPlainObject(annotation) || !Object.hasOwn(annotation, "contributedParamsSchema")) throw new Error("Invalid workflow reference annotation");
27
- Value.Assert(Meta["https://json-schema.org/draft/2020-12/schema"], annotation.contributedParamsSchema);
28
- assertWorkflowReferenceAnnotations(annotation.contributedParamsSchema);
26
+ if (!isPlainObject(annotation) || !Object.hasOwn(annotation, "contributedArgsSchema")) throw new Error("Invalid workflow reference annotation");
27
+ Value.Assert(Meta["https://json-schema.org/draft/2020-12/schema"], annotation.contributedArgsSchema);
28
+ assertWorkflowReferenceAnnotations(annotation.contributedArgsSchema);
29
29
  }
30
30
  for (const keyword of ["properties", "patternProperties", "$defs", "definitions", "dependentSchemas"]) {
31
31
  const schemas = schema[keyword];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vimhead.dev/norn",
3
- "version": "0.1.0-tip.35359392805.1",
3
+ "version": "0.1.0-tip.35436871363.1",
4
4
  "description": "TypeScript SDK for building agent-driven and code-driven Norn workflows.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -26,10 +26,6 @@
26
26
  "types": "./dist/index.d.ts",
27
27
  "import": "./dist/index.js"
28
28
  },
29
- "./files": {
30
- "types": "./dist/files.d.ts",
31
- "import": "./dist/files.js"
32
- },
33
29
  "./schema": {
34
30
  "types": "./dist/schema.d.ts",
35
31
  "import": "./dist/schema.js"
@@ -1,12 +0,0 @@
1
- import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
2
- export type NornAgentResourceBinding = {
3
- readonly tools: readonly ToolDefinition[];
4
- dispose(): Promise<void>;
5
- };
6
- export type NornAgentResourceAdapter = {
7
- readonly name: string;
8
- bind(context: {
9
- readonly runId: string;
10
- readonly label: string;
11
- }): Promise<NornAgentResourceBinding>;
12
- };
File without changes
package/dist/files.d.ts DELETED
@@ -1,17 +0,0 @@
1
- export declare class NornFileCoordinator {
2
- private readonly input;
3
- private readonly lockRoot;
4
- constructor(input: {
5
- readonly lockRoot: string;
6
- readonly waitTimeoutMs: number;
7
- });
8
- withExclusiveLock<T>(path: string, operation: (lockedPath: string) => Promise<T>): Promise<T>;
9
- readText(path: string): Promise<string>;
10
- writeText(path: string, content: string): Promise<void>;
11
- private withCleanup;
12
- private resolveTarget;
13
- private acquire;
14
- private reclaimDeadOwner;
15
- private removeEmptyLock;
16
- }
17
- export declare function createRunFileCoordinator(runRoot: string): NornFileCoordinator;
package/dist/files.js DELETED
@@ -1,162 +0,0 @@
1
- // ../core/src/atomic-files.ts
2
- import { randomUUID } from "node:crypto";
3
- import { chmod, mkdir, rename, rm, stat, writeFile } from "node:fs/promises";
4
- import { dirname } from "node:path";
5
-
6
- // ../core/src/errors.ts
7
- function isNodeError(error) {
8
- return error instanceof Error && "code" in error;
9
- }
10
-
11
- // ../core/src/atomic-files.ts
12
- async function writeTextAtomically(path, content) {
13
- await mkdir(dirname(path), { recursive: true });
14
- let existingMode;
15
- try {
16
- existingMode = (await stat(path)).mode & 511;
17
- } catch (error) {
18
- if (!isNodeError(error) || error.code !== "ENOENT") throw error;
19
- }
20
- const tmpPath = `${path}.${randomUUID()}.tmp`;
21
- try {
22
- await writeFile(tmpPath, content, { encoding: "utf8", mode: existingMode });
23
- if (existingMode !== void 0) await chmod(tmpPath, existingMode);
24
- await rename(tmpPath, path);
25
- } catch (error) {
26
- await rm(tmpPath, { force: true }).catch(() => void 0);
27
- throw error;
28
- }
29
- }
30
-
31
- // src/files.ts
32
- import { createHash, randomUUID as randomUUID2 } from "node:crypto";
33
- import { lstat, mkdir as mkdir2, mkdtemp, readFile, readdir, realpath, rename as rename2, rm as rm2, rmdir, unlink, writeFile as writeFile2 } from "node:fs/promises";
34
- import { hostname } from "node:os";
35
- import { basename, dirname as dirname2, join, resolve } from "node:path";
36
- import { setTimeout as delay } from "node:timers/promises";
37
- import { Type } from "typebox";
38
- import { Value } from "typebox/value";
39
- var ownerSchema = Type.Object({
40
- token: Type.String({ format: "uuid" }),
41
- pid: Type.Integer({ exclusiveMinimum: 0 }),
42
- host: Type.String(),
43
- target: Type.String()
44
- }, { additionalProperties: false });
45
- var NornFileCoordinator = class {
46
- constructor(input) {
47
- this.input = input;
48
- if (!Number.isSafeInteger(input.waitTimeoutMs) || input.waitTimeoutMs <= 0) throw new Error("Lock wait timeout must be a positive integer");
49
- this.lockRoot = resolve(input.lockRoot);
50
- }
51
- input;
52
- lockRoot;
53
- async withExclusiveLock(path, operation) {
54
- const target = await this.resolveTarget(path);
55
- await mkdir2(this.lockRoot, { recursive: true, mode: 448 });
56
- const key = createHash("sha256").update(target).digest("hex");
57
- const lockPath = join(this.lockRoot, `${key}.lock`);
58
- const stagingPath = await mkdtemp(join(this.lockRoot, `${key}.pending-`));
59
- const token = randomUUID2();
60
- const marker = `${token}.json`;
61
- return this.withCleanup({
62
- operation: async () => {
63
- await writeFile2(join(stagingPath, marker), JSON.stringify({ token, pid: process.pid, host: hostname(), target }), { mode: 384 });
64
- await this.acquire({ stagingPath, lockPath, target });
65
- return this.withCleanup({
66
- operation: () => operation(target),
67
- cleanup: async () => {
68
- await unlink(join(lockPath, marker));
69
- await this.removeEmptyLock(lockPath);
70
- }
71
- });
72
- },
73
- cleanup: () => rm2(stagingPath, { recursive: true, force: true })
74
- });
75
- }
76
- async readText(path) {
77
- return this.withExclusiveLock(path, (lockedPath) => readFile(lockedPath, "utf8"));
78
- }
79
- async writeText(path, content) {
80
- await mkdir2(dirname2(path), { recursive: true });
81
- await this.withExclusiveLock(path, (lockedPath) => writeTextAtomically(lockedPath, content));
82
- }
83
- async withCleanup(input) {
84
- let result;
85
- try {
86
- result = await input.operation();
87
- } catch (error) {
88
- try {
89
- await input.cleanup();
90
- } catch (cleanupError) {
91
- throw new AggregateError([error, cleanupError], "File operation and lock cleanup failed");
92
- }
93
- throw error;
94
- }
95
- await input.cleanup();
96
- return result;
97
- }
98
- async resolveTarget(path) {
99
- try {
100
- return await realpath(path);
101
- } catch (error) {
102
- if (!isNodeError(error) || error.code !== "ENOENT") throw error;
103
- const entry = await lstat(path).catch((error2) => {
104
- if (isNodeError(error2) && error2.code === "ENOENT") return void 0;
105
- throw error2;
106
- });
107
- if (entry?.isSymbolicLink()) throw new Error(`Cannot lock a dangling symbolic link: ${path}`);
108
- return join(await realpath(dirname2(path)), basename(path));
109
- }
110
- }
111
- async acquire(input) {
112
- const deadline = Date.now() + this.input.waitTimeoutMs;
113
- while (true) {
114
- try {
115
- await rename2(input.stagingPath, input.lockPath);
116
- return;
117
- } catch (error) {
118
- if (!isNodeError(error) || !["ENOTEMPTY", "EEXIST"].includes(error.code ?? "")) throw error;
119
- }
120
- await this.reclaimDeadOwner(input);
121
- if (Date.now() >= deadline) throw new Error(`Timed out waiting for file lock: ${input.target}`);
122
- await delay(10);
123
- }
124
- }
125
- async reclaimDeadOwner(input) {
126
- try {
127
- const entries = await readdir(input.lockPath);
128
- if (entries.length === 0) return;
129
- if (entries.length !== 1) throw new Error(`Invalid file lock ownership: ${input.lockPath}`);
130
- const marker = entries[0];
131
- const owner = Value.Parse(ownerSchema, JSON.parse(await readFile(join(input.lockPath, marker), "utf8")));
132
- if (marker !== `${owner.token}.json` || owner.target !== input.target || owner.host !== hostname()) {
133
- throw new Error(`Incompatible file lock ownership: ${input.lockPath}`);
134
- }
135
- try {
136
- process.kill(owner.pid, 0);
137
- return;
138
- } catch (error) {
139
- if (isNodeError(error) && error.code === "EPERM") return;
140
- if (!isNodeError(error) || error.code !== "ESRCH") throw error;
141
- }
142
- await unlink(join(input.lockPath, marker));
143
- await this.removeEmptyLock(input.lockPath);
144
- } catch (error) {
145
- if (!isNodeError(error) || error.code !== "ENOENT") throw error;
146
- }
147
- }
148
- async removeEmptyLock(path) {
149
- try {
150
- await rmdir(path);
151
- } catch (error) {
152
- if (!isNodeError(error) || !["ENOENT", "ENOTEMPTY", "EEXIST"].includes(error.code ?? "")) throw error;
153
- }
154
- }
155
- };
156
- function createRunFileCoordinator(runRoot) {
157
- return new NornFileCoordinator({ lockRoot: join(runRoot, "locks"), waitTimeoutMs: 3e4 });
158
- }
159
- export {
160
- NornFileCoordinator,
161
- createRunFileCoordinator
162
- };
@@ -1,17 +0,0 @@
1
- import type { NornFileCoordinator } from "./files.ts";
2
- import type { NornJsonValue } from "./schema.ts";
3
- export type NornResourceContext = {
4
- readonly mode: "create" | "open";
5
- readonly directory: string;
6
- readonly files: NornFileCoordinator;
7
- };
8
- export type NornResourceDefinition<T> = {
9
- readonly name: string;
10
- readonly kind: string;
11
- readonly configuration: NornJsonValue;
12
- initialize(context: NornResourceContext): Promise<T>;
13
- };
14
- export type NornResources = {
15
- readonly files: NornFileCoordinator;
16
- ensure<T>(definition: NornResourceDefinition<T>): Promise<T>;
17
- };
package/dist/resources.js DELETED
File without changes
@@ -1,10 +0,0 @@
1
- import type { NornAgentResourceAdapter } from "./agent-resource-adapter.ts";
2
- import type { NornWorkflowState, NornWorkflowStateDefinition } from "./api.ts";
3
- export type NornStateFieldAccess = {
4
- readonly field: NornWorkflowStateDefinition;
5
- readonly access: "read" | "write" | "read-write";
6
- };
7
- export declare function StateAdapter(input: {
8
- readonly state: NornWorkflowState;
9
- readonly fields: readonly NornStateFieldAccess[];
10
- }): NornAgentResourceAdapter;
@@ -1,70 +0,0 @@
1
- // src/state-adapter.ts
2
- import { defineTool } from "@earendil-works/pi-coding-agent";
3
- import { createHash } from "node:crypto";
4
- import { Type } from "typebox";
5
- import { inspectSchema } from "./schema.js";
6
- var pageParameters = {
7
- offset: Type.Integer({ minimum: 0, description: "Zero-based UTF-16 offset into the serialized JSON. Start at 0." }),
8
- limit: Type.Integer({ minimum: 1, maximum: 1e4 })
9
- };
10
- function StateAdapter(input) {
11
- const fields = new Map(input.fields.map((grant) => [grant.field.id, grant]));
12
- if (fields.size !== input.fields.length || fields.size === 0) throw new Error("State attachment requires unique, explicitly selected fields");
13
- const selectField = (key, access) => {
14
- const grant = fields.get(key);
15
- if (!grant || grant.access !== access && grant.access !== "read-write") throw new Error(`State ${access} is not attached: ${key}`);
16
- return grant.field;
17
- };
18
- return {
19
- name: "norn.state",
20
- async bind() {
21
- return {
22
- tools: [
23
- defineTool({
24
- name: "norn_state_list",
25
- label: "Attached workflow state",
26
- description: "List only attached workflow-state field IDs, permissions and value schemas. JSON is paginated; use nextOffset until null.",
27
- parameters: Type.Object(pageParameters),
28
- async execute(_id, params) {
29
- return serializePage({ value: [...fields.values()].map(({ field, access }) => ({ id: field.id, access, schema: inspectSchema(field.schema) })), ...params });
30
- }
31
- }),
32
- defineTool({
33
- name: "norn_state_get",
34
- label: "Read workflow state",
35
- description: "Read a selected workflow-state field. Unset fields return isSet:false. JSON is paginated; concurrent writes can change later pages, so compare revision before combining pages.",
36
- parameters: Type.Object({ key: Type.String(), ...pageParameters }),
37
- async execute(_id, params) {
38
- const value = await input.state.getOptional(selectField(params.key, "read"));
39
- return serializePage({ value: value === void 0 ? { isSet: false } : { isSet: true, value }, ...params });
40
- }
41
- }),
42
- defineTool({
43
- name: "norn_state_set",
44
- label: "Write workflow state",
45
- description: "Set an explicitly writable workflow-state field. Validate the value against its schema from norn_state_list. A get followed by set is not a transaction.",
46
- parameters: Type.Object({ key: Type.String(), value: Type.Unknown() }),
47
- async execute(_id, params, signal) {
48
- signal?.throwIfAborted();
49
- const field = selectField(params.key, "write");
50
- await input.state.set(field, params.value);
51
- return { content: [{ type: "text", text: "Workflow state saved." }], details: {} };
52
- }
53
- })
54
- ],
55
- async dispose() {
56
- }
57
- };
58
- }
59
- };
60
- }
61
- function serializePage(input) {
62
- const serialized = JSON.stringify(input.value);
63
- if (!Number.isInteger(input.offset) || input.offset < 0 || !Number.isInteger(input.limit) || input.limit < 1 || input.limit > 1e4) throw new Error("Invalid state output page");
64
- const end = Math.min(serialized.length, input.offset + input.limit);
65
- const details = { text: serialized.slice(input.offset, end), nextOffset: end < serialized.length ? end : null, revision: createHash("sha256").update(serialized).digest("hex") };
66
- return { content: [{ type: "text", text: JSON.stringify(details) }], details };
67
- }
68
- export {
69
- StateAdapter
70
- };