@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.
- package/assets/README.md +35 -17
- package/assets/docs/agents.md +4 -4
- package/assets/docs/cli.md +3 -3
- package/assets/docs/recovery.md +1 -1
- package/assets/docs/workflows.md +22 -16
- package/assets/examples/agent-then-analysis/plugin.ts +9 -10
- package/assets/examples/caller-selected-continuation/caller.ts +5 -5
- package/assets/examples/caller-selected-continuation/producer.ts +3 -4
- package/assets/examples/coordinating-multiple-agents/README.md +1 -1
- package/assets/examples/coordinating-multiple-agents/plugin.ts +12 -13
- package/assets/examples/getting-started/README.md +24 -9
- package/assets/examples/getting-started/plugin.ts +27 -13
- package/assets/examples/minimal-workflow/README.md +2 -2
- package/assets/examples/minimal-workflow/plugin.ts +2 -3
- package/assets/examples/shared-state/plugin.ts +6 -7
- package/assets/examples/worktree-development-loop/scope.ts +1 -1
- package/assets/examples/worktree-development-loop/workflows/development-loop/execute.ts +4 -5
- package/assets/examples/worktree-development-loop/workflows/development-loop/repository.ts +3 -3
- package/assets/examples/worktree-development-loop/workflows/implementation/execute.ts +6 -7
- package/assets/examples/worktree-development-loop/workflows/planning/execute.ts +4 -5
- package/assets/examples/worktree-development-loop/workflows/review/execute.ts +6 -7
- package/assets/examples/worktree-development-loop/workflows/review-router/execute.ts +2 -3
- package/assets/package.json +1 -1
- package/assets/packages/cli/src/generated-build-info.ts +2 -2
- package/assets/packages/cli/src/internal/engine.ts +15 -15
- package/assets/packages/cli/src/internal/{run.ts → execution-context.ts} +23 -31
- package/assets/packages/cli/src/internal/workflow-registry.ts +11 -6
- package/assets/packages/sdk/src/api.ts +49 -46
- package/assets/packages/sdk/src/schema.ts +5 -5
- package/assets/tests/workflow-ref.test.ts +4 -3
- package/dist/generated-build-info.d.ts +2 -2
- package/dist/generated-build-info.js +2 -2
- package/dist/internal/engine.d.ts +1 -1
- package/dist/internal/engine.js +13 -13
- package/dist/internal/{run.d.ts → execution-context.d.ts} +8 -13
- package/dist/internal/{run.js → execution-context.js} +11 -15
- package/dist/internal/workflow-registry.d.ts +2 -2
- package/dist/internal/workflow-registry.js +8 -5
- package/package.json +2 -2
package/dist/internal/engine.js
CHANGED
|
@@ -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 {
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
265
|
-
return { runRoot, cwd: process.cwd(),
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
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
|
|
17
|
+
export declare class NornExecutionContext {
|
|
18
18
|
private readonly input;
|
|
19
|
-
readonly
|
|
20
|
-
readonly
|
|
21
|
-
readonly
|
|
22
|
-
readonly
|
|
23
|
-
constructor(input:
|
|
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/
|
|
7
|
+
// src/internal/execution-context.ts
|
|
8
8
|
import { NornAgentRunner } from "./agents.js";
|
|
9
9
|
import { NornCommandRunner } from "./commands.js";
|
|
10
|
-
var
|
|
10
|
+
var NornExecutionContext = class {
|
|
11
11
|
constructor(input) {
|
|
12
12
|
this.input = input;
|
|
13
|
-
this.
|
|
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
|
-
|
|
54
|
+
NornExecutionContext
|
|
59
55
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type NornAnyWorkflowDeclaration, type NornDispose, type NornInspectedWorkflowInfo, type NornRegisteredWorkflowInfo, type NornRunComplete, type NornRunFail, type
|
|
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
|
|
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.
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
46
|
+
"@vimhead.dev/norn": "0.1.0-tip.35570530940.1"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "node ../../scripts/build-package.ts"
|