@agntk/agent-harness 0.1.4 → 0.1.6

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 (178) hide show
  1. package/README.md +104 -43
  2. package/dist/{analytics-RPT73WNM.js → analytics-L24W3B7U.js} +1 -2
  3. package/dist/auto-processor-QIRUOGEI.js +12 -0
  4. package/dist/{chunk-UPLBF4RZ.js → chunk-2UVWCTAY.js} +2 -2
  5. package/dist/{chunk-CSL3ERUI.js → chunk-4P6TRFPZ.js} +3 -3
  6. package/dist/chunk-4P6TRFPZ.js.map +1 -0
  7. package/dist/{chunk-4CWAGBNS.js → chunk-4TQQZILG.js} +73 -3
  8. package/dist/chunk-4TQQZILG.js.map +1 -0
  9. package/dist/{chunk-DA7IKHC4.js → chunk-5CO5JTYT.js} +2 -2
  10. package/dist/chunk-5CO5JTYT.js.map +1 -0
  11. package/dist/{chunk-A7BJPQQ6.js → chunk-5O5OGOOQ.js} +2 -2
  12. package/dist/{chunk-UWQTZMNI.js → chunk-7GZ4D6V6.js} +2 -2
  13. package/dist/{chunk-FLZU44SV.js → chunk-AN6Y4MDD.js} +6 -6
  14. package/dist/{chunk-4FDUOGSZ.js → chunk-D7AWV24Z.js} +3 -3
  15. package/dist/{chunk-CHJ5GNZC.js → chunk-EC42HQQH.js} +2 -2
  16. package/dist/{chunk-YIJY5DBV.js → chunk-KLYMGWQJ.js} +4 -4
  17. package/dist/chunk-KLYMGWQJ.js.map +1 -0
  18. package/dist/{chunk-YUFNYN2H.js → chunk-M62KLIEK.js} +4 -4
  19. package/dist/chunk-M62KLIEK.js.map +1 -0
  20. package/dist/{chunk-GJNNR2RA.js → chunk-M6PDMK2O.js} +3 -3
  21. package/dist/{chunk-M7NXUK55.js → chunk-NVC2WY4K.js} +2 -2
  22. package/dist/{chunk-XTBKL5BI.js → chunk-PMFAYKBD.js} +2 -2
  23. package/dist/chunk-PMFAYKBD.js.map +1 -0
  24. package/dist/{chunk-274RV3YO.js → chunk-QMOIVORH.js} +3 -3
  25. package/dist/chunk-QMOIVORH.js.map +1 -0
  26. package/dist/{chunk-RY3ZFII7.js → chunk-SEHAQTBO.js} +6 -6
  27. package/dist/{chunk-MPZ3BPUI.js → chunk-UMXPOYZR.js} +4 -4
  28. package/dist/{chunk-W4T7PGI2.js → chunk-UXCHAS3Z.js} +4 -4
  29. package/dist/cli/index.js +153 -167
  30. package/dist/cli/index.js.map +1 -1
  31. package/dist/config-PYSS3QY6.js +12 -0
  32. package/dist/context-loader-RSXXFW5R.js +12 -0
  33. package/dist/{conversation-QDEIDQPH.js → conversation-TBTFIJVU.js} +6 -7
  34. package/dist/{cost-tracker-RS3W7SVY.js → cost-tracker-NZRZEHVA.js} +1 -2
  35. package/dist/{delegate-VJCJLYEK.js → delegate-3KJAL4NZ.js} +7 -8
  36. package/dist/{emotional-state-VQVRA6ED.js → emotional-state-IN4ZUL2Q.js} +1 -2
  37. package/dist/{emotional-state-VQVRA6ED.js.map → emotional-state-IN4ZUL2Q.js.map} +1 -1
  38. package/dist/{env-discovery-2BLVMAIM.js → env-discovery-PXBRE5FX.js} +1 -2
  39. package/dist/{env-discovery-2BLVMAIM.js.map → env-discovery-PXBRE5FX.js.map} +1 -1
  40. package/dist/{export-6GCYHEHQ.js → export-GYLWROMB.js} +3 -4
  41. package/dist/{export-6GCYHEHQ.js.map → export-GYLWROMB.js.map} +1 -1
  42. package/dist/graph-LEEO37L3.js +13 -0
  43. package/dist/{harness-WE4SLCML.js → harness-R5FKRICG.js} +8 -9
  44. package/dist/{health-NZ6WNIMV.js → health-HL2JYHIY.js} +1 -2
  45. package/dist/indexer-L5UC6J2V.js +15 -0
  46. package/dist/{instinct-learner-SRM72DHF.js → instinct-learner-QGAMIS3X.js} +5 -6
  47. package/dist/{intake-4M3HNU43.js → intake-SVJKFHTL.js} +5 -6
  48. package/dist/{intelligence-HJOCA4SJ.js → intelligence-XPV3MC5U.js} +10 -13
  49. package/dist/intelligence-XPV3MC5U.js.map +1 -0
  50. package/dist/{journal-WANJL3MI.js → journal-ITUMKT6U.js} +5 -6
  51. package/dist/{loader-C3TKIKZR.js → loader-27PLDCOJ.js} +3 -4
  52. package/dist/{mcp-WTQJJZAO.js → mcp-JSIUJJZV.js} +1 -2
  53. package/dist/{mcp-discovery-WPAQFL6S.js → mcp-discovery-DG3RQYLM.js} +1 -2
  54. package/dist/{mcp-discovery-WPAQFL6S.js.map → mcp-discovery-DG3RQYLM.js.map} +1 -1
  55. package/dist/{mcp-installer-6O2XXD3V.js → mcp-installer-X2TJ2S2G.js} +3 -4
  56. package/dist/{mcp-installer-6O2XXD3V.js.map → mcp-installer-X2TJ2S2G.js.map} +1 -1
  57. package/dist/{metrics-KXGNFAAB.js → metrics-2MNINXNQ.js} +1 -2
  58. package/dist/{primitive-registry-I6VTIR4W.js → primitive-registry-ZMGGXSO5.js} +3 -4
  59. package/dist/{primitive-registry-I6VTIR4W.js.map → primitive-registry-ZMGGXSO5.js.map} +1 -1
  60. package/dist/{project-discovery-C4UMD7JI.js → project-discovery-FQLAZKEM.js} +1 -2
  61. package/dist/project-discovery-FQLAZKEM.js.map +1 -0
  62. package/dist/{provider-SXPQZ74H.js → provider-HQY6SPZI.js} +1 -2
  63. package/dist/{rate-limiter-RLRVM325.js → rate-limiter-PH5DCVU4.js} +1 -2
  64. package/dist/{rule-engine-YGQ3RYZM.js → rule-engine-DM26S77N.js} +3 -4
  65. package/dist/{rule-engine-YGQ3RYZM.js.map → rule-engine-DM26S77N.js.map} +1 -1
  66. package/dist/{scaffold-A3VRRCBV.js → scaffold-2F36YVW6.js} +5 -6
  67. package/dist/{scaffold-A3VRRCBV.js.map → scaffold-2F36YVW6.js.map} +1 -1
  68. package/dist/{scheduler-XHHIVHRI.js → scheduler-Q7GB2KCW.js} +11 -12
  69. package/dist/{scheduler-XHHIVHRI.js.map → scheduler-Q7GB2KCW.js.map} +1 -1
  70. package/dist/{search-V3W5JMJG.js → search-6Y6NCOLQ.js} +3 -4
  71. package/dist/search-6Y6NCOLQ.js.map +1 -0
  72. package/dist/{semantic-search-2DTOO5UX.js → semantic-search-FN6FZIXI.js} +3 -4
  73. package/dist/semantic-search-FN6FZIXI.js.map +1 -0
  74. package/dist/{serve-DTQ3HENY.js → serve-MXRTP2HE.js} +10 -11
  75. package/dist/serve-MXRTP2HE.js.map +1 -0
  76. package/dist/{sessions-CZGVXKQE.js → sessions-G6SZZXWS.js} +1 -2
  77. package/dist/{sources-RW5DT56F.js → sources-7LDYO5GK.js} +1 -2
  78. package/dist/{starter-packs-76YUVHEU.js → starter-packs-OR7NI5NA.js} +1 -2
  79. package/dist/{starter-packs-76YUVHEU.js.map → starter-packs-OR7NI5NA.js.map} +1 -1
  80. package/dist/{state-GMXILIHW.js → state-25IQEC5C.js} +1 -2
  81. package/dist/{state-merge-NKO5FRBA.js → state-merge-E333OEIQ.js} +1 -2
  82. package/dist/{state-merge-NKO5FRBA.js.map → state-merge-E333OEIQ.js.map} +1 -1
  83. package/dist/{telemetry-UC6PBXC7.js → telemetry-RS2JZUZP.js} +4 -5
  84. package/dist/{tool-executor-MJ7IG7PQ.js → tool-executor-6I5PHQDY.js} +5 -6
  85. package/dist/{tools-DZ4KETET.js → tools-NDFJNVHK.js} +4 -5
  86. package/dist/{types-EW7AIB3R.js → types-NPJZAI72.js} +2 -3
  87. package/dist/{universal-installer-AAXXYM5A.js → universal-installer-LCAZHFZR.js} +91 -7
  88. package/dist/universal-installer-LCAZHFZR.js.map +1 -0
  89. package/dist/validator-LM7RZWSH.js +21 -0
  90. package/dist/{verification-gate-FYXUX6LH.js → verification-gate-2O6DF2B7.js} +3 -4
  91. package/dist/verification-gate-2O6DF2B7.js.map +1 -0
  92. package/dist/{versioning-Z3XNE2Q2.js → versioning-WEGF6KJG.js} +1 -2
  93. package/dist/versioning-WEGF6KJG.js.map +1 -0
  94. package/dist/{watcher-ISJC7YKL.js → watcher-GZWQSWZ6.js} +5 -6
  95. package/dist/{watcher-ISJC7YKL.js.map → watcher-GZWQSWZ6.js.map} +1 -1
  96. package/dist/{web-server-DD7ZOP46.js → web-server-2Y4CHD2W.js} +8 -9
  97. package/package.json +1 -9
  98. package/dist/agent-framework-K4GUIICH.js +0 -344
  99. package/dist/agent-framework-K4GUIICH.js.map +0 -1
  100. package/dist/auto-processor-OLE45UI3.js +0 -13
  101. package/dist/chunk-274RV3YO.js.map +0 -1
  102. package/dist/chunk-4CWAGBNS.js.map +0 -1
  103. package/dist/chunk-CSL3ERUI.js.map +0 -1
  104. package/dist/chunk-DA7IKHC4.js.map +0 -1
  105. package/dist/chunk-DGUM43GV.js +0 -11
  106. package/dist/chunk-FD55B3IO.js +0 -204
  107. package/dist/chunk-FD55B3IO.js.map +0 -1
  108. package/dist/chunk-GUJTBGVS.js +0 -2212
  109. package/dist/chunk-GUJTBGVS.js.map +0 -1
  110. package/dist/chunk-KFX54TQM.js +0 -165
  111. package/dist/chunk-KFX54TQM.js.map +0 -1
  112. package/dist/chunk-XTBKL5BI.js.map +0 -1
  113. package/dist/chunk-YIJY5DBV.js.map +0 -1
  114. package/dist/chunk-YUFNYN2H.js.map +0 -1
  115. package/dist/chunk-ZZJOFKAT.js +0 -13
  116. package/dist/config-WVMRUOCA.js +0 -13
  117. package/dist/context-loader-3ORBPMHJ.js +0 -13
  118. package/dist/graph-YUIPOSOO.js +0 -14
  119. package/dist/harness-LCHA3DWP.js +0 -10
  120. package/dist/index.d.ts +0 -3612
  121. package/dist/index.js +0 -13713
  122. package/dist/index.js.map +0 -1
  123. package/dist/indexer-LONANRRM.js +0 -16
  124. package/dist/intelligence-HJOCA4SJ.js.map +0 -1
  125. package/dist/project-discovery-C4UMD7JI.js.map +0 -1
  126. package/dist/provider-LQHQX7Z7.js +0 -26
  127. package/dist/search-V3W5JMJG.js.map +0 -1
  128. package/dist/semantic-search-2DTOO5UX.js.map +0 -1
  129. package/dist/serve-DTQ3HENY.js.map +0 -1
  130. package/dist/tools-DZ4KETET.js.map +0 -1
  131. package/dist/types-EW7AIB3R.js.map +0 -1
  132. package/dist/types-WGDLSPO6.js +0 -16
  133. package/dist/types-WGDLSPO6.js.map +0 -1
  134. package/dist/universal-installer-AAXXYM5A.js.map +0 -1
  135. package/dist/validator-7WXMDIHH.js +0 -22
  136. package/dist/validator-7WXMDIHH.js.map +0 -1
  137. package/dist/verification-gate-FYXUX6LH.js.map +0 -1
  138. package/dist/versioning-Z3XNE2Q2.js.map +0 -1
  139. package/dist/web-server-DD7ZOP46.js.map +0 -1
  140. /package/dist/{analytics-RPT73WNM.js.map → analytics-L24W3B7U.js.map} +0 -0
  141. /package/dist/{auto-processor-OLE45UI3.js.map → auto-processor-QIRUOGEI.js.map} +0 -0
  142. /package/dist/{chunk-UPLBF4RZ.js.map → chunk-2UVWCTAY.js.map} +0 -0
  143. /package/dist/{chunk-A7BJPQQ6.js.map → chunk-5O5OGOOQ.js.map} +0 -0
  144. /package/dist/{chunk-UWQTZMNI.js.map → chunk-7GZ4D6V6.js.map} +0 -0
  145. /package/dist/{chunk-FLZU44SV.js.map → chunk-AN6Y4MDD.js.map} +0 -0
  146. /package/dist/{chunk-4FDUOGSZ.js.map → chunk-D7AWV24Z.js.map} +0 -0
  147. /package/dist/{chunk-CHJ5GNZC.js.map → chunk-EC42HQQH.js.map} +0 -0
  148. /package/dist/{chunk-GJNNR2RA.js.map → chunk-M6PDMK2O.js.map} +0 -0
  149. /package/dist/{chunk-M7NXUK55.js.map → chunk-NVC2WY4K.js.map} +0 -0
  150. /package/dist/{chunk-RY3ZFII7.js.map → chunk-SEHAQTBO.js.map} +0 -0
  151. /package/dist/{chunk-MPZ3BPUI.js.map → chunk-UMXPOYZR.js.map} +0 -0
  152. /package/dist/{chunk-W4T7PGI2.js.map → chunk-UXCHAS3Z.js.map} +0 -0
  153. /package/dist/{chunk-DGUM43GV.js.map → config-PYSS3QY6.js.map} +0 -0
  154. /package/dist/{chunk-ZZJOFKAT.js.map → context-loader-RSXXFW5R.js.map} +0 -0
  155. /package/dist/{config-WVMRUOCA.js.map → conversation-TBTFIJVU.js.map} +0 -0
  156. /package/dist/{context-loader-3ORBPMHJ.js.map → cost-tracker-NZRZEHVA.js.map} +0 -0
  157. /package/dist/{conversation-QDEIDQPH.js.map → delegate-3KJAL4NZ.js.map} +0 -0
  158. /package/dist/{cost-tracker-RS3W7SVY.js.map → graph-LEEO37L3.js.map} +0 -0
  159. /package/dist/{delegate-VJCJLYEK.js.map → harness-R5FKRICG.js.map} +0 -0
  160. /package/dist/{graph-YUIPOSOO.js.map → health-HL2JYHIY.js.map} +0 -0
  161. /package/dist/{harness-LCHA3DWP.js.map → indexer-L5UC6J2V.js.map} +0 -0
  162. /package/dist/{harness-WE4SLCML.js.map → instinct-learner-QGAMIS3X.js.map} +0 -0
  163. /package/dist/{health-NZ6WNIMV.js.map → intake-SVJKFHTL.js.map} +0 -0
  164. /package/dist/{indexer-LONANRRM.js.map → journal-ITUMKT6U.js.map} +0 -0
  165. /package/dist/{instinct-learner-SRM72DHF.js.map → loader-27PLDCOJ.js.map} +0 -0
  166. /package/dist/{intake-4M3HNU43.js.map → mcp-JSIUJJZV.js.map} +0 -0
  167. /package/dist/{journal-WANJL3MI.js.map → metrics-2MNINXNQ.js.map} +0 -0
  168. /package/dist/{loader-C3TKIKZR.js.map → provider-HQY6SPZI.js.map} +0 -0
  169. /package/dist/{mcp-WTQJJZAO.js.map → rate-limiter-PH5DCVU4.js.map} +0 -0
  170. /package/dist/{metrics-KXGNFAAB.js.map → sessions-G6SZZXWS.js.map} +0 -0
  171. /package/dist/{provider-LQHQX7Z7.js.map → sources-7LDYO5GK.js.map} +0 -0
  172. /package/dist/{provider-SXPQZ74H.js.map → state-25IQEC5C.js.map} +0 -0
  173. /package/dist/{rate-limiter-RLRVM325.js.map → telemetry-RS2JZUZP.js.map} +0 -0
  174. /package/dist/{sessions-CZGVXKQE.js.map → tool-executor-6I5PHQDY.js.map} +0 -0
  175. /package/dist/{sources-RW5DT56F.js.map → tools-NDFJNVHK.js.map} +0 -0
  176. /package/dist/{state-GMXILIHW.js.map → types-NPJZAI72.js.map} +0 -0
  177. /package/dist/{telemetry-UC6PBXC7.js.map → validator-LM7RZWSH.js.map} +0 -0
  178. /package/dist/{tool-executor-MJ7IG7PQ.js.map → web-server-2Y4CHD2W.js.map} +0 -0
