@agentdeck/bridge 1.0.18 → 1.0.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.
- package/dist/adapters/claude-code.d.ts +4 -2
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +9 -10
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/codex-cli.d.ts +3 -4
- package/dist/adapters/codex-cli.d.ts.map +1 -1
- package/dist/adapters/codex-cli.js +8 -12
- package/dist/adapters/codex-cli.js.map +1 -1
- package/dist/adapters/pty-adapter.d.ts +2 -2
- package/dist/adapters/pty-adapter.js +2 -2
- package/dist/apme/adapters/codex-turn-manager.d.ts +13 -77
- package/dist/apme/adapters/codex-turn-manager.d.ts.map +1 -1
- package/dist/apme/adapters/codex-turn-manager.js +97 -403
- package/dist/apme/adapters/codex-turn-manager.js.map +1 -1
- package/dist/check-deps.d.ts.map +1 -1
- package/dist/check-deps.js +3 -1
- package/dist/check-deps.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +19 -3
- package/dist/cli.js.map +1 -1
- package/dist/codex-rate-limits.d.ts +1 -1
- package/dist/codex-rate-limits.d.ts.map +1 -1
- package/dist/codex-rate-limits.js +27 -17
- package/dist/codex-rate-limits.js.map +1 -1
- package/dist/daemon.js +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -192
- package/dist/index.js.map +1 -1
- package/dist/state-machine.d.ts +5 -0
- package/dist/state-machine.d.ts.map +1 -1
- package/dist/state-machine.js +34 -4
- package/dist/state-machine.js.map +1 -1
- package/dist/types.d.ts +11 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -3
- package/dist/apme/adapters/claude-pty.d.ts +0 -28
- package/dist/apme/adapters/claude-pty.d.ts.map +0 -1
- package/dist/apme/adapters/claude-pty.js +0 -88
- package/dist/apme/adapters/claude-pty.js.map +0 -1
|
@@ -67,10 +67,17 @@ function candidateRolloutFiles(root, maxDays = 3, maxFiles = 6) {
|
|
|
67
67
|
files.sort((a, b) => b.mtime - a.mtime);
|
|
68
68
|
return files.slice(0, maxFiles);
|
|
69
69
|
}
|
|
70
|
-
/** Scan
|
|
71
|
-
*
|
|
72
|
-
*
|
|
70
|
+
/** Scan every candidate and return the usable rate-limits snapshot with the
|
|
71
|
+
* newest CAPTURE timestamp.
|
|
72
|
+
*
|
|
73
|
+
* File mtime only identifies which rollouts are active enough to inspect. It
|
|
74
|
+
* cannot decide which ACCOUNT snapshot is newest when several Codex sessions
|
|
75
|
+
* append concurrently: a reasoning/tool line can make one file newest while
|
|
76
|
+
* its last rate_limits line is older than a snapshot in another file. Choosing
|
|
77
|
+
* the first usable file made usage move backwards or appear frozen. */
|
|
73
78
|
function parseFirstUsable(candidates) {
|
|
79
|
+
let newest = null;
|
|
80
|
+
let newestCapturedAtMs = -Infinity;
|
|
74
81
|
for (const { full, mtime } of candidates) {
|
|
75
82
|
const tail = readTail(full);
|
|
76
83
|
const parsed = tail ? parseCodexRateLimitsFromText(tail) : null;
|
|
@@ -81,10 +88,14 @@ function parseFirstUsable(candidates) {
|
|
|
81
88
|
// reading stays put — that would under-report the age of exactly the frozen
|
|
82
89
|
// snapshot this anchor exists to expose. mtime is the fallback.
|
|
83
90
|
parsed.capturedAt = parsed.capturedAt ?? new Date(mtime).toISOString();
|
|
84
|
-
|
|
91
|
+
const capturedAtMs = new Date(parsed.capturedAt).getTime();
|
|
92
|
+
if (!newest || capturedAtMs > newestCapturedAtMs) {
|
|
93
|
+
newest = parsed;
|
|
94
|
+
newestCapturedAtMs = capturedAtMs;
|
|
95
|
+
}
|
|
85
96
|
}
|
|
86
97
|
}
|
|
87
|
-
return
|
|
98
|
+
return newest;
|
|
88
99
|
}
|
|
89
100
|
/**
|
|
90
101
|
* Read the newest usable Codex rate-limits snapshot from a sessions tree.
|
|
@@ -115,7 +126,9 @@ function readTail(file, maxBytes = 262144) {
|
|
|
115
126
|
try {
|
|
116
127
|
fs.closeSync(fd);
|
|
117
128
|
}
|
|
118
|
-
catch {
|
|
129
|
+
catch {
|
|
130
|
+
/* ignore */
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
function toCredits(raw) {
|
|
@@ -140,9 +153,7 @@ function toWindow(raw) {
|
|
|
140
153
|
if (!raw || typeof raw.used_percent !== 'number' || typeof raw.window_minutes !== 'number') {
|
|
141
154
|
return undefined;
|
|
142
155
|
}
|
|
143
|
-
const resetsAt = typeof raw.resets_at === 'number' && raw.resets_at > 0
|
|
144
|
-
? new Date(raw.resets_at * 1000).toISOString()
|
|
145
|
-
: undefined;
|
|
156
|
+
const resetsAt = typeof raw.resets_at === 'number' && raw.resets_at > 0 ? new Date(raw.resets_at * 1000).toISOString() : undefined;
|
|
146
157
|
return {
|
|
147
158
|
usedPercent: Math.min(100, Math.max(0, raw.used_percent)),
|
|
148
159
|
windowMinutes: raw.window_minutes,
|
|
@@ -189,16 +200,15 @@ export function parseCodexRateLimitsFromText(text) {
|
|
|
189
200
|
}
|
|
190
201
|
return null;
|
|
191
202
|
}
|
|
192
|
-
// Cache keyed on
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
203
|
+
// Cache keyed on EVERY candidate rollout's path + mtime. Multiple Codex
|
|
204
|
+
// sessions append concurrently, and the freshest rate_limits snapshot may live
|
|
205
|
+
// outside candidates[0]. Keying on only that first file let a newer snapshot in
|
|
206
|
+
// another candidate remain invisible until the first file changed again.
|
|
196
207
|
let cacheKey = '';
|
|
197
208
|
let cacheValue = null;
|
|
198
|
-
export function readCodexRateLimits() {
|
|
199
|
-
const candidates = candidateRolloutFiles(
|
|
200
|
-
const
|
|
201
|
-
const key = newest ? `${newest.full}:${newest.mtime}` : '';
|
|
209
|
+
export function readCodexRateLimits(root = defaultSessionsRoot()) {
|
|
210
|
+
const candidates = candidateRolloutFiles(root);
|
|
211
|
+
const key = candidates.map(({ full, mtime }) => `${full}:${mtime}`).join('|');
|
|
202
212
|
if (key && key === cacheKey)
|
|
203
213
|
return cacheValue;
|
|
204
214
|
const parsed = parseFirstUsable(candidates);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-rate-limits.js","sourceRoot":"","sources":["../src/codex-rate-limits.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"codex-rate-limits.js","sourceRoot":"","sources":["../src/codex-rate-limits.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.js
CHANGED
|
@@ -17,7 +17,7 @@ const program = new Command();
|
|
|
17
17
|
program
|
|
18
18
|
.name('agentdeck')
|
|
19
19
|
.description('AgentDeck daemon (legacy entry point — use `agentdeck daemon` instead)')
|
|
20
|
-
.version('1.0.
|
|
20
|
+
.version('1.0.19');
|
|
21
21
|
program
|
|
22
22
|
.command('start', { isDefault: true })
|
|
23
23
|
.description('Start monitoring daemon')
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2DH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAUxD,OAAO,EAOL,KAAK,SAAS,EAQf,MAAM,YAAY,CAAC;AAwDpB,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,wEAAwE;IACxE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;kFAC8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;0EACsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,wBAAsB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA8nCtE"}
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,6 @@ import { readLastTurn as readClaudeTranscriptLastTurn } from './apme/claude-tran
|
|
|
14
14
|
import { claudeHookToSpans } from './apme/adapters/claude-hook.js';
|
|
15
15
|
import { codexHookToSpans } from './apme/adapters/codex-hook.js';
|
|
16
16
|
import { CodexTurnManager } from './apme/adapters/codex-turn-manager.js';
|
|
17
|
-
import { claudePtyParserEventToSpans, claudePtyResponseToSpan } from './apme/adapters/claude-pty.js';
|
|
18
17
|
import { timelineEntryToSpans } from './apme/adapters/timeline.js';
|
|
19
18
|
import { classifyAndEnqueueTurn } from './apme/classify-turn.js';
|
|
20
19
|
import { VoiceManager } from './voice.js';
|
|
@@ -106,6 +105,13 @@ export async function startSession(opts) {
|
|
|
106
105
|
process.exit(1);
|
|
107
106
|
for (const w of deps.warnings)
|
|
108
107
|
log(`WARNING: ${w}`);
|
|
108
|
+
if (agentType === 'codex-cli' && deps.agentVersion) {
|
|
109
|
+
const { satisfiesRange } = await import('./version-check.js');
|
|
110
|
+
if (!satisfiesRange(deps.agentVersion, '>=0.141.0')) {
|
|
111
|
+
log(`WARNING: Codex ${deps.agentVersion} predates the lifecycle-hook baseline (>=0.141.0). ` +
|
|
112
|
+
'The terminal can start, but AgentDeck lifecycle monitoring requires a newer Codex CLI.');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
109
115
|
// Version compatibility check (Claude Code only — uses npm registry + compatibleClaudeCode range)
|
|
110
116
|
if (agentType === 'claude-code' && !opts.noUpdateCheck) {
|
|
111
117
|
const { checkVersionCompatibility } = await import('./version-check.js');
|
|
@@ -443,20 +449,13 @@ export async function startSession(opts) {
|
|
|
443
449
|
});
|
|
444
450
|
// Claude Code hook events → timeline entries
|
|
445
451
|
if (agentType === 'claude-code') {
|
|
446
|
-
wireClaudeCodeTimeline(adapter, core
|
|
452
|
+
wireClaudeCodeTimeline(adapter, core);
|
|
447
453
|
}
|
|
448
454
|
// APME wiring for non-Claude-Code agents (OpenCode, Codex, OpenClaw)
|
|
449
455
|
if (apme && agentType !== 'claude-code' && agentType !== 'monitor') {
|
|
450
|
-
wireAgentApme(adapter, agentType, apme, core
|
|
456
|
+
wireAgentApme(adapter, agentType, apme, core);
|
|
451
457
|
}
|
|
452
458
|
// ===== Wire adapter events → StateMachine + journal =====
|
|
453
|
-
// APME: PTY response fallback — captures response from terminal output when
|
|
454
|
-
// the Stop hook doesn't fire (unreliable in Claude Code v2.1+).
|
|
455
|
-
// Three capture paths handle the hook/PTY race condition:
|
|
456
|
-
// Path A: idle fires, turn exists → apply directly
|
|
457
|
-
// Path B: idle fires before hook (fast responses) → buffer, apply on hook arrival
|
|
458
|
-
// Path C: UserPromptSubmit closes prev turn → apply PTY text to closed turn
|
|
459
|
-
let pendingPtyResponse = null;
|
|
460
459
|
adapter.on('event', (evt) => {
|
|
461
460
|
switch (evt.source) {
|
|
462
461
|
case 'hook':
|
|
@@ -479,28 +478,6 @@ export async function startSession(opts) {
|
|
|
479
478
|
apme.collector.ingestSpan(core.sessionId, span);
|
|
480
479
|
}
|
|
481
480
|
}
|
|
482
|
-
if (evt.event === 'UserPromptSubmit' && apme) {
|
|
483
|
-
// Path B: apply buffered response to the NEW turn (idle fired before hook)
|
|
484
|
-
if (pendingPtyResponse) {
|
|
485
|
-
debug('APME', `hook:UPS Path B: applying pending (${pendingPtyResponse.length} chars)`);
|
|
486
|
-
const ctx = makeApmeAdapterCtx(apme, core.sessionId, agentType);
|
|
487
|
-
const span = claudePtyResponseToSpan(ctx, pendingPtyResponse);
|
|
488
|
-
if (span)
|
|
489
|
-
apme.collector.ingestSpan(core.sessionId, span);
|
|
490
|
-
pendingPtyResponse = null;
|
|
491
|
-
}
|
|
492
|
-
// Path C: prev turn was just closed by ingestHook — apply pending response
|
|
493
|
-
if (pendingPtyResponse) {
|
|
494
|
-
debug('APME', `hook:UPS Path C: applying pending to closed turn (${pendingPtyResponse.length} chars)`);
|
|
495
|
-
const ctx = makeApmeAdapterCtx(apme, core.sessionId, agentType);
|
|
496
|
-
const span = claudePtyResponseToSpan(ctx, pendingPtyResponse, { fallbackToLastClosed: true });
|
|
497
|
-
if (span)
|
|
498
|
-
apme.collector.ingestSpan(core.sessionId, span);
|
|
499
|
-
pendingPtyResponse = null;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
if (evt.event === 'Stop')
|
|
503
|
-
pendingPtyResponse = null; // Stop has cleaner response
|
|
504
481
|
// APME-off fallback: task rows from boundary hooks alone.
|
|
505
482
|
if (fallbackTasks)
|
|
506
483
|
fallbackTasks.ingestHook(core.sessionId, evt.event, evt.data ?? {});
|
|
@@ -511,67 +488,14 @@ export async function startSession(opts) {
|
|
|
511
488
|
core.stateMachine.handleHookEvent(evt.event, evt.data);
|
|
512
489
|
break;
|
|
513
490
|
case 'parser':
|
|
514
|
-
|
|
491
|
+
// Structured adapters (OpenCode SSE / OpenClaw Gateway) normalize
|
|
492
|
+
// their native event streams into the legacy state vocabulary.
|
|
493
|
+
journal.write('adapter_signal', agentType, { event: evt.event, ...evt.data });
|
|
515
494
|
core.stateMachine.handleParserEvent(evt.event, evt.data);
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
for (const span of claudePtyParserEventToSpans(ctx, evt.event, evt.data ?? {})) {
|
|
521
|
-
apme.collector.ingestSpan(core.sessionId, span);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
// APME: Path A — spinner_stop fires when Claude finishes responding.
|
|
525
|
-
// Delay 500ms to let response render in PTY, then extract text after ⏺ marker.
|
|
526
|
-
if (apme && evt.event === 'spinner_stop') {
|
|
527
|
-
const sid = core.sessionId;
|
|
528
|
-
setTimeout(async () => {
|
|
529
|
-
if (!apme)
|
|
530
|
-
return;
|
|
531
|
-
const tail = ptyRingBuffer.getTail(5000);
|
|
532
|
-
// Claude's response starts with ⏺ — extract content after last ⏺ marker.
|
|
533
|
-
// Take only meaningful lines (stop at spinner chars ✢✻⏸, prompt ❯, or separator ──).
|
|
534
|
-
const marker = tail.lastIndexOf('⏺');
|
|
535
|
-
let response = '';
|
|
536
|
-
if (marker >= 0) {
|
|
537
|
-
const afterMarker = tail.slice(marker + 1).trim();
|
|
538
|
-
const lines = afterMarker.split('\n');
|
|
539
|
-
const clean = [];
|
|
540
|
-
for (const line of lines) {
|
|
541
|
-
const trimmed = line.trim();
|
|
542
|
-
if (!trimmed)
|
|
543
|
-
continue;
|
|
544
|
-
// Stop at UI artifacts: spinner chars (✢✳✶✻✽), plan mode (⏸), prompt (❯), separator (─)
|
|
545
|
-
if (/^[✢✳✶✻✽⏸⏵❯─>]/.test(trimmed))
|
|
546
|
-
break;
|
|
547
|
-
if (/planmode|plan\s*mode|shift\+tab|accept\s*edits/i.test(trimmed))
|
|
548
|
-
break;
|
|
549
|
-
// Status text: "Whirring…", "Finagling…", token count, shortcuts hint
|
|
550
|
-
if (/^\S+…(\s|$)/.test(trimmed) && /tokens|shortcuts|\d+[ms]\s/i.test(trimmed))
|
|
551
|
-
break;
|
|
552
|
-
if (/\?\s*for\s*shortcuts/.test(trimmed))
|
|
553
|
-
break;
|
|
554
|
-
clean.push(trimmed);
|
|
555
|
-
}
|
|
556
|
-
response = clean.join('\n').trim();
|
|
557
|
-
}
|
|
558
|
-
debug('APME', `spinner_stop+500ms: tailLen=${tail.length} marker=${marker} respLen=${response.length}`);
|
|
559
|
-
if (response.length > 2) {
|
|
560
|
-
const turnId = apme.collector.getActiveTurnId(sid);
|
|
561
|
-
if (turnId) {
|
|
562
|
-
const ctx = makeApmeAdapterCtx(apme, sid, agentType);
|
|
563
|
-
const span = claudePtyResponseToSpan(ctx, response);
|
|
564
|
-
if (span)
|
|
565
|
-
apme.collector.ingestSpan(sid, span);
|
|
566
|
-
pendingPtyResponse = null;
|
|
567
|
-
await classifyAndEnqueueTurn(apme, sid);
|
|
568
|
-
}
|
|
569
|
-
else {
|
|
570
|
-
pendingPtyResponse = response;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
}, 500);
|
|
574
|
-
}
|
|
495
|
+
break;
|
|
496
|
+
case 'terminal_ui':
|
|
497
|
+
journal.write('terminal_ui', 'pty', { event: evt.event, ...evt.data });
|
|
498
|
+
core.stateMachine.handleTerminalUiEvent(evt.event, evt.data);
|
|
575
499
|
break;
|
|
576
500
|
case 'metadata':
|
|
577
501
|
switch (evt.event) {
|
|
@@ -587,11 +511,6 @@ export async function startSession(opts) {
|
|
|
587
511
|
const text = evt.data?.text;
|
|
588
512
|
if (text)
|
|
589
513
|
core.broadcast({ type: 'user_prompt', text });
|
|
590
|
-
// APME: user_prompt is the PTY-detected prompt — use it to open a turn
|
|
591
|
-
// and capture the prompt text (fallback for when hooks don't fire).
|
|
592
|
-
if (apme && text) {
|
|
593
|
-
apme.collector.ingestHook(core.sessionId, 'UserPromptSubmit', { message: { content: text } });
|
|
594
|
-
}
|
|
595
514
|
break;
|
|
596
515
|
}
|
|
597
516
|
case 'model_catalog': {
|
|
@@ -1266,14 +1185,12 @@ export async function startSession(opts) {
|
|
|
1266
1185
|
// ===== Non-Claude agent APME wiring =====
|
|
1267
1186
|
// For OpenCode, Codex, OpenClaw: intercepts adapter timeline events to create
|
|
1268
1187
|
// APME turns with prompts and responses. Claude Code uses hooks instead.
|
|
1269
|
-
function wireAgentApme(adapter, agentType, apme, core
|
|
1188
|
+
function wireAgentApme(adapter, agentType, apme, core) {
|
|
1270
1189
|
const sid = core.sessionId;
|
|
1271
|
-
// Codex turn boundaries
|
|
1272
|
-
// module
|
|
1273
|
-
// machine plus the hook-fresh shortcut so non-codex sessions allocate
|
|
1274
|
-
// nothing here.
|
|
1190
|
+
// Codex turn boundaries and rollout response capture live in their own
|
|
1191
|
+
// hook-owned module so non-Codex sessions allocate nothing here.
|
|
1275
1192
|
const codexManager = agentType === 'codex-cli'
|
|
1276
|
-
? new CodexTurnManager(core, apme,
|
|
1193
|
+
? new CodexTurnManager(core, apme, sid, agentType)
|
|
1277
1194
|
: null;
|
|
1278
1195
|
adapter.on('event', (evt) => {
|
|
1279
1196
|
if (evt.source === 'hook' && isSubagentOnlyHook(evt.event, evt.data ?? {})) {
|
|
@@ -1309,12 +1226,10 @@ function wireAgentApme(adapter, agentType, apme, core, ptyRingBuffer) {
|
|
|
1309
1226
|
void classifyAndEnqueueTurn(apme, sid);
|
|
1310
1227
|
}
|
|
1311
1228
|
}
|
|
1312
|
-
// ── Codex:
|
|
1229
|
+
// ── Codex: lifecycle hooks + notify turn-complete fallback ──
|
|
1313
1230
|
if (codexManager) {
|
|
1314
1231
|
if (evt.source === 'hook')
|
|
1315
1232
|
codexManager.onHookEvent(evt);
|
|
1316
|
-
else if (evt.source === 'parser')
|
|
1317
|
-
codexManager.onParserEvent(evt);
|
|
1318
1233
|
}
|
|
1319
1234
|
});
|
|
1320
1235
|
if (codexManager) {
|
|
@@ -1338,14 +1253,12 @@ function isClaudeTaskNotificationPrompt(text) {
|
|
|
1338
1253
|
return text.trim().toLowerCase().startsWith('<task-notification>');
|
|
1339
1254
|
}
|
|
1340
1255
|
// ===== Claude Code timeline wiring =====
|
|
1341
|
-
function wireClaudeCodeTimeline(adapter, core
|
|
1256
|
+
function wireClaudeCodeTimeline(adapter, core) {
|
|
1342
1257
|
let ccChatStart = null;
|
|
1343
1258
|
let ccPendingChatStart = false;
|
|
1344
1259
|
let ccPendingChatStartTimer = null;
|
|
1345
1260
|
let ccLastPromptText = null;
|
|
1346
|
-
let
|
|
1347
|
-
let ccPendingCompletion = false; // Change 2: track pending chat_end for PTY fallback
|
|
1348
|
-
let ccPendingCompletionTimer = null;
|
|
1261
|
+
let ccPendingCompletion = false;
|
|
1349
1262
|
const emitChatStart = (text) => {
|
|
1350
1263
|
if (ccPendingChatStartTimer) {
|
|
1351
1264
|
clearTimeout(ccPendingChatStartTimer);
|
|
@@ -1376,33 +1289,8 @@ function wireClaudeCodeTimeline(adapter, core, journal, ptyRingBuffer) {
|
|
|
1376
1289
|
startedAt: ccChatStart ?? Date.now(),
|
|
1377
1290
|
});
|
|
1378
1291
|
};
|
|
1379
|
-
/** Extract response text from PTY ringbuffer after ⏺ marker (same pattern as APME) */
|
|
1380
|
-
const extractPtyResponse = () => {
|
|
1381
|
-
const tail = ptyRingBuffer.getTail(5000);
|
|
1382
|
-
const marker = tail.lastIndexOf('⏺');
|
|
1383
|
-
if (marker < 0)
|
|
1384
|
-
return '';
|
|
1385
|
-
const afterMarker = tail.slice(marker + 1).trim();
|
|
1386
|
-
const lines = afterMarker.split('\n');
|
|
1387
|
-
const clean = [];
|
|
1388
|
-
for (const line of lines) {
|
|
1389
|
-
const trimmed = line.trim();
|
|
1390
|
-
if (!trimmed)
|
|
1391
|
-
continue;
|
|
1392
|
-
if (/^[✢✳✶✻✽⏸⏵❯─>]/.test(trimmed))
|
|
1393
|
-
break;
|
|
1394
|
-
if (/planmode|plan\s*mode|shift\+tab|accept\s*edits/i.test(trimmed))
|
|
1395
|
-
break;
|
|
1396
|
-
if (/^\S+…(\s|$)/.test(trimmed) && /tokens|shortcuts|\d+[ms]\s/i.test(trimmed))
|
|
1397
|
-
break;
|
|
1398
|
-
if (/\?\s*for\s*shortcuts/.test(trimmed))
|
|
1399
|
-
break;
|
|
1400
|
-
clean.push(trimmed);
|
|
1401
|
-
}
|
|
1402
|
-
return clean.join('\n').trim();
|
|
1403
|
-
};
|
|
1404
1292
|
/**
|
|
1405
|
-
* Emit a single Claude turn-close row
|
|
1293
|
+
* Emit a single Claude turn-close row from the authoritative Stop hook:
|
|
1406
1294
|
* a `chat_response` when there is meaningful response text, otherwise a
|
|
1407
1295
|
* `chat_end`. The two are mutually exclusive so a turn never produces both —
|
|
1408
1296
|
* the paired dimmed `chat_end` used to fragment every turn into three rows on
|
|
@@ -1501,48 +1389,6 @@ function wireClaudeCodeTimeline(adapter, core, journal, ptyRingBuffer) {
|
|
|
1501
1389
|
}
|
|
1502
1390
|
}
|
|
1503
1391
|
});
|
|
1504
|
-
// Change 1: PTY tool_action → tool_exec timeline entry (fills gap when hooks don't fire)
|
|
1505
|
-
adapter.on('event', (evt) => {
|
|
1506
|
-
if (evt.source !== 'parser' || evt.event !== 'tool_action')
|
|
1507
|
-
return;
|
|
1508
|
-
const now = Date.now();
|
|
1509
|
-
// Skip if hook already emitted tool_request within 2s (avoid duplicates)
|
|
1510
|
-
if (now - ccLastHookToolTs < 2000)
|
|
1511
|
-
return;
|
|
1512
|
-
const toolName = evt.data?.toolName || 'tool';
|
|
1513
|
-
const toolArgs = evt.data?.toolArgs || '';
|
|
1514
|
-
const raw = toolArgs ? `${toolName} ${toolArgs}` : toolName;
|
|
1515
|
-
core.bridgeTimeline.addEntry({
|
|
1516
|
-
ts: now, type: 'tool_exec',
|
|
1517
|
-
raw: raw.length > 500 ? raw.slice(0, 497) + '...' : raw,
|
|
1518
|
-
agentType: 'claude-code',
|
|
1519
|
-
});
|
|
1520
|
-
});
|
|
1521
|
-
// Change 2: PTY fallback chat_end from spinner_stop/idle (when Stop hook doesn't fire)
|
|
1522
|
-
adapter.on('event', (evt) => {
|
|
1523
|
-
if (evt.source !== 'parser')
|
|
1524
|
-
return;
|
|
1525
|
-
if ((evt.event === 'spinner_stop' || evt.event === 'idle') && ccPendingCompletion) {
|
|
1526
|
-
// Wait 1.5s — Stop hook may still arrive
|
|
1527
|
-
if (ccPendingCompletionTimer)
|
|
1528
|
-
clearTimeout(ccPendingCompletionTimer);
|
|
1529
|
-
ccPendingCompletionTimer = setTimeout(() => {
|
|
1530
|
-
ccPendingCompletionTimer = null;
|
|
1531
|
-
if (!ccPendingCompletion)
|
|
1532
|
-
return; // Stop hook already handled it
|
|
1533
|
-
ccPendingCompletion = false;
|
|
1534
|
-
if (ccPendingChatStart)
|
|
1535
|
-
emitChatStart('');
|
|
1536
|
-
const now = Date.now();
|
|
1537
|
-
const duration = ccChatStart ? Math.round((now - ccChatStart) / 1000) : null;
|
|
1538
|
-
const toolSummary = core.usageTracker.getToolSummary();
|
|
1539
|
-
// Extract response from PTY ringbuffer
|
|
1540
|
-
const responseText = extractPtyResponse();
|
|
1541
|
-
debug('timeline', `CC PTY fallback chat_end: respLen=${responseText.length} duration=${duration}`);
|
|
1542
|
-
emitCompletion(responseText, duration, toolSummary);
|
|
1543
|
-
}, 1500);
|
|
1544
|
-
}
|
|
1545
|
-
});
|
|
1546
1392
|
adapter.on('event', (evt) => {
|
|
1547
1393
|
if (evt.source !== 'hook')
|
|
1548
1394
|
return;
|
|
@@ -1554,7 +1400,7 @@ function wireClaudeCodeTimeline(adapter, core, journal, ptyRingBuffer) {
|
|
|
1554
1400
|
ccChatStart = now;
|
|
1555
1401
|
core.usageTracker.resetToolCounts();
|
|
1556
1402
|
ccPendingChatStart = true;
|
|
1557
|
-
ccPendingCompletion = true;
|
|
1403
|
+
ccPendingCompletion = true;
|
|
1558
1404
|
// Claude Code v2.1+ sends { message: { content: "..." } }, not { prompt: "..." }
|
|
1559
1405
|
const msg = evt.data?.message;
|
|
1560
1406
|
const hookText = evt.data?.prompt
|
|
@@ -1569,7 +1415,6 @@ function wireClaudeCodeTimeline(adapter, core, journal, ptyRingBuffer) {
|
|
|
1569
1415
|
break;
|
|
1570
1416
|
}
|
|
1571
1417
|
case 'PreToolUse': {
|
|
1572
|
-
ccLastHookToolTs = now; // Change 1: mark hook tool time for dedup
|
|
1573
1418
|
const toolName = evt.data?.tool_name || 'tool';
|
|
1574
1419
|
const formatted = formatToolInputForTimeline(toolName, evt.data?.tool_input);
|
|
1575
1420
|
core.bridgeTimeline.addEntry({
|
|
@@ -1586,18 +1431,10 @@ function wireClaudeCodeTimeline(adapter, core, journal, ptyRingBuffer) {
|
|
|
1586
1431
|
break;
|
|
1587
1432
|
}
|
|
1588
1433
|
case 'Stop': {
|
|
1589
|
-
// Race guard: if ccPendingCompletion is already false, the PTY fallback
|
|
1590
|
-
// timer fired first (Stop hook arrived >1.5s after spinner_stop) and
|
|
1591
|
-
// already emitted chat_response/chat_end. Skipping here prevents the
|
|
1592
|
-
// duplicate-line bug visible on the dashboard timeline.
|
|
1593
1434
|
const wasPending = ccPendingCompletion;
|
|
1594
|
-
ccPendingCompletion = false;
|
|
1595
|
-
if (ccPendingCompletionTimer) {
|
|
1596
|
-
clearTimeout(ccPendingCompletionTimer);
|
|
1597
|
-
ccPendingCompletionTimer = null;
|
|
1598
|
-
}
|
|
1435
|
+
ccPendingCompletion = false;
|
|
1599
1436
|
if (!wasPending) {
|
|
1600
|
-
debug('timeline', '
|
|
1437
|
+
debug('timeline', 'duplicate Claude Stop hook ignored');
|
|
1601
1438
|
break;
|
|
1602
1439
|
}
|
|
1603
1440
|
if (ccPendingChatStart)
|
|
@@ -1612,8 +1449,6 @@ function wireClaudeCodeTimeline(adapter, core, journal, ptyRingBuffer) {
|
|
|
1612
1449
|
// payload points at it.
|
|
1613
1450
|
// 2. last_assistant_message — ~18% reliable field on the hook
|
|
1614
1451
|
// payload; honoured when the transcript isn't reachable.
|
|
1615
|
-
// 3. PTY ringbuffer — last-resort fallback already handled by
|
|
1616
|
-
// the existing spinner_stop pathway.
|
|
1617
1452
|
const transcriptPath = evt.data?.transcript_path || '';
|
|
1618
1453
|
let lastAssistantMsg = evt.data?.last_assistant_message || '';
|
|
1619
1454
|
if (transcriptPath) {
|