agent-bober 0.15.0 → 0.17.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 (301) hide show
  1. package/.claude-plugin/marketplace.json +20 -0
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/CHANGELOG.md +30 -0
  4. package/README.md +127 -3
  5. package/agents/bober-architect.md +34 -0
  6. package/agents/bober-code-reviewer.md +2 -0
  7. package/agents/bober-curator.md +12 -0
  8. package/agents/bober-documenter.md +129 -0
  9. package/agents/bober-evaluator.md +46 -0
  10. package/agents/bober-generator.md +12 -0
  11. package/agents/bober-planner.md +8 -1
  12. package/dist/cli/commands/graph.js +3 -3
  13. package/dist/cli/commands/graph.js.map +1 -1
  14. package/dist/cli/commands/init.js +4 -0
  15. package/dist/cli/commands/init.js.map +1 -1
  16. package/dist/cli/commands/memory.d.ts +14 -0
  17. package/dist/cli/commands/memory.d.ts.map +1 -0
  18. package/dist/cli/commands/memory.js +132 -0
  19. package/dist/cli/commands/memory.js.map +1 -0
  20. package/dist/cli/index.js +6 -0
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/config/defaults.d.ts.map +1 -1
  23. package/dist/config/defaults.js +14 -3
  24. package/dist/config/defaults.js.map +1 -1
  25. package/dist/config/loader.d.ts.map +1 -1
  26. package/dist/config/loader.js +7 -0
  27. package/dist/config/loader.js.map +1 -1
  28. package/dist/config/role-providers.d.ts +29 -0
  29. package/dist/config/role-providers.d.ts.map +1 -0
  30. package/dist/config/role-providers.js +115 -0
  31. package/dist/config/role-providers.js.map +1 -0
  32. package/dist/config/schema.d.ts +383 -14
  33. package/dist/config/schema.d.ts.map +1 -1
  34. package/dist/config/schema.js +42 -0
  35. package/dist/config/schema.js.map +1 -1
  36. package/dist/contracts/eval-result.d.ts +112 -56
  37. package/dist/contracts/eval-result.d.ts.map +1 -1
  38. package/dist/contracts/eval-result.js +3 -0
  39. package/dist/contracts/eval-result.js.map +1 -1
  40. package/dist/contracts/sprint-contract.d.ts +30 -30
  41. package/dist/fleet/aggregator.d.ts +5 -0
  42. package/dist/fleet/aggregator.d.ts.map +1 -0
  43. package/dist/fleet/aggregator.js +39 -0
  44. package/dist/fleet/aggregator.js.map +1 -0
  45. package/dist/fleet/child-config.d.ts +12 -0
  46. package/dist/fleet/child-config.d.ts.map +1 -0
  47. package/dist/fleet/child-config.js +38 -0
  48. package/dist/fleet/child-config.js.map +1 -0
  49. package/dist/fleet/coordinator.d.ts +25 -0
  50. package/dist/fleet/coordinator.d.ts.map +1 -0
  51. package/dist/fleet/coordinator.js +40 -0
  52. package/dist/fleet/coordinator.js.map +1 -0
  53. package/dist/fleet/index.d.ts +40 -0
  54. package/dist/fleet/index.d.ts.map +1 -0
  55. package/dist/fleet/index.js +117 -0
  56. package/dist/fleet/index.js.map +1 -0
  57. package/dist/fleet/manifest.d.ts +51 -0
  58. package/dist/fleet/manifest.d.ts.map +1 -0
  59. package/dist/fleet/manifest.js +32 -0
  60. package/dist/fleet/manifest.js.map +1 -0
  61. package/dist/fleet/reporter.d.ts +32 -0
  62. package/dist/fleet/reporter.d.ts.map +1 -0
  63. package/dist/fleet/reporter.js +71 -0
  64. package/dist/fleet/reporter.js.map +1 -0
  65. package/dist/fleet/runner.d.ts +48 -0
  66. package/dist/fleet/runner.d.ts.map +1 -0
  67. package/dist/fleet/runner.js +104 -0
  68. package/dist/fleet/runner.js.map +1 -0
  69. package/dist/fleet/scaffolder.d.ts +12 -0
  70. package/dist/fleet/scaffolder.d.ts.map +1 -0
  71. package/dist/fleet/scaffolder.js +82 -0
  72. package/dist/fleet/scaffolder.js.map +1 -0
  73. package/dist/fleet/types.d.ts +21 -0
  74. package/dist/fleet/types.d.ts.map +1 -0
  75. package/dist/fleet/types.js +2 -0
  76. package/dist/fleet/types.js.map +1 -0
  77. package/dist/graph/cli.d.ts +6 -2
  78. package/dist/graph/cli.d.ts.map +1 -1
  79. package/dist/graph/cli.js +53 -12
  80. package/dist/graph/cli.js.map +1 -1
  81. package/dist/graph/pipeline-lifecycle.d.ts +9 -0
  82. package/dist/graph/pipeline-lifecycle.d.ts.map +1 -1
  83. package/dist/graph/pipeline-lifecycle.js +12 -0
  84. package/dist/graph/pipeline-lifecycle.js.map +1 -1
  85. package/dist/graph/preflight-injector.d.ts +14 -0
  86. package/dist/graph/preflight-injector.d.ts.map +1 -1
  87. package/dist/graph/preflight-injector.js +84 -4
  88. package/dist/graph/preflight-injector.js.map +1 -1
  89. package/dist/incident/types.d.ts +24 -24
  90. package/dist/mcp/tools/graph-schemas.d.ts +7 -7
  91. package/dist/mcp/tools/init.d.ts.map +1 -1
  92. package/dist/mcp/tools/init.js +2 -0
  93. package/dist/mcp/tools/init.js.map +1 -1
  94. package/dist/orchestrator/agent-loader.d.ts.map +1 -1
  95. package/dist/orchestrator/agent-loader.js +15 -1
  96. package/dist/orchestrator/agent-loader.js.map +1 -1
  97. package/dist/orchestrator/agentic-loop.d.ts +51 -0
  98. package/dist/orchestrator/agentic-loop.d.ts.map +1 -1
  99. package/dist/orchestrator/agentic-loop.js +123 -4
  100. package/dist/orchestrator/agentic-loop.js.map +1 -1
  101. package/dist/orchestrator/arch-lenses.d.ts +7 -0
  102. package/dist/orchestrator/arch-lenses.d.ts.map +1 -0
  103. package/dist/orchestrator/arch-lenses.js +22 -0
  104. package/dist/orchestrator/arch-lenses.js.map +1 -0
  105. package/dist/orchestrator/architect-agent.d.ts +16 -0
  106. package/dist/orchestrator/architect-agent.d.ts.map +1 -1
  107. package/dist/orchestrator/architect-agent.js +509 -1
  108. package/dist/orchestrator/architect-agent.js.map +1 -1
  109. package/dist/orchestrator/curator-agent.js +1 -1
  110. package/dist/orchestrator/curator-agent.js.map +1 -1
  111. package/dist/orchestrator/deploy/types.d.ts +2 -2
  112. package/dist/orchestrator/documenter-agent.d.ts +57 -0
  113. package/dist/orchestrator/documenter-agent.d.ts.map +1 -0
  114. package/dist/orchestrator/documenter-agent.js +195 -0
  115. package/dist/orchestrator/documenter-agent.js.map +1 -0
  116. package/dist/orchestrator/environment.d.ts +45 -0
  117. package/dist/orchestrator/environment.d.ts.map +1 -0
  118. package/dist/orchestrator/environment.js +151 -0
  119. package/dist/orchestrator/environment.js.map +1 -0
  120. package/dist/orchestrator/eval-lenses.d.ts +7 -0
  121. package/dist/orchestrator/eval-lenses.d.ts.map +1 -0
  122. package/dist/orchestrator/eval-lenses.js +19 -0
  123. package/dist/orchestrator/eval-lenses.js.map +1 -0
  124. package/dist/orchestrator/eval-persist.d.ts +25 -0
  125. package/dist/orchestrator/eval-persist.d.ts.map +1 -0
  126. package/dist/orchestrator/eval-persist.js +74 -0
  127. package/dist/orchestrator/eval-persist.js.map +1 -0
  128. package/dist/orchestrator/evaluator-agent.d.ts +23 -0
  129. package/dist/orchestrator/evaluator-agent.d.ts.map +1 -1
  130. package/dist/orchestrator/evaluator-agent.js +60 -3
  131. package/dist/orchestrator/evaluator-agent.js.map +1 -1
  132. package/dist/orchestrator/generator-agent.d.ts.map +1 -1
  133. package/dist/orchestrator/generator-agent.js +32 -0
  134. package/dist/orchestrator/generator-agent.js.map +1 -1
  135. package/dist/orchestrator/memory/distill.d.ts +60 -0
  136. package/dist/orchestrator/memory/distill.d.ts.map +1 -0
  137. package/dist/orchestrator/memory/distill.js +177 -0
  138. package/dist/orchestrator/memory/distill.js.map +1 -0
  139. package/dist/orchestrator/memory/eval-source.d.ts +20 -0
  140. package/dist/orchestrator/memory/eval-source.d.ts.map +1 -0
  141. package/dist/orchestrator/memory/eval-source.js +88 -0
  142. package/dist/orchestrator/memory/eval-source.js.map +1 -0
  143. package/dist/orchestrator/memory/retrieve.d.ts +45 -0
  144. package/dist/orchestrator/memory/retrieve.d.ts.map +1 -0
  145. package/dist/orchestrator/memory/retrieve.js +102 -0
  146. package/dist/orchestrator/memory/retrieve.js.map +1 -0
  147. package/dist/orchestrator/model-resolver.d.ts.map +1 -1
  148. package/dist/orchestrator/model-resolver.js +12 -0
  149. package/dist/orchestrator/model-resolver.js.map +1 -1
  150. package/dist/orchestrator/pipeline.d.ts +10 -0
  151. package/dist/orchestrator/pipeline.d.ts.map +1 -1
  152. package/dist/orchestrator/pipeline.js +111 -3
  153. package/dist/orchestrator/pipeline.js.map +1 -1
  154. package/dist/orchestrator/planner-agent.d.ts +22 -1
  155. package/dist/orchestrator/planner-agent.d.ts.map +1 -1
  156. package/dist/orchestrator/planner-agent.js +160 -4
  157. package/dist/orchestrator/planner-agent.js.map +1 -1
  158. package/dist/orchestrator/research-agent.js +2 -2
  159. package/dist/orchestrator/research-agent.js.map +1 -1
  160. package/dist/orchestrator/tools/handlers.d.ts +14 -0
  161. package/dist/orchestrator/tools/handlers.d.ts.map +1 -1
  162. package/dist/orchestrator/tools/handlers.js +29 -4
  163. package/dist/orchestrator/tools/handlers.js.map +1 -1
  164. package/dist/orchestrator/tools/schemas.js +5 -5
  165. package/dist/orchestrator/tools/schemas.js.map +1 -1
  166. package/dist/orchestrator/workflow/args-builder.d.ts +35 -0
  167. package/dist/orchestrator/workflow/args-builder.d.ts.map +1 -0
  168. package/dist/orchestrator/workflow/args-builder.js +142 -0
  169. package/dist/orchestrator/workflow/args-builder.js.map +1 -0
  170. package/dist/orchestrator/workflow/budget.d.ts +57 -0
  171. package/dist/orchestrator/workflow/budget.d.ts.map +1 -0
  172. package/dist/orchestrator/workflow/budget.js +80 -0
  173. package/dist/orchestrator/workflow/budget.js.map +1 -0
  174. package/dist/orchestrator/workflow/conformance.d.ts +27 -0
  175. package/dist/orchestrator/workflow/conformance.d.ts.map +1 -0
  176. package/dist/orchestrator/workflow/conformance.js +111 -0
  177. package/dist/orchestrator/workflow/conformance.js.map +1 -0
  178. package/dist/orchestrator/workflow/eligibility.d.ts +8 -0
  179. package/dist/orchestrator/workflow/eligibility.d.ts.map +1 -0
  180. package/dist/orchestrator/workflow/eligibility.js +10 -0
  181. package/dist/orchestrator/workflow/eligibility.js.map +1 -0
  182. package/dist/orchestrator/workflow/engine.d.ts +10 -0
  183. package/dist/orchestrator/workflow/engine.d.ts.map +1 -0
  184. package/dist/orchestrator/workflow/engine.js +2 -0
  185. package/dist/orchestrator/workflow/engine.js.map +1 -0
  186. package/dist/orchestrator/workflow/errors.d.ts +13 -0
  187. package/dist/orchestrator/workflow/errors.d.ts.map +1 -0
  188. package/dist/orchestrator/workflow/errors.js +26 -0
  189. package/dist/orchestrator/workflow/errors.js.map +1 -0
  190. package/dist/orchestrator/workflow/flusher.d.ts +19 -0
  191. package/dist/orchestrator/workflow/flusher.d.ts.map +1 -0
  192. package/dist/orchestrator/workflow/flusher.js +81 -0
  193. package/dist/orchestrator/workflow/flusher.js.map +1 -0
  194. package/dist/orchestrator/workflow/interpreter.d.ts +48 -0
  195. package/dist/orchestrator/workflow/interpreter.d.ts.map +1 -0
  196. package/dist/orchestrator/workflow/interpreter.js +92 -0
  197. package/dist/orchestrator/workflow/interpreter.js.map +1 -0
  198. package/dist/orchestrator/workflow/pure-sprint.d.ts +65 -0
  199. package/dist/orchestrator/workflow/pure-sprint.d.ts.map +1 -0
  200. package/dist/orchestrator/workflow/pure-sprint.js +82 -0
  201. package/dist/orchestrator/workflow/pure-sprint.js.map +1 -0
  202. package/dist/orchestrator/workflow/reconciler.d.ts +15 -0
  203. package/dist/orchestrator/workflow/reconciler.d.ts.map +1 -0
  204. package/dist/orchestrator/workflow/reconciler.js +65 -0
  205. package/dist/orchestrator/workflow/reconciler.js.map +1 -0
  206. package/dist/orchestrator/workflow/resume-cursor.d.ts +10 -0
  207. package/dist/orchestrator/workflow/resume-cursor.d.ts.map +1 -0
  208. package/dist/orchestrator/workflow/resume-cursor.js +25 -0
  209. package/dist/orchestrator/workflow/resume-cursor.js.map +1 -0
  210. package/dist/orchestrator/workflow/retry.d.ts +50 -0
  211. package/dist/orchestrator/workflow/retry.d.ts.map +1 -0
  212. package/dist/orchestrator/workflow/retry.js +100 -0
  213. package/dist/orchestrator/workflow/retry.js.map +1 -0
  214. package/dist/orchestrator/workflow/scheduler.d.ts +87 -0
  215. package/dist/orchestrator/workflow/scheduler.d.ts.map +1 -0
  216. package/dist/orchestrator/workflow/scheduler.js +158 -0
  217. package/dist/orchestrator/workflow/scheduler.js.map +1 -0
  218. package/dist/orchestrator/workflow/selector.d.ts +26 -0
  219. package/dist/orchestrator/workflow/selector.d.ts.map +1 -0
  220. package/dist/orchestrator/workflow/selector.js +54 -0
  221. package/dist/orchestrator/workflow/selector.js.map +1 -0
  222. package/dist/orchestrator/workflow/synthesizer.d.ts +52 -0
  223. package/dist/orchestrator/workflow/synthesizer.d.ts.map +1 -0
  224. package/dist/orchestrator/workflow/synthesizer.js +75 -0
  225. package/dist/orchestrator/workflow/synthesizer.js.map +1 -0
  226. package/dist/orchestrator/workflow/ts-engine.d.ts +13 -0
  227. package/dist/orchestrator/workflow/ts-engine.d.ts.map +1 -0
  228. package/dist/orchestrator/workflow/ts-engine.js +14 -0
  229. package/dist/orchestrator/workflow/ts-engine.js.map +1 -0
  230. package/dist/orchestrator/workflow/types.d.ts +55 -0
  231. package/dist/orchestrator/workflow/types.d.ts.map +1 -0
  232. package/dist/orchestrator/workflow/types.js +3 -0
  233. package/dist/orchestrator/workflow/types.js.map +1 -0
  234. package/dist/orchestrator/workflow/workflow-engine.d.ts +31 -0
  235. package/dist/orchestrator/workflow/workflow-engine.d.ts.map +1 -0
  236. package/dist/orchestrator/workflow/workflow-engine.js +70 -0
  237. package/dist/orchestrator/workflow/workflow-engine.js.map +1 -0
  238. package/dist/providers/anthropic.d.ts.map +1 -1
  239. package/dist/providers/anthropic.js +49 -6
  240. package/dist/providers/anthropic.js.map +1 -1
  241. package/dist/providers/claude-code.d.ts +44 -0
  242. package/dist/providers/claude-code.d.ts.map +1 -0
  243. package/dist/providers/claude-code.js +143 -0
  244. package/dist/providers/claude-code.js.map +1 -0
  245. package/dist/providers/factory.d.ts +16 -2
  246. package/dist/providers/factory.d.ts.map +1 -1
  247. package/dist/providers/factory.js +66 -12
  248. package/dist/providers/factory.js.map +1 -1
  249. package/dist/providers/google.d.ts.map +1 -1
  250. package/dist/providers/google.js +27 -3
  251. package/dist/providers/google.js.map +1 -1
  252. package/dist/providers/index.d.ts +3 -1
  253. package/dist/providers/index.d.ts.map +1 -1
  254. package/dist/providers/index.js +3 -1
  255. package/dist/providers/index.js.map +1 -1
  256. package/dist/providers/openai.d.ts.map +1 -1
  257. package/dist/providers/openai.js +24 -3
  258. package/dist/providers/openai.js.map +1 -1
  259. package/dist/providers/preflight.d.ts +22 -0
  260. package/dist/providers/preflight.d.ts.map +1 -0
  261. package/dist/providers/preflight.js +54 -0
  262. package/dist/providers/preflight.js.map +1 -0
  263. package/dist/providers/structured.d.ts +130 -0
  264. package/dist/providers/structured.d.ts.map +1 -0
  265. package/dist/providers/structured.js +205 -0
  266. package/dist/providers/structured.js.map +1 -0
  267. package/dist/providers/types.d.ts +28 -0
  268. package/dist/providers/types.d.ts.map +1 -1
  269. package/dist/state/history-rotation.d.ts +17 -0
  270. package/dist/state/history-rotation.d.ts.map +1 -0
  271. package/dist/state/history-rotation.js +84 -0
  272. package/dist/state/history-rotation.js.map +1 -0
  273. package/dist/state/history.d.ts +16 -4
  274. package/dist/state/history.d.ts.map +1 -1
  275. package/dist/state/history.js +62 -20
  276. package/dist/state/history.js.map +1 -1
  277. package/dist/state/index.d.ts +1 -1
  278. package/dist/state/index.d.ts.map +1 -1
  279. package/dist/state/index.js +1 -1
  280. package/dist/state/index.js.map +1 -1
  281. package/dist/state/memory.d.ts +60 -0
  282. package/dist/state/memory.d.ts.map +1 -0
  283. package/dist/state/memory.js +242 -0
  284. package/dist/state/memory.js.map +1 -0
  285. package/hooks/hooks.json +12 -2
  286. package/package.json +9 -5
  287. package/scripts/spike-claude-code-provider.mjs +66 -0
  288. package/scripts/spike-deepseek.mjs +63 -0
  289. package/scripts/sync-targets.json +12 -0
  290. package/scripts/update-all.mjs +255 -0
  291. package/skills/bober.architect/SKILL.md +13 -0
  292. package/skills/bober.architect/references/arch-lens-panel.md +126 -0
  293. package/skills/bober.eval/SKILL.md +9 -0
  294. package/skills/bober.eval/references/lens-panel.md +115 -0
  295. package/skills/bober.plan/SKILL.md +6 -0
  296. package/skills/bober.run/SKILL.md +23 -4
  297. package/skills/bober.run/references/lens-panel.md +115 -0
  298. package/skills/bober.sprint/SKILL.md +44 -2
  299. package/skills/bober.sprint/references/lens-panel.md +115 -0
  300. package/skills/shared/arch-lens-panel.md +126 -0
  301. package/skills/shared/lens-panel.md +115 -0
