@archmax-ai/harness 0.0.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 (351) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +219 -0
  3. package/dist/agent.d.ts +174 -0
  4. package/dist/agent.js +140 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/assembly/compose.d.ts +170 -0
  7. package/dist/assembly/compose.js +391 -0
  8. package/dist/assembly/compose.js.map +1 -0
  9. package/dist/assembly/delegation-registry.d.ts +5 -0
  10. package/dist/assembly/delegation-registry.js +118 -0
  11. package/dist/assembly/delegation-registry.js.map +1 -0
  12. package/dist/assembly/index.d.ts +192 -0
  13. package/dist/assembly/index.js +265 -0
  14. package/dist/assembly/index.js.map +1 -0
  15. package/dist/assembly/plain.d.ts +7 -0
  16. package/dist/assembly/plain.js +41 -0
  17. package/dist/assembly/plain.js.map +1 -0
  18. package/dist/authoring-skill/archmax-harness/README.md +76 -0
  19. package/dist/authoring-skill/archmax-harness/SKILL.md +241 -0
  20. package/dist/authoring-skill/archmax-harness/references/backend-integration.md +626 -0
  21. package/dist/authoring-skill/archmax-harness/references/cases.md +41 -0
  22. package/dist/authoring-skill/archmax-harness/references/diagnostics.md +51 -0
  23. package/dist/authoring-skill/archmax-harness/references/hook-and-test-scripts.md +1070 -0
  24. package/dist/authoring-skill/archmax-harness/references/hooks-and-scripts.md +82 -0
  25. package/dist/authoring-skill/archmax-harness/references/wiring.md +101 -0
  26. package/dist/authoring-skill/archmax-harness/references/workflow-schema.md +1631 -0
  27. package/dist/authoring-skill/archmax-harness/references/workflow-yaml.md +241 -0
  28. package/dist/behaviour/support.d.ts +232 -0
  29. package/dist/behaviour/support.js +339 -0
  30. package/dist/behaviour/support.js.map +1 -0
  31. package/dist/cli/banner.d.ts +11 -0
  32. package/dist/cli/banner.js +29 -0
  33. package/dist/cli/banner.js.map +1 -0
  34. package/dist/cli/bootstrap.d.ts +33 -0
  35. package/dist/cli/bootstrap.js +153 -0
  36. package/dist/cli/bootstrap.js.map +1 -0
  37. package/dist/cli/command.d.ts +39 -0
  38. package/dist/cli/command.js +97 -0
  39. package/dist/cli/command.js.map +1 -0
  40. package/dist/cli/state-flow.d.ts +46 -0
  41. package/dist/cli/state-flow.js +268 -0
  42. package/dist/cli/state-flow.js.map +1 -0
  43. package/dist/cli/style.d.ts +41 -0
  44. package/dist/cli/style.js +64 -0
  45. package/dist/cli/style.js.map +1 -0
  46. package/dist/cli/turn.d.ts +41 -0
  47. package/dist/cli/turn.js +161 -0
  48. package/dist/cli/turn.js.map +1 -0
  49. package/dist/cli.d.ts +10 -0
  50. package/dist/cli.js +426 -0
  51. package/dist/cli.js.map +1 -0
  52. package/dist/core/code-description.d.ts +22 -0
  53. package/dist/core/code-description.js +38 -0
  54. package/dist/core/code-description.js.map +1 -0
  55. package/dist/core/deepagents.d.ts +183 -0
  56. package/dist/core/deepagents.js +128 -0
  57. package/dist/core/deepagents.js.map +1 -0
  58. package/dist/core/events.d.ts +350 -0
  59. package/dist/core/events.js +205 -0
  60. package/dist/core/events.js.map +1 -0
  61. package/dist/core/frontmatter.d.ts +15 -0
  62. package/dist/core/frontmatter.js +32 -0
  63. package/dist/core/frontmatter.js.map +1 -0
  64. package/dist/core/listing-redact.d.ts +37 -0
  65. package/dist/core/listing-redact.js +88 -0
  66. package/dist/core/listing-redact.js.map +1 -0
  67. package/dist/core/match.d.ts +26 -0
  68. package/dist/core/match.js +75 -0
  69. package/dist/core/match.js.map +1 -0
  70. package/dist/core/message-readers.d.ts +84 -0
  71. package/dist/core/message-readers.js +159 -0
  72. package/dist/core/message-readers.js.map +1 -0
  73. package/dist/core/messages.d.ts +49 -0
  74. package/dist/core/messages.js +85 -0
  75. package/dist/core/messages.js.map +1 -0
  76. package/dist/core/mount-prompt.d.ts +28 -0
  77. package/dist/core/mount-prompt.js +55 -0
  78. package/dist/core/mount-prompt.js.map +1 -0
  79. package/dist/core/mount-redact.d.ts +28 -0
  80. package/dist/core/mount-redact.js +32 -0
  81. package/dist/core/mount-redact.js.map +1 -0
  82. package/dist/core/mounts.d.ts +88 -0
  83. package/dist/core/mounts.js +147 -0
  84. package/dist/core/mounts.js.map +1 -0
  85. package/dist/core/path-mapping.d.ts +52 -0
  86. package/dist/core/path-mapping.js +113 -0
  87. package/dist/core/path-mapping.js.map +1 -0
  88. package/dist/core/platform-prompt.generated.d.ts +2 -0
  89. package/dist/core/platform-prompt.generated.js +4 -0
  90. package/dist/core/platform-prompt.generated.js.map +1 -0
  91. package/dist/core/prompt.d.ts +42 -0
  92. package/dist/core/prompt.js +75 -0
  93. package/dist/core/prompt.js.map +1 -0
  94. package/dist/core/session-id.d.ts +38 -0
  95. package/dist/core/session-id.js +61 -0
  96. package/dist/core/session-id.js.map +1 -0
  97. package/dist/core/session-store.d.ts +85 -0
  98. package/dist/core/session-store.js +149 -0
  99. package/dist/core/session-store.js.map +1 -0
  100. package/dist/core/session-zone.d.ts +54 -0
  101. package/dist/core/session-zone.js +82 -0
  102. package/dist/core/session-zone.js.map +1 -0
  103. package/dist/core/skill-prompt.d.ts +31 -0
  104. package/dist/core/skill-prompt.js +54 -0
  105. package/dist/core/skill-prompt.js.map +1 -0
  106. package/dist/core/skill-redact.d.ts +15 -0
  107. package/dist/core/skill-redact.js +27 -0
  108. package/dist/core/skill-redact.js.map +1 -0
  109. package/dist/core/skills.d.ts +172 -0
  110. package/dist/core/skills.js +214 -0
  111. package/dist/core/skills.js.map +1 -0
  112. package/dist/core/tool-mocks.d.ts +23 -0
  113. package/dist/core/tool-mocks.js +39 -0
  114. package/dist/core/tool-mocks.js.map +1 -0
  115. package/dist/core/tool-telemetry.d.ts +16 -0
  116. package/dist/core/tool-telemetry.js +40 -0
  117. package/dist/core/tool-telemetry.js.map +1 -0
  118. package/dist/core/usage.d.ts +114 -0
  119. package/dist/core/usage.js +226 -0
  120. package/dist/core/usage.js.map +1 -0
  121. package/dist/core/workspace-context.d.ts +136 -0
  122. package/dist/core/workspace-context.js +178 -0
  123. package/dist/core/workspace-context.js.map +1 -0
  124. package/dist/core/workspace-prompt.d.ts +7 -0
  125. package/dist/core/workspace-prompt.js +102 -0
  126. package/dist/core/workspace-prompt.js.map +1 -0
  127. package/dist/core/workspace-router.d.ts +61 -0
  128. package/dist/core/workspace-router.js +145 -0
  129. package/dist/core/workspace-router.js.map +1 -0
  130. package/dist/core/workspace.d.ts +85 -0
  131. package/dist/core/workspace.js +193 -0
  132. package/dist/core/workspace.js.map +1 -0
  133. package/dist/core/zones.d.ts +181 -0
  134. package/dist/core/zones.js +202 -0
  135. package/dist/core/zones.js.map +1 -0
  136. package/dist/env.d.ts +99 -0
  137. package/dist/env.js +271 -0
  138. package/dist/env.js.map +1 -0
  139. package/dist/index.d.ts +265 -0
  140. package/dist/index.js +197 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/kernel/kernel.d.ts +192 -0
  143. package/dist/kernel/kernel.js +751 -0
  144. package/dist/kernel/kernel.js.map +1 -0
  145. package/dist/lifecycle/hook-shape.d.ts +44 -0
  146. package/dist/lifecycle/hook-shape.js +66 -0
  147. package/dist/lifecycle/hook-shape.js.map +1 -0
  148. package/dist/lifecycle/runner.d.ts +177 -0
  149. package/dist/lifecycle/runner.js +372 -0
  150. package/dist/lifecycle/runner.js.map +1 -0
  151. package/dist/lifecycle/transcript.d.ts +27 -0
  152. package/dist/lifecycle/transcript.js +43 -0
  153. package/dist/lifecycle/transcript.js.map +1 -0
  154. package/dist/machine/allow.d.ts +65 -0
  155. package/dist/machine/allow.js +107 -0
  156. package/dist/machine/allow.js.map +1 -0
  157. package/dist/machine/delegation.d.ts +9 -0
  158. package/dist/machine/delegation.js +10 -0
  159. package/dist/machine/delegation.js.map +1 -0
  160. package/dist/machine/diagnostic.d.ts +14 -0
  161. package/dist/machine/diagnostic.js +2 -0
  162. package/dist/machine/diagnostic.js.map +1 -0
  163. package/dist/machine/lint-spec.d.ts +4 -0
  164. package/dist/machine/lint-spec.js +266 -0
  165. package/dist/machine/lint-spec.js.map +1 -0
  166. package/dist/machine/load-spec.d.ts +90 -0
  167. package/dist/machine/load-spec.js +120 -0
  168. package/dist/machine/load-spec.js.map +1 -0
  169. package/dist/machine/machine.d.ts +273 -0
  170. package/dist/machine/machine.js +551 -0
  171. package/dist/machine/machine.js.map +1 -0
  172. package/dist/machine/mount-grants.d.ts +25 -0
  173. package/dist/machine/mount-grants.js +24 -0
  174. package/dist/machine/mount-grants.js.map +1 -0
  175. package/dist/machine/slug.d.ts +14 -0
  176. package/dist/machine/slug.js +17 -0
  177. package/dist/machine/slug.js.map +1 -0
  178. package/dist/machine/spec-schema.d.ts +662 -0
  179. package/dist/machine/spec-schema.js +717 -0
  180. package/dist/machine/spec-schema.js.map +1 -0
  181. package/dist/machine/tool-names.d.ts +98 -0
  182. package/dist/machine/tool-names.js +144 -0
  183. package/dist/machine/tool-names.js.map +1 -0
  184. package/dist/machine/triggers.d.ts +114 -0
  185. package/dist/machine/triggers.js +165 -0
  186. package/dist/machine/triggers.js.map +1 -0
  187. package/dist/machine/types.d.ts +186 -0
  188. package/dist/machine/types.js +12 -0
  189. package/dist/machine/types.js.map +1 -0
  190. package/dist/machine/validate-spec.d.ts +42 -0
  191. package/dist/machine/validate-spec.js +29 -0
  192. package/dist/machine/validate-spec.js.map +1 -0
  193. package/dist/machine/variables.d.ts +196 -0
  194. package/dist/machine/variables.js +415 -0
  195. package/dist/machine/variables.js.map +1 -0
  196. package/dist/public/cli.d.ts +15 -0
  197. package/dist/public/cli.js +14 -0
  198. package/dist/public/cli.js.map +1 -0
  199. package/dist/public/messages.d.ts +33 -0
  200. package/dist/public/messages.js +33 -0
  201. package/dist/public/messages.js.map +1 -0
  202. package/dist/public/sandbox.d.ts +99 -0
  203. package/dist/public/sandbox.js +32 -0
  204. package/dist/public/sandbox.js.map +1 -0
  205. package/dist/public/spec.d.ts +147 -0
  206. package/dist/public/spec.js +149 -0
  207. package/dist/public/spec.js.map +1 -0
  208. package/dist/public/testing.d.ts +71 -0
  209. package/dist/public/testing.js +39 -0
  210. package/dist/public/testing.js.map +1 -0
  211. package/dist/rubrics/rubrics.d.ts +135 -0
  212. package/dist/rubrics/rubrics.js +145 -0
  213. package/dist/rubrics/rubrics.js.map +1 -0
  214. package/dist/runtime/contract.d.ts +73 -0
  215. package/dist/runtime/contract.js +96 -0
  216. package/dist/runtime/contract.js.map +1 -0
  217. package/dist/sandbox/assets/parts/core.js +22 -0
  218. package/dist/sandbox/assets/parts/lifecycle-hook.js +47 -0
  219. package/dist/sandbox/bridge.d.ts +16 -0
  220. package/dist/sandbox/bridge.js +95 -0
  221. package/dist/sandbox/bridge.js.map +1 -0
  222. package/dist/sandbox/executor.d.ts +46 -0
  223. package/dist/sandbox/executor.js +119 -0
  224. package/dist/sandbox/executor.js.map +1 -0
  225. package/dist/sandbox/imports.d.ts +33 -0
  226. package/dist/sandbox/imports.js +67 -0
  227. package/dist/sandbox/imports.js.map +1 -0
  228. package/dist/sandbox/prelude.d.ts +12 -0
  229. package/dist/sandbox/prelude.js +51 -0
  230. package/dist/sandbox/prelude.js.map +1 -0
  231. package/dist/sandbox/ptc-gateway.d.ts +104 -0
  232. package/dist/sandbox/ptc-gateway.js +167 -0
  233. package/dist/sandbox/ptc-gateway.js.map +1 -0
  234. package/dist/sandbox/runtime.d.ts +59 -0
  235. package/dist/sandbox/runtime.js +51 -0
  236. package/dist/sandbox/runtime.js.map +1 -0
  237. package/dist/sandbox/tools.d.ts +34 -0
  238. package/dist/sandbox/tools.js +147 -0
  239. package/dist/sandbox/tools.js.map +1 -0
  240. package/dist/sessions/operations.d.ts +79 -0
  241. package/dist/sessions/operations.js +121 -0
  242. package/dist/sessions/operations.js.map +1 -0
  243. package/dist/sessions/resolve.d.ts +97 -0
  244. package/dist/sessions/resolve.js +145 -0
  245. package/dist/sessions/resolve.js.map +1 -0
  246. package/dist/sessions/resume.d.ts +242 -0
  247. package/dist/sessions/resume.js +288 -0
  248. package/dist/sessions/resume.js.map +1 -0
  249. package/dist/sessions/scope.d.ts +99 -0
  250. package/dist/sessions/scope.js +145 -0
  251. package/dist/sessions/scope.js.map +1 -0
  252. package/dist/sessions/summary.d.ts +65 -0
  253. package/dist/sessions/summary.js +56 -0
  254. package/dist/sessions/summary.js.map +1 -0
  255. package/dist/testing/assertions.d.ts +30 -0
  256. package/dist/testing/assertions.js +231 -0
  257. package/dist/testing/assertions.js.map +1 -0
  258. package/dist/testing/case-document.d.ts +141 -0
  259. package/dist/testing/case-document.js +51 -0
  260. package/dist/testing/case-document.js.map +1 -0
  261. package/dist/testing/case-schema.d.ts +29 -0
  262. package/dist/testing/case-schema.js +519 -0
  263. package/dist/testing/case-schema.js.map +1 -0
  264. package/dist/testing/discovery.d.ts +10 -0
  265. package/dist/testing/discovery.js +24 -0
  266. package/dist/testing/discovery.js.map +1 -0
  267. package/dist/testing/driver.d.ts +78 -0
  268. package/dist/testing/driver.js +117 -0
  269. package/dist/testing/driver.js.map +1 -0
  270. package/dist/testing/grade.d.ts +116 -0
  271. package/dist/testing/grade.js +261 -0
  272. package/dist/testing/grade.js.map +1 -0
  273. package/dist/testing/interpreter.d.ts +55 -0
  274. package/dist/testing/interpreter.js +103 -0
  275. package/dist/testing/interpreter.js.map +1 -0
  276. package/dist/testing/mock-middleware.d.ts +5 -0
  277. package/dist/testing/mock-middleware.js +33 -0
  278. package/dist/testing/mock-middleware.js.map +1 -0
  279. package/dist/testing/runner.d.ts +205 -0
  280. package/dist/testing/runner.js +266 -0
  281. package/dist/testing/runner.js.map +1 -0
  282. package/dist/testing/target.d.ts +27 -0
  283. package/dist/testing/target.js +21 -0
  284. package/dist/testing/target.js.map +1 -0
  285. package/dist/validate/validate.d.ts +41 -0
  286. package/dist/validate/validate.js +669 -0
  287. package/dist/validate/validate.js.map +1 -0
  288. package/dist/workflow/agent-tools.d.ts +10 -0
  289. package/dist/workflow/agent-tools.js +10 -0
  290. package/dist/workflow/agent-tools.js.map +1 -0
  291. package/dist/workflow/checkpointer.d.ts +52 -0
  292. package/dist/workflow/checkpointer.js +200 -0
  293. package/dist/workflow/checkpointer.js.map +1 -0
  294. package/dist/workflow/control-tools.d.ts +174 -0
  295. package/dist/workflow/control-tools.js +468 -0
  296. package/dist/workflow/control-tools.js.map +1 -0
  297. package/dist/workflow/governance.d.ts +104 -0
  298. package/dist/workflow/governance.js +546 -0
  299. package/dist/workflow/governance.js.map +1 -0
  300. package/dist/workflow/middleware.d.ts +85 -0
  301. package/dist/workflow/middleware.js +283 -0
  302. package/dist/workflow/middleware.js.map +1 -0
  303. package/dist/workflow/on-error.d.ts +25 -0
  304. package/dist/workflow/on-error.js +58 -0
  305. package/dist/workflow/on-error.js.map +1 -0
  306. package/dist/workflow/parks.d.ts +46 -0
  307. package/dist/workflow/parks.js +513 -0
  308. package/dist/workflow/parks.js.map +1 -0
  309. package/dist/workflow/paths.d.ts +67 -0
  310. package/dist/workflow/paths.js +108 -0
  311. package/dist/workflow/paths.js.map +1 -0
  312. package/dist/workflow/prompt-cache.d.ts +70 -0
  313. package/dist/workflow/prompt-cache.js +103 -0
  314. package/dist/workflow/prompt-cache.js.map +1 -0
  315. package/dist/workflow/prompt-pruning.d.ts +20 -0
  316. package/dist/workflow/prompt-pruning.js +83 -0
  317. package/dist/workflow/prompt-pruning.js.map +1 -0
  318. package/dist/workflow/render-prompt.d.ts +45 -0
  319. package/dist/workflow/render-prompt.js +140 -0
  320. package/dist/workflow/render-prompt.js.map +1 -0
  321. package/dist/workflow/runtime-config.d.ts +7 -0
  322. package/dist/workflow/runtime-config.js +9 -0
  323. package/dist/workflow/runtime-config.js.map +1 -0
  324. package/dist/workflow/session-artifacts.d.ts +90 -0
  325. package/dist/workflow/session-artifacts.js +134 -0
  326. package/dist/workflow/session-artifacts.js.map +1 -0
  327. package/dist/workflow/session-view.d.ts +31 -0
  328. package/dist/workflow/session-view.js +94 -0
  329. package/dist/workflow/session-view.js.map +1 -0
  330. package/dist/workflow/snapshot.d.ts +14 -0
  331. package/dist/workflow/snapshot.js +97 -0
  332. package/dist/workflow/snapshot.js.map +1 -0
  333. package/dist/workflow/state.d.ts +347 -0
  334. package/dist/workflow/state.js +322 -0
  335. package/dist/workflow/state.js.map +1 -0
  336. package/dist/workflow/sub-workflow.d.ts +174 -0
  337. package/dist/workflow/sub-workflow.js +392 -0
  338. package/dist/workflow/sub-workflow.js.map +1 -0
  339. package/dist/workflow/tool-service.d.ts +48 -0
  340. package/dist/workflow/tool-service.js +291 -0
  341. package/dist/workflow/tool-service.js.map +1 -0
  342. package/dist/workflow/turn-boundary.d.ts +39 -0
  343. package/dist/workflow/turn-boundary.js +128 -0
  344. package/dist/workflow/turn-boundary.js.map +1 -0
  345. package/dist/workflow/turn-runner.d.ts +40 -0
  346. package/dist/workflow/turn-runner.js +122 -0
  347. package/dist/workflow/turn-runner.js.map +1 -0
  348. package/dist/workflow/workflow-tools.d.ts +46 -0
  349. package/dist/workflow/workflow-tools.js +90 -0
  350. package/dist/workflow/workflow-tools.js.map +1 -0
  351. package/package.json +119 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The line-oriented listing filter both governed-capability redactions run on.
