@hwip/cli 0.0.1 → 0.1.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 (245) hide show
  1. package/LICENSE +190 -0
  2. package/NOTICE +11 -0
  3. package/README.md +1979 -0
  4. package/dist/agent-list.d.ts +76 -0
  5. package/dist/agent-list.js +102 -0
  6. package/dist/agent-read.d.ts +105 -0
  7. package/dist/agent-read.js +309 -0
  8. package/dist/agent-rules-fetch.d.ts +51 -0
  9. package/dist/agent-rules-fetch.js +275 -0
  10. package/dist/agent-rules.default.d.ts +30 -0
  11. package/dist/agent-rules.default.js +292 -0
  12. package/dist/agent-session.d.ts +23 -0
  13. package/dist/agent-session.js +44 -0
  14. package/dist/agent-state.d.ts +84 -0
  15. package/dist/agent-state.js +188 -0
  16. package/dist/agent-target.d.ts +60 -0
  17. package/dist/agent-target.js +81 -0
  18. package/dist/agents.d.ts +31 -0
  19. package/dist/agents.js +75 -0
  20. package/dist/api.d.ts +28 -0
  21. package/dist/api.js +76 -0
  22. package/dist/args.d.ts +74 -0
  23. package/dist/args.js +254 -0
  24. package/dist/ask-context-attach.d.ts +73 -0
  25. package/dist/ask-context-attach.js +151 -0
  26. package/dist/ask-context-screen.d.ts +21 -0
  27. package/dist/ask-context-screen.js +49 -0
  28. package/dist/ask-context-switch.d.ts +31 -0
  29. package/dist/ask-context-switch.js +74 -0
  30. package/dist/ask-context.d.ts +84 -0
  31. package/dist/ask-context.js +172 -0
  32. package/dist/ask-pending.d.ts +47 -0
  33. package/dist/ask-pending.js +221 -0
  34. package/dist/ask-seal.d.ts +120 -0
  35. package/dist/ask-seal.js +179 -0
  36. package/dist/ask.d.ts +107 -0
  37. package/dist/ask.js +551 -0
  38. package/dist/blocked-prompt-seal.d.ts +35 -0
  39. package/dist/blocked-prompt-seal.js +89 -0
  40. package/dist/blocked-prompt.d.ts +57 -0
  41. package/dist/blocked-prompt.js +181 -0
  42. package/dist/channel.d.ts +67 -0
  43. package/dist/channel.js +136 -0
  44. package/dist/check-update.d.ts +28 -0
  45. package/dist/check-update.js +153 -0
  46. package/dist/cli.d.ts +3 -0
  47. package/dist/cli.js +813 -0
  48. package/dist/codex-config.d.ts +24 -0
  49. package/dist/codex-config.js +169 -0
  50. package/dist/codex-transcript.d.ts +59 -0
  51. package/dist/codex-transcript.js +373 -0
  52. package/dist/command-refusal.d.ts +56 -0
  53. package/dist/command-refusal.js +127 -0
  54. package/dist/command-scan.d.ts +46 -0
  55. package/dist/command-scan.js +154 -0
  56. package/dist/command-seal.d.ts +57 -0
  57. package/dist/command-seal.js +88 -0
  58. package/dist/command-seq.d.ts +30 -0
  59. package/dist/command-seq.js +150 -0
  60. package/dist/config.d.ts +156 -0
  61. package/dist/config.js +392 -0
  62. package/dist/core-sections.d.ts +18 -0
  63. package/dist/core-sections.js +28 -0
  64. package/dist/crypto.d.ts +278 -0
  65. package/dist/crypto.js +698 -0
  66. package/dist/desktop-notify.d.ts +33 -0
  67. package/dist/desktop-notify.js +49 -0
  68. package/dist/device-directory.d.ts +36 -0
  69. package/dist/device-directory.js +97 -0
  70. package/dist/device-presence.d.ts +17 -0
  71. package/dist/device-presence.js +62 -0
  72. package/dist/downloads.d.ts +29 -0
  73. package/dist/downloads.js +106 -0
  74. package/dist/errors.d.ts +12 -0
  75. package/dist/errors.js +28 -0
  76. package/dist/file-crypto.d.ts +94 -0
  77. package/dist/file-crypto.js +272 -0
  78. package/dist/file-view-budget.d.ts +15 -0
  79. package/dist/file-view-budget.js +34 -0
  80. package/dist/file-view-switch.d.ts +28 -0
  81. package/dist/file-view-switch.js +122 -0
  82. package/dist/file-view.d.ts +108 -0
  83. package/dist/file-view.js +327 -0
  84. package/dist/gate.d.ts +141 -0
  85. package/dist/gate.js +336 -0
  86. package/dist/gemini-transcript.d.ts +32 -0
  87. package/dist/gemini-transcript.js +189 -0
  88. package/dist/http-failure.d.ts +98 -0
  89. package/dist/http-failure.js +349 -0
  90. package/dist/hwip-core.generated.d.ts +7 -0
  91. package/dist/hwip-core.generated.js +14 -0
  92. package/dist/hwip-hook.d.ts +77 -0
  93. package/dist/hwip-hook.js +340 -0
  94. package/dist/index.d.ts +7 -0
  95. package/dist/index.js +14 -0
  96. package/dist/input-sequencer.d.ts +65 -0
  97. package/dist/input-sequencer.js +142 -0
  98. package/dist/insecure-url.d.ts +16 -0
  99. package/dist/insecure-url.js +76 -0
  100. package/dist/installer.d.ts +96 -0
  101. package/dist/installer.js +850 -0
  102. package/dist/inventory-offload.d.ts +49 -0
  103. package/dist/inventory-offload.js +209 -0
  104. package/dist/inventory-worker.d.ts +2 -0
  105. package/dist/inventory-worker.js +27 -0
  106. package/dist/jsonc-doc.d.ts +106 -0
  107. package/dist/jsonc-doc.js +354 -0
  108. package/dist/keep-awake.d.ts +32 -0
  109. package/dist/keep-awake.js +46 -0
  110. package/dist/key-changes.d.ts +48 -0
  111. package/dist/key-changes.js +140 -0
  112. package/dist/lan-auth.d.ts +140 -0
  113. package/dist/lan-auth.js +217 -0
  114. package/dist/lan-endpoint.d.ts +41 -0
  115. package/dist/lan-endpoint.js +115 -0
  116. package/dist/lan-receiver.d.ts +122 -0
  117. package/dist/lan-receiver.js +510 -0
  118. package/dist/lan-sender.d.ts +76 -0
  119. package/dist/lan-sender.js +184 -0
  120. package/dist/lan-transfer.d.ts +36 -0
  121. package/dist/lan-transfer.js +54 -0
  122. package/dist/listener-device-id.d.ts +20 -0
  123. package/dist/listener-device-id.js +133 -0
  124. package/dist/listener-log.d.ts +4 -0
  125. package/dist/listener-log.js +23 -0
  126. package/dist/listener-process.d.ts +200 -0
  127. package/dist/listener-process.js +470 -0
  128. package/dist/listener-service.d.ts +225 -0
  129. package/dist/listener-service.js +682 -0
  130. package/dist/listener-worktree-cleanup.d.ts +27 -0
  131. package/dist/listener-worktree-cleanup.js +62 -0
  132. package/dist/listener.d.ts +1325 -0
  133. package/dist/listener.js +5680 -0
  134. package/dist/login-address.d.ts +25 -0
  135. package/dist/login-address.js +97 -0
  136. package/dist/login-page.d.ts +29 -0
  137. package/dist/login-page.js +93 -0
  138. package/dist/login.d.ts +98 -0
  139. package/dist/login.js +388 -0
  140. package/dist/mcp-command.d.ts +45 -0
  141. package/dist/mcp-command.js +50 -0
  142. package/dist/mcp.d.ts +19 -0
  143. package/dist/mcp.js +29 -0
  144. package/dist/node-support.d.ts +19 -0
  145. package/dist/node-support.js +38 -0
  146. package/dist/notify-failure.d.ts +57 -0
  147. package/dist/notify-failure.js +150 -0
  148. package/dist/opencode-transcript.d.ts +139 -0
  149. package/dist/opencode-transcript.js +390 -0
  150. package/dist/optional-features.d.ts +6 -0
  151. package/dist/optional-features.js +19 -0
  152. package/dist/pane-fit.d.ts +40 -0
  153. package/dist/pane-fit.js +119 -0
  154. package/dist/peer-key.d.ts +33 -0
  155. package/dist/peer-key.js +34 -0
  156. package/dist/pi-transcript.d.ts +26 -0
  157. package/dist/pi-transcript.js +255 -0
  158. package/dist/presence.d.ts +14 -0
  159. package/dist/presence.js +124 -0
  160. package/dist/private-files.d.ts +51 -0
  161. package/dist/private-files.js +218 -0
  162. package/dist/project-switch.d.ts +19 -0
  163. package/dist/project-switch.js +60 -0
  164. package/dist/redact.d.ts +10 -0
  165. package/dist/redact.js +21 -0
  166. package/dist/remote-agents.d.ts +410 -0
  167. package/dist/remote-agents.js +1218 -0
  168. package/dist/remote-hook.d.ts +12 -0
  169. package/dist/remote-hook.js +196 -0
  170. package/dist/replace-file.d.ts +50 -0
  171. package/dist/replace-file.js +328 -0
  172. package/dist/schedule-command.d.ts +35 -0
  173. package/dist/schedule-command.js +260 -0
  174. package/dist/schedule-launch.d.ts +15 -0
  175. package/dist/schedule-launch.js +24 -0
  176. package/dist/schedule-ready.d.ts +44 -0
  177. package/dist/schedule-ready.js +71 -0
  178. package/dist/schedule-remote.d.ts +77 -0
  179. package/dist/schedule-remote.js +167 -0
  180. package/dist/schedule-runner.d.ts +89 -0
  181. package/dist/schedule-runner.js +452 -0
  182. package/dist/schedule.d.ts +149 -0
  183. package/dist/schedule.js +428 -0
  184. package/dist/secret-mask.d.ts +29 -0
  185. package/dist/secret-mask.js +245 -0
  186. package/dist/self-register.d.ts +45 -0
  187. package/dist/self-register.js +67 -0
  188. package/dist/send.d.ts +56 -0
  189. package/dist/send.js +104 -0
  190. package/dist/session-diff.d.ts +161 -0
  191. package/dist/session-diff.js +445 -0
  192. package/dist/session-registry.d.ts +143 -0
  193. package/dist/session-registry.js +216 -0
  194. package/dist/sessions-report.d.ts +59 -0
  195. package/dist/sessions-report.js +99 -0
  196. package/dist/shell-audit.d.ts +34 -0
  197. package/dist/shell-audit.js +47 -0
  198. package/dist/subagent-transcripts.d.ts +167 -0
  199. package/dist/subagent-transcripts.js +437 -0
  200. package/dist/subscriber-trust.d.ts +128 -0
  201. package/dist/subscriber-trust.js +397 -0
  202. package/dist/templates.d.ts +105 -0
  203. package/dist/templates.js +871 -0
  204. package/dist/tmux-install.d.ts +44 -0
  205. package/dist/tmux-install.js +65 -0
  206. package/dist/tmux-liveness.d.ts +45 -0
  207. package/dist/tmux-liveness.js +71 -0
  208. package/dist/tmux-pane.d.ts +55 -0
  209. package/dist/tmux-pane.js +126 -0
  210. package/dist/tmux-socket.d.ts +20 -0
  211. package/dist/tmux-socket.js +292 -0
  212. package/dist/todo-fold.d.ts +31 -0
  213. package/dist/todo-fold.js +102 -0
  214. package/dist/transcript-tail.d.ts +312 -0
  215. package/dist/transcript-tail.js +718 -0
  216. package/dist/trust-command.d.ts +49 -0
  217. package/dist/trust-command.js +200 -0
  218. package/dist/trust-lock.d.ts +26 -0
  219. package/dist/trust-lock.js +94 -0
  220. package/dist/trust-pins.d.ts +37 -0
  221. package/dist/trust-pins.js +82 -0
  222. package/dist/turn-recorder-wire.d.ts +70 -0
  223. package/dist/turn-recorder-wire.js +165 -0
  224. package/dist/turn-recorder.d.ts +190 -0
  225. package/dist/turn-recorder.js +695 -0
  226. package/dist/turn-ring.d.ts +93 -0
  227. package/dist/turn-ring.js +418 -0
  228. package/dist/turn-watch.d.ts +177 -0
  229. package/dist/turn-watch.js +630 -0
  230. package/dist/types.d.ts +63 -0
  231. package/dist/types.js +2 -0
  232. package/dist/uninstall.d.ts +55 -0
  233. package/dist/uninstall.js +507 -0
  234. package/dist/usage.d.ts +17 -0
  235. package/dist/usage.js +421 -0
  236. package/dist/verify.d.ts +47 -0
  237. package/dist/verify.js +396 -0
  238. package/dist/worktree.d.ts +144 -0
  239. package/dist/worktree.js +310 -0
  240. package/dist/wrapper.d.ts +254 -0
  241. package/dist/wrapper.js +704 -0
  242. package/dist/ws-url.d.ts +109 -0
  243. package/dist/ws-url.js +202 -0
  244. package/package.json +78 -10
  245. package/bin/hwip.js +0 -3
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ /**
3
+ * The last failed `hwip notify`, kept so a failure is visible after the fact.
4
+ *
5
+ * Every agent hook runs `hwip notify … 2>/dev/null || true`: a hook must never
6
+ * break the session, so the error output is thrown away. A revoked key, a used
7
+ * up quota or a dead network then looked exactly like "quiet mode, nothing to
8
+ * send". `hwip notify` itself writes this file on failure and deletes it on
9
+ * success — the one writer — so the record survives whatever the hook does
10
+ * with stderr. Concurrent hooks race last-writer-wins: a failure that finishes
11
+ * after a newer success stays until the next good push clears it. `hwip verify` and the Claude Code plugin (/hwip-mode, the
12
+ * SessionStart hook) only read it.
13
+ *
14
+ * THE CONTRACT (the plugin reads it with jq and node, so changing it is a
15
+ * cross-repo change — notify-failure.test.ts pins it):
16
+ *
17
+ * path ${XDG_STATE_HOME:-~/.local/state}/hwip/last-notify-failure.json
18
+ * — the same state dir as the mute and push-mode dials (gate.ts
19
+ * stateDir, plugin hooks/gate.sh HWIP_STATE_DIR)
20
+ * body {"v":1,"at":"<ISO 8601 UTC>","kind":"<kind>","status":<int|null>,"code":"<string|null>"}
21
+ * kind no-key | auth | quota | rate-limit | client | server | timeout | network | no-app | unsealed
22
+ *
23
+ * `no-app` (NO_APP_DEVICE) and `unsealed` (E2E_REQUIRED) are refusals made here, before the push went out: they
24
+ * carry no HTTP status, so a reader never shows one as the server's answer.
25
+ *
26
+ * A device whose key changed is not recorded here: the pin that replaced it writes
27
+ * key-changes.json (key-changes.ts), which another process's push cannot clear.
28
+ *
29
+ * No message text and nothing from the request: `status` is the HTTP status
30
+ * and `code` the server's error code (e.g. QUOTA_EXCEEDED), so the file can
31
+ * never carry a key, a title or a body.
32
+ */
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.isTransientNotifyFailure = exports.describeNotifyFailure = exports.readNotifyFailure = exports.withNotifyFailureRecord = exports.clearNotifyFailure = exports.recordNotifyFailure = exports.classifyNotifyFailure = exports.notifyFailurePath = exports.NOTIFY_FAILURE_KINDS = void 0;
35
+ const fs_1 = require("fs");
36
+ const path_1 = require("path");
37
+ const errors_js_1 = require("./errors.js");
38
+ const gate_js_1 = require("./gate.js");
39
+ const private_files_js_1 = require("./private-files.js");
40
+ exports.NOTIFY_FAILURE_KINDS = [
41
+ 'no-key', 'auth', 'quota', 'rate-limit', 'client', 'server', 'timeout', 'network', 'no-app', 'unsealed',
42
+ ];
43
+ const notifyFailurePath = () => (0, path_1.join)((0, gate_js_1.stateDir)(), 'last-notify-failure.json');
44
+ exports.notifyFailurePath = notifyFailurePath;
45
+ /** What went wrong, in the contract's terms. Anything that is not an HwipError
46
+ * never got an HTTP answer — fetch rejects on DNS, refused or reset. The code is read before the
47
+ * status: a refusal made here carries a status (400) the server never sent. */
48
+ const classifyNotifyFailure = (err) => {
49
+ if (err instanceof errors_js_1.AuthenticationError)
50
+ return { kind: 'auth', status: err.status, code: err.code };
51
+ if (err instanceof errors_js_1.QuotaExceededError)
52
+ return { kind: 'quota', status: err.status, code: err.code };
53
+ if (err instanceof errors_js_1.HwipError) {
54
+ const { status, code } = err;
55
+ if (code === 'NO_APP_DEVICE')
56
+ return { kind: 'no-app', status: null, code };
57
+ if (code === 'E2E_REQUIRED')
58
+ return { kind: 'unsealed', status: null, code };
59
+ if (code === 'TIMEOUT')
60
+ return { kind: 'timeout', status: null, code };
61
+ if (code === 'NETWORK_ERROR')
62
+ return { kind: 'network', status: null, code: null };
63
+ if (status === 429)
64
+ return { kind: 'rate-limit', status, code };
65
+ if (status >= 500)
66
+ return { kind: 'server', status, code };
67
+ return { kind: 'client', status, code };
68
+ }
69
+ return { kind: 'network', status: null, code: null };
70
+ };
71
+ exports.classifyNotifyFailure = classifyNotifyFailure;
72
+ /** Best effort: a hook must never fail because its failure could not be noted. */
73
+ const recordNotifyFailure = (failure, now = new Date()) => {
74
+ const record = { v: 1, at: now.toISOString(), ...failure };
75
+ const path = (0, exports.notifyFailurePath)();
76
+ const tmp = `${path}.${process.pid}.tmp`;
77
+ try {
78
+ (0, private_files_js_1.mkdirHandedBack)((0, gate_js_1.stateDir)());
79
+ // Temp + rename: a reader never sees half a file.
80
+ (0, fs_1.writeFileSync)(tmp, `${JSON.stringify(record)}\n`, { mode: 0o600 });
81
+ (0, private_files_js_1.handBackToSudoUser)(tmp);
82
+ (0, fs_1.renameSync)(tmp, path);
83
+ }
84
+ catch {
85
+ try {
86
+ (0, fs_1.unlinkSync)(tmp);
87
+ }
88
+ catch { /* never written */ }
89
+ }
90
+ };
91
+ exports.recordNotifyFailure = recordNotifyFailure;
92
+ const clearNotifyFailure = () => {
93
+ try {
94
+ (0, fs_1.unlinkSync)((0, exports.notifyFailurePath)());
95
+ }
96
+ catch { /* nothing recorded */ }
97
+ };
98
+ exports.clearNotifyFailure = clearNotifyFailure;
99
+ /** Run one push attempt and leave the record matching its outcome. */
100
+ const withNotifyFailureRecord = async (send) => {
101
+ try {
102
+ const result = await send();
103
+ (0, exports.clearNotifyFailure)();
104
+ return result;
105
+ }
106
+ catch (err) {
107
+ (0, exports.recordNotifyFailure)((0, exports.classifyNotifyFailure)(err));
108
+ throw err;
109
+ }
110
+ };
111
+ exports.withNotifyFailureRecord = withNotifyFailureRecord;
112
+ /** null when there is no record, or one this version cannot read. */
113
+ const readNotifyFailure = () => {
114
+ try {
115
+ const raw = JSON.parse((0, fs_1.readFileSync)((0, exports.notifyFailurePath)(), 'utf-8'));
116
+ if (raw.v !== 1 || typeof raw.at !== 'string')
117
+ return null;
118
+ if (!exports.NOTIFY_FAILURE_KINDS.includes(raw.kind))
119
+ return null;
120
+ return {
121
+ v: 1,
122
+ at: raw.at,
123
+ kind: raw.kind,
124
+ status: typeof raw.status === 'number' ? raw.status : null,
125
+ code: typeof raw.code === 'string' ? raw.code : null,
126
+ };
127
+ }
128
+ catch {
129
+ return null;
130
+ }
131
+ };
132
+ exports.readNotifyFailure = readNotifyFailure;
133
+ const KIND_TEXT = {
134
+ 'no-key': 'no API key — run: hwip install',
135
+ auth: 'API key rejected — it may have been revoked; run: hwip login',
136
+ quota: 'push quota used up',
137
+ 'rate-limit': 'rate limited by the server',
138
+ client: 'request rejected by the server',
139
+ server: 'server error',
140
+ timeout: 'request timed out',
141
+ network: 'could not reach the server',
142
+ 'no-app': 'no app is signed in — sign in to the Hwip app on an iPhone or Android phone',
143
+ unsealed: 'could not encrypt the push, so nothing was sent — run: hwip verify',
144
+ };
145
+ /** One line for a person: what, when, and the HTTP status when there was one. */
146
+ const describeNotifyFailure = (f) => `last push failed at ${f.at}: ${KIND_TEXT[f.kind]}${f.status === null ? '' : ` (HTTP ${f.status})`}`;
147
+ exports.describeNotifyFailure = describeNotifyFailure;
148
+ /** Transient kinds clear themselves on the next good push; the rest need the user. */
149
+ const isTransientNotifyFailure = (f) => f.kind === 'timeout' || f.kind === 'network' || f.kind === 'server' || f.kind === 'rate-limit';
150
+ exports.isTransientNotifyFailure = isTransientNotifyFailure;
@@ -0,0 +1,139 @@
1
+ /**
2
+ * opencode's session store, read into the events the timeline draws.
3
+ *
4
+ * opencode keeps no transcript file. 2.x writes every session to SQLite
5
+ * (`opencode.db`, WAL), one `session_message` row per user message and per
6
+ * assistant step, and rewrites an assistant row in place while it streams. So
7
+ * this file is both halves the other agents split: a reader that asks the
8
+ * database what changed (`readOpencodeTranscript`, the `TranscriptReader`
9
+ * behind the opencode row) and a projector for what it hands back
10
+ * (`projectOpencodeEntries`).
11
+ *
12
+ * Shape measured 2026-10-10 against opencode 2.0.24 — the schema with
13
+ * `.schema`, the JSON with `json_each` key and type counts over 3,965 rows on
14
+ * this machine, and a scratch store written by sessions run for the purpose.
15
+ * No conversation text was opened.
16
+ *
17
+ * - `session_message(id, session_id, type, seq, time_created, time_updated,
18
+ * data)`, `seq` increasing per session. `type` is `user` · `assistant` ·
19
+ * `system` · `synthetic` · `idle` · `compaction` · `*-switched`; only the
20
+ * first two are drawn.
21
+ * - user `data`: `{ text, time: { created }, files, agents, skills }`.
22
+ * - assistant `data`: `{ model: { id, providerID }, content: [...], tokens:
23
+ * { input, output, reasoning, cache: { read, write } }, time: { created,
24
+ * completed?, streamed? }, finish, … }` — `time.completed` is set once the
25
+ * step is over. `content` items are `{ type: "text", text }`,
26
+ * `{ type: "reasoning", … }` and `{ type: "tool", id, name, state: { status,
27
+ * input, content: [{ type: "text", text }], error }, time }`; a finished
28
+ * call is `completed` or `error`.
29
+ * - 1.x wrote `session` · `message` · `part` instead. 2.x leaves those alone
30
+ * and this file does not read them.
31
+ *
32
+ * The lines the reader hands over are `TurnEvent`s already, one JSON object
33
+ * each, so the projector only checks them. The work of deciding what is new
34
+ * lives in `opencodeLinesOf`, which is pure and is where the tests point.
35
+ */
36
+ import { type TailRead, type TailState, type TranscriptProjector } from './transcript-tail.js';
37
+ /** Where opencode 2.x keeps its store, by the rules opencode itself follows (`opencode debug paths db`, 2.0.24). */
38
+ export declare const opencodeDbPath: (env?: NodeJS.ProcessEnv) => string;
39
+ /**
40
+ * A session id as opencode mints them (`ses_` + base62, measured). The query
41
+ * below has nowhere to bind a parameter (`sqliteJson` runs the `sqlite3`
42
+ * binary), so an id goes into the SQL text only after it passes this.
43
+ */
44
+ export declare const OPENCODE_SESSION_ID: RegExp;
45
+ /**
46
+ * The transcript "path" an opencode pane resolves to: the store and the session
47
+ * in one string. A string because every consumer compares and logs paths, and
48
+ * because the session changing — a new one in the same pane — has to read as
49
+ * the path changing, which is what makes `turn-watch` start over on it.
50
+ */
51
+ export declare const opencodeSourcePath: (db: string, sessionId: string) => string;
52
+ /** One `content` item, reduced in SQL to the fields drawn — a tool's input and output can be megabytes. */
53
+ export interface OpencodeItem {
54
+ type?: string | null;
55
+ id?: string | null;
56
+ name?: string | null;
57
+ text?: string | null;
58
+ status?: string | null;
59
+ target?: string | null;
60
+ lines?: number | null;
61
+ at?: number | null;
62
+ }
63
+ /** One `session_message` row as the query below returns it. */
64
+ export interface OpencodeRow {
65
+ id: string;
66
+ seq: number;
67
+ type: string;
68
+ created: number;
69
+ completed?: number | null;
70
+ text?: string | null;
71
+ model?: string | null;
72
+ out?: number | null;
73
+ input?: number | null;
74
+ cacheRead?: number | null;
75
+ cacheWrite?: number | null;
76
+ /** `error.type` of a step that failed (`provider.quota`, `aborted`, …). */
77
+ errorType?: string | null;
78
+ errorText?: string | null;
79
+ items?: OpencodeItem[] | string | null;
80
+ }
81
+ /** Rows read on the first look at a session — enough for the turn in flight and a screen above it. */
82
+ export declare const OPENCODE_BACKFILL_ROWS = 200;
83
+ /** Rows read per look after that. */
84
+ export declare const OPENCODE_ROWS_PER_READ = 500;
85
+ /** How far behind the newest row an unfinished one may hold the read position. */
86
+ export declare const OPENCODE_OPEN_WINDOW = 200;
87
+ /** The fewest milliseconds between two queries for one session. */
88
+ export declare const OPENCODE_MIN_QUERY_MS = 1000;
89
+ /**
90
+ * The rows of one session from `from` on, or its last `OPENCODE_BACKFILL_ROWS`
91
+ * when `from` is null. Exported for the test that pins the id check.
92
+ */
93
+ export declare const opencodeRowsSql: (sessionId: string, from: number | null) => string;
94
+ /**
95
+ * What these rows add to what was already sent, and where the next read starts.
96
+ *
97
+ * Every piece of a row gets a key (`<seq>:<part><index>`), and a key sent once
98
+ * is never sent again. A user row is final when written. An assistant row is
99
+ * not: its text is sent once something follows it in the row or the row is
100
+ * closed, a tool call once it runs, its result once the call has one, and
101
+ * the step's token count and any error when the step is finished. A row is
102
+ * closed when it is finished, when a later assistant step exists (opencode
103
+ * starts one only after the last is over, so an unfinished one behind it died
104
+ * mid-stream), or when it falls out of the `OPENCODE_OPEN_WINDOW` rows behind
105
+ * the newest — closing is what sends a dead step's last words, which nothing
106
+ * would otherwise send. `from` stays on the oldest row still open, so the next
107
+ * read sees it again. `emitted` keeps only the keys at or after `from`;
108
+ * nothing before it is read again.
109
+ */
110
+ export declare const opencodeLinesOf: (rows: readonly OpencodeRow[], sent: {
111
+ from: number;
112
+ emitted: readonly string[];
113
+ }) => {
114
+ lines: string[];
115
+ from: number;
116
+ emitted: string[];
117
+ };
118
+ export interface OpencodeReadDeps {
119
+ /** Rows of a SQLite file, null when the read failed (`sqliteJson`). */
120
+ query: (db: string, sql: string) => unknown[] | null;
121
+ /** The store's files, size and mtime — any write to the session shows up in one of them. */
122
+ stamp?: (db: string) => string | null;
123
+ now?: () => number;
124
+ }
125
+ /**
126
+ * What changed in one opencode session since `prev`, or null when nothing did
127
+ * — the store's files have not moved, the last query was under
128
+ * `OPENCODE_MIN_QUERY_MS` ago, or the store cannot be read. The WAL moves on
129
+ * every write by every opencode session on this machine, so the time floor is
130
+ * what keeps a busy neighbour from turning a 500 ms poll into a `sqlite3`
131
+ * spawn per tick.
132
+ */
133
+ export declare const readOpencodeTranscript: (path: string, prev: TailState | null, deps: OpencodeReadDeps) => TailRead | null;
134
+ /**
135
+ * The reader's lines back into events. They were built as events, so this
136
+ * only refuses what is not one and names what the reader marked unknown.
137
+ */
138
+ export declare const projectOpencodeEntries: TranscriptProjector;
139
+ //# sourceMappingURL=opencode-transcript.d.ts.map