@@ -0,0 +1,60 @@
1
+ import { z } from "zod";
2
+ export declare const LessonEntrySchema: z.ZodObject<{
3
+ lessonId: z.ZodString;
4
+ createdAt: z.ZodString;
5
+ category: z.ZodString;
6
+ tags: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
7
+ summary: z.ZodString;
8
+ occurrences: z.ZodNumber;
9
+ severity: z.ZodEnum<["info", "warn", "high"]>;
10
+ sourceEntryRefs: z.ZodArray<z.ZodString, "many">;
11
+ }, "strip", z.ZodTypeAny, {
12
+ severity: "info" | "high" | "warn";
13
+ summary: string;
14
+ category: string;
15
+ createdAt: string;
16
+ lessonId: string;
17
+ tags: string[];
18
+ occurrences: number;
19
+ sourceEntryRefs: string[];
20
+ }, {
21
+ severity: "info" | "high" | "warn";
22
+ summary: string;
23
+ category: string;
24
+ createdAt: string;
25
+ lessonId: string;
26
+ occurrences: number;
27
+ sourceEntryRefs: string[];
28
+ tags?: string[] | undefined;
29
+ }>;
30
+ export type LessonEntry = z.infer<typeof LessonEntrySchema>;
31
+ export interface LessonIndexRecord {
32
+ lessonId: string;
33
+ category: string;
34
+ severity: string;
35
+ occurrences: number;
36
+ tags: string[];
37
+ summarySnippet: string;
38
+ }
39
+ /**
40
+ * Append (or update) a lesson to the .bober/memory/ store.
41
+ * Writes <lessonId>.md with hand-rolled front-matter plus a human body.
42
+ * Upserts exactly one INDEX.md line for this lessonId (replace if exists, else append).
43
+ * Throws if the lesson fails schema validation (sourceEntryRefs must be non-empty).
44
+ */
45
+ export declare function appendLesson(projectRoot: string, lesson: LessonEntry): Promise<void>;
46
+ /**
47
+ * Load at most `limit` lesson index records from INDEX.md.
48
+ * Never opens individual lesson files — parses only INDEX.md.
49
+ * Returns an empty array if INDEX.md does not exist.
50
+ */
51
+ export declare function loadLessonIndex(projectRoot: string, { limit }: {
52
+ limit: number;
53
+ }): Promise<LessonIndexRecord[]>;
54
+ /**
55
+ * Load a single lesson by ID from its <lessonId>.md file.
56
+ * Parses front-matter and validates against LessonEntrySchema.
57
+ * Throws a descriptive error if the file does not exist or fails validation.
58
+ */
59
+ export declare function loadLesson(projectRoot: string, lessonId: string): Promise<LessonEntry>;
60
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/state/memory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA0BxB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AA6ID;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC,CAkCf;AAID;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3B,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAoB9B;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAkCtB"}
@@ -0,0 +1,242 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { z } from "zod";
4
+ import { ensureDir } from "./helpers.js";
5
+ // ── Constants ───────────────────────────────────────────────────────
6
+ const BOBER_DIR = ".bober";
7
+ const MEMORY_DIR = "memory";
8
+ const INDEX_FILE = "INDEX.md";
9
+ // ── Path Helpers ─────────────────────────────────────────────────────
10
+ function memoryDir(projectRoot) {
11
+ return join(projectRoot, BOBER_DIR, MEMORY_DIR);
12
+ }
13
+ function lessonPath(projectRoot, lessonId) {
14
+ return join(memoryDir(projectRoot), `${lessonId}.md`);
15
+ }
16
+ function indexPath(projectRoot) {
17
+ return join(memoryDir(projectRoot), INDEX_FILE);
18
+ }
19
+ // ── Schema ───────────────────────────────────────────────────────────
20
+ export const LessonEntrySchema = z.object({
21
+ lessonId: z.string().min(1),
22
+ createdAt: z.string().datetime(),
23
+ category: z.string().min(1),
24
+ tags: z.array(z.string()).default([]),
25
+ summary: z.string().min(1),
26
+ occurrences: z.number().int().positive(),
27
+ severity: z.enum(["info", "warn", "high"]),
28
+ sourceEntryRefs: z.array(z.string().min(1)).min(1),
29
+ });
30
+ // ── Serialization ─────────────────────────────────────────────────────
31
+ /**
32
+ * Serialize a LessonEntry to a markdown file with hand-rolled front-matter.
33
+ * Arrays (tags, sourceEntryRefs) are emitted as YAML block sequences.
34
+ */
35
+ function serializeLesson(lesson) {
36
+ const tagsBlock = lesson.tags.length > 0
37
+ ? `tags:\n${lesson.tags.map((t) => ` - ${t}`).join("\n")}`
38
+ : `tags: []`;
39
+ const refsBlock = `sourceEntryRefs:\n${lesson.sourceEntryRefs.map((r) => ` - ${r}`).join("\n")}`;
40
+ const frontMatter = [
41
+ `lessonId: ${lesson.lessonId}`,
42
+ `createdAt: ${lesson.createdAt}`,
43
+ `category: ${lesson.category}`,
44
+ tagsBlock,
45
+ `summary: ${lesson.summary}`,
46
+ `occurrences: ${lesson.occurrences}`,
47
+ `severity: ${lesson.severity}`,
48
+ refsBlock,
49
+ ].join("\n");
50
+ const body = `Lesson: ${lesson.lessonId}\n\nCategory: ${lesson.category}\nSeverity: ${lesson.severity}\nOccurrences: ${lesson.occurrences}\n\nSummary:\n${lesson.summary}\n\nSource References:\n${lesson.sourceEntryRefs.map((r) => `- ${r}`).join("\n")}\n`;
51
+ return `---\n${frontMatter}\n---\n\n${body}`;
52
+ }
53
+ /**
54
+ * Build a single INDEX.md line for a lesson, following the MEMORY.md curated-index format:
55
+ * - <lessonId> [<category>/<severity>] (x<occurrences>) tags: a,b — <summary first 80 chars>
56
+ */
57
+ function buildIndexLine(lesson) {
58
+ const tagsStr = lesson.tags.length > 0 ? lesson.tags.join(",") : "";
59
+ const snippet = lesson.summary.slice(0, 80);
60
+ const tagsSegment = tagsStr ? `tags: ${tagsStr}` : `tags:`;
61
+ return `- ${lesson.lessonId} [${lesson.category}/${lesson.severity}] (x${lesson.occurrences}) ${tagsSegment} — ${snippet}`;
62
+ }
63
+ /**
64
+ * Parse a single INDEX.md line into a LessonIndexRecord.
65
+ * Returns null for lines that do not match the expected format.
66
+ */
67
+ function parseIndexLine(line) {
68
+ // Expected: - <lessonId> [<category>/<severity>] (x<occurrences>) tags: a,b — <snippet>
69
+ const match = line.match(/^- (\S+) \[([^/\]]+)\/([^\]]+)\] \(x(\d+)\) tags: ([^—]*)— (.*)$/);
70
+ if (!match)
71
+ return null;
72
+ const [, lessonId, category, severity, occStr, tagsRaw, summarySnippet] = match;
73
+ const tags = tagsRaw.trim()
74
+ ? tagsRaw
75
+ .trim()
76
+ .split(",")
77
+ .map((t) => t.trim())
78
+ .filter(Boolean)
79
+ : [];
80
+ return {
81
+ lessonId: lessonId.trim(),
82
+ category: category.trim(),
83
+ severity: severity.trim(),
84
+ occurrences: Number(occStr),
85
+ tags,
86
+ summarySnippet: summarySnippet.trim(),
87
+ };
88
+ }
89
+ /**
90
+ * Parse the front-matter block from a lesson markdown file.
91
+ * Uses the hand-rolled regex approach from src/orchestrator/agent-loader.ts.
92
+ * Returns null if the file does not have the expected front-matter delimiters.
93
+ */
94
+ function parseLessonFrontMatter(raw) {
95
+ const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
96
+ if (!match)
97
+ return null;
98
+ const [, yamlBlock] = match;
99
+ const meta = {};
100
+ let currentKey = null;
101
+ let currentList = null;
102
+ for (const line of yamlBlock.split("\n")) {
103
+ const trimmed = line.trim();
104
+ // Block sequence item (e.g. " - value")
105
+ if (line.startsWith(" - ") && currentKey !== null && currentList !== null) {
106
+ currentList.push(line.slice(4).trim());
107
+ continue;
108
+ }
109
+ // Flush any pending list on a new key
110
+ if (currentKey !== null && currentList !== null && !line.startsWith(" ")) {
111
+ meta[currentKey] = currentList;
112
+ currentKey = null;
113
+ currentList = null;
114
+ }
115
+ if (trimmed.length === 0)
116
+ continue;
117
+ // Key: value or Key: (block sequence start)
118
+ const kvMatch = trimmed.match(/^([\w-]+):\s*(.*)$/);
119
+ if (!kvMatch)
120
+ continue;
121
+ const [, key, value] = kvMatch;
122
+ if (value === "[]") {
123
+ // Explicit empty array
124
+ meta[key] = [];
125
+ continue;
126
+ }
127
+ if (!value) {
128
+ // Start of a block sequence
129
+ currentKey = key;
130
+ currentList = [];
131
+ continue;
132
+ }
133
+ // Scalar value
134
+ meta[key] = value;
135
+ }
136
+ // Flush trailing list
137
+ if (currentKey !== null && currentList !== null) {
138
+ meta[currentKey] = currentList;
139
+ }
140
+ return meta;
141
+ }
142
+ // ── Persistence ──────────────────────────────────────────────────────
143
+ /**
144
+ * Append (or update) a lesson to the .bober/memory/ store.
145
+ * Writes <lessonId>.md with hand-rolled front-matter plus a human body.
146
+ * Upserts exactly one INDEX.md line for this lessonId (replace if exists, else append).
147
+ * Throws if the lesson fails schema validation (sourceEntryRefs must be non-empty).
148
+ */
149
+ export async function appendLesson(projectRoot, lesson) {
150
+ const validation = LessonEntrySchema.safeParse(lesson);
151
+ if (!validation.success) {
152
+ const issues = validation.error.issues
153
+ .map((i) => ` - ${i.path.join(".")}: ${i.message}`)
154
+ .join("\n");
155
+ throw new Error(`Invalid lesson entry:\n${issues}`);
156
+ }
157
+ const dir = memoryDir(projectRoot);
158
+ await ensureDir(dir);
159
+ // Write the lesson markdown file
160
+ await writeFile(lessonPath(projectRoot, lesson.lessonId), serializeLesson(lesson), "utf-8");
161
+ // Upsert one INDEX.md line for this lessonId
162
+ const idxPath = indexPath(projectRoot);
163
+ let existingContent = "";
164
+ try {
165
+ existingContent = await readFile(idxPath, "utf-8");
166
+ }
167
+ catch {
168
+ // INDEX.md does not exist yet — treat as empty
169
+ }
170
+ const lines = existingContent.split("\n").filter((l) => l.trim().length > 0);
171
+ // Drop any prior line for this lessonId (match leading "- <lessonId> " token)
172
+ const filtered = lines.filter((l) => {
173
+ const parts = l.split(" ");
174
+ // parts[0] = "-", parts[1] = lessonId
175
+ return !(parts[0] === "-" && parts[1] === lesson.lessonId);
176
+ });
177
+ filtered.push(buildIndexLine(lesson));
178
+ await writeFile(idxPath, filtered.join("\n") + "\n", "utf-8");
179
+ }
180
+ // ── Read ─────────────────────────────────────────────────────────────
181
+ /**
182
+ * Load at most `limit` lesson index records from INDEX.md.
183
+ * Never opens individual lesson files — parses only INDEX.md.
184
+ * Returns an empty array if INDEX.md does not exist.
185
+ */
186
+ export async function loadLessonIndex(projectRoot, { limit }) {
187
+ let content;
188
+ try {
189
+ content = await readFile(indexPath(projectRoot), "utf-8");
190
+ }
191
+ catch {
192
+ // INDEX.md does not exist yet
193
+ return [];
194
+ }
195
+ const lines = content.split("\n").filter((l) => l.trim().length > 0);
196
+ const records = [];
197
+ for (const line of lines) {
198
+ const record = parseIndexLine(line);
199
+ if (record !== null) {
200
+ records.push(record);
201
+ }
202
+ }
203
+ return records.slice(-limit);
204
+ }
205
+ /**
206
+ * Load a single lesson by ID from its <lessonId>.md file.
207
+ * Parses front-matter and validates against LessonEntrySchema.
208
+ * Throws a descriptive error if the file does not exist or fails validation.
209
+ */
210
+ export async function loadLesson(projectRoot, lessonId) {
211
+ let raw;
212
+ try {
213
+ raw = await readFile(lessonPath(projectRoot, lessonId), "utf-8");
214
+ }
215
+ catch {
216
+ throw new Error(`Lesson not found: ${lessonId} (path: ${lessonPath(projectRoot, lessonId)})`);
217
+ }
218
+ const meta = parseLessonFrontMatter(raw);
219
+ if (meta === null) {
220
+ throw new Error(`Lesson file for ${lessonId} has no valid front-matter`);
221
+ }
222
+ // Reconstruct lesson object from parsed meta — coerce numeric fields
223
+ const candidate = {
224
+ lessonId: meta["lessonId"],
225
+ createdAt: meta["createdAt"],
226
+ category: meta["category"],
227
+ tags: meta["tags"] ?? [],
228
+ summary: meta["summary"],
229
+ occurrences: Number(meta["occurrences"]),
230
+ severity: meta["severity"],
231
+ sourceEntryRefs: meta["sourceEntryRefs"],
232
+ };
233
+ const result = LessonEntrySchema.safeParse(candidate);
234
+ if (!result.success) {
235
+ const issues = result.error.issues
236
+ .map((i) => ` - ${i.path.join(".")}: ${i.message}`)
237
+ .join("\n");
238
+ throw new Error(`Lesson file for ${lessonId} failed validation:\n${issues}`);
239
+ }
240
+ return result.data;
241
+ }
242
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/state/memory.ts"],"names":[],"mappings":"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"}
package/hooks/hooks.json CHANGED
@@ -15,11 +15,21 @@
15
15
  "PostToolUse": [
16
16
  {
17
17
  "matcher": "Edit|Write",
18
- "command": "echo 'Files modified — run /bober:eval to verify'"
18
+ "hooks": [
19
+ {
20
+ "type": "command",
21
+ "command": "echo 'Files modified — run /bober:eval to verify'"
22
+ }
23
+ ]
19
24
  },
20
25
  {
21
26
  "matcher": "Edit|Write",
22
- "command": "node scripts/graph-hook.mjs"
27
+ "hooks": [
28
+ {
29
+ "type": "command",
30
+ "command": "node ${CLAUDE_PLUGIN_ROOT:-.}/scripts/graph-hook.mjs"
31
+ }
32
+ ]
23
33
  }
24
34
  ]
