harnery 0.34.1 → 0.35.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 (212) hide show
  1. package/dist/commander.d.ts.map +1 -1
  2. package/dist/commander.js +2 -0
  3. package/dist/commands/agents.d.ts +15 -4
  4. package/dist/commands/agents.d.ts.map +1 -1
  5. package/dist/commands/agents.js +89 -175
  6. package/dist/commands/browse.d.ts.map +1 -1
  7. package/dist/commands/browse.js +26 -2
  8. package/dist/commands/decision.d.ts.map +1 -1
  9. package/dist/commands/decision.js +2 -2
  10. package/dist/commands/events.d.ts.map +1 -1
  11. package/dist/commands/events.js +18 -1
  12. package/dist/commands/presence.d.ts.map +1 -1
  13. package/dist/commands/presence.js +2 -2
  14. package/dist/commands/semantic.d.ts +4 -0
  15. package/dist/commands/semantic.d.ts.map +1 -0
  16. package/dist/commands/semantic.js +147 -0
  17. package/dist/commands/web.d.ts.map +1 -1
  18. package/dist/commands/web.js +17 -0
  19. package/dist/core/agents/canonical-emit.d.ts +3 -0
  20. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  21. package/dist/core/agents/canonical-emit.js +12 -0
  22. package/dist/core/agents/claim-path.d.ts +11 -0
  23. package/dist/core/agents/claim-path.d.ts.map +1 -0
  24. package/dist/core/agents/claim-path.js +22 -0
  25. package/dist/core/agents/coord-client.d.ts +29 -3
  26. package/dist/core/agents/coord-client.d.ts.map +1 -1
  27. package/dist/core/agents/coord-client.js +88 -9
  28. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  29. package/dist/core/agents/live-authority-v3.js +1 -3
  30. package/dist/core/agents/live-lifecycle-v3.js +3 -3
  31. package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
  32. package/dist/core/agents/live-observation-v3.js +2 -2
  33. package/dist/core/agents/render/prompt-context.js +12 -10
  34. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  35. package/dist/core/agents/rules/stop-hook.js +23 -11
  36. package/dist/core/agents/session-name-display.d.ts +1 -0
  37. package/dist/core/agents/session-name-display.d.ts.map +1 -1
  38. package/dist/core/agents/session-name-display.js +8 -1
  39. package/dist/core/agents/state/heartbeat-reader.d.ts +46 -0
  40. package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -0
  41. package/dist/core/agents/state/heartbeat-reader.js +25 -0
  42. package/dist/core/agents/state/heartbeat-writer.d.ts +3 -48
  43. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  44. package/dist/core/agents/state/heartbeat-writer.js +16 -34
  45. package/dist/core/agents/state/live-coordination-view.d.ts +1 -1
  46. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  47. package/dist/core/agents/state/live-coordination-view.js +25 -1
  48. package/dist/core/agents/state/names.d.ts +9 -1
  49. package/dist/core/agents/state/names.d.ts.map +1 -1
  50. package/dist/core/agents/state/names.js +190 -182
  51. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  52. package/dist/core/agents/state/stale-sweep.js +23 -5
  53. package/dist/core/artifacts/constants.d.ts +5 -0
  54. package/dist/core/artifacts/constants.d.ts.map +1 -0
  55. package/dist/core/artifacts/constants.js +4 -0
  56. package/dist/core/artifacts/index.d.ts +3 -3
  57. package/dist/core/artifacts/index.d.ts.map +1 -1
  58. package/dist/core/artifacts/index.js +50 -7
  59. package/dist/core/events/v3/base-contract.d.ts +795 -0
  60. package/dist/core/events/v3/base-contract.d.ts.map +1 -1
  61. package/dist/core/events/v3/base-contract.js +33 -0
  62. package/dist/core/events/v3/capabilities.d.ts +11 -0
  63. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  64. package/dist/core/events/v3/capabilities.js +23 -0
  65. package/dist/core/events/v3/generated.d.ts +1 -1
  66. package/dist/core/events/v3/generated.js +1 -1
  67. package/dist/core/events/v3/index.d.ts +4 -3
  68. package/dist/core/events/v3/index.d.ts.map +1 -1
  69. package/dist/core/events/v3/index.js +4 -3
  70. package/dist/core/events/v3/latency.d.ts +31 -1
  71. package/dist/core/events/v3/latency.d.ts.map +1 -1
  72. package/dist/core/events/v3/latency.js +127 -3
  73. package/dist/core/events/v3/live-routing.d.ts +30 -0
  74. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  75. package/dist/core/events/v3/live-routing.js +109 -1
  76. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
  77. package/dist/core/events/v3/producers/command-recorder.js +10 -1
  78. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  79. package/dist/core/events/v3/producers/coordination-recorder.js +14 -3
  80. package/dist/core/events/v3/producers/hook-base.d.ts +17 -1
  81. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  82. package/dist/core/events/v3/producers/hook-base.js +82 -1
  83. package/dist/core/events/v3/producers/intake.d.ts +6 -0
  84. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  85. package/dist/core/events/v3/producers/intake.js +11 -0
  86. package/dist/core/events/v3/producers/recorder.d.ts +62 -0
  87. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  88. package/dist/core/events/v3/producers/recorder.js +654 -18
  89. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +51 -0
  90. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -0
  91. package/dist/core/events/v3/runtime-telemetry-capabilities.js +54 -0
  92. package/dist/core/events/v3/turn-telemetry.d.ts +9 -0
  93. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
  94. package/dist/core/hooks/adapter/parse.d.ts +3 -0
  95. package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
  96. package/dist/core/hooks/adapter/parse.js +14 -0
  97. package/dist/core/hooks/adapter/runtime-telemetry.d.ts +119 -0
  98. package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -0
  99. package/dist/core/hooks/adapter/runtime-telemetry.js +568 -0
  100. package/dist/core/hooks/cli.js +111 -36
  101. package/dist/core/hooks/remediation-cap.d.ts +34 -0
  102. package/dist/core/hooks/remediation-cap.d.ts.map +1 -0
  103. package/dist/core/hooks/remediation-cap.js +71 -0
  104. package/dist/core/hooks/resolve/transcript.d.ts +25 -9
  105. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  106. package/dist/core/hooks/resolve/transcript.js +22 -10
  107. package/dist/core/semantic/adapters.d.ts +34 -0
  108. package/dist/core/semantic/adapters.d.ts.map +1 -0
  109. package/dist/core/semantic/adapters.js +222 -0
  110. package/dist/core/semantic/contract.d.ts +588 -0
  111. package/dist/core/semantic/contract.d.ts.map +1 -0
  112. package/dist/core/semantic/contract.js +230 -0
  113. package/dist/core/semantic/evidence.d.ts +11 -0
  114. package/dist/core/semantic/evidence.d.ts.map +1 -0
  115. package/dist/core/semantic/evidence.js +262 -0
  116. package/dist/core/semantic/index.d.ts +10 -0
  117. package/dist/core/semantic/index.d.ts.map +1 -0
  118. package/dist/core/semantic/index.js +9 -0
  119. package/dist/core/semantic/once.d.ts +33 -0
  120. package/dist/core/semantic/once.d.ts.map +1 -0
  121. package/dist/core/semantic/once.js +293 -0
  122. package/dist/core/semantic/prompt.d.ts +12 -0
  123. package/dist/core/semantic/prompt.d.ts.map +1 -0
  124. package/dist/core/semantic/prompt.js +70 -0
  125. package/dist/core/semantic/scheduler.d.ts +16 -0
  126. package/dist/core/semantic/scheduler.d.ts.map +1 -0
  127. package/dist/core/semantic/scheduler.js +67 -0
  128. package/dist/core/semantic/service-status.d.ts +31 -0
  129. package/dist/core/semantic/service-status.d.ts.map +1 -0
  130. package/dist/core/semantic/service-status.js +84 -0
  131. package/dist/core/semantic/service.d.ts +51 -0
  132. package/dist/core/semantic/service.d.ts.map +1 -0
  133. package/dist/core/semantic/service.js +470 -0
  134. package/dist/core/semantic/storage.d.ts +71 -0
  135. package/dist/core/semantic/storage.d.ts.map +1 -0
  136. package/dist/core/semantic/storage.js +179 -0
  137. package/dist/core/semantic/validate.d.ts +16 -0
  138. package/dist/core/semantic/validate.d.ts.map +1 -0
  139. package/dist/core/semantic/validate.js +174 -0
  140. package/dist/lib/browser/client.d.ts +11 -0
  141. package/dist/lib/browser/client.d.ts.map +1 -1
  142. package/dist/lib/browser/client.js +13 -0
  143. package/dist/lib/browser/index.d.ts +1 -0
  144. package/dist/lib/browser/index.d.ts.map +1 -1
  145. package/dist/lib/browser/standalone-html.d.ts +25 -0
  146. package/dist/lib/browser/standalone-html.d.ts.map +1 -0
  147. package/dist/lib/browser/standalone-html.js +284 -0
  148. package/dist/lib/instructions/apply.d.ts.map +1 -1
  149. package/dist/lib/instructions/apply.js +1 -0
  150. package/dist/lib/instructions/templates.d.ts +2 -0
  151. package/dist/lib/instructions/templates.d.ts.map +1 -1
  152. package/dist/lib/instructions/templates.js +144 -4
  153. package/package.json +6 -1
  154. package/schemas/event-v3.schema.json +2758 -478
  155. package/src/commander.ts +2 -0
  156. package/src/commands/agents.ts +102 -167
  157. package/src/commands/browse.ts +25 -2
  158. package/src/commands/decision.ts +8 -2
  159. package/src/commands/events.ts +21 -1
  160. package/src/commands/presence.ts +7 -2
  161. package/src/commands/semantic.ts +179 -0
  162. package/src/commands/web.ts +15 -0
  163. package/src/core/agents/canonical-emit.ts +15 -0
  164. package/src/core/agents/claim-path.ts +23 -0
  165. package/src/core/agents/coord-client.ts +92 -8
  166. package/src/core/agents/live-authority-v3.ts +1 -4
  167. package/src/core/agents/live-lifecycle-v3.ts +8 -3
  168. package/src/core/agents/live-observation-v3.ts +7 -2
  169. package/src/core/agents/render/prompt-context.ts +13 -10
  170. package/src/core/agents/rules/stop-hook.ts +24 -11
  171. package/src/core/agents/session-name-display.ts +9 -1
  172. package/src/core/agents/state/heartbeat-reader.ts +69 -0
  173. package/src/core/agents/state/heartbeat-writer.ts +20 -84
  174. package/src/core/agents/state/live-coordination-view.ts +26 -1
  175. package/src/core/agents/state/names.ts +190 -182
  176. package/src/core/agents/state/stale-sweep.ts +25 -5
  177. package/src/core/artifacts/constants.ts +4 -0
  178. package/src/core/artifacts/index.ts +49 -7
  179. package/src/core/events/v3/base-contract.ts +39 -0
  180. package/src/core/events/v3/capabilities.ts +34 -0
  181. package/src/core/events/v3/generated.ts +1 -1
  182. package/src/core/events/v3/index.ts +21 -0
  183. package/src/core/events/v3/latency.ts +213 -2
  184. package/src/core/events/v3/live-routing.ts +120 -1
  185. package/src/core/events/v3/producers/command-recorder.ts +10 -1
  186. package/src/core/events/v3/producers/coordination-recorder.ts +17 -5
  187. package/src/core/events/v3/producers/hook-base.ts +115 -1
  188. package/src/core/events/v3/producers/intake.ts +18 -0
  189. package/src/core/events/v3/producers/recorder.ts +856 -21
  190. package/src/core/events/v3/runtime-telemetry-capabilities.ts +137 -0
  191. package/src/core/events/v3/turn-telemetry.ts +10 -0
  192. package/src/core/hooks/adapter/parse.ts +16 -0
  193. package/src/core/hooks/adapter/runtime-telemetry.ts +805 -0
  194. package/src/core/hooks/cli.ts +123 -39
  195. package/src/core/hooks/remediation-cap.ts +77 -0
  196. package/src/core/hooks/resolve/transcript.ts +37 -11
  197. package/src/core/semantic/adapters.ts +293 -0
  198. package/src/core/semantic/contract.ts +298 -0
  199. package/src/core/semantic/evidence.ts +336 -0
  200. package/src/core/semantic/index.ts +127 -0
  201. package/src/core/semantic/once.ts +410 -0
  202. package/src/core/semantic/prompt.ts +84 -0
  203. package/src/core/semantic/scheduler.ts +107 -0
  204. package/src/core/semantic/service-status.ts +118 -0
  205. package/src/core/semantic/service.ts +580 -0
  206. package/src/core/semantic/storage.ts +286 -0
  207. package/src/core/semantic/validate.ts +212 -0
  208. package/src/lib/browser/client.ts +21 -0
  209. package/src/lib/browser/index.ts +4 -0
  210. package/src/lib/browser/standalone-html.ts +312 -0
  211. package/src/lib/instructions/apply.ts +1 -0
  212. package/src/lib/instructions/templates.ts +149 -4
