@vimhead.dev/norn-cli 0.1.0-tip.35614826665.1 → 0.1.0-tip.35724621678.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 +41 -13
- package/assets/docs/README.md +16 -16
- package/assets/docs/agents.md +23 -15
- package/assets/docs/cli.md +10 -8
- package/assets/docs/composition.md +7 -7
- package/assets/docs/persistence.md +22 -22
- package/assets/docs/projects.md +6 -6
- package/assets/docs/recovery.md +10 -10
- package/assets/docs/schemas.md +42 -36
- package/assets/docs/workflows.md +39 -32
- package/assets/examples/agent-then-analysis/input.json +3 -3
- package/assets/examples/agent-then-analysis/norn.project.json +2 -2
- package/assets/examples/agent-then-analysis/plugin.ts +37 -9
- package/assets/examples/caller-owned-routing/README.md +6 -6
- package/assets/examples/caller-owned-routing/assessment.ts +18 -4
- package/assets/examples/caller-owned-routing/contracts.ts +7 -2
- package/assets/examples/caller-owned-routing/input.json +12 -12
- package/assets/examples/caller-owned-routing/norn.project.json +2 -2
- package/assets/examples/caller-owned-routing/revision.ts +7 -2
- package/assets/examples/caller-owned-routing/router.ts +14 -3
- package/assets/examples/caller-selected-continuation/caller.ts +38 -12
- package/assets/examples/caller-selected-continuation/input.json +7 -7
- package/assets/examples/caller-selected-continuation/norn.project.json +2 -2
- package/assets/examples/caller-selected-continuation/producer.ts +10 -3
- package/assets/examples/coordinating-multiple-agents/README.md +6 -6
- package/assets/examples/coordinating-multiple-agents/input.json +20 -8
- package/assets/examples/coordinating-multiple-agents/norn.project.json +2 -2
- package/assets/examples/coordinating-multiple-agents/plugin.ts +165 -46
- package/assets/examples/coordinating-multiple-agents/queue-tools.ts +30 -7
- package/assets/examples/coordinating-multiple-agents/work-queue.ts +211 -63
- package/assets/examples/getting-started/norn.project.json +2 -2
- package/assets/examples/getting-started/plugin.ts +33 -13
- package/assets/examples/minimal-workflow/norn.project.json +2 -2
- package/assets/examples/minimal-workflow/plugin.ts +12 -3
- package/assets/examples/shared-state/README.md +6 -6
- package/assets/examples/shared-state/input.json +1 -1
- package/assets/examples/shared-state/norn.project.json +2 -2
- package/assets/examples/shared-state/plugin.ts +44 -15
- package/assets/examples/shared-state/shared-state.ts +46 -13
- package/assets/examples/shared-state/state-tools.ts +68 -16
- package/assets/examples/worktree-development-loop/README.md +12 -12
- package/assets/examples/worktree-development-loop/norn.project.json +7 -7
- package/assets/examples/worktree-development-loop/plugin.ts +7 -1
- package/assets/examples/worktree-development-loop/scope.ts +4 -1
- package/assets/examples/worktree-development-loop/shared/commands.ts +6 -2
- package/assets/examples/worktree-development-loop/workflows/development-loop/execute.ts +18 -4
- package/assets/examples/worktree-development-loop/workflows/development-loop/index.ts +4 -1
- package/assets/examples/worktree-development-loop/workflows/development-loop/repository.ts +11 -1
- package/assets/examples/worktree-development-loop/workflows/development-loop/schema.ts +6 -2
- package/assets/examples/worktree-development-loop/workflows/implementation/execute.ts +40 -10
- package/assets/examples/worktree-development-loop/workflows/implementation/index.ts +5 -1
- package/assets/examples/worktree-development-loop/workflows/planning/execute.ts +1 -1
- package/assets/examples/worktree-development-loop/workflows/planning/index.ts +5 -1
- package/assets/examples/worktree-development-loop/workflows/review/execute.ts +33 -9
- package/assets/examples/worktree-development-loop/workflows/review-router/execute.ts +51 -8
- package/assets/package.json +1 -1
- package/assets/packages/cli/src/build-info.ts +4 -1
- package/assets/packages/cli/src/bun/cli.ts +21 -5
- package/assets/packages/cli/src/cli.ts +585 -170
- package/assets/packages/cli/src/client.ts +194 -36
- package/assets/packages/cli/src/documentation.ts +135 -30
- package/assets/packages/cli/src/generated-build-info.ts +2 -2
- package/assets/packages/cli/src/internal/agent-directory.ts +7 -2
- package/assets/packages/cli/src/internal/agent-response-tool.ts +57 -15
- package/assets/packages/cli/src/internal/agents.ts +248 -60
- package/assets/packages/cli/src/internal/commands.ts +82 -20
- package/assets/packages/cli/src/internal/documentation-bundle.ts +44 -13
- package/assets/packages/cli/src/internal/engine.ts +396 -87
- package/assets/packages/cli/src/internal/errors.ts +13 -5
- package/assets/packages/cli/src/internal/execution-context.ts +20 -12
- package/assets/packages/cli/src/internal/file-coordinator.ts +95 -26
- package/assets/packages/cli/src/internal/file-names.ts +4 -1
- package/assets/packages/cli/src/internal/launch-request.ts +74 -22
- package/assets/packages/cli/src/internal/logs.ts +10 -2
- package/assets/packages/cli/src/internal/metrics.ts +247 -61
- package/assets/packages/cli/src/internal/pi-assets.ts +105 -23
- package/assets/packages/cli/src/internal/run-lease.ts +72 -22
- package/assets/packages/cli/src/internal/run-log.ts +49 -20
- package/assets/packages/cli/src/internal/run-names.ts +120 -12
- package/assets/packages/cli/src/internal/run-state.ts +306 -71
- package/assets/packages/cli/src/internal/run-store.ts +216 -53
- package/assets/packages/cli/src/internal/usage.ts +23 -7
- package/assets/packages/cli/src/internal/worker-directory.ts +9 -3
- package/assets/packages/cli/src/internal/workflow-registry.ts +281 -70
- package/assets/packages/cli/src/internal/working-directory.ts +2 -1
- package/assets/packages/cli/src/workflow-loader.ts +341 -74
- package/assets/packages/core/src/atomic-files.ts +13 -4
- package/assets/packages/core/src/workflow-transition.ts +13 -2
- package/assets/packages/sdk/src/api.ts +248 -80
- package/assets/packages/sdk/src/index.ts +6 -1
- package/assets/packages/sdk/src/schema.ts +75 -21
- package/assets/tests/workflow-ref.test.ts +242 -57
- package/bin/norn.mjs +13 -4
- package/dist/cli.js +344 -90
- package/dist/client.js +100 -22
- package/dist/documentation.js +102 -25
- package/dist/generated-build-info.d.ts +2 -2
- package/dist/generated-build-info.js +2 -2
- package/dist/internal/agent-directory.js +3 -1
- package/dist/internal/agent-response-tool.js +42 -11
- package/dist/internal/agents.js +149 -37
- package/dist/internal/commands.js +65 -16
- package/dist/internal/documentation-bundle.js +23 -11
- package/dist/internal/engine.js +304 -66
- package/dist/internal/errors.js +4 -2
- package/dist/internal/execution-context.js +2 -1
- package/dist/internal/file-coordinator.js +59 -19
- package/dist/internal/launch-request.js +32 -14
- package/dist/internal/metrics.js +138 -38
- package/dist/internal/pi-assets.js +70 -19
- package/dist/internal/run-lease.js +29 -9
- package/dist/internal/run-log.js +24 -12
- package/dist/internal/run-state.js +172 -48
- package/dist/internal/run-store.js +157 -45
- package/dist/internal/worker-directory.js +6 -2
- package/dist/internal/workflow-registry.js +123 -32
- package/dist/internal/working-directory.js +2 -1
- package/dist/workflow-loader.js +198 -41
- package/package.json +2 -2
package/dist/client.js
CHANGED
|
@@ -13,23 +13,78 @@ function createNornClient(input = {}) {
|
|
|
13
13
|
inspect: async () => processRunner.readJson(["project", "inspect"])
|
|
14
14
|
},
|
|
15
15
|
workflows: {
|
|
16
|
-
list: async (options) => processRunner.readJson([
|
|
17
|
-
|
|
16
|
+
list: async (options) => processRunner.readJson([
|
|
17
|
+
"workflows",
|
|
18
|
+
"list",
|
|
19
|
+
...options?.all ? ["--all"] : []
|
|
20
|
+
]),
|
|
21
|
+
inspect: async (workflowId) => processRunner.readJson([
|
|
22
|
+
"workflows",
|
|
23
|
+
"inspect",
|
|
24
|
+
workflowId
|
|
25
|
+
]),
|
|
18
26
|
entries: async () => (await catalog.load()).workflows
|
|
19
27
|
},
|
|
20
28
|
runs: {
|
|
21
|
-
start: async (startInput) => (await processRunner.readJson(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
start: async (startInput) => (await processRunner.readJson(
|
|
30
|
+
["runs", "start", startInput.workflowId],
|
|
31
|
+
JSON.stringify(runStartInput(startInput))
|
|
32
|
+
)).run,
|
|
33
|
+
resume: async (resumeInput) => (await processRunner.readJson(
|
|
34
|
+
["runs", "resume", resumeInput.run],
|
|
35
|
+
runResumeStdin(resumeInput)
|
|
36
|
+
)).run,
|
|
37
|
+
wait: async (run) => (await processRunner.readJson([
|
|
38
|
+
"runs",
|
|
39
|
+
"wait",
|
|
40
|
+
run
|
|
41
|
+
])).run,
|
|
42
|
+
list: async () => (await processRunner.readJson([
|
|
43
|
+
"runs",
|
|
44
|
+
"list"
|
|
45
|
+
])).runs,
|
|
46
|
+
inspect: async (run) => (await processRunner.readJson([
|
|
47
|
+
"runs",
|
|
48
|
+
"inspect",
|
|
49
|
+
run
|
|
50
|
+
])).run,
|
|
51
|
+
checkpoints: async (run) => (await processRunner.readJson([
|
|
52
|
+
"runs",
|
|
53
|
+
"checkpoints",
|
|
54
|
+
run
|
|
55
|
+
])).checkpoints,
|
|
56
|
+
metrics: async (run) => (await processRunner.readJson([
|
|
57
|
+
"runs",
|
|
58
|
+
"metrics",
|
|
59
|
+
run
|
|
60
|
+
])).metrics,
|
|
61
|
+
rollback: async (run, checkpointId) => (await processRunner.readJson([
|
|
62
|
+
"runs",
|
|
63
|
+
"rollback",
|
|
64
|
+
run,
|
|
65
|
+
checkpointId
|
|
66
|
+
])).run,
|
|
67
|
+
stop: async (run) => (await processRunner.readJson([
|
|
68
|
+
"runs",
|
|
69
|
+
"stop",
|
|
70
|
+
run
|
|
71
|
+
])).run,
|
|
72
|
+
kill: async (run) => (await processRunner.readJson([
|
|
73
|
+
"runs",
|
|
74
|
+
"kill",
|
|
75
|
+
run
|
|
76
|
+
])).run,
|
|
77
|
+
delete: async (run) => (await processRunner.readJson([
|
|
78
|
+
"runs",
|
|
79
|
+
"delete",
|
|
80
|
+
run
|
|
81
|
+
])).deleted,
|
|
82
|
+
logs: (run, options) => processRunner.readJsonLines([
|
|
83
|
+
"runs",
|
|
84
|
+
"logs",
|
|
85
|
+
run,
|
|
86
|
+
...options?.follow ? ["--follow"] : []
|
|
87
|
+
])
|
|
33
88
|
}
|
|
34
89
|
};
|
|
35
90
|
return client;
|
|
@@ -59,14 +114,23 @@ var NornProcessRunner = class {
|
|
|
59
114
|
const result = await this.spawn(args, stdin);
|
|
60
115
|
const parsed = JSON.parse(result.stdout);
|
|
61
116
|
if (parsed && typeof parsed === "object" && "error" in parsed) {
|
|
62
|
-
if (parsed.error?.code === "NORN_PROJECT_INVALID" && Array.isArray(parsed.error.diagnostics))
|
|
117
|
+
if (parsed.error?.code === "NORN_PROJECT_INVALID" && Array.isArray(parsed.error.diagnostics))
|
|
118
|
+
throw new NornProjectLoadError({
|
|
119
|
+
diagnostics: parsed.error.diagnostics
|
|
120
|
+
});
|
|
63
121
|
throw new Error(parsed.error?.message ?? "Norn command failed");
|
|
64
122
|
}
|
|
65
|
-
if (result.exitCode !== 0)
|
|
123
|
+
if (result.exitCode !== 0)
|
|
124
|
+
throw new Error(
|
|
125
|
+
result.stderr || `Norn exited with code ${result.exitCode}`
|
|
126
|
+
);
|
|
66
127
|
return parsed;
|
|
67
128
|
}
|
|
68
129
|
async *readJsonLines(args) {
|
|
69
|
-
const child = spawn(process.execPath, [this.executablePath, ...args], {
|
|
130
|
+
const child = spawn(process.execPath, [this.executablePath, ...args], {
|
|
131
|
+
cwd: this.input.spawnCwd,
|
|
132
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
133
|
+
});
|
|
70
134
|
let stderr = "";
|
|
71
135
|
child.stderr?.on("data", (chunk) => {
|
|
72
136
|
stderr += chunk.toString();
|
|
@@ -75,15 +139,26 @@ var NornProcessRunner = class {
|
|
|
75
139
|
for await (const line of lines) {
|
|
76
140
|
if (line.trim().length === 0) continue;
|
|
77
141
|
const parsed = JSON.parse(line);
|
|
78
|
-
if (parsed.error)
|
|
142
|
+
if (parsed.error)
|
|
143
|
+
throw new Error(
|
|
144
|
+
String(
|
|
145
|
+
parsed.error.message ?? "Norn stream failed"
|
|
146
|
+
)
|
|
147
|
+
);
|
|
79
148
|
yield parsed;
|
|
80
149
|
}
|
|
81
|
-
const exitCode = await new Promise(
|
|
82
|
-
|
|
150
|
+
const exitCode = await new Promise(
|
|
151
|
+
(resolvePromise) => child.on("close", resolvePromise)
|
|
152
|
+
);
|
|
153
|
+
if (exitCode !== 0)
|
|
154
|
+
throw new Error(stderr || `Norn exited with code ${exitCode}`);
|
|
83
155
|
}
|
|
84
156
|
async spawn(args, stdin) {
|
|
85
157
|
return new Promise((resolvePromise, reject) => {
|
|
86
|
-
const child = spawn(process.execPath, [this.executablePath, ...args], {
|
|
158
|
+
const child = spawn(process.execPath, [this.executablePath, ...args], {
|
|
159
|
+
cwd: this.input.spawnCwd,
|
|
160
|
+
stdio: [stdin === void 0 ? "ignore" : "pipe", "pipe", "pipe"]
|
|
161
|
+
});
|
|
87
162
|
let stdout = "";
|
|
88
163
|
let stderr = "";
|
|
89
164
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -94,7 +169,10 @@ var NornProcessRunner = class {
|
|
|
94
169
|
});
|
|
95
170
|
child.on("error", reject);
|
|
96
171
|
if (stdin !== void 0) child.stdin?.end(stdin);
|
|
97
|
-
child.on(
|
|
172
|
+
child.on(
|
|
173
|
+
"close",
|
|
174
|
+
(exitCode) => resolvePromise({ stdout, stderr, exitCode })
|
|
175
|
+
);
|
|
98
176
|
});
|
|
99
177
|
}
|
|
100
178
|
};
|
package/dist/documentation.js
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
// src/documentation.ts
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
lstat,
|
|
5
|
+
mkdir,
|
|
6
|
+
mkdtemp,
|
|
7
|
+
readFile,
|
|
8
|
+
readdir,
|
|
9
|
+
rename,
|
|
10
|
+
rm,
|
|
11
|
+
writeFile
|
|
12
|
+
} from "node:fs/promises";
|
|
4
13
|
import { join, resolve } from "node:path";
|
|
5
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
DOCUMENTATION_PATHS,
|
|
16
|
+
hashDocumentationBundle,
|
|
17
|
+
validateDocumentationBundle
|
|
18
|
+
} from "./internal/documentation-bundle.js";
|
|
6
19
|
|
|
7
20
|
// ../core/src/errors.ts
|
|
8
21
|
function isNodeError(error) {
|
|
@@ -14,10 +27,20 @@ import { renderNornDocumentationIntro } from "./documentation-intro.js";
|
|
|
14
27
|
function resolveDocumentationCacheRoot(input) {
|
|
15
28
|
const override = input.environment.NORN_DOCS_CACHE_DIR;
|
|
16
29
|
if (override) return resolve(override);
|
|
17
|
-
if (input.platform === "win32")
|
|
18
|
-
|
|
30
|
+
if (input.platform === "win32")
|
|
31
|
+
return join(
|
|
32
|
+
input.environment.LOCALAPPDATA || join(input.home, "AppData", "Local"),
|
|
33
|
+
"norn",
|
|
34
|
+
"docs"
|
|
35
|
+
);
|
|
36
|
+
if (input.platform === "darwin")
|
|
37
|
+
return join(input.home, "Library", "Caches", "norn", "docs");
|
|
19
38
|
const xdgCache = input.environment.XDG_CACHE_HOME;
|
|
20
|
-
return join(
|
|
39
|
+
return join(
|
|
40
|
+
xdgCache?.startsWith("/") ? xdgCache : join(input.home, ".cache"),
|
|
41
|
+
"norn",
|
|
42
|
+
"docs"
|
|
43
|
+
);
|
|
21
44
|
}
|
|
22
45
|
async function resolveNornDocumentation(input) {
|
|
23
46
|
let root;
|
|
@@ -25,18 +48,38 @@ async function resolveNornDocumentation(input) {
|
|
|
25
48
|
let assetDigest = null;
|
|
26
49
|
if (input.source.kind === "local") {
|
|
27
50
|
root = resolve(input.source.root);
|
|
28
|
-
const packageInfo = JSON.parse(
|
|
29
|
-
|
|
51
|
+
const packageInfo = JSON.parse(
|
|
52
|
+
await readFile(join(root, "package.json"), "utf8")
|
|
53
|
+
);
|
|
54
|
+
if (typeof packageInfo.version !== "string" || packageInfo.version.length === 0)
|
|
55
|
+
throw new Error("Invalid documentation package version");
|
|
30
56
|
version = packageInfo.version;
|
|
31
|
-
if (version !== input.build.version)
|
|
57
|
+
if (version !== input.build.version)
|
|
58
|
+
throw new Error(
|
|
59
|
+
"Local documentation version does not match the runtime; rebuild or reinstall this CLI package"
|
|
60
|
+
);
|
|
32
61
|
await validateLocalDocumentation(root);
|
|
33
62
|
} else {
|
|
34
63
|
validateDocumentationBundle(input.source.bundle);
|
|
35
64
|
version = input.source.bundle.version;
|
|
36
|
-
if (version !== input.build.version)
|
|
65
|
+
if (version !== input.build.version)
|
|
66
|
+
throw new Error(
|
|
67
|
+
"Embedded documentation version does not match the binary build"
|
|
68
|
+
);
|
|
37
69
|
assetDigest = hashDocumentationBundle(input.source.bundle);
|
|
38
|
-
const cacheKey = createHash("sha256").update(
|
|
39
|
-
|
|
70
|
+
const cacheKey = createHash("sha256").update(
|
|
71
|
+
JSON.stringify({
|
|
72
|
+
format: 1,
|
|
73
|
+
assetDigest,
|
|
74
|
+
version,
|
|
75
|
+
commit: input.build.commit
|
|
76
|
+
})
|
|
77
|
+
).digest("hex");
|
|
78
|
+
root = await new NornDocumentationCache({
|
|
79
|
+
cacheRoot: resolve(input.cacheRoot),
|
|
80
|
+
cacheKey,
|
|
81
|
+
bundle: input.source.bundle
|
|
82
|
+
}).materialize();
|
|
40
83
|
}
|
|
41
84
|
return {
|
|
42
85
|
storage: input.source.kind === "local" ? "installation" : "cache",
|
|
@@ -56,14 +99,17 @@ async function validateLocalDocumentation(root) {
|
|
|
56
99
|
for (const [key, path] of Object.entries(DOCUMENTATION_PATHS)) {
|
|
57
100
|
const stat = await lstat(join(root, path));
|
|
58
101
|
const isExpectedType = key === "docs" || key === "examples" ? stat.isDirectory() : stat.isFile();
|
|
59
|
-
if (!isExpectedType)
|
|
102
|
+
if (!isExpectedType)
|
|
103
|
+
throw new Error(`Invalid local documentation path: ${join(root, path)}`);
|
|
60
104
|
}
|
|
61
105
|
}
|
|
62
106
|
var NornDocumentationCache = class {
|
|
63
107
|
constructor(input) {
|
|
64
108
|
this.input = input;
|
|
65
109
|
this.root = join(input.cacheRoot, `v1-${input.cacheKey}`);
|
|
66
|
-
this.files = new Map(
|
|
110
|
+
this.files = new Map(
|
|
111
|
+
input.bundle.files.map((file) => [file.path, file.content])
|
|
112
|
+
);
|
|
67
113
|
}
|
|
68
114
|
input;
|
|
69
115
|
root;
|
|
@@ -71,22 +117,36 @@ var NornDocumentationCache = class {
|
|
|
71
117
|
async materialize() {
|
|
72
118
|
await mkdir(this.input.cacheRoot, { recursive: true, mode: 448 });
|
|
73
119
|
const cacheStat = await lstat(this.input.cacheRoot);
|
|
74
|
-
if (!cacheStat.isDirectory() || cacheStat.isSymbolicLink())
|
|
120
|
+
if (!cacheStat.isDirectory() || cacheStat.isSymbolicLink())
|
|
121
|
+
throw new Error(
|
|
122
|
+
`Documentation cache root must be a real directory: ${this.input.cacheRoot}`
|
|
123
|
+
);
|
|
75
124
|
if (await this.validateExistingCache()) return this.root;
|
|
76
125
|
const staging = await mkdtemp(join(this.input.cacheRoot, ".extract-"));
|
|
77
126
|
try {
|
|
78
127
|
for (const file of this.input.bundle.files) {
|
|
79
128
|
const parts = file.path.split("/");
|
|
80
|
-
await mkdir(join(staging, ...parts.slice(0, -1)), {
|
|
81
|
-
|
|
129
|
+
await mkdir(join(staging, ...parts.slice(0, -1)), {
|
|
130
|
+
recursive: true,
|
|
131
|
+
mode: 448
|
|
132
|
+
});
|
|
133
|
+
await writeFile(join(staging, ...parts), file.content, {
|
|
134
|
+
encoding: "utf8",
|
|
135
|
+
flag: "wx",
|
|
136
|
+
mode: 384
|
|
137
|
+
});
|
|
82
138
|
}
|
|
83
139
|
try {
|
|
84
140
|
await rename(staging, this.root);
|
|
85
141
|
} catch (error) {
|
|
86
|
-
if (!isNodeError(error) || !["EEXIST", "ENOTEMPTY", "EPERM", "EACCES"].includes(error.code ?? ""))
|
|
142
|
+
if (!isNodeError(error) || !["EEXIST", "ENOTEMPTY", "EPERM", "EACCES"].includes(error.code ?? ""))
|
|
143
|
+
throw error;
|
|
87
144
|
if (!await this.validateExistingCache()) throw error;
|
|
88
145
|
}
|
|
89
|
-
if (!await this.validateExistingCache())
|
|
146
|
+
if (!await this.validateExistingCache())
|
|
147
|
+
throw new Error(
|
|
148
|
+
`Documentation cache disappeared after extraction: ${this.root}`
|
|
149
|
+
);
|
|
90
150
|
return this.root;
|
|
91
151
|
} finally {
|
|
92
152
|
await rm(staging, { recursive: true, force: true });
|
|
@@ -100,21 +160,36 @@ var NornDocumentationCache = class {
|
|
|
100
160
|
if (isNodeError(error) && error.code === "ENOENT") return false;
|
|
101
161
|
throw error;
|
|
102
162
|
}
|
|
103
|
-
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
163
|
+
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
164
|
+
throw this.invalidCacheError();
|
|
104
165
|
const seenFiles = /* @__PURE__ */ new Set();
|
|
105
|
-
await this.validateDirectory({
|
|
166
|
+
await this.validateDirectory({
|
|
167
|
+
directory: this.root,
|
|
168
|
+
prefix: "",
|
|
169
|
+
seenFiles
|
|
170
|
+
});
|
|
106
171
|
if (seenFiles.size !== this.files.size) throw this.invalidCacheError();
|
|
107
172
|
return true;
|
|
108
173
|
}
|
|
109
174
|
async validateDirectory(input) {
|
|
110
|
-
for (const entry of await readdir(input.directory, {
|
|
175
|
+
for (const entry of await readdir(input.directory, {
|
|
176
|
+
withFileTypes: true
|
|
177
|
+
})) {
|
|
111
178
|
const path = input.prefix ? `${input.prefix}/${entry.name}` : entry.name;
|
|
112
179
|
const absolutePath = join(input.directory, entry.name);
|
|
113
180
|
if (entry.isDirectory()) {
|
|
114
|
-
if (![...this.files.keys()].some((file) => file.startsWith(`${path}/`)))
|
|
115
|
-
|
|
181
|
+
if (![...this.files.keys()].some((file) => file.startsWith(`${path}/`)))
|
|
182
|
+
throw this.invalidCacheError();
|
|
183
|
+
await this.validateDirectory({
|
|
184
|
+
directory: absolutePath,
|
|
185
|
+
prefix: path,
|
|
186
|
+
seenFiles: input.seenFiles
|
|
187
|
+
});
|
|
116
188
|
} else if (entry.isFile() && this.files.has(path)) {
|
|
117
|
-
if (!(await readFile(absolutePath)).equals(
|
|
189
|
+
if (!(await readFile(absolutePath)).equals(
|
|
190
|
+
Buffer.from(this.files.get(path), "utf8")
|
|
191
|
+
))
|
|
192
|
+
throw this.invalidCacheError();
|
|
118
193
|
input.seenFiles.add(path);
|
|
119
194
|
} else {
|
|
120
195
|
throw this.invalidCacheError();
|
|
@@ -122,7 +197,9 @@ var NornDocumentationCache = class {
|
|
|
122
197
|
}
|
|
123
198
|
}
|
|
124
199
|
invalidCacheError() {
|
|
125
|
-
return new Error(
|
|
200
|
+
return new Error(
|
|
201
|
+
`Documentation cache is incomplete or modified: ${this.root}. Remove this cache entry and retry; copy examples elsewhere before editing them.`
|
|
202
|
+
);
|
|
126
203
|
}
|
|
127
204
|
};
|
|
128
205
|
export {
|
|
@@ -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.35724621678.1";
|
|
4
|
+
readonly commit: "51ea925604755506d4cde05b9224eacb48189ffd";
|
|
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.35724621678.1",
|
|
5
|
+
"commit": "51ea925604755506d4cde05b9224eacb48189ffd",
|
|
6
6
|
"packageSpec": "@vimhead.dev/norn-cli@tip",
|
|
7
7
|
"upgrade": {
|
|
8
8
|
"supported": false,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// src/internal/agent-directory.ts
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
function resolveNornAgentDirectory(input) {
|
|
4
|
-
return resolve(
|
|
4
|
+
return resolve(
|
|
5
|
+
input.environment.NORN_AGENT_DIR || join(input.home, ".norn", "agent")
|
|
6
|
+
);
|
|
5
7
|
}
|
|
6
8
|
export {
|
|
7
9
|
resolveNornAgentDirectory
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// src/internal/agent-response-tool.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
defineTool
|
|
4
|
+
} from "@earendil-works/pi-coding-agent";
|
|
3
5
|
|
|
4
6
|
// ../core/src/agent-protocol.ts
|
|
5
7
|
var AGENT_RESPONSE_TOOL_NAME = "pi_workflows_agent_response";
|
|
@@ -16,11 +18,15 @@ var NornAgentResponseCollector = class {
|
|
|
16
18
|
}
|
|
17
19
|
capture(runId, label, response) {
|
|
18
20
|
const pending = this.pending.get(runId);
|
|
19
|
-
if (!pending)
|
|
21
|
+
if (!pending)
|
|
22
|
+
throw new Error(`No active workflow agent response slot: ${runId}`);
|
|
20
23
|
if (pending.label !== label) {
|
|
21
|
-
throw new Error(
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Workflow agent response label mismatch: expected ${pending.label}, received ${label}`
|
|
26
|
+
);
|
|
22
27
|
}
|
|
23
|
-
if (pending.called)
|
|
28
|
+
if (pending.called)
|
|
29
|
+
throw new Error(`Workflow agent response already recorded for ${runId}`);
|
|
24
30
|
const decoded = Value.Decode(pending.responseSchema, response);
|
|
25
31
|
pending.called = true;
|
|
26
32
|
pending.response = decoded;
|
|
@@ -48,16 +54,36 @@ var NornAgentResponseToolFactory = class {
|
|
|
48
54
|
`After calling ${AGENT_RESPONSE_TOOL_NAME}, do not emit another assistant response in the same turn.`
|
|
49
55
|
],
|
|
50
56
|
parameters: Type.Object({
|
|
51
|
-
runId: Type.String({
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
runId: Type.String({
|
|
58
|
+
description: "The exact workflow response runId provided in the prompt."
|
|
59
|
+
}),
|
|
60
|
+
label: Type.String({
|
|
61
|
+
description: "The exact workflow agent label provided in the prompt."
|
|
62
|
+
}),
|
|
63
|
+
response: Type.Unknown({
|
|
64
|
+
description: "The structured response object requested by the workflow."
|
|
65
|
+
})
|
|
54
66
|
}),
|
|
55
67
|
async execute(_toolCallId, args) {
|
|
56
68
|
try {
|
|
57
|
-
const captured = responseCollector.capture(
|
|
69
|
+
const captured = responseCollector.capture(
|
|
70
|
+
args.runId,
|
|
71
|
+
args.label,
|
|
72
|
+
args.response
|
|
73
|
+
);
|
|
58
74
|
return {
|
|
59
|
-
content: [
|
|
60
|
-
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: "text",
|
|
78
|
+
text: `Recorded workflow agent response for ${captured.label}.`
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
details: {
|
|
82
|
+
valid: true,
|
|
83
|
+
runId: args.runId,
|
|
84
|
+
label: captured.label,
|
|
85
|
+
response: captured.response
|
|
86
|
+
},
|
|
61
87
|
terminate: true
|
|
62
88
|
};
|
|
63
89
|
} catch (error) {
|
|
@@ -69,7 +95,12 @@ var NornAgentResponseToolFactory = class {
|
|
|
69
95
|
};
|
|
70
96
|
function invalidAgentResponseToolResult(error) {
|
|
71
97
|
return {
|
|
72
|
-
content: [
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: "text",
|
|
101
|
+
text: `Invalid workflow agent response: ${error}. Call the tool again with a corrected response.`
|
|
102
|
+
}
|
|
103
|
+
],
|
|
73
104
|
details: { valid: false, error }
|
|
74
105
|
};
|
|
75
106
|
}
|