@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.
Files changed (119) hide show
  1. package/assets/README.md +41 -13
  2. package/assets/docs/README.md +16 -16
  3. package/assets/docs/agents.md +23 -15
  4. package/assets/docs/cli.md +10 -8
  5. package/assets/docs/composition.md +7 -7
  6. package/assets/docs/persistence.md +22 -22
  7. package/assets/docs/projects.md +6 -6
  8. package/assets/docs/recovery.md +10 -10
  9. package/assets/docs/schemas.md +42 -36
  10. package/assets/docs/workflows.md +39 -32
  11. package/assets/examples/agent-then-analysis/input.json +3 -3
  12. package/assets/examples/agent-then-analysis/norn.project.json +2 -2
  13. package/assets/examples/agent-then-analysis/plugin.ts +37 -9
  14. package/assets/examples/caller-owned-routing/README.md +6 -6
  15. package/assets/examples/caller-owned-routing/assessment.ts +18 -4
  16. package/assets/examples/caller-owned-routing/contracts.ts +7 -2
  17. package/assets/examples/caller-owned-routing/input.json +12 -12
  18. package/assets/examples/caller-owned-routing/norn.project.json +2 -2
  19. package/assets/examples/caller-owned-routing/revision.ts +7 -2
  20. package/assets/examples/caller-owned-routing/router.ts +14 -3
  21. package/assets/examples/caller-selected-continuation/caller.ts +38 -12
  22. package/assets/examples/caller-selected-continuation/input.json +7 -7
  23. package/assets/examples/caller-selected-continuation/norn.project.json +2 -2
  24. package/assets/examples/caller-selected-continuation/producer.ts +10 -3
  25. package/assets/examples/coordinating-multiple-agents/README.md +6 -6
  26. package/assets/examples/coordinating-multiple-agents/input.json +20 -8
  27. package/assets/examples/coordinating-multiple-agents/norn.project.json +2 -2
  28. package/assets/examples/coordinating-multiple-agents/plugin.ts +165 -46
  29. package/assets/examples/coordinating-multiple-agents/queue-tools.ts +30 -7
  30. package/assets/examples/coordinating-multiple-agents/work-queue.ts +211 -63
  31. package/assets/examples/getting-started/norn.project.json +2 -2
  32. package/assets/examples/getting-started/plugin.ts +33 -13
  33. package/assets/examples/minimal-workflow/norn.project.json +2 -2
  34. package/assets/examples/minimal-workflow/plugin.ts +12 -3
  35. package/assets/examples/shared-state/README.md +6 -6
  36. package/assets/examples/shared-state/input.json +1 -1
  37. package/assets/examples/shared-state/norn.project.json +2 -2
  38. package/assets/examples/shared-state/plugin.ts +44 -15
  39. package/assets/examples/shared-state/shared-state.ts +46 -13
  40. package/assets/examples/shared-state/state-tools.ts +68 -16
  41. package/assets/examples/worktree-development-loop/README.md +12 -12
  42. package/assets/examples/worktree-development-loop/norn.project.json +7 -7
  43. package/assets/examples/worktree-development-loop/plugin.ts +7 -1
  44. package/assets/examples/worktree-development-loop/scope.ts +4 -1
  45. package/assets/examples/worktree-development-loop/shared/commands.ts +6 -2
  46. package/assets/examples/worktree-development-loop/workflows/development-loop/execute.ts +18 -4
  47. package/assets/examples/worktree-development-loop/workflows/development-loop/index.ts +4 -1
  48. package/assets/examples/worktree-development-loop/workflows/development-loop/repository.ts +11 -1
  49. package/assets/examples/worktree-development-loop/workflows/development-loop/schema.ts +6 -2
  50. package/assets/examples/worktree-development-loop/workflows/implementation/execute.ts +40 -10
  51. package/assets/examples/worktree-development-loop/workflows/implementation/index.ts +5 -1
  52. package/assets/examples/worktree-development-loop/workflows/planning/execute.ts +1 -1
  53. package/assets/examples/worktree-development-loop/workflows/planning/index.ts +5 -1
  54. package/assets/examples/worktree-development-loop/workflows/review/execute.ts +33 -9
  55. package/assets/examples/worktree-development-loop/workflows/review-router/execute.ts +51 -8
  56. package/assets/package.json +1 -1
  57. package/assets/packages/cli/src/build-info.ts +4 -1
  58. package/assets/packages/cli/src/bun/cli.ts +21 -5
  59. package/assets/packages/cli/src/cli.ts +585 -170
  60. package/assets/packages/cli/src/client.ts +194 -36
  61. package/assets/packages/cli/src/documentation.ts +135 -30
  62. package/assets/packages/cli/src/generated-build-info.ts +2 -2
  63. package/assets/packages/cli/src/internal/agent-directory.ts +7 -2
  64. package/assets/packages/cli/src/internal/agent-response-tool.ts +57 -15
  65. package/assets/packages/cli/src/internal/agents.ts +248 -60
  66. package/assets/packages/cli/src/internal/commands.ts +82 -20
  67. package/assets/packages/cli/src/internal/documentation-bundle.ts +44 -13
  68. package/assets/packages/cli/src/internal/engine.ts +396 -87
  69. package/assets/packages/cli/src/internal/errors.ts +13 -5
  70. package/assets/packages/cli/src/internal/execution-context.ts +20 -12
  71. package/assets/packages/cli/src/internal/file-coordinator.ts +95 -26
  72. package/assets/packages/cli/src/internal/file-names.ts +4 -1
  73. package/assets/packages/cli/src/internal/launch-request.ts +74 -22
  74. package/assets/packages/cli/src/internal/logs.ts +10 -2
  75. package/assets/packages/cli/src/internal/metrics.ts +247 -61
  76. package/assets/packages/cli/src/internal/pi-assets.ts +105 -23
  77. package/assets/packages/cli/src/internal/run-lease.ts +72 -22
  78. package/assets/packages/cli/src/internal/run-log.ts +49 -20
  79. package/assets/packages/cli/src/internal/run-names.ts +120 -12
  80. package/assets/packages/cli/src/internal/run-state.ts +306 -71
  81. package/assets/packages/cli/src/internal/run-store.ts +216 -53
  82. package/assets/packages/cli/src/internal/usage.ts +23 -7
  83. package/assets/packages/cli/src/internal/worker-directory.ts +9 -3
  84. package/assets/packages/cli/src/internal/workflow-registry.ts +281 -70
  85. package/assets/packages/cli/src/internal/working-directory.ts +2 -1
  86. package/assets/packages/cli/src/workflow-loader.ts +341 -74
  87. package/assets/packages/core/src/atomic-files.ts +13 -4
  88. package/assets/packages/core/src/workflow-transition.ts +13 -2
  89. package/assets/packages/sdk/src/api.ts +248 -80
  90. package/assets/packages/sdk/src/index.ts +6 -1
  91. package/assets/packages/sdk/src/schema.ts +75 -21
  92. package/assets/tests/workflow-ref.test.ts +242 -57
  93. package/bin/norn.mjs +13 -4
  94. package/dist/cli.js +344 -90
  95. package/dist/client.js +100 -22
  96. package/dist/documentation.js +102 -25
  97. package/dist/generated-build-info.d.ts +2 -2
  98. package/dist/generated-build-info.js +2 -2
  99. package/dist/internal/agent-directory.js +3 -1
  100. package/dist/internal/agent-response-tool.js +42 -11
  101. package/dist/internal/agents.js +149 -37
  102. package/dist/internal/commands.js +65 -16
  103. package/dist/internal/documentation-bundle.js +23 -11
  104. package/dist/internal/engine.js +304 -66
  105. package/dist/internal/errors.js +4 -2
  106. package/dist/internal/execution-context.js +2 -1
  107. package/dist/internal/file-coordinator.js +59 -19
  108. package/dist/internal/launch-request.js +32 -14
  109. package/dist/internal/metrics.js +138 -38
  110. package/dist/internal/pi-assets.js +70 -19
  111. package/dist/internal/run-lease.js +29 -9
  112. package/dist/internal/run-log.js +24 -12
  113. package/dist/internal/run-state.js +172 -48
  114. package/dist/internal/run-store.js +157 -45
  115. package/dist/internal/worker-directory.js +6 -2
  116. package/dist/internal/workflow-registry.js +123 -32
  117. package/dist/internal/working-directory.js +2 -1
  118. package/dist/workflow-loader.js +198 -41
  119. 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(["workflows", "list", ...options?.all ? ["--all"] : []]),