@@ -0,0 +1,284 @@
1
+ // Self-contained HTML snapshots for `harn browse` trio mode.
2
+ //
3
+ // `page.content()` serializes the DOM but not the resources it points at, and
4
+ // framework pages reference those with root-absolute paths (`/_next/static/…`).
5
+ // Written to a file and reopened from anywhere else — the files origin, another
6
+ // host, `file://` — every one of those paths resolves against the wrong root and
7
+ // 404s, so the snapshot renders as unstyled black-on-white text with broken
8
+ // images. That is what an operator sees when they preview an artifact's `.html`.
9
+ //
10
+ // This rewrite makes the saved document stand on its own:
11
+ // - stylesheets are fetched and inlined as <style>
12
+ // - fonts, images, and icons are inlined as data: URIs under a byte budget
13
+ // - anything left over (too large, cross-origin, unreachable) is rewritten to
14
+ // an absolute URL on the captured origin rather than left root-relative
15
+ // - <script> and preload/prefetch hints are dropped: none of them can work in
16
+ // a snapshot, and a dead script tag only invites a hydration attempt
17
+ //
18
+ // The live page is untouched — everything happens on a clone of the document.
19
+ /** Byte budget for one inlined sub-resource. Larger ones stay as absolute URLs. */
20
+ export const DEFAULT_MAX_RESOURCE_BYTES = 512 * 1024;
21
+ /** Byte budget for all inlined sub-resources in one snapshot. */
22
+ export const DEFAULT_MAX_TOTAL_RESOURCE_BYTES = 8 * 1024 * 1024;
23
+ export function buildStandaloneHtmlScript() {
24
+ return async ({ maxResourceBytes, maxTotalResourceBytes }) => {
25
+ const SKIP = /^(?:data:|blob:|javascript:|mailto:|tel:|sms:|about:|#)/i;
26
+ const base = document.baseURI;
27
+ let inlinedBytes = 0;
28
+ let resourcesInlined = 0;
29
+ let resourcesLinked = 0;
30
+ let stylesheetsInlined = 0;
31
+ let stylesheetsLinked = 0;
32
+ const absolute = (url, from) => {
33
+ try {
34
+ return new URL(url, from).href;
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ };
40
+ const dataUriCache = new Map();
41
+ /** Fetch a resource as a data: URI, or null when it is unreachable or over budget. */
42
+ const toDataUri = async (url) => {
43
+ const cached = dataUriCache.get(url);
44
+ if (cached !== undefined)
45
+ return cached;
46
+ let result = null;
47
+ try {
48
+ const res = await fetch(url, { credentials: "include" });
49
+ if (res.ok) {
50
+ const buf = await res.arrayBuffer();
51
+ const fits = buf.byteLength <= maxResourceBytes &&
52
+ inlinedBytes + buf.byteLength <= maxTotalResourceBytes;
53
+ if (fits) {
54
+ const bytes = new Uint8Array(buf);
55
+ let binary = "";
56
+ const chunk = 0x8000;
57
+ for (let i = 0; i < bytes.length; i += chunk) {
58
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
59
+ }
60
+ const type = (res.headers.get("content-type") ?? "").split(";")[0]?.trim();
61
+ result = `data:${type || "application/octet-stream"};base64,${btoa(binary)}`;
62
+ inlinedBytes += buf.byteLength;
63
+ }
64
+ }
65
+ }
66
+ catch {
67
+ result = null;
68
+ }
69
+ dataUriCache.set(url, result);
70
+ return result;
71
+ };
72
+ /** Resolve one reference: data: URI when it fits, absolute URL otherwise. */
73
+ const resolveRef = async (raw, from, inline) => {
74
+ const trimmed = raw.trim();
75
+ if (!trimmed || SKIP.test(trimmed))
76
+ return null;
77
+ const url = absolute(trimmed, from);
78
+ if (!url)
79
+ return null;
80
+ if (!inline)
81
+ return url;
82
+ const dataUri = await toDataUri(url);
83
+ if (dataUri) {
84
+ resourcesInlined += 1;
85
+ return dataUri;
86
+ }
87
+ resourcesLinked += 1;
88
+ return url;
89
+ };
90
+ /** Rewrite url() and @import references inside a stylesheet against its own URL. */
91
+ const rewriteCss = async (css, from) => {
92
+ const urlRef = /url\(\s*(['"]?)([^'")]*)\1\s*\)/g;
93
+ const importRef = /@import\s+(['"])([^'"]+)\1/g;
94
+ const replacements = new Map();
95
+ const collect = async (pattern, inline) => {
96
+ pattern.lastIndex = 0;
97
+ const seen = [];
98
+ for (let m = pattern.exec(css); m; m = pattern.exec(css)) {
99
+ const raw = m[2];
100
+ if (raw !== undefined && !replacements.has(raw))
101
+ seen.push(raw);
102
+ }
103
+ for (const raw of seen) {
104
+ const resolved = await resolveRef(raw, from, inline);
105
+ if (resolved)
106
+ replacements.set(raw, resolved);
107
+ }
108
+ };
109
+ await collect(urlRef, true);
110
+ await collect(importRef, false);
111
+ return css
112
+ .replace(urlRef, (full, _q, raw) => {
113
+ const next = replacements.get(raw);
114
+ return next ? `url("${next}")` : full;
115
+ })
116
+ .replace(importRef, (full, _q, raw) => {
117
+ const next = replacements.get(raw);
118
+ return next ? `@import "${next}"` : full;
119
+ });
120
+ };
121
+ const doc = document.cloneNode(true);
122
+ // Nothing executable survives a snapshot; leaving these in only produces
123
+ // console noise and a doomed hydration pass on reopen.
124
+ for (const node of Array.from(doc.querySelectorAll("script, base")))
125
+ node.remove();
126
+ const deadHints = 'link[rel~="preload"],link[rel~="modulepreload"],link[rel~="prefetch"]';
127
+ for (const node of Array.from(doc.querySelectorAll(deadHints)))
128
+ node.remove();
129
+ // Stylesheets: fetch → inline. Falls back to the CSSOM (which covers rules a
130
+ // same-origin sheet already parsed) and finally to an absolute <link>.
131
+ for (const link of Array.from(doc.querySelectorAll('link[rel~="stylesheet"]'))) {
132
+ const href = link.getAttribute("href");
133
+ const url = href ? absolute(href, base) : null;
134
+ if (!url) {
135
+ link.remove();
136
+ continue;
137
+ }
138
+ let css = null;
139
+ try {
140
+ const res = await fetch(url, { credentials: "include" });
141
+ if (res.ok)
142
+ css = await res.text();
143
+ }
144
+ catch {
145
+ css = null;
146
+ }
147
+ if (css === null) {
148
+ for (const sheet of Array.from(document.styleSheets)) {
149
+ if (sheet.href !== url)
150
+ continue;
151
+ try {
152
+ css = Array.from(sheet.cssRules)
153
+ .map((rule) => rule.cssText)
154
+ .join("\n");
155
+ }
156
+ catch {
157
+ css = null;
158
+ }
159
+ break;
160
+ }
161
+ }
162
+ if (css === null) {
163
+ link.setAttribute("href", url);
164
+ stylesheetsLinked += 1;
165
+ continue;
166
+ }
167
+ const style = doc.createElement("style");
168
+ style.setAttribute("data-harnery-inlined-from", url);
169
+ const media = link.getAttribute("media");
170
+ if (media)
171
+ style.setAttribute("media", media);
172
+ style.textContent = await rewriteCss(css, url);
173
+ link.replaceWith(style);
174
+ stylesheetsInlined += 1;
175
+ }
176
+ // Inline <style> blocks carry their own relative refs (framework @font-face
177
+ // rules in particular), so they need the same treatment.
178
+ for (const style of Array.from(doc.querySelectorAll("style"))) {
179
+ if (style.hasAttribute("data-harnery-inlined-from"))
180
+ continue;
181
+ const css = style.textContent;
182
+ if (css)
183
+ style.textContent = await rewriteCss(css, base);
184
+ }
185
+ // Stylesheets adopted via CSSOM never appear in the DOM and would be lost.
186
+ const adopted = document
187
+ .adoptedStyleSheets;
188
+ if (adopted?.length) {
189
+ const parts = [];
190
+ for (const sheet of adopted) {
191
+ try {
192
+ parts.push(Array.from(sheet.cssRules)
193
+ .map((rule) => rule.cssText)
194
+ .join("\n"));
195
+ }
196
+ catch {
197
+ // Constructed sheet with unreadable rules; nothing to recover.
198
+ }
199
+ }
200
+ if (parts.length) {
201
+ const style = doc.createElement("style");
202
+ style.setAttribute("data-harnery-adopted", "");
203
+ style.textContent = await rewriteCss(parts.join("\n"), base);
204
+ doc.head?.appendChild(style);
205
+ }
206
+ }
207
+ // Element references. Media and icons are worth inlining; navigation targets
208
+ // only need to stop pointing at the wrong root.
209
+ const inlineAttrs = [
210
+ ["img", "src"],
211
+ ["source", "src"],
212
+ ["video", "src"],
213
+ ["video", "poster"],
214
+ ["audio", "src"],
215
+ ["track", "src"],
216
+ ["input", "src"],
217
+ ["object", "data"],
218
+ ['link[rel~="icon"]', "href"],
219
+ ['link[rel~="apple-touch-icon"]', "href"],
220
+ ["image", "href"],
221
+ ["use", "href"],
222
+ ];
223
+ const absoluteAttrs = [
224
+ ["a", "href"],
225
+ ["area", "href"],
226
+ ["form", "action"],
227
+ ["iframe", "src"],
228
+ ["embed", "src"],
229
+ ["link", "href"],
230
+ ];
231
+ const applyAttrs = async (specs, inline) => {
232
+ for (const [selector, attr] of specs) {
233
+ for (const el of Array.from(doc.querySelectorAll(selector))) {
234
+ const raw = el.getAttribute(attr);
235
+ if (!raw)
236
+ continue;
237
+ const next = await resolveRef(raw, base, inline);
238
+ if (next)
239
+ el.setAttribute(attr, next);
240
+ }
241
+ }
242
+ };
243
+ await applyAttrs(inlineAttrs, true);
244
+ await applyAttrs(absoluteAttrs, false);
245
+ // srcset is a comma-separated list of `url descriptor` pairs.
246
+ for (const el of Array.from(doc.querySelectorAll("img[srcset], source[srcset]"))) {
247
+ const raw = el.getAttribute("srcset");
248
+ if (!raw)
249
+ continue;
250
+ const rewritten = [];
251
+ for (const candidate of raw.split(",")) {
252
+ const parts = candidate.trim().split(/\s+/);
253
+ const url = parts.shift();
254
+ if (!url)
255
+ continue;
256
+ const next = (await resolveRef(url, base, true)) ?? url;
257
+ rewritten.push([next, ...parts].join(" "));
258
+ }
259
+ if (rewritten.length)
260
+ el.setAttribute("srcset", rewritten.join(", "));
261
+ }
262
+ // Inline style attributes can carry background-image url().
263
+ for (const el of Array.from(doc.querySelectorAll("[style]"))) {
264
+ const raw = el.getAttribute("style");
265
+ if (!raw?.includes("url("))
266
+ continue;
267
+ el.setAttribute("style", await rewriteCss(raw, base));
268
+ }
269
+ const provenance = doc.createElement("meta");
270
+ provenance.setAttribute("name", "harnery:snapshot-source");
271
+ provenance.setAttribute("content", location.href);
272
+ doc.head?.prepend(provenance);
273
+ const doctype = document.doctype ? `<!DOCTYPE ${document.doctype.name}>` : "<!DOCTYPE html>";
274
+ return {
275
+ html: `${doctype}\n${doc.documentElement.outerHTML}\n`,
276
+ source: location.href,
277
+ stylesheetsInlined,
278
+ stylesheetsLinked,
279
+ resourcesInlined,
280
+ resourcesLinked,
281
+ inlinedBytes,
282
+ };
283
+ };
284
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/lib/instructions/apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAsDH,sFAAsF;AACtF,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAYlE;AAkBD,UAAU,SAAS;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,WAAW,CA+GnF;AAED,UAAU,UAAU;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,WAAW,CAkFrF;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IACpC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzC,WAAW,CAkDb"}
1
+ {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/lib/instructions/apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAsDH,sFAAsF;AACtF,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAYlE;AAmBD,UAAU,SAAS;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,WAAW,CA+GnF;AAED,UAAU,UAAU;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,WAAW,CAkFrF;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IACpC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzC,WAAW,CAkDb"}
@@ -70,6 +70,7 @@ function blockSkills(projectRoot, adapter) {
70
70
  decide: supported && !exclude.has("harn-decide"),
71
71
  council: supported && !exclude.has("harn-council"),
72
72
  end: supported && !exclude.has("harn-end"),
73
+ team: supported && !exclude.has("harn-team"),
73
74
  };
74
75
  }
75
76
  /**
@@ -29,6 +29,8 @@ export interface BlockSkills {
29
29
  council: boolean;
30
30
  /** the `harn-end` skill file is present */
31
31
  end: boolean;
32
+ /** the `harn-team` skill file is present */
33
+ team: boolean;
32
34
  }
33
35
  /**
34
36
  * The always-on orientation spliced into `AGENTS.md`. Target ≤ 80 rendered
@@ -1 +1 @@
1
- {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/lib/instructions/templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAClD,sEAAsE;AACtE,eAAO,MAAM,aAAa,WAAW,CAAC;AACtC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AAEpD,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,MAAM,EAAE,OAAO,CAAC;IAChB,+CAA+C;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,2CAA2C;IAC3C,GAAG,EAAE,OAAO,CAAC;CACd;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,WAAwD,GAC/D,MAAM,CA+FR;AAID,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC;AAsND,eAAO,MAAM,MAAM,EAAE,aAAa,EAqCjC,CAAC"}
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/lib/instructions/templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAClD,sEAAsE;AACtE,eAAO,MAAM,aAAa,WAAW,CAAC;AACtC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AAEpD,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,MAAM,EAAE,OAAO,CAAC;IAChB,+CAA+C;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,2CAA2C;IAC3C,GAAG,EAAE,OAAO,CAAC;IACb,4CAA4C;IAC5C,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,WAAoE,GAC3E,MAAM,CAqGR;AAID,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC;AAmVD,eAAO,MAAM,MAAM,EAAE,aAAa,EAiDjC,CAAC"}
@@ -35,12 +35,13 @@ export const HOST_ADDENDUM_REGION = "host-addendum";
35
35
  * excludes one via `skills.exclude` gets a CLI pointer instead of a dangling
36
36
  * reference to a skill it doesn't have.
37
37
  */
38
- export function renderInstructionsBlock(binName, skills = { decide: true, council: true, end: true }) {
38
+ export function renderInstructionsBlock(binName, skills = { decide: true, council: true, end: true, team: true }) {
39
39
  const b = binName;
40
40
  const named = [
41
41
  skills.decide && "`harn-decide`",
42
42
  skills.council && "`harn-council`",
43
43
  skills.end && "`harn-end`",
44
+ skills.team && "`harn-team`",
44
45
  ].filter(Boolean);
45
46
  const deeper = named.length > 0
46
47
  ? `Procedures for the deeper flows live in the ${named.join(" and ")} skill${named.length > 1 ? "s" : ""}.`
@@ -54,6 +55,9 @@ export function renderInstructionsBlock(binName, skills = { decide: true, counci
54
55
  const endPointer = skills.end
55
56
  ? "When the whole session is genuinely finished, use the `harn-end` skill as the final workflow."
56
57
  : `When the whole session is genuinely finished, run \`${b} agents status --end-turn --end-session\` as the final tool action.`;
58
+ const teamPointer = skills.team
59
+ ? "The `harn-team` skill owns the tier choice, the governor artifacts, and the drive loop."
60
+ : `See \`${b} governor --help\` for the tier choice and the drive loop.`;
57
61
  // Render the journal categories from the canonical enum so this prose can
58
62
  // never drift from what `journal add` actually accepts (the "note, plan…" list
59
63
  // silently lagged the tool by two categories before this).
@@ -95,6 +99,7 @@ first when one pass will do, the second when the objective must outlive the
95
99
  attempt, and the third when a human would otherwise have to babysit the loop. A
96
100
  run that needs authorization parks durably instead of failing, so check
97
101
  \`${b} approval list\` when one appears to be waiting rather than stuck.
102
+ ${teamPointer}
98
103
 
99
104
  **Durable role handoff.** When you are replacing a prior session in the same
100
105
  named role, run \`${b} agents identity assume <name>\` before declaring your task.
@@ -103,9 +108,10 @@ live process still holds the name; never hand-edit Harnery's history, heartbeat,
103
108
  or derived identity cache.
104
109
 
105
110
  **Declare intent on shell commands.** Every command you run is captured to the
106
- coordination ledger. Lead a shell command with a \`# intent: <why>\` comment (or set
107
- the tool's description) so the recorded event carries a reason instead of
108
- \`(no intent)\`.
111
+ coordination ledger (\`.harnery/ledgers/v3/\`). Lead a shell command with a
112
+ \`# intent: <why>\` comment (or set the tool's description) so the recorded event
113
+ carries a reason instead of \`(no intent)\`; the [tool-intent
114
+ guide](https://harnery.com/guides/tool-intent/) owns the details.
109
115
 
110
116
  **Journal.** \`${b} journal add <category> "<text>"\` (category = ${journalCats})
111
117
  leaves breadcrumbs that survive context compaction;
@@ -336,6 +342,130 @@ explicitly identifies it. Use the web control or \`${b} agents end --instance-id
336
342
  <id>\` for that operator action; it records immediately for an idle session or
337
343
  durably queues the end for its current turn.`;
338
344
  }
345
+ function teamBody(b) {
346
+ return `Harnery gives you three ways to put more than one agent on a job. They differ
347
+ by how long the objective outlives a single execution, and picking the wrong one
348
+ is the usual reason a team spins. This skill owns that choice, the files a
349
+ governed team needs, and the drive loop.
350
+
351
+ ## Step 0: do not build a second team
352
+
353
+ Run this before anything else, every time:
354
+
355
+ \`\`\`bash
356
+ ${b} governor list
357
+ \`\`\`
358
+
359
+ If a goal already covers the objective, **you are done building** — drive the
360
+ existing one (Step 3). A second team pointed at the same tree fights the first:
361
+ both hold the same files and their frozen missions contradict each other. It is
362
+ the most expensive mistake available here, and it looks like progress while you
363
+ make it. Listings are tolerant: an unreadable record prints a warning row with
364
+ its id, which is evidence the goal *exists* — inspect it before creating a
365
+ replacement. Treat stale or suffixed experiment goals as shared runtime state;
366
+ archiving them is an operator call, not yours.
367
+
368
+ ## Step 1: pick the tier
369
+
370
+ Match the tier to how long the objective must survive, not to how big it feels.
371
+
372
+ | Surface | Use when | Dies when |
373
+ |---|---|---|
374
+ | \`${b} run <script>\` | One bounded pass: deterministic JS stages fan out to headless subagents. | The pass ends. Nothing remembers it. |
375
+ | \`${b} work create <title> <workflow>\` | The objective must outlive the attempt: retries, failures, review rounds. | You accept or cancel it. |
376
+ | \`${b} governor create\` | A graph of interdependent work with distinct roles, where a human would otherwise babysit the loop. | You accept the root or it exhausts its bounds. |
377
+
378
+ When unsure, start with \`${b} run\`: it is the only tier you can throw away for
379
+ free, and iterating a script there before freezing it is how you avoid
380
+ invalidating a durable work item later. And check the sizing first: a single
381
+ agent often matches a team on a task that does not truly decompose — reliability
382
+ is multiplicative across steps, and the metric that decides is cost per
383
+ completed task, not agent count.
384
+
385
+ ## Step 2: build the governor team
386
+
387
+ Four artifacts, kept in a managed workspace
388
+ (\`${b} artifacts create <slug> --purpose "<why>"\`), then frozen:
389
+
390
+ **team.json** maps specialist id to profile: \`instructions\` (the role's whole
391
+ charter) plus optional \`adapter\`, \`effort\`, \`maxAttempts\`. Two role rules
392
+ carry most of the value: **split producing evidence from judging it** (a
393
+ verifier that runs gates, a separate reviewer that accepts or refuses — no agent
394
+ grades its own homework), and **add a standing scope-auditor** that reports at
395
+ each milestone whether the finish line moved, since no one else is positioned to
396
+ notice a rising bar. Write each role's hard boundaries explicitly, in the
397
+ negative: name every act that is somebody else's. Write every brief as a
398
+ four-part contract — objective, output (the named artifact that proves it),
399
+ tools, boundaries — and pass references, not pasted content. \`timeoutMs\` and
400
+ \`maxTurns\` are workflow-script options, never specialist-profile keys; the
401
+ create command rejects unsupported keys with the offending key and the allowed
402
+ set.
403
+
404
+ **mission.json** carries \`objective\`, \`acceptance\` (criteria), and
405
+ \`max_milestones\`. Write acceptance so **refusing is a representable outcome**
406
+ ("X exists, or the blocker is stated with its citation") — a criterion an agent
407
+ cannot satisfy by correctly refusing gets reissued forever. Every criterion
408
+ names the artifact that satisfies it (a path, a passing command, a review
409
+ record); a criterion satisfiable by prose will eventually be satisfied exactly
410
+ that way.
411
+
412
+ **replanning.json** freezes the planner policy: \`planner_specialist\`,
413
+ \`auto_apply\`, \`max_replans\`, \`max_work_items_per_plan\`,
414
+ \`max_total_work_items\`, a \`templates\` catalog, and \`review\` with
415
+ \`reviewer_specialists\` and \`max_revision_rounds\`. Keep \`auto_apply: false\`
416
+ and proof auto-acceptance off for anything that can touch public state.
417
+
418
+ **Workflow templates** are the plain-JS scripts the planner may choose from;
419
+ route product decisions to a decision-brief template, never an implement one.
420
+ Authoring traps (frozen script hashes, the five-minute \`timeoutMs\` default,
421
+ schema caps, child sandboxes) live in the
422
+ [workflow-authoring guide](https://harnery.com/guides/workflow-authoring/).
423
+
424
+ \`\`\`bash
425
+ ${b} governor create --id <goal-id> --title "<title>" \\
426
+ --team <ws>/team.json --mission <ws>/mission.json \\
427
+ --replanning <ws>/replanning.json --max-parallel-work 2 --json
428
+ \`\`\`
429
+
430
+ ## Step 3: drive it
431
+
432
+ \`${b} governor show <goal-id> --json\` — the \`projection\` object is the whole
433
+ dashboard: read \`state\`, \`reason\`, and \`next_action\`, then do exactly that
434
+ action. Useful fields: \`ready_work\` / \`retryable_work\` / \`attention_work\`,
435
+ \`decision_blocked_work\` (parked on a docket entry, not broken),
436
+ \`replans_used\` / \`replans_remaining\`, and the milestone counters.
437
+
438
+ \`\`\`bash
439
+ ${b} governor tick <goal-id> # at most one scheduling cycle
440
+ ${b} governor run <goal-id> # cycles until success, attention, or budget
441
+ ${b} approval list # a run needing authorization parks, not fails
442
+ \`\`\`
443
+
444
+ Rules that prevent stranded work:
445
+
446
+ - **Never drive a governed item with \`${b} work retry\` or \`${b} work run\`.**
447
+ Only the governor supplies the frozen specialist map; a bare retry starts a
448
+ run with no team, dies at the first specialist stage, and still burns the
449
+ attempt. \`${b} work retry\` is for standalone work only.
450
+ - **A blocked item cannot be accepted.** When its objective was met out of band,
451
+ the door back is \`${b} work reopen\` plus a fresh governor cycle, not accept.
452
+ - **Read the spin signals before retrying.** Zero milestones with climbing
453
+ \`replans_used\` and repeated reviewer rejections means the mission prose or
454
+ acceptance criteria are wrong, not the agents. Replans are capped; diagnose
455
+ first.
456
+ - **A frozen mission cannot be edited** — deliberately. Pass corrections as
457
+ retry context on individual items, or create a new goal and cancel the old
458
+ one. Do not keep re-planning against prose you know is stale.
459
+ - **"ended without terminal evidence"** means the child died before writing its
460
+ proof, not that the work failed. Check whether the outcome landed before
461
+ redoing it.
462
+
463
+ ## Reporting back
464
+
465
+ Tell the operator which tier you chose and why, the goal id, the roles, and the
466
+ single next action. If you declined to build a team because one already existed,
467
+ say that first; it is the most useful sentence in the reply.`;
468
+ }
339
469
  export const SKILLS = [
340
470
  {
341
471
  id: "harn-decide",
@@ -367,4 +497,14 @@ export const SKILLS = [
367
497
  body: endBody(binName),
368
498
  }),
369
499
  },
500
+ {
501
+ id: "harn-team",
502
+ relPath: "harn-team/SKILL.md",
503
+ render: (binName) => buildOwnedSkill({
504
+ name: "harn-team",
505
+ description: "Stand up and drive a multi-agent team on an objective: pick between a bounded run, durable work, and a governed role team; build the governor artifacts; drive off projection.next_action. Use when asked to put a team of agents on a job, orchestrate agents, or check on a goal already running. Refuses to build a second team when one already covers the objective.",
506
+ binName,
507
+ body: teamBody(binName),
508
+ }),
509
+ },
370
510
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harnery",
3
- "version": "0.34.1",
3
+ "version": "0.35.0",
4
4
  "description": "Multi-agent coordination for AI coding agents - Claude Code, Cursor, and Codex.",
5
5
  "license": "MIT",
6
6
  "author": "Ryan Kelly",
@@ -102,6 +102,11 @@
102
102
  "types": "./dist/core/events/v3/index.d.ts",
103
103
  "import": "./dist/core/events/v3/index.js"
104
104
  },
105
+ "./core/semantic": {
106
+ "bun": "./src/core/semantic/index.ts",
107
+ "types": "./dist/core/semantic/index.d.ts",
108
+ "import": "./dist/core/semantic/index.js"
109
+ },
105
110
  "./core/governor/plans": {
106
111
  "bun": "./src/core/governor/plan-read.ts",
107
112
  "types": "./dist/core/governor/plan-read.d.ts",