package/README.md CHANGED
@@ -1,16 +1,82 @@
1
1
  # Agent Harness
2
2
 
3
- > **The first agent framework where the agent gets measurably better as you use it. You write markdown, not code. Tools come from MCP.**
3
+ > **A self-managing, self-improving agent runtime. Point it at a problem, write what it should know in markdown, and watch it get better as you use it.**
4
4
 
5
- Agent Harness is a file-first framework for building agents by editing markdown. It's designed for anyone who wants to build an agent in 2026 coder or non-coder and its differentiator is a built-in learning loop: every interaction is journaled, patterns become instincts, and the agent improves without retraining or fine-tuning.
5
+ Agent Harness is the layer between "I have an LLM API key" and "I have a working agent that does useful work." It handles identity, memory, tools, context budgeting, session capture, journal synthesis, instinct learning, progressive disclosure, and MCP integration so you can describe the problem in markdown instead of wiring up 500 lines of TypeScript.
6
6
 
7
- The code layer exists as an escape hatch, not the entry point. The folder IS the agent.
7
+ **Who this is for**: anyone technical or semi-technical who has a repeating problem they want an agent to own. Writers, founders, ops people, researchers, developers, consultants, analysts. If you can describe what you want in a document, you can build an agent for it.
8
+
9
+ ## What makes it different
10
+
11
+ Most agent frameworks give you a box of parts and leave the rest to you. agent-harness gives you a runtime that does three things nobody else does:
12
+
13
+ ### 1. It manages itself
14
+ The harness handles its own upkeep automatically:
15
+ - **Context budget**: three disclosure levels (L0/L1/L2) loaded intelligently so you never hit the token ceiling
16
+ - **Session capture**: every interaction is recorded without asking
17
+ - **Journal synthesis**: run `harness journal` and the agent writes its own daily reflection
18
+ - **Dead primitive detection**: orphan files get flagged, contradictions get surfaced
19
+ - **Format auto-repair**: `harness doctor` fixes missing frontmatter, tags, and summaries
20
+ - **Scaffold validation**: primitives are checked for consistency on every load
21
+
22
+ You don't prune files, check token counts, or write cleanup scripts. The harness does its own housekeeping.
23
+
24
+ ### 2. It learns from itself
25
+ The headline feature, and the one nobody else has shipped in a working form:
26
+
27
+ ```
28
+ Interaction → Session → Journal → Instinct proposed → Auto-installed → Behavior changes
29
+ ```
30
+
31
+ 1. Every `harness run` is saved as a session.
32
+ 2. `harness journal` synthesizes the day's sessions and finds patterns across them.
33
+ 3. `harness learn --install` promotes patterns to **instincts** — behavioral rules written to disk with full provenance ("learned from session X because you kept doing Y").
34
+ 4. On the next run, the agent loads the new instincts and **actually behaves differently**.
35
+
36
+ No retraining. No fine-tuning. No tokenization. You use the agent for a week and it measurably improves, with an auditable trail of what changed and why. [Verified end-to-end against real LLM runs in v0.1.0+.](#the-learning-loop)
37
+
38
+ ### 3. It's pointable at any problem
39
+ The primitives (`rules/`, `skills/`, `playbooks/`, `instincts/`, `workflows/`, `tools/`, `agents/`) are domain-agnostic. The same harness layout handles:
40
+
41
+ - A research assistant that learns your writing style and source preferences
42
+ - An incident responder that composes runbooks from past resolutions
43
+ - A content marketer that learns what headlines your audience opens
44
+ - A personal planning agent that remembers how you make decisions
45
+ - A code review bot that encodes your team's review standards
46
+ - A customer support triage agent that learns from resolved tickets
47
+
48
+ You describe the problem in `CORE.md`, add a few `skills/` and `rules/`, point `config.yaml` at your LLM provider, and start using it. As you use it, the harness writes `instincts/` for you. Want to share with a teammate? Commit the folder to git.
49
+
50
+ ## Install
51
+
52
+ ```bash
53
+ npm install -g @agntk/agent-harness
54
+ harness init my-agent && cd my-agent
55
+ export OPENROUTER_API_KEY=sk-or-...
56
+ harness run "Help me decide between two options: A or B"
57
+ ```
58
+
59
+ That's it. No config file to wire up, no tool layer to build, no state store to provision. Your agent is the folder.
60
+
61
+ ## Why markdown (not code)
62
+
63
+ Writing an agent in TypeScript or Python couples the agent's behavior to your programming environment. Markdown decouples them completely:
64
+
65
+ - **Non-coders can author and edit** — if you can write a document, you can write a skill.
66
+ - **Content is greppable, diffable, reviewable** — normal PR workflows work on agent behavior.
67
+ - **The agent reads itself** — when you edit `skills/research.md`, the next run picks it up. No rebuild, no restart.
68
+ - **The harness can write back** — `harness learn` produces markdown files you can read and edit by hand before accepting them.
69
+ - **Portability** — the folder IS the agent. Share it by copying. Version it with git. Deploy it by tarring it.
70
+
71
+ agent-harness is a CLI, not a library. There is no `import { createAgent }` API to wire into a TypeScript app — the entire authoring surface is markdown files inside a harness directory and the `harness` command. If you need programmatic control, script the CLI from your shell or call `harness run` from any process spawn (subprocess, Lambda, GitHub Actions). The tool is the boundary, not a JavaScript module.
8
72
 
9
73
  ## Why this is different
10
74
 
11
- - **Self-learning by default**: every interaction is journaled, patterns become instincts, agents get measurably better with use no retraining, no fine-tuning.
12
- - **File-first authoring**: edit markdown, not code. The folder IS the agent.
13
- - **MCP-native tools**: the entire MCP ecosystem is your toolbox. No custom adapter layer.
75
+ - **Self-managing**: automatic context budgeting, session capture, format repair, dead-primitive detection, contradiction surfacing. Zero maintenance.
76
+ - **Self-learning**: every interaction becomes training data for the agent itself. Patterns become instincts. Behavior measurably changes over time. No retraining.
77
+ - **File-first authoring**: edit markdown, not code. The folder IS the agent. Non-coders can author; coders have escape hatches.
78
+ - **MCP-native tools**: the entire Model Context Protocol ecosystem is your toolbox. No custom adapter layer to build.
79
+ - **License-aware installation**: every `harness install <url>` records source, detects the license, and blocks proprietary content by default. Bundled content is traceable, auditable, and safe by default.
14
80
 
15
81
  ## Quick Start
16
82
 
@@ -163,6 +229,38 @@ harness sources list
163
229
 
164
230
  The installer auto-detects format (Claude Code skills, raw markdown, bash hooks, MCP configs) and normalizes to harness convention with proper frontmatter.
165
231
 
232
+ ### Automatic provenance + license safety
233
+
234
+ Every `harness install <url>` records where content came from and what license governs it:
235
+
236
+ ```yaml
237
+ # Auto-written into the installed file's frontmatter
238
+ source: https://raw.githubusercontent.com/owner/repo/main/skill.md
239
+ source_commit: 60af65e1d74303b965587f7d43ed7beb53e84d84
240
+ license: MIT
241
+ copyright: Copyright (c) 2024 Seth Hobson
242
+ license_source: https://github.com/owner/repo/blob/main/LICENSE
243
+ installed_at: '2026-04-08T13:50:09.623Z'
244
+ installed_by: agent-harness@0.1.5
245
+ ```
246
+
247
+ The detector checks per-file LICENSE siblings (catches repos where each subdirectory has its own proprietary LICENSE), then the repo-root LICENSE via the GitHub API, then the file's own frontmatter. Strictest finding wins.
248
+
249
+ **Proprietary content is blocked by default.** If a LICENSE says "all rights reserved" or the content is otherwise unlicensed, the install is refused with a clear error. Configure the policy in `config.yaml`:
250
+
251
+ ```yaml
252
+ install:
253
+ allowed_licenses: [MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, MPL-2.0, CC-BY-4.0, CC0-1.0, Unlicense]
254
+ on_unknown_license: warn # allow | warn | prompt | block
255
+ on_proprietary: block # never install without explicit override
256
+ ```
257
+
258
+ Override for one install when you have written permission:
259
+
260
+ ```bash
261
+ harness install <url> --force-license MIT
262
+ ```
263
+
166
264
  Share your own primitives as bundles:
167
265
 
168
266
  ```bash
@@ -325,43 +423,6 @@ harness dev --no-auto-process # Skip auto-processing
325
423
 
326
424
  The dashboard includes: agent status, health checks, spending, sessions, workflows, primitives browser, file editor, MCP status, settings editor, and a chat interface.
327
425
 
328
- ## Using as a Library
329
-
330
- ```typescript
331
- import { createHarness } from '@agntk/agent-harness';
332
-
333
- const agent = createHarness({
334
- dir: './my-agent',
335
- apiKey: process.env.OPENROUTER_API_KEY,
336
- });
337
-
338
- await agent.boot();
339
-
340
- // One-shot
341
- const result = await agent.run('What should I work on today?');
342
- console.log(result.text);
343
-
344
- // Streaming
345
- for await (const chunk of agent.stream('Explain this codebase')) {
346
- process.stdout.write(chunk);
347
- }
348
-
349
- await agent.shutdown();
350
- ```
351
-
352
- ### Fluent Builder API
353
-
354
- ```typescript
355
- import { defineAgent } from '@agntk/agent-harness';
356
-
357
- const agent = defineAgent('./my-agent')
358
- .model('anthropic/claude-sonnet-4')
359
- .provider('openrouter')
360
- .onBoot(({ config }) => console.log(`Booted ${config.agent.name}`))
361
- .onError(({ error }) => console.error(error))
362
- .build();
363
- ```
364
-
365
426
  ## Configuration
366
427
 
367
428
  `config.yaml`:
@@ -4,9 +4,8 @@ import {
4
4
  getSessionAnalytics,
5
5
  getSessionsInRange
6
6
  } from "./chunk-GNUSHD2Y.js";
7
- import "./chunk-ZZJOFKAT.js";
8
7
  export {
9
8
  getSessionAnalytics,
10
9
  getSessionsInRange
11
10
  };
12
- //# sourceMappingURL=analytics-RPT73WNM.js.map
11
+ //# sourceMappingURL=analytics-L24W3B7U.js.map
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {
4
+ autoProcessAll,
5
+ autoProcessFile
6
+ } from "./chunk-NVC2WY4K.js";
7
+ import "./chunk-4TQQZILG.js";
8
+ export {
9
+ autoProcessAll,
10
+ autoProcessFile
11
+ };
12
+ //# sourceMappingURL=auto-processor-QIRUOGEI.js.map
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  CORE_PRIMITIVE_DIRS,
5
5
  FrontmatterSchema
6
- } from "./chunk-4CWAGBNS.js";
6
+ } from "./chunk-4TQQZILG.js";
7
7
 
8
8
  // src/primitives/loader.ts
9
9
  import { readFileSync, readdirSync, existsSync } from "fs";
@@ -112,4 +112,4 @@ export {
112
112
  estimateTokens,
113
113
  getAtLevel
114
114
  };
115
- //# sourceMappingURL=chunk-UPLBF4RZ.js.map
115
+ //# sourceMappingURL=chunk-2UVWCTAY.js.map
@@ -2,14 +2,14 @@
2
2
 
3
3
  import {
4
4
  parseHarnessDocument
5
- } from "./chunk-UPLBF4RZ.js";
5
+ } from "./chunk-2UVWCTAY.js";
6
6
  import {
7
7
  generate,
8
8
  getModel
9
9
  } from "./chunk-IZ6UZ3ZL.js";
10
10
  import {
11
11
  loadConfig
12
- } from "./chunk-CHJ5GNZC.js";
12
+ } from "./chunk-EC42HQQH.js";
13
13
 
14
14
  // src/runtime/journal.ts
15
15
  import { readFileSync, writeFileSync, readdirSync, existsSync, mkdirSync } from "fs";
@@ -304,4 +304,4 @@ export {
304
304
  listJournals,
305
305
  compressJournals
306
306
  };
307
- //# sourceMappingURL=chunk-CSL3ERUI.js.map
307
+ //# sourceMappingURL=chunk-4P6TRFPZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/journal.ts"],"sourcesContent":["import { readFileSync, writeFileSync, readdirSync, existsSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { parseHarnessDocument } from '../primitives/loader.js';\nimport { getModel, generate } from '../llm/provider.js';\nimport { loadConfig } from '../core/config.js';\nimport type { HarnessDocument } from '../core/types.js';\n\nexport interface JournalSynthesis {\n summary: string;\n insights: string[];\n instinct_candidates: string[];\n knowledge_updates: string[];\n}\n\nexport interface JournalEntry {\n date: string;\n sessions: HarnessDocument[];\n synthesis: string;\n structured: JournalSynthesis;\n instinct_candidates: string[];\n tokens_used: number;\n}\n\nexport async function synthesizeJournal(\n harnessDir: string,\n date?: string,\n apiKey?: string,\n): Promise<JournalEntry> {\n const targetDate = date || new Date().toISOString().split('T')[0];\n const sessionsDir = join(harnessDir, 'memory', 'sessions');\n const journalDir = join(harnessDir, 'memory', 'journal');\n\n if (!existsSync(journalDir)) {\n mkdirSync(journalDir, { recursive: true });\n }\n\n // Load sessions for this date\n const sessions: HarnessDocument[] = [];\n if (existsSync(sessionsDir)) {\n const files = readdirSync(sessionsDir).filter(\n (f) => f.endsWith('.md') && f.startsWith(targetDate),\n );\n\n for (const file of files) {\n try {\n const doc = parseHarnessDocument(join(sessionsDir, file));\n sessions.push(doc);\n } catch {\n // Skip unparseable\n }\n }\n }\n\n if (sessions.length === 0) {\n return {\n date: targetDate,\n sessions: [],\n synthesis: 'No sessions recorded today.',\n structured: {\n summary: 'No sessions recorded today.',\n insights: [],\n instinct_candidates: [],\n knowledge_updates: [],\n },\n instinct_candidates: [],\n tokens_used: 0,\n };\n }\n\n // Build synthesis prompt\n const sessionSummaries = sessions\n .map((s, i) => {\n const prompt = s.body.match(/## Prompt\\n([\\s\\S]*?)(?=\\n## |$)/)?.[1]?.trim() || '';\n const summary = s.body.match(/## Summary\\n([\\s\\S]*?)(?=\\n## |$)/)?.[1]?.trim() || '';\n return `Session ${i + 1}:\\n Prompt: ${prompt}\\n Summary: ${summary}`;\n })\n .join('\\n\\n');\n\n const synthesisPrompt = `You are synthesizing today's agent sessions into a structured journal entry.\n\nSessions from ${targetDate}:\n\n${sessionSummaries}\n\nWrite a journal entry with these EXACT sections (use the exact headers shown):\n\n## Summary\n2-3 sentence synthesis of what happened today.\n\n## Insights\nBullet points (starting with \"- \") of patterns, recurring themes, or notable observations.\n\n## Instinct Candidates\nBullet points (starting with \"- INSTINCT: \") of behaviors that should become reflexive rules.\n\n## Knowledge Updates\nBullet points (starting with \"- \") of new facts, corrections, or learnings that should be remembered.`;\n\n const config = loadConfig(harnessDir);\n const model = getModel(config, apiKey);\n\n const result = await generate({\n model,\n system: 'You are a reflective journal synthesizer. Be concise and insightful. Follow the output format exactly.',\n prompt: synthesisPrompt,\n });\n\n // Parse structured sections from the response\n const structured = parseJournalSynthesis(result.text);\n\n // Write journal entry\n const journalPath = join(journalDir, `${targetDate}.md`);\n const journalContent = `---\nid: journal-${targetDate}\ntags: [journal, daily]\ncreated: ${targetDate}\nupdated: ${new Date().toISOString().split('T')[0]}\nauthor: infrastructure\nstatus: active\n---\n\n<!-- L0: Journal for ${targetDate} — ${sessions.length} sessions synthesized. -->\n<!-- L1: ${structured.summary.slice(0, 200)} -->\n\n# Journal: ${targetDate}\n\n**Sessions:** ${sessions.length}\n**Tokens used:** ${result.usage.totalTokens}\n\n${result.text}\n`;\n\n writeFileSync(journalPath, journalContent, 'utf-8');\n\n return {\n date: targetDate,\n sessions,\n synthesis: result.text,\n structured,\n instinct_candidates: structured.instinct_candidates,\n tokens_used: result.usage.totalTokens,\n };\n}\n\n/**\n * Parse a journal synthesis response into structured sections.\n * Resilient to missing sections — returns empty arrays/strings for missing parts.\n */\nexport function parseJournalSynthesis(text: string): JournalSynthesis {\n const sectionRegex = /## (Summary|Insights|Instinct Candidates|Knowledge Updates|Patterns)\\n([\\s\\S]*?)(?=\\n## |\\n*$)/g;\n const sections = new Map<string, string>();\n\n for (const match of text.matchAll(sectionRegex)) {\n sections.set(match[1].toLowerCase(), match[2].trim());\n }\n\n const extractBullets = (content: string | undefined): string[] => {\n if (!content) return [];\n return content\n .split('\\n')\n .filter((line) => line.startsWith('- '))\n .map((line) => line.slice(2).trim())\n .filter(Boolean);\n };\n\n const summary = sections.get('summary') ?? '';\n\n // \"Insights\" or legacy \"Patterns\" section\n const insightsRaw = sections.get('insights') ?? sections.get('patterns') ?? '';\n const insights = extractBullets(insightsRaw);\n\n // Extract instinct candidates, stripping \"INSTINCT:\" prefix\n const instinctRaw = sections.get('instinct candidates') ?? '';\n const instinct_candidates = extractBullets(instinctRaw).map((line) =>\n line.replace(/^INSTINCT:\\s*/i, ''),\n );\n\n const knowledgeRaw = sections.get('knowledge updates') ?? '';\n const knowledge_updates = extractBullets(knowledgeRaw);\n\n return { summary, insights, instinct_candidates, knowledge_updates };\n}\n\n/**\n * Synthesize journals for a date range.\n * Processes each date that has sessions, skipping dates already journaled unless force is set.\n */\nexport async function synthesizeJournalRange(\n harnessDir: string,\n options: { from?: string; to?: string; all?: boolean; force?: boolean; apiKey?: string },\n): Promise<JournalEntry[]> {\n const sessionsDir = join(harnessDir, 'memory', 'sessions');\n if (!existsSync(sessionsDir)) return [];\n\n // Collect all unique dates from session filenames\n const files = readdirSync(sessionsDir).filter(\n (f) => f.endsWith('.md') && !f.startsWith('.') && !f.startsWith('_'),\n );\n const dateSet = new Set<string>();\n for (const file of files) {\n const match = file.match(/^(\\d{4}-\\d{2}-\\d{2})/);\n if (match) dateSet.add(match[1]);\n }\n\n let dates = [...dateSet].sort();\n\n // Apply range filters\n if (!options.all) {\n const from = options.from;\n const to = options.to || new Date().toISOString().split('T')[0];\n if (from) {\n dates = dates.filter((d) => d >= from && d <= to);\n }\n }\n\n if (dates.length === 0) return [];\n\n // Check which dates already have journals\n const journalDir = join(harnessDir, 'memory', 'journal');\n const existingJournals = new Set<string>();\n if (existsSync(journalDir)) {\n for (const jf of readdirSync(journalDir)) {\n const match = jf.match(/^(\\d{4}-\\d{2}-\\d{2})/);\n if (match) existingJournals.add(match[1]);\n }\n }\n\n const entries: JournalEntry[] = [];\n for (const date of dates) {\n if (!options.force && existingJournals.has(date)) continue;\n\n const entry = await synthesizeJournal(harnessDir, date, options.apiKey);\n entries.push(entry);\n }\n\n return entries;\n}\n\n/**\n * List dates that have sessions but no journal entry.\n */\nexport function listUnjournaled(harnessDir: string): string[] {\n const sessionsDir = join(harnessDir, 'memory', 'sessions');\n if (!existsSync(sessionsDir)) return [];\n\n const sessionDates = new Set<string>();\n for (const file of readdirSync(sessionsDir)) {\n if (!file.endsWith('.md') || file.startsWith('.')) continue;\n const match = file.match(/^(\\d{4}-\\d{2}-\\d{2})/);\n if (match) sessionDates.add(match[1]);\n }\n\n const journalDir = join(harnessDir, 'memory', 'journal');\n const journalDates = new Set<string>();\n if (existsSync(journalDir)) {\n for (const file of readdirSync(journalDir)) {\n const match = file.match(/^(\\d{4}-\\d{2}-\\d{2})/);\n if (match) journalDates.add(match[1]);\n }\n }\n\n return [...sessionDates].filter((d) => !journalDates.has(d)).sort();\n}\n\nexport function listJournals(harnessDir: string): string[] {\n const journalDir = join(harnessDir, 'memory', 'journal');\n if (!existsSync(journalDir)) return [];\n\n return readdirSync(journalDir)\n .filter((f) => f.endsWith('.md') && !f.startsWith('.'))\n .sort()\n .reverse();\n}\n\nexport interface WeekSummary {\n weekStart: string;\n weekEnd: string;\n journalDates: string[];\n summary: string;\n allInsights: string[];\n allInstinctCandidates: string[];\n allKnowledgeUpdates: string[];\n filePath: string;\n}\n\n/**\n * Get the Monday of the ISO week for a given date string (YYYY-MM-DD).\n */\nfunction getWeekStart(dateStr: string): string {\n const date = new Date(dateStr + 'T12:00:00Z');\n const day = date.getUTCDay();\n const diff = day === 0 ? 6 : day - 1;\n date.setUTCDate(date.getUTCDate() - diff);\n return date.toISOString().split('T')[0];\n}\n\n/**\n * Get the Sunday of the ISO week for a given date string.\n */\nfunction getWeekEnd(dateStr: string): string {\n const start = new Date(getWeekStart(dateStr) + 'T12:00:00Z');\n start.setUTCDate(start.getUTCDate() + 6);\n return start.toISOString().split('T')[0];\n}\n\n/**\n * Compress daily journals into weekly roll-up summaries.\n * Groups journals by ISO week, aggregates structured sections, writes\n * weekly summary files to memory/journal/weekly/. Pure file-based — no LLM calls.\n *\n * Returns only weeks that were newly created (skips existing unless force=true).\n */\nexport function compressJournals(\n harnessDir: string,\n options?: { force?: boolean },\n): WeekSummary[] {\n const journalDir = join(harnessDir, 'memory', 'journal');\n if (!existsSync(journalDir)) return [];\n\n const weeklyDir = join(journalDir, 'weekly');\n if (!existsSync(weeklyDir)) {\n mkdirSync(weeklyDir, { recursive: true });\n }\n\n // Load all daily journals\n const files = readdirSync(journalDir)\n .filter((f) => f.endsWith('.md') && !f.startsWith('.') && !f.startsWith('_'))\n .sort();\n\n // Group by week\n const weeks = new Map<string, string[]>();\n for (const file of files) {\n const dateMatch = file.match(/^(\\d{4}-\\d{2}-\\d{2})/);\n if (!dateMatch) continue;\n const weekStart = getWeekStart(dateMatch[1]);\n if (!weeks.has(weekStart)) weeks.set(weekStart, []);\n weeks.get(weekStart)!.push(file);\n }\n\n const results: WeekSummary[] = [];\n\n for (const [weekStart, journalFiles] of weeks) {\n const weekEnd = getWeekEnd(weekStart);\n const weeklyFile = join(weeklyDir, `${weekStart}.md`);\n\n // Skip existing unless force\n if (!options?.force && existsSync(weeklyFile)) continue;\n\n // Only compress complete past weeks (not the current week)\n const today = new Date().toISOString().split('T')[0];\n const currentWeekStart = getWeekStart(today);\n if (weekStart === currentWeekStart) continue;\n\n // Aggregate structured sections from each journal\n const allSummaries: string[] = [];\n const allInsights: string[] = [];\n const allInstinctCandidates: string[] = [];\n const allKnowledgeUpdates: string[] = [];\n const journalDates: string[] = [];\n\n for (const file of journalFiles) {\n const content = readFileSync(join(journalDir, file), 'utf-8');\n const dateMatch = file.match(/^(\\d{4}-\\d{2}-\\d{2})/);\n if (dateMatch) journalDates.push(dateMatch[1]);\n\n const structured = parseJournalSynthesis(content);\n if (structured.summary) allSummaries.push(`**${dateMatch?.[1]}:** ${structured.summary}`);\n allInsights.push(...structured.insights);\n allInstinctCandidates.push(...structured.instinct_candidates);\n allKnowledgeUpdates.push(...structured.knowledge_updates);\n }\n\n // Deduplicate\n const uniqueInsights = [...new Set(allInsights)];\n const uniqueInstincts = [...new Set(allInstinctCandidates)];\n const uniqueKnowledge = [...new Set(allKnowledgeUpdates)];\n\n const weekSummary = allSummaries.join('\\n\\n');\n const insightsBullets = uniqueInsights.map((i) => `- ${i}`).join('\\n');\n const instinctBullets = uniqueInstincts.map((i) => `- INSTINCT: ${i}`).join('\\n');\n const knowledgeBullets = uniqueKnowledge.map((k) => `- ${k}`).join('\\n');\n\n const weeklyContent = `---\nid: weekly-${weekStart}\ntags: [journal, weekly]\ncreated: ${weekStart}\nupdated: ${new Date().toISOString().split('T')[0]}\nauthor: infrastructure\nstatus: active\n---\n\n<!-- L0: Weekly journal roll-up ${weekStart} to ${weekEnd} (${journalDates.length} days) -->\n<!-- L1: ${allSummaries[0]?.slice(0, 200) || 'No summaries available'} -->\n\n# Weekly Journal: ${weekStart} to ${weekEnd}\n\n**Days journaled:** ${journalDates.length}\n**Dates:** ${journalDates.join(', ')}\n\n## Summary\n${weekSummary || 'No daily summaries available.'}\n\n## Insights\n${insightsBullets || '(none)'}\n\n## Instinct Candidates\n${instinctBullets || '(none)'}\n\n## Knowledge Updates\n${knowledgeBullets || '(none)'}\n`;\n\n writeFileSync(weeklyFile, weeklyContent, 'utf-8');\n\n results.push({\n weekStart,\n weekEnd,\n journalDates,\n summary: weekSummary,\n allInsights: uniqueInsights,\n allInstinctCandidates: uniqueInstincts,\n allKnowledgeUpdates: uniqueKnowledge,\n filePath: weeklyFile,\n });\n }\n\n return results;\n}\n"],"mappings":"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","names":[]}
@@ -124,7 +124,62 @@ var HarnessConfigSchema = z.object({
124
124
  name: z.string().optional(),
125
125
  /** Optional auth token for private registries */
126
126
  token: z.string().optional()
127
- }).passthrough()).default([])
127
+ }).passthrough()).default([]),
128
+ /**
129
+ * License policy for `harness install <url>`. Controls how the universal
130
+ * installer reacts to the license detected on a fetched primitive (Level 3
131
+ * of task 12.14). Detection itself runs unconditionally — this only governs
132
+ * what happens after the license is determined.
133
+ */
134
+ install: z.object({
135
+ /**
136
+ * SPDX ids the installer accepts without warning. Permissive defaults
137
+ * cover the OSI-approved ecosystem most users care about. Add or remove
138
+ * here to tighten or loosen the policy.
139
+ */
140
+ allowed_licenses: z.array(z.string()).default([
141
+ "MIT",
142
+ "Apache-2.0",
143
+ "BSD-2-Clause",
144
+ "BSD-3-Clause",
145
+ "ISC",
146
+ "MPL-2.0",
147
+ "CC-BY-4.0",
148
+ "CC0-1.0",
149
+ "Unlicense"
150
+ ]),
151
+ /**
152
+ * What to do when the detected license is not in `allowed_licenses` and
153
+ * is not classified as PROPRIETARY. Includes the UNKNOWN case (no LICENSE
154
+ * file found anywhere) and any non-permissive SPDX id like GPL-3.0.
155
+ *
156
+ * - allow: install silently (legacy v0.1.3 behavior — safest for migration)
157
+ * - warn: install with a stderr warning naming the license_source
158
+ * - prompt: ask Y/n on TTY; treats non-TTY as `block`
159
+ * - block: refuse the install with an error showing the override flag
160
+ */
161
+ on_unknown_license: z.enum(["allow", "warn", "prompt", "block"]).default("warn"),
162
+ /**
163
+ * What to do when the detected license is PROPRIETARY (text contains
164
+ * "all rights reserved" or no permission grant). Defaults to `block`
165
+ * because shipping proprietary content was the v0.1.0 yank cause.
166
+ */
167
+ on_proprietary: z.enum(["allow", "warn", "prompt", "block"]).default("block")
168
+ }).passthrough().default({
169
+ allowed_licenses: [
170
+ "MIT",
171
+ "Apache-2.0",
172
+ "BSD-2-Clause",
173
+ "BSD-3-Clause",
174
+ "ISC",
175
+ "MPL-2.0",
176
+ "CC-BY-4.0",
177
+ "CC0-1.0",
178
+ "Unlicense"
179
+ ],
180
+ on_unknown_license: "warn",
181
+ on_proprietary: "block"
182
+ })
128
183
  }).passthrough();
