@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 +62 -26
- package/lib/sessions.js +141 -26
- package/lib/tui.js +13 -2
- package/package.json +1 -1
- package/server.js +15 -5
- package/web/dist/assets/{core-BPDebW1g.js → core-CXYe4Mpr.js} +1 -1
- package/web/dist/assets/{index-DIwGyVZ7.js → index-B15X7siX.js} +34 -34
- package/web/dist/assets/index-BT4vDWJt.css +1 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-B3rIEzoc.css +0 -1
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
|
-
|
|
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.
|
|
457
|
-
this.
|
|
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.
|
|
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.
|
|
531
|
-
this.
|
|
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
|
-
|
|
556
|
-
|
|
557
|
-
this.
|
|
558
|
-
this.
|
|
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.
|
|
700
|
+
return !!this.clients.get(target)?.isOpen();
|
|
669
701
|
}
|
|
670
702
|
|
|
671
703
|
get(target) {
|
|
672
|
-
|
|
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', () =>
|
|
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
|
|
853
|
-
endpoint
|
|
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
|
|
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
|
-
|
|
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
|
+
"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
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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};
|