@songsid/agend 2.1.3 → 2.1.4-beta.10
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 +21 -0
- package/README.md +2 -2
- package/README.zh-TW.md +2 -2
- package/dist/backend/antigravity.d.ts +1 -0
- package/dist/backend/antigravity.js +1 -0
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.d.ts +1 -0
- package/dist/backend/claude-code.js +24 -2
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.d.ts +1 -0
- package/dist/backend/codex.js +43 -4
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/gemini-cli.d.ts +1 -0
- package/dist/backend/gemini-cli.js +1 -0
- package/dist/backend/gemini-cli.js.map +1 -1
- package/dist/backend/grok.d.ts +1 -0
- package/dist/backend/grok.js +1 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +1 -0
- package/dist/backend/kiro.js +1 -0
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/mock.d.ts +1 -0
- package/dist/backend/mock.js +1 -0
- package/dist/backend/mock.js.map +1 -1
- package/dist/backend/opencode.d.ts +40 -0
- package/dist/backend/opencode.js +83 -5
- package/dist/backend/opencode.js.map +1 -1
- package/dist/backend/types.d.ts +10 -0
- package/dist/backend/types.js +7 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.js +24 -7
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/mcp-server.js +6 -20
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.js +1 -1
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/types.d.ts +1 -1
- package/dist/classic-channel-manager.d.ts +34 -3
- package/dist/classic-channel-manager.js +190 -31
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +74 -23
- package/dist/cli.js.map +1 -1
- package/dist/completion-install.d.ts +70 -0
- package/dist/completion-install.js +152 -0
- package/dist/completion-install.js.map +1 -0
- package/dist/completion.d.ts +7 -1
- package/dist/completion.js +14 -4
- package/dist/completion.js.map +1 -1
- package/dist/config-validator.js +35 -7
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +53 -9
- package/dist/daemon.js +222 -86
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-context.d.ts +8 -0
- package/dist/fleet-manager.d.ts +136 -5
- package/dist/fleet-manager.js +1088 -316
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/backend-providers/SKILL.md +114 -0
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +3 -1
- package/dist/general-knowledge/skills/delegation-playbook/SKILL.md +52 -0
- package/dist/general-knowledge/skills/development-workflow/SKILL.md +28 -0
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +1 -0
- package/dist/general-knowledge/skills/fleet-health/SKILL.md +1 -0
- package/dist/general-knowledge/skills/fleet-restart/SKILL.md +1 -0
- package/dist/general-knowledge/skills/instance-lifecycle/SKILL.md +1 -0
- package/dist/general-knowledge/skills/model-discovery/SKILL.md +1 -0
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -0
- package/dist/general-knowledge/skills/scheduling/SKILL.md +1 -0
- package/dist/general-knowledge/skills/session-management/SKILL.md +1 -0
- package/dist/general-knowledge/skills/tui-effort/SKILL.md +1 -0
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +30 -0
- package/dist/instance-lifecycle.d.ts +10 -0
- package/dist/instance-lifecycle.js +50 -33
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +12 -0
- package/dist/instructions.js +33 -0
- package/dist/instructions.js.map +1 -1
- package/dist/locale.js +130 -0
- package/dist/locale.js.map +1 -1
- package/dist/outbound-schemas.d.ts +2 -1
- package/dist/outbound-schemas.js +1 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/quickstart.js +29 -2
- package/dist/quickstart.js.map +1 -1
- package/dist/restart-progress.d.ts +7 -1
- package/dist/restart-progress.js +27 -6
- package/dist/restart-progress.js.map +1 -1
- package/dist/setup-wizard.d.ts +4 -2
- package/dist/setup-wizard.js +2 -2
- package/dist/setup-wizard.js.map +1 -1
- package/dist/tool-progress.d.ts +40 -0
- package/dist/tool-progress.js +289 -0
- package/dist/tool-progress.js.map +1 -0
- package/dist/topic-commands.d.ts +26 -0
- package/dist/topic-commands.js +117 -1
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-monitor.d.ts +15 -2
- package/dist/transcript-monitor.js +63 -17
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-sources.d.ts +106 -0
- package/dist/transcript-sources.js +428 -0
- package/dist/transcript-sources.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/ui/dashboard.html +5 -4
- package/dist/update-marker.d.ts +30 -0
- package/dist/update-marker.js +71 -20
- package/dist/update-marker.js.map +1 -1
- package/dist/update-progress.d.ts +6 -0
- package/dist/update-progress.js +29 -0
- package/dist/update-progress.js.map +1 -0
- package/dist/web-api.js +2 -2
- package/dist/web-api.js.map +1 -1
- package/dist/workflow-templates/default.md +2 -1
- package/package.json +2 -2
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-backend tool-event sources for the transcript monitor.
|
|
3
|
+
*
|
|
4
|
+
* claude-code keeps its transcript path in statusline.json and is handled
|
|
5
|
+
* inside TranscriptMonitor itself (it predates this file). The sources here
|
|
6
|
+
* cover backends whose CLIs persist their conversation elsewhere:
|
|
7
|
+
*
|
|
8
|
+
* codex — rollout JSONL under <codex home>/sessions/YYYY/MM/DD/,
|
|
9
|
+
* matched to this instance by session_meta.cwd (sessions are a
|
|
10
|
+
* shared symlinked dir across instances, #507)
|
|
11
|
+
* kiro-cli — ~/.kiro/sessions/cli/<uuid>.jsonl with a sibling <uuid>.json
|
|
12
|
+
* carrying { cwd, updated_at }
|
|
13
|
+
* opencode — $XDG_DATA_HOME/opencode/opencode.db `part` table rows of
|
|
14
|
+
* data JSON { type: "tool", tool, state.input }, matched by the
|
|
15
|
+
* `session` table's directory column
|
|
16
|
+
*
|
|
17
|
+
* Common rules, learned the hard way (#528 traps):
|
|
18
|
+
* - No persisted byte offsets. Codex writes a fresh rollout per process and
|
|
19
|
+
* kiro/opencode keep full history — a stale offset is meaningless at best
|
|
20
|
+
* and replays history at worst.
|
|
21
|
+
* - First attach to a PRE-EXISTING transcript baselines to its end: only
|
|
22
|
+
* new work emits. A transcript that APPEARS after the source was created
|
|
23
|
+
* is this instance's own new session and is read from the start.
|
|
24
|
+
* - Every poll re-resolves which transcript is active. Pinning to the first
|
|
25
|
+
* one found silently goes blind when the CLI starts a new session.
|
|
26
|
+
*/
|
|
27
|
+
import { closeSync, existsSync, openSync, readdirSync, readFileSync, readSync, statSync } from "node:fs";
|
|
28
|
+
import { open, stat } from "node:fs/promises";
|
|
29
|
+
import { homedir } from "node:os";
|
|
30
|
+
import { join } from "node:path";
|
|
31
|
+
const EMPTY = { toolUses: [], toolResults: [], assistantTexts: [] };
|
|
32
|
+
function emptyEvents() {
|
|
33
|
+
return { toolUses: [], toolResults: [], assistantTexts: [] };
|
|
34
|
+
}
|
|
35
|
+
/** Shared JSONL tailer: byte-offset incremental reads of a single file. */
|
|
36
|
+
async function readNewLines(path, fromOffset) {
|
|
37
|
+
const stats = await stat(path);
|
|
38
|
+
if (stats.size <= fromOffset)
|
|
39
|
+
return { lines: [], newOffset: fromOffset };
|
|
40
|
+
const fh = await open(path, "r");
|
|
41
|
+
try {
|
|
42
|
+
const length = stats.size - fromOffset;
|
|
43
|
+
const buffer = Buffer.alloc(length);
|
|
44
|
+
await fh.read(buffer, 0, length, fromOffset);
|
|
45
|
+
return { lines: buffer.toString("utf-8").split("\n").filter(l => l.trim()), newOffset: stats.size };
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
await fh.close();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/* ------------------------------------------------------------------ codex */
|
|
52
|
+
/**
|
|
53
|
+
* Follows the newest rollout JSONL whose session_meta.cwd matches this
|
|
54
|
+
* instance's working directory. Rollouts are date-sharded and shared across
|
|
55
|
+
* instances, so cwd is the only reliable ownership signal.
|
|
56
|
+
*/
|
|
57
|
+
export class CodexRolloutSource {
|
|
58
|
+
workingDirectory;
|
|
59
|
+
sessionsDir;
|
|
60
|
+
currentFile = null;
|
|
61
|
+
byteOffset = 0;
|
|
62
|
+
createdAt;
|
|
63
|
+
/** Files whose session_meta was read and did NOT match our cwd. */
|
|
64
|
+
rejected = new Set();
|
|
65
|
+
constructor(workingDirectory, sessionsDir = join(process.env.CODEX_HOME?.trim() || join(homedir(), ".codex"), "sessions"), now = Date.now()) {
|
|
66
|
+
this.workingDirectory = workingDirectory;
|
|
67
|
+
this.sessionsDir = sessionsDir;
|
|
68
|
+
this.createdAt = now;
|
|
69
|
+
}
|
|
70
|
+
reset() {
|
|
71
|
+
this.currentFile = null;
|
|
72
|
+
this.byteOffset = 0;
|
|
73
|
+
}
|
|
74
|
+
/** Newest rollout files first, bounded to the last two date shards. */
|
|
75
|
+
candidateFiles() {
|
|
76
|
+
const out = [];
|
|
77
|
+
const walk = (dir, depth) => {
|
|
78
|
+
let entries;
|
|
79
|
+
try {
|
|
80
|
+
entries = readdirSync(dir);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Date-sharded YYYY/MM/DD tree: at each level only the two newest
|
|
86
|
+
// subdirs can contain today's/yesterday's rollouts.
|
|
87
|
+
const dirs = [];
|
|
88
|
+
for (const e of entries) {
|
|
89
|
+
const p = join(dir, e);
|
|
90
|
+
try {
|
|
91
|
+
const st = statSync(p);
|
|
92
|
+
if (st.isDirectory())
|
|
93
|
+
dirs.push(e);
|
|
94
|
+
else if (depth >= 3 && e.startsWith("rollout-") && e.endsWith(".jsonl")) {
|
|
95
|
+
out.push({ path: p, mtimeMs: st.mtimeMs });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch { /* raced with deletion */ }
|
|
99
|
+
}
|
|
100
|
+
if (depth < 3) {
|
|
101
|
+
for (const d of dirs.sort().reverse().slice(0, 2))
|
|
102
|
+
walk(join(dir, d), depth + 1);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
walk(this.sessionsDir, 0);
|
|
106
|
+
return out.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
107
|
+
}
|
|
108
|
+
fileBelongsToUs(path) {
|
|
109
|
+
if (this.rejected.has(path))
|
|
110
|
+
return false;
|
|
111
|
+
try {
|
|
112
|
+
// session_meta is the first line. It can carry long instructions, so
|
|
113
|
+
// give it headroom — but never read the whole rollout.
|
|
114
|
+
const fd = openSync(path, "r");
|
|
115
|
+
let head;
|
|
116
|
+
try {
|
|
117
|
+
const buf = Buffer.alloc(65536);
|
|
118
|
+
const bytes = readSync(fd, buf, 0, buf.length, 0);
|
|
119
|
+
head = buf.toString("utf-8", 0, bytes);
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
closeSync(fd);
|
|
123
|
+
}
|
|
124
|
+
const firstLine = head.split("\n")[0];
|
|
125
|
+
const meta = JSON.parse(firstLine);
|
|
126
|
+
const cwd = meta?.payload?.cwd;
|
|
127
|
+
if (meta?.type === "session_meta" && cwd === this.workingDirectory)
|
|
128
|
+
return true;
|
|
129
|
+
this.rejected.add(path);
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// First line unreadable/partial — retry next poll, do not cache the verdict.
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async poll() {
|
|
138
|
+
// Re-resolve every poll: a restarted codex writes a NEW rollout, and
|
|
139
|
+
// staying pinned to the old one goes silently blind (#528 trap 1).
|
|
140
|
+
const candidates = this.candidateFiles();
|
|
141
|
+
const active = candidates.find(c => this.fileBelongsToUs(c.path));
|
|
142
|
+
if (!active)
|
|
143
|
+
return EMPTY;
|
|
144
|
+
if (active.path !== this.currentFile) {
|
|
145
|
+
this.currentFile = active.path;
|
|
146
|
+
// A rollout born after this source existed is our own fresh session —
|
|
147
|
+
// read it from the start. A pre-existing one is history — baseline EOF.
|
|
148
|
+
if (active.mtimeMs >= this.createdAt) {
|
|
149
|
+
this.byteOffset = 0;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
try {
|
|
153
|
+
this.byteOffset = (await stat(active.path)).size;
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
this.byteOffset = 0;
|
|
157
|
+
}
|
|
158
|
+
return EMPTY;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const { lines, newOffset } = await readNewLines(this.currentFile, this.byteOffset);
|
|
162
|
+
this.byteOffset = newOffset;
|
|
163
|
+
const events = emptyEvents();
|
|
164
|
+
for (const line of lines) {
|
|
165
|
+
let entry;
|
|
166
|
+
try {
|
|
167
|
+
entry = JSON.parse(line);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (entry.type !== "response_item")
|
|
173
|
+
continue;
|
|
174
|
+
const p = entry.payload;
|
|
175
|
+
if (!p)
|
|
176
|
+
continue;
|
|
177
|
+
if (p.type === "function_call") {
|
|
178
|
+
let input = p.arguments;
|
|
179
|
+
if (typeof input === "string") {
|
|
180
|
+
try {
|
|
181
|
+
input = JSON.parse(input);
|
|
182
|
+
}
|
|
183
|
+
catch { /* keep raw */ }
|
|
184
|
+
}
|
|
185
|
+
events.toolUses.push({ name: String(p.name ?? "unknown"), input });
|
|
186
|
+
}
|
|
187
|
+
else if (p.type === "custom_tool_call") {
|
|
188
|
+
events.toolUses.push({ name: String(p.name ?? "unknown"), input: p.input });
|
|
189
|
+
}
|
|
190
|
+
else if (p.type === "local_shell_call") {
|
|
191
|
+
const action = p.action;
|
|
192
|
+
events.toolUses.push({ name: "shell", input: { command: action?.command } });
|
|
193
|
+
}
|
|
194
|
+
else if (p.type === "function_call_output" || p.type === "custom_tool_call_output") {
|
|
195
|
+
events.toolResults.push({ name: String(p.name ?? "unknown") });
|
|
196
|
+
}
|
|
197
|
+
else if (p.type === "message" && p.role === "assistant") {
|
|
198
|
+
const content = p.content;
|
|
199
|
+
for (const block of content ?? []) {
|
|
200
|
+
const text = block.text;
|
|
201
|
+
if (typeof text === "string" && text.trim())
|
|
202
|
+
events.assistantTexts.push(text);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return events;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/* -------------------------------------------------------------------- kiro */
|
|
210
|
+
/**
|
|
211
|
+
* Follows the newest kiro session whose metadata cwd matches this instance's
|
|
212
|
+
* working directory. Session transcript is <uuid>.jsonl; ownership and
|
|
213
|
+
* recency come from the sibling <uuid>.json ({ cwd, updated_at,
|
|
214
|
+
* session_created_reason }).
|
|
215
|
+
*/
|
|
216
|
+
export class KiroSessionSource {
|
|
217
|
+
workingDirectory;
|
|
218
|
+
sessionsDir;
|
|
219
|
+
currentFile = null;
|
|
220
|
+
byteOffset = 0;
|
|
221
|
+
createdAt;
|
|
222
|
+
constructor(workingDirectory, sessionsDir = join(homedir(), ".kiro", "sessions", "cli"), now = Date.now()) {
|
|
223
|
+
this.workingDirectory = workingDirectory;
|
|
224
|
+
this.sessionsDir = sessionsDir;
|
|
225
|
+
this.createdAt = now;
|
|
226
|
+
}
|
|
227
|
+
reset() {
|
|
228
|
+
this.currentFile = null;
|
|
229
|
+
this.byteOffset = 0;
|
|
230
|
+
}
|
|
231
|
+
resolveActiveSession() {
|
|
232
|
+
let entries;
|
|
233
|
+
try {
|
|
234
|
+
entries = readdirSync(this.sessionsDir);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
let best = null;
|
|
240
|
+
for (const e of entries) {
|
|
241
|
+
if (!e.endsWith(".json") || e.endsWith(".jsonl"))
|
|
242
|
+
continue;
|
|
243
|
+
const metaPath = join(this.sessionsDir, e);
|
|
244
|
+
try {
|
|
245
|
+
const meta = JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
246
|
+
if (meta.cwd !== this.workingDirectory)
|
|
247
|
+
continue;
|
|
248
|
+
// Subagent sessions are children of a turn already being reported.
|
|
249
|
+
if (meta.session_created_reason === "subagent")
|
|
250
|
+
continue;
|
|
251
|
+
const updated = Date.parse(meta.updated_at ?? "") || 0;
|
|
252
|
+
const created = Date.parse(meta.created_at ?? "") || 0;
|
|
253
|
+
if (!best || updated > best.updated) {
|
|
254
|
+
const jsonlPath = join(this.sessionsDir, e.replace(/\.json$/, ".jsonl"));
|
|
255
|
+
best = { jsonlPath, updated, createdAtMs: created };
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
catch { /* partially written metadata — next poll */ }
|
|
259
|
+
}
|
|
260
|
+
return best && existsSync(best.jsonlPath)
|
|
261
|
+
? { jsonlPath: best.jsonlPath, createdAtMs: best.createdAtMs }
|
|
262
|
+
: null;
|
|
263
|
+
}
|
|
264
|
+
async poll() {
|
|
265
|
+
const active = this.resolveActiveSession();
|
|
266
|
+
if (!active)
|
|
267
|
+
return EMPTY;
|
|
268
|
+
if (active.jsonlPath !== this.currentFile) {
|
|
269
|
+
this.currentFile = active.jsonlPath;
|
|
270
|
+
if (active.createdAtMs >= this.createdAt) {
|
|
271
|
+
this.byteOffset = 0; // our own fresh session — observable from the start
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
try {
|
|
275
|
+
this.byteOffset = (await stat(active.jsonlPath)).size;
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
this.byteOffset = 0;
|
|
279
|
+
}
|
|
280
|
+
return EMPTY;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const { lines, newOffset } = await readNewLines(this.currentFile, this.byteOffset);
|
|
284
|
+
this.byteOffset = newOffset;
|
|
285
|
+
const events = emptyEvents();
|
|
286
|
+
for (const line of lines) {
|
|
287
|
+
let entry;
|
|
288
|
+
try {
|
|
289
|
+
entry = JSON.parse(line);
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
collectKiroEvents(entry, events);
|
|
295
|
+
}
|
|
296
|
+
return events;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Kiro nests { kind: "toolUse", data: { name, input } } blocks inside
|
|
301
|
+
* AssistantMessage content; exact nesting has shifted across kiro versions,
|
|
302
|
+
* so walk the tree for the kind markers instead of hardcoding a path.
|
|
303
|
+
*/
|
|
304
|
+
function collectKiroEvents(node, out, depth = 0) {
|
|
305
|
+
if (depth > 8 || node === null || typeof node !== "object")
|
|
306
|
+
return;
|
|
307
|
+
if (Array.isArray(node)) {
|
|
308
|
+
for (const item of node)
|
|
309
|
+
collectKiroEvents(item, out, depth + 1);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const obj = node;
|
|
313
|
+
if (obj.kind === "toolUse" && obj.data && typeof obj.data === "object") {
|
|
314
|
+
const d = obj.data;
|
|
315
|
+
out.toolUses.push({ name: String(d.name ?? "unknown"), input: d.input });
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (obj.kind === "toolResult" && obj.data && typeof obj.data === "object") {
|
|
319
|
+
out.toolResults.push({ name: "toolResult" });
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
for (const value of Object.values(obj))
|
|
323
|
+
collectKiroEvents(value, out, depth + 1);
|
|
324
|
+
}
|
|
325
|
+
function loadSqlite() {
|
|
326
|
+
try {
|
|
327
|
+
return process
|
|
328
|
+
.getBuiltinModule?.("node:sqlite");
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
return undefined;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Reads tool parts from opencode's sqlite DB for the newest top-level
|
|
336
|
+
* session in this instance's working directory. Rows are cursored by
|
|
337
|
+
* time_created, which is immutable — a part that later flips from `running`
|
|
338
|
+
* to `completed` only changes time_updated, so each tool use emits once.
|
|
339
|
+
*
|
|
340
|
+
* Requires node:sqlite (Node ≥22.13); silently inert otherwise, matching the
|
|
341
|
+
* session-resume feature's degradation.
|
|
342
|
+
*/
|
|
343
|
+
export class OpenCodeDbSource {
|
|
344
|
+
workingDirectory;
|
|
345
|
+
dbPath;
|
|
346
|
+
sessionId = null;
|
|
347
|
+
partCursor = 0;
|
|
348
|
+
createdAt;
|
|
349
|
+
constructor(workingDirectory, dbPath = join(process.env.XDG_DATA_HOME || join(homedir(), ".local", "share"), "opencode", "opencode.db"), now = Date.now()) {
|
|
350
|
+
this.workingDirectory = workingDirectory;
|
|
351
|
+
this.dbPath = dbPath;
|
|
352
|
+
this.createdAt = now;
|
|
353
|
+
}
|
|
354
|
+
reset() {
|
|
355
|
+
this.sessionId = null;
|
|
356
|
+
this.partCursor = 0;
|
|
357
|
+
}
|
|
358
|
+
async poll() {
|
|
359
|
+
const sqlite = loadSqlite();
|
|
360
|
+
if (!sqlite || !existsSync(this.dbPath))
|
|
361
|
+
return EMPTY;
|
|
362
|
+
let db;
|
|
363
|
+
try {
|
|
364
|
+
db = new sqlite.DatabaseSync(this.dbPath, { readOnly: true });
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
return EMPTY;
|
|
368
|
+
}
|
|
369
|
+
try {
|
|
370
|
+
const session = db.prepare("SELECT id, time_created FROM session WHERE directory = ? AND parent_id IS NULL ORDER BY time_updated DESC LIMIT 1").get(this.workingDirectory);
|
|
371
|
+
if (!session)
|
|
372
|
+
return EMPTY;
|
|
373
|
+
if (session.id !== this.sessionId) {
|
|
374
|
+
this.sessionId = session.id;
|
|
375
|
+
// Fresh session started under us → report from its beginning;
|
|
376
|
+
// pre-existing session → only new parts.
|
|
377
|
+
this.partCursor = session.time_created >= this.createdAt ? 0 : Date.now();
|
|
378
|
+
}
|
|
379
|
+
const rows = db.prepare("SELECT data, time_created FROM part WHERE session_id = ? AND time_created > ? ORDER BY time_created ASC LIMIT 100").all(this.sessionId, this.partCursor);
|
|
380
|
+
const events = emptyEvents();
|
|
381
|
+
for (const row of rows) {
|
|
382
|
+
this.partCursor = Math.max(this.partCursor, row.time_created);
|
|
383
|
+
let data;
|
|
384
|
+
try {
|
|
385
|
+
data = JSON.parse(row.data);
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
if (data.type === "tool") {
|
|
391
|
+
const state = data.state;
|
|
392
|
+
events.toolUses.push({ name: String(data.tool ?? "unknown"), input: state?.input });
|
|
393
|
+
}
|
|
394
|
+
else if (data.type === "text") {
|
|
395
|
+
const text = data.text;
|
|
396
|
+
if (typeof text === "string" && text.trim())
|
|
397
|
+
events.assistantTexts.push(text);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return events;
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
return EMPTY;
|
|
404
|
+
}
|
|
405
|
+
finally {
|
|
406
|
+
try {
|
|
407
|
+
db.close();
|
|
408
|
+
}
|
|
409
|
+
catch { /* already closed */ }
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/* ----------------------------------------------------------------- factory */
|
|
414
|
+
/**
|
|
415
|
+
* Source for a backend, or null for backends handled elsewhere (claude-code
|
|
416
|
+
* lives inside TranscriptMonitor) and backends with no known source
|
|
417
|
+
* (antigravity, gemini-cli — nothing usable found on disk; grok has
|
|
418
|
+
* events.jsonl with tool names only and can be added later).
|
|
419
|
+
*/
|
|
420
|
+
export function createTranscriptSource(backend, workingDirectory) {
|
|
421
|
+
switch (backend) {
|
|
422
|
+
case "codex": return new CodexRolloutSource(workingDirectory);
|
|
423
|
+
case "kiro-cli": return new KiroSessionSource(workingDirectory);
|
|
424
|
+
case "opencode": return new OpenCodeDbSource(workingDirectory);
|
|
425
|
+
default: return null;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
//# sourceMappingURL=transcript-sources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcript-sources.js","sourceRoot":"","sources":["../src/transcript-sources.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -119,6 +119,12 @@ export interface InstanceConfig {
|
|
|
119
119
|
kiro_ui?: "legacy" | "tui" | "v3";
|
|
120
120
|
/** MCP tool profile: "full" (20 tools), "standard" (8), "minimal" (3). Default: "full" */
|
|
121
121
|
tool_set?: string;
|
|
122
|
+
/**
|
|
123
|
+
* Tool-progress detail shown in the channel processing bubble.
|
|
124
|
+
* "standard" (default) shows semantic labels with no shell arguments;
|
|
125
|
+
* "verbose" adds truncated command previews; "off" disables the list.
|
|
126
|
+
*/
|
|
127
|
+
tool_progress?: "off" | "standard" | "verbose";
|
|
122
128
|
/** Skip non-essential subsystems (transcript monitor, context guardian, approval server, prompt detector) */
|
|
123
129
|
lightweight?: boolean;
|
|
124
130
|
/** System prompt — supports comma-separated file: paths for modularization */
|
|
@@ -166,6 +172,8 @@ export interface InstanceConfig {
|
|
|
166
172
|
terminal?: TerminalConfig;
|
|
167
173
|
/** Command to paste raw before each user message (e.g. "/chat load base.json") */
|
|
168
174
|
pre_task_command?: string;
|
|
175
|
+
/** Per-backend options keyed by backend name (e.g. { codex: { provider: "glm" } }) */
|
|
176
|
+
backend_options?: Record<string, Record<string, unknown>>;
|
|
169
177
|
}
|
|
170
178
|
export interface WebhookConfig {
|
|
171
179
|
url: string;
|
package/dist/ui/dashboard.html
CHANGED
|
@@ -463,12 +463,13 @@ async function showCreateInstance() {
|
|
|
463
463
|
let backendOpts = '<option value="">Use fleet default</option>';
|
|
464
464
|
try {
|
|
465
465
|
const bd = await api("GET", "/ui/backends");
|
|
466
|
-
const first = (bd.backends || []).find(b => b.installed);
|
|
466
|
+
const first = (bd.backends || []).find(b => b.installed && !b.deprecated) || (bd.backends || []).find(b => b.installed);
|
|
467
467
|
backendOpts += (bd.backends || []).map(b => {
|
|
468
|
-
|
|
468
|
+
let label = b.deprecated ? `${b.name} (deprecated)` : b.name;
|
|
469
|
+
if (!b.installed) label += " (not installed)";
|
|
469
470
|
return `<option value="${b.name}" ${b.installed ? "" : "disabled"} ${b.name === first?.name ? "selected" : ""}>${label}</option>`;
|
|
470
471
|
}).join("");
|
|
471
|
-
} catch { backendOpts += ["claude-code","codex","
|
|
472
|
+
} catch { backendOpts += ["claude-code","codex","opencode","kiro-cli","antigravity","grok","gemini-cli"].map(b => `<option value="${b}">${b === "gemini-cli" ? "gemini-cli (deprecated)" : b}</option>`).join(""); }
|
|
472
473
|
ov.innerHTML = `<div class="form-card"><h2>Create Instance</h2>
|
|
473
474
|
<div class="form-field"><label>Directory</label><input id="ci-dir" placeholder="Optional — auto-creates workspace if empty"></div>
|
|
474
475
|
<div class="form-field"><label id="ci-topic-label">Topic Name</label><input id="ci-topic" placeholder="Auto from directory name"></div>
|
|
@@ -689,7 +690,7 @@ async function loadConfig() {
|
|
|
689
690
|
<div class="card"><h3>Defaults</h3>
|
|
690
691
|
<div class="form-field"><label>Backend</label>
|
|
691
692
|
<select id="cfg-backend">
|
|
692
|
-
${["claude-code","codex","
|
|
693
|
+
${["claude-code","codex","opencode","kiro-cli","antigravity","grok","gemini-cli"].map(b => `<option value="${b}" ${defs.backend===b?"selected":""}>${b === "gemini-cli" ? "gemini-cli (deprecated)" : b}</option>`).join("")}
|
|
693
694
|
</select></div>
|
|
694
695
|
</div>
|
|
695
696
|
<div class="card"><h3>Project Roots</h3>
|
package/dist/update-marker.d.ts
CHANGED
|
@@ -4,6 +4,36 @@
|
|
|
4
4
|
* one quiet window, not silence until someone notices.
|
|
5
5
|
*/
|
|
6
6
|
export declare const UPDATE_MARKER_MAX_AGE_MS: number;
|
|
7
|
+
export type UpdateProgressStage = "preparing" | "downloading" | "installed" | "stopping" | "starting" | "complete" | "failed";
|
|
8
|
+
export interface UpdateProgressTarget {
|
|
9
|
+
adapterId: string;
|
|
10
|
+
chatId: string;
|
|
11
|
+
threadId?: string;
|
|
12
|
+
messageId: string;
|
|
13
|
+
}
|
|
14
|
+
export interface UpdateProgressState {
|
|
15
|
+
stage: UpdateProgressStage;
|
|
16
|
+
target: UpdateProgressTarget;
|
|
17
|
+
version?: string;
|
|
18
|
+
error?: string;
|
|
19
|
+
failedStage?: UpdateProgressStage;
|
|
20
|
+
}
|
|
21
|
+
export interface UpdateMarker {
|
|
22
|
+
startedAt: number;
|
|
23
|
+
pid: number;
|
|
24
|
+
progress?: UpdateProgressState;
|
|
25
|
+
}
|
|
26
|
+
/** Persist the channel message that `/update` will edit across process restart. */
|
|
27
|
+
export declare function beginUpdateProgress(dataDir: string, target: UpdateProgressTarget, now?: number): void;
|
|
28
|
+
/** Read the live progress contract shared by the old CLI and the new fleet. */
|
|
29
|
+
export declare function readUpdateProgress(dataDir: string): (UpdateMarker & {
|
|
30
|
+
progress: UpdateProgressState;
|
|
31
|
+
}) | null;
|
|
32
|
+
/** Advance the cross-process progress state without losing its message target. */
|
|
33
|
+
export declare function setUpdateProgressStage(dataDir: string, stage: UpdateProgressStage, details?: {
|
|
34
|
+
version?: string;
|
|
35
|
+
error?: string;
|
|
36
|
+
}): boolean;
|
|
7
37
|
/** Called by `agend update` before it touches anything. */
|
|
8
38
|
export declare function markUpdateInProgress(dataDir: string, now?: number): void;
|
|
9
39
|
/** Called when the update finishes or gives up, and by the new fleet on startup. */
|
package/dist/update-marker.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* machine reboots) must not leave the fleet permanently unable to report a real
|
|
14
14
|
* crash — a stale marker is ignored, and the next fleet startup deletes it.
|
|
15
15
|
*/
|
|
16
|
-
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
16
|
+
import { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
17
17
|
import { join } from "node:path";
|
|
18
18
|
/**
|
|
19
19
|
* How long a marker is believed. Long enough for a slow npm install plus a
|
|
@@ -25,16 +25,75 @@ const FILE = "update-in-progress.json";
|
|
|
25
25
|
function markerPath(dataDir) {
|
|
26
26
|
return join(dataDir, FILE);
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
function readMarker(dataDir) {
|
|
29
|
+
try {
|
|
30
|
+
const parsed = JSON.parse(readFileSync(markerPath(dataDir), "utf-8"));
|
|
31
|
+
if (typeof parsed.startedAt !== "number" || !Number.isFinite(parsed.startedAt))
|
|
32
|
+
return null;
|
|
33
|
+
if (typeof parsed.pid !== "number" || !Number.isFinite(parsed.pid))
|
|
34
|
+
return null;
|
|
35
|
+
return parsed;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function writeMarker(dataDir, marker) {
|
|
42
|
+
const path = markerPath(dataDir);
|
|
43
|
+
const temp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
30
44
|
try {
|
|
31
|
-
writeFileSync(
|
|
45
|
+
writeFileSync(temp, JSON.stringify(marker), { mode: 0o600 });
|
|
46
|
+
renameSync(temp, path);
|
|
47
|
+
return true;
|
|
32
48
|
}
|
|
33
49
|
catch {
|
|
34
|
-
|
|
35
|
-
|
|
50
|
+
try {
|
|
51
|
+
unlinkSync(temp);
|
|
52
|
+
}
|
|
53
|
+
catch { /* best effort */ }
|
|
54
|
+
return false;
|
|
36
55
|
}
|
|
37
56
|
}
|
|
57
|
+
/** Persist the channel message that `/update` will edit across process restart. */
|
|
58
|
+
export function beginUpdateProgress(dataDir, target, now = Date.now()) {
|
|
59
|
+
writeMarker(dataDir, {
|
|
60
|
+
startedAt: now,
|
|
61
|
+
pid: process.pid,
|
|
62
|
+
progress: { stage: "preparing", target },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/** Read the live progress contract shared by the old CLI and the new fleet. */
|
|
66
|
+
export function readUpdateProgress(dataDir) {
|
|
67
|
+
const marker = readMarker(dataDir);
|
|
68
|
+
if (!marker?.progress?.target?.messageId || !marker.progress.target.adapterId)
|
|
69
|
+
return null;
|
|
70
|
+
return marker;
|
|
71
|
+
}
|
|
72
|
+
/** Advance the cross-process progress state without losing its message target. */
|
|
73
|
+
export function setUpdateProgressStage(dataDir, stage, details = {}) {
|
|
74
|
+
const marker = readMarker(dataDir);
|
|
75
|
+
if (!marker?.progress)
|
|
76
|
+
return false;
|
|
77
|
+
const previousStage = marker.progress.stage;
|
|
78
|
+
marker.pid = process.pid;
|
|
79
|
+
marker.progress = {
|
|
80
|
+
...marker.progress,
|
|
81
|
+
stage,
|
|
82
|
+
...(details.version !== undefined ? { version: details.version } : {}),
|
|
83
|
+
...(details.error !== undefined ? { error: details.error.replace(/\s+/g, " ").trim().slice(0, 300) } : {}),
|
|
84
|
+
...(stage === "failed" ? { failedStage: previousStage } : {}),
|
|
85
|
+
};
|
|
86
|
+
return writeMarker(dataDir, marker);
|
|
87
|
+
}
|
|
88
|
+
/** Called by `agend update` before it touches anything. */
|
|
89
|
+
export function markUpdateInProgress(dataDir, now = Date.now()) {
|
|
90
|
+
const existing = readMarker(dataDir);
|
|
91
|
+
writeMarker(dataDir, {
|
|
92
|
+
startedAt: existing?.startedAt ?? now,
|
|
93
|
+
pid: process.pid,
|
|
94
|
+
...(existing?.progress ? { progress: existing.progress } : {}),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
38
97
|
/** Called when the update finishes or gives up, and by the new fleet on startup. */
|
|
39
98
|
export function clearUpdateMarker(dataDir) {
|
|
40
99
|
try {
|
|
@@ -47,23 +106,15 @@ export function clearUpdateMarker(dataDir) {
|
|
|
47
106
|
* abandoned marker must not silence real incidents forever.
|
|
48
107
|
*/
|
|
49
108
|
export function isUpdateInProgress(dataDir, now = Date.now()) {
|
|
50
|
-
|
|
51
|
-
if (!existsSync(path))
|
|
109
|
+
if (!existsSync(markerPath(dataDir)))
|
|
52
110
|
return false;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
startedAt = parsed.startedAt;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
// Truncated or hand-edited: treat as unknown age rather than as fresh.
|
|
62
|
-
}
|
|
63
|
-
if (startedAt === null)
|
|
111
|
+
const marker = readMarker(dataDir);
|
|
112
|
+
if (!marker)
|
|
113
|
+
return false;
|
|
114
|
+
if (marker.progress?.stage === "failed" || marker.progress?.stage === "complete")
|
|
64
115
|
return false;
|
|
65
116
|
// A clock jump backwards would otherwise make a marker look infinitely fresh.
|
|
66
|
-
const age = now - startedAt;
|
|
117
|
+
const age = now - marker.startedAt;
|
|
67
118
|
return age >= 0 && age < UPDATE_MARKER_MAX_AGE_MS;
|
|
68
119
|
}
|
|
69
120
|
//# sourceMappingURL=update-marker.js.map
|