pi-harness-runtime 0.9.25 → 0.10.0

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 (321) hide show
  1. package/CHANGELOG.md +27 -7
  2. package/README.md +51 -51
  3. package/harness/auto-compact.ts +1 -1
  4. package/harness/autonomous-review.ts +88 -0
  5. package/harness/context-compact-orchestrator.ts +23 -23
  6. package/harness/context-window-manager.ts +5 -5
  7. package/harness/continue-prompt.ts +3 -3
  8. package/harness/e2e/minimax-quota-scraper.ts +1 -1
  9. package/harness/forked-summarizer.ts +4 -4
  10. package/harness/herdr-agents.ts +91 -0
  11. package/harness/index.ts +5 -5
  12. package/harness/loop-code-agent.ts +284 -0
  13. package/harness/loop-controller.ts +201 -0
  14. package/harness/loop-review-agent.ts +295 -0
  15. package/harness/loop-runtime.ts +10 -10
  16. package/harness/loop-types.ts +118 -0
  17. package/harness/notification-events.ts +3 -3
  18. package/harness/output-limit-handler.ts +1 -1
  19. package/harness/partial-recovery.ts +3 -3
  20. package/harness/session-memory.ts +5 -5
  21. package/index.ts +46 -32
  22. package/package.json +1 -1
  23. package/packages/a2a-adapter/package.json +1 -1
  24. package/packages/a2a-adapter/src/types.ts +5 -5
  25. package/packages/auth/package.json +1 -1
  26. package/packages/autonomous-refactor/package.json +1 -1
  27. package/packages/autonomous-runtime/dist/inbox.d.ts +3 -3
  28. package/packages/autonomous-runtime/dist/inbox.js +12 -12
  29. package/packages/autonomous-runtime/dist/lease.js +14 -14
  30. package/packages/autonomous-runtime/dist/types.js +1 -1
  31. package/packages/autonomous-runtime/package.json +1 -1
  32. package/packages/autonomous-runtime/src/inbox.ts +12 -12
  33. package/packages/autonomous-runtime/src/lease.ts +15 -15
  34. package/packages/autonomous-runtime/src/types.ts +13 -13
  35. package/packages/autonomous-runtime/tsconfig.tsbuildinfo +1 -1
  36. package/packages/cache-strategy/package.json +1 -1
  37. package/packages/capability-registry/dist/types.js +1 -1
  38. package/packages/capability-registry/package.json +1 -1
  39. package/packages/capability-registry/src/types.ts +5 -5
  40. package/packages/checkpoint/README.md +6 -6
  41. package/packages/checkpoint/dist/differ.js +2 -2
  42. package/packages/checkpoint/dist/engine.js +3 -3
  43. package/packages/checkpoint/dist/index.js +5 -5
  44. package/packages/checkpoint/dist/storage.js +3 -3
  45. package/packages/checkpoint/dist/types.js +1 -1
  46. package/packages/checkpoint/package.json +1 -1
  47. package/packages/checkpoint/src/differ.ts +2 -2
  48. package/packages/checkpoint/src/engine.ts +3 -3
  49. package/packages/checkpoint/src/index.ts +5 -5
  50. package/packages/checkpoint/src/storage.ts +3 -3
  51. package/packages/checkpoint/src/types.ts +10 -10
  52. package/packages/checkpoint/tsconfig.tsbuildinfo +1 -1
  53. package/packages/cli-plugin-sdk/package.json +1 -1
  54. package/packages/clipboard/dist/src/clipboard.d.ts.map +1 -1
  55. package/packages/clipboard/dist/src/clipboard.js +15 -7
  56. package/packages/clipboard/dist/src/clipboard.js.map +1 -1
  57. package/packages/clipboard/package.json +1 -1
  58. package/packages/clipboard/src/clipboard.ts +16 -9
  59. package/packages/code-generation/README.md +13 -13
  60. package/packages/code-generation/dist/faker.js +4 -4
  61. package/packages/code-generation/dist/generator.js +3 -3
  62. package/packages/code-generation/dist/index.js +3 -3
  63. package/packages/code-generation/dist/templates/registry.js +1 -1
  64. package/packages/code-generation/dist/types.js +1 -1
  65. package/packages/code-generation/package.json +1 -1
  66. package/packages/code-generation/src/faker.ts +5 -5
  67. package/packages/code-generation/src/generator.ts +4 -4
  68. package/packages/code-generation/src/index.ts +3 -3
  69. package/packages/code-generation/src/templates/registry.ts +1 -1
  70. package/packages/code-generation/src/types.ts +10 -10
  71. package/packages/code-generation/tsconfig.tsbuildinfo +1 -1
  72. package/packages/code-review/README.md +13 -13
  73. package/packages/code-review/dist/engine.js +3 -3
  74. package/packages/code-review/dist/index.js +3 -3
  75. package/packages/code-review/dist/types.js +1 -1
  76. package/packages/code-review/package.json +1 -1
  77. package/packages/code-review/src/engine.ts +3 -3
  78. package/packages/code-review/src/index.ts +3 -3
  79. package/packages/code-review/src/types.ts +10 -10
  80. package/packages/code-review/tsconfig.tsbuildinfo +1 -1
  81. package/packages/codex-adapter/package.json +1 -1
  82. package/packages/context-compiler/dist/compiler.js +1 -1
  83. package/packages/context-compiler/package.json +1 -1
  84. package/packages/context-compiler/src/compiler.ts +1 -1
  85. package/packages/context-compiler/src/types.ts +11 -11
  86. package/packages/context-compiler/test/context-compiler.test.ts +11 -11
  87. package/packages/context-discovery/package.json +1 -1
  88. package/packages/context-manager/package.json +1 -1
  89. package/packages/cookie-sanitizer/README.md +27 -27
  90. package/packages/cookie-sanitizer/package.json +1 -1
  91. package/packages/cost-optimizer/package.json +1 -1
  92. package/packages/cost-optimizer/src/types.ts +5 -5
  93. package/packages/dependency-analyzer/package.json +1 -1
  94. package/packages/django-plugin/dist/analyzer.js +7 -7
  95. package/packages/django-plugin/package.json +1 -1
  96. package/packages/django-plugin/src/analyzer.ts +7 -7
  97. package/packages/doc-generator/package.json +1 -1
  98. package/packages/evaluation-engine/dist/engine.js +9 -9
  99. package/packages/evaluation-engine/package.json +1 -1
  100. package/packages/evaluation-engine/src/engine.ts +9 -9
  101. package/packages/evaluation-engine/src/types.ts +3 -3
  102. package/packages/evaluation-runner/package.json +1 -1
  103. package/packages/event-bus/dist/src/herdr-bus.d.ts +121 -0
  104. package/packages/event-bus/dist/src/herdr-bus.d.ts.map +1 -0
  105. package/packages/event-bus/dist/src/herdr-bus.js +322 -0
  106. package/packages/event-bus/dist/src/herdr-bus.js.map +1 -0
  107. package/packages/event-bus/dist/src/index.d.ts +2 -0
  108. package/packages/event-bus/dist/src/index.d.ts.map +1 -1
  109. package/packages/event-bus/dist/src/index.js +1 -0
  110. package/packages/event-bus/dist/src/index.js.map +1 -1
  111. package/packages/event-bus/package.json +1 -1
  112. package/packages/event-bus/src/herdr-bus.ts +525 -0
  113. package/packages/event-bus/src/index.ts +29 -0
  114. package/packages/event-store/package.json +1 -1
  115. package/packages/experience-replay/dist/replay.js +7 -7
  116. package/packages/experience-replay/package.json +1 -1
  117. package/packages/experience-replay/src/replay.ts +7 -7
  118. package/packages/experience-replay/src/types.ts +5 -5
  119. package/packages/feedback-collector/package.json +1 -1
  120. package/packages/framework-detector/README.md +18 -18
  121. package/packages/framework-detector/dist/detector.js +3 -3
  122. package/packages/framework-detector/dist/index.js +3 -3
  123. package/packages/framework-detector/dist/signatures/registry.js +24 -24
  124. package/packages/framework-detector/dist/types.js +1 -1
  125. package/packages/framework-detector/package.json +1 -1
  126. package/packages/framework-detector/src/detector.ts +3 -3
  127. package/packages/framework-detector/src/index.ts +3 -3
  128. package/packages/framework-detector/src/signatures/registry.ts +24 -24
  129. package/packages/framework-detector/src/types.ts +7 -7
  130. package/packages/framework-detector/tsconfig.tsbuildinfo +1 -1
  131. package/packages/framework-plugin-sdk/README.md +23 -23
  132. package/packages/framework-plugin-sdk/dist/index.js +2 -2
  133. package/packages/framework-plugin-sdk/dist/manager.js +3 -3
  134. package/packages/framework-plugin-sdk/dist/types.js +2 -2
  135. package/packages/framework-plugin-sdk/package.json +1 -1
  136. package/packages/framework-plugin-sdk/src/index.ts +2 -2
  137. package/packages/framework-plugin-sdk/src/manager.ts +3 -3
  138. package/packages/framework-plugin-sdk/src/types.ts +10 -10
  139. package/packages/framework-plugin-sdk/tsconfig.tsbuildinfo +1 -1
  140. package/packages/frappe-plugin/dist/analyzer.js +8 -8
  141. package/packages/frappe-plugin/dist/types.js +1 -1
  142. package/packages/frappe-plugin/package.json +1 -1
  143. package/packages/frappe-plugin/src/analyzer.ts +8 -8
  144. package/packages/frappe-plugin/src/types.ts +10 -10
  145. package/packages/generic-web-plugin/dist/analyzer.js +5 -5
  146. package/packages/generic-web-plugin/package.json +1 -1
  147. package/packages/generic-web-plugin/src/analyzer.ts +5 -5
  148. package/packages/health-monitor/package.json +1 -1
  149. package/packages/health-monitor/src/monitor.ts +1 -1
  150. package/packages/intent-analyzer/package.json +1 -1
  151. package/packages/laravel-plugin/dist/analyzer.js +11 -11
  152. package/packages/laravel-plugin/package.json +1 -1
  153. package/packages/laravel-plugin/src/analyzer.ts +11 -11
  154. package/packages/learning-engine/dist/engine.js +5 -5
  155. package/packages/learning-engine/dist/types.js +1 -1
  156. package/packages/learning-engine/package.json +1 -1
  157. package/packages/learning-engine/src/engine.ts +5 -5
  158. package/packages/learning-engine/src/types.ts +6 -6
  159. package/packages/mcp-adapter/package.json +1 -1
  160. package/packages/memory-engine/dist/engine.js +8 -8
  161. package/packages/memory-engine/dist/types.js +2 -2
  162. package/packages/memory-engine/package.json +1 -1
  163. package/packages/memory-engine/src/engine.ts +8 -8
  164. package/packages/memory-engine/src/types.ts +9 -9
  165. package/packages/model-registry/package.json +1 -1
  166. package/packages/model-registry/src/types.ts +4 -4
  167. package/packages/nextjs-plugin/dist/analyzer.js +9 -9
  168. package/packages/nextjs-plugin/package.json +1 -1
  169. package/packages/nextjs-plugin/src/analyzer.ts +9 -9
  170. package/packages/notification/dist/notification-center.js +1 -1
  171. package/packages/notification/package.json +1 -1
  172. package/packages/notification/src/notification-center.ts +1 -1
  173. package/packages/observability/dist/alerts.js +2 -2
  174. package/packages/observability/dist/health.js +4 -4
  175. package/packages/observability/dist/index.js +6 -6
  176. package/packages/observability/dist/logger.js +7 -7
  177. package/packages/observability/dist/metrics.js +11 -11
  178. package/packages/observability/dist/tracer.js +3 -3
  179. package/packages/observability/dist/types.js +1 -1
  180. package/packages/observability/package.json +1 -1
  181. package/packages/observability/src/alerts.ts +2 -2
  182. package/packages/observability/src/health.ts +4 -4
  183. package/packages/observability/src/index.ts +6 -6
  184. package/packages/observability/src/logger.ts +7 -7
  185. package/packages/observability/src/metrics.ts +11 -11
  186. package/packages/observability/src/tracer.ts +3 -3
  187. package/packages/observability/src/types.ts +7 -7
  188. package/packages/observability/test/observability.test.ts +4 -4
  189. package/packages/observability/tsconfig.tsbuildinfo +1 -1
  190. package/packages/performance-optimizer/dist/optimizer.js +1 -1
  191. package/packages/performance-optimizer/package.json +1 -1
  192. package/packages/performance-optimizer/src/optimizer.ts +1 -1
  193. package/packages/performance-optimizer/src/types.ts +4 -4
  194. package/packages/privilege-broker/package.json +1 -1
  195. package/packages/project-analyzer/dist/analyzer.js +4 -4
  196. package/packages/project-analyzer/dist/index.js +8 -8
  197. package/packages/project-analyzer/dist/signals.js +3 -3
  198. package/packages/project-analyzer/dist/types.js +1 -1
  199. package/packages/project-analyzer/package.json +1 -1
  200. package/packages/project-analyzer/src/analyzer.ts +4 -4
  201. package/packages/project-analyzer/src/index.ts +9 -9
  202. package/packages/project-analyzer/src/signals.ts +4 -4
  203. package/packages/project-analyzer/src/types.ts +15 -15
  204. package/packages/project-analyzer/test/index.test.ts +17 -17
  205. package/packages/project-analyzer/tsconfig.tsbuildinfo +1 -1
  206. package/packages/projection-engine/package.json +1 -1
  207. package/packages/prompt-compiler/dist/section-builder.js +1 -1
  208. package/packages/prompt-compiler/dist/types.js +3 -3
  209. package/packages/prompt-compiler/package.json +1 -1
  210. package/packages/prompt-compiler/src/section-builder.ts +1 -1
  211. package/packages/prompt-compiler/src/types.ts +12 -12
  212. package/packages/prompt-compiler/test/prompt-compiler.test.ts +12 -12
  213. package/packages/prompt-versioning/package.json +1 -1
  214. package/packages/provider-adapter-sdk/dist/builder.js +1 -1
  215. package/packages/provider-adapter-sdk/dist/index.js +5 -5
  216. package/packages/provider-adapter-sdk/dist/registry.js +1 -1
  217. package/packages/provider-adapter-sdk/dist/tester.js +1 -1
  218. package/packages/provider-adapter-sdk/dist/types.js +1 -1
  219. package/packages/provider-adapter-sdk/package.json +1 -1
  220. package/packages/provider-adapter-sdk/src/builder.ts +1 -1
  221. package/packages/provider-adapter-sdk/src/index.ts +6 -6
  222. package/packages/provider-adapter-sdk/src/registry.ts +1 -1
  223. package/packages/provider-adapter-sdk/src/tester.ts +1 -1
  224. package/packages/provider-adapter-sdk/src/types.ts +5 -5
  225. package/packages/provider-adapter-sdk/tsconfig.tsbuildinfo +1 -1
  226. package/packages/provider-router/package.json +1 -1
  227. package/packages/provider-router/src/types.ts +4 -4
  228. package/packages/provider-selector/package.json +1 -1
  229. package/packages/providers/dist/deepagents-adapter.js +1 -1
  230. package/packages/providers/package.json +1 -1
  231. package/packages/providers/src/deepagents-adapter.ts +1 -1
  232. package/packages/quota-manager/package.json +1 -1
  233. package/packages/rate-limiter/package.json +1 -1
  234. package/packages/react-vite-plugin/dist/analyzer.js +7 -7
  235. package/packages/react-vite-plugin/package.json +1 -1
  236. package/packages/react-vite-plugin/src/analyzer.ts +7 -7
  237. package/packages/release-manager/package.json +1 -1
  238. package/packages/requirement-compiler/dist/compiler.js +17 -17
  239. package/packages/requirement-compiler/dist/types.js +2 -2
  240. package/packages/requirement-compiler/package.json +1 -1
  241. package/packages/requirement-compiler/src/compiler.ts +17 -17
  242. package/packages/requirement-compiler/src/types.ts +21 -21
  243. package/packages/requirement-compiler/test/requirement-compiler.test.ts +17 -17
  244. package/packages/runtime/dist/command-executor.js +1 -1
  245. package/packages/runtime/dist/local-runtime-agent.js +1 -1
  246. package/packages/runtime/dist/policy-engine.js +1 -1
  247. package/packages/runtime/dist/runtime-api.js +1 -1
  248. package/packages/runtime/dist/workspace-manager.js +1 -1
  249. package/packages/runtime/package.json +1 -1
  250. package/packages/runtime/src/command-executor.ts +1 -1
  251. package/packages/runtime/src/local-runtime-agent.ts +1 -1
  252. package/packages/runtime/src/policy-engine.ts +1 -1
  253. package/packages/runtime/src/runtime-api.ts +1 -1
  254. package/packages/runtime/src/workspace-manager.ts +1 -1
  255. package/packages/scheduler/package.json +1 -1
  256. package/packages/scheduler-adapter/package.json +1 -1
  257. package/packages/session/README.md +18 -18
  258. package/packages/session/dist/history.js +3 -3
  259. package/packages/session/dist/index.js +5 -5
  260. package/packages/session/dist/manager.js +3 -3
  261. package/packages/session/dist/policy.js +2 -2
  262. package/packages/session/dist/store.js +2 -2
  263. package/packages/session/dist/types.js +1 -1
  264. package/packages/session/package.json +1 -1
  265. package/packages/session/src/history.ts +3 -3
  266. package/packages/session/src/index.ts +5 -5
  267. package/packages/session/src/manager.ts +3 -3
  268. package/packages/session/src/policy.ts +4 -4
  269. package/packages/session/src/store.ts +3 -3
  270. package/packages/session/src/types.ts +10 -10
  271. package/packages/session/tsconfig.tsbuildinfo +1 -1
  272. package/packages/session-api/package.json +1 -1
  273. package/packages/session-export/package.json +1 -1
  274. package/packages/shared-context/package.json +1 -1
  275. package/packages/skill-registry/package.json +1 -1
  276. package/packages/skill-registry/src/types.ts +4 -4
  277. package/packages/sprint-planner/package.json +1 -1
  278. package/packages/subscription-engine/package.json +1 -1
  279. package/packages/task-compiler/dist/compiler.js +7 -7
  280. package/packages/task-compiler/dist/decompose.js +11 -11
  281. package/packages/task-compiler/dist/file-scope.js +6 -6
  282. package/packages/task-compiler/dist/graph.js +6 -6
  283. package/packages/task-compiler/dist/index.js +2 -2
  284. package/packages/task-compiler/dist/types.js +5 -5
  285. package/packages/task-compiler/dist/validate.js +2 -2
  286. package/packages/task-compiler/dist/verification.js +2 -2
  287. package/packages/task-compiler/package.json +1 -1
  288. package/packages/task-compiler/src/command-policy.ts +1 -1
  289. package/packages/task-compiler/src/compiler.ts +7 -7
  290. package/packages/task-compiler/src/decompose.ts +11 -11
  291. package/packages/task-compiler/src/file-scope.ts +6 -6
  292. package/packages/task-compiler/src/graph.ts +6 -6
  293. package/packages/task-compiler/src/index.ts +3 -3
  294. package/packages/task-compiler/src/types.ts +14 -14
  295. package/packages/task-compiler/src/validate.ts +2 -2
  296. package/packages/task-compiler/src/verification.ts +2 -2
  297. package/packages/task-compiler/test/task-compiler.test.ts +10 -10
  298. package/packages/test-data-generator/README.md +13 -13
  299. package/packages/test-data-generator/dist/faker-adapter.js +4 -4
  300. package/packages/test-data-generator/dist/generator.js +3 -3
  301. package/packages/test-data-generator/dist/index.js +3 -3
  302. package/packages/test-data-generator/dist/types.js +1 -1
  303. package/packages/test-data-generator/package.json +1 -1
  304. package/packages/test-data-generator/src/faker-adapter.ts +4 -4
  305. package/packages/test-data-generator/src/generator.ts +3 -3
  306. package/packages/test-data-generator/src/index.ts +3 -3
  307. package/packages/test-data-generator/src/types.ts +9 -9
  308. package/packages/test-data-generator/tsconfig.tsbuildinfo +1 -1
  309. package/packages/test-generator/package.json +1 -1
  310. package/packages/token-estimation/package.json +1 -1
  311. package/packages/token-optimizer/package.json +1 -1
  312. package/packages/tui/package.json +1 -1
  313. package/packages/types/package.json +1 -1
  314. package/packages/types/src/agent-worker-types.ts +5 -5
  315. package/packages/types/src/runtime-types.ts +12 -12
  316. package/packages/types/tsconfig.tsbuildinfo +1 -1
  317. package/packages/workflow-events/package.json +1 -1
  318. package/packages/workspace-scanner/package.json +1 -1
  319. package/packages/worktree/package.json +1 -1
  320. package/renderer.ts +7 -7
  321. package/skills/harness-runtime/SKILL.md +15 -15
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Herdr Agent Commands
3
+ */
4
+ import { existsSync, readdirSync, readFileSync } from "fs";
5
+ import { join } from "path";
6
+ import {
7
+ createHerdrBus,
8
+ getHerdrWorkspacePaths,
9
+ ensureHerdrWorkspace,
10
+ } from "../packages/event-bus/src/herdr-bus.js";
11
+
12
+ async function startReviewAgent(): Promise<void> {
13
+ console.log("[herdr:review] Starting review agent...");
14
+ const bus = createHerdrBus("review-agent");
15
+ ensureHerdrWorkspace();
16
+ bus.subscribe("code.written");
17
+ bus.startPolling(async (payload) => {
18
+ if (payload.topic === "code.written") {
19
+ const data = payload.data as { taskId: string; files: string[] };
20
+ console.log(
21
+ `[herdr:review] code.written: task=${data.taskId} files=${data.files.length}`,
22
+ );
23
+ for (const file of data.files ?? []) {
24
+ console.log(`[herdr:review] Reviewing: ${file}`);
25
+ }
26
+ }
27
+ });
28
+ console.log(`[herdr:review] Workspace: ${bus.getWorkspace()}`);
29
+ await new Promise(() => {});
30
+ }
31
+
32
+ async function startCodeAgent(): Promise<void> {
33
+ console.log("[herdr:code] Starting code agent...");
34
+ const bus = createHerdrBus("code-agent");
35
+ ensureHerdrWorkspace();
36
+ bus.subscribe("review.completed");
37
+ bus.startPolling(async (payload) => {
38
+ if (payload.topic === "review.completed") {
39
+ const data = payload.data as {
40
+ taskId: string;
41
+ reportFile: string;
42
+ status: string;
43
+ };
44
+ console.log(
45
+ `[herdr:code] Review done: task=${data.taskId} status=${data.status} report=${data.reportFile}`,
46
+ );
47
+ }
48
+ });
49
+ console.log(`[herdr:code] Workspace: ${bus.getWorkspace()}`);
50
+ await new Promise(() => {});
51
+ }
52
+
53
+ function showStatus(): void {
54
+ const paths = getHerdrWorkspacePaths();
55
+ console.log(`Workspace: ${paths.root}`);
56
+ const evPath = join(paths.root, "events.jsonl");
57
+ if (existsSync(evPath)) {
58
+ const lines = readFileSync(evPath, "utf-8")
59
+ .split("\n")
60
+ .filter(Boolean)
61
+ .slice(-10);
62
+ console.log("Recent events:");
63
+ for (const line of lines) {
64
+ try {
65
+ const { topic, ts } = JSON.parse(line);
66
+ console.log(` ${ts} ${topic}`);
67
+ } catch {
68
+ /* skip */
69
+ }
70
+ }
71
+ }
72
+ if (existsSync(paths.subscriptions)) {
73
+ const agents = readdirSync(paths.subscriptions);
74
+ console.log(`Active agents: ${agents.join(", ") || "none"}`);
75
+ }
76
+ }
77
+
78
+ const [command] = process.argv.slice(2);
79
+ switch (command) {
80
+ case "review":
81
+ startReviewAgent().catch(console.error);
82
+ break;
83
+ case "code":
84
+ startCodeAgent().catch(console.error);
85
+ break;
86
+ case "status":
87
+ showStatus();
88
+ break;
89
+ default:
90
+ console.log("Usage: bun harness/herdr-agents.ts <review|code|status>");
91
+ }
package/harness/index.ts CHANGED
@@ -178,7 +178,7 @@ export type { QuotaStatus, QuotaDisplayConfig } from "./e2e/quota-status.js";
178
178
  // Project Detector
