@hwip/cli 0.0.1 → 0.1.1
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.
- package/LICENSE +190 -0
- package/NOTICE +11 -0
- package/README.md +1983 -0
- package/dist/agent-list.d.ts +76 -0
- package/dist/agent-list.js +102 -0
- package/dist/agent-read.d.ts +105 -0
- package/dist/agent-read.js +309 -0
- package/dist/agent-rules-fetch.d.ts +51 -0
- package/dist/agent-rules-fetch.js +275 -0
- package/dist/agent-rules.default.d.ts +30 -0
- package/dist/agent-rules.default.js +305 -0
- package/dist/agent-session.d.ts +23 -0
- package/dist/agent-session.js +44 -0
- package/dist/agent-state.d.ts +84 -0
- package/dist/agent-state.js +188 -0
- package/dist/agent-target.d.ts +60 -0
- package/dist/agent-target.js +81 -0
- package/dist/agents.d.ts +31 -0
- package/dist/agents.js +75 -0
- package/dist/api.d.ts +28 -0
- package/dist/api.js +76 -0
- package/dist/args.d.ts +74 -0
- package/dist/args.js +254 -0
- package/dist/ask-context-attach.d.ts +73 -0
- package/dist/ask-context-attach.js +151 -0
- package/dist/ask-context-screen.d.ts +21 -0
- package/dist/ask-context-screen.js +49 -0
- package/dist/ask-context-switch.d.ts +31 -0
- package/dist/ask-context-switch.js +74 -0
- package/dist/ask-context.d.ts +84 -0
- package/dist/ask-context.js +172 -0
- package/dist/ask-pending.d.ts +47 -0
- package/dist/ask-pending.js +221 -0
- package/dist/ask-seal.d.ts +120 -0
- package/dist/ask-seal.js +179 -0
- package/dist/ask.d.ts +107 -0
- package/dist/ask.js +551 -0
- package/dist/blocked-prompt-seal.d.ts +39 -0
- package/dist/blocked-prompt-seal.js +92 -0
- package/dist/blocked-prompt.d.ts +62 -0
- package/dist/blocked-prompt.js +518 -0
- package/dist/channel.d.ts +67 -0
- package/dist/channel.js +136 -0
- package/dist/check-update.d.ts +28 -0
- package/dist/check-update.js +153 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +813 -0
- package/dist/codex-config.d.ts +24 -0
- package/dist/codex-config.js +169 -0
- package/dist/codex-transcript.d.ts +59 -0
- package/dist/codex-transcript.js +373 -0
- package/dist/command-refusal.d.ts +56 -0
- package/dist/command-refusal.js +127 -0
- package/dist/command-scan.d.ts +46 -0
- package/dist/command-scan.js +154 -0
- package/dist/command-seal.d.ts +57 -0
- package/dist/command-seal.js +88 -0
- package/dist/command-seq.d.ts +30 -0
- package/dist/command-seq.js +150 -0
- package/dist/config.d.ts +156 -0
- package/dist/config.js +392 -0
- package/dist/core-sections.d.ts +18 -0
- package/dist/core-sections.js +28 -0
- package/dist/crypto.d.ts +278 -0
- package/dist/crypto.js +698 -0
- package/dist/desktop-notify.d.ts +33 -0
- package/dist/desktop-notify.js +49 -0
- package/dist/device-directory.d.ts +36 -0
- package/dist/device-directory.js +97 -0
- package/dist/device-presence.d.ts +17 -0
- package/dist/device-presence.js +62 -0
- package/dist/downloads.d.ts +29 -0
- package/dist/downloads.js +106 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +28 -0
- package/dist/file-crypto.d.ts +94 -0
- package/dist/file-crypto.js +278 -0
- package/dist/file-view-budget.d.ts +15 -0
- package/dist/file-view-budget.js +34 -0
- package/dist/file-view-switch.d.ts +28 -0
- package/dist/file-view-switch.js +122 -0
- package/dist/file-view.d.ts +108 -0
- package/dist/file-view.js +327 -0
- package/dist/gate.d.ts +141 -0
- package/dist/gate.js +336 -0
- package/dist/gemini-transcript.d.ts +32 -0
- package/dist/gemini-transcript.js +189 -0
- package/dist/http-failure.d.ts +98 -0
- package/dist/http-failure.js +349 -0
- package/dist/hwip-core.generated.d.ts +7 -0
- package/dist/hwip-core.generated.js +14 -0
- package/dist/hwip-hook.d.ts +77 -0
- package/dist/hwip-hook.js +340 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +14 -0
- package/dist/input-sequencer.d.ts +65 -0
- package/dist/input-sequencer.js +142 -0
- package/dist/insecure-url.d.ts +16 -0
- package/dist/insecure-url.js +76 -0
- package/dist/installer.d.ts +96 -0
- package/dist/installer.js +850 -0
- package/dist/inventory-offload.d.ts +49 -0
- package/dist/inventory-offload.js +209 -0
- package/dist/inventory-worker.d.ts +2 -0
- package/dist/inventory-worker.js +27 -0
- package/dist/jsonc-doc.d.ts +106 -0
- package/dist/jsonc-doc.js +354 -0
- package/dist/keep-awake.d.ts +32 -0
- package/dist/keep-awake.js +46 -0
- package/dist/key-changes.d.ts +48 -0
- package/dist/key-changes.js +140 -0
- package/dist/lan-auth.d.ts +140 -0
- package/dist/lan-auth.js +217 -0
- package/dist/lan-endpoint.d.ts +41 -0
- package/dist/lan-endpoint.js +115 -0
- package/dist/lan-receiver.d.ts +122 -0
- package/dist/lan-receiver.js +510 -0
- package/dist/lan-sender.d.ts +76 -0
- package/dist/lan-sender.js +184 -0
- package/dist/lan-transfer.d.ts +36 -0
- package/dist/lan-transfer.js +54 -0
- package/dist/listener-device-id.d.ts +20 -0
- package/dist/listener-device-id.js +133 -0
- package/dist/listener-log.d.ts +4 -0
- package/dist/listener-log.js +23 -0
- package/dist/listener-process.d.ts +200 -0
- package/dist/listener-process.js +470 -0
- package/dist/listener-service.d.ts +225 -0
- package/dist/listener-service.js +682 -0
- package/dist/listener-worktree-cleanup.d.ts +27 -0
- package/dist/listener-worktree-cleanup.js +62 -0
- package/dist/listener.d.ts +1325 -0
- package/dist/listener.js +5681 -0
- package/dist/login-address.d.ts +25 -0
- package/dist/login-address.js +97 -0
- package/dist/login-page.d.ts +29 -0
- package/dist/login-page.js +93 -0
- package/dist/login.d.ts +98 -0
- package/dist/login.js +388 -0
- package/dist/mcp-command.d.ts +45 -0
- package/dist/mcp-command.js +50 -0
- package/dist/mcp.d.ts +19 -0
- package/dist/mcp.js +29 -0
- package/dist/node-support.d.ts +19 -0
- package/dist/node-support.js +38 -0
- package/dist/notify-failure.d.ts +57 -0
- package/dist/notify-failure.js +150 -0
- package/dist/opencode-transcript.d.ts +139 -0
- package/dist/opencode-transcript.js +390 -0
- package/dist/optional-features.d.ts +6 -0
- package/dist/optional-features.js +19 -0
- package/dist/pane-fit.d.ts +40 -0
- package/dist/pane-fit.js +119 -0
- package/dist/peer-key.d.ts +33 -0
- package/dist/peer-key.js +34 -0
- package/dist/pi-transcript.d.ts +26 -0
- package/dist/pi-transcript.js +255 -0
- package/dist/presence.d.ts +14 -0
- package/dist/presence.js +124 -0
- package/dist/private-files.d.ts +51 -0
- package/dist/private-files.js +218 -0
- package/dist/project-switch.d.ts +19 -0
- package/dist/project-switch.js +60 -0
- package/dist/redact.d.ts +10 -0
- package/dist/redact.js +21 -0
- package/dist/remote-agents.d.ts +410 -0
- package/dist/remote-agents.js +1218 -0
- package/dist/remote-hook.d.ts +12 -0
- package/dist/remote-hook.js +196 -0
- package/dist/replace-file.d.ts +50 -0
- package/dist/replace-file.js +328 -0
- package/dist/schedule-command.d.ts +35 -0
- package/dist/schedule-command.js +260 -0
- package/dist/schedule-launch.d.ts +15 -0
- package/dist/schedule-launch.js +24 -0
- package/dist/schedule-ready.d.ts +44 -0
- package/dist/schedule-ready.js +71 -0
- package/dist/schedule-remote.d.ts +77 -0
- package/dist/schedule-remote.js +167 -0
- package/dist/schedule-runner.d.ts +89 -0
- package/dist/schedule-runner.js +452 -0
- package/dist/schedule.d.ts +149 -0
- package/dist/schedule.js +428 -0
- package/dist/secret-mask.d.ts +29 -0
- package/dist/secret-mask.js +245 -0
- package/dist/self-register.d.ts +45 -0
- package/dist/self-register.js +67 -0
- package/dist/send.d.ts +56 -0
- package/dist/send.js +104 -0
- package/dist/session-diff.d.ts +161 -0
- package/dist/session-diff.js +445 -0
- package/dist/session-registry.d.ts +143 -0
- package/dist/session-registry.js +216 -0
- package/dist/sessions-report.d.ts +59 -0
- package/dist/sessions-report.js +99 -0
- package/dist/shell-audit.d.ts +34 -0
- package/dist/shell-audit.js +47 -0
- package/dist/subagent-transcripts.d.ts +167 -0
- package/dist/subagent-transcripts.js +437 -0
- package/dist/subscriber-trust.d.ts +128 -0
- package/dist/subscriber-trust.js +397 -0
- package/dist/templates.d.ts +105 -0
- package/dist/templates.js +871 -0
- package/dist/tmux-install.d.ts +44 -0
- package/dist/tmux-install.js +65 -0
- package/dist/tmux-liveness.d.ts +45 -0
- package/dist/tmux-liveness.js +71 -0
- package/dist/tmux-pane.d.ts +55 -0
- package/dist/tmux-pane.js +126 -0
- package/dist/tmux-socket.d.ts +20 -0
- package/dist/tmux-socket.js +292 -0
- package/dist/todo-fold.d.ts +31 -0
- package/dist/todo-fold.js +102 -0
- package/dist/transcript-tail.d.ts +312 -0
- package/dist/transcript-tail.js +718 -0
- package/dist/trust-command.d.ts +49 -0
- package/dist/trust-command.js +200 -0
- package/dist/trust-lock.d.ts +26 -0
- package/dist/trust-lock.js +94 -0
- package/dist/trust-pins.d.ts +37 -0
- package/dist/trust-pins.js +82 -0
- package/dist/turn-recorder-wire.d.ts +70 -0
- package/dist/turn-recorder-wire.js +165 -0
- package/dist/turn-recorder.d.ts +190 -0
- package/dist/turn-recorder.js +695 -0
- package/dist/turn-ring.d.ts +93 -0
- package/dist/turn-ring.js +418 -0
- package/dist/turn-watch.d.ts +177 -0
- package/dist/turn-watch.js +630 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.js +2 -0
- package/dist/uninstall.d.ts +55 -0
- package/dist/uninstall.js +507 -0
- package/dist/usage.d.ts +17 -0
- package/dist/usage.js +421 -0
- package/dist/verify.d.ts +47 -0
- package/dist/verify.js +396 -0
- package/dist/worktree.d.ts +144 -0
- package/dist/worktree.js +310 -0
- package/dist/wrapper.d.ts +254 -0
- package/dist/wrapper.js +704 -0
- package/dist/ws-url.d.ts +109 -0
- package/dist/ws-url.js +202 -0
- package/package.json +78 -10
- 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
|