25
35
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-bober",
3
- "version": "0.15.0",
4
- "description": "Multi-agent harness for building applications autonomously with any LLM. Researcher, Planner, Curator, Generator, Evaluator pipeline. Supports Claude, GPT, Gemini, Ollama. MCP server for Cursor/Windsurf.",
3
+ "version": "0.17.0",
4
+ "description": "Multi-agent harness for building applications autonomously with any LLM. Researcher, Planner, Curator, Generator, Evaluator, Documenter pipeline. Supports Claude, GPT, Gemini, DeepSeek, Ollama, and Claude Code subscriptions. MCP server for Cursor/Windsurf.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -14,6 +14,8 @@
14
14
  "lint": "eslint src/",
15
15
  "typecheck": "tsc --noEmit",
16
16
  "test": "vitest",
17
+ "update-all": "node scripts/update-all.mjs",
18
+ "update-all:check": "node scripts/update-all.mjs --check",
17
19
  "prepublishOnly": "npm run build"
18
20
  },
19
21
  "keywords": [
@@ -28,6 +30,7 @@
28
30
  "claude",
29
31
  "openai",
30
32
  "gemini",
33
+ "deepseek",
31
34
  "ollama",
32
35
  "plugin"
33
36
  ],
@@ -66,11 +69,12 @@
66
69
  "ora": "^8.1.1",
