@vimhead.dev/norn-cli 0.1.0-tip.35568631545.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 +3 -2
- package/assets/docs/workflows.md +5 -6
- package/assets/examples/agent-then-analysis/plugin.ts +2 -3
- package/assets/examples/caller-selected-continuation/caller.ts +2 -2
- package/assets/examples/caller-selected-continuation/producer.ts +1 -2
- package/assets/examples/coordinating-multiple-agents/plugin.ts +3 -4
- package/assets/examples/getting-started/plugin.ts +1 -2
- package/assets/examples/minimal-workflow/plugin.ts +1 -2
- package/assets/examples/shared-state/plugin.ts +2 -3
- package/assets/examples/worktree-development-loop/workflows/development-loop/execute.ts +1 -2
- package/assets/examples/worktree-development-loop/workflows/implementation/execute.ts +1 -2
- package/assets/examples/worktree-development-loop/workflows/planning/execute.ts +1 -2
- package/assets/examples/worktree-development-loop/workflows/review/execute.ts +1 -2
- package/assets/examples/worktree-development-loop/workflows/review-router/execute.ts +1 -2
- package/assets/package.json +1 -1
- package/assets/packages/cli/src/generated-build-info.ts +2 -2
- package/assets/packages/cli/src/internal/workflow-registry.ts +4 -2
- package/assets/packages/sdk/src/api.ts +7 -10
- package/assets/packages/sdk/src/schema.ts +5 -5
- package/assets/tests/workflow-ref.test.ts +1 -1
- package/dist/generated-build-info.d.ts +2 -2
- package/dist/generated-build-info.js +2 -2
- package/dist/internal/workflow-registry.js +3 -3
- package/package.json +2 -2
package/assets/README.md
CHANGED
|
@@ -20,8 +20,9 @@ through the CLI from any harness. Agents run on the bundled
|
|
|
20
20
|
|
|
21
21
|
const summarize = workflow({
|
|
22
22
|
name: "summarize",
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
entrypoint: {
|
|
24
|
+
instructions: "Summarize staged and unstaged tracked changes relative to HEAD in an absolute repositoryPath. Requires Git and an existing commit; untracked files are excluded. Saves workspace-relative summaryPath and retains the diff log. A nonempty diff is sent to the configured model; an empty diff needs no model call.",
|
|
25
|
+
},
|
|
25
26
|
args: Type.Object({ repositoryPath: Type.String({ minLength: 1 }) }),
|
|
26
27
|
async execute({ args, paths, commands, logs, agents, run }) {
|
|
27
28
|
const diff = await commands.run({
|
package/assets/docs/workflows.md
CHANGED
|
@@ -14,8 +14,7 @@ import { Type } from "typebox";
|
|
|
14
14
|
|
|
15
15
|
export const greet = workflow({
|
|
16
16
|
name: "greet",
|
|
17
|
-
|
|
18
|
-
instructions: "Return a greeting for the supplied name.",
|
|
17
|
+
entrypoint: { instructions: "Return a greeting for the supplied name." },
|
|
19
18
|
args: Type.Object({ name: Type.String() }),
|
|
20
19
|
execute({ args, run }) {
|
|
21
20
|
return run.complete({ summary: `Hello, ${args.name}!` });
|
|
@@ -25,11 +24,11 @@ export const greet = workflow({
|
|
|
25
24
|
export default [greet];
|
|
26
25
|
```
|
|
27
26
|
|
|
28
|
-
Supply `name`, `args`, `
|
|
27
|
+
Supply `name`, `args`, `entrypoint`, and `execute` explicitly. Use `entrypoint: { instructions: "..." }` with nonempty caller-facing instructions, or `entrypoint: false` for an internal step. This controls default catalogue visibility, not authorization: the CLI can start a known internal workflow ID directly. Discovery exposes the derived `isEntrypoint` boolean and `instructions` string; internal steps have no caller instructions.
|
|
29
28
|
|
|
30
29
|
Workflow and scope names must be nonempty and cannot contain dots. A standalone workflow's ID is its name; a scoped workflow's ID is `<scope name>.<workflow name>`. Declarations expose the resolved `id`; CLI commands, references, and `run.next` use that exact ID, without implicit scope lookup.
|
|
31
30
|
|
|
32
|
-
`instructions` describe selection, inputs, effects, and outputs. They are neither a Norn agent system prompt nor a gate decision. Declare args and config with [TypeBox schemas](schemas.md). Workflow inputs must be JSON data; `execute` receives the values after schema defaults and conversions. Public schemas must support `workflows inspect`.
|
|
31
|
+
`entrypoint.instructions` describe selection, inputs, effects, and outputs. They are neither a Norn agent system prompt nor a gate decision. Declare args and config with [TypeBox schemas](schemas.md). Workflow inputs must be JSON data; `execute` receives the values after schema defaults and conversions. Public schemas must support `workflows inspect`.
|
|
33
32
|
|
|
34
33
|
Destructure the properties needed by the step from `execute(context)`. Gate descriptions receive the same inferred context:
|
|
35
34
|
|
|
@@ -79,7 +78,7 @@ export const reports = workflowScope({
|
|
|
79
78
|
|
|
80
79
|
export const save = reports.workflow({
|
|
81
80
|
name: "save",
|
|
82
|
-
|
|
81
|
+
entrypoint: false,
|
|
83
82
|
args: Type.Object({ text: Type.String() }),
|
|
84
83
|
config: Type.Object({ filename: Type.String() }),
|
|
85
84
|
async execute({ args, config, scope, paths, run }) {
|
|
@@ -116,7 +115,7 @@ import { Type } from "typebox";
|
|
|
116
115
|
|
|
117
116
|
const repeat = workflow({
|
|
118
117
|
name: "repeat",
|
|
119
|
-
|
|
118
|
+
entrypoint: false,
|
|
120
119
|
args: Type.Object({ remaining: Type.Integer() }),
|
|
121
120
|
execute({ args, run }): WorkflowResult {
|
|
122
121
|
return args.remaining > 0
|
|
@@ -24,8 +24,7 @@ const analysisSchema = Type.Object({
|
|
|
24
24
|
const scope = workflowScope({ name: "sourceSummary" });
|
|
25
25
|
export const draft = scope.workflow({
|
|
26
26
|
name: "draft",
|
|
27
|
-
|
|
28
|
-
instructions: "Summarize a supplied source, save the draft, and independently assess its support and omissions. Returns workspace-relative draftPath and analysisPath plus an assessment; needs-revision is a completed assessment, not an approved summary.",
|
|
27
|
+
entrypoint: { instructions: "Summarize a supplied source, save the draft, and independently assess its support and omissions. Returns workspace-relative draftPath and analysisPath plus an assessment; needs-revision is a completed assessment, not an approved summary." },
|
|
29
28
|
args: Type.Object({ source: Type.String({ minLength: 1 }) }),
|
|
30
29
|
async execute({ args, paths, agents }) {
|
|
31
30
|
const draft = await agents.prompt({
|
|
@@ -47,7 +46,7 @@ export const draft = scope.workflow({
|
|
|
47
46
|
});
|
|
48
47
|
export const analyze = scope.workflow({
|
|
49
48
|
name: "analyze",
|
|
50
|
-
|
|
49
|
+
entrypoint: false,
|
|
51
50
|
args: Type.Object({ draftPath: Type.String() }),
|
|
52
51
|
async execute({ args, paths, agents, run }) {
|
|
53
52
|
const savedDraft = Value.Parse(savedDraftSchema, JSON.parse(await readFile(join(paths.workspace, args.draftPath), "utf8")));
|
|
@@ -12,7 +12,7 @@ const deliveryArgsSchema = Type.Object({
|
|
|
12
12
|
const scope = workflowScope({ name: "greetingConsumer" });
|
|
13
13
|
export const saveJson = scope.workflow({
|
|
14
14
|
name: "saveJson",
|
|
15
|
-
|
|
15
|
+
entrypoint: false,
|
|
16
16
|
args: deliveryArgsSchema,
|
|
17
17
|
async execute({ args, paths, run }) {
|
|
18
18
|
const greeting = await readFile(join(paths.workspace, args.resultPath), "utf8");
|
|
@@ -30,7 +30,7 @@ export const saveJson = scope.workflow({
|
|
|
30
30
|
});
|
|
31
31
|
export const saveText = scope.workflow({
|
|
32
32
|
name: "saveText",
|
|
33
|
-
|
|
33
|
+
entrypoint: false,
|
|
34
34
|
args: deliveryArgsSchema,
|
|
35
35
|
async execute({ args, paths, run }) {
|
|
36
36
|
const greeting = await readFile(join(paths.workspace, args.resultPath), "utf8");
|
|
@@ -11,8 +11,7 @@ export const greetingContributionSchema = Type.Object({
|
|
|
11
11
|
const scope = workflowScope({ name: "greetingProducer" });
|
|
12
12
|
export const write = scope.workflow({
|
|
13
13
|
name: "write",
|
|
14
|
-
|
|
15
|
-
instructions: "Write a greeting file for name, then invoke the caller-selected next workflow with workspace-relative resultPath and summary. The continuation owns completion; no model or external service is used.",
|
|
14
|
+
entrypoint: { instructions: "Write a greeting file for name, then invoke the caller-selected next workflow with workspace-relative resultPath and summary. The continuation owns completion; no model or external service is used." },
|
|
16
15
|
args: Type.Object({
|
|
17
16
|
name: Type.String({ minLength: 1 }),
|
|
18
17
|
next: workflowRefSchema({ args: greetingContributionSchema }),
|
|
@@ -13,8 +13,7 @@ const workerReportSchema = Type.Object({ status: Type.Enum(["acknowledged", "idl
|
|
|
13
13
|
const scope = workflowScope({ name: "coordinatingAgents" });
|
|
14
14
|
export const start = scope.workflow({
|
|
15
15
|
name: "start",
|
|
16
|
-
|
|
17
|
-
instructions: "Summarize 2–12 supplied notes using two concurrent Norn agents and a shared leased work queue. Checkpoint completed rounds, verify every persisted result and exact source quotation, and return workspace-relative summariesPath for summaries.json. Requires configured Norn agent authentication; modifies only this run's logs and workspace.",
|
|
16
|
+
entrypoint: { instructions: "Summarize 2–12 supplied notes using two concurrent Norn agents and a shared leased work queue. Checkpoint completed rounds, verify every persisted result and exact source quotation, and return workspace-relative summariesPath for summaries.json. Requires configured Norn agent authentication; modifies only this run's logs and workspace." },
|
|
18
17
|
args: inputSchema,
|
|
19
18
|
async execute({ args, paths }) {
|
|
20
19
|
const queue = await openQueue({ workspace: paths.workspace, create: true });
|
|
@@ -28,7 +27,7 @@ export const start = scope.workflow({
|
|
|
28
27
|
});
|
|
29
28
|
export const work = scope.workflow({
|
|
30
29
|
name: "work",
|
|
31
|
-
|
|
30
|
+
entrypoint: false,
|
|
32
31
|
args: Type.Object({ ...inputSchema.properties, round: Type.Integer({ minimum: 0, maximum: 12 }) }, { additionalProperties: false }),
|
|
33
32
|
async execute({ args, paths, agents, run }): Promise<WorkflowResult> {
|
|
34
33
|
const queue = await openQueue({ workspace: paths.workspace, create: false });
|
|
@@ -54,7 +53,7 @@ export const work = scope.workflow({
|
|
|
54
53
|
});
|
|
55
54
|
export const verify = scope.workflow({
|
|
56
55
|
name: "verify",
|
|
57
|
-
|
|
56
|
+
entrypoint: false,
|
|
58
57
|
args: inputSchema,
|
|
59
58
|
async execute({ args, paths, run }) {
|
|
60
59
|
const queue = await openQueue({ workspace: paths.workspace, create: false });
|
|
@@ -5,8 +5,7 @@ import { Type } from "typebox";
|
|
|
5
5
|
|
|
6
6
|
export const summarize = workflow({
|
|
7
7
|
name: "summarize",
|
|
8
|
-
|
|
9
|
-
instructions: "Summarize staged and unstaged tracked changes relative to HEAD in an absolute repositoryPath. Requires Git and an existing commit; untracked files are excluded. Saves workspace-relative summaryPath and retains the diff log. A nonempty diff is sent to the configured model; an empty diff needs no model call.",
|
|
8
|
+
entrypoint: { instructions: "Summarize staged and unstaged tracked changes relative to HEAD in an absolute repositoryPath. Requires Git and an existing commit; untracked files are excluded. Saves workspace-relative summaryPath and retains the diff log. A nonempty diff is sent to the configured model; an empty diff needs no model call." },
|
|
10
9
|
args: Type.Object({ repositoryPath: Type.String({ minLength: 1 }) }),
|
|
11
10
|
async execute({ args, paths, commands, logs, agents, run }) {
|
|
12
11
|
const diff = await commands.run({
|
|
@@ -5,8 +5,7 @@ import { Type } from "typebox";
|
|
|
5
5
|
|
|
6
6
|
export const write = workflow({
|
|
7
7
|
name: "greet",
|
|
8
|
-
|
|
9
|
-
instructions: "Write a greeting file for the supplied name. Returns the greeting text and its workspace-relative greetingPath; no agent or external service is used.",
|
|
8
|
+
entrypoint: { instructions: "Write a greeting file for the supplied name. Returns the greeting text and its workspace-relative greetingPath; no agent or external service is used." },
|
|
10
9
|
args: Type.Object({ name: Type.Decode(Type.String({ pattern: "\\S" }), value => value.trim()) }),
|
|
11
10
|
async execute({ args, paths, run }) {
|
|
12
11
|
const greeting = `Hello, ${args.name}!`;
|
|
@@ -11,8 +11,7 @@ const copyField = { id: "copiedText", schema: Type.String() };
|
|
|
11
11
|
|
|
12
12
|
export const copy = copyScope.workflow({
|
|
13
13
|
name: "copy",
|
|
14
|
-
|
|
15
|
-
instructions: "A Norn agent reads explicitly shared source and writes a copy, then a separate workflow verifies exact equality from a workspace SQLite database.",
|
|
14
|
+
entrypoint: { instructions: "A Norn agent reads explicitly shared source and writes a copy, then a separate workflow verifies exact equality from a workspace SQLite database." },
|
|
16
15
|
args: Type.Object({ source: Type.String({ minLength: 1, maxLength: 500 }) }),
|
|
17
16
|
async execute({ args, paths, agents }) {
|
|
18
17
|
const state = await SharedState.open({ path: join(paths.workspace, "state.sqlite"), create: true });
|
|
@@ -37,7 +36,7 @@ export const copy = copyScope.workflow({
|
|
|
37
36
|
},
|
|
38
37
|
});
|
|
39
38
|
export const verify = copyScope.workflow({
|
|
40
|
-
name: "verify",
|
|
39
|
+
name: "verify", entrypoint: false, args: Type.Object({}),
|
|
41
40
|
async execute({ paths, run }) {
|
|
42
41
|
const state = await SharedState.open({ path: join(paths.workspace, "state.sqlite"), create: false });
|
|
43
42
|
try {
|
|
@@ -6,8 +6,7 @@ import { materializeWorkspaceRepository } from "./repository.ts";
|
|
|
6
6
|
|
|
7
7
|
export const developmentLoopWorkflow = developmentLoopScope.workflow({
|
|
8
8
|
name: "developmentLoop",
|
|
9
|
-
|
|
10
|
-
instructions: "Plan once, then loop implementation and review in a workspace repository copy. Call this when a repository task should run through planning, implementation, and review.",
|
|
9
|
+
entrypoint: { instructions: "Plan once, then loop implementation and review in a workspace repository copy. Call this when a repository task should run through planning, implementation, and review." },
|
|
11
10
|
args: developmentLoopArgsSchema,
|
|
12
11
|
async execute({ args, scope, paths, commands }): Promise<WorkflowResult> {
|
|
13
12
|
const repositoryPath = await materializeWorkspaceRepository({ commands, paths, repositoryRoot: scope.config.repositoryRoot, baseRef: args.baseRef });
|
|
@@ -9,8 +9,7 @@ import { implementationAgentResponseSchema } from "./schema.ts";
|
|
|
9
9
|
|
|
10
10
|
export const implementationWorkflow = developmentLoopScope.workflow({
|
|
11
11
|
name: "implementation",
|
|
12
|
-
|
|
13
|
-
instructions: "Apply one implementation pass in the current repository.",
|
|
12
|
+
entrypoint: false,
|
|
14
13
|
args: implementationArgsSchema,
|
|
15
14
|
async execute({ args, paths, agents, commands, logs }): Promise<WorkflowResult> {
|
|
16
15
|
const repositoryPath = resolve(paths.workspace, args.repositoryPath);
|
|
@@ -8,8 +8,7 @@ import { planningAgentResponseSchema } from "./schema.ts";
|
|
|
8
8
|
|
|
9
9
|
export const planningWorkflow = developmentLoopScope.workflow({
|
|
10
10
|
name: "planning",
|
|
11
|
-
|
|
12
|
-
instructions: "Create an implementation plan for a repository task.",
|
|
11
|
+
entrypoint: false,
|
|
13
12
|
args: planningArgsSchema,
|
|
14
13
|
async execute({ args, paths, agents }): Promise<WorkflowResult> {
|
|
15
14
|
const repositoryPath = resolve(paths.workspace, args.repositoryPath);
|
|
@@ -9,8 +9,7 @@ import { reviewAgentResponseSchema } from "./schema.ts";
|
|
|
9
9
|
|
|
10
10
|
export const reviewWorkflow = developmentLoopScope.workflow({
|
|
11
11
|
name: "review",
|
|
12
|
-
|
|
13
|
-
instructions: "Review the current repository boundary changes.",
|
|
12
|
+
entrypoint: false,
|
|
14
13
|
args: reviewArgsSchema,
|
|
15
14
|
async execute({ args, paths, agents, commands, logs }): Promise<WorkflowResult> {
|
|
16
15
|
const repositoryPath = resolve(paths.workspace, args.repositoryPath);
|
|
@@ -8,8 +8,7 @@ import type { StoredReview } from "../review/schema.ts";
|
|
|
8
8
|
|
|
9
9
|
export const reviewRouterWorkflow = developmentLoopScope.workflow({
|
|
10
10
|
name: "reviewRouter",
|
|
11
|
-
|
|
12
|
-
instructions: "Route implementation and review iterations based on the latest review decision.",
|
|
11
|
+
entrypoint: false,
|
|
13
12
|
gate: {
|
|
14
13
|
enabled: true,
|
|
15
14
|
describe: ({ args }) => `Review iteration ${args.iteration}. Confirm or edit the automated decision before continuing. Plan: ${args.planPath}.`,
|
package/assets/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.1.0-tip.
|
|
1
|
+
{"version":"0.1.0-tip.35570530940.1"}
|
|
@@ -2,8 +2,8 @@ import type { NornBuildInfo } from "./build-info.ts";
|
|
|
2
2
|
|
|
3
3
|
export const NORN_GENERATED_BUILD_INFO = {
|
|
4
4
|
"kind": "npm-registry",
|
|
5
|
-
"version": "0.1.0-tip.
|
|
6
|
-
"commit": "
|
|
5
|
+
"version": "0.1.0-tip.35570530940.1",
|
|
6
|
+
"commit": "48ecaf47ae0e82e17970db9465497a4e1ad5ff10",
|
|
7
7
|
"packageSpec": "@vimhead.dev/norn-cli@tip",
|
|
8
8
|
"upgrade": {
|
|
9
9
|
"supported": false,
|
|
@@ -105,7 +105,7 @@ export class NornWorkflowRegistry {
|
|
|
105
105
|
].map(({ configuration, scopeId }) => ({ key: configuration.key, scopeId, configSchema: configuration.schema ? inspectSchema(configuration.schema) : null, config: configuration.value }));
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
launchableEntries(): NornRegisteredWorkflow[] { return this.sortedEntries().filter(({ workflow }) => workflow.
|
|
108
|
+
launchableEntries(): NornRegisteredWorkflow[] { return this.sortedEntries().filter(({ workflow }) => workflow.entrypoint !== false); }
|
|
109
109
|
workflowById(workflowId: string): NornAnyWorkflowDeclaration | undefined { return this.entries.get(workflowId)?.workflow; }
|
|
110
110
|
|
|
111
111
|
async describeGate(input: NornWorkflowExecutionInput): Promise<string> {
|
|
@@ -189,7 +189,9 @@ function assertGateWorkflow(workflow: NornAnyWorkflowDeclaration): void {
|
|
|
189
189
|
|
|
190
190
|
function workflowInfo(entry: NornRegisteredWorkflow): NornRegisteredWorkflowInfo {
|
|
191
191
|
return {
|
|
192
|
-
id: entry.workflow.id,
|
|
192
|
+
id: entry.workflow.id,
|
|
193
|
+
instructions: entry.workflow.entrypoint === false ? undefined : entry.workflow.entrypoint.instructions,
|
|
194
|
+
isEntrypoint: entry.workflow.entrypoint !== false,
|
|
193
195
|
source: entry.source,
|
|
194
196
|
configKey: entry.workflow.id,
|
|
195
197
|
scope: entry.scopeId ? { id: entry.scopeId } : undefined,
|
|
@@ -32,8 +32,7 @@ export type NornWorkflowDeclaration<
|
|
|
32
32
|
(args: StaticEncode<ArgsSchema>): NornRunNext;
|
|
33
33
|
readonly kind: typeof WORKFLOW_DECLARATION_KIND;
|
|
34
34
|
readonly id: Id;
|
|
35
|
-
readonly
|
|
36
|
-
readonly instructions?: string;
|
|
35
|
+
readonly entrypoint: NornWorkflowEntrypoint;
|
|
37
36
|
readonly args: ArgsSchema;
|
|
38
37
|
readonly gate?: NornWorkflowGate<ArgsSchema> & {
|
|
39
38
|
describe?(context: NornWorkflowContext<ArgsSchema, ConfigSchema, Scope>): MaybePromise<string>;
|
|
@@ -65,9 +64,7 @@ export type NornWorkflowGate<ArgsSchema extends TSchema> = unknown extends Stati
|
|
|
65
64
|
readonly fields?: never;
|
|
66
65
|
};
|
|
67
66
|
|
|
68
|
-
type
|
|
69
|
-
| { readonly isEntrypoint: true; readonly instructions: string }
|
|
70
|
-
| { readonly isEntrypoint: false; readonly instructions?: string };
|
|
67
|
+
export type NornWorkflowEntrypoint = false | { readonly instructions: string };
|
|
71
68
|
|
|
72
69
|
type WorkflowConfig<Schema extends TSchema | undefined> = Schema extends TSchema ? StaticDecode<Schema> : undefined;
|
|
73
70
|
|
|
@@ -94,13 +91,14 @@ export type NornWorkflowDefinition<
|
|
|
94
91
|
Scope extends NornWorkflowScopeInfo | undefined = undefined,
|
|
95
92
|
> = {
|
|
96
93
|
readonly name: Name;
|
|
94
|
+
readonly entrypoint: NornWorkflowEntrypoint;
|
|
97
95
|
readonly args: ArgsSchema;
|
|
98
96
|
readonly config?: ConfigSchema;
|
|
99
97
|
readonly gate?: NornWorkflowGate<ArgsSchema> & {
|
|
100
98
|
describe?(context: NornWorkflowContext<ArgsSchema, ConfigSchema, Scope>): MaybePromise<string>;
|
|
101
99
|
};
|
|
102
100
|
execute(context: NornWorkflowContext<ArgsSchema, ConfigSchema, Scope>): MaybePromise<WorkflowResult>;
|
|
103
|
-
}
|
|
101
|
+
};
|
|
104
102
|
|
|
105
103
|
export type NornWorkflowScopeInfo = {
|
|
106
104
|
readonly id: string;
|
|
@@ -134,8 +132,8 @@ function createWorkflow<Id extends string, ArgsSchema extends TSchema, ConfigSch
|
|
|
134
132
|
id,
|
|
135
133
|
scope,
|
|
136
134
|
}) as NornWorkflowDeclaration<Id, ArgsSchema, ConfigSchema, Scope>;
|
|
137
|
-
if (!isWorkflowDeclaration(result)) throw new Error(`Invalid workflow definition: ${id}`);
|
|
138
135
|
assertWorkflowMetadata(result);
|
|
136
|
+
if (!isWorkflowDeclaration(result)) throw new Error(`Invalid workflow definition: ${id}`);
|
|
139
137
|
return result;
|
|
140
138
|
}
|
|
141
139
|
|
|
@@ -564,13 +562,12 @@ function assertDeclarationName(name: string): void {
|
|
|
564
562
|
|
|
565
563
|
export function isWorkflowDeclaration(value: unknown): value is NornAnyWorkflowDeclaration {
|
|
566
564
|
if (typeof value !== "function") return false;
|
|
567
|
-
const candidate = value as { kind?: unknown; id?: unknown;
|
|
565
|
+
const candidate = value as { kind?: unknown; id?: unknown; entrypoint?: unknown; args?: unknown; execute?: unknown };
|
|
568
566
|
return (
|
|
569
567
|
candidate.kind === WORKFLOW_DECLARATION_KIND &&
|
|
570
568
|
typeof candidate.id === "string" &&
|
|
571
569
|
candidate.id.length > 0 &&
|
|
572
|
-
(candidate.
|
|
573
|
-
typeof candidate.isEntrypoint === "boolean" &&
|
|
570
|
+
(candidate.entrypoint === false || (isPlainObject(candidate.entrypoint) && typeof candidate.entrypoint.instructions === "string")) &&
|
|
574
571
|
Boolean(candidate.args) &&
|
|
575
572
|
typeof candidate.execute === "function"
|
|
576
573
|
);
|
|
@@ -43,11 +43,11 @@ function assertWorkflowReferenceAnnotations(schema: unknown): void {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export function assertWorkflowMetadata(workflow: NornAnyWorkflowDeclaration): void {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
if (
|
|
50
|
-
throw new Error(`
|
|
46
|
+
const { entrypoint } = workflow;
|
|
47
|
+
if (entrypoint === false) return;
|
|
48
|
+
if (!isPlainObject(entrypoint)) throw new Error(`Workflow entrypoint must be false or an object with instructions: ${workflow.id}`);
|
|
49
|
+
if (typeof entrypoint.instructions !== "string" || entrypoint.instructions.trim().length === 0) {
|
|
50
|
+
throw new Error(`Workflow entrypoint.instructions must be a nonempty string: ${workflow.id}`);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -7,7 +7,7 @@ import { expect, expectTypeOf, test } from "vitest";
|
|
|
7
7
|
|
|
8
8
|
const refs = workflowScope({ name: "refs" });
|
|
9
9
|
const target = refs.workflow({
|
|
10
|
-
name: "finish",
|
|
10
|
+
name: "finish", entrypoint: false, args: Type.Object({ report: Type.String() }),
|
|
11
11
|
execute() { throw new Error("A callable must select a transition, not execute it"); },
|
|
12
12
|
});
|
|
13
13
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const NORN_GENERATED_BUILD_INFO: {
|
|
2
2
|
readonly kind: "npm-registry";
|
|
3
|
-
readonly version: "0.1.0-tip.
|
|
4
|
-
readonly commit: "
|
|
3
|
+
readonly version: "0.1.0-tip.35570530940.1";
|
|
4
|
+
readonly commit: "48ecaf47ae0e82e17970db9465497a4e1ad5ff10";
|
|
5
5
|
readonly packageSpec: "@vimhead.dev/norn-cli@tip";
|
|
6
6
|
readonly upgrade: {
|
|
7
7
|
readonly supported: false;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/generated-build-info.ts
|
|
2
2
|
var NORN_GENERATED_BUILD_INFO = {
|
|
3
3
|
"kind": "npm-registry",
|
|
4
|
-
"version": "0.1.0-tip.
|
|
5
|
-
"commit": "
|
|
4
|
+
"version": "0.1.0-tip.35570530940.1",
|
|
5
|
+
"commit": "48ecaf47ae0e82e17970db9465497a4e1ad5ff10",
|
|
6
6
|
"packageSpec": "@vimhead.dev/norn-cli@tip",
|
|
7
7
|
"upgrade": {
|
|
8
8
|
"supported": false,
|
|
@@ -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;
|
|
@@ -156,8 +156,8 @@ function assertGateWorkflow(workflow) {
|
|
|
156
156
|
function workflowInfo(entry) {
|
|
157
157
|
return {
|
|
158
158
|
id: entry.workflow.id,
|
|
159
|
-
instructions: entry.workflow.instructions,
|
|
160
|
-
isEntrypoint: entry.workflow.
|
|
159
|
+
instructions: entry.workflow.entrypoint === false ? void 0 : entry.workflow.entrypoint.instructions,
|
|
160
|
+
isEntrypoint: entry.workflow.entrypoint !== false,
|
|
161
161
|
source: entry.source,
|
|
162
162
|
configKey: entry.workflow.id,
|
|
163
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"
|