3
+ *
4
+ * The kernel refuses a path the state may not reach, which is enforcement — but
5
+ * a scoped tool asks about a *directory*, not a file: `ls skills/`, `glob
6
+ * catalogs/**\/*.csv`, and `grep` over the root all name a scope the state may
7
+ * legitimately reach and would hand back everything in it. Blocking those calls
8
+ * outright is the wrong trade (a state with one enabled capability could then
9
+ * not list it), so the result is filtered instead.
10
+ *
11
+ * This is the only place governance touches a tool **result** rather than a
12
+ * call, and it exists because invisibility is a requirement of governance in its
13
+ * own right: a name the model never sees is a capability it never tries.
14
+ *
15
+ * Filtering is line-oriented because the upstream filesystem tools render
16
+ * line-oriented text: `ls` one entry per line, `glob` one path per line, `grep`
17
+ * a `<path>:` header followed by indented ` <line>: <text>` matches. A header
18
+ * for a hidden owner therefore suppresses its continuation lines too —
19
+ * otherwise the matched *content* would survive its filename.
20
+ */
21
+ /** Whether a line carries no path of its own (a grep match under a header). */
22
+ function isContinuation(line) {
23
+ return /^\s/.test(line) && line.trim() !== "";
24
+ }
25
+ /**
26
+ * The path a result line is about, or null when it names none. Takes the leading
27
+ * token up to the first whitespace or `:` — enough for every shape the upstream
28
+ * tools emit (`/skills/x (directory)`, `/skills/x/SKILL.md`,
29
+ * `/skills/x/SKILL.md:`) without trying to parse arbitrary prose.
30
+ */
31
+ function pathOfLine(line) {
32
+ const token = line.trim().split(/[\s:]/, 1)[0] ?? "";
33
+ return token === "" ? null : token;
34
+ }
35
+ /**
36
+ * Drop from `text` every line about an owner `isHidden` refuses.
37
+ *
38
+ * `ownerOf` maps a result line's path to the governed thing that owns it (a
39
+ * skill slug, a mount name) or `null` when it owns none — a line no owner claims
40
+ * is always kept, since the state's other rules govern it.
41
+ *
42
+ * Returns the text unchanged when nothing was hidden, so a result the filter has
43
+ * no opinion about is passed through by identity rather than rebuilt.
44
+ */
45
+ export function redactListing(text, ownerOf, isHidden) {
46
+ const out = [];
47
+ let suppressing = false;
48
+ let hid = false;
49
+ for (const line of text.split("\n")) {
50
+ if (isContinuation(line)) {
51
+ // A grep match line belongs to whichever header preceded it.
52
+ if (!suppressing)
53
+ out.push(line);
54
+ continue;
55
+ }
56
+ if (line.trim() === "") {
57
+ // A blank line separates grep's file groups; keep it only outside a
58
+ // suppressed group, so a hidden owner leaves no gap where it was.
59
+ if (!suppressing)
60
+ out.push(line);
61
+ continue;
62
+ }
63
+ const path = pathOfLine(line);
64
+ const owner = path == null ? null : ownerOf(path);
65
+ if (owner == null) {
66
+ suppressing = false;
67
+ out.push(line);
68
+ continue;
69
+ }
70
+ suppressing = isHidden(owner);
71
+ if (suppressing) {
72
+ hid = true;
73
+ // Drop the blank separator this group's header would have followed.
74
+ if (out.length > 0 && out[out.length - 1]?.trim() === "")
75
+ out.pop();
76
+ continue;
77
+ }
78
+ out.push(line);
79
+ }
80
+ return hid ? out.join("\n") : text;
81
+ }
82
+ /**
83
+ * The scoped file tools whose results are filtered. `read_file` is absent on
84
+ * purpose: it names one path, which the kernel already refuses, and filtering a
85
+ * file's *contents* would hand the model a silently truncated document.
86
+ */
87
+ export const REDACTED_TOOLS = new Set(["ls", "glob", "grep"]);
88
+ //# sourceMappingURL=listing-redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listing-redact.js","sourceRoot":"","sources":["../../src/core/listing-redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,+EAA+E;AAC/E,SAAS,cAAc,CAAC,IAAY;IAClC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrD,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AACrC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,OAAwC,EACxC,QAAoC;IAEpC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,GAAG,GAAG,KAAK,CAAC;IAEhB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,6DAA6D;YAC7D,IAAI,CAAC,WAAW;gBAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjC,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACvB,oEAAoE;YACpE,kEAAkE;YAClE,IAAI,CAAC,WAAW;gBAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjC,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,WAAW,GAAG,KAAK,CAAC;YACpB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,SAAS;QACX,CAAC;QACD,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,WAAW,EAAE,CAAC;YAChB,GAAG,GAAG,IAAI,CAAC;YACX,oEAAoE;YACpE,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE;gBAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YACpE,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IAED,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAwB,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The one partial-match vocabulary for a *declared* value against an *observed*
3
+ * one. Case assertions (`calledTool.input`, `blockedTool.input`, …) and tool
4
+ * mocks (`whenInput`) both read it, so a matcher an author writes means the same
5
+ * thing whichever side of a tool call it sits on:
6
+ *
7
+ * - a mapping matches when every declared key is present and matches — nested
8
+ * mappings partially, so undeclared keys are ignored at every depth;
9
+ * - an array matches element-wise: same length, each element by these rules;
10
+ * - a string of the form `/pattern/flags` is a regular expression, tested
11
+ * against the stringified observed value;
12
+ * - every other scalar (and `null`) matches by strict equality.
13
+ *
14
+ * Runtime-owned (`core/`) because the tool-mock gateway is runtime code and the
15
+ * runtime never imports from the testing modules.
16
+ */
17
+ /**
18
+ * Compile a `/pattern/flags` string to a regex; `null` when the string is not
19
+ * regex-shaped. Throws on a malformed pattern, so a schema can reject it
20
+ * statically rather than let it match as a literal at run time.
21
+ */
22
+ export declare function regexFromString(raw: string): RegExp | null;
23
+ /** Structural equality over JSON-shaped values. */
24
+ export declare function deepEqual(a: unknown, b: unknown): boolean;
25
+ /** Whether `actual` satisfies the declared `expected` shape (see module docs). */
26
+ export declare function partialMatch(expected: unknown, actual: unknown): boolean;
@@ -0,0 +1,75 @@
1
+ /**
2
+ * The one partial-match vocabulary for a *declared* value against an *observed*
3
+ * one. Case assertions (`calledTool.input`, `blockedTool.input`, …) and tool
4
+ * mocks (`whenInput`) both read it, so a matcher an author writes means the same
5
+ * thing whichever side of a tool call it sits on:
6
+ *
7
+ * - a mapping matches when every declared key is present and matches — nested
8
+ * mappings partially, so undeclared keys are ignored at every depth;
9
+ * - an array matches element-wise: same length, each element by these rules;
10
+ * - a string of the form `/pattern/flags` is a regular expression, tested
11
+ * against the stringified observed value;
12
+ * - every other scalar (and `null`) matches by strict equality.
13
+ *
14
+ * Runtime-owned (`core/`) because the tool-mock gateway is runtime code and the
15
+ * runtime never imports from the testing modules.
16
+ */
17
+ /**
18
+ * Compile a `/pattern/flags` string to a regex; `null` when the string is not
19
+ * regex-shaped. Throws on a malformed pattern, so a schema can reject it
20
+ * statically rather than let it match as a literal at run time.
21
+ */
22
+ export function regexFromString(raw) {
23
+ const match = /^\/(.*)\/([a-z]*)$/s.exec(raw);
24
+ if (!match)
25
+ return null;
26
+ return new RegExp(match[1], match[2]);
27
+ }
28
+ /** Structural equality over JSON-shaped values. */
29
+ export function deepEqual(a, b) {
30
+ if (a === b)
31
+ return true;
32
+ if (a == null || b == null || typeof a !== typeof b || typeof a !== "object")
33
+ return false;
34
+ if (Array.isArray(a) !== Array.isArray(b))
35
+ return false;
36
+ if (Array.isArray(a) && Array.isArray(b)) {
37
+ return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
38
+ }
39
+ const objA = a;
40
+ const objB = b;
41
+ const keysA = Object.keys(objA);
42
+ return (keysA.length === Object.keys(objB).length && keysA.every((k) => deepEqual(objA[k], objB[k])));
43
+ }
44
+ function isPlainObject(value) {
45
+ return value != null && typeof value === "object" && !Array.isArray(value);
46
+ }
47
+ function scalarMatches(expected, actual) {
48
+ if (typeof expected === "string") {
49
+ let regex = null;
50
+ try {
51
+ regex = regexFromString(expected);
52
+ }
53
+ catch {
54
+ // A malformed pattern is a schema error upstream; here it can only be a literal.
55
+ }
56
+ if (regex)
57
+ return regex.test(String(actual ?? ""));
58
+ }
59
+ return expected === actual;
60
+ }
61
+ /** Whether `actual` satisfies the declared `expected` shape (see module docs). */
62
+ export function partialMatch(expected, actual) {
63
+ if (Array.isArray(expected)) {
64
+ return (Array.isArray(actual) &&
65
+ expected.length === actual.length &&
66
+ expected.every((v, i) => partialMatch(v, actual[i])));
67
+ }
68
+ if (isPlainObject(expected)) {
69
+ if (!isPlainObject(actual))
70
+ return false;
71
+ return Object.entries(expected).every(([k, v]) => k in actual && partialMatch(v, actual[k]));
72
+ }
73
+ return scalarMatches(expected, actual);
74
+ }
75
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/core/match.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,SAAS,CAAC,CAAU,EAAE,CAAU;IAC9C,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC3F,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACxD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,IAAI,GAAG,CAA4B,CAAC;IAC1C,MAAM,IAAI,GAAG,CAA4B,CAAC;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,CACL,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAC7F,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,aAAa,CAAC,QAAiB,EAAE,MAAe;IACvD,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,IAAI,KAAK,GAAkB,IAAI,CAAC;QAChC,IAAI,CAAC;YACH,KAAK,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,iFAAiF;QACnF,CAAC;QACD,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAAC,QAAiB,EAAE,MAAe;IAC7D,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YACrB,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;YACjC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CACrD,CAAC;IACJ,CAAC;IACD,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;QACzC,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,MAAM,IAAI,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/F,CAAC;IACD,OAAO,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Reading a transcript: what kind a message is, who wrote it, what the agent
3
+ * last said, and where a turn begins. Every reader is duck-typed over the shapes
4
+ * a message takes at runtime — a LangChain class instance, a serialized object,
5
+ * a raw `{ role, content }` — and never `instanceof`, so this module imports
6
+ * nothing and a host can read a checkpointed transcript without the runtime.
7
+ * The writers (`runtimeNote`, `humanNote`) live in `messages.ts`.
8
+ */
9
+ export declare const ROLE_BY_TYPE: Record<string, string>;
10
+ /**
11
+ * The LangChain message kind (`ai`, `human`, `tool`, `system`, …), read
12
+ * robustly across the shapes a message can take at runtime: a class instance
13
+ * (`_getType()`/`getType()`), a serialized object (`type`), or a raw role
14
+ * (`role`). One definition, shared by the workflow graph, session-artifact
15
+ * serialization, and history building, so message classification cannot drift.
16
+ */
17
+ export declare function messageTypeOf(message: unknown): string;
18
+ /** Whether a message is an assistant/AI message (`ai` or `assistant`). */
19
+ export declare function isAiMessage(message: unknown): boolean;
20
+ /** Whether a message is a human/user message (`human` or `user`). */
21
+ export declare function isHumanMessage(message: unknown): boolean;
22
+ /**
23
+ * What the agent last *said*: the final assistant message carrying text. Tool
24
+ * results — the `archmax_advance` confirmation is routinely the literal last
25
+ * message — and the runtime's own notes are skipped, so this is the session's
26
+ * answer as a person would read it.
27
+ */
28
+ export declare function lastAgentText(messages: unknown[]): string;
29
+ /**
30
+ * What the runtime wrote into a transcript, and why.
31
+ *
32
+ * - `decision` — a person picked an edge at a human state and the session was routed
33
+ * - `event` — a trigger firing was delivered to a parked session
34
+ * - `error` — a failed state was routed to its `on_error` target
35
+ * - `after` — a terminal state's completion check asked for a revision
36
+ * - `sub-workflow` — a resumed child's result, handed back to its caller
37
+ * - `opening` — the fixed line a child session's own transcript opens with
38
+ */
39
+ export type RuntimeNoteKind = "decision" | "event" | "error" | "after" | "sub-workflow" | "opening";
40
+ /** Where the marker lives on a message: `additional_kwargs.archmax.note`. */
41
+ export declare const NOTE_KEY = "archmax";
42
+ /**
43
+ * The kind of runtime note a message is, or `null` if a person wrote it. Read
44
+ * from `additional_kwargs` across the shapes a message takes at runtime, the way
45
+ * {@link messageTypeOf} reads a message's kind.
46
+ */
47
+ export declare function runtimeNoteKind(message: unknown): RuntimeNoteKind | null;
48
+ /** Whether the runtime wrote this message rather than a person. */
49
+ export declare function isRuntimeNote(message: unknown): boolean;
50
+ /**
51
+ * Whether a message opens a turn: something the session was **told**, by a person
52
+ * or by the runtime. A runtime note opens one too — an arrival, a decision, a
53
+ * correction is news the session has to answer for. Evaluated per message, so a
54
+ * transcript mixing human-role notes (checkpointed before notes became tool-call
55
+ * pairs) with marked notes decides identically for each.
56
+ */
57
+ export declare function opensTurn(message: unknown): boolean;
58
+ /** Whether the last thing in the transcript is something the session was told. */
59
+ export declare function lastMessageIsHuman(messages: unknown[]): boolean;
60
+ /**
61
+ * Whether the agent has said anything since the last thing it was told — any
62
+ * assistant message carrying non-empty text, including one that also made a tool
63
+ * call. The window is closed by a turn-opening message: a person's, or the
64
+ * runtime's own narration, which closes it exactly as a real message does.
65
+ */
66
+ export declare function spokeSinceLastHumanMessage(messages: unknown[]): boolean;
67
+ /**
68
+ * The messages appended since `cursor` — a message count read before a turn
69
+ * (`agent.sessions.messageCount(sessionId)`), so a host slices exactly what one
70
+ * `invoke` added without knowing how many seeds or notes opened it. A cursor past
71
+ * the end yields nothing.
72
+ */
73
+ export declare function messagesSince<T>(messages: readonly T[], cursor: number): T[];
74
+ /**
75
+ * The trailing turn of a transcript: from the last thing the session was told to
76
+ * the end. What the session was told may be several adjacent messages — a
77
+ * delivered firing is a note pair followed by the person's message — so the
78
+ * turn starts at the first of the last unbroken run of turn-opening messages.
79
+ * For everything one `invoke` appended, use a cursor and {@link messagesSince}:
80
+ * a child's result note lands mid-turn and opens a reply window of its own.
81
+ */
82
+ export declare function lastTurn<T>(messages: readonly T[]): T[];
83
+ /** Flatten LangChain message content (string or multimodal parts) to plain text. */
84
+ export declare function contentToString(content: unknown): string;
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Reading a transcript: what kind a message is, who wrote it, what the agent
3
+ * last said, and where a turn begins. Every reader is duck-typed over the shapes
4
+ * a message takes at runtime — a LangChain class instance, a serialized object,
5
+ * a raw `{ role, content }` — and never `instanceof`, so this module imports
6
+ * nothing and a host can read a checkpointed transcript without the runtime.
7
+ * The writers (`runtimeNote`, `humanNote`) live in `messages.ts`.
8
+ */
9
+ export const ROLE_BY_TYPE = {
10
+ human: "user",
11
+ ai: "assistant",
12
+ system: "system",
13
+ tool: "tool",
14
+ function: "tool",
15
+ };
16
+ /**
17
+ * The LangChain message kind (`ai`, `human`, `tool`, `system`, …), read
18
+ * robustly across the shapes a message can take at runtime: a class instance
19
+ * (`_getType()`/`getType()`), a serialized object (`type`), or a raw role
20
+ * (`role`). One definition, shared by the workflow graph, session-artifact
21
+ * serialization, and history building, so message classification cannot drift.
22
+ */
23
+ export function messageTypeOf(message) {
24
+ const msg = message;
25
+ const t = msg._getType?.() ??
26
+ msg.getType?.() ??
27
+ msg.type ??
28
+ msg.role ??
29
+ "";
30
+ return String(t);
31
+ }
32
+ /** Whether a message is an assistant/AI message (`ai` or `assistant`). */
33
+ export function isAiMessage(message) {
34
+ const t = messageTypeOf(message);
35
+ return t === "ai" || t === "assistant";
36
+ }
37
+ /** Whether a message is a human/user message (`human` or `user`). */
38
+ export function isHumanMessage(message) {
39
+ const t = messageTypeOf(message);
40
+ return t === "human" || t === "user";
41
+ }
42
+ /**
43
+ * What the agent last *said*: the final assistant message carrying text. Tool
44
+ * results — the `archmax_advance` confirmation is routinely the literal last
45
+ * message — and the runtime's own notes are skipped, so this is the session's
46
+ * answer as a person would read it.
47
+ */
48
+ export function lastAgentText(messages) {
49
+ for (let i = messages.length - 1; i >= 0; i--) {
50
+ const message = messages[i];
51
+ if (!isAiMessage(message) || isRuntimeNote(message))
52
+ continue;
53
+ const text = contentToString(message.content).trim();
54
+ if (text)
55
+ return text;
56
+ }
57
+ return "";
58
+ }
59
+ /** Where the marker lives on a message: `additional_kwargs.archmax.note`. */
60
+ export const NOTE_KEY = "archmax";
61
+ /**
62
+ * The kind of runtime note a message is, or `null` if a person wrote it. Read
63
+ * from `additional_kwargs` across the shapes a message takes at runtime, the way
64
+ * {@link messageTypeOf} reads a message's kind.
65
+ */
66
+ export function runtimeNoteKind(message) {
67
+ const msg = message;
68
+ // A class instance and a plain message-like object both carry
69
+ // `additional_kwargs` at the top; LangChain's own serialized-constructor form
70
+ // (what a checkpoint holds on disk) nests it under `kwargs`.
71
+ const kwargs = (msg?.additional_kwargs ?? msg?.kwargs?.additional_kwargs);
72
+ const marker = kwargs?.[NOTE_KEY];
73
+ const note = marker?.note;
74
+ return typeof note === "string" ? note : null;
75
+ }
76
+ /** Whether the runtime wrote this message rather than a person. */
77
+ export function isRuntimeNote(message) {
78
+ return runtimeNoteKind(message) !== null;
79
+ }
80
+ /**
81
+ * Whether a message opens a turn: something the session was **told**, by a person
82
+ * or by the runtime. A runtime note opens one too — an arrival, a decision, a
83
+ * correction is news the session has to answer for. Evaluated per message, so a
84
+ * transcript mixing human-role notes (checkpointed before notes became tool-call
85
+ * pairs) with marked notes decides identically for each.
86
+ */
87
+ export function opensTurn(message) {
88
+ return isHumanMessage(message) || isRuntimeNote(message);
89
+ }
90
+ /** Whether the last thing in the transcript is something the session was told. */
91
+ export function lastMessageIsHuman(messages) {
92
+ const last = messages[messages.length - 1];
93
+ return last !== undefined && opensTurn(last);
94
+ }
95
+ /**
96
+ * Whether the agent has said anything since the last thing it was told — any
97
+ * assistant message carrying non-empty text, including one that also made a tool
98
+ * call. The window is closed by a turn-opening message: a person's, or the
99
+ * runtime's own narration, which closes it exactly as a real message does.
100
+ */
101
+ export function spokeSinceLastHumanMessage(messages) {
102
+ for (let i = messages.length - 1; i >= 0; i--) {
103
+ const message = messages[i];
104
+ if (message === undefined)
105
+ continue;
106
+ if (opensTurn(message))
107
+ return false;
108
+ if (!isAiMessage(message))
109
+ continue;
110
+ if (contentToString(message.content).trim() !== "")
111
+ return true;
112
+ }
113
+ return false;
114
+ }
115
+ /**
116
+ * The messages appended since `cursor` — a message count read before a turn
117
+ * (`agent.sessions.messageCount(sessionId)`), so a host slices exactly what one
118
+ * `invoke` added without knowing how many seeds or notes opened it. A cursor past
119
+ * the end yields nothing.
120
+ */
121
+ export function messagesSince(messages, cursor) {
122
+ const from = Math.max(0, Math.floor(cursor));
123
+ return from >= messages.length ? [] : messages.slice(from);
124
+ }
125
+ /**
126
+ * The trailing turn of a transcript: from the last thing the session was told to
127
+ * the end. What the session was told may be several adjacent messages — a
128
+ * delivered firing is a note pair followed by the person's message — so the
129
+ * turn starts at the first of the last unbroken run of turn-opening messages.
130
+ * For everything one `invoke` appended, use a cursor and {@link messagesSince}:
131
+ * a child's result note lands mid-turn and opens a reply window of its own.
132
+ */
133
+ export function lastTurn(messages) {
134
+ let end = messages.length - 1;
135
+ while (end >= 0 && !opensTurn(messages[end]))
136
+ end--;
137
+ if (end < 0)
138
+ return [];
139
+ let start = end;
140
+ while (start > 0 && opensTurn(messages[start - 1]))
141
+ start--;
142
+ return messages.slice(start);
143
+ }
144
+ /** Flatten LangChain message content (string or multimodal parts) to plain text. */
145
+ export function contentToString(content) {
146
+ if (typeof content === "string")
147
+ return content;
148
+ if (Array.isArray(content)) {
149
+ return content
150
+ .map((part) => typeof part === "string"
151
+ ? part
152
+ : typeof part?.text === "string"
153
+ ? part.text
154
+ : "")
155
+ .join("");
156
+ }
157
+ return "";
158
+ }
159
+ //# sourceMappingURL=message-readers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-readers.js","sourceRoot":"","sources":["../../src/core/message-readers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { HumanMessage } from "@langchain/core/messages";
2
+ import type { BaseMessage } from "@langchain/core/messages";
3
+ import { type RuntimeNoteKind } from "./message-readers.js";
4
+ export { contentToString, isAiMessage, isHumanMessage, isRuntimeNote, lastAgentText, lastMessageIsHuman, lastTurn, messagesSince, messageTypeOf, opensTurn, runtimeNoteKind, spokeSinceLastHumanMessage, type RuntimeNoteKind, } from "./message-readers.js";
5
+ /**
6
+ * A message the runtime wrote into a session's transcript on its own behalf, shaped
7
+ * as a **tool call and its result**: an assistant message carrying one
8
+ * {@link NOTE_TOOL} call, and the note itself as that call's result.
9
+ *
10
+ * Role is the only authorship signal a model reads; a human-role note gets
11
+ * treated as a request, and a mid-thread system message is rejected by Anthropic
12
+ * after assistant text, so notes are tool-call pairs. The pair is a transcript
13
+ * shape, not an invocation: the model never made the call, it is answered the
14
+ * instant it appears, nothing runs, and {@link NOTE_TOOL} is registered nowhere.
15
+ *
16
+ * Both messages carry the marker in `additional_kwargs` (round-trips through
17
+ * checkpointed serialization), so a host can hide the synthetic call and label
18
+ * the note without parsing content. The `[bracket]` prefix stays in the text for
19
+ * people to read; it is not the signal.
20
+ */
21
+ export declare function runtimeNote(kind: RuntimeNoteKind, text: string): BaseMessage[];
22
+ /**
23
+ * The one runtime-authored message that stays human-role: a child session's
24
+ * opening line, which is that session's *entire* transcript at that moment. A
25
+ * session has to open with a request, so it is marked rather than reshaped.
26
+ */
27
+ export declare function humanNote(kind: RuntimeNoteKind, text: string): HumanMessage;
28
+ export interface HistoryEntry {
29
+ role: string;
30
+ content: string;
31
+ toolCalls?: {
32
+ name: string;
33
+ args: unknown;
34
+ }[];
35
+ }
36
+ export interface RunContext {
37
+ history: HistoryEntry[];
38
+ userRequest: string;
39
+ }
40
+ /**
41
+ * Build the compact view a lifecycle hook and a rubric grader read: the last
42
+ * {@link HISTORY_WINDOW} messages plus the request that opened the session.
43
+ *
44
+ * `userRequest` is derived from the **whole** list, not the window: a grader
45
+ * asked whether the reply satisfies the request must see the request, and a
46
+ * session of more than a couple of tool-calling turns pushes the opening message
47
+ * out of any fixed window (issue #61).
48
+ */
49
+ export declare function runContextFromMessages(messages: unknown[]): RunContext;
@@ -0,0 +1,85 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { AIMessage, HumanMessage, ToolMessage } from "@langchain/core/messages";
3
+ import { NOTE_TOOL } from "../machine/tool-names.js";
4
+ import { contentToString, messageTypeOf, NOTE_KEY, ROLE_BY_TYPE } from "./message-readers.js";
5
+ // The readers are pure and live in `message-readers.ts` (the `@archmax-ai/harness/messages`
6
+ // subpath); re-exported so every runtime importer keeps one module for both halves.
7
+ export { contentToString, isAiMessage, isHumanMessage, isRuntimeNote, lastAgentText, lastMessageIsHuman, lastTurn, messagesSince, messageTypeOf, opensTurn, runtimeNoteKind, spokeSinceLastHumanMessage, } from "./message-readers.js";
8
+ /** The marker every message of a runtime note carries. */
9
+ function marker(kind) {
10
+ return { [NOTE_KEY]: { note: kind } };
11
+ }
12
+ /**
13
+ * A message the runtime wrote into a session's transcript on its own behalf, shaped
14
+ * as a **tool call and its result**: an assistant message carrying one
15
+ * {@link NOTE_TOOL} call, and the note itself as that call's result.
16
+ *
17
+ * Role is the only authorship signal a model reads; a human-role note gets
18
+ * treated as a request, and a mid-thread system message is rejected by Anthropic
19
+ * after assistant text, so notes are tool-call pairs. The pair is a transcript
20
+ * shape, not an invocation: the model never made the call, it is answered the
21
+ * instant it appears, nothing runs, and {@link NOTE_TOOL} is registered nowhere.
22
+ *
23
+ * Both messages carry the marker in `additional_kwargs` (round-trips through
24
+ * checkpointed serialization), so a host can hide the synthetic call and label
25
+ * the note without parsing content. The `[bracket]` prefix stays in the text for
26
+ * people to read; it is not the signal.
27
+ */
28
+ export function runtimeNote(kind, text) {
29
+ const callId = `note_${randomUUID()}`;
30
+ return [
31
+ new AIMessage({
32
+ content: "",
33
+ tool_calls: [{ id: callId, name: NOTE_TOOL, args: { note: kind } }],
34
+ additional_kwargs: marker(kind),
35
+ }),
36
+ new ToolMessage({
37
+ content: text,
38
+ tool_call_id: callId,
39
+ name: NOTE_TOOL,
40
+ additional_kwargs: marker(kind),
41
+ }),
42
+ ];
43
+ }
44
+ /**
45
+ * The one runtime-authored message that stays human-role: a child session's
46
+ * opening line, which is that session's *entire* transcript at that moment. A
47
+ * session has to open with a request, so it is marked rather than reshaped.
48
+ */
49
+ export function humanNote(kind, text) {
50
+ return new HumanMessage({ content: text, additional_kwargs: marker(kind) });
51
+ }
52
+ /** How many trailing messages a hook's compact `history` carries. */
53
+ const HISTORY_WINDOW = 24;
54
+ /** One message as a hook reads it: its role, its text, and any tool calls it made. */
55
+ function historyEntry(m) {
56
+ const msg = m;
57
+ const type = messageTypeOf(m) || "?";
58
+ const role = ROLE_BY_TYPE[type] ?? type;
59
+ const entry = { role, content: contentToString(msg.content) };
60
+ const toolCalls = msg.tool_calls;
61
+ if (Array.isArray(toolCalls) && toolCalls.length > 0) {
62
+ entry.toolCalls = toolCalls.map((c) => {
63
+ const call = c;
64
+ return { name: String(call.name ?? ""), args: call.args ?? {} };
65
+ });
66
+ }
67
+ return entry;
68
+ }
69
+ /**
70
+ * Build the compact view a lifecycle hook and a rubric grader read: the last
71
+ * {@link HISTORY_WINDOW} messages plus the request that opened the session.
72
+ *
73
+ * `userRequest` is derived from the **whole** list, not the window: a grader
74
+ * asked whether the reply satisfies the request must see the request, and a
75
+ * session of more than a couple of tool-calling turns pushes the opening message
76
+ * out of any fixed window (issue #61).
77
+ */
78
+ export function runContextFromMessages(messages) {
79
+ const all = Array.isArray(messages) ? messages : [];
80
+ const history = all.slice(-HISTORY_WINDOW).map(historyEntry);
81
+ const opening = all.find((m) => (ROLE_BY_TYPE[messageTypeOf(m) || "?"] ?? "") === "user");
82
+ const userRequest = opening !== undefined ? contentToString(opening.content) : "";
83
+ return { history, userRequest };
84
+ }
85
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/core/messages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { MountPrefixes } from "./zones.js";
2
+ /**
3
+ * The model-facing account of the governed mounts a state may reach — the mount
4
+ * twin of `renderSkillsSection`, and in the **volatile** system block for the
5
+ * same reason: what varies with the state cannot live in the cacheable prefix.
6
+ *
7
+ * The static "Workspace zones" section therefore names ungoverned mounts only
8
+ * (see {@link renderWorkspaceZones}), and this names what this state was given.
9
+ * A state that reaches none gets no heading rather than an empty one, and
10
+ * therefore no invitation to go looking.
11
+ */
12
+ /** Heading of the rendered section, also the marker tests assert on. */
13
+ export declare const MOUNTS_SECTION_HEADING = "Mounts available in this state";
14
+ /**
15
+ * Render the section for one state's enabled governed mounts, or `null` when the
16
+ * set is empty.
17
+ *
18
+ * `enabled` is the resolved name order (see `WorkflowMachine.enabledMounts`),
19
+ * sorted here so the text is stable under a spec edit that only reorders a
20
+ * list — a prompt section that reordered itself would churn the transcript for
21
+ * no reason. Each name is printed as the agent addresses it: a directory mount
22
+ * with a trailing slash, a file mount by its exact path, read-only or read/write
23
+ * per `writable` — the state's own posture (`WorkflowMachine.mountWritable`),
24
+ * which a grant's `access: read` may have narrowed below the host's. A mount the
25
+ * host declared unsearchable gets a browse-only note, so the model lists and
26
+ * reads it rather than searching it; every other line is unchanged.
27
+ */
28
+ export declare function renderMountsSection(enabled: readonly string[], mounts: MountPrefixes, writable: (name: string) => boolean): string | null;