waterplane 0.1.17 → 0.1.19

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 (280) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/NOTICES.md +18 -7
  3. package/README.md +46 -2
  4. package/SECURITY.md +196 -12
  5. package/node_modules/@waterplane/shared/dist/desktopfiles.d.ts +24 -2
  6. package/node_modules/@waterplane/shared/dist/desktopfiles.js +73 -3
  7. package/node_modules/@waterplane/shared/dist/desktopfiles.js.map +1 -1
  8. package/node_modules/@waterplane/shared/dist/hosts.d.ts +31 -0
  9. package/node_modules/@waterplane/shared/dist/hosts.js +46 -1
  10. package/node_modules/@waterplane/shared/dist/hosts.js.map +1 -1
  11. package/node_modules/@waterplane/shared/dist/hosturl.d.ts +55 -0
  12. package/node_modules/@waterplane/shared/dist/hosturl.js +85 -0
  13. package/node_modules/@waterplane/shared/dist/hosturl.js.map +1 -1
  14. package/node_modules/@waterplane/shared/dist/index.d.ts +4 -0
  15. package/node_modules/@waterplane/shared/dist/index.js +4 -0
  16. package/node_modules/@waterplane/shared/dist/index.js.map +1 -1
  17. package/node_modules/@waterplane/shared/dist/installrow.d.ts +6 -1
  18. package/node_modules/@waterplane/shared/dist/installrow.js +20 -1
  19. package/node_modules/@waterplane/shared/dist/installrow.js.map +1 -1
  20. package/node_modules/@waterplane/shared/dist/lanroute.d.ts +5 -0
  21. package/node_modules/@waterplane/shared/dist/lanroute.js.map +1 -1
  22. package/node_modules/@waterplane/shared/dist/pairing.d.ts +96 -2
  23. package/node_modules/@waterplane/shared/dist/pairing.js +71 -3
  24. package/node_modules/@waterplane/shared/dist/pairing.js.map +1 -1
  25. package/node_modules/@waterplane/shared/dist/pake.d.ts +131 -0
  26. package/node_modules/@waterplane/shared/dist/pake.js +272 -0
  27. package/node_modules/@waterplane/shared/dist/pake.js.map +1 -0
  28. package/node_modules/@waterplane/shared/dist/peer.d.ts +63 -0
  29. package/node_modules/@waterplane/shared/dist/peer.js +41 -0
  30. package/node_modules/@waterplane/shared/dist/peer.js.map +1 -1
  31. package/node_modules/@waterplane/shared/dist/plugin/api.d.ts +15 -0
  32. package/node_modules/@waterplane/shared/dist/plugin/version.d.ts +5 -1
  33. package/node_modules/@waterplane/shared/dist/plugin/version.js +5 -1
  34. package/node_modules/@waterplane/shared/dist/plugin/version.js.map +1 -1
  35. package/node_modules/@waterplane/shared/dist/repotwins.d.ts +47 -0
  36. package/node_modules/@waterplane/shared/dist/repotwins.js +80 -0
  37. package/node_modules/@waterplane/shared/dist/repotwins.js.map +1 -1
  38. package/node_modules/@waterplane/shared/dist/sessioncost/costwords.d.ts +7 -2
  39. package/node_modules/@waterplane/shared/dist/sessioncost/costwords.js +6 -3
  40. package/node_modules/@waterplane/shared/dist/sessioncost/costwords.js.map +1 -1
  41. package/node_modules/@waterplane/shared/dist/waiting.d.ts +64 -0
  42. package/node_modules/@waterplane/shared/dist/waiting.js +86 -0
  43. package/node_modules/@waterplane/shared/dist/waiting.js.map +1 -0
  44. package/node_modules/@waterplane/shared/dist/wire/messages/hostcore.d.ts +3 -0
  45. package/node_modules/@waterplane/shared/dist/wire/notify.d.ts +2 -0
  46. package/node_modules/@waterplane/shared/dist/wire/notify.js +2 -0
  47. package/node_modules/@waterplane/shared/dist/wire/notify.js.map +1 -1
  48. package/node_modules/@waterplane/shared/dist/wire/repo.d.ts +30 -1
  49. package/node_modules/@waterplane/shared/dist/wire/repo.js.map +1 -1
  50. package/node_modules/@waterplane/shared/dist/wire/session/context.d.ts +4 -0
  51. package/node_modules/@waterplane/shared/dist/wire/session/context.js.map +1 -1
  52. package/node_modules/@waterplane/shared/dist/wire/sysstat.d.ts +7 -0
  53. package/node_modules/@waterplane/shared/dist/wire/telemetry.d.ts +3 -0
  54. package/node_modules/@waterplane/shared/package.json +3 -0
  55. package/npm-shrinkwrap.json +30 -2
  56. package/package.json +2 -1
  57. package/packages/extensions/desktop/helper/Capture.swift +245 -0
  58. package/packages/extensions/desktop/helper/H264.swift +226 -0
  59. package/packages/extensions/desktop/helper/Info.plist +20 -0
  60. package/packages/extensions/desktop/helper/Input.swift +195 -0
  61. package/packages/extensions/desktop/helper/Jpeg.swift +81 -0
  62. package/packages/extensions/desktop/helper/PROTOCOL.md +366 -0
  63. package/packages/extensions/desktop/helper/Params.swift +133 -0
  64. package/packages/extensions/desktop/helper/Probe.swift +119 -0
  65. package/packages/extensions/desktop/helper/Protocol.swift +224 -0
  66. package/packages/extensions/desktop/helper/Request.swift +51 -0
  67. package/packages/extensions/desktop/helper/Responsibility.swift +133 -0
  68. package/packages/extensions/desktop/helper/Server.swift +334 -0
  69. package/packages/extensions/desktop/helper/Synthetic.swift +281 -0
  70. package/packages/extensions/desktop/helper/build.sh +53 -0
  71. package/packages/extensions/desktop/helper/main.swift +79 -0
  72. package/packages/extensions/desktop/helper/selftest-driver +626 -0
  73. package/packages/extensions/desktop/helper/selftest.sh +16 -0
  74. package/packages/extensions/desktop/helper-win/Capture.cs +299 -0
  75. package/packages/extensions/desktop/helper-win/H264.cs +340 -0
  76. package/packages/extensions/desktop/helper-win/Input.cs +257 -0
  77. package/packages/extensions/desktop/helper-win/Jpeg.cs +75 -0
  78. package/packages/extensions/desktop/helper-win/Main.cs +118 -0
  79. package/packages/extensions/desktop/helper-win/Native.cs +276 -0
  80. package/packages/extensions/desktop/helper-win/Params.cs +138 -0
  81. package/packages/extensions/desktop/helper-win/Protocol.cs +206 -0
  82. package/packages/extensions/desktop/helper-win/Server.cs +304 -0
  83. package/packages/extensions/desktop/helper-win/Synthetic.cs +88 -0
  84. package/packages/extensions/desktop/helper-win/build.sh +57 -0
  85. package/packages/extensions/desktop/helper-win/selftest.sh +36 -0
  86. package/packages/extensions/desktop/waterplane-plugin.json +24 -0
  87. package/packages/host/dist/agentlogs.d.ts +18 -0
  88. package/packages/host/dist/agentlogs.js +58 -0
  89. package/packages/host/dist/agentlogs.js.map +1 -0
  90. package/packages/host/dist/agents.d.ts +5 -0
  91. package/packages/host/dist/agents.js +3 -2
  92. package/packages/host/dist/agents.js.map +1 -1
  93. package/packages/host/dist/alwayson.js +1 -1
  94. package/packages/host/dist/alwayson.js.map +1 -1
  95. package/packages/host/dist/answergate.js +3 -2
  96. package/packages/host/dist/answergate.js.map +1 -1
  97. package/packages/host/dist/attentionstore.d.ts +4 -0
  98. package/packages/host/dist/attentionstore.js +17 -0
  99. package/packages/host/dist/attentionstore.js.map +1 -1
  100. package/packages/host/dist/auth.d.ts +28 -0
  101. package/packages/host/dist/auth.js +65 -2
  102. package/packages/host/dist/auth.js.map +1 -1
  103. package/packages/host/dist/cli/pair.d.ts +4 -0
  104. package/packages/host/dist/cli/pair.js +18 -5
  105. package/packages/host/dist/cli/pair.js.map +1 -1
  106. package/packages/host/dist/composer.d.ts +6 -0
  107. package/packages/host/dist/composer.js +7 -1
  108. package/packages/host/dist/composer.js.map +1 -1
  109. package/packages/host/dist/ctxlog/ctxagents.d.ts +0 -29
  110. package/packages/host/dist/ctxlog/ctxagents.js +41 -8
  111. package/packages/host/dist/ctxlog/ctxagents.js.map +1 -1
  112. package/packages/host/dist/der.d.ts +19 -0
  113. package/packages/host/dist/der.js +51 -0
  114. package/packages/host/dist/der.js.map +1 -0
  115. package/packages/host/dist/doctor.d.ts +2 -0
  116. package/packages/host/dist/doctor.js +10 -2
  117. package/packages/host/dist/doctor.js.map +1 -1
  118. package/packages/host/dist/extensions/desktop/host/auto.d.mts +71 -0
  119. package/packages/host/dist/extensions/desktop/host/auto.mjs +114 -0
  120. package/packages/host/dist/extensions/desktop/host/auto.mjs.map +1 -0
  121. package/packages/host/dist/extensions/desktop/host/desktop.d.mts +51 -0
  122. package/packages/host/dist/extensions/desktop/host/desktop.mjs +113 -0
  123. package/packages/host/dist/extensions/desktop/host/desktop.mjs.map +1 -0
  124. package/packages/host/dist/extensions/desktop/host/helperbin.d.mts +71 -0
  125. package/packages/host/dist/extensions/desktop/host/helperbin.mjs +160 -0
  126. package/packages/host/dist/extensions/desktop/host/helperbin.mjs.map +1 -0
  127. package/packages/host/dist/extensions/desktop/host/index.d.mts +4 -0
  128. package/packages/host/dist/extensions/desktop/host/index.mjs +88 -0
  129. package/packages/host/dist/extensions/desktop/host/index.mjs.map +1 -0
  130. package/packages/host/dist/extensions/desktop/host/knobs.d.mts +52 -0
  131. package/packages/host/dist/extensions/desktop/host/knobs.mjs +81 -0
  132. package/packages/host/dist/extensions/desktop/host/knobs.mjs.map +1 -0
  133. package/packages/host/dist/extensions/desktop/host/probe.d.mts +57 -0
  134. package/packages/host/dist/extensions/desktop/host/probe.mjs +119 -0
  135. package/packages/host/dist/extensions/desktop/host/probe.mjs.map +1 -0
  136. package/packages/host/dist/extensions/desktop/host/records.d.mts +40 -0
  137. package/packages/host/dist/extensions/desktop/host/records.mjs +101 -0
  138. package/packages/host/dist/extensions/desktop/host/records.mjs.map +1 -0
  139. package/packages/host/dist/extensions/desktop/host/session.d.mts +86 -0
  140. package/packages/host/dist/extensions/desktop/host/session.mjs +318 -0
  141. package/packages/host/dist/extensions/desktop/host/session.mjs.map +1 -0
  142. package/packages/host/dist/extensions/desktop/host/setup.d.mts +28 -0
  143. package/packages/host/dist/extensions/desktop/host/setup.mjs +217 -0
  144. package/packages/host/dist/extensions/desktop/host/setup.mjs.map +1 -0
  145. package/packages/host/dist/extensions/desktop/host/status.d.mts +27 -0
  146. package/packages/host/dist/extensions/desktop/host/status.mjs +62 -0
  147. package/packages/host/dist/extensions/desktop/host/status.mjs.map +1 -0
  148. package/packages/host/dist/extensions/desktop/shared/wire.d.mts +206 -0
  149. package/packages/host/dist/extensions/desktop/shared/wire.mjs +174 -0
  150. package/packages/host/dist/extensions/desktop/shared/wire.mjs.map +1 -0
  151. package/packages/host/dist/git.d.ts +23 -6
  152. package/packages/host/dist/git.js +54 -26
  153. package/packages/host/dist/git.js.map +1 -1
  154. package/packages/host/dist/gitfetchfail.d.ts +24 -0
  155. package/packages/host/dist/gitfetchfail.js +62 -0
  156. package/packages/host/dist/gitfetchfail.js.map +1 -0
  157. package/packages/host/dist/gitlog.d.ts +4 -0
  158. package/packages/host/dist/gitlog.js +8 -3
  159. package/packages/host/dist/gitlog.js.map +1 -1
  160. package/packages/host/dist/gitnotify.d.ts +7 -1
  161. package/packages/host/dist/gitnotify.js +61 -1
  162. package/packages/host/dist/gitnotify.js.map +1 -1
  163. package/packages/host/dist/healthwatch.js +1 -1
  164. package/packages/host/dist/healthwatch.js.map +1 -1
  165. package/packages/host/dist/host.js +5 -1
  166. package/packages/host/dist/host.js.map +1 -1
  167. package/packages/host/dist/hoststore.js +4 -4
  168. package/packages/host/dist/hoststore.js.map +1 -1
  169. package/packages/host/dist/lantls.d.ts +145 -0
  170. package/packages/host/dist/lantls.js +337 -0
  171. package/packages/host/dist/lantls.js.map +1 -0
  172. package/packages/host/dist/main.js +10 -2
  173. package/packages/host/dist/main.js.map +1 -1
  174. package/packages/host/dist/net.d.ts +7 -0
  175. package/packages/host/dist/net.js +9 -0
  176. package/packages/host/dist/net.js.map +1 -1
  177. package/packages/host/dist/origin.d.ts +4 -0
  178. package/packages/host/dist/origin.js +6 -0
  179. package/packages/host/dist/origin.js.map +1 -1
  180. package/packages/host/dist/pair.d.ts +54 -5
  181. package/packages/host/dist/pair.js +139 -34
  182. package/packages/host/dist/pair.js.map +1 -1
  183. package/packages/host/dist/pairpake.d.ts +58 -0
  184. package/packages/host/dist/pairpake.js +208 -0
  185. package/packages/host/dist/pairpake.js.map +1 -0
  186. package/packages/host/dist/passive.d.ts +2 -0
  187. package/packages/host/dist/passive.js +4 -0
  188. package/packages/host/dist/passive.js.map +1 -1
  189. package/packages/host/dist/peers/client.d.ts +3 -1
  190. package/packages/host/dist/peers/client.js +4 -0
  191. package/packages/host/dist/peers/client.js.map +1 -1
  192. package/packages/host/dist/peers/routes.d.ts +6 -1
  193. package/packages/host/dist/peers/routes.js +39 -0
  194. package/packages/host/dist/peers/routes.js.map +1 -1
  195. package/packages/host/dist/permmode.js +3 -3
  196. package/packages/host/dist/plugins/pluginapi.js +13 -0
  197. package/packages/host/dist/plugins/pluginapi.js.map +1 -1
  198. package/packages/host/dist/plugins/pluginregistry.d.ts +6 -0
  199. package/packages/host/dist/plugins/pluginregistry.js.map +1 -1
  200. package/packages/host/dist/prepushcheck.d.ts +34 -0
  201. package/packages/host/dist/prepushcheck.js +157 -0
  202. package/packages/host/dist/prepushcheck.js.map +1 -0
  203. package/packages/host/dist/prs.js +2 -1
  204. package/packages/host/dist/prs.js.map +1 -1
  205. package/packages/host/dist/reponames.d.ts +26 -0
  206. package/packages/host/dist/reponames.js +119 -0
  207. package/packages/host/dist/reponames.js.map +1 -0
  208. package/packages/host/dist/repos.js +13 -0
  209. package/packages/host/dist/repos.js.map +1 -1
  210. package/packages/host/dist/routes/apigitcheck.d.ts +2 -0
  211. package/packages/host/dist/routes/apigitcheck.js +29 -0
  212. package/packages/host/dist/routes/apigitcheck.js.map +1 -0
  213. package/packages/host/dist/routes/apihost.js +28 -1
  214. package/packages/host/dist/routes/apihost.js.map +1 -1
  215. package/packages/host/dist/routes/apiio.js +2 -1
  216. package/packages/host/dist/routes/apiio.js.map +1 -1
  217. package/packages/host/dist/routes/apirepofiles.js +2 -1
  218. package/packages/host/dist/routes/apirepofiles.js.map +1 -1
  219. package/packages/host/dist/routes/apisystem.js +21 -3
  220. package/packages/host/dist/routes/apisystem.js.map +1 -1
  221. package/packages/host/dist/server/http.js +31 -5
  222. package/packages/host/dist/server/http.js.map +1 -1
  223. package/packages/host/dist/server/intentEvents.js +3 -2
  224. package/packages/host/dist/server/intentEvents.js.map +1 -1
  225. package/packages/host/dist/server/plugins.d.ts +13 -0
  226. package/packages/host/dist/server/plugins.js +26 -0
  227. package/packages/host/dist/server/plugins.js.map +1 -1
  228. package/packages/host/dist/server/sessionEvents.js +10 -9
  229. package/packages/host/dist/server/sessionEvents.js.map +1 -1
  230. package/packages/host/dist/server/wsops.js +3 -1
  231. package/packages/host/dist/server/wsops.js.map +1 -1
  232. package/packages/host/dist/sessionSearch.js +3 -1
  233. package/packages/host/dist/sessionSearch.js.map +1 -1
  234. package/packages/host/dist/sessions/apiretry.d.ts +14 -0
  235. package/packages/host/dist/sessions/apiretry.js +28 -2
  236. package/packages/host/dist/sessions/apiretry.js.map +1 -1
  237. package/packages/host/dist/sessions/core.d.ts +5 -0
  238. package/packages/host/dist/sysstat.js +10 -1
  239. package/packages/host/dist/sysstat.js.map +1 -1
  240. package/packages/host/dist/tokenscan.d.ts +4 -2
  241. package/packages/host/dist/tokenscan.js +5 -3
  242. package/packages/host/dist/tokenscan.js.map +1 -1
  243. package/packages/host/dist/transcript/transcriptparse.js +5 -2
  244. package/packages/host/dist/transcript/transcriptparse.js.map +1 -1
  245. package/packages/host/dist/turnagents.d.ts +8 -1
  246. package/packages/host/dist/turnagents.js +49 -16
  247. package/packages/host/dist/turnagents.js.map +1 -1
  248. package/packages/host/dist/updatekey.d.ts +22 -0
  249. package/packages/host/dist/updatekey.js +140 -0
  250. package/packages/host/dist/updatekey.js.map +1 -0
  251. package/packages/host/dist/webbundle.d.ts +15 -6
  252. package/packages/host/dist/webbundle.js +44 -7
  253. package/packages/host/dist/webbundle.js.map +1 -1
  254. package/packages/host/dist/wincpu.d.ts +13 -0
  255. package/packages/host/dist/wincpu.js +101 -0
  256. package/packages/host/dist/wincpu.js.map +1 -0
  257. package/packages/host/package.json +2 -1
  258. package/packages/web/dist/assets/demo-iVbE6mpm.js +26 -0
  259. package/packages/web/dist/assets/icons-D8RlmSLR.js +1 -0
  260. package/packages/web/dist/assets/index-DiZysQBa.css +1 -0
  261. package/packages/web/dist/assets/index-NA--kuEl.js +170 -0
  262. package/packages/web/dist/assets/noble-DV-r0OkE.js +1 -0
  263. package/packages/web/dist/assets/{react-CoSyT_xY.js → react-CjmvHigY.js} +2 -2
  264. package/packages/web/dist/assets/rolldown-runtime-4tVxZq34.js +1 -0
  265. package/packages/web/dist/assets/shared-CsHyApn-.js +51 -0
  266. package/packages/web/dist/assets/sheets-CDv71Sfe.js +256 -0
  267. package/packages/web/dist/assets/xterm-BHsKrDzh.js +16 -0
  268. package/packages/web/dist/build-id.txt +1 -1
  269. package/packages/web/dist/buildstamp.json +1 -1
  270. package/packages/web/dist/index.html +9 -9
  271. package/packages/web/dist/sw.js +2 -2
  272. package/release.json +7 -3
  273. package/packages/web/dist/assets/demo-DkCtg-SJ.js +0 -26
  274. package/packages/web/dist/assets/icons-B48F-4nA.js +0 -1
  275. package/packages/web/dist/assets/index-BYRdfW3T.js +0 -170
  276. package/packages/web/dist/assets/index-DcZrEQNl.css +0 -1
  277. package/packages/web/dist/assets/rolldown-runtime-BpQH8Ho1.js +0 -1
  278. package/packages/web/dist/assets/shared-DjRRLGfw.js +0 -50
  279. package/packages/web/dist/assets/sheets-BGN7Cs73.js +0 -248
  280. package/packages/web/dist/assets/xterm-C8zLTNGk.js +0 -16