179
179
  export { ProjectDetector } from "./project-detector/detector.js";
180
180
 
181
- // ─── RFC-0056: Performance Optimizer ────────────────────────────────────────
181
+ // --- RFC-0056: Performance Optimizer ----------------------------------------
182
182
  export {
183
183
  PerformanceOptimizer,
184
184
  createPerformanceOptimizer,
@@ -189,7 +189,7 @@ export type {
189
189
  PerformanceRecommendation,
190
190
  } from "../packages/performance-optimizer/src/types.js";
191
191
 
192
- // ─── RFC-0057: Evaluation Engine ───────────────────────────────────────────
192
+ // --- RFC-0057: Evaluation Engine -------------------------------------------
193
193
  export {
194
194
  EvaluationEngine,
195
195
  createEvaluationEngine,
@@ -200,7 +200,7 @@ export type {
200
200
  EvaluationFinding,
201
201
  } from "../packages/evaluation-engine/src/types.js";
202
202
 
203
- // ─── RFC-0058: Learning Engine ─────────────────────────────────────────────
203
+ // --- RFC-0058: Learning Engine ---------------------------------------------
204
204
  export {
205
205
  LearningEngine,
206
206
  createLearningEngine,
@@ -210,7 +210,7 @@ export type {
210
210
  LearnedExperience,
211
211
  } from "../packages/learning-engine/src/types.js";
212
212
 
213
- // ─── RFC-0059: Experience Replay ──────────────────────────────────────────
213
+ // --- RFC-0059: Experience Replay ------------------------------------------
214
214
  export {
215
215
  ExperienceReplay,
216
216
  createExperienceReplay,
@@ -220,7 +220,7 @@ export type {
220
220
  ReplayResult,
221
221
  } from "../packages/experience-replay/src/types.js";
222
222
 
223
- // ─── RFC-0060: Memory Engine ───────────────────────────────────────────────
223
+ // --- RFC-0060: Memory Engine -----------------------------------------------
224
224
  export {
225
225
  MemoryEngine,
226
226
  createMemoryEngine,
@@ -0,0 +1,284 @@
1
+ /**
2
+ * Loop Code Agent (Minimax) — coordinates via blackboard.
3
+ *
4
+ * Polls blackboard for nextAction where agentType="code".
5
+ * Writes code, updates node status, sets nextAction for review-agent.
6
+ *
7
+ * Usage: bun harness/loop-code-agent.ts
8
+ */
9
+
10
+ import { readFileSync, writeFileSync, mkdirSync } from "fs";
11
+ import { join } from "path";
12
+ import {
13
+ createHerdrBus,
14
+ ensureHerdrWorkspace,
15
+ } from "../packages/event-bus/src/herdr-bus.js";
16
+ import { SharedBlackboard } from "./blackboard.js";
17
+ import type { LoopNextAction, LoopAgentReport } from "./loop-types.js";
18
+ import type { BlackboardRecord } from "../packages/types/src/runtime-types.js";
19
+
20
+ const AGENT_ID = "code-agent";
21
+ const AGENT_TYPE = "code";
22
+ const POLL_MS = 1000;
23
+
24
+ async function main(): Promise<void> {
25
+ console.log(`[${AGENT_ID}] Starting...`);
26
+ const paths = ensureHerdrWorkspace();
27
+
28
+ // Find active loop config
29
+ const loopId = await findActiveLoop(paths.root);
30
+ if (!loopId) {
31
+ console.log(`[${AGENT_ID}] No active loop found. Waiting...`);
32
+ }
33
+
34
+ const rootDir = paths.root;
35
+ const blackboard = new SharedBlackboard(loopId ?? "no-loop", rootDir);
36
+ blackboard.load();
37
+ blackboard.registerAgent(AGENT_ID, "Code Agent", "minimax", "minimax");
38
+ blackboard.updateAgentStatus(AGENT_ID, "idle");
39
+ console.log(`[${AGENT_ID}] Registered. Blackboard: ${blackboard.getPath()}`);
40
+
41
+ while (true) {
42
+ await sleep(POLL_MS);
43
+
44
+ blackboard.load();
45
+ const record = blackboard.getRecord();
46
+ if (!record) continue;
47
+
48
+ // Check for early exit
49
+ const earlyExit = checkEarlyExit(record);
50
+ if (earlyExit) {
51
+ console.log(`[${AGENT_ID}] Early exit: ${earlyExit}`);
52
+ blackboard.updateAgentStatus(AGENT_ID, "idle");
53
+ break;
54
+ }
55
+
56
+ // Check if this loop is ours (loopId matches)
57
+ if (record.jobId !== loopId) continue;
58
+
59
+ // Check nextAction for code agent
60
+ const action = parseNextAction(record.nextAction);
61
+ if (!action || action.agentType !== AGENT_TYPE) continue;
62
+
63
+ // Claim the task
64
+ const locked = blackboard.acquireLock(action.taskId, AGENT_ID);
65
+ if (!locked) continue;
66
+
67
+ blackboard.updateAgentStatus(AGENT_ID, "working", action.taskId);
68
+ console.log(`[${AGENT_ID}] Claimed: ${action.taskId}`);
69
+
70
+ // Do the work
71
+ const result = await writeCode(action, paths, record.jobId);
72
+
73
+ // Update task status
74
+ updateTaskStatus(blackboard, record, action.taskId, "done", result.files);
75
+
76
+ // Set nextAction for review agent
77
+ const nextTaskId = getNextReviewTask(record, action.iteration);
78
+ if (nextTaskId) {
79
+ blackboard.setNextAction(
80
+ encodeNextAction({
81
+ taskId: nextTaskId,
82
+ agentType: "review",
83
+ iteration: getReviewIteration(nextTaskId),
84
+ prompt: action.prompt,
85
+ codeFiles: result.files,
86
+ }),
87
+ );
88
+ console.log(`[${AGENT_ID}] -> nextAction: review ${nextTaskId}`);
89
+ } else {
90
+ // No review needed — go to report
91
+ const writeDone = getNextWriteTask(record, action.iteration);
92
+ if (writeDone) {
93
+ blackboard.setNextAction(
94
+ encodeNextAction({
95
+ taskId: writeDone,
96
+ agentType: "code",
97
+ iteration: getWriteIteration(writeDone),
98
+ prompt: action.prompt,
99
+ }),
100
+ );
101
+ console.log(`[${AGENT_ID}] -> nextAction: code ${writeDone}`);
102
+ } else {
103
+ // All done — go to report
104
+ blackboard.setNextAction(
105
+ encodeNextAction({
106
+ taskId: "report",
107
+ agentType: "review",
108
+ iteration: 0,
109
+ }),
110
+ );
111
+ console.log(`[${AGENT_ID}] -> nextAction: report`);
112
+ }
113
+ }
114
+
115
+ // Release lock and report
116
+ blackboard.releaseLock(action.taskId, AGENT_ID);
117
+ blackboard.writeReport({
118
+ agentId: AGENT_ID,
119
+ taskId: action.taskId,
120
+ status: "success",
121
+ files: result.files,
122
+ } satisfies LoopAgentReport);
123
+ blackboard.updateAgentStatus(AGENT_ID, "idle");
124
+ }
125
+ }
126
+
127
+ async function writeCode(
128
+ action: LoopNextAction,
129
+ paths: { code: string },
130
+ loopId: string,
131
+ ): Promise<{ files: string[] }> {
132
+ const iteration = action.iteration;
133
+ const outputDir = join(paths.code, loopId, `iteration-${iteration}`);
134
+ mkdirSync(outputDir, { recursive: true });
135
+
136
+ const codeFile = join(outputDir, `index.ts`);
137
+ // TODO: Replace with actual Minimax call
138
+ const code = `// Iteration ${iteration} — ${action.prompt}
139
+ // TODO: Replace with actual Minimax code generation
140
+ export const iteration = ${iteration};
141
+ export const prompt = ${JSON.stringify(action.prompt)};
142
+ `;
143
+ writeFileSync(codeFile, code);
144
+ console.log(`[${AGENT_ID}] Wrote: ${codeFile}`);
145
+ return { files: [codeFile] };
146
+ }
147
+
148
+ // ─── Helpers ────────────────────────────────────────────────────────────────
149
+
150
+ async function findActiveLoop(rootDir: string): Promise<string | null> {
151
+ const { readdirSync, existsSync } = await import("fs");
152
+ try {
153
+ const files = readdirSync(rootDir).filter(
154
+ (f) => f.startsWith("loop-") && f.endsWith(".config.json"),
155
+ );
156
+ // Find most recent config that has an active blackboard
157
+ for (const configFile of files.slice(-1)) {
158
+ const config = JSON.parse(
159
+ readFileSync(join(rootDir, configFile), "utf-8"),
160
+ );
161
+ const bbPath = join(rootDir, "jobs", config.loopId, "blackboard");
162
+ if (existsSync(bbPath)) return config.loopId;
163
+ }
164
+ } catch {
165
+ // no loop yet
166
+ }
167
+ return null;
168
+ }
169
+
170
+ function encodeNextAction(action: Partial<LoopNextAction>) {
171
+ return {
172
+ taskId: action.taskId,
173
+ instruction: "LOOP:" + JSON.stringify(action),
174
+ priority: "high" as const,
175
+ createdAt: new Date().toISOString(),
176
+ };
177
+ }
178
+
179
+ function parseNextAction(nextAction: unknown): LoopNextAction | null {
180
+ if (!nextAction) return null;
181
+ const a = nextAction as Record<string, unknown>;
182
+ if (!a.taskId) return null;
183
+ if (typeof a.instruction === "string" && a.instruction.startsWith("LOOP:")) {
184
+ try {
185
+ return JSON.parse(a.instruction.slice(5)) as LoopNextAction;
186
+ } catch {
187
+ return null;
188
+ }
189
+ }
190
+ return null;
191
+ }
192
+
193
+ function checkEarlyExit(record: BlackboardRecord): string | null {
194
+ const blocked = Object.values(record.tasks.nodes).find(
195
+ (n) => n.status === "blocked",
196
+ );
197
+ if (blocked) return `blocked at ${blocked.id}`;
198
+ const approved = Object.values(record.tasks.nodes).find(
199
+ (n) =>
200
+ n.status === "done" && (n as { result?: string }).result === "approved",
201
+ );
202
+ if (approved) return "approved";
203
+ return null;
204
+ }
205
+
206
+ function updateTaskStatus(
207
+ blackboard: SharedBlackboard,
208
+ record: BlackboardRecord,
209
+ taskId: string,
210
+ status: "done" | "running" | "blocked",
211
+ files?: string[],
212
+ ): void {
213
+ if (record.tasks.nodes[taskId]) {
214
+ (
215
+ record.tasks.nodes[taskId] as unknown as {
216
+ status: string;
217
+ result?: string;
218
+ }
219
+ ).status = status;
220
+ if (files)
221
+ (record.tasks.nodes[taskId] as unknown as { result?: string }).result =
222
+ files.join(", ");
223
+ (
224
+ record.tasks.nodes[taskId] as unknown as { updatedAt?: string }
225
+ ).updatedAt = new Date().toISOString();
226
+ blackboard.save();
227
+ }
228
+ }
229
+
230
+ function getNextReviewTask(
231
+ record: BlackboardRecord,
232
+ writeIteration: number,
233
+ ): string | null {
234
+ const reviewCount = Object.keys(record.tasks.nodes).filter((id) =>
235
+ id.startsWith("review-"),
236
+ ).length;
237
+ const step = Math.max(
238
+ 1,
239
+ Math.floor(
240
+ Object.keys(record.tasks.nodes).filter((id) => id.startsWith("write-"))
241
+ .length / (reviewCount || 1),
242
+ ),
243
+ );
244
+ const targetReview = Math.ceil(writeIteration / step);
245
+ const taskId = `review-${targetReview}`;
246
+ if (
247
+ record.tasks.nodes[taskId] &&
248
+ record.tasks.nodes[taskId].status === "pending"
249
+ ) {
250
+ return taskId;
251
+ }
252
+ return null;
253
+ }
254
+
255
+ function getNextWriteTask(
256
+ record: BlackboardRecord,
257
+ currentIteration: number,
258
+ ): string | null {
259
+ const nextWrite = currentIteration + 1;
260
+ const taskId = `write-${nextWrite}`;
261
+ if (
262
+ record.tasks.nodes[taskId] &&
263
+ record.tasks.nodes[taskId].status === "pending"
264
+ ) {
265
+ return taskId;
266
+ }
267
+ return null;
268
+ }
269
+
270
+ function getReviewIteration(taskId: string): number {
271
+ const m = taskId.match(/^review-(\d+)$/);
272
+ return m ? parseInt(m[1], 10) : 0;
273
+ }
274
+
275
+ function getWriteIteration(taskId: string): number {
276
+ const m = taskId.match(/^write-(\d+)$/);
277
+ return m ? parseInt(m[1], 10) : 0;
278
+ }
279
+
280
+ function sleep(ms: number): Promise<void> {
281
+ return new Promise((r) => setTimeout(r, ms));
282
+ }
283
+
284
+ main().catch(console.error);
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Loop Controller — blackboard-coordinated write-review loops.
3
+ *
4
+ * Human types /review-loop <write_count> <review_count> --prompt="..."
5
+ * Controller creates blackboard, sets first nextAction, monitors progress.
6
+ */
7
+
8
+ import { writeFileSync } from "fs";
9
+ import { join } from "path";
10
+ import { randomUUID } from "crypto";
11
+ import {
12
+ createHerdrBus,
13
+ ensureHerdrWorkspace,
14
+ publishLoopStarted,
15
+ type LoopConfig,
16
+ } from "../packages/event-bus/src/index.js";
17
+ import { createBlackboard } from "./blackboard.js";
18
+ import { buildLoopTaskGraph } from "./loop-types.js";
19
+ import type { SharedBlackboard } from "./blackboard.js";
20
+
21
+ function encodeNextAction(la: {
22
+ taskId: string;
23
+ agentType: string;
24
+ iteration: number;
25
+ prompt?: string;
26
+ codeFiles?: string[];
27
+ }) {
28
+ return {
29
+ taskId: la.taskId,
30
+ instruction: "LOOP:" + JSON.stringify(la),
31
+ priority: "high" as const,
32
+ createdAt: new Date().toISOString(),
33
+ };
34
+ }
35
+
36
+ function sleep(ms: number): Promise<void> {
37
+ return new Promise((r) => setTimeout(r, ms));
38
+ }
39
+
40
+ // ─── Monitor ────────────────────────────────────────────────────────────────
41
+
42
+ async function monitorLoop(
43
+ blackboard: SharedBlackboard,
44
+ loopId: string,
45
+ ): Promise<void> {
46
+ const paths = ensureHerdrWorkspace();
47
+
48
+ while (true) {
49
+ blackboard.load();
50
+ const record = blackboard.getRecord();
51
+ if (!record) {
52
+ await sleep(500);
53
+ continue;
54
+ }
55
+
56
+ // Check if report is done
57
+ const reportNode = record.tasks.nodes["report"];
58
+ if (reportNode?.status === "done") {
59
+ const reviews = Object.values(record.tasks.nodes).filter(
60
+ (n) => n.id.startsWith("review-") && n.status === "done",
61
+ );
62
+ const lastReview = reviews.sort((a, b) =>
63
+ (b.updatedAt ?? "").localeCompare(a.updatedAt ?? ""),
64
+ )[0];
65
+ const verdict = (lastReview as { result?: string }).result ?? "unknown";
66
+ const summary =
67
+ verdict !== "unknown" ? `Verdict: ${verdict}` : "Loop completed";
68
+
69
+ const reportPath = join(
70
+ paths.reviews,
71
+ `loop-${loopId.slice(0, 8)}-final.md`,
72
+ );
73
+ writeFileSync(
74
+ reportPath,
75
+ `# Loop Result — ${loopId.slice(0, 8)}
76
+
77
+ ## Result
78
+ ${summary}
79
+
80
+ ## Verdict: **${verdict.toUpperCase()}**
81
+ `,
82
+ );
83
+ console.log(`[controller] VERDICT: ${verdict.toUpperCase()}`);
84
+ console.log(`[controller] Report: ${reportPath}`);
85
+ return;
86
+ }
87
+
88
+ // Check for blocked
89
+ const blocked = Object.values(record.tasks.nodes).find(
90
+ (n) => n.status === "blocked",
91
+ );
92
+ if (blocked) {
93
+ const reportPath = join(
94
+ paths.reviews,
95
+ `loop-${loopId.slice(0, 8)}-final.md`,
96
+ );
97
+ writeFileSync(
98
+ reportPath,
99
+ `# Loop Result — ${loopId.slice(0, 8)}
100
+
101
+ ## Result
102
+ Blocked at: ${blocked.id}
103
+
104
+ ## Verdict: **BLOCKED**
105
+ `,
106
+ );
107
+ console.log(`[controller] VERDICT: BLOCKED (${blocked.id})`);
108
+ return;
109
+ }
110
+
111
+ await sleep(500);
112
+ }
113
+ }
114
+
115
+ // ─── Run ──────────────────────────────────────────────────────────────────
116
+
117
+ async function runLoop(args: string[]): Promise<void> {
118
+ const writeCount = parseInt(args[0] ?? "3", 10);
119
+ const reviewCount = parseInt(args[1] ?? "2", 10);
120
+ const prompt =
121
+ (args.find((a) => a.startsWith("--prompt=")) ?? "")
122
+ .slice("--prompt=".length)
123
+ .replace(/^["']|["']$/g, "") || "No prompt";
124
+
125
+ if (isNaN(writeCount) || writeCount < 1 || writeCount > 20) {
126
+ console.error("write_count must be 1-20");
127
+ process.exit(1);
128
+ }
129
+ if (isNaN(reviewCount) || reviewCount < 0 || reviewCount > 20) {
130
+ console.error("review_count must be 0-20");
131
+ process.exit(1);
132
+ }
133
+
134
+ const loopId = randomUUID();
135
+ const paths = ensureHerdrWorkspace();
136
+ const taskGraph = buildLoopTaskGraph(writeCount, reviewCount, loopId);
137
+
138
+ console.log("=".repeat(60));
139
+ console.log(`LOOP STARTED — ${loopId.slice(0, 8)}`);
140
+ console.log(` Writes: ${writeCount} Reviews: ${reviewCount}`);
141
+ console.log(` Prompt: ${prompt}`);
142
+ console.log("=".repeat(60));
143
+
144
+ // Create blackboard
145
+ const blackboard = createBlackboard(loopId, paths.root, taskGraph);
146
+ console.log(`[controller] Blackboard: ${blackboard.getPath()}`);
147
+
148
+ // Event bus for cross-process signaling
149
+ const bus = createHerdrBus(`ctrl-${loopId.slice(0, 8)}`);
150
+
151
+ // Save config
152
+ // Clean old loop configs
153
+ for (const f of (await import("fs")).readdirSync(paths.root)) {
154
+ if (f.startsWith("loop-") && f.endsWith(".config.json")) {
155
+ (await import("fs")).unlinkSync(join(paths.root, f));
156
+ }
157
+ }
158
+
159
+ const config: LoopConfig = {
160
+ loopId,
161
+ writeCount,
162
+ reviewCount,
163
+ prompt,
164
+ nextReviewAfter: Math.max(1, Math.floor(writeCount / (reviewCount || 1))),
165
+ createdAt: new Date().toISOString(),
166
+ };
167
+ writeFileSync(
168
+ join(paths.root, `loop-${loopId}.config.json`),
169
+ JSON.stringify(config, null, 2),
170
+ );
171
+ publishLoopStarted(bus, config);
172
+
173
+ // Set first action: code agent writes iteration 1
174
+ blackboard.setNextAction(
175
+ encodeNextAction({
176
+ taskId: "write-1",
177
+ agentType: "code",
178
+ iteration: 1,
179
+ prompt,
180
+ }),
181
+ );
182
+ console.log("[controller] nextAction: code write-1");
183
+
184
+ // Monitor until done
185
+ await monitorLoop(blackboard, loopId);
186
+ }
187
+
188
+ // ─── CLI ──────────────────────────────────────────────────────────────────
189
+
190
+ const args = process.argv.slice(2);
191
+ if (!args.length || args[0] === "--help" || args[0] === "-h") {
192
+ console.log(
193
+ 'Usage: bun harness/loop-controller.ts <write_count> <review_count> --prompt="..."\nExample: bun harness/loop-controller.ts 3 2 --prompt="build REST API"',
194
+ );
195
+ process.exit(0);
196
+ }
197
+
198
+ runLoop(args).catch((err) => {
199
+ console.error("[controller] Fatal:", err);
200
+ process.exit(1);
201
+ });