17
- inspect: async (workflowId) => processRunner.readJson(["workflows", "inspect", workflowId]),
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(["runs", "start", startInput.workflowId], JSON.stringify(runStartInput(startInput)))).run,
22
- resume: async (resumeInput) => (await processRunner.readJson(["runs", "resume", resumeInput.run], runResumeStdin(resumeInput))).run,
23
- wait: async (run) => (await processRunner.readJson(["runs", "wait", run])).run,
24
- list: async () => (await processRunner.readJson(["runs", "list"])).runs,
25
- inspect: async (run) => (await processRunner.readJson(["runs", "inspect", run])).run,
26
- checkpoints: async (run) => (await processRunner.readJson(["runs", "checkpoints", run])).checkpoints,
27
- metrics: async (run) => (await processRunner.readJson(["runs", "metrics", run])).metrics,
28
- rollback: async (run, checkpointId) => (await processRunner.readJson(["runs", "rollback", run, checkpointId])).run,
29
- stop: async (run) => (await processRunner.readJson(["runs", "stop", run])).run,
30
- kill: async (run) => (await processRunner.readJson(["runs", "kill", run])).run,
31
- delete: async (run) => (await processRunner.readJson(["runs", "delete", run])).deleted,
32
- logs: (run, options) => processRunner.readJsonLines(["runs", "logs", run, ...options?.follow ? ["--follow"] : []])
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)) throw new NornProjectLoadError({ diagnostics: 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) throw new Error(result.stderr || `Norn exited with code ${result.exitCode}`);
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], { cwd: this.input.spawnCwd, stdio: ["ignore", "pipe", "pipe"] });
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) throw new Error(String(parsed.error.message ?? "Norn stream failed"));
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((resolvePromise) => child.on("close", resolvePromise));
82
- if (exitCode !== 0) throw new Error(stderr || `Norn exited with code ${exitCode}`);
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], { cwd: this.input.spawnCwd, stdio: [stdin === void 0 ? "ignore" : "pipe", "pipe", "pipe"] });
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("close", (exitCode) => resolvePromise({ stdout, stderr, exitCode }));
172
+ child.on(
173
+ "close",
174
+ (exitCode) => resolvePromise({ stdout, stderr, exitCode })
175
+ );
98
176
  });
