@vimhead.dev/norn-cli 0.1.0-tip.35436871363.1 → 0.1.0-tip.35570530940.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 (39) hide show
  1. package/assets/README.md +35 -17
  2. package/assets/docs/agents.md +4 -4
  3. package/assets/docs/cli.md +3 -3
  4. package/assets/docs/recovery.md +1 -1
  5. package/assets/docs/workflows.md +22 -16
  6. package/assets/examples/agent-then-analysis/plugin.ts +9 -10
  7. package/assets/examples/caller-selected-continuation/caller.ts +5 -5
  8. package/assets/examples/caller-selected-continuation/producer.ts +3 -4
  9. package/assets/examples/coordinating-multiple-agents/README.md +1 -1
  10. package/assets/examples/coordinating-multiple-agents/plugin.ts +12 -13
  11. package/assets/examples/getting-started/README.md +24 -9
  12. package/assets/examples/getting-started/plugin.ts +27 -13
  13. package/assets/examples/minimal-workflow/README.md +2 -2
  14. package/assets/examples/minimal-workflow/plugin.ts +2 -3
  15. package/assets/examples/shared-state/plugin.ts +6 -7
  16. package/assets/examples/worktree-development-loop/scope.ts +1 -1
  17. package/assets/examples/worktree-development-loop/workflows/development-loop/execute.ts +4 -5
  18. package/assets/examples/worktree-development-loop/workflows/development-loop/repository.ts +3 -3
  19. package/assets/examples/worktree-development-loop/workflows/implementation/execute.ts +6 -7
  20. package/assets/examples/worktree-development-loop/workflows/planning/execute.ts +4 -5
  21. package/assets/examples/worktree-development-loop/workflows/review/execute.ts +6 -7
  22. package/assets/examples/worktree-development-loop/workflows/review-router/execute.ts +2 -3
  23. package/assets/package.json +1 -1
  24. package/assets/packages/cli/src/generated-build-info.ts +2 -2
  25. package/assets/packages/cli/src/internal/engine.ts +15 -15
  26. package/assets/packages/cli/src/internal/{run.ts → execution-context.ts} +23 -31
  27. package/assets/packages/cli/src/internal/workflow-registry.ts +11 -6
  28. package/assets/packages/sdk/src/api.ts +49 -46
  29. package/assets/packages/sdk/src/schema.ts +5 -5
  30. package/assets/tests/workflow-ref.test.ts +4 -3
  31. package/dist/generated-build-info.d.ts +2 -2
  32. package/dist/generated-build-info.js +2 -2
  33. package/dist/internal/engine.d.ts +1 -1
  34. package/dist/internal/engine.js +13 -13
  35. package/dist/internal/{run.d.ts → execution-context.d.ts} +8 -13
  36. package/dist/internal/{run.js → execution-context.js} +11 -15
  37. package/dist/internal/workflow-registry.d.ts +2 -2
  38. package/dist/internal/workflow-registry.js +8 -5
  39. package/package.json +2 -2
@@ -12,7 +12,7 @@ import { NornRunLease } from "./run-lease.js";
12
12
  import { NornRunLogger } from "./run-log.js";
13
13
  import { assertRunVersion, getRunInfo, mergeInterruptedWorkflowArgs, NornRunStateStore, resolveRunRoot } from "./run-state.js";
14
14
  import { NornRunStore, runCurrentRoot } from "./run-store.js";
15
- import { NornRunContext } from "./run.js";
15
+ import { NornExecutionContext } from "./execution-context.js";
16
16
  import { NornWorkflowRegistry } from "./workflow-registry.js";
17
17
  var RUNS_DIR_NAME = ".norn";
18
18
  var MANIFEST_FILE_NAME = "manifest.json";