129
184
  var CONFIG_DEFAULTS = {
130
185
  agent: { name: "agent", version: "0.1.0" },
@@ -143,7 +198,22 @@ var CONFIG_DEFAULTS = {
143
198
  intelligence: { auto_journal: false, auto_learn: false },
144
199
  proactive: { enabled: false, max_per_hour: 5, cooldown_minutes: 30 },
145
200
  mcp: { servers: {} },
146
- registries: []
201
+ registries: [],
202
+ install: {
203
+ allowed_licenses: [
204
+ "MIT",
205
+ "Apache-2.0",
206
+ "BSD-2-Clause",
207
+ "BSD-3-Clause",
208
+ "ISC",
209
+ "MPL-2.0",
210
+ "CC-BY-4.0",
211
+ "CC0-1.0",
212
+ "Unlicense"
213
+ ],
214
+ on_unknown_license: "warn",
215
+ on_proprietary: "block"
216
+ }
147
217
  };
148
218
  var CORE_PRIMITIVE_DIRS = ["rules", "instincts", "skills", "playbooks", "workflows", "tools", "agents"];
149
219
  function getPrimitiveDirs(config) {
@@ -165,4 +235,4 @@ export {
165
235
  CORE_PRIMITIVE_DIRS,
166
236
  getPrimitiveDirs
167
237
  };
168
- //# sourceMappingURL=chunk-4CWAGBNS.js.map
238
+ //# sourceMappingURL=chunk-4TQQZILG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/types.ts"],"sourcesContent":["import { z } from 'zod';\n\n// --- Frontmatter ---\nexport const FrontmatterSchema = z.object({\n id: z.string(),\n tags: z.array(z.string()).default([]),\n created: z.string().optional(),\n updated: z.string().optional(),\n author: z.enum(['human', 'agent', 'infrastructure']).default('human'),\n status: z.enum(['active', 'archived', 'deprecated', 'draft']).default('active'),\n related: z.array(z.string()).default([]),\n schedule: z.string().optional(),\n with: z.string().optional(),\n channel: z.string().optional(),\n duration_minutes: z.number().optional(),\n max_retries: z.number().int().nonnegative().optional(),\n retry_delay_ms: z.number().int().positive().optional(),\n});\n\nexport type Frontmatter = z.infer<typeof FrontmatterSchema>;\n\n// --- Primitive Document ---\nexport interface HarnessDocument {\n path: string;\n frontmatter: Frontmatter;\n l0: string;\n l1: string;\n body: string;\n raw: string;\n}\n\n// --- Primitive Types ---\nexport type PrimitiveType =\n | 'rule'\n | 'instinct'\n | 'skill'\n | 'playbook'\n | 'workflow'\n | 'tool'\n | 'agent'\n | 'session'\n | 'journal';\n\nexport interface Primitive {\n type: PrimitiveType;\n doc: HarnessDocument;\n}\n\n// --- Config ---\nexport const HarnessConfigSchema = z.object({\n agent: z.object({\n name: z.string().min(1),\n version: z.string().default('0.1.0'),\n }).passthrough(),\n model: z.object({\n provider: z.string().default('openrouter'),\n id: z.string().min(1),\n max_tokens: z.number().int().positive().default(200000),\n max_retries: z.number().int().nonnegative().default(2),\n timeout_ms: z.number().int().positive().optional(),\n /** Cheap model for auto-generating summaries, tags, frontmatter (e.g. 'google/gemini-flash-1.5') */\n summary_model: z.string().optional(),\n /** Fast model for validation, checks, and quick decisions (e.g. 'google/gemini-flash-1.5') */\n fast_model: z.string().optional(),\n }).passthrough(),\n runtime: z.object({\n scratchpad_budget: z.number().int().nonnegative().default(10000),\n /** Reserved: cron expression for periodic heartbeat check (not yet implemented) */\n heartbeat: z.string().optional(),\n /** Reserved: cron expression for daily summary generation (not yet implemented) */\n daily_summary: z.string().optional(),\n /** Auto-process primitives on save: generate frontmatter, L0/L1 summaries (default: true) */\n auto_process: z.boolean().default(true),\n quiet_hours: z.object({\n start: z.number().int().min(0).max(23).default(23),\n end: z.number().int().min(0).max(23).default(6),\n }).passthrough().default({ start: 23, end: 6 }),\n timezone: z.string().default('America/New_York'),\n }).passthrough(),\n memory: z.object({\n session_retention_days: z.number().int().positive().default(7),\n journal_retention_days: z.number().int().positive().default(365),\n }).passthrough(),\n channels: z.object({\n primary: z.string().default('cli'),\n }).passthrough(),\n extensions: z.object({\n directories: z.array(z.string()).default([]),\n }).passthrough().default({ directories: [] }),\n rate_limits: z.object({\n /** Max LLM calls per minute (default: unlimited) */\n per_minute: z.number().int().positive().optional(),\n /** Max LLM calls per hour (default: unlimited) */\n per_hour: z.number().int().positive().optional(),\n /** Max LLM calls per day (default: unlimited) */\n per_day: z.number().int().positive().optional(),\n }).passthrough().default({}),\n budget: z.object({\n /** Max daily spend in USD (default: unlimited) */\n daily_limit_usd: z.number().positive().optional(),\n /** Max monthly spend in USD (default: unlimited) */\n monthly_limit_usd: z.number().positive().optional(),\n /** Block runs when budget exceeded (default: true) */\n enforce: z.boolean().default(true),\n }).passthrough().default({ enforce: true }),\n mcp: z.object({\n /** MCP server definitions keyed by server name */\n servers: z.record(z.string(), z.object({\n /** Transport type: 'stdio' for local processes, 'http' for remote, 'sse' for SSE */\n transport: z.enum(['stdio', 'http', 'sse']),\n /** Command to spawn (stdio transport only) */\n command: z.string().optional(),\n /** Command arguments (stdio transport only) */\n args: z.array(z.string()).optional(),\n /** Environment variables for the spawned process (stdio transport only) */\n env: z.record(z.string(), z.string()).optional(),\n /** Working directory for the spawned process (stdio transport only) */\n cwd: z.string().optional(),\n /** URL endpoint (http/sse transport only) */\n url: z.string().optional(),\n /** Additional HTTP headers (http/sse transport only) */\n headers: z.record(z.string(), z.string()).optional(),\n /** Whether this server is enabled (default: true) */\n enabled: z.boolean().default(true),\n }).passthrough()).default({}),\n }).passthrough().default({ servers: {} }),\n /** Intelligence & continuous learning config */\n intelligence: z.object({\n /** Auto-run journal synthesis on a cron schedule (default: off). Set to cron string e.g. \"0 22 * * *\" or true for default \"0 22 * * *\". */\n auto_journal: z.union([z.boolean(), z.string()]).default(false),\n /** Auto-run instinct learning after journal synthesis (default: off) */\n auto_learn: z.boolean().default(false),\n }).passthrough().default({ auto_journal: false, auto_learn: false }),\n /** Proactive execution config (scheduler rate-limiting) */\n proactive: z.object({\n /** Enable proactive scheduled workflows (default: false) */\n enabled: z.boolean().default(false),\n /** Max proactive workflow executions per hour (default: 5) */\n max_per_hour: z.number().int().positive().default(5),\n /** Cooldown in minutes between proactive runs of the same workflow (default: 30) */\n cooldown_minutes: z.number().int().nonnegative().default(30),\n /** Override quiet hours for proactive execution (start/end hours, inherits runtime.quiet_hours if not set) */\n quiet_hours: z.object({\n start: z.number().int().min(0).max(23).optional(),\n end: z.number().int().min(0).max(23).optional(),\n }).passthrough().optional(),\n }).passthrough().default({ enabled: false, max_per_hour: 5, cooldown_minutes: 30 }),\n /** Primitive bundle registries for search/install */\n registries: z.array(z.object({\n /** Registry URL (HTTPS endpoint) */\n url: z.string().url(),\n /** Optional display name */\n name: z.string().optional(),\n /** Optional auth token for private registries */\n token: z.string().optional(),\n }).passthrough()).default([]),\n /**\n * License policy for `harness install <url>`. Controls how the universal\n * installer reacts to the license detected on a fetched primitive (Level 3\n * of task 12.14). Detection itself runs unconditionally — this only governs\n * what happens after the license is determined.\n */\n install: z.object({\n /**\n * SPDX ids the installer accepts without warning. Permissive defaults\n * cover the OSI-approved ecosystem most users care about. Add or remove\n * here to tighten or loosen the policy.\n */\n allowed_licenses: z.array(z.string()).default([\n 'MIT',\n 'Apache-2.0',\n 'BSD-2-Clause',\n 'BSD-3-Clause',\n 'ISC',\n 'MPL-2.0',\n 'CC-BY-4.0',\n 'CC0-1.0',\n 'Unlicense',\n ]),\n /**\n * What to do when the detected license is not in `allowed_licenses` and\n * is not classified as PROPRIETARY. Includes the UNKNOWN case (no LICENSE\n * file found anywhere) and any non-permissive SPDX id like GPL-3.0.\n *\n * - allow: install silently (legacy v0.1.3 behavior — safest for migration)\n * - warn: install with a stderr warning naming the license_source\n * - prompt: ask Y/n on TTY; treats non-TTY as `block`\n * - block: refuse the install with an error showing the override flag\n */\n on_unknown_license: z.enum(['allow', 'warn', 'prompt', 'block']).default('warn'),\n /**\n * What to do when the detected license is PROPRIETARY (text contains\n * \"all rights reserved\" or no permission grant). Defaults to `block`\n * because shipping proprietary content was the v0.1.0 yank cause.\n */\n on_proprietary: z.enum(['allow', 'warn', 'prompt', 'block']).default('block'),\n }).passthrough().default({\n allowed_licenses: [\n 'MIT',\n 'Apache-2.0',\n 'BSD-2-Clause',\n 'BSD-3-Clause',\n 'ISC',\n 'MPL-2.0',\n 'CC-BY-4.0',\n 'CC0-1.0',\n 'Unlicense',\n ],\n on_unknown_license: 'warn',\n on_proprietary: 'block',\n }),\n}).passthrough();\n\nexport type HarnessConfig = z.infer<typeof HarnessConfigSchema>;\n\nexport const CONFIG_DEFAULTS: HarnessConfig = {\n agent: { name: 'agent', version: '0.1.0' },\n model: { provider: 'openrouter', id: 'anthropic/claude-sonnet-4', max_tokens: 200000, max_retries: 2 },\n runtime: {\n scratchpad_budget: 10000,\n auto_process: true,\n quiet_hours: { start: 23, end: 6 },\n timezone: 'America/New_York',\n },\n memory: { session_retention_days: 7, journal_retention_days: 365 },\n channels: { primary: 'cli' },\n extensions: { directories: [] },\n rate_limits: {},\n budget: { enforce: true },\n intelligence: { auto_journal: false, auto_learn: false },\n proactive: { enabled: false, max_per_hour: 5, cooldown_minutes: 30 },\n mcp: { servers: {} },\n registries: [],\n install: {\n allowed_licenses: [\n 'MIT',\n 'Apache-2.0',\n 'BSD-2-Clause',\n 'BSD-3-Clause',\n 'ISC',\n 'MPL-2.0',\n 'CC-BY-4.0',\n 'CC0-1.0',\n 'Unlicense',\n ],\n on_unknown_license: 'warn',\n on_proprietary: 'block',\n },\n};\n\nexport const CORE_PRIMITIVE_DIRS = ['rules', 'instincts', 'skills', 'playbooks', 'workflows', 'tools', 'agents'] as const;\n\nexport function getPrimitiveDirs(config?: HarnessConfig): string[] {\n const dirs: string[] = [...CORE_PRIMITIVE_DIRS];\n if (config?.extensions?.directories) {\n for (const dir of config.extensions.directories) {\n if (!dirs.includes(dir)) {\n dirs.push(dir);\n }\n }\n }\n return dirs;\n}\n\n// --- Agent State ---\nexport interface AgentState {\n mode: string;\n goals: string[];\n active_workflows: string[];\n last_interaction: string;\n unfinished_business: string[];\n}\n\n// --- Context Budget ---\nexport interface ContextBudget {\n max_tokens: number;\n used_tokens: number;\n remaining: number;\n loaded_files: string[];\n}\n\n// --- Utility Types ---\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];\n};\n\n// --- Lifecycle Hooks ---\nexport interface HarnessHooks {\n /** Called after boot completes (context loaded, state ready) */\n onBoot?: (context: { agent: HarnessAgent; config: HarnessConfig; state: AgentState }) => void | Promise<void>;\n /** Called after each session completes (run or stream) */\n onSessionEnd?: (context: { agent: HarnessAgent; sessionId: string; prompt: string; result: AgentRunResult }) => void | Promise<void>;\n /** Called when an error occurs during run/stream */\n onError?: (context: { agent: HarnessAgent; error: Error; prompt?: string }) => void | Promise<void>;\n /** Called when agent state changes (boot, shutdown, after run) */\n onStateChange?: (context: { agent: HarnessAgent; previous: string; current: string }) => void | Promise<void>;\n /** Called before shutdown completes */\n onShutdown?: (context: { agent: HarnessAgent; state: AgentState }) => void | Promise<void>;\n}\n\n// --- Tool Executor Config (inline to avoid circular deps) ---\nexport interface ToolExecutorOptions {\n /** Maximum tool calls per run (default: 5) */\n maxToolCalls?: number;\n /** Timeout per tool call in ms (default: 30000) */\n toolTimeoutMs?: number;\n /** Whether to allow HTTP tool execution (default: true) */\n allowHttpExecution?: boolean;\n}\n\n// --- Agent Options (programmatic API) ---\nexport interface CreateHarnessOptions {\n dir: string;\n /** Model ID override (e.g., \"claude-sonnet-4-20250514\" or \"gpt-4o\") */\n model?: string;\n /** Provider override (e.g., \"anthropic\", \"openai\", \"openrouter\") */\n provider?: string;\n apiKey?: string;\n config?: DeepPartial<HarnessConfig>;\n /** Lifecycle hooks for agent events */\n hooks?: HarnessHooks;\n /** Tool execution configuration */\n toolExecutor?: ToolExecutorOptions;\n}\n\n/** Record of a single tool call made during a run */\nexport interface ToolCallInfo {\n toolName: string;\n args: Record<string, unknown>;\n result: unknown;\n}\n\n// --- Agent Interface ---\nexport interface AgentRunResult {\n text: string;\n usage: { inputTokens: number; outputTokens: number; totalTokens: number };\n session_id: string;\n steps: number;\n /** Tool calls made during the run (empty array if none) */\n toolCalls: ToolCallInfo[];\n}\n\nexport interface AgentStreamResult {\n /** Async iterable of text chunks — consume with for-await */\n textStream: AsyncIterable<string>;\n /** Resolves after the stream is fully consumed with session metadata */\n result: Promise<AgentRunResult>;\n}\n\nexport interface HarnessAgent {\n name: string;\n config: HarnessConfig;\n boot(): Promise<void>;\n run(prompt: string): Promise<AgentRunResult>;\n stream(prompt: string): AgentStreamResult;\n shutdown(): Promise<void>;\n getSystemPrompt(): string;\n getState(): AgentState;\n}\n\n// --- Index Entry ---\nexport interface IndexEntry {\n id: string;\n path: string;\n tags: string[];\n l0: string;\n created: string;\n status: string;\n}\n"],"mappings":"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","names":[]}
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  loadTools
5
- } from "./chunk-XTBKL5BI.js";
5
+ } from "./chunk-PMFAYKBD.js";
6
6
  import {
7
7
  log
8
8
  } from "./chunk-BSKDOFRT.js";
