@idl3/claude-control 1.4.5 → 1.4.7
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/README.md +35 -0
- package/bin/install-service.sh +12 -0
- package/lib/sessions.js +140 -14
- package/package.json +1 -1
- package/server.js +8 -5
- package/web/dist/assets/{core-CXYe4Mpr.js → core-BeFEsKn3.js} +1 -1
- package/web/dist/assets/{index-B15X7siX.js → index-4j41LhdC.js} +41 -41
- package/web/dist/assets/{index-BT4vDWJt.css → index-CJQIxV4S.css} +1 -1
- package/web/dist/index.html +2 -2
package/README.md
CHANGED
|
@@ -103,6 +103,41 @@ matching transcript under `~/.claude/projects/`.
|
|
|
103
103
|
|
|
104
104
|
---
|
|
105
105
|
|
|
106
|
+
## macOS Full Disk Access
|
|
107
|
+
|
|
108
|
+
If panes show **`Operation not permitted`** when reading `~/Documents`,
|
|
109
|
+
`~/Desktop`, or `~/Downloads` — even though the same commands work in your normal
|
|
110
|
+
terminal — it's macOS privacy protection (**TCC**), not a bug. claude-control runs
|
|
111
|
+
as a **launchd** service, and the tmux server it starts inherits that context,
|
|
112
|
+
which has **no Full Disk Access**. Your terminal app (iTerm/Terminal) already has
|
|
113
|
+
the grant, which is why it works there.
|
|
114
|
+
|
|
115
|
+
**Fix — grant Full Disk Access to the `node` that runs the service:**
|
|
116
|
+
|
|
117
|
+
1. Find the node path the service uses:
|
|
118
|
+
```bash
|
|
119
|
+
grep -A2 ProgramArguments ~/Library/LaunchAgents/com.*claude-control*.plist
|
|
120
|
+
```
|
|
121
|
+
(e.g. `~/.nvm/versions/node/vXX/bin/node`, or `which node` → `/opt/homebrew/bin/node`)
|
|
122
|
+
2. **System Settings → Privacy & Security → Full Disk Access → `+`**. In the file
|
|
123
|
+
picker press **⌘⇧G**, paste that node path (the `~/.nvm` dir is hidden, so the
|
|
124
|
+
typed path is the only way in), add it, and **toggle it on**.
|
|
125
|
+
3. Restart the service so node relaunches with the grant:
|
|
126
|
+
```bash
|
|
127
|
+
launchctl kickstart -k gui/$(id -u)/com.<your-service-name>
|
|
128
|
+
```
|
|
129
|
+
4. Kill the stale (permission-less) tmux server so new panes start under the
|
|
130
|
+
granted node — this ends the claude-control tmux sessions; the service recreates
|
|
131
|
+
them:
|
|
132
|
+
```bash
|
|
133
|
+
tmux kill-server
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Verify in a fresh pane: `ls ~/Documents` should work (no `Operation not permitted`).
|
|
137
|
+
Grant it to **your own** node path, not someone else's.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
106
141
|
## Updating & restarting
|
|
107
142
|
|
|
108
143
|
How you update depends on **how you installed** — pick your row. Check your
|
package/bin/install-service.sh
CHANGED
|
@@ -113,3 +113,15 @@ if [ -n "$TOKEN" ]; then
|
|
|
113
113
|
else
|
|
114
114
|
echo " auth: TOKENLESS (tailnet-only)"
|
|
115
115
|
fi
|
|
116
|
+
|
|
117
|
+
# macOS only: a launchd service has no Full Disk Access, so panes get
|
|
118
|
+
# "Operation not permitted" on ~/Documents etc. Remind the user to grant it.
|
|
119
|
+
if [ "$(uname)" = "Darwin" ]; then
|
|
120
|
+
echo ""
|
|
121
|
+
echo "⚠ macOS Full Disk Access: panes spawned by the service can't read"
|
|
122
|
+
echo " ~/Documents, ~/Desktop, ~/Downloads until you grant Full Disk Access to:"
|
|
123
|
+
echo " $NODE_BIN"
|
|
124
|
+
echo " System Settings → Privacy & Security → Full Disk Access → + (⌘⇧G to paste"
|
|
125
|
+
echo " the path) → enable it, then restart the service + run 'tmux kill-server'."
|
|
126
|
+
echo " Details: https://github.com/idl3/claude-control#macos-full-disk-access"
|
|
127
|
+
fi
|
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';
|
|
@@ -37,10 +38,16 @@ const CLAUDE_COMM_RE = /(^|\/)claude$/;
|
|
|
37
38
|
// Matches Codex CLI executable basename.
|
|
38
39
|
const CODEX_COMM_RE = /(^|\/)codex$/;
|
|
39
40
|
const CLAUDE_ARG_RE = /(^|[\s/])claude(?:\s|$)/;
|
|
41
|
+
const LOCAL_WS_RE = /\bws:\/\/(?:127\.0\.0\.1|localhost|\[::1\]|::1):\d+\b/;
|
|
40
42
|
|
|
41
43
|
function isCodexAppServerArgs(args) {
|
|
42
44
|
const s = String(args || '');
|
|
43
|
-
return /\bapp-server\b/.test(s) &&
|
|
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;
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
// A pane is a Claude Code session when its process title is the Claude version
|
|
@@ -87,6 +94,43 @@ export function isCwdConsistent(recCwd, winCwd) {
|
|
|
87
94
|
|
|
88
95
|
const PENDING_QUESTION_MAX = 140; // truncate the surfaced question text
|
|
89
96
|
|
|
97
|
+
// macOS TCC "Operation not permitted" — a pane that can't read protected dirs
|
|
98
|
+
// (~/Documents etc.) because the launchd service lacks Full Disk Access.
|
|
99
|
+
const PERM_DENIED_RE = /\boperation not permitted\b/i;
|
|
100
|
+
|
|
101
|
+
/** True when a pane capture shows the macOS Full-Disk-Access denial. */
|
|
102
|
+
export function paneHasPermIssue(capture) {
|
|
103
|
+
return PERM_DENIED_RE.test(String(capture || ''));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// A pane is scraped (capture-pane) by the 2 s thinking poll only while it's
|
|
107
|
+
// "live"; idle backgrounded panes are skipped to cut needless tmux execs. A pane
|
|
108
|
+
// stays live for this long after its transcript last changed.
|
|
109
|
+
const ACTIVE_SCRAPE_WINDOW_MS = 20_000;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Should the 2 s thinking poll scrape this pane? True when:
|
|
113
|
+
* - it carries a live flag (thinking/compacting/pending/errored) — keep polling
|
|
114
|
+
* until it settles/clears, OR
|
|
115
|
+
* - it has no transcript to gate on (can't tell; scrape to be safe), OR
|
|
116
|
+
* - its transcript changed recently — via fs.watch (`activeUntilMs`) or the 4 s
|
|
117
|
+
* tail read (`lastActivityMs`) as a backstop.
|
|
118
|
+
* Otherwise it's idle → skip the capture.
|
|
119
|
+
*
|
|
120
|
+
* @param {{thinking?:boolean,compacting?:boolean,pending?:boolean,errored?:boolean,transcriptPath?:string|null,lastActivityMs?:number|null}} s
|
|
121
|
+
* @param {number} activeUntilMs fs.watch-fed "active until" timestamp for this transcript (0 if none)
|
|
122
|
+
* @param {number} now
|
|
123
|
+
* @param {number} windowMs
|
|
124
|
+
* @returns {boolean}
|
|
125
|
+
*/
|
|
126
|
+
export function shouldScrapePane(s, activeUntilMs, now, windowMs = ACTIVE_SCRAPE_WINDOW_MS) {
|
|
127
|
+
if (s.thinking || s.compacting || s.pending || s.errored) return true;
|
|
128
|
+
if (!s.transcriptPath) return true;
|
|
129
|
+
if (activeUntilMs && now < activeUntilMs) return true;
|
|
130
|
+
if (s.lastActivityMs && now - s.lastActivityMs < windowMs) return true;
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
90
134
|
function codexRecordToCandidate(rec) {
|
|
91
135
|
return {
|
|
92
136
|
transcriptPath: rec.transcriptPath,
|
|
@@ -406,6 +450,12 @@ export class SessionRegistry extends EventEmitter {
|
|
|
406
450
|
this._compactingMap = new Map();
|
|
407
451
|
/** @type {Map<string, boolean>} target -> API-error/stall flag */
|
|
408
452
|
this._erroredMap = new Map();
|
|
453
|
+
/** @type {Map<string, boolean>} target -> macOS TCC "operation not permitted" */
|
|
454
|
+
this._permIssueMap = new Map();
|
|
455
|
+
/** @type {Map<string, number>} transcriptPath -> "scrape until" ts (fs.watch-fed) */
|
|
456
|
+
this._activeUntil = new Map();
|
|
457
|
+
/** @type {Map<string, import('node:fs').FSWatcher>} transcriptPath -> watcher */
|
|
458
|
+
this._transcriptWatchers = new Map();
|
|
409
459
|
/** @type {Map<string, boolean>} target -> has a sub-agent actively running */
|
|
410
460
|
this._subAgentActiveMap = new Map();
|
|
411
461
|
/** @type {Map<string, {pending:boolean, question:string|null}>} target -> pane-derived prompt */
|
|
@@ -707,8 +757,7 @@ export class SessionRegistry extends EventEmitter {
|
|
|
707
757
|
codexPanes.map(async (p) => {
|
|
708
758
|
try {
|
|
709
759
|
const procInfo = paneProc.get(p.target);
|
|
710
|
-
if (procInfo?.appServer) appServerTargets.add(p.target);
|
|
711
|
-
if (appServerTargets.has(p.target) && p.ccTransport !== 'rpc') return;
|
|
760
|
+
if (procInfo?.appServer || procInfo?.appServerEndpoint) appServerTargets.add(p.target);
|
|
712
761
|
|
|
713
762
|
const runtimeHint = this._transcriptHintMap.get(p.target);
|
|
714
763
|
if (runtimeHint?.transcriptPath) {
|
|
@@ -725,7 +774,10 @@ export class SessionRegistry extends EventEmitter {
|
|
|
725
774
|
|
|
726
775
|
const reg = p.paneId ? paneReg.get(p.paneId) : null;
|
|
727
776
|
const codexPid = procInfo?.pid ?? null;
|
|
728
|
-
if (
|
|
777
|
+
if (appServerTargets.has(p.target)) {
|
|
778
|
+
// App-server processes may hold multiple rollout files for
|
|
779
|
+
// multiple RPC threads. Only runtime/pane-registry hints are
|
|
780
|
+
// authoritative enough to bind one back to this tmux pane.
|
|
729
781
|
if (reg?.transcriptPath) {
|
|
730
782
|
const rec = await readCodexTranscriptRecord(reg.transcriptPath);
|
|
731
783
|
if (rec && isCwdConsistent(rec.cwd, p.cwd)) {
|
|
@@ -738,10 +790,17 @@ export class SessionRegistry extends EventEmitter {
|
|
|
738
790
|
}
|
|
739
791
|
return;
|
|
740
792
|
}
|
|
741
|
-
if (
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
793
|
+
if (!codexPid) {
|
|
794
|
+
if (reg?.transcriptPath) {
|
|
795
|
+
const rec = await readCodexTranscriptRecord(reg.transcriptPath);
|
|
796
|
+
if (rec && isCwdConsistent(rec.cwd, p.cwd)) {
|
|
797
|
+
exactByTarget.set(p.target, codexRecordToCandidate({
|
|
798
|
+
...rec,
|
|
799
|
+
sessionId: rec.sessionId ?? reg.sessionId ?? null,
|
|
800
|
+
}));
|
|
801
|
+
exactPaths.add(rec.transcriptPath);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
745
804
|
return;
|
|
746
805
|
}
|
|
747
806
|
const rolloutPath = await findOpenRollout(codexPid);
|
|
@@ -823,6 +882,17 @@ export class SessionRegistry extends EventEmitter {
|
|
|
823
882
|
// polled codex model and the rail would show no model for codex rows.
|
|
824
883
|
const ctx = isClaude || kind === 'codex' ? this._ctxMap.get(win.target) || {} : {};
|
|
825
884
|
|
|
885
|
+
const procInfo = paneProc.get(win.target);
|
|
886
|
+
const codexAppServer = kind === 'codex' && (!!procInfo?.appServer || !!procInfo?.appServerEndpoint);
|
|
887
|
+
const transport = kind === 'claude'
|
|
888
|
+
? (win.ccTransport || 'tmux')
|
|
889
|
+
: kind === 'codex'
|
|
890
|
+
? (codexAppServer ? 'rpc' : (win.ccTransport || 'tmux'))
|
|
891
|
+
: null;
|
|
892
|
+
const endpoint = kind === 'codex'
|
|
893
|
+
? (win.ccEndpoint || procInfo?.appServerEndpoint || null)
|
|
894
|
+
: (win.ccEndpoint || null);
|
|
895
|
+
|
|
826
896
|
return {
|
|
827
897
|
id,
|
|
828
898
|
sessionId: transcript?.sessionId ?? null,
|
|
@@ -847,8 +917,8 @@ export class SessionRegistry extends EventEmitter {
|
|
|
847
917
|
cmd: win.cmd,
|
|
848
918
|
isClaude,
|
|
849
919
|
kind,
|
|
850
|
-
transport
|
|
851
|
-
endpoint
|
|
920
|
+
transport,
|
|
921
|
+
endpoint,
|
|
852
922
|
ccShell: !!win.ccShell, // a composer >_ sister shell pane
|
|
853
923
|
|
|
854
924
|
model: ctx.model || prettyModel(transcript?.model) || null,
|
|
@@ -856,6 +926,7 @@ export class SessionRegistry extends EventEmitter {
|
|
|
856
926
|
thinking: (isClaude || kind === 'codex') ? this._thinkingMap.get(win.target) ?? false : false,
|
|
857
927
|
compacting: (isClaude || kind === 'codex') ? this._compactingMap.get(win.target) ?? false : false,
|
|
858
928
|
errored: (isClaude || kind === 'codex') ? this._erroredMap.get(win.target) ?? false : false,
|
|
929
|
+
permIssue: this._permIssueMap.get(win.target) ?? false,
|
|
859
930
|
subAgentActive: isClaude ? this._subAgentActiveMap.get(win.target) ?? false : false,
|
|
860
931
|
usagePct: transcript?.usagePct ?? null,
|
|
861
932
|
usageWindowMin: transcript?.usageWindowMin ?? null,
|
|
@@ -865,10 +936,46 @@ export class SessionRegistry extends EventEmitter {
|
|
|
865
936
|
// Surface EVERY pane: Claude sessions AND plain terminals (each pane is a row;
|
|
866
937
|
// terminals render a live interactive terminal instead of a transcript).
|
|
867
938
|
this._sessions = sessions;
|
|
939
|
+
this._syncTranscriptWatchers();
|
|
868
940
|
this._maybeEmit();
|
|
869
941
|
return this._sessions;
|
|
870
942
|
}
|
|
871
943
|
|
|
944
|
+
/**
|
|
945
|
+
* Keep one fs.watch per live transcript so a change instantly marks that pane
|
|
946
|
+
* "active" (scrape-worthy) for the next thinking poll — replacing blanket 2 s
|
|
947
|
+
* scraping of idle panes. Best-effort: a watch that fails to attach just means
|
|
948
|
+
* that pane falls back to the lastActivityMs backstop in shouldScrapePane.
|
|
949
|
+
*/
|
|
950
|
+
_syncTranscriptWatchers() {
|
|
951
|
+
const wanted = new Set();
|
|
952
|
+
for (const s of this._sessions) {
|
|
953
|
+
if (s.transcriptPath) wanted.add(s.transcriptPath);
|
|
954
|
+
}
|
|
955
|
+
// Add watchers for new transcripts; seed them active so a freshly-appeared
|
|
956
|
+
// session is scraped right away, then settles into the gated cadence.
|
|
957
|
+
for (const p of wanted) {
|
|
958
|
+
if (this._transcriptWatchers.has(p)) continue;
|
|
959
|
+
try {
|
|
960
|
+
const w = fsWatch(p, { persistent: false }, () => {
|
|
961
|
+
this._activeUntil.set(p, Date.now() + ACTIVE_SCRAPE_WINDOW_MS);
|
|
962
|
+
});
|
|
963
|
+
w.on('error', () => {}); // ignore — backstop covers it
|
|
964
|
+
this._transcriptWatchers.set(p, w);
|
|
965
|
+
this._activeUntil.set(p, Date.now() + ACTIVE_SCRAPE_WINDOW_MS);
|
|
966
|
+
} catch {
|
|
967
|
+
/* unwatchable (gone / FD limit) — lastActivityMs backstop handles it */
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
// Drop watchers for transcripts no longer present.
|
|
971
|
+
for (const [p, w] of this._transcriptWatchers) {
|
|
972
|
+
if (wanted.has(p)) continue;
|
|
973
|
+
try { w.close(); } catch { /* ignore */ }
|
|
974
|
+
this._transcriptWatchers.delete(p);
|
|
975
|
+
this._activeUntil.delete(p);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
872
979
|
/**
|
|
873
980
|
* Capture each Claude pane's TUI status line and parse model + context %.
|
|
874
981
|
* Throttled (separate from the 4 s refresh) and best-effort — capture-pane is
|
|
@@ -920,6 +1027,11 @@ export class SessionRegistry extends EventEmitter {
|
|
|
920
1027
|
if (!this._tmux.isValidTarget(s.target)) return;
|
|
921
1028
|
try {
|
|
922
1029
|
if (s.transport === 'print') return;
|
|
1030
|
+
// Skip idle backgrounded panes — only scrape while the pane is live
|
|
1031
|
+
// (flagged) or its transcript changed recently. Cuts capture-pane execs
|
|
1032
|
+
// for sleeping sessions; active/pending/errored panes keep updating.
|
|
1033
|
+
const activeUntil = s.transcriptPath ? this._activeUntil.get(s.transcriptPath) ?? 0 : 0;
|
|
1034
|
+
if (!shouldScrapePane(s, activeUntil, Date.now(), ACTIVE_SCRAPE_WINDOW_MS)) return;
|
|
923
1035
|
// Capture the VISIBLE pane only (no scrollback). One capture feeds the
|
|
924
1036
|
// working line ("esc to interrupt"), the TUI question picker
|
|
925
1037
|
// (parsePanePrompt), and the codex prompt parse. Scrollback MUST be
|
|
@@ -932,6 +1044,13 @@ export class SessionRegistry extends EventEmitter {
|
|
|
932
1044
|
const { thinking, compacting, errored } = parseTuiStatus(cap);
|
|
933
1045
|
this._erroredMap.set(s.target, errored);
|
|
934
1046
|
s.errored = errored;
|
|
1047
|
+
// macOS TCC denial: a pane spawned by the launchd service (no Full Disk
|
|
1048
|
+
// Access) gets "Operation not permitted" reading ~/Documents etc. Flag
|
|
1049
|
+
// it so the UI can point the user at the FDA fix instead of looking
|
|
1050
|
+
// silently broken. Works for any pane kind (shells hit it too).
|
|
1051
|
+
const permIssue = paneHasPermIssue(cap);
|
|
1052
|
+
this._permIssueMap.set(s.target, permIssue);
|
|
1053
|
+
s.permIssue = permIssue;
|
|
935
1054
|
this._thinkingMap.set(s.target, thinking);
|
|
936
1055
|
this._compactingMap.set(s.target, compacting);
|
|
937
1056
|
// Cache raw capture text for the content-fingerprint tiebreak in
|
|
@@ -1019,6 +1138,11 @@ export class SessionRegistry extends EventEmitter {
|
|
|
1019
1138
|
clearInterval(this._thinkingInterval);
|
|
1020
1139
|
this._thinkingInterval = null;
|
|
1021
1140
|
}
|
|
1141
|
+
for (const w of this._transcriptWatchers.values()) {
|
|
1142
|
+
try { w.close(); } catch { /* ignore */ }
|
|
1143
|
+
}
|
|
1144
|
+
this._transcriptWatchers.clear();
|
|
1145
|
+
this._activeUntil.clear();
|
|
1022
1146
|
}
|
|
1023
1147
|
|
|
1024
1148
|
// -------------------------------------------------------------------------
|
|
@@ -1105,7 +1229,7 @@ export class SessionRegistry extends EventEmitter {
|
|
|
1105
1229
|
* startMs:null} and callers fall back to the cmd heuristic / other passes.
|
|
1106
1230
|
*
|
|
1107
1231
|
* @param {import('./tmux.js').Window[]} allPanes
|
|
1108
|
-
* @returns {Promise<Map<string, {isClaude: boolean, isCodex: boolean, kind: string|null, startMs: number|null, appServer?: boolean}>>} target -> info
|
|
1232
|
+
* @returns {Promise<Map<string, {isClaude: boolean, isCodex: boolean, kind: string|null, startMs: number|null, appServer?: boolean, appServerEndpoint?: string|null}>>} target -> info
|
|
1109
1233
|
*/
|
|
1110
1234
|
async _buildPaneProc(allPanes) {
|
|
1111
1235
|
const out = new Map();
|
|
@@ -1157,13 +1281,15 @@ export class SessionRegistry extends EventEmitter {
|
|
|
1157
1281
|
: null;
|
|
1158
1282
|
if (codexKind) {
|
|
1159
1283
|
const sec = parseEtime(meta.etime);
|
|
1284
|
+
const appServerEndpoint = codexAppServerEndpointFromArgs(meta.args);
|
|
1160
1285
|
const codexInfo = {
|
|
1161
1286
|
isClaude: false,
|
|
1162
1287
|
isCodex: true,
|
|
1163
1288
|
kind: 'codex',
|
|
1164
1289
|
startMs: sec == null ? null : now - sec * 1000,
|
|
1165
1290
|
pid,
|
|
1166
|
-
appServer: isCodexAppServerArgs(meta.args),
|
|
1291
|
+
appServer: isCodexAppServerArgs(meta.args) || !!appServerEndpoint,
|
|
1292
|
+
appServerEndpoint,
|
|
1167
1293
|
};
|
|
1168
1294
|
// npm/nvm installs launch Codex as `node .../bin/codex`, which then
|
|
1169
1295
|
// spawns the native Codex child. The native child holds the rollout
|
|
@@ -1174,11 +1300,11 @@ export class SessionRegistry extends EventEmitter {
|
|
|
1174
1300
|
}
|
|
1175
1301
|
for (const c of children.get(pid) ?? []) queue.push(c);
|
|
1176
1302
|
}
|
|
1177
|
-
return codexFallback || { isClaude: false, isCodex: false, kind: null, startMs: null, pid: null, appServer: false };
|
|
1303
|
+
return codexFallback || { isClaude: false, isCodex: false, kind: null, startMs: null, pid: null, appServer: false, appServerEndpoint: null };
|
|
1178
1304
|
};
|
|
1179
1305
|
|
|
1180
1306
|
for (const p of allPanes) {
|
|
1181
|
-
out.set(p.target, p.panePid ? findClaude(p.panePid) : { isClaude: false, isCodex: false, kind: null, startMs: null, pid: null, appServer: false });
|
|
1307
|
+
out.set(p.target, p.panePid ? findClaude(p.panePid) : { isClaude: false, isCodex: false, kind: null, startMs: null, pid: null, appServer: false, appServerEndpoint: null });
|
|
1182
1308
|
}
|
|
1183
1309
|
return out;
|
|
1184
1310
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idl3/claude-control",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.7",
|
|
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
|
@@ -1734,12 +1734,15 @@ async function ensureCodexRpcForSession(session) {
|
|
|
1734
1734
|
if (existing) return existing;
|
|
1735
1735
|
|
|
1736
1736
|
let capture = '';
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
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);
|
|
1741
1745
|
}
|
|
1742
|
-
const endpoint = parseCodexAppServerEndpoint(capture);
|
|
1743
1746
|
if (!endpoint) {
|
|
1744
1747
|
if (isCodexAppServerCapture(capture)) {
|
|
1745
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-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.
|
|
1
|
+
import{g as Ve}from"./index-4j41LhdC.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};
|