@@ -32,11 +32,11 @@
32
32
  * that cannot be placed withholds every running total, because a total missing
33
33
  * it would read as complete.
34
34
  */
35
- import { readdirSync, statSync } from "node:fs";
35
+ import { statSync } from "node:fs";
36
36
  import { join } from "node:path";
37
37
  import { AGENT_LIVE_MS, normalizeModel } from "@waterplane/shared";
38
38
  import { agentUsage } from "./ctxlog.js";
39
- import { readMeta } from "./agents.js";
39
+ import { agentLogId, agentLogs, agentLogWorkflow, PARENT_TAIL, readMeta, readTail, readWorkflowJournal } from "./agents.js";
40
40
  /** Per-directory ledgers, kept so a poll re-reads only the agent logs that
41
41
  * grew — `agentUsage` is incremental given its previous result. */
42
42
  const cache = new Map();
@@ -52,15 +52,13 @@ export function agentsMtime(logPath) {
52
52
  const dir = subagentsDirOf(logPath);
53
53
  let names;
54
54
  try {
55
- names = readdirSync(dir);
55
+ names = agentLogs(dir);
56
56
  }
57
57
  catch {
58
58
  return 0;
59
59
  }
60
60
  let max = 0;
61
61
  for (const n of names) {
62
- if (!n.startsWith("agent-") || !n.endsWith(".jsonl"))
63
- continue;
64
62
  try {
65
63
  max = Math.max(max, statSync(join(dir, n)).mtimeMs);
66
64
  }
@@ -85,13 +83,31 @@ export function noteRetired(line, at, into) {
85
83
  }
86
84
  }
87
85
  }
