@jhizzard/termdeck 0.12.0 → 0.14.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.
- package/package.json +3 -2
- package/packages/client/public/app.js +60 -16
- package/packages/server/src/agent-adapters/claude.js +158 -0
- package/packages/server/src/agent-adapters/codex.js +199 -0
- package/packages/server/src/agent-adapters/gemini.js +158 -0
- package/packages/server/src/agent-adapters/grok-models.js +115 -0
- package/packages/server/src/agent-adapters/grok.js +253 -0
- package/packages/server/src/agent-adapters/index.js +61 -0
- package/packages/server/src/index.js +45 -6
- package/packages/server/src/rumen-pool-resilience.js +111 -0
- package/packages/server/src/session.js +72 -53
|
@@ -15,6 +15,8 @@ const os = require('os');
|
|
|
15
15
|
const path = require('path');
|
|
16
16
|
const { resolveTheme } = require('./theme-resolver');
|
|
17
17
|
const flashbackDiag = require('./flashback-diag');
|
|
18
|
+
const geminiAdapter = require('./agent-adapters/gemini');
|
|
19
|
+
const { detectAdapter, getAdapterForSessionType } = require('./agent-adapters');
|
|
18
20
|
|
|
19
21
|
// Strip ANSI escape codes for pattern matching
|
|
20
22
|
function stripAnsi(str) {
|
|
@@ -25,18 +27,33 @@ function stripAnsi(str) {
|
|
|
25
27
|
.replace(/\x1b[>=<]/g, ''); // Keypad/cursor modes
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
// Pattern matchers for detecting terminal type and status
|
|
30
|
+
// Pattern matchers for detecting terminal type and status.
|
|
31
|
+
//
|
|
32
|
+
// Sprint 45 T4 removed the Sprint 44 T3 Claude shim (`PATTERNS.claudeCode.*`
|
|
33
|
+
// and `PATTERNS.errorLineStart`). Claude-specific regexes now live exclusively
|
|
34
|
+
// at ./agent-adapters/claude.js — read via `claudeAdapter.patterns.*`. The
|
|
35
|
+
// `_detectErrors` and `_updateStatus` paths route through `getAdapterForSessionType`
|
|
36
|
+
// for any registered adapter.
|
|
37
|
+
//
|
|
38
|
+
// Sprint 45 T2 retains `PATTERNS.geminiCli` as a shim into the Gemini adapter
|
|
39
|
+
// for the one-release deprecation horizon — same pattern Sprint 44 T3 used.
|
|
40
|
+
// What stays in this file:
|
|
41
|
+
// • geminiCli — Sprint 45 T2 shim into ./agent-adapters/gemini.js
|
|
42
|
+
// • pythonServer — server SUBTYPE detection (no adapter; status-badge only)
|
|
43
|
+
// • shell — default fallback (no adapter)
|
|
44
|
+
// • error — cross-agent prose-shape primary error fallback (used
|
|
45
|
+
// by `_detectErrors` when the active adapter has no
|
|
46
|
+
// `patterns.error`, and exported for tests)
|
|
47
|
+
// • shellError — cross-agent Unix shell-error shapes (always tried as
|
|
48
|
+
// the secondary fallback in `_detectErrors`)
|
|
29
49
|
const PATTERNS = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
tool: /^⏺\s/m,
|
|
35
|
-
idle: /^>\s*$/m
|
|
36
|
-
},
|
|
50
|
+
// Sprint 45 T2: geminiCli patterns are owned by the Gemini adapter at
|
|
51
|
+
// ./agent-adapters/gemini.js. Shim preserves the legacy
|
|
52
|
+
// `PATTERNS.geminiCli.{prompt,thinking}` shape — same regex objects, so
|
|
53
|
+
// any external reference equality holds.
|
|
37
54
|
geminiCli: {
|
|
38
|
-
prompt:
|
|
39
|
-
thinking:
|
|
55
|
+
prompt: geminiAdapter.patterns.prompt,
|
|
56
|
+
thinking: geminiAdapter.patterns.thinking,
|
|
40
57
|
},
|
|
41
58
|
pythonServer: {
|
|
42
59
|
uvicorn: /Uvicorn running on/,
|
|
@@ -80,13 +97,12 @@ const PATTERNS = {
|
|
|
80
97
|
// child-process error reporting fire without depending on the line ALSO
|
|
81
98
|
// containing the `No such file or directory` prose phrase.
|
|
82
99
|
error: /(?:^|\n)\s*(?:Error:\s+\S|error:\s+\S|ERROR:\s+\S|Traceback \(most recent call last\):|npm ERR!|error\[E\d+\]:|Uncaught Exception|Fatal:|ENOENT:\s+\S|EACCES:\s+\S|ECONNREFUSED:\s+\S)/m,
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
errorLineStart: /^\s*(?:(?:error|Error|ERROR|exception|Exception|Traceback|fatal|Fatal|FATAL|segmentation fault|panic|EACCES|ECONNREFUSED|ENOENT|command not found|undefined reference|cannot find module|failed with exit code|No such file or directory|Permission denied)\b|npm ERR!)/m,
|
|
100
|
+
// Sprint 45 T4: the Claude-specific line-anchored variant
|
|
101
|
+
// (formerly `PATTERNS.errorLineStart`) is owned by the Claude adapter at
|
|
102
|
+
// ./agent-adapters/claude.js — read via `claudeAdapter.patterns.error`.
|
|
103
|
+
// _detectErrors below routes through `getAdapterForSessionType` for
|
|
104
|
+
// claude-code sessions and falls through to PATTERNS.error / shellError
|
|
105
|
+
// for non-adapter sessions.
|
|
90
106
|
// Sprint 33: PATTERNS.error misses the most common Unix shell errors —
|
|
91
107
|
// `cat: /foo: No such file or directory`, `bash: foo: command not found`,
|
|
92
108
|
// `rm: cannot remove ...: Permission denied`. These have a colon-prefix
|
|
@@ -241,11 +257,17 @@ class Session {
|
|
|
241
257
|
}
|
|
242
258
|
|
|
243
259
|
_detectType(data) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
260
|
+
// Sprint 44 T3 + Sprint 45: registry-aware detection. detectAdapter()
|
|
261
|
+
// iterates AGENT_ADAPTERS in declaration order and returns the first
|
|
262
|
+
// hit by prompt regex OR command-string match. Claude / Codex /
|
|
263
|
+
// Gemini / Grok all live in the registry now; only python-server
|
|
264
|
+
// (a non-CLI-agent type) stays here as in-file fall-through.
|
|
265
|
+
const adapter = detectAdapter(data, this.meta.command);
|
|
266
|
+
if (adapter) {
|
|
267
|
+
this.meta.type = adapter.sessionType;
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (
|
|
249
271
|
PATTERNS.pythonServer.uvicorn.test(data) ||
|
|
250
272
|
PATTERNS.pythonServer.flask.test(data) ||
|
|
251
273
|
PATTERNS.pythonServer.django.test(data) ||
|
|
@@ -259,34 +281,20 @@ class Session {
|
|
|
259
281
|
const p = PATTERNS;
|
|
260
282
|
const oldStatus = this.meta.status;
|
|
261
283
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
this.meta.statusDetail = 'Waiting for input';
|
|
277
|
-
}
|
|
278
|
-
break;
|
|
279
|
-
|
|
280
|
-
case 'gemini':
|
|
281
|
-
if (p.geminiCli.thinking.test(data)) {
|
|
282
|
-
this.meta.status = 'thinking';
|
|
283
|
-
this.meta.statusDetail = 'Gemini is generating...';
|
|
284
|
-
} else if (p.geminiCli.prompt.test(data)) {
|
|
285
|
-
this.meta.status = 'idle';
|
|
286
|
-
this.meta.statusDetail = 'Waiting for input';
|
|
287
|
-
}
|
|
288
|
-
break;
|
|
289
|
-
|
|
284
|
+
// Sprint 44 T3 + Sprint 45: per-agent status detection lives in each
|
|
285
|
+
// adapter's `statusFor(data)` method. Returns { status, statusDetail }
|
|
286
|
+
// on a match, null on no-change — preserves the original switch's
|
|
287
|
+
// "leave status untouched if no pattern fires" semantics. Only
|
|
288
|
+
// non-CLI-agent types (python-server + default shell) stay in-file.
|
|
289
|
+
const adapter = getAdapterForSessionType(this.meta.type);
|
|
290
|
+
if (adapter && typeof adapter.statusFor === 'function') {
|
|
291
|
+
const result = adapter.statusFor(data);
|
|
292
|
+
if (result && result.status) {
|
|
293
|
+
this.meta.status = result.status;
|
|
294
|
+
this.meta.statusDetail = result.statusDetail || '';
|
|
295
|
+
}
|
|
296
|
+
} else {
|
|
297
|
+
switch (this.meta.type) {
|
|
290
298
|
case 'python-server':
|
|
291
299
|
if (p.pythonServer.request.test(data)) {
|
|
292
300
|
this.meta.status = 'active';
|
|
@@ -309,6 +317,7 @@ class Session {
|
|
|
309
317
|
} else {
|
|
310
318
|
this.meta.status = 'active';
|
|
311
319
|
}
|
|
320
|
+
}
|
|
312
321
|
}
|
|
313
322
|
|
|
314
323
|
// Debounce status change events (3s) to avoid flooding RAG with active↔idle flaps
|
|
@@ -387,10 +396,20 @@ class Session {
|
|
|
387
396
|
// Claude Code's tool output frequently contains "error"/"Error" mid-line
|
|
388
397
|
// (grep matches, test results, log dumps). Use a line-anchored pattern
|
|
389
398
|
// for that session type so we don't flag content as failure.
|
|
390
|
-
|
|
391
|
-
|
|
399
|
+
//
|
|
400
|
+
// Sprint 44 T3 / Sprint 45 T4: per-agent primary error pattern is read
|
|
401
|
+
// off the adapter (`patterns.error` + `patternNames.error`). Falls back
|
|
402
|
+
// to the generic prose-shape PATTERNS.error when no adapter has claimed
|
|
403
|
+
// the session type. (Sprint 44 retained a `PATTERNS.errorLineStart` shim
|
|
404
|
+
// that pointed at the Claude adapter's regex; Sprint 45 T4 removed the
|
|
405
|
+
// shim — read `claudeAdapter.patterns.error` directly when needed.)
|
|
406
|
+
const adapter = getAdapterForSessionType(this.meta.type);
|
|
407
|
+
const primaryPattern = adapter && adapter.patterns && adapter.patterns.error
|
|
408
|
+
? adapter.patterns.error
|
|
392
409
|
: PATTERNS.error;
|
|
393
|
-
const primaryName =
|
|
410
|
+
const primaryName = adapter && adapter.patternNames && adapter.patternNames.error
|
|
411
|
+
? adapter.patternNames.error
|
|
412
|
+
: 'error';
|
|
394
413
|
// Sprint 33 fix: the structured patterns above miss `cat: /foo: No such
|
|
395
414
|
// file or directory` and friends — the most common Unix shell error
|
|
396
415
|
// shapes Josh hits day-to-day. Fall through to PATTERNS.shellError so
|