@idl3/claude-control 1.4.3 → 1.4.6

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/lib/codex-rpc.js CHANGED
@@ -175,15 +175,7 @@ function responseForPrompt(req, key) {
175
175
 
176
176
  function normalizeServerMessage(msg) {
177
177
  if (msg?.id == null || typeof msg.method !== 'string') return null;
178
- if (
179
- msg.method === 'item/commandExecution/requestApproval' ||
180
- msg.method === 'item/fileChange/requestApproval' ||
181
- msg.method === 'item/permissions/requestApproval' ||
182
- msg.method === 'item/tool/requestUserInput'
183
- ) {
184
- return msg;
185
- }
186
- return null;
178
+ return msg;
187
179
  }
188
180
 
189
181
  export async function codexRpcEndpoint() {
@@ -312,6 +304,12 @@ export class CodexRpcClient extends EventEmitter {
312
304
  this.messages = [];
313
305
  this.currentPrompt = null;
314
306
  this.currentRequest = null;
307
+ this.serverRequests = new Map();
308
+ this._closed = true;
309
+ }
310
+
311
+ isOpen() {
312
+ return this.ws?.readyState === WebSocket.OPEN;
315
313
  }
316
314
 
317
315
  async connect() {
@@ -402,6 +400,7 @@ export class CodexRpcClient extends EventEmitter {
402
400
  ws.once('open', () => {
403
401
  clearTimeout(timer);
404
402
  this.ws = ws;
403
+ this._closed = false;
405
404
  this._attachSocket(ws);
406
405
  resolve();
407
406
  });
@@ -419,6 +418,7 @@ export class CodexRpcClient extends EventEmitter {
419
418
  } catch {
420
419
  // best effort
421
420
  }
421
+ this._handleClose(this.ws);
422
422
  }
423
423
 
424
424
  async submit(text, { cwd = this.cwd } = {}) {
@@ -453,10 +453,8 @@ export class CodexRpcClient extends EventEmitter {
453
453
  payload: { id: req.id, result },
454
454
  });
455
455
  this._send({ id: req.id, result });
456
- this.currentRequest = null;
457
- this.currentPrompt = null;
458
- this.emit('prompt', null);
459
- this.emit('pending', false);
456
+ this.serverRequests.delete(req.id);
457
+ this._activateNextRequest();
460
458
  }
461
459
 
462
460
  request(method, params, timeoutMs = REQUEST_TIMEOUT_MS) {
@@ -474,7 +472,27 @@ export class CodexRpcClient extends EventEmitter {
474
472
  _attachSocket(ws) {
475
473
  ws.on('message', (data) => this._onData(`${data.toString()}\n`));
476
474
  ws.on('error', (err) => this.emit('error', err));
477
- ws.on('close', () => this.emit('close'));
475
+ ws.on('close', () => this._handleClose(ws));
476
+ }
477
+
478
+ _handleClose(ws = this.ws) {
479
+ if (ws && this.ws && ws !== this.ws) return;
480
+ if (this._closed) return;
481
+ this._closed = true;
482
+ const err = new Error('Codex RPC WebSocket closed');
483
+ for (const pending of this.pending.values()) {
484
+ clearTimeout(pending.timer);
485
+ pending.reject(err);
486
+ }
487
+ this.pending.clear();
488
+ this.ws = null;
489
+ this.buffer = '';
490
+ this.serverRequests.clear();
491
+ this.currentRequest = null;
492
+ this.currentPrompt = null;
493
+ this.emit('prompt', null);
494
+ this.emit('pending', false);
495
+ this.emit('close');
478
496
  }
479
497
 
480
498
  _send(obj) {
@@ -527,10 +545,8 @@ export class CodexRpcClient extends EventEmitter {
527
545
  if (typeof msg.method === 'string') {
528
546
  const serverRequest = normalizeServerMessage(msg);
529
547
  if (serverRequest) {
530
- this.currentRequest = serverRequest;
531
- this.currentPrompt = promptForRequest(serverRequest);
532
- this.emit('prompt', this.currentPrompt);
533
- this.emit('pending', true);
548
+ this.serverRequests.set(serverRequest.id, serverRequest);
549
+ if (!this.currentRequest) this._activateNextRequest();
534
550
  return;
535
551
  }
536
552
  this._onNotification(msg.method, msg.params || {});
@@ -552,10 +568,14 @@ export class CodexRpcClient extends EventEmitter {
552
568
 
553
569
  _onNotification(method, params) {
554
570
  if (method === 'serverRequest/resolved') {
555
- this.currentRequest = null;
556
- this.currentPrompt = null;
557
- this.emit('prompt', null);
558
- this.emit('pending', false);
571
+ const requestId = params?.id ?? params?.requestId ?? params?.request_id ?? null;
572
+ if (requestId != null) this.serverRequests.delete(requestId);
573
+ else this.serverRequests.clear();
574
+ if (this.currentRequest && (requestId == null || this.currentRequest.id === requestId)) {
575
+ this._activateNextRequest();
576
+ } else {
577
+ this.emit('pending', this.serverRequests.size > 0);
578
+ }
559
579
  return;
560
580
  }
561
581
 
@@ -631,6 +651,14 @@ export class CodexRpcClient extends EventEmitter {
631
651
  if (this.messages.length > 4000) this.messages.splice(0, this.messages.length - 4000);
632
652
  this.emit('messages', [msg]);
633
653
  }
654
+
655
+ _activateNextRequest() {
656
+ const next = this.serverRequests.values().next().value || null;
657
+ this.currentRequest = next;
658
+ this.currentPrompt = next ? promptForRequest(next) : null;
659
+ this.emit('prompt', this.currentPrompt);
660
+ this.emit('pending', !!next);
661
+ }
634
662
  }
635
663
 
636
664
  export class CodexRpcManager extends EventEmitter {
@@ -660,16 +688,21 @@ export class CodexRpcManager extends EventEmitter {
660
688
 
661
689
  async ensureAttached({ target, endpoint, cwd, resumeThreadId = null, transcriptPath = null }) {
662
690
  const existing = this.clients.get(target);
663
- if (existing) return existing;
691
+ if (existing?.isOpen() && existing.endpoint === endpoint) return existing;
692
+ if (existing) {
693
+ existing.close();
694
+ this.clients.delete(target);
695
+ }
664
696
  return this.attach({ target, endpoint, cwd, resumeThreadId, transcriptPath });
665
697
  }
666
698
 
667
699
  has(target) {
668
- return this.clients.has(target);
700
+ return !!this.clients.get(target)?.isOpen();
669
701
  }
670
702
 
671
703
  get(target) {
672
- return this.clients.get(target) || null;
704
+ const client = this.clients.get(target) || null;
705
+ return client?.isOpen() ? client : null;
673
706
  }
674
707
 
675
708
  messages(target) {
@@ -714,6 +747,9 @@ export class CodexRpcManager extends EventEmitter {
714
747
  client.on('subagent', (subagent) => this.emit('subagent', client.target, subagent));
715
748
  client.on('raw', (event) => this.emit('raw', client.target, event));
716
749
  client.on('error', (err) => this.emit('error', client.target, err));
717
- client.on('close', () => this.emit('close', client.target));
750
+ client.on('close', () => {
751
+ if (this.clients.get(client.target) === client) this.clients.delete(client.target);
752
+ this.emit('close', client.target);
753
+ });
718
754
  }
719
755
  }
package/lib/sessions.js CHANGED
@@ -9,6 +9,7 @@
9
9
 
10
10
  import { EventEmitter } from 'node:events';
11
11
  import fs from 'node:fs/promises';
12
+ import { watch as fsWatch } from 'node:fs';
12
13
  import path from 'node:path';
13
14
  import { execFile as _execFile } from 'node:child_process';
14
15
  import { promisify } from 'node:util';
@@ -29,7 +30,6 @@ import {
29
30
  readRolloutMeta,
30
31
  } from './codex.js';
31
32
  import { hasActiveSubAgents } from './subagents.js';
32
- import { isCodexAppServerCapture } from './codex-rpc.js';
33
33
 
34
34
  const execFile = promisify(_execFile);
35
35
 
@@ -38,6 +38,17 @@ const CLAUDE_COMM_RE = /(^|\/)claude$/;
38
38
  // Matches Codex CLI executable basename.
39
39
  const CODEX_COMM_RE = /(^|\/)codex$/;
40
40
  const CLAUDE_ARG_RE = /(^|[\s/])claude(?:\s|$)/;
41
+ const LOCAL_WS_RE = /\bws:\/\/(?:127\.0\.0\.1|localhost|\[::1\]|::1):\d+\b/;
42
+
43
+ function isCodexAppServerArgs(args) {
44
+ const s = String(args || '');
45
+ return /\bapp-server\b/.test(s) && /(?:^|\s)--listen(?:[=\s]|$)/.test(s);
46
+ }
47
+
48
+ function codexAppServerEndpointFromArgs(args) {
49
+ const m = LOCAL_WS_RE.exec(String(args || ''));
50
+ return m ? m[0] : null;
51
+ }
41
52
 
42
53
  // A pane is a Claude Code session when its process title is the Claude version
43
54
  // (e.g. "2.1.162") — shells report zsh/bash/etc. A linked transcript also counts.
@@ -83,6 +94,34 @@ export function isCwdConsistent(recCwd, winCwd) {
83
94
 
84
95
  const PENDING_QUESTION_MAX = 140; // truncate the surfaced question text
85
96
 
97
+ // A pane is scraped (capture-pane) by the 2 s thinking poll only while it's
98
+ // "live"; idle backgrounded panes are skipped to cut needless tmux execs. A pane
99
+ // stays live for this long after its transcript last changed.
100
+ const ACTIVE_SCRAPE_WINDOW_MS = 20_000;
101
+
102
+ /**
103
+ * Should the 2 s thinking poll scrape this pane? True when:
104
+ * - it carries a live flag (thinking/compacting/pending/errored) — keep polling
105
+ * until it settles/clears, OR
106
+ * - it has no transcript to gate on (can't tell; scrape to be safe), OR
107
+ * - its transcript changed recently — via fs.watch (`activeUntilMs`) or the 4 s
108
+ * tail read (`lastActivityMs`) as a backstop.
109
+ * Otherwise it's idle → skip the capture.
110
+ *
111
+ * @param {{thinking?:boolean,compacting?:boolean,pending?:boolean,errored?:boolean,transcriptPath?:string|null,lastActivityMs?:number|null}} s
112
+ * @param {number} activeUntilMs fs.watch-fed "active until" timestamp for this transcript (0 if none)
113
+ * @param {number} now
114
+ * @param {number} windowMs
115
+ * @returns {boolean}
116
+ */
117
+ export function shouldScrapePane(s, activeUntilMs, now, windowMs = ACTIVE_SCRAPE_WINDOW_MS) {
118
+ if (s.thinking || s.compacting || s.pending || s.errored) return true;
119
+ if (!s.transcriptPath) return true;
120
+ if (activeUntilMs && now < activeUntilMs) return true;
121
+ if (s.lastActivityMs && now - s.lastActivityMs < windowMs) return true;
122
+ return false;
123
+ }
124
+
86
125
  function codexRecordToCandidate(rec) {
87
126
  return {
88
127
  transcriptPath: rec.transcriptPath,
@@ -400,6 +439,12 @@ export class SessionRegistry extends EventEmitter {
400
439
  this._thinkingMap = new Map();
401
440
  /** @type {Map<string, boolean>} target -> compacting-conversation flag */
402
441
  this._compactingMap = new Map();
442
+ /** @type {Map<string, boolean>} target -> API-error/stall flag */
443
+ this._erroredMap = new Map();
444
+ /** @type {Map<string, number>} transcriptPath -> "scrape until" ts (fs.watch-fed) */
445
+ this._activeUntil = new Map();
446
+ /** @type {Map<string, import('node:fs').FSWatcher>} transcriptPath -> watcher */
447
+ this._transcriptWatchers = new Map();
403
448
  /** @type {Map<string, boolean>} target -> has a sub-agent actively running */
404
449
  this._subAgentActiveMap = new Map();
405
450
  /** @type {Map<string, {pending:boolean, question:string|null}>} target -> pane-derived prompt */
@@ -697,21 +742,12 @@ export class SessionRegistry extends EventEmitter {
697
742
  const exactByTarget = new Map();
698
743
  const exactPaths = new Set();
699
744
  const appServerTargets = new Set();
700
- const markAppServerIfVisible = async (p) => {
701
- let capture = this._paneTextCache.get(p.target) ?? '';
702
- if (!capture && this._tmux?.capturePane) {
703
- try {
704
- capture = await this._tmux.capturePane(p.target, 80, false, true);
705
- this._paneTextCache.set(p.target, capture);
706
- } catch {
707
- capture = '';
708
- }
709
- }
710
- if (isCodexAppServerCapture(capture)) appServerTargets.add(p.target);
711
- };
712
745
  await Promise.all(
713
746
  codexPanes.map(async (p) => {
714
747
  try {
748
+ const procInfo = paneProc.get(p.target);
749
+ if (procInfo?.appServer || procInfo?.appServerEndpoint) appServerTargets.add(p.target);
750
+
715
751
  const runtimeHint = this._transcriptHintMap.get(p.target);
716
752
  if (runtimeHint?.transcriptPath) {
717
753
  const rec = await readCodexTranscriptRecord(runtimeHint.transcriptPath);
@@ -726,11 +762,24 @@ export class SessionRegistry extends EventEmitter {
726
762
  }
727
763
 
728
764
  const reg = p.paneId ? paneReg.get(p.paneId) : null;
729
- const procInfo = paneProc.get(p.target);
730
765
  const codexPid = procInfo?.pid ?? null;
766
+ if (appServerTargets.has(p.target)) {
767
+ // App-server processes may hold multiple rollout files for
768
+ // multiple RPC threads. Only runtime/pane-registry hints are
769
+ // authoritative enough to bind one back to this tmux pane.
770
+ if (reg?.transcriptPath) {
771
+ const rec = await readCodexTranscriptRecord(reg.transcriptPath);
772
+ if (rec && isCwdConsistent(rec.cwd, p.cwd)) {
773
+ exactByTarget.set(p.target, codexRecordToCandidate({
774
+ ...rec,
775
+ sessionId: rec.sessionId ?? reg.sessionId ?? null,
776
+ }));
777
+ exactPaths.add(rec.transcriptPath);
778
+ }
779
+ }
780
+ return;
781
+ }
731
782
  if (!codexPid) {
732
- await markAppServerIfVisible(p);
733
- if (appServerTargets.has(p.target)) return;
734
783
  if (reg?.transcriptPath) {
735
784
  const rec = await readCodexTranscriptRecord(reg.transcriptPath);
736
785
  if (rec && isCwdConsistent(rec.cwd, p.cwd)) {
@@ -745,8 +794,6 @@ export class SessionRegistry extends EventEmitter {
745
794
  }
746
795
  const rolloutPath = await findOpenRollout(codexPid);
747
796
  if (!rolloutPath || exactPaths.has(rolloutPath)) {
748
- await markAppServerIfVisible(p);
749
- if (appServerTargets.has(p.target)) return;
750
797
  if (reg?.transcriptPath) {
751
798
  const rec = await readCodexTranscriptRecord(reg.transcriptPath);
752
799
  if (rec && isCwdConsistent(rec.cwd, p.cwd)) {
@@ -762,7 +809,6 @@ export class SessionRegistry extends EventEmitter {
762
809
  const rec = await readCodexTranscriptRecord(rolloutPath);
763
810
  if (!rec) return;
764
811
  if (!isCwdConsistent(rec.cwd, p.cwd)) {
765
- await markAppServerIfVisible(p);
766
812
  return;
767
813
  }
768
814
  exactByTarget.set(p.target, codexRecordToCandidate(rec));
@@ -825,6 +871,17 @@ export class SessionRegistry extends EventEmitter {
825
871
  // polled codex model and the rail would show no model for codex rows.
826
872
  const ctx = isClaude || kind === 'codex' ? this._ctxMap.get(win.target) || {} : {};
827
873
 
874
+ const procInfo = paneProc.get(win.target);
875
+ const codexAppServer = kind === 'codex' && (!!procInfo?.appServer || !!procInfo?.appServerEndpoint);
876
+ const transport = kind === 'claude'
877
+ ? (win.ccTransport || 'tmux')
878
+ : kind === 'codex'
879
+ ? (codexAppServer ? 'rpc' : (win.ccTransport || 'tmux'))
880
+ : null;
881
+ const endpoint = kind === 'codex'
882
+ ? (win.ccEndpoint || procInfo?.appServerEndpoint || null)
883
+ : (win.ccEndpoint || null);
884
+
828
885
  return {
829
886
  id,
830
887
  sessionId: transcript?.sessionId ?? null,
@@ -849,14 +906,15 @@ export class SessionRegistry extends EventEmitter {
849
906
  cmd: win.cmd,
850
907
  isClaude,
851
908
  kind,
852
- transport: kind === 'claude' ? (win.ccTransport || 'tmux') : (win.ccTransport || null),
853
- endpoint: win.ccEndpoint || null,
909
+ transport,
910
+ endpoint,
854
911
  ccShell: !!win.ccShell, // a composer >_ sister shell pane
855
912
 
856
913
  model: ctx.model || prettyModel(transcript?.model) || null,
857
914
  ctxPct: ctx.ctxPct ?? null,
858
915
  thinking: (isClaude || kind === 'codex') ? this._thinkingMap.get(win.target) ?? false : false,
859
916
  compacting: (isClaude || kind === 'codex') ? this._compactingMap.get(win.target) ?? false : false,
917
+ errored: (isClaude || kind === 'codex') ? this._erroredMap.get(win.target) ?? false : false,
860
918
  subAgentActive: isClaude ? this._subAgentActiveMap.get(win.target) ?? false : false,
861
919
  usagePct: transcript?.usagePct ?? null,
862
920
  usageWindowMin: transcript?.usageWindowMin ?? null,
@@ -866,10 +924,46 @@ export class SessionRegistry extends EventEmitter {
866
924
  // Surface EVERY pane: Claude sessions AND plain terminals (each pane is a row;
867
925
  // terminals render a live interactive terminal instead of a transcript).
868
926
  this._sessions = sessions;
927
+ this._syncTranscriptWatchers();
869
928
  this._maybeEmit();
870
929
  return this._sessions;
871
930
  }
872
931
 
932
+ /**
933
+ * Keep one fs.watch per live transcript so a change instantly marks that pane
934
+ * "active" (scrape-worthy) for the next thinking poll — replacing blanket 2 s
935
+ * scraping of idle panes. Best-effort: a watch that fails to attach just means
936
+ * that pane falls back to the lastActivityMs backstop in shouldScrapePane.
937
+ */
938
+ _syncTranscriptWatchers() {
939
+ const wanted = new Set();
940
+ for (const s of this._sessions) {
941
+ if (s.transcriptPath) wanted.add(s.transcriptPath);
942
+ }
943
+ // Add watchers for new transcripts; seed them active so a freshly-appeared
944
+ // session is scraped right away, then settles into the gated cadence.
945
+ for (const p of wanted) {
946
+ if (this._transcriptWatchers.has(p)) continue;
947
+ try {
948
+ const w = fsWatch(p, { persistent: false }, () => {
949
+ this._activeUntil.set(p, Date.now() + ACTIVE_SCRAPE_WINDOW_MS);
950
+ });
951
+ w.on('error', () => {}); // ignore — backstop covers it
952
+ this._transcriptWatchers.set(p, w);
953
+ this._activeUntil.set(p, Date.now() + ACTIVE_SCRAPE_WINDOW_MS);
954
+ } catch {
955
+ /* unwatchable (gone / FD limit) — lastActivityMs backstop handles it */
956
+ }
957
+ }
958
+ // Drop watchers for transcripts no longer present.
959
+ for (const [p, w] of this._transcriptWatchers) {
960
+ if (wanted.has(p)) continue;
961
+ try { w.close(); } catch { /* ignore */ }
962
+ this._transcriptWatchers.delete(p);
963
+ this._activeUntil.delete(p);
964
+ }
965
+ }
966
+
873
967
  /**
874
968
  * Capture each Claude pane's TUI status line and parse model + context %.
875
969
  * Throttled (separate from the 4 s refresh) and best-effort — capture-pane is
@@ -921,6 +1015,11 @@ export class SessionRegistry extends EventEmitter {
921
1015
  if (!this._tmux.isValidTarget(s.target)) return;
922
1016
  try {
923
1017
  if (s.transport === 'print') return;
1018
+ // Skip idle backgrounded panes — only scrape while the pane is live
1019
+ // (flagged) or its transcript changed recently. Cuts capture-pane execs
1020
+ // for sleeping sessions; active/pending/errored panes keep updating.
1021
+ const activeUntil = s.transcriptPath ? this._activeUntil.get(s.transcriptPath) ?? 0 : 0;
1022
+ if (!shouldScrapePane(s, activeUntil, Date.now(), ACTIVE_SCRAPE_WINDOW_MS)) return;
924
1023
  // Capture the VISIBLE pane only (no scrollback). One capture feeds the
925
1024
  // working line ("esc to interrupt"), the TUI question picker
926
1025
  // (parsePanePrompt), and the codex prompt parse. Scrollback MUST be
@@ -930,7 +1029,9 @@ export class SessionRegistry extends EventEmitter {
930
1029
  // numbered prose look like a live menu. The live picker is always on
931
1030
  // the visible screen, so visible-only is both sufficient and accurate.
932
1031
  const cap = await this._tmux.capturePane(s.target, 26, false, false, { visibleOnly: true });
933
- const { thinking, compacting } = parseTuiStatus(cap);
1032
+ const { thinking, compacting, errored } = parseTuiStatus(cap);
1033
+ this._erroredMap.set(s.target, errored);
1034
+ s.errored = errored;
934
1035
  this._thinkingMap.set(s.target, thinking);
935
1036
  this._compactingMap.set(s.target, compacting);
936
1037
  // Cache raw capture text for the content-fingerprint tiebreak in
@@ -1018,6 +1119,11 @@ export class SessionRegistry extends EventEmitter {
1018
1119
  clearInterval(this._thinkingInterval);
1019
1120
  this._thinkingInterval = null;
1020
1121
  }
1122
+ for (const w of this._transcriptWatchers.values()) {
1123
+ try { w.close(); } catch { /* ignore */ }
1124
+ }
1125
+ this._transcriptWatchers.clear();
1126
+ this._activeUntil.clear();
1021
1127
  }
1022
1128
 
1023
1129
  // -------------------------------------------------------------------------
@@ -1104,7 +1210,7 @@ export class SessionRegistry extends EventEmitter {
1104
1210
  * startMs:null} and callers fall back to the cmd heuristic / other passes.
1105
1211
  *
1106
1212
  * @param {import('./tmux.js').Window[]} allPanes
1107
- * @returns {Promise<Map<string, {isClaude: boolean, isCodex: boolean, kind: string|null, startMs: number|null}>>} target -> info
1213
+ * @returns {Promise<Map<string, {isClaude: boolean, isCodex: boolean, kind: string|null, startMs: number|null, appServer?: boolean, appServerEndpoint?: string|null}>>} target -> info
1108
1214
  */
1109
1215
  async _buildPaneProc(allPanes) {
1110
1216
  const out = new Map();
@@ -1156,7 +1262,16 @@ export class SessionRegistry extends EventEmitter {
1156
1262
  : null;
1157
1263
  if (codexKind) {
1158
1264
  const sec = parseEtime(meta.etime);
1159
- const codexInfo = { isClaude: false, isCodex: true, kind: 'codex', startMs: sec == null ? null : now - sec * 1000, pid };
1265
+ const appServerEndpoint = codexAppServerEndpointFromArgs(meta.args);
1266
+ const codexInfo = {
1267
+ isClaude: false,
1268
+ isCodex: true,
1269
+ kind: 'codex',
1270
+ startMs: sec == null ? null : now - sec * 1000,
1271
+ pid,
1272
+ appServer: isCodexAppServerArgs(meta.args) || !!appServerEndpoint,
1273
+ appServerEndpoint,
1274
+ };
1160
1275
  // npm/nvm installs launch Codex as `node .../bin/codex`, which then
1161
1276
  // spawns the native Codex child. The native child holds the rollout
1162
1277
  // file open, so prefer it for lsof-based transcript binding while
@@ -1166,11 +1281,11 @@ export class SessionRegistry extends EventEmitter {
1166
1281
  }
1167
1282
  for (const c of children.get(pid) ?? []) queue.push(c);
1168
1283
  }
1169
- return codexFallback || { isClaude: false, isCodex: false, kind: null, startMs: null, pid: null };
1284
+ return codexFallback || { isClaude: false, isCodex: false, kind: null, startMs: null, pid: null, appServer: false, appServerEndpoint: null };
1170
1285
  };
1171
1286
 
1172
1287
  for (const p of allPanes) {
1173
- out.set(p.target, p.panePid ? findClaude(p.panePid) : { isClaude: false, isCodex: false, kind: null, startMs: null, pid: null });
1288
+ out.set(p.target, p.panePid ? findClaude(p.panePid) : { isClaude: false, isCodex: false, kind: null, startMs: null, pid: null, appServer: false, appServerEndpoint: null });
1174
1289
  }
1175
1290
  return out;
1176
1291
  }
package/lib/tui.js CHANGED
@@ -33,10 +33,16 @@ const THINKING_SCAN_LINES = 8;
33
33
  // conversation…"). It can run for many seconds with no other output, so without
34
34
  // a dedicated signal the UI looks hung. Treated as a busy sub-state of thinking.
35
35
  const COMPACTING_RE = /compacting\b/i;
36
+ // A fatal/recoverable API error printed by the CLI when a turn fails (rate
37
+ // limit, overload, 5xx). The agent STALLS — it isn't "working" — so the cockpit
38
+ // surfaces an [ERROR] badge + a Retry. Matched on a wider window than the
39
+ // thinking scan because the error line can sit a few rows above the input box.
40
+ const ERROR_SCAN_LINES = 14;
41
+ const API_ERROR_RE = /\bAPI Error\b|\boverloaded_error\b|\brate limit(?:ed)?\b[^\n]*\b(?:try again|retry|later)\b|Please try again later/i;
36
42
 
37
43
  /**
38
44
  * @param {string} capture raw `tmux capture-pane -p` output (ANSI ok)
39
- * @returns {{ ctxPct: number|null, model: string|null, thinking: boolean, compacting: boolean }}
45
+ * @returns {{ ctxPct: number|null, model: string|null, thinking: boolean, compacting: boolean, errored: boolean }}
40
46
  */
41
47
  export function parseTuiStatus(capture) {
42
48
  const text = String(capture || '').replace(ANSI_RE, '');
@@ -62,7 +68,12 @@ export function parseTuiStatus(capture) {
62
68
  // "working" even if the compaction line omits "esc to interrupt".
63
69
  const thinking = compacting || THINKING_RE.test(tail) || WORKING_TIMER_RE.test(tail);
64
70
 
65
- return { ctxPct, model, thinking, compacting };
71
+ // API error only when the agent is NOT actively working (a real stall, not
72
+ // an error string scrolling by mid-generation). Scans a slightly wider window.
73
+ const errTail = lines.slice(-ERROR_SCAN_LINES).join('\n');
74
+ const errored = !thinking && API_ERROR_RE.test(errTail);
75
+
76
+ return { ctxPct, model, thinking, compacting, errored };
66
77
  }
67
78
 
68
79
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idl3/claude-control",
3
- "version": "1.4.3",
3
+ "version": "1.4.6",
4
4
  "type": "module",
5
5
  "description": "Local web UI to watch and drive your Claude Code sessions running in tmux — live transcripts, reply, answer AskUserQuestion, attach files, from a browser or phone.",
6
6
  "keywords": [
package/server.js CHANGED
@@ -921,6 +921,12 @@ async function handleSessionNew(req, res) {
921
921
  launch = `${config.launchCommand} --name ${tmux.shellQuoteName(name)}`;
922
922
  }
923
923
 
924
+ if (agent === 'codex') {
925
+ await tmux.setPaneOption(target, '@cc_agent', 'codex');
926
+ await tmux.setPaneOption(target, '@cc_transport', codexTransport);
927
+ if (codexRpcEndpoint) await tmux.setPaneOption(target, '@cc_endpoint', codexRpcEndpoint);
928
+ }
929
+
924
930
  await tmux.sendText(target, launch);
925
931
  if (printClient) {
926
932
  await printClient.waitForBridge();
@@ -1723,16 +1729,20 @@ function upgradeSubscriptionIfTranscriptReady(id) {
1723
1729
 
1724
1730
  async function ensureCodexRpcForSession(session) {
1725
1731
  if (session.kind !== 'codex') return null;
1732
+ if (session.transport !== 'rpc') return null;
1726
1733
  const existing = codexRpc.get(session.target);
1727
1734
  if (existing) return existing;
1728
1735
 
1729
1736
  let capture = '';
1730
- try {
1731
- capture = await tmux.capturePane(session.target, 200, false, true);
1732
- } catch {
1733
- return null;
1737
+ let endpoint = session.endpoint || null;
1738
+ if (!endpoint) {
1739
+ try {
1740
+ capture = await tmux.capturePane(session.target, 200, false, true);
1741
+ } catch {
1742
+ return null;
1743
+ }
1744
+ endpoint = parseCodexAppServerEndpoint(capture);
1734
1745
  }
1735
- const endpoint = parseCodexAppServerEndpoint(capture);
1736
1746
  if (!endpoint) {
1737
1747
  if (isCodexAppServerCapture(capture)) {
1738
1748
  throw new Error('Codex RPC app-server endpoint unavailable; refusing to type prompt into tmux pane');
@@ -1,3 +1,3 @@
1
- import{g as Ve}from"./index-DIwGyVZ7.js";function xe(e){return e instanceof Map?e.clear=e.delete=e.set=function(){throw new Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=function(){throw new Error("set is read-only")}),Object.freeze(e),Object.getOwnPropertyNames(e).forEach(t=>{const i=e[t],u=typeof i;(u==="object"||u==="function")&&!Object.isFrozen(i)&&xe(i)}),e}class he{constructor(t){t.data===void 0&&(t.data={}),this.data=t.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}}function we(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")}function B(e,...t){const i=Object.create(null);for(const u in e)i[u]=e[u];return t.forEach(function(u){for(const b in u)i[b]=u[b]}),i}const qe="</span>",pe=e=>!!e.scope,Qe=(e,{prefix:t})=>{if(e.startsWith("language:"))return e.replace("language:","language-");if(e.includes(".")){const i=e.split(".");return[`${t}${i.shift()}`,...i.map((u,b)=>`${u}${"_".repeat(b+1)}`)].join(" ")}return`${t}${e}`};class me{constructor(t,i){this.buffer="",this.classPrefix=i.classPrefix,t.walk(this)}addText(t){this.buffer+=we(t)}openNode(t){if(!pe(t))return;const i=Qe(t.scope,{prefix:this.classPrefix});this.span(i)}closeNode(t){pe(t)&&(this.buffer+=qe)}value(){return this.buffer}span(t){this.buffer+=`<span class="${t}">`}}const de=(e={})=>{const t={children:[]};return Object.assign(t,e),t};class te{constructor(){this.rootNode=de(),this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(t){this.top.children.push(t)}openNode(t){const i=de({scope:t});this.add(i),this.stack.push(i)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(t){return this.constructor._walk(t,this.rootNode)}static _walk(t,i){return typeof i=="string"?t.addText(i):i.children&&(t.openNode(i),i.children.forEach(u=>this._walk(t,u)),t.closeNode(i)),t}static _collapse(t){typeof t!="string"&&t.children&&(t.children.every(i=>typeof i=="string")?t.children=[t.children.join("")]:t.children.forEach(i=>{te._collapse(i)}))}}class et extends te{constructor(t){super(),this.options=t}addText(t){t!==""&&this.add(t)}startScope(t){this.openNode(t)}endScope(){this.closeNode()}__addSublanguage(t,i){const u=t.root;i&&(u.scope=`language:${i}`),this.add(u)}toHTML(){return new me(this,this.options).value()}finalize(){return this.closeAllNodes(),!0}}function P(e){return e?typeof e=="string"?e:e.source:null}function Oe(e){return C("(?=",e,")")}function tt(e){return C("(?:",e,")*")}function nt(e){return C("(?:",e,")?")}function C(...e){return e.map(i=>P(i)).join("")}function it(e){const t=e[e.length-1];return typeof t=="object"&&t.constructor===Object?(e.splice(e.length-1,1),t):{}}function ne(...e){return"("+(it(e).capture?"":"?:")+e.map(u=>P(u)).join("|")+")"}function Re(e){return new RegExp(e.toString()+"|").exec("").length-1}function st(e,t){const i=e&&e.exec(t);return i&&i.index===0}const rt=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;function ie(e,{joinWith:t}){let i=0;return e.map(u=>{i+=1;const b=i;let _=P(u),c="";for(;_.length>0;){const r=rt.exec(_);if(!r){c+=_;break}c+=_.substring(0,r.index),_=_.substring(r.index+r[0].length),r[0][0]==="\\"&&r[1]?c+="\\"+String(Number(r[1])+b):(c+=r[0],r[0]==="("&&i++)}return c}).map(u=>`(${u})`).join(t)}const ct=/\b\B/,ye="[a-zA-Z]\\w*",se="[a-zA-Z_]\\w*",Se="\\b\\d+(\\.\\d+)?",Ne="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",Ae="\\b(0b[01]+)",ot="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",at=(e={})=>{const t=/^#![ ]*\//;return e.binary&&(e.begin=C(t,/.*\b/,e.binary,/\b.*/)),B({scope:"meta",begin:t,end:/$/,relevance:0,"on:begin":(i,u)=>{i.index!==0&&u.ignoreMatch()}},e)},U={begin:"\\\\[\\s\\S]",relevance:0},lt={scope:"string",begin:"'",end:"'",illegal:"\\n",contains:[U]},ut={scope:"string",begin:'"',end:'"',illegal:"\\n",contains:[U]},ft={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},Y=function(e,t,i={}){const u=B({scope:"comment",begin:e,end:t,contains:[]},i);u.contains.push({scope:"doctag",begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0});const b=ne("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/);return u.contains.push({begin:C(/[ ]+/,"(",b,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),u},gt=Y("//","$"),ht=Y("/\\*","\\*/"),pt=Y("#","$"),dt={scope:"number",begin:Se,relevance:0},Et={scope:"number",begin:Ne,relevance:0},bt={scope:"number",begin:Ae,relevance:0},_t={scope:"regexp",begin:/\/(?=[^/\n]*\/)/,end:/\/[gimuy]*/,contains:[U,{begin:/\[/,end:/\]/,relevance:0,contains:[U]}]},Mt={scope:"title",begin:ye,relevance:0},xt={scope:"title",begin:se,relevance:0},wt={begin:"\\.\\s*"+se,relevance:0},Ot=function(e){return Object.assign(e,{"on:begin":(t,i)=>{i.data._beginMatch=t[1]},"on:end":(t,i)=>{i.data._beginMatch!==t[1]&&i.ignoreMatch()}})};var z=Object.freeze({__proto__:null,APOS_STRING_MODE:lt,BACKSLASH_ESCAPE:U,BINARY_NUMBER_MODE:bt,BINARY_NUMBER_RE:Ae,COMMENT:Y,C_BLOCK_COMMENT_MODE:ht,C_LINE_COMMENT_MODE:gt,C_NUMBER_MODE:Et,C_NUMBER_RE:Ne,END_SAME_AS_BEGIN:Ot,HASH_COMMENT_MODE:pt,IDENT_RE:ye,MATCH_NOTHING_RE:ct,METHOD_GUARD:wt,NUMBER_MODE:dt,NUMBER_RE:Se,PHRASAL_WORDS_MODE:ft,QUOTE_STRING_MODE:ut,REGEXP_MODE:_t,RE_STARTERS_RE:ot,SHEBANG:at,TITLE_MODE:Mt,UNDERSCORE_IDENT_RE:se,UNDERSCORE_TITLE_MODE:xt});function Rt(e,t){e.input[e.index-1]==="."&&t.ignoreMatch()}function yt(e,t){e.className!==void 0&&(e.scope=e.className,delete e.className)}function St(e,t){t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",e.__beforeBegin=Rt,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,e.relevance===void 0&&(e.relevance=0))}function Nt(e,t){Array.isArray(e.illegal)&&(e.illegal=ne(...e.illegal))}function At(e,t){if(e.match){if(e.begin||e.end)throw new Error("begin & end are not supported with match");e.begin=e.match,delete e.match}}function kt(e,t){e.relevance===void 0&&(e.relevance=1)}const Tt=(e,t)=>{if(!e.beforeMatch)return;if(e.starts)throw new Error("beforeMatch cannot be used with starts");const i=Object.assign({},e);Object.keys(e).forEach(u=>{delete e[u]}),e.keywords=i.keywords,e.begin=C(i.beforeMatch,Oe(i.begin)),e.starts={relevance:0,contains:[Object.assign(i,{endsParent:!0})]},e.relevance=0,delete i.beforeMatch},It=["of","and","for","in","not","or","if","then","parent","list","value"],Bt="keyword";function ke(e,t,i=Bt){const u=Object.create(null);return typeof e=="string"?b(i,e.split(" ")):Array.isArray(e)?b(i,e):Object.keys(e).forEach(function(_){Object.assign(u,ke(e[_],t,_))}),u;function b(_,c){t&&(c=c.map(r=>r.toLowerCase())),c.forEach(function(r){const l=r.split("|");u[l[0]]=[_,Dt(l[0],l[1])]})}}function Dt(e,t){return t?Number(t):vt(e)?0:1}function vt(e){return It.includes(e.toLowerCase())}const Ee={},v=e=>{console.error(e)},be=(e,...t)=>{console.log(`WARN: ${e}`,...t)},L=(e,t)=>{Ee[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),Ee[`${e}/${t}`]=!0)},X=new Error;function Te(e,t,{key:i}){let u=0;const b=e[i],_={},c={};for(let r=1;r<=t.length;r++)c[r+u]=b[r],_[r+u]=!0,u+=Re(t[r-1]);e[i]=c,e[i]._emit=_,e[i]._multi=!0}function Ct(e){if(Array.isArray(e.begin)){if(e.skip||e.excludeBegin||e.returnBegin)throw v("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),X;if(typeof e.beginScope!="object"||e.beginScope===null)throw v("beginScope must be object"),X;Te(e,e.begin,{key:"beginScope"}),e.begin=ie(e.begin,{joinWith:""})}}function Lt(e){if(Array.isArray(e.end)){if(e.skip||e.excludeEnd||e.returnEnd)throw v("skip, excludeEnd, returnEnd not compatible with endScope: {}"),X;if(typeof e.endScope!="object"||e.endScope===null)throw v("endScope must be object"),X;Te(e,e.end,{key:"endScope"}),e.end=ie(e.end,{joinWith:""})}}function Ht(e){e.scope&&typeof e.scope=="object"&&e.scope!==null&&(e.beginScope=e.scope,delete e.scope)}function jt(e){Ht(e),typeof e.beginScope=="string"&&(e.beginScope={_wrap:e.beginScope}),typeof e.endScope=="string"&&(e.endScope={_wrap:e.endScope}),Ct(e),Lt(e)}function Pt(e){function t(c,r){return new RegExp(P(c),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(r?"g":""))}class i{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(r,l){l.position=this.position++,this.matchIndexes[this.matchAt]=l,this.regexes.push([l,r]),this.matchAt+=Re(r)+1}compile(){this.regexes.length===0&&(this.exec=()=>null);const r=this.regexes.map(l=>l[1]);this.matcherRe=t(ie(r,{joinWith:"|"}),!0),this.lastIndex=0}exec(r){this.matcherRe.lastIndex=this.lastIndex;const l=this.matcherRe.exec(r);if(!l)return null;const w=l.findIndex((j,Z)=>Z>0&&j!==void 0),M=this.matchIndexes[w];return l.splice(0,w),Object.assign(l,M)}}class u{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(r){if(this.multiRegexes[r])return this.multiRegexes[r];const l=new i;return this.rules.slice(r).forEach(([w,M])=>l.addRule(w,M)),l.compile(),this.multiRegexes[r]=l,l}resumingScanAtSamePosition(){return this.regexIndex!==0}considerAll(){this.regexIndex=0}addRule(r,l){this.rules.push([r,l]),l.type==="begin"&&this.count++}exec(r){const l=this.getMatcher(this.regexIndex);l.lastIndex=this.lastIndex;let w=l.exec(r);if(this.resumingScanAtSamePosition()&&!(w&&w.index===this.lastIndex)){const M=this.getMatcher(0);M.lastIndex=this.lastIndex+1,w=M.exec(r)}return w&&(this.regexIndex+=w.position+1,this.regexIndex===this.count&&this.considerAll()),w}}function b(c){const r=new u;return c.contains.forEach(l=>r.addRule(l.begin,{rule:l,type:"begin"})),c.terminatorEnd&&r.addRule(c.terminatorEnd,{type:"end"}),c.illegal&&r.addRule(c.illegal,{type:"illegal"}),r}function _(c,r){const l=c;if(c.isCompiled)return l;[yt,At,jt,Tt].forEach(M=>M(c,r)),e.compilerExtensions.forEach(M=>M(c,r)),c.__beforeBegin=null,[St,Nt,kt].forEach(M=>M(c,r)),c.isCompiled=!0;let w=null;return typeof c.keywords=="object"&&c.keywords.$pattern&&(c.keywords=Object.assign({},c.keywords),w=c.keywords.$pattern,delete c.keywords.$pattern),w=w||/\w+/,c.keywords&&(c.keywords=ke(c.keywords,e.case_insensitive)),l.keywordPatternRe=t(w,!0),r&&(c.begin||(c.begin=/\B|\b/),l.beginRe=t(l.begin),!c.end&&!c.endsWithParent&&(c.end=/\B|\b/),c.end&&(l.endRe=t(l.end)),l.terminatorEnd=P(l.end)||"",c.endsWithParent&&r.terminatorEnd&&(l.terminatorEnd+=(c.end?"|":"")+r.terminatorEnd)),c.illegal&&(l.illegalRe=t(c.illegal)),c.contains||(c.contains=[]),c.contains=[].concat(...c.contains.map(function(M){return Ut(M==="self"?c:M)})),c.contains.forEach(function(M){_(M,l)}),c.starts&&_(c.starts,r),l.matcher=b(l),l}if(e.compilerExtensions||(e.compilerExtensions=[]),e.contains&&e.contains.includes("self"))throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return e.classNameAliases=B(e.classNameAliases||{}),_(e)}function Ie(e){return e?e.endsWithParent||Ie(e.starts):!1}function Ut(e){return e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map(function(t){return B(e,{variants:null},t)})),e.cachedVariants?e.cachedVariants:Ie(e)?B(e,{starts:e.starts?B(e.starts):null}):Object.isFrozen(e)?B(e):e}var $t="11.11.1";class Gt extends Error{constructor(t,i){super(t),this.name="HTMLInjectionError",this.html=i}}const ee=we,_e=B,Me=Symbol("nomatch"),Wt=7,Be=function(e){const t=Object.create(null),i=Object.create(null),u=[];let b=!0;const _="Could not find the language '{}', did you forget to load/include a language module?",c={disableAutodetect:!0,name:"Plain text",contains:[]};let r={ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",cssSelector:"pre code",languages:null,__emitter:et};function l(n){return r.noHighlightRe.test(n)}function w(n){let a=n.className+" ";a+=n.parentNode?n.parentNode.className:"";const h=r.languageDetectRe.exec(a);if(h){const d=T(h[1]);return d||(be(_.replace("{}",h[1])),be("Falling back to no-highlight mode for this block.",n)),d?h[1]:"no-highlight"}return a.split(/\s+/).find(d=>l(d)||T(d))}function M(n,a,h){let d="",x="";typeof a=="object"?(d=n,h=a.ignoreIllegals,x=a.language):(L("10.7.0","highlight(lang, code, ...args) has been deprecated."),L("10.7.0",`Please use highlight(code, options) instead.
1
+ import{g as Ve}from"./index-B15X7siX.js";function xe(e){return e instanceof Map?e.clear=e.delete=e.set=function(){throw new Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=function(){throw new Error("set is read-only")}),Object.freeze(e),Object.getOwnPropertyNames(e).forEach(t=>{const i=e[t],u=typeof i;(u==="object"||u==="function")&&!Object.isFrozen(i)&&xe(i)}),e}class he{constructor(t){t.data===void 0&&(t.data={}),this.data=t.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}}function we(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")}function B(e,...t){const i=Object.create(null);for(const u in e)i[u]=e[u];return t.forEach(function(u){for(const b in u)i[b]=u[b]}),i}const qe="</span>",pe=e=>!!e.scope,Qe=(e,{prefix:t})=>{if(e.startsWith("language:"))return e.replace("language:","language-");if(e.includes(".")){const i=e.split(".");return[`${t}${i.shift()}`,...i.map((u,b)=>`${u}${"_".repeat(b+1)}`)].join(" ")}return`${t}${e}`};class me{constructor(t,i){this.buffer="",this.classPrefix=i.classPrefix,t.walk(this)}addText(t){this.buffer+=we(t)}openNode(t){if(!pe(t))return;const i=Qe(t.scope,{prefix:this.classPrefix});this.span(i)}closeNode(t){pe(t)&&(this.buffer+=qe)}value(){return this.buffer}span(t){this.buffer+=`<span class="${t}">`}}const de=(e={})=>{const t={children:[]};return Object.assign(t,e),t};class te{constructor(){this.rootNode=de(),this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(t){this.top.children.push(t)}openNode(t){const i=de({scope:t});this.add(i),this.stack.push(i)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(t){return this.constructor._walk(t,this.rootNode)}static _walk(t,i){return typeof i=="string"?t.addText(i):i.children&&(t.openNode(i),i.children.forEach(u=>this._walk(t,u)),t.closeNode(i)),t}static _collapse(t){typeof t!="string"&&t.children&&(t.children.every(i=>typeof i=="string")?t.children=[t.children.join("")]:t.children.forEach(i=>{te._collapse(i)}))}}class et extends te{constructor(t){super(),this.options=t}addText(t){t!==""&&this.add(t)}startScope(t){this.openNode(t)}endScope(){this.closeNode()}__addSublanguage(t,i){const u=t.root;i&&(u.scope=`language:${i}`),this.add(u)}toHTML(){return new me(this,this.options).value()}finalize(){return this.closeAllNodes(),!0}}function P(e){return e?typeof e=="string"?e:e.source:null}function Oe(e){return C("(?=",e,")")}function tt(e){return C("(?:",e,")*")}function nt(e){return C("(?:",e,")?")}function C(...e){return e.map(i=>P(i)).join("")}function it(e){const t=e[e.length-1];return typeof t=="object"&&t.constructor===Object?(e.splice(e.length-1,1),t):{}}function ne(...e){return"("+(it(e).capture?"":"?:")+e.map(u=>P(u)).join("|")+")"}function Re(e){return new RegExp(e.toString()+"|").exec("").length-1}function st(e,t){const i=e&&e.exec(t);return i&&i.index===0}const rt=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;function ie(e,{joinWith:t}){let i=0;return e.map(u=>{i+=1;const b=i;let _=P(u),c="";for(;_.length>0;){const r=rt.exec(_);if(!r){c+=_;break}c+=_.substring(0,r.index),_=_.substring(r.index+r[0].length),r[0][0]==="\\"&&r[1]?c+="\\"+String(Number(r[1])+b):(c+=r[0],r[0]==="("&&i++)}return c}).map(u=>`(${u})`).join(t)}const ct=/\b\B/,ye="[a-zA-Z]\\w*",se="[a-zA-Z_]\\w*",Se="\\b\\d+(\\.\\d+)?",Ne="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",Ae="\\b(0b[01]+)",ot="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",at=(e={})=>{const t=/^#![ ]*\//;return e.binary&&(e.begin=C(t,/.*\b/,e.binary,/\b.*/)),B({scope:"meta",begin:t,end:/$/,relevance:0,"on:begin":(i,u)=>{i.index!==0&&u.ignoreMatch()}},e)},U={begin:"\\\\[\\s\\S]",relevance:0},lt={scope:"string",begin:"'",end:"'",illegal:"\\n",contains:[U]},ut={scope:"string",begin:'"',end:'"',illegal:"\\n",contains:[U]},ft={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},Y=function(e,t,i={}){const u=B({scope:"comment",begin:e,end:t,contains:[]},i);u.contains.push({scope:"doctag",begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0});const b=ne("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/);return u.contains.push({begin:C(/[ ]+/,"(",b,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),u},gt=Y("//","$"),ht=Y("/\\*","\\*/"),pt=Y("#","$"),dt={scope:"number",begin:Se,relevance:0},Et={scope:"number",begin:Ne,relevance:0},bt={scope:"number",begin:Ae,relevance:0},_t={scope:"regexp",begin:/\/(?=[^/\n]*\/)/,end:/\/[gimuy]*/,contains:[U,{begin:/\[/,end:/\]/,relevance:0,contains:[U]}]},Mt={scope:"title",begin:ye,relevance:0},xt={scope:"title",begin:se,relevance:0},wt={begin:"\\.\\s*"+se,relevance:0},Ot=function(e){return Object.assign(e,{"on:begin":(t,i)=>{i.data._beginMatch=t[1]},"on:end":(t,i)=>{i.data._beginMatch!==t[1]&&i.ignoreMatch()}})};var z=Object.freeze({__proto__:null,APOS_STRING_MODE:lt,BACKSLASH_ESCAPE:U,BINARY_NUMBER_MODE:bt,BINARY_NUMBER_RE:Ae,COMMENT:Y,C_BLOCK_COMMENT_MODE:ht,C_LINE_COMMENT_MODE:gt,C_NUMBER_MODE:Et,C_NUMBER_RE:Ne,END_SAME_AS_BEGIN:Ot,HASH_COMMENT_MODE:pt,IDENT_RE:ye,MATCH_NOTHING_RE:ct,METHOD_GUARD:wt,NUMBER_MODE:dt,NUMBER_RE:Se,PHRASAL_WORDS_MODE:ft,QUOTE_STRING_MODE:ut,REGEXP_MODE:_t,RE_STARTERS_RE:ot,SHEBANG:at,TITLE_MODE:Mt,UNDERSCORE_IDENT_RE:se,UNDERSCORE_TITLE_MODE:xt});function Rt(e,t){e.input[e.index-1]==="."&&t.ignoreMatch()}function yt(e,t){e.className!==void 0&&(e.scope=e.className,delete e.className)}function St(e,t){t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",e.__beforeBegin=Rt,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,e.relevance===void 0&&(e.relevance=0))}function Nt(e,t){Array.isArray(e.illegal)&&(e.illegal=ne(...e.illegal))}function At(e,t){if(e.match){if(e.begin||e.end)throw new Error("begin & end are not supported with match");e.begin=e.match,delete e.match}}function kt(e,t){e.relevance===void 0&&(e.relevance=1)}const Tt=(e,t)=>{if(!e.beforeMatch)return;if(e.starts)throw new Error("beforeMatch cannot be used with starts");const i=Object.assign({},e);Object.keys(e).forEach(u=>{delete e[u]}),e.keywords=i.keywords,e.begin=C(i.beforeMatch,Oe(i.begin)),e.starts={relevance:0,contains:[Object.assign(i,{endsParent:!0})]},e.relevance=0,delete i.beforeMatch},It=["of","and","for","in","not","or","if","then","parent","list","value"],Bt="keyword";function ke(e,t,i=Bt){const u=Object.create(null);return typeof e=="string"?b(i,e.split(" ")):Array.isArray(e)?b(i,e):Object.keys(e).forEach(function(_){Object.assign(u,ke(e[_],t,_))}),u;function b(_,c){t&&(c=c.map(r=>r.toLowerCase())),c.forEach(function(r){const l=r.split("|");u[l[0]]=[_,Dt(l[0],l[1])]})}}function Dt(e,t){return t?Number(t):vt(e)?0:1}function vt(e){return It.includes(e.toLowerCase())}const Ee={},v=e=>{console.error(e)},be=(e,...t)=>{console.log(`WARN: ${e}`,...t)},L=(e,t)=>{Ee[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),Ee[`${e}/${t}`]=!0)},X=new Error;function Te(e,t,{key:i}){let u=0;const b=e[i],_={},c={};for(let r=1;r<=t.length;r++)c[r+u]=b[r],_[r+u]=!0,u+=Re(t[r-1]);e[i]=c,e[i]._emit=_,e[i]._multi=!0}function Ct(e){if(Array.isArray(e.begin)){if(e.skip||e.excludeBegin||e.returnBegin)throw v("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),X;if(typeof e.beginScope!="object"||e.beginScope===null)throw v("beginScope must be object"),X;Te(e,e.begin,{key:"beginScope"}),e.begin=ie(e.begin,{joinWith:""})}}function Lt(e){if(Array.isArray(e.end)){if(e.skip||e.excludeEnd||e.returnEnd)throw v("skip, excludeEnd, returnEnd not compatible with endScope: {}"),X;if(typeof e.endScope!="object"||e.endScope===null)throw v("endScope must be object"),X;Te(e,e.end,{key:"endScope"}),e.end=ie(e.end,{joinWith:""})}}function Ht(e){e.scope&&typeof e.scope=="object"&&e.scope!==null&&(e.beginScope=e.scope,delete e.scope)}function jt(e){Ht(e),typeof e.beginScope=="string"&&(e.beginScope={_wrap:e.beginScope}),typeof e.endScope=="string"&&(e.endScope={_wrap:e.endScope}),Ct(e),Lt(e)}function Pt(e){function t(c,r){return new RegExp(P(c),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(r?"g":""))}class i{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(r,l){l.position=this.position++,this.matchIndexes[this.matchAt]=l,this.regexes.push([l,r]),this.matchAt+=Re(r)+1}compile(){this.regexes.length===0&&(this.exec=()=>null);const r=this.regexes.map(l=>l[1]);this.matcherRe=t(ie(r,{joinWith:"|"}),!0),this.lastIndex=0}exec(r){this.matcherRe.lastIndex=this.lastIndex;const l=this.matcherRe.exec(r);if(!l)return null;const w=l.findIndex((j,Z)=>Z>0&&j!==void 0),M=this.matchIndexes[w];return l.splice(0,w),Object.assign(l,M)}}class u{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(r){if(this.multiRegexes[r])return this.multiRegexes[r];const l=new i;return this.rules.slice(r).forEach(([w,M])=>l.addRule(w,M)),l.compile(),this.multiRegexes[r]=l,l}resumingScanAtSamePosition(){return this.regexIndex!==0}considerAll(){this.regexIndex=0}addRule(r,l){this.rules.push([r,l]),l.type==="begin"&&this.count++}exec(r){const l=this.getMatcher(this.regexIndex);l.lastIndex=this.lastIndex;let w=l.exec(r);if(this.resumingScanAtSamePosition()&&!(w&&w.index===this.lastIndex)){const M=this.getMatcher(0);M.lastIndex=this.lastIndex+1,w=M.exec(r)}return w&&(this.regexIndex+=w.position+1,this.regexIndex===this.count&&this.considerAll()),w}}function b(c){const r=new u;return c.contains.forEach(l=>r.addRule(l.begin,{rule:l,type:"begin"})),c.terminatorEnd&&r.addRule(c.terminatorEnd,{type:"end"}),c.illegal&&r.addRule(c.illegal,{type:"illegal"}),r}function _(c,r){const l=c;if(c.isCompiled)return l;[yt,At,jt,Tt].forEach(M=>M(c,r)),e.compilerExtensions.forEach(M=>M(c,r)),c.__beforeBegin=null,[St,Nt,kt].forEach(M=>M(c,r)),c.isCompiled=!0;let w=null;return typeof c.keywords=="object"&&c.keywords.$pattern&&(c.keywords=Object.assign({},c.keywords),w=c.keywords.$pattern,delete c.keywords.$pattern),w=w||/\w+/,c.keywords&&(c.keywords=ke(c.keywords,e.case_insensitive)),l.keywordPatternRe=t(w,!0),r&&(c.begin||(c.begin=/\B|\b/),l.beginRe=t(l.begin),!c.end&&!c.endsWithParent&&(c.end=/\B|\b/),c.end&&(l.endRe=t(l.end)),l.terminatorEnd=P(l.end)||"",c.endsWithParent&&r.terminatorEnd&&(l.terminatorEnd+=(c.end?"|":"")+r.terminatorEnd)),c.illegal&&(l.illegalRe=t(c.illegal)),c.contains||(c.contains=[]),c.contains=[].concat(...c.contains.map(function(M){return Ut(M==="self"?c:M)})),c.contains.forEach(function(M){_(M,l)}),c.starts&&_(c.starts,r),l.matcher=b(l),l}if(e.compilerExtensions||(e.compilerExtensions=[]),e.contains&&e.contains.includes("self"))throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return e.classNameAliases=B(e.classNameAliases||{}),_(e)}function Ie(e){return e?e.endsWithParent||Ie(e.starts):!1}function Ut(e){return e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map(function(t){return B(e,{variants:null},t)})),e.cachedVariants?e.cachedVariants:Ie(e)?B(e,{starts:e.starts?B(e.starts):null}):Object.isFrozen(e)?B(e):e}var $t="11.11.1";class Gt extends Error{constructor(t,i){super(t),this.name="HTMLInjectionError",this.html=i}}const ee=we,_e=B,Me=Symbol("nomatch"),Wt=7,Be=function(e){const t=Object.create(null),i=Object.create(null),u=[];let b=!0;const _="Could not find the language '{}', did you forget to load/include a language module?",c={disableAutodetect:!0,name:"Plain text",contains:[]};let r={ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",cssSelector:"pre code",languages:null,__emitter:et};function l(n){return r.noHighlightRe.test(n)}function w(n){let a=n.className+" ";a+=n.parentNode?n.parentNode.className:"";const h=r.languageDetectRe.exec(a);if(h){const d=T(h[1]);return d||(be(_.replace("{}",h[1])),be("Falling back to no-highlight mode for this block.",n)),d?h[1]:"no-highlight"}return a.split(/\s+/).find(d=>l(d)||T(d))}function M(n,a,h){let d="",x="";typeof a=="object"?(d=n,h=a.ignoreIllegals,x=a.language):(L("10.7.0","highlight(lang, code, ...args) has been deprecated."),L("10.7.0",`Please use highlight(code, options) instead.
2
2
  https://github.com/highlightjs/highlight.js/issues/2277`),x=n,d=a),h===void 0&&(h=!0);const S={code:d,language:x};G("before:highlight",S);const I=S.result?S.result:j(S.language,S.code,h);return I.code=S.code,G("after:highlight",I),I}function j(n,a,h,d){const x=Object.create(null);function S(s,o){return s.keywords[o]}function I(){if(!f.keywords){O.addText(E);return}let s=0;f.keywordPatternRe.lastIndex=0;let o=f.keywordPatternRe.exec(E),g="";for(;o;){g+=E.substring(s,o.index);const p=A.case_insensitive?o[0].toLowerCase():o[0],R=S(f,p);if(R){const[k,Ze]=R;if(O.addText(g),g="",x[p]=(x[p]||0)+1,x[p]<=Wt&&(F+=Ze),k.startsWith("_"))g+=o[0];else{const Je=A.classNameAliases[k]||k;N(o[0],Je)}}else g+=o[0];s=f.keywordPatternRe.lastIndex,o=f.keywordPatternRe.exec(E)}g+=E.substring(s),O.addText(g)}function W(){if(E==="")return;let s=null;if(typeof f.subLanguage=="string"){if(!t[f.subLanguage]){O.addText(E);return}s=j(f.subLanguage,E,!0,ge[f.subLanguage]),ge[f.subLanguage]=s._top}else s=J(E,f.subLanguage.length?f.subLanguage:null);f.relevance>0&&(F+=s.relevance),O.__addSublanguage(s._emitter,s.language)}function y(){f.subLanguage!=null?W():I(),E=""}function N(s,o){s!==""&&(O.startScope(o),O.addText(s),O.endScope())}function ae(s,o){let g=1;const p=o.length-1;for(;g<=p;){if(!s._emit[g]){g++;continue}const R=A.classNameAliases[s[g]]||s[g],k=o[g];R?N(k,R):(E=k,I(),E=""),g++}}function le(s,o){return s.scope&&typeof s.scope=="string"&&O.openNode(A.classNameAliases[s.scope]||s.scope),s.beginScope&&(s.beginScope._wrap?(N(E,A.classNameAliases[s.beginScope._wrap]||s.beginScope._wrap),E=""):s.beginScope._multi&&(ae(s.beginScope,o),E="")),f=Object.create(s,{parent:{value:f}}),f}function ue(s,o,g){let p=st(s.endRe,g);if(p){if(s["on:end"]){const R=new he(s);s["on:end"](o,R),R.isMatchIgnored&&(p=!1)}if(p){for(;s.endsParent&&s.parent;)s=s.parent;return s}}if(s.endsWithParent)return ue(s.parent,o,g)}function Ke(s){return f.matcher.regexIndex===0?(E+=s[0],1):(m=!0,0)}function Fe(s){const o=s[0],g=s.rule,p=new he(g),R=[g.__beforeBegin,g["on:begin"]];for(const k of R)if(k&&(k(s,p),p.isMatchIgnored))return Ke(o);return g.skip?E+=o:(g.excludeBegin&&(E+=o),y(),!g.returnBegin&&!g.excludeBegin&&(E=o)),le(g,s),g.returnBegin?0:o.length}function ze(s){const o=s[0],g=a.substring(s.index),p=ue(f,s,g);if(!p)return Me;const R=f;f.endScope&&f.endScope._wrap?(y(),N(o,f.endScope._wrap)):f.endScope&&f.endScope._multi?(y(),ae(f.endScope,s)):R.skip?E+=o:(R.returnEnd||R.excludeEnd||(E+=o),y(),R.excludeEnd&&(E=o));do f.scope&&O.closeNode(),!f.skip&&!f.subLanguage&&(F+=f.relevance),f=f.parent;while(f!==p.parent);return p.starts&&le(p.starts,s),R.returnEnd?0:o.length}function Xe(){const s=[];for(let o=f;o!==A;o=o.parent)o.scope&&s.unshift(o.scope);s.forEach(o=>O.openNode(o))}let K={};function fe(s,o){const g=o&&o[0];if(E+=s,g==null)return y(),0;if(K.type==="begin"&&o.type==="end"&&K.index===o.index&&g===""){if(E+=a.slice(o.index,o.index+1),!b){const p=new Error(`0 width match regex (${n})`);throw p.languageName=n,p.badRule=K.rule,p}return 1}if(K=o,o.type==="begin")return Fe(o);if(o.type==="illegal"&&!h){const p=new Error('Illegal lexeme "'+g+'" for mode "'+(f.scope||"<unnamed>")+'"');throw p.mode=f,p}else if(o.type==="end"){const p=ze(o);if(p!==Me)return p}if(o.type==="illegal"&&g==="")return E+=`
3
3
  `,1;if(Q>1e5&&Q>o.index*3)throw new Error("potential infinite loop, way more iterations than matches");return E+=g,g.length}const A=T(n);if(!A)throw v(_.replace("{}",n)),new Error('Unknown language: "'+n+'"');const Ye=Pt(A);let q="",f=d||Ye;const ge={},O=new r.__emitter(r);Xe();let E="",F=0,D=0,Q=0,m=!1;try{if(A.__emitTokens)A.__emitTokens(a,O);else{for(f.matcher.considerAll();;){Q++,m?m=!1:f.matcher.considerAll(),f.matcher.lastIndex=D;const s=f.matcher.exec(a);if(!s)break;const o=a.substring(D,s.index),g=fe(o,s);D=s.index+g}fe(a.substring(D))}return O.finalize(),q=O.toHTML(),{language:n,value:q,relevance:F,illegal:!1,_emitter:O,_top:f}}catch(s){if(s.message&&s.message.includes("Illegal"))return{language:n,value:ee(a),illegal:!0,relevance:0,_illegalBy:{message:s.message,index:D,context:a.slice(D-100,D+100),mode:s.mode,resultSoFar:q},_emitter:O};if(b)return{language:n,value:ee(a),illegal:!1,relevance:0,errorRaised:s,_emitter:O,_top:f};throw s}}function Z(n){const a={value:ee(n),illegal:!1,relevance:0,_top:c,_emitter:new r.__emitter(r)};return a._emitter.addText(n),a}function J(n,a){a=a||r.languages||Object.keys(t);const h=Z(n),d=a.filter(T).filter(oe).map(y=>j(y,n,!1));d.unshift(h);const x=d.sort((y,N)=>{if(y.relevance!==N.relevance)return N.relevance-y.relevance;if(y.language&&N.language){if(T(y.language).supersetOf===N.language)return 1;if(T(N.language).supersetOf===y.language)return-1}return 0}),[S,I]=x,W=S;return W.secondBest=I,W}function De(n,a,h){const d=a&&i[a]||h;n.classList.add("hljs"),n.classList.add(`language-${d}`)}function V(n){let a=null;const h=w(n);if(l(h))return;if(G("before:highlightElement",{el:n,language:h}),n.dataset.highlighted){console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",n);return}if(n.children.length>0&&(r.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),console.warn("The element with unescaped HTML:"),console.warn(n)),r.throwUnescapedHTML))throw new Gt("One of your code blocks includes unescaped HTML.",n.innerHTML);a=n;const d=a.textContent,x=h?M(d,{language:h,ignoreIllegals:!0}):J(d);n.innerHTML=x.value,n.dataset.highlighted="yes",De(n,h,x.language),n.result={language:x.language,re:x.relevance,relevance:x.relevance},x.secondBest&&(n.secondBest={language:x.secondBest.language,relevance:x.secondBest.relevance}),G("after:highlightElement",{el:n,result:x,text:d})}function ve(n){r=_e(r,n)}const Ce=()=>{$(),L("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")};function Le(){$(),L("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")}let re=!1;function $(){function n(){$()}if(document.readyState==="loading"){re||window.addEventListener("DOMContentLoaded",n,!1),re=!0;return}document.querySelectorAll(r.cssSelector).forEach(V)}function He(n,a){let h=null;try{h=a(e)}catch(d){if(v("Language definition for '{}' could not be registered.".replace("{}",n)),b)v(d);else throw d;h=c}h.name||(h.name=n),t[n]=h,h.rawDefinition=a.bind(null,e),h.aliases&&ce(h.aliases,{languageName:n})}function je(n){delete t[n];for(const a of Object.keys(i))i[a]===n&&delete i[a]}function Pe(){return Object.keys(t)}function T(n){return n=(n||"").toLowerCase(),t[n]||t[i[n]]}function ce(n,{languageName:a}){typeof n=="string"&&(n=[n]),n.forEach(h=>{i[h.toLowerCase()]=a})}function oe(n){const a=T(n);return a&&!a.disableAutodetect}function Ue(n){n["before:highlightBlock"]&&!n["before:highlightElement"]&&(n["before:highlightElement"]=a=>{n["before:highlightBlock"](Object.assign({block:a.el},a))}),n["after:highlightBlock"]&&!n["after:highlightElement"]&&(n["after:highlightElement"]=a=>{n["after:highlightBlock"](Object.assign({block:a.el},a))})}function $e(n){Ue(n),u.push(n)}function Ge(n){const a=u.indexOf(n);a!==-1&&u.splice(a,1)}function G(n,a){const h=n;u.forEach(function(d){d[h]&&d[h](a)})}function We(n){return L("10.7.0","highlightBlock will be removed entirely in v12.0"),L("10.7.0","Please use highlightElement now."),V(n)}Object.assign(e,{highlight:M,highlightAuto:J,highlightAll:$,highlightElement:V,highlightBlock:We,configure:ve,initHighlighting:Ce,initHighlightingOnLoad:Le,registerLanguage:He,unregisterLanguage:je,listLanguages:Pe,getLanguage:T,registerAliases:ce,autoDetection:oe,inherit:_e,addPlugin:$e,removePlugin:Ge}),e.debugMode=function(){b=!1},e.safeMode=function(){b=!0},e.versionString=$t,e.regex={concat:C,lookahead:Oe,either:ne,optional:nt,anyNumberOfTimes:tt};for(const n in z)typeof z[n]=="object"&&xe(z[n]);return Object.assign(e,z),e},H=Be({});H.newInstance=()=>Be({});var Kt=H;H.HighlightJS=H;H.default=H;const zt=Ve(Kt);export{zt as HighlightJS,zt as default};