99
177
  }
100
178
  };
@@ -1,8 +1,21 @@
1
1
  // src/documentation.ts
2
2
  import { createHash } from "node:crypto";
3
- import { lstat, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
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 { DOCUMENTATION_PATHS, hashDocumentationBundle, validateDocumentationBundle } from "./internal/documentation-bundle.js";
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") return join(input.environment.LOCALAPPDATA || join(input.home, "AppData", "Local"), "norn", "docs");
18
- if (input.platform === "darwin") return join(input.home, "Library", "Caches", "norn", "docs");
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(xdgCache?.startsWith("/") ? xdgCache : join(input.home, ".cache"), "norn", "docs");
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(await readFile(join(root, "package.json"), "utf8"));
29
- if (typeof packageInfo.version !== "string" || packageInfo.version.length === 0) throw new Error("Invalid documentation package version");
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) throw new Error("Local documentation version does not match the runtime; rebuild or reinstall this CLI package");
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) throw new Error("Embedded documentation version does not match the binary build");
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(JSON.stringify({ format: 1, assetDigest, version, commit: input.build.commit })).digest("hex");
39
- root = await new NornDocumentationCache({ cacheRoot: resolve(input.cacheRoot), cacheKey, bundle: input.source.bundle }).materialize();
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) throw new Error(`Invalid local documentation path: ${join(root, path)}`);
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(input.bundle.files.map((file) => [file.path, file.content]));
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()) throw new Error(`Documentation cache root must be a real directory: ${this.input.cacheRoot}`);
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)), { recursive: true, mode: 448 });
81
- await writeFile(join(staging, ...parts), file.content, { encoding: "utf8", flag: "wx", mode: 384 });
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 ?? "")) throw error;
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()) throw new Error(`Documentation cache disappeared after extraction: ${this.root}`);
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()) throw this.invalidCacheError();
163
+ if (!stat.isDirectory() || stat.isSymbolicLink())
164
+ throw this.invalidCacheError();
104
165
  const seenFiles = /* @__PURE__ */ new Set();
105
- await this.validateDirectory({ directory: this.root, prefix: "", seenFiles });
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, { withFileTypes: true })) {
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}/`))) throw this.invalidCacheError();
115
- await this.validateDirectory({ directory: absolutePath, prefix: path, seenFiles: input.seenFiles });
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(Buffer.from(this.files.get(path), "utf8"))) throw this.invalidCacheError();
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(`Documentation cache is incomplete or modified: ${this.root}. Remove this cache entry and retry; copy examples elsewhere before editing them.`);
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.35614826665.1";
4
- readonly commit: "286e68533b1d26b5afbb0cba9d75f857fb85dc53";
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.35614826665.1",
5
- "commit": "286e68533b1d26b5afbb0cba9d75f857fb85dc53",
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(input.environment.NORN_AGENT_DIR || join(input.home, ".norn", "agent"));
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 { defineTool } from "@earendil-works/pi-coding-agent";
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) throw new Error(`No active workflow agent response slot: ${runId}`);
21
+ if (!pending)
22
+ throw new Error(`No active workflow agent response slot: ${runId}`);
20
23
  if (pending.label !== label) {
21
- throw new Error(`Workflow agent response label mismatch: expected ${pending.label}, received ${label}`);
24
+ throw new Error(
25
+ `Workflow agent response label mismatch: expected ${pending.label}, received ${label}`
26
+ );
22
27
  }
23
- if (pending.called) throw new Error(`Workflow agent response already recorded for ${runId}`);
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({ description: "The exact workflow response runId provided in the prompt." }),
52
- label: Type.String({ description: "The exact workflow agent label provided in the prompt." }),
53
- response: Type.Unknown({ description: "The structured response object requested by the workflow." })
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(args.runId, args.label, args.response);
69
+ const captured = responseCollector.capture(
70
+ args.runId,
71
+ args.label,
72
+ args.response
73
+ );
58
74
  return {
59
- content: [{ type: "text", text: `Recorded workflow agent response for ${captured.label}.` }],
60
- details: { valid: true, runId: args.runId, label: captured.label, response: captured.response },
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: [{ type: "text", text: `Invalid workflow agent response: ${error}. Call the tool again with a corrected response.` }],
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
  }