@@ -226,4 +226,4 @@ export {
226
226
  createToolCallTracker,
227
227
  getToolSetSummary
228
228
  };
229
- //# sourceMappingURL=chunk-DA7IKHC4.js.map
229
+ //# sourceMappingURL=chunk-5CO5JTYT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/tool-executor.ts"],"sourcesContent":["import { tool as aiTool, jsonSchema, type ToolSet } from 'ai';\nimport { z } from 'zod';\nimport { loadTools, type ToolDefinition, type ToolOperation } from './tools.js';\nimport { log } from '../core/logger.js';\n\n// --- Types ---\n\n/** Result of a single tool execution */\nexport interface ToolCallResult {\n toolName: string;\n input: Record<string, unknown>;\n output: unknown;\n durationMs: number;\n error: string | null;\n}\n\n/** Record of all tool calls in a run (for session recording) */\nexport interface ToolCallRecord {\n calls: ToolCallResult[];\n totalDurationMs: number;\n}\n\n/** A programmatic tool definition (not from markdown) */\nexport interface ProgrammaticTool {\n name: string;\n description: string;\n inputSchema: z.ZodType;\n execute: (input: Record<string, unknown>) => Promise<unknown>;\n}\n\n/** Configuration for tool execution */\nexport interface ToolExecutorConfig {\n /** Maximum tool calls per run (default: 10) */\n maxToolCalls?: number;\n /** Timeout per tool call in ms (default: 30000) */\n toolTimeoutMs?: number;\n /** Whether to allow HTTP tool execution (default: true) */\n allowHttpExecution?: boolean;\n /** Additional programmatic tools */\n tools?: ProgrammaticTool[];\n}\n\n/** AI SDK ToolSet — record of named tool definitions */\nexport type AIToolSet = ToolSet;\n\n// --- HTTP Execution ---\n\n/**\n * Resolve a URL template by replacing `{param}` placeholders with input values.\n * E.g., `/repos/{owner}/{repo}/pulls` with { owner: 'a', repo: 'b' } → `/repos/a/b/pulls`\n */\nexport function resolveEndpoint(endpoint: string, input: Record<string, unknown>): string {\n return endpoint.replace(/\\{(\\w+)\\}/g, (_match, key: string) => {\n const value = input[key];\n if (value === undefined || value === null) {\n return `{${key}}`;\n }\n return encodeURIComponent(String(value));\n });\n}\n\n/**\n * Build a JSON Schema object for a tool operation's URL parameters.\n * Extracts `{param}` patterns from the endpoint URL and creates string properties for each.\n */\nexport function buildOperationSchema(operation: ToolOperation): Record<string, unknown> {\n const params: string[] = [];\n const paramRegex = /\\{(\\w+)\\}/g;\n let match: RegExpExecArray | null;\n while ((match = paramRegex.exec(operation.endpoint)) !== null) {\n params.push(match[1]);\n }\n\n const properties: Record<string, { type: string; description: string }> = {};\n for (const param of params) {\n properties[param] = { type: 'string', description: `Value for ${param}` };\n }\n\n // Add a body property for POST/PUT/PATCH\n if (['POST', 'PUT', 'PATCH'].includes(operation.method)) {\n properties['body'] = { type: 'string', description: 'Request body (JSON string)' };\n }\n\n // Add optional query parameters\n properties['query'] = { type: 'string', description: 'Query parameters (key=value&key2=value2)' };\n\n return {\n type: 'object',\n properties,\n required: params,\n };\n}\n\n/**\n * Execute an HTTP tool operation.\n * Resolves URL parameters, attaches auth headers, and makes the HTTP request.\n */\nexport async function executeHttpOperation(\n operation: ToolOperation,\n baseUrl: string,\n authHeaders: Record<string, string>,\n input: Record<string, unknown>,\n timeoutMs: number,\n): Promise<unknown> {\n const resolvedPath = resolveEndpoint(operation.endpoint, input);\n let url = resolvedPath.startsWith('http') ? resolvedPath : `${baseUrl}${resolvedPath}`;\n\n // Append query parameters if provided\n const query = input['query'];\n if (typeof query === 'string' && query.length > 0) {\n const separator = url.includes('?') ? '&' : '?';\n url = `${url}${separator}${query}`;\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json',\n ...authHeaders,\n };\n\n const fetchOptions: RequestInit = {\n method: operation.method,\n headers,\n signal: AbortSignal.timeout(timeoutMs),\n };\n\n // Attach body for methods that support it\n if (['POST', 'PUT', 'PATCH'].includes(operation.method)) {\n const body = input['body'];\n if (typeof body === 'string') {\n fetchOptions.body = body;\n } else if (body !== undefined && body !== null) {\n fetchOptions.body = JSON.stringify(body);\n }\n }\n\n const response = await fetch(url, fetchOptions);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(`HTTP ${response.status} ${response.statusText}: ${errorText.slice(0, 500)}`);\n }\n\n const contentType = response.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n return response.json() as Promise<unknown>;\n }\n return response.text();\n}\n\n// --- Tool Conversion ---\n\n/**\n * Sanitize a tool name for the AI SDK.\n * Tool names must be alphanumeric with underscores/hyphens only.\n */\nfunction sanitizeToolName(name: string): string {\n return name\n .replace(/[^a-zA-Z0-9_-]/g, '_')\n .replace(/_+/g, '_')\n .replace(/^_|_$/g, '')\n .slice(0, 64);\n}\n\n/**\n * Extract a base URL from the tool's operations or body.\n * Looks for full URLs in operations, or common API URL patterns in the body.\n */\nfunction extractBaseUrl(toolDef: ToolDefinition): string {\n // Check operations for full URLs\n for (const op of toolDef.operations) {\n if (op.endpoint.startsWith('http')) {\n try {\n const url = new URL(op.endpoint);\n return `${url.protocol}//${url.host}`;\n } catch {\n // not a valid URL\n }\n }\n }\n\n // Try to find API base URL in the document body\n const urlMatch = toolDef.doc.body.match(/(?:base[_ ]?url|api[_ ]?url|endpoint)\\s*[:=]\\s*`?(https?:\\/\\/[^\\s`\"']+)/i);\n if (urlMatch) {\n try {\n const url = new URL(urlMatch[1]);\n return `${url.protocol}//${url.host}`;\n } catch {\n // not a valid URL\n }\n }\n\n return '';\n}\n\n/**\n * Build auth headers from a tool's auth configuration.\n * Maps known env var patterns to standard header formats.\n */\nexport function buildAuthHeaders(toolDef: ToolDefinition): Record<string, string> {\n const headers: Record<string, string> = {};\n\n for (const auth of toolDef.auth) {\n const value = process.env[auth.envVar];\n if (!value) continue;\n\n // Common patterns for auth header mapping (check specific patterns first)\n const envLower = auth.envVar.toLowerCase();\n if (envLower.includes('bot_token')) {\n headers['Authorization'] = `Bot ${value}`;\n } else if (envLower.includes('token') || envLower.includes('api_key') || envLower.includes('apikey')) {\n headers['Authorization'] = `Bearer ${value}`;\n } else {\n // Generic: use as Bearer token\n headers['Authorization'] = `Bearer ${value}`;\n }\n }\n\n return headers;\n}\n\n/**\n * Convert a single ToolDefinition (from markdown) into AI SDK tools.\n * Each operation becomes a separate tool entry.\n */\nexport function convertToolDefinition(\n toolDef: ToolDefinition,\n config: ToolExecutorConfig,\n): AIToolSet {\n const tools: AIToolSet = {};\n const baseUrl = extractBaseUrl(toolDef);\n const allowHttp = config.allowHttpExecution !== false;\n const timeoutMs = config.toolTimeoutMs ?? 30_000;\n\n for (const operation of toolDef.operations) {\n const toolName = sanitizeToolName(`${toolDef.id}_${operation.name}`);\n const opSchema = buildOperationSchema(operation);\n\n tools[toolName] = aiTool({\n description: `[${toolDef.id}] ${operation.method} ${operation.endpoint} — ${toolDef.doc.l0}`,\n inputSchema: jsonSchema<Record<string, unknown>>(opSchema),\n execute: async (input) => {\n const typedInput = input;\n\n if (!allowHttp) {\n return { error: 'HTTP tool execution is disabled' };\n }\n\n // Check auth\n const missingAuth = toolDef.auth.filter((a) => !process.env[a.envVar]);\n if (missingAuth.length > 0) {\n return {\n error: `Missing required auth: ${missingAuth.map((a) => a.envVar).join(', ')}`,\n };\n }\n\n const authHeaders = buildAuthHeaders(toolDef);\n\n try {\n const result = await executeHttpOperation(\n operation,\n baseUrl,\n authHeaders,\n typedInput,\n timeoutMs,\n );\n return result;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n log.error(`Tool ${toolName} execution failed: ${message}`);\n return { error: message };\n }\n },\n });\n }\n\n return tools;\n}\n\n/**\n * Convert a programmatic tool definition into an AI SDK tool.\n */\nfunction convertProgrammaticTool(pt: ProgrammaticTool): AIToolSet {\n const toolName = sanitizeToolName(pt.name);\n\n return {\n [toolName]: aiTool({\n description: pt.description,\n inputSchema: pt.inputSchema,\n execute: async (input: unknown) => {\n try {\n return await pt.execute(input as Record<string, unknown>);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n log.error(`Tool ${toolName} execution failed: ${message}`);\n return { error: message };\n }\n },\n }),\n };\n}\n\n// --- Public API ---\n\n/**\n * Load all tools from the harness directory and convert them to AI SDK format.\n * Includes markdown-defined tools, programmatic tools from config, and MCP tools.\n *\n * Returns an empty object if no tools are configured.\n *\n * @param harnessDir - Path to the harness directory\n * @param config - Tool executor configuration\n * @param mcpTools - Pre-loaded MCP tools to merge (from McpManager.getTools())\n */\nexport function buildToolSet(\n harnessDir: string,\n config?: ToolExecutorConfig,\n mcpTools?: AIToolSet,\n): AIToolSet {\n const executorConfig = config ?? {};\n const tools: AIToolSet = {};\n\n // Load markdown-defined tools\n const toolDefs = loadTools(harnessDir);\n for (const toolDef of toolDefs) {\n // Skip inactive tools\n if (toolDef.status !== 'active') continue;\n\n // Skip tools without operations\n if (toolDef.operations.length === 0) continue;\n\n const converted = convertToolDefinition(toolDef, executorConfig);\n Object.assign(tools, converted);\n }\n\n // Add programmatic tools\n if (executorConfig.tools) {\n for (const pt of executorConfig.tools) {\n const converted = convertProgrammaticTool(pt);\n Object.assign(tools, converted);\n }\n }\n\n // Merge MCP tools (from connected MCP servers)\n if (mcpTools) {\n Object.assign(tools, mcpTools);\n }\n\n return tools;\n}\n\n/**\n * Create a ToolCallRecord tracker for recording tool calls in a run.\n */\nexport function createToolCallTracker(): {\n record: (result: ToolCallResult) => void;\n getRecord: () => ToolCallRecord;\n} {\n const calls: ToolCallResult[] = [];\n let totalDurationMs = 0;\n\n return {\n record(result: ToolCallResult) {\n calls.push(result);\n totalDurationMs += result.durationMs;\n },\n getRecord(): ToolCallRecord {\n return { calls: [...calls], totalDurationMs };\n },\n };\n}\n\n/**\n * Get a human-readable summary of tools available in the harness.\n */\nexport function getToolSetSummary(tools: AIToolSet): string[] {\n return Object.entries(tools).map(([name, t]) => {\n const desc = (t as { description?: string }).description ?? '';\n return `${name}: ${desc}`;\n });\n}\n"],"mappings":"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","names":[]}
@@ -21,7 +21,7 @@ import {
21
21
  } from "./chunk-JKMGYWXB.js";