@@ -127,12 +127,12 @@ var NornEngine = class {
127
127
  for (let step = 1; step <= 1e3; step++) {
128
128
  throwIfRunAborted(session.activeRun);
129
129
  if (shouldPauseForGate(currentStep)) {
130
- const description = await this.registry.describeGate({ workflow: currentStep.workflow, run: session.run, paths: session.paths, args: currentStep.args, configOverride: session.state.currentState().configOverride });
130
+ const description = await this.registry.describeGate({ workflow: currentStep.workflow, execution: session.execution, paths: session.paths, args: currentStep.args, configOverride: session.state.currentState().configOverride });
131
131
  const interruption = { description, fields: currentStep.workflow.gate?.fields };
132
132
  await session.state.interruptCurrent(currentStep.args, interruption);
133
133
  await recordRunEvent(session, { type: "run.interrupted", workflowId: currentStep.workflow.id });
134
134
  await commitRunBoundary(session, `run interrupted: ${currentStep.workflow.id}`);
135
- return interruptedLaunchResult({ id: session.run.id, name: session.state.currentState().name, workspace: session.paths.workspace, cwd: session.cwd }, currentStep.workflow, currentStep.args, interruption);
135
+ return interruptedLaunchResult({ id: session.execution.run.id, name: session.state.currentState().name, workspace: session.paths.workspace, cwd: session.cwd }, currentStep.workflow, currentStep.args, interruption);
136
136
  }
137
137
  await session.state.startStep(toRunStateStep(currentStep));
138
138
  const stepResult = await this.executeWorkflowStep(session, currentStep);
@@ -141,12 +141,12 @@ var NornEngine = class {
141
141
  await session.state.completeRun(stepResult.workflow.id, stepResult.metadata);
142
142
  await recordRunEvent(session, { type: "run.completed", workflowId: stepResult.workflow.id, metadata: stepResult.metadata });
143
143
  await commitRunBoundary(session, `run completed: ${stepResult.workflow.id}`);
144
- return { status: "completed", id: session.run.id, name: session.state.currentState().name, workspace: session.paths.workspace, cwd: session.cwd, workflowId: stepResult.workflow.id, metadata: stepResult.metadata };
144
+ return { status: "completed", id: session.execution.run.id, name: session.state.currentState().name, workspace: session.paths.workspace, cwd: session.cwd, workflowId: stepResult.workflow.id, metadata: stepResult.metadata };
145
145
  }
146
146
  if (stepResult.type === "fail") {
147
147
  await session.state.failRun(stepResult.workflow.id, stepResult.metadata);
148
148
  await recordRunEvent(session, { type: "run.failed", workflowId: stepResult.workflow.id, metadata: stepResult.metadata });
149
- return { status: "failed", id: session.run.id, name: session.state.currentState().name, workspace: session.paths.workspace, cwd: session.cwd, workflowId: stepResult.workflow.id, metadata: stepResult.metadata };
149
+ return { status: "failed", id: session.execution.run.id, name: session.state.currentState().name, workspace: session.paths.workspace, cwd: session.cwd, workflowId: stepResult.workflow.id, metadata: stepResult.metadata };
150
150
  }
151
151
  const nextStep = this.nextWorkflowStep(stepResult);
152
152
  await session.state.completeWithNext(currentStep.workflow.id, toRunStateStep(nextStep));
@@ -159,7 +159,7 @@ var NornEngine = class {
159
159
  if (isRunStopped(session, error)) {
160
160
  await session.state.stopCurrent();
161
161
  await recordRunEvent(session, { type: "run.stopped", workflowId: currentStep.workflow.id });
162
- return { status: "stopped", id: session.run.id, name: session.state.currentState().name, workspace: session.paths.workspace, cwd: session.cwd, workflowId: currentStep.workflow.id };
162
+ return { status: "stopped", id: session.execution.run.id, name: session.state.currentState().name, workspace: session.paths.workspace, cwd: session.cwd, workflowId: currentStep.workflow.id };
163
163
  }
164
164
  await session.state.failCurrent(errorMessage(error));
165
165
  await recordRunEvent(session, { type: "run.failed", workflowId: currentStep.workflow.id, error: errorMessage(error) });
@@ -174,7 +174,7 @@ var NornEngine = class {
174
174
  try {
175
175
  await assertWorkspaceBoundary(session, session.paths.workspace);
176
176
  await recordRunEvent(session, { type: "workflow.started", workflowId: step.workflow.id });
177
- const result = await this.registry.execute({ workflow: step.workflow, run: session.run, paths: session.paths, args: step.args, configOverride: session.state.currentState().configOverride });
177
+ const result = await this.registry.execute({ workflow: step.workflow, execution: session.execution, paths: session.paths, args: step.args, configOverride: session.state.currentState().configOverride });
178
178
  await assertWorkspaceBoundary(session, session.paths.workspace);
179
179
  const durationMs = Date.now() - startedAtMs;
180
180
  if (result.type === "complete") await recordRunEvent(session, { type: "workflow.completed", workflowId: result.workflow.id, durationMs, metadata: result.metadata });
@@ -224,7 +224,7 @@ var NornEngine = class {
224
224
  initialCwd: cwd,
225
225
  startedAt
226
226
  } });
227
- const run = await this.buildRun({ id, currentRoot, paths, signal: activeRun.controller.signal, logger });
227
+ const execution = await this.buildExecutionContext({ id, currentRoot, paths, signal: activeRun.controller.signal, logger });
228
228
  const state = await NornRunStateStore.create(runRoot, {
229
229
  projectRoot: paths.project,
230
230
  id,
@@ -241,7 +241,7 @@ var NornEngine = class {
241
241
  },
242
242
  startedAt
243
243
  });
244
- const session = { runRoot, cwd, run, paths, state, lease, runStore, logger, activeRun };
244
+ const session = { runRoot, cwd, execution, paths, state, lease, runStore, logger, activeRun };
245
245
  await logger.record({ type: "run.started", workflowId: workflow.id, cwd, workspace });
246
246
  await commitRunBoundary(session, `run started: ${workflow.id}`);
247
247
  return session;
@@ -261,19 +261,19 @@ var NornEngine = class {
261
261
  const currentRoot = runCurrentRoot(runRoot);
262
262
  const logger = await NornRunLogger.load(join(currentRoot, MANIFEST_FILE_NAME), createRunFileCoordinator(runRoot));
263
263
  const paths = { project: currentState.projectRoot ?? resolve(runRoot, "../../.."), workspace: currentState.workspace };
264
- const run = await this.buildRun({ id: currentState.id, currentRoot, paths, signal: activeRun.controller.signal, logger });
265
- return { runRoot, cwd: process.cwd(), run, paths, state, lease, runStore, logger, activeRun };
264
+ const execution = await this.buildExecutionContext({ id: currentState.id, currentRoot, paths, signal: activeRun.controller.signal, logger });
265
+ return { runRoot, cwd: process.cwd(), execution, paths, state, lease, runStore, logger, activeRun };
266
266
  } catch (error) {
267
267
  this.failActiveRun(runRoot, activeRun);
268
268
  throw error;
269
269
  }
270
270
  }
271
- async buildRun(input) {
271
+ async buildExecutionContext(input) {
272
272
  const logsRoot = join(input.currentRoot, "logs");
273
273
  await mkdir(input.paths.workspace, { recursive: true });
274
274
  await mkdir(logsRoot, { recursive: true });
275
275
  const files = createRunFileCoordinator(dirname(input.currentRoot));
276
- return new NornRunContext({
276
+ return new NornExecutionContext({
277
277
  id: input.id,
278
278
  runRoot: input.currentRoot,
279
279
  signal: input.signal,
@@ -1,9 +1,9 @@
1
1
  import type { CreateAgentSessionOptions } from "@earendil-works/pi-coding-agent";
2
- import type { NornRunOutcomeMetadata, NornRun } from "@vimhead.dev/norn";
2
+ import type { NornAgents, NornCommands, NornLogs, NornRun } from "@vimhead.dev/norn";
3
3
  import type { NornAgentResponseCollector } from "./agent-response-tool.ts";
4
4
  import type { NornRunLogs } from "./logs.ts";
5
5
  import type { NornRunLogger } from "./run-log.ts";
6
- type DefaultNornRunInput = {
6
+ type NornExecutionContextInput = {
7
7
  readonly id: string;
8
8
  readonly runRoot: string;
9
9
  readonly signal?: AbortSignal;
@@ -14,18 +14,13 @@ type DefaultNornRunInput = {
14
14
  readonly logger: NornRunLogger;
15
15
  readonly logs: NornRunLogs;
16
16
  };
17
- export declare class NornRunContext implements NornRun {
17
+ export declare class NornExecutionContext {
18
18
  private readonly input;
19
- readonly logs: NornRun["logs"];
20
- readonly commands: NornRun["commands"];
21
- readonly agents: NornRun["agents"];
22
- readonly id: string;
23
- constructor(input: DefaultNornRunInput);
19
+ readonly run: NornRun;
20
+ readonly logs: NornLogs;
21
+ readonly commands: NornCommands;
22
+ readonly agents: NornAgents;
23
+ constructor(input: NornExecutionContextInput);
24
24
  private createAgentRunner;
25
- next(workflowId: string, args: unknown): ReturnType<NornRun["next"]>;
26
- complete(metadata?: NornRunOutcomeMetadata): ReturnType<NornRun["complete"]>;
27
- fail(metadata: NornRunOutcomeMetadata & {
28
- readonly summary: string;
29
- }): ReturnType<NornRun["fail"]>;
30
25
  }
31
26
  export {};
@@ -4,13 +4,18 @@ function createWorkflowTransition(input) {
4
4
  return { type: "next", workflowId: input.workflowId, args: input.args };
5
5
  }
6
6
 
7
- // src/internal/run.ts
7
+ // src/internal/execution-context.ts
8
8
  import { NornAgentRunner } from "./agents.js";
9
9
  import { NornCommandRunner } from "./commands.js";
10
- var NornRunContext = class {
10
+ var NornExecutionContext = class {
11
11
  constructor(input) {
12
12
  this.input = input;
13
- this.id = input.id;
13
+ this.run = {
14
+ id: input.id,
15
+ next: (workflowId, args) => createWorkflowTransition({ workflowId, args }),
16
+ complete: (metadata) => ({ type: "complete", metadata }),
17
+ fail: (metadata) => ({ type: "fail", metadata })
18
+ };
14
19
  this.logs = {
15
20
  read: (log) => this.input.logs.read(log)
16
21
  };
@@ -27,13 +32,13 @@ var NornRunContext = class {
27
32
  };
28
33
  }
29
34
  input;
35
+ run;
30
36
  logs;
31
37
  commands;
32
38
  agents;
33
- id;
34
39
  createAgentRunner() {
35
40
  return new NornAgentRunner({
36
- id: this.id,
41
+ id: this.input.id,
37
42
  runRoot: this.input.runRoot,
38
43
  signal: this.input.signal,
39
44
  model: this.input.model,
@@ -44,16 +49,7 @@ var NornRunContext = class {
44
49
  responseCollector: this.input.responseCollector
45
50
  });
46
51
  }
47
- next(workflowId, args) {
48
- return createWorkflowTransition({ workflowId, args });
49
- }
50
- complete(metadata) {
51
- return { type: "complete", metadata };
52
- }
53
- fail(metadata) {
54
- return { type: "fail", metadata };
55
- }
56
52
  };
57
53
  export {
58
- NornRunContext
54
+ NornExecutionContext
59
55
  };
@@ -1,4 +1,4 @@
1
- import { type NornAnyWorkflowDeclaration, type NornDispose, type NornInspectedWorkflowInfo, type NornRegisteredWorkflowInfo, type NornRunComplete, type NornRunFail, type NornRun, type NornRunNext, type NornWorkflowPaths, type NornWorkflowSource, type NornProjectConfigurationInfo } from "@vimhead.dev/norn";
1
+ import { type NornAnyWorkflowDeclaration, type NornDispose, type NornInspectedWorkflowInfo, type NornRegisteredWorkflowInfo, type NornRunComplete, type NornRunFail, type NornRunNext, type NornWorkflowPaths, type NornWorkflowContext, type NornWorkflowSource, type NornProjectConfigurationInfo } from "@vimhead.dev/norn";
2
2
  import type { TSchema } from "typebox";
3
3
  export type NornRegisteredConfiguration = {
4
4
  readonly key: string;
@@ -28,7 +28,7 @@ export type NornWorkflowStepResult = NornRunNext | {
28
28
  readonly metadata: NornRunFail["metadata"];
29
29
  };
30
30
  type NornExecutionContextInput = {
31
- readonly run: NornRun;
31
+ readonly execution: Pick<NornWorkflowContext, "run" | "agents" | "commands" | "logs">;
32
32
  readonly paths: NornWorkflowPaths;
33
33
  readonly args: unknown;
34
34
  readonly configOverride: unknown;
@@ -76,7 +76,7 @@ var NornWorkflowRegistry = class {
76
76
  ].map(({ configuration, scopeId }) => ({ key: configuration.key, scopeId, configSchema: configuration.schema ? inspectSchema(configuration.schema) : null, config: configuration.value }));
77
77
  }
78
78
  launchableEntries() {
79
- return this.sortedEntries().filter(({ workflow }) => workflow.isEntrypoint);
79
+ return this.sortedEntries().filter(({ workflow }) => workflow.entrypoint !== false);
80
80
  }
81
81
  workflowById(workflowId) {
82
82
  return this.entries.get(workflowId)?.workflow;
@@ -100,14 +100,17 @@ var NornWorkflowRegistry = class {
100
100
  throw new Error(`Workflow returned invalid control result: ${workflow.id}`);
101
101
  }
102
102
  createExecutionContext(input) {
103
- const { entry, run, paths, configOverride } = input;
103
+ const { entry, execution, paths, configOverride } = input;
104
104
  const scope = entry.scopeId ? this.scopes.get(entry.scopeId) : void 0;
105
105
  return {
106
106
  args: Value.Decode(entry.workflow.args, input.args),
107
107
  config: parseExecutionConfig(entry.configuration, configOverride),
108
108
  ...scope ? { scope: { id: scope.definition.id, config: parseExecutionConfig(scope.configuration, configOverride) } } : {},
109
109
  paths,
110
- run
110
+ run: execution.run,
111
+ agents: execution.agents,
112
+ commands: execution.commands,
113
+ logs: execution.logs
111
114
  };
112
115
  }
113
116
  requireEntry(id) {
@@ -153,8 +156,8 @@ function assertGateWorkflow(workflow) {
153
156
  function workflowInfo(entry) {
154
157
  return {
155
158
  id: entry.workflow.id,
156
- instructions: entry.workflow.instructions,
157
- isEntrypoint: entry.workflow.isEntrypoint,
159
+ instructions: entry.workflow.entrypoint === false ? void 0 : entry.workflow.entrypoint.instructions,
160
+ isEntrypoint: entry.workflow.entrypoint !== false,
158
161
  source: entry.source,
159
162
  configKey: entry.workflow.id,
160
163
  scope: entry.scopeId ? { id: entry.scopeId } : void 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vimhead.dev/norn-cli",
3
- "version": "0.1.0-tip.35436871363.1",
3
+ "version": "0.1.0-tip.35570530940.1",
4
4
  "description": "Harness-agnostic runtime for agent-driven and code-driven workflows, built primarily for agents.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -43,7 +43,7 @@
43
43
  "@earendil-works/pi-coding-agent": "0.85.1",
44
44
  "jiti": "^2.7.0",
45
45
  "typebox": "^1.3.34",
46
- "@vimhead.dev/norn": "0.1.0-tip.35436871363.1"
46
+ "@vimhead.dev/norn": "0.1.0-tip.35570530940.1"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "node ../../scripts/build-package.ts"