67
70
  "prompts": "^2.4.2",
68
71
  "semver": "^7.8.1",
69
- "zod": "^3.24.2"
72
+ "zod": "^3.24.2",
73
+ "zod-to-json-schema": "^3.25.2"
70
74
  },
71
75
  "peerDependencies": {
72
76
  "@google/generative-ai": ">=0.21.0",
73
- "openai": ">=4.0.0"
77
+ "openai": "^6.42.0"
74
78
  },
75
79
  "peerDependenciesMeta": {
76
80
  "openai": {
@@ -87,7 +91,7 @@
87
91
  "@types/semver": "^7.7.1",
88
92
  "@typescript-eslint/eslint-plugin": "^8.22.0",
89
93
  "@typescript-eslint/parser": "^8.22.0",
90
- "eslint": "^9.19.0",
94
+ "eslint": "^10.0.0",
91
95
  "markdownlint-cli": "^0.48.0",
92
96
  "typescript": "^5.7.3",
93
97
  "vitest": "^3.0.5"
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ // SPIKE runner: prove ClaudeCodeAdapter satisfies LLMClient.chat() end-to-end
3
+ // against the user's Claude subscription (NO ANTHROPIC_API_KEY).
4
+ //
5
+ // node scripts/spike-claude-code-provider.mjs
6
+ //
7
+ // Builds nothing; imports the compiled dist adapter (run `npm run build` first).
8
+ // Exercises the real `claude -p` subprocess. Prints the normalized ChatResponse
9
+ // and asserts the contract shape. Also demonstrates the tools-rejection guard.
10
+
11
+ import { spawnSync } from "node:child_process";
12
+ import { ClaudeCodeAdapter } from "../dist/providers/claude-code.js";
13
+
14
+ const probe = spawnSync("claude", ["--version"], { stdio: "ignore" });
15
+ if (probe.error || probe.status !== 0) {
16
+ console.log("SKIP: `claude` binary not on PATH — skipping claude-code smoke.");
17
+ process.exit(0);
18
+ }
19
+
20
+ function assert(cond, msg) {
21
+ if (!cond) {
22
+ console.error("ASSERT FAILED:", msg);
23
+ process.exit(1);
24
+ }
25
+ }
26
+
27
+ const adapter = new ClaudeCodeAdapter();
28
+
29
+ console.log("── Spike 1: no-tools planner-style completion (real subscription call) ──");
30
+ const res = await adapter.chat({
31
+ model: "haiku", // cheapest for a spike; proves the seam without burning credit
32
+ system:
33
+ "You are a terse planning assistant. Answer in one short sentence, no preamble.",
34
+ messages: [
35
+ { role: "user", content: "Name one risk of building a feature without tests." },
36
+ ],
37
+ });
38
+
39
+ console.log("text:", JSON.stringify(res.text));
40
+ console.log("stopReason:", res.stopReason);
41
+ console.log("usage:", JSON.stringify(res.usage));
42
+
43
+ assert(typeof res.text === "string" && res.text.length > 0, "text should be non-empty");
44
+ assert(Array.isArray(res.toolCalls) && res.toolCalls.length === 0, "toolCalls should be empty");
45
+ assert(typeof res.usage.inputTokens === "number", "usage.inputTokens should be a number");
46
+ assert(typeof res.usage.outputTokens === "number", "usage.outputTokens should be a number");
47
+ console.log("✓ ChatResponse contract satisfied via subscription (no API key)\n");
48
+
49
+ console.log("── Spike 2: tools guard must throw (honest about the limitation) ──");
50
+ let threw = false;
51
+ try {
52
+ await adapter.chat({
53
+ model: "haiku",
54
+ system: "x",
55
+ messages: [{ role: "user", content: "y" }],
56
+ tools: [
57
+ { name: "do_thing", description: "d", input_schema: { type: "object", properties: {} } },
58
+ ],
59
+ });
60
+ } catch (err) {
61
+ threw = true;
62
+ console.log("✓ threw as designed:", err.message.split(":")[0]);
63
+ }
64
+ assert(threw, "adapter must reject custom tools rather than silently drop them");
65
+
66
+ console.log("\nSPIKE PASSED — claude -p backs LLMClient for no-tools roles on the subscription.");
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ // SPIKE: verify DeepSeek works through the EXISTING openai-compat adapter,
3
+ // including TOOL CALLING (the capability that makes it usable for ALL roles,
4
+ // unlike the claude-code provider). No new adapter code — this is the whole point.
5
+ //
6
+ // DEEPSEEK_API_KEY=sk-... node scripts/spike-deepseek.mjs
7
+ //
8
+ // Run `npm run build` first (imports compiled dist).
9
+
10
+ import { createClient } from "../dist/providers/factory.js";
11
+
12
+ const key = process.env.DEEPSEEK_API_KEY;
13
+ if (!key) {
14
+ console.log("SKIP: DEEPSEEK_API_KEY not set — skipping DeepSeek smoke.");
15
+ process.exit(0);
16
+ }
17
+
18
+ function assert(c, m) { if (!c) { console.error("ASSERT FAILED:", m); process.exit(1); } }
19
+
20
+ // Existing openai-compat adapter, pointed at DeepSeek's OpenAI-compatible endpoint.
21
+ const client = createClient(
22
+ "openai-compat",
23
+ "https://api.deepseek.com",
24
+ { apiKey: key },
25
+ "deepseek-v4-pro",
26
+ "Spike",
27
+ );
28
+
29
+ console.log("── Spike 1: plain completion via DeepSeek (openai-compat) ──");
30
+ const r1 = await client.chat({
31
+ model: "deepseek-v4-pro",
32
+ system: "You are terse. One sentence, no preamble.",
33
+ messages: [{ role: "user", content: "What is a code knowledge graph, in one sentence?" }],
34
+ });
35
+ console.log("text:", JSON.stringify(r1.text).slice(0, 200));
36
+ console.log("stopReason:", r1.stopReason, "| usage:", JSON.stringify(r1.usage));
37
+ assert(typeof r1.text === "string" && r1.text.length > 0, "text non-empty");
38
+
39
+ console.log("\n── Spike 2: TOOL CALLING (the differentiator vs claude-code) ──");
40
+ const r2 = await client.chat({
41
+ model: "deepseek-v4-pro",
42
+ system: "You are an agent. When asked to read a file, you MUST call the read_file tool. Do not answer directly.",
43
+ messages: [{ role: "user", content: "Read the file src/index.ts and tell me what it does." }],
44
+ tools: [
45
+ {
46
+ name: "read_file",
47
+ description: "Read a file from the project by path.",
48
+ input_schema: {
49
+ type: "object",
50
+ properties: { file_path: { type: "string", description: "Path to read" } },
51
+ required: ["file_path"],
52
+ },
53
+ },
54
+ ],
55
+ });
56
+ console.log("stopReason:", r2.stopReason);
57
+ console.log("toolCalls:", JSON.stringify(r2.toolCalls, null, 2));
58
+ console.log("usage:", JSON.stringify(r2.usage));
59
+ assert(r2.toolCalls.length > 0, "DeepSeek should emit a tool_use call");
60
+ assert(r2.toolCalls[0].name === "read_file", "should call read_file");
61
+ assert(typeof r2.toolCalls[0].input?.file_path === "string", "tool input should parse with file_path");
62
+
63
+ console.log("\nDEEPSEEK SPIKE PASSED — existing openai-compat adapter drives DeepSeek WITH tool calling, all roles, zero new code.");
@@ -0,0 +1,12 @@
1
+ {
2
+ "//": "Projects that consume agent-bober's skills/agents. `npm run update-all` rebuilds the CLI once (shared via symlink) and re-inlines skills/agents into each target's .claude/. Add absolute project paths here. Auto-discovery (--discover) appends any initialized project it finds under the configured roots.",
3
+ "discoverRoots": [
4
+ "/Users/bober4ik/WebstormProjects",
5
+ "/Users/bober4ik/agent-bober-workspace"
6
+ ],
7
+ "targets": [
8
+ "/Users/bober4ik/WebstormProjects/solex-integration-demo",
9
+ "/Users/bober4ik/WebstormProjects/solex-integration-demo/apps/api",
10
+ "/Users/bober4ik/WebstormProjects/solex-integration-demo/solex-games-betbook (Copy)"
11
+ ]
12
+ }