22
22
  import {
23
23
  loadConfig
24
- } from "./chunk-CHJ5GNZC.js";
24
+ } from "./chunk-EC42HQQH.js";
25
25
 
26
26
  // src/runtime/telemetry.ts
27
27
  import { existsSync, readdirSync } from "fs";
@@ -233,4 +233,4 @@ export {
233
233
  collectSnapshot,
234
234
  formatDashboard
235
235
  };
236
- //# sourceMappingURL=chunk-A7BJPQQ6.js.map
236
+ //# sourceMappingURL=chunk-5O5OGOOQ.js.map
@@ -4,7 +4,7 @@ import {
4
4
  estimateTokens,
5
5
  getAtLevel,
6
6
  loadAllPrimitivesWithErrors
7
- } from "./chunk-UPLBF4RZ.js";
7
+ } from "./chunk-2UVWCTAY.js";
8
8
  import {
9
9
  log
10
10
  } from "./chunk-BSKDOFRT.js";
@@ -151,4 +151,4 @@ ${scratch}`);
151
151
  export {
152
152
  buildSystemPrompt
153
153
  };
154
- //# sourceMappingURL=chunk-UWQTZMNI.js.map
154
+ //# sourceMappingURL=chunk-7GZ4D6V6.js.map
@@ -2,25 +2,25 @@
2
2
 
3
3
  import {
4
4
  fixCapability
5
- } from "./chunk-W4T7PGI2.js";
5
+ } from "./chunk-UXCHAS3Z.js";
6
6
  import {
7
7
  validateMcpConfig
8
8
  } from "./chunk-5H34JPMB.js";
9
9
  import {
10
10
  buildSystemPrompt
11
- } from "./chunk-UWQTZMNI.js";
11
+ } from "./chunk-7GZ4D6V6.js";
12
12
  import {
13
13
  loadState
14
14
  } from "./chunk-UDZIS2AQ.js";
15
15
  import {
16
16
  loadDirectoryWithErrors
17
- } from "./chunk-UPLBF4RZ.js";
17
+ } from "./chunk-2UVWCTAY.js";
18
18
  import {
19
19
  loadConfig
20
- } from "./chunk-CHJ5GNZC.js";
20
+ } from "./chunk-EC42HQQH.js";
21
21
  import {
22
22
  getPrimitiveDirs
23
- } from "./chunk-4CWAGBNS.js";
23
+ } from "./chunk-4TQQZILG.js";
24
24
 
25
25
  // src/runtime/validator.ts
26
26
  import { existsSync, readdirSync, mkdirSync } from "fs";
@@ -227,4 +227,4 @@ export {
227
227
  validateHarness,
228
228
  doctorHarness
229
229
  };
230
- //# sourceMappingURL=chunk-FLZU44SV.js.map
230
+ //# sourceMappingURL=chunk-AN6Y4MDD.js.map
@@ -2,10 +2,10 @@
2
2
 
3
3
  import {
4
4
  loadDirectory
5
- } from "./chunk-UPLBF4RZ.js";
5
+ } from "./chunk-2UVWCTAY.js";
6
6
  import {
7
7
  CORE_PRIMITIVE_DIRS
8
- } from "./chunk-4CWAGBNS.js";
8
+ } from "./chunk-4TQQZILG.js";
9
9
 
10
10
  // src/runtime/indexer.ts
11
11
  import { writeFileSync, existsSync, mkdirSync } from "fs";
@@ -66,4 +66,4 @@ export {
66
66
  writeIndexFile,
67
67
  rebuildAllIndexes
68
68
  };
69
- //# sourceMappingURL=chunk-4FDUOGSZ.js.map
69
+ //# sourceMappingURL=chunk-D7AWV24Z.js.map
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  CONFIG_DEFAULTS,
5
5
  HarnessConfigSchema
6
- } from "./chunk-4CWAGBNS.js";
6
+ } from "./chunk-4TQQZILG.js";
7
7
 
8
8
  // src/core/config.ts
9
9
  import { readFileSync, existsSync } from "fs";
@@ -97,4 +97,4 @@ export {
97
97
  loadConfig,
98
98
  writeDefaultConfig
99
99
  };
100
- //# sourceMappingURL=chunk-CHJ5GNZC.js.map
100
+ //# sourceMappingURL=chunk-EC42HQQH.js.map
@@ -8,10 +8,10 @@ import {
8
8
  } from "./chunk-5H34JPMB.js";
9
9
  import {
10
10
  buildToolSet
11
- } from "./chunk-DA7IKHC4.js";
11
+ } from "./chunk-5CO5JTYT.js";
12
12
  import {
13
13
  buildSystemPrompt
14
- } from "./chunk-UWQTZMNI.js";
14
+ } from "./chunk-7GZ4D6V6.js";
15
15
  import {
16
16
  loadState,
17
17
  saveState
@@ -38,7 +38,7 @@ import {
38
38
  } from "./chunk-IZ6UZ3ZL.js";
39
39
  import {
40
40
  loadConfig
41
- } from "./chunk-CHJ5GNZC.js";
41
+ } from "./chunk-EC42HQQH.js";
42
42
 
43
43
  // src/core/harness.ts
44
44
  import { existsSync } from "fs";
@@ -396,4 +396,4 @@ function createHarness(options) {
396
396
  export {
397
397
  createHarness
398
398
  };
399
- //# sourceMappingURL=chunk-YIJY5DBV.js.map
399
+ //# sourceMappingURL=chunk-KLYMGWQJ.js.map