86
+ /**
87
+ * `wf_… → the Workflow call that launched it`, off the launch's own tool_result
88
+ * record. A workflow's agents name no `toolUseId` in their meta files, so this
89
+ * is the lookup that puts them on a turn. Read off the structured `toolUseResult`
90
+ * and never the text: a tool result that merely quotes a launch receipt is not one.
91
+ */
92
+ export function noteWorkflowLaunch(rec, into) {
93
+ const r = rec;
94
+ const runId = r?.toolUseResult?.runId;
95
+ if (typeof runId !== "string" || !runId.startsWith("wf_"))
96
+ return;
97
+ const content = r?.message?.content;
98
+ if (!Array.isArray(content))
99
+ return;
100
+ const res = content.find((b) => b?.type === "tool_result" && typeof b.tool_use_id === "string");
101
+ if (res)
102
+ into.set(runId, res.tool_use_id);
103
+ }
88
104
  /**
89
105
  * Put each agent's spend on the turn that started it, in place.
90
106
  *
91
107
  * `partial`: the parent log was tail-read, so earlier turns — and the calls of
92
108
  * agents started there — are missing; no running total is published.
93
109
  */
94
- export function attachAgentSpend(turns, logPath, retired, partial, now = Date.now()) {
110
+ export function attachAgentSpend(turns, logPath, retired, partial, now = Date.now(), workflows = new Map()) {
95
111
  const dir = subagentsDirOf(logPath);
96
112
  const use = agentUsage(dir, cache.get(dir) ?? null);
97
113
  if (!use)
@@ -107,17 +123,31 @@ export function attachAgentSpend(turns, logPath, retired, partial, now = Date.no
107
123
  for (const b of t.blocks) {
108
124
  if (b.kind !== "tool")
109
125
  continue;
110
- if (b.name === "Task" || b.name === "Agent")
126
+ if (b.name === "Task" || b.name === "Agent" || b.name === "Workflow")
111
127
  turnOfCall.set(b.id, t);
112
128
  if (b.ok !== undefined)
113
129
  answered.add(b.id);
114
130
  }
115
131
  }
116
132
  const metas = new Map();
117
- for (const name of use.files.keys()) {
118
- const id = name.slice("agent-".length, -".jsonl".length);
119
- metas.set(id, readMeta(join(dir, `agent-${id}.meta.json`)));
133
+ const fileOf = new Map();
134
+ for (const [name, f] of use.files) {
135
+ const id = agentLogId(name);
136
+ metas.set(id, readMeta(join(dir, `${name.slice(0, -".jsonl".length)}.meta.json`)));
137
+ fileOf.set(id, f);
120
138
  }
139
+ /** A workflow's agent gets no notification of its own: its journal says when
140
+ * it ended, and only an agent still writing is worth reading one for. */
141
+ const journals = new Map();
142
+ const workflowEnded = (wf, id) => {
143
+ let j = journals.get(wf);
144
+ if (!j) {
145
+ j = readWorkflowJournal(readTail(join(dir, "workflows", wf, "journal.jsonl"), PARENT_TAIL));
146
+ journals.set(wf, j);
147
+ }
148
+ const key = j.agentKey.get(id);
149
+ return key !== undefined && j.ended.has(key);
150
+ };
121
151
  /** The top-level agent an agent descends from; itself when it is one. Null
122
152
  * on a broken or cyclic chain. */
123
153
  const rootOf = (id) => {
@@ -147,9 +177,10 @@ export function attachAgentSpend(turns, logPath, retired, partial, now = Date.no
147
177
  const perTurn = new Array(turns.length).fill(0);
148
178
  const seenCalls = new Set();
149
179
  for (const [name, f] of use.files) {
150
- const id = name.slice("agent-".length, -".jsonl".length);
180
+ const id = agentLogId(name);
181
+ const wf = agentLogWorkflow(name);
151
182
  const root = rootOf(id);
152
- const call = root ? metas.get(root)?.toolUseId : undefined;
183
+ const call = wf ? workflows.get(wf) : root ? metas.get(root)?.toolUseId : undefined;
153
184
  const t = call ? turnOfCall.get(call) : undefined;
154
185
  if (!t || !root) {
155
186
  if (f.tok > 0)
@@ -158,10 +189,12 @@ export function attachAgentSpend(turns, logPath, retired, partial, now = Date.no
158
189
  }
159
190
  if (call)
160
191
  seenCalls.add(call);
161
- const rootFile = use.files.get(`agent-${root}.jsonl`);
162
- const live = root === id
163
- ? runningTop(id, f.mtime)
164
- : now - f.mtime <= AGENT_LIVE_MS && !!rootFile && runningTop(root, Math.max(rootFile.mtime, f.mtime));
192
+ const rootFile = fileOf.get(root);
193
+ const live = wf
194
+ ? now - f.mtime <= AGENT_LIVE_MS && !workflowEnded(wf, id)
195
+ : root === id
196
+ ? runningTop(id, f.mtime)
197
+ : now - f.mtime <= AGENT_LIVE_MS && !!rootFile && runningTop(root, Math.max(rootFile.mtime, f.mtime));
165
198
  if (live)
166
199
  t.agentsRunning = (t.agentsRunning ?? 0) + 1;
167
200
  if (f.cost.total > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"turnagents.js","sourceRoot":"","sources":["../src/turnagents.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"turnagents.js","sourceRoot":"","sources":["../src/turnagents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /** What the signature covers, beside `hostId` and `gen`, which this file adds. */
2
+ export interface UpdateBody {
3
+ buildId: string;
4
+ total: number;
5
+ files: {
6
+ path: string;
7
+ size: number;
8
+ sha256: string;
9
+ }[];
10
+ }
11
+ /** `signed`: base64 of the JSON a phone reads. `sig`: base64 P1363 `r‖s` over those decoded bytes. */
12
+ export interface UpdateSignature {
13
+ signed: string;
14
+ sig: string;
15
+ }
16
+ export declare function updateKeyFile(root: string): string;
17
+ /** base64 SPKI DER of this desktop's update key, or undefined when there is none to give. */
18
+ export declare function updatePublicKey(root: string): string | undefined;
19
+ /** Sign one build. Undefined means serve it unsigned: never throws, the reason is logged. */
20
+ export declare function signUpdate(root: string, body: UpdateBody): UpdateSignature | undefined;
21
+ /** For tests: forget what is held for `root`, as a restart would. */
22
+ export declare function forgetUpdateKey(root: string): void;
@@ -0,0 +1,140 @@
1
+ /**
2
+ * This desktop's update signing key: what lets a phone tell a web bundle this
3
+ * desktop published from one a relay on the Wi-Fi made up.
4
+ *
5
+ * The manifest's hashes arrive in the same answer as the rest of it, so whoever
6
+ * can change the files can change the hashes. A phone that pinned `updateKey`
7
+ * over a protected route can check `sig` over `signed` instead, and a relay has
8
+ * no way to produce one. The key is per desktop, not per project, because people
9
+ * build their own bundles and a private key shipped to every desktop is no key.
10
+ * P-256, not Ed25519: `minSdk` is 24 and old WebViews lack Ed25519.
11
+ *
12
+ * `<state dir>/update-key.json`, mode 0600, created the first time anything asks:
13
+ * the private key (PKCS#8 DER, base64), `gen` and `lastBuildId`.
14
+ *
15
+ * `gen` is what stops an old signed bundle being replayed: it moves up by one
16
+ * only when the served build id differs from `lastBuildId`, so a poll or a
17
+ * restart leaves it alone, and a real revert to an older build gets a higher
18
+ * number than the build it replaces. It reaches the disk before anything is
19
+ * signed with it, so a crash can never hand out the same number twice.
20
+ *
21
+ * Degrade, never break. A file that cannot be read is moved aside and a new key
22
+ * made, which each phone asks about once. When the disk refuses, `signUpdate`
23
+ * and `updatePublicKey` answer undefined, the reason goes to the console once,
24
+ * and the bundle is served unsigned.
25
+ */
26
+ import { createPrivateKey, createPublicKey, generateKeyPairSync, sign } from "node:crypto";
27
+ import { chmodSync, renameSync } from "node:fs";
28
+ import { join } from "node:path";
29
+ import { logTag } from "@waterplane/shared";
30
+ import { hostStateDir } from "./branddirs.js";
31
+ import { corruptPathFor, readJsonGuardedDetail, writeJsonAtomic } from "./jsonstore.js";
32
+ import { lanIdentity } from "./lanid.js";
33
+ const held = new Map();
34
+ /** Reasons already on the console, so a phone polling a broken disk logs each one once. */
35
+ const said = new Set();
36
+ export function updateKeyFile(root) {
37
+ return join(hostStateDir(root), "update-key.json");
38
+ }
39
+ function privateKeyOf(key) {
40
+ try {
41
+ const k = createPrivateKey({ key: Buffer.from(key, "base64"), format: "der", type: "pkcs8" });
42
+ return k.asymmetricKeyDetails?.namedCurve === "prime256v1" ? k : null;
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ function isStoredKey(v) {
49
+ const j = v;
50
+ return typeof j?.key === "string" && privateKeyOf(j.key) !== null
51
+ && Number.isSafeInteger(j.gen) && j.gen >= 0
52
+ && (j.lastBuildId === null || typeof j.lastBuildId === "string");
53
+ }
54
+ function hold(s) {
55
+ const privateKey = privateKeyOf(s.key);
56
+ if (!privateKey)
57
+ throw new Error("update key is not a P-256 key");
58
+ const publicKey = createPublicKey(privateKey).export({ format: "der", type: "spki" }).toString("base64");
59
+ return { key: s.key, gen: s.gen, lastBuildId: s.lastBuildId, privateKey, publicKey };
60
+ }
61
+ function save(file, s) {
62
+ writeJsonAtomic(file, { key: s.key, gen: s.gen, lastBuildId: s.lastBuildId }, { mode: 0o600 });
63
+ }
64
+ /** The key of `root`: held, else read, else made. Throws only when the disk refuses a new one. */
65
+ function load(root) {
66
+ const hit = held.get(root);
67
+ if (hit)
68
+ return hit;
69
+ const file = updateKeyFile(root);
70
+ const read = readJsonGuardedDetail(file, null, isStoredKey);
71
+ if (read.value) {
72
+ try {
73
+ chmodSync(file, 0o600);
74
+ }
75
+ catch { /* best effort on odd filesystems */ }
76
+ const k = hold(read.value);
77
+ held.set(root, k);
78
+ return k;
79
+ }
80
+ if (read.corrupt) {
81
+ // jsonstore leaves a file it could not open where it is. A rename needs no
82
+ // read access, and the next write must never land on the only copy.
83
+ const movedTo = read.corrupt.movedTo ?? corruptPathFor(file);
84
+ if (!read.corrupt.movedTo)
85
+ renameSync(file, movedTo);
86
+ console.error(`${logTag} update signing key could not be read (${read.corrupt.error}); kept as ${movedTo}. Making a new key: each phone asks once before it trusts it.`);
87
+ }
88
+ const key = generateKeyPairSync("ec", { namedCurve: "prime256v1" }).privateKey.export({ format: "der", type: "pkcs8" }).toString("base64");
89
+ const k = hold({ key, gen: 0, lastBuildId: null });
90
+ save(file, k);
91
+ held.set(root, k);
92
+ return k;
93
+ }
94
+ /** `gen` for this build: the same one for the same build, and on disk before it is returned. */
95
+ function advance(root, k, buildId) {
96
+ if (k.lastBuildId === buildId)
97
+ return k.gen;
98
+ save(updateKeyFile(root), { key: k.key, gen: k.gen + 1, lastBuildId: buildId });
99
+ k.gen += 1;
100
+ k.lastBuildId = buildId;
101
+ return k.gen;
102
+ }
103
+ function refused(root, what, e) {
104
+ const why = `${what}: ${e?.message ?? e}`;
105
+ if (!said.has(`${root}\0${why}`))
106
+ console.error(`${logTag} ${why}`);
107
+ said.add(`${root}\0${why}`);
108
+ return undefined;
109
+ }
110
+ /** base64 SPKI DER of this desktop's update key, or undefined when there is none to give. */
111
+ export function updatePublicKey(root) {
112
+ try {
113
+ return load(root).publicKey;
114
+ }
115
+ catch (e) {
116
+ return refused(root, "no update signing key", e);
117
+ }
118
+ }
119
+ /** Sign one build. Undefined means serve it unsigned: never throws, the reason is logged. */
120
+ export function signUpdate(root, body) {
121
+ try {
122
+ const { hostId } = lanIdentity(root);
123
+ const k = load(root);
124
+ const gen = advance(root, k, body.buildId);
125
+ const files = body.files.map(({ path, size, sha256 }) => ({ path, size, sha256 }));
126
+ const bytes = Buffer.from(JSON.stringify({ v: 1, hostId, buildId: body.buildId, gen, total: body.total, files }), "utf8");
127
+ const sig = sign("sha256", bytes, { key: k.privateKey, dsaEncoding: "ieee-p1363" });
128
+ said.clear();
129
+ return { signed: bytes.toString("base64"), sig: sig.toString("base64") };
130
+ }
131
+ catch (e) {
132
+ return refused(root, "web bundle served unsigned", e);
133
+ }
134
+ }
135
+ /** For tests: forget what is held for `root`, as a restart would. */
136
+ export function forgetUpdateKey(root) {
137
+ held.delete(root);
138
+ said.clear();
139
+ }
140
+ //# sourceMappingURL=updatekey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updatekey.js","sourceRoot":"","sources":["../src/updatekey.ts"],"names":[],"mappings":"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"}
@@ -23,15 +23,24 @@ export interface BundleManifest {
23
23
  total: number;
24
24
  /** Present when `ok` is false — safe to show to the user. */
25
25
  reason?: string;
26
+ /** base64 of the JSON this manifest's signature covers. A new client reads
27
+ * only this, so nothing has to be put in a canonical form. Old clients ignore it. */
28
+ signed?: string;
29
+ /** base64 P1363 `r‖s`, ECDSA P-256 SHA-256 over the decoded `signed` bytes. */
30
+ sig?: string;
26
31
  }
27
32
  /**
28
- * The manifest for the bundle currently on disk.
29
- *
30
- * Hashes are cached against a paths+sizes+mtimes fingerprint: the phone polls
31
- * this, and re-reading ~1 MB per poll to produce a value that changes a few
32
- * times a day is waste. A rebuild moves an mtime, so the cache cannot go stale.
33
+ * The manifest for the bundle currently on disk, signed with the key of `root`.
34
+ * With no `root` there is no state dir to keep a key in, so it stays unsigned.
35
+ */
36
+ export declare function webBundleManifest(root?: string): BundleManifest;
37
+ /**
38
+ * `base` with `signed` and `sig`, or `base` itself when it cannot be signed. Signs
39
+ * once per manifest object: the phone polls this, and `hashedManifest` hands back
40
+ * the same object until the tree changes. A refused manifest describes no build
41
+ * and is never signed.
33
42
  */
34
- export declare function webBundleManifest(): BundleManifest;
43
+ export declare function signedManifest(base: BundleManifest, root: string): BundleManifest;
35
44
  /**
36
45
  * Resolve one bundle-relative path to a real file, or null.
37
46
  *
@@ -20,18 +20,27 @@
20
20
  * id that changed per build would have the phone re-downloading ~900 KB over
21
21
  * a roaming link to arrive at a byte-identical bundle.
22
22
  * - **Per-file `sha256`**, so the client can verify each piece before it
23
- * replaces a working app. This guards against a truncated transfer on a bad
24
- * link — it is NOT a defence against a hostile host, which is already able to
25
- * run arbitrary code on your machine (see SECURITY.md); the bundle is only
26
- * ever fetched from the host the user paired with.
23
+ * replaces a working app. This catches a truncated transfer on a bad link and
24
+ * nothing more: the hashes come in the same answer as the rest of the
25
+ * manifest, so whoever can change one can change the other.
26
+ * - **`signed` + `sig` are the defence.** `signed` carries the build id, the
27
+ * file list, this desktop's `hostId` and a rising `gen`; `sig` is this
28
+ * desktop's own P-256 key over those bytes (`updatekey.ts`). A phone that
29
+ * pinned the key over a protected route reads only what is inside `signed`,
30
+ * so a relay on the Wi-Fi can neither change a bundle nor replay an older
31
+ * one. It does nothing for a phone with no pin, and nothing against a hostile
32
+ * desktop, which holds the key and can already run arbitrary code on your
33
+ * machine (see SECURITY.md).
27
34
  * - **Degrade, never break.** No `dist`, no `build-id.txt`, or a bundle past the
28
35
  * caps ⇒ `ok: false` with a reason, and the shell simply says updating is
29
- * unavailable and keeps running what it has.
36
+ * unavailable and keeps running what it has. No usable signing key ⇒ the same
37
+ * manifest with no `signed`, and the reason on the console.
30
38
  */
31
39
  import { createHash } from "node:crypto";
32
40
  import { readFileSync, readdirSync, statSync } from "node:fs";
33
41
  import { join, relative, resolve, sep } from "node:path";
34
42
  import { BRAND } from "@waterplane/shared";
43
+ import { signUpdate } from "./updatekey.js";
35
44
  /** Why a dist with no `build-id.txt` is refused, and what to do in either kind
36
45
  * of install: a checkout builds it; a release tarball ships it, so one without
37
46
  * it is a damaged install. */
@@ -49,14 +58,42 @@ const MAX_TOTAL = 64 * 1024 * 1024;
49
58
  /** Cheap fingerprint of the tree (paths + sizes + mtimes), to skip re-hashing. */
50
59
  let cacheKey = "";
51
60
  let cached = null;
61
+ /** The signed copy of one cached manifest. A failed signing is not kept, so the next poll tries again. */
62
+ let signedCopy = null;
52
63
  /**
53
- * The manifest for the bundle currently on disk.
64
+ * The manifest for the bundle currently on disk, signed with the key of `root`.
65
+ * With no `root` there is no state dir to keep a key in, so it stays unsigned.
66
+ */
67
+ export function webBundleManifest(root) {
68
+ const base = hashedManifest();
69
+ return root === undefined ? base : signedManifest(base, root);
70
+ }
71
+ /**
72
+ * `base` with `signed` and `sig`, or `base` itself when it cannot be signed. Signs
73
+ * once per manifest object: the phone polls this, and `hashedManifest` hands back
74
+ * the same object until the tree changes. A refused manifest describes no build
75
+ * and is never signed.
76
+ */
77
+ export function signedManifest(base, root) {
78
+ if (!base.ok || !base.buildId)
79
+ return base;
80
+ if (signedCopy?.base === base && signedCopy.root === root)
81
+ return signedCopy.out;
82
+ const sig = signUpdate(root, { buildId: base.buildId, total: base.total, files: base.files });
83
+ if (!sig)
84
+ return base;
85
+ const out = { ...base, ...sig };
86
+ signedCopy = { base, root, out };
87
+ return out;
88
+ }
89
+ /**
90
+ * The hashed manifest of the tree.
54
91
  *
55
92
  * Hashes are cached against a paths+sizes+mtimes fingerprint: the phone polls
56
93
  * this, and re-reading ~1 MB per poll to produce a value that changes a few
57
94
  * times a day is waste. A rebuild moves an mtime, so the cache cannot go stale.
58
95
  */
59
- export function webBundleManifest() {
96
+ function hashedManifest() {
60
97
  let files;
61
98
  try {
62
99
  files = walk(WEB_DIST).sort();
@@ -1 +1 @@
1
- {"version":3,"file":"webbundle.js","sourceRoot":"","sources":["../src/webbundle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webbundle.js","sourceRoot":"","sources":["../src/webbundle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export declare const WIN_CPU_STALE_MS = 15000;
2
+ /** One line of the child's output → percent busy, or null. Accepts `12.5`; a
3
+ * comma decimal, text, blank or an out-of-range value is null. Utility may
4
+ * exceed 100 on a turbo-boosted core, so up to 200 is clamped, beyond is null. */
5
+ export declare function parseCpuLine(line: string): number | null;
6
+ /** Stop the child (shutdown). */
7
+ export declare function stopWindowsCpu(): void;
8
+ /** The newest Windows-wide reading, or null (not WSL, interop missing, child
9
+ * dead, or reading stale). Starts the child lazily on first call. */
10
+ export declare function windowsCpuNow(now?: number): {
11
+ pct: number;
12
+ at: number;
13
+ } | null;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Windows-wide CPU for a host that runs inside WSL2.
3
+ *
4
+ * Inside the VM `/proc/stat` (and so `os.cpus()` and the load average) only
5
+ * describes the VM's own load; Task Manager shows the whole machine, so the
6
+ * phone read far LOWER than the desktop beside it. Here ONE long-running
7
+ * `powershell.exe` (WSL interop) prints the machine's utilisation every
8
+ * couple of seconds; we keep the newest line. No process is spawned per poll.
9
+ *
10
+ * It reads the WMI perf class (`Win32_PerfFormattedData_*`), whose class and
11
+ * property names are English on every locale — unlike `typeperf`'s counter
12
+ * paths, which are localised. `Processor Information` `PercentProcessorUtility`
13
+ * is what Task Manager's CPU graph uses; the older `PercentProcessorTime` is
14
+ * the fallback. A line that is not a number in range is DROPPED, and a reading
15
+ * older than STALE_MS is ABSENT: the caller then falls back to the VM's own
16
+ * figure and says so. Never a wrong number.
17
+ */
18
+ import { spawn } from "node:child_process";
19
+ import { isWsl } from "./ocrlocal.js";
20
+ export const WIN_CPU_STALE_MS = 15_000;
21
+ const RETRY_MS = 60_000;
22
+ const INTERVAL_S = 2;
23
+ /** One line of the child's output → percent busy, or null. Accepts `12.5`; a
24
+ * comma decimal, text, blank or an out-of-range value is null. Utility may
25
+ * exceed 100 on a turbo-boosted core, so up to 200 is clamped, beyond is null. */
26
+ export function parseCpuLine(line) {
27
+ const s = line.trim();
28
+ if (!/^\d{1,3}(\.\d+)?$/.test(s))
29
+ return null;
30
+ const n = Number(s);
31
+ if (!Number.isFinite(n) || n < 0 || n > 200)
32
+ return null;
33
+ return Math.min(100, n);
34
+ }
35
+ const SCRIPT = [
36
+ "$ErrorActionPreference='SilentlyContinue';",
37
+ "$c=[cultureinfo]::InvariantCulture;",
38
+ "while($true){",
39
+ "$v=$null;",
40
+ "$u=Get-CimInstance Win32_PerfFormattedData_Counters_ProcessorInformation -Filter \"Name='_Total'\";",
41
+ "if($u -and $u.PercentProcessorUtility -ne $null){$v=$u.PercentProcessorUtility}",
42
+ "else{$p=Get-CimInstance Win32_PerfFormattedData_PerfOS_Processor -Filter \"Name='_Total'\";if($p){$v=$p.PercentProcessorTime}}",
43
+ "if($v -ne $null){[Console]::Out.WriteLine(([double]$v).ToString('0.0',$c))}",
44
+ `Start-Sleep -Seconds ${INTERVAL_S}}`,
45
+ ].join("");
46
+ let latest = null;
47
+ let child = null;
48
+ let failedAt = 0;
49
+ let wsl = null;
50
+ const detectWsl = () => (wsl ??= process.platform === "linux" && isWsl());
51
+ function start() {
52
+ try {
53
+ let buf = "";
54
+ const c = spawn("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", SCRIPT], {
55
+ stdio: ["ignore", "pipe", "ignore"], windowsHide: true,
56
+ });
57
+ child = c;
58
+ c.stdout.setEncoding("utf8");
59
+ c.stdout.on("data", (d) => {
60
+ buf += d;
61
+ let i;
62
+ while ((i = buf.indexOf("\n")) >= 0) {
63
+ const pct = parseCpuLine(buf.slice(0, i));
64
+ buf = buf.slice(i + 1);
65
+ if (pct !== null)
66
+ latest = { pct, at: Date.now() };
67
+ }
68
+ });
69
+ const dead = () => { if (child === c) {
70
+ child = null;
71
+ failedAt = Date.now();
72
+ } };
73
+ c.on("error", dead);
74
+ c.on("exit", dead);
75
+ }
76
+ catch {
77
+ failedAt = Date.now();
78
+ }
79
+ }
80
+ /** Stop the child (shutdown). */
81
+ export function stopWindowsCpu() {
82
+ const c = child;
83
+ child = null;
84
+ try {
85
+ c?.kill();
86
+ }
87
+ catch { /* already gone */ }
88
+ }
89
+ process.on("exit", stopWindowsCpu);
90
+ /** The newest Windows-wide reading, or null (not WSL, interop missing, child
91
+ * dead, or reading stale). Starts the child lazily on first call. */
92
+ export function windowsCpuNow(now = Date.now()) {
93
+ if (!detectWsl())
94
+ return null;
95
+ if (!child && now - failedAt >= RETRY_MS)
96
+ start();
97
+ if (!latest || now - latest.at > WIN_CPU_STALE_MS)
98
+ return null;
99
+ return latest;
100
+ }
101
+ //# sourceMappingURL=wincpu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wincpu.js","sourceRoot":"","sources":["../src/wincpu.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@
11
11
  "start": "node dist/main.js"
12
12
  },
13
13
  "dependencies": {
14
+ "@noble/curves": "2.4.0",
14
15
  "@waterplane/shared": "*",
15
16
  "@xterm/headless": "^5.5.0",
16
17
  "node-pty": "1.2.0-beta.15",
@@ -18,7 +19,7 @@
18
19
  "ws": "^8.22.0"
19
20
  },
20
21
  "devDependencies": {
21
- "@types/node": "^22.10.0",
22
+ "@types/node": "^22.20.5",
22
23
  "@types/web-push": "^3.6.4",
23
24
  "@types/ws": "^8.18.2",
24
25
  "tsx": "^4.23.15"