@idl3/claude-control 0.1.21 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/bin/cli.js +5 -0
- package/bin/setup.sh +60 -0
- package/hooks/record-pane.mjs +72 -0
- package/lib/config.js +39 -3
- package/lib/match.js +39 -26
- package/lib/mlx.js +260 -0
- package/lib/models.js +66 -0
- package/lib/optimize.js +126 -2
- package/lib/pane-registry.js +86 -0
- package/lib/sessions.js +75 -35
- package/lib/shell.js +101 -0
- package/lib/tmux.js +77 -11
- package/package.json +5 -1
- package/scripts/eval-optimize.mjs +46 -0
- package/scripts/install-pane-hook.mjs +72 -0
- package/server.js +112 -3
- package/web/dist/assets/{core-CyYMg33t.js → core-DM2iK52g.js} +1 -1
- package/web/dist/assets/index-DwNp83VT.css +1 -0
- package/web/dist/assets/index-DwmU8Yna.js +89 -0
- package/web/dist/index.html +4 -2
- package/web/dist/assets/index-BeJg6Cs1.js +0 -85
- package/web/dist/assets/index-Dn7NDGPq.css +0 -1
package/lib/tmux.js
CHANGED
|
@@ -177,6 +177,8 @@ const FORMAT = [
|
|
|
177
177
|
'#{window_id}',
|
|
178
178
|
'#{pane_index}',
|
|
179
179
|
'#{pane_active}',
|
|
180
|
+
'#{pane_id}',
|
|
181
|
+
'#{@cc_shell}',
|
|
180
182
|
].join(SEP);
|
|
181
183
|
|
|
182
184
|
/**
|
|
@@ -222,7 +224,7 @@ export async function listPanes() {
|
|
|
222
224
|
const parts = trimmed.split(SEP);
|
|
223
225
|
if (parts.length < 9) continue;
|
|
224
226
|
|
|
225
|
-
const [sessionName, rawIndex, windowName, rawActive, rawPid, cwd, cmd, windowId, rawPane, rawPaneActive] = parts;
|
|
227
|
+
const [sessionName, rawIndex, windowName, rawActive, rawPid, cwd, cmd, windowId, rawPane, rawPaneActive, paneId, ccShell] = parts;
|
|
226
228
|
const windowIndex = Number(rawIndex);
|
|
227
229
|
const panePid = Number(rawPid);
|
|
228
230
|
const paneIndex = Number(rawPane) || 0;
|
|
@@ -239,6 +241,8 @@ export async function listPanes() {
|
|
|
239
241
|
cmd,
|
|
240
242
|
windowId: windowId ?? `${sessionName}:${windowIndex}`,
|
|
241
243
|
paneIndex,
|
|
244
|
+
paneId: paneId ?? null, // stable tmux %N — joins to $TMUX_PANE from the hook
|
|
245
|
+
ccShell: ccShell === '1', // sister shell pane created for the composer >_
|
|
242
246
|
});
|
|
243
247
|
}
|
|
244
248
|
|
|
@@ -377,6 +381,54 @@ export async function createWindow({ cwd, name } = {}) {
|
|
|
377
381
|
return target;
|
|
378
382
|
}
|
|
379
383
|
|
|
384
|
+
// ---------------------------------------------------------------------------
|
|
385
|
+
// Split window (sister pane)
|
|
386
|
+
// ---------------------------------------------------------------------------
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Split a window to add a sister pane running the default shell, WITHOUT
|
|
390
|
+
* stealing focus (`-d`), and return the new pane's target. Used to give each
|
|
391
|
+
* Claude session its own scratch shell next to it (composer >_).
|
|
392
|
+
*
|
|
393
|
+
* @param {{ windowTarget: string, cwd: string, size?: string }} opts
|
|
394
|
+
* windowTarget e.g. "0:1"; size e.g. "30%" (height of the new pane).
|
|
395
|
+
* @returns {Promise<string>} new pane target "session:window.pane"
|
|
396
|
+
*/
|
|
397
|
+
export async function splitWindow({ windowTarget, cwd, size = '30%' } = {}) {
|
|
398
|
+
if (!windowTarget) throw new Error('splitWindow: windowTarget required');
|
|
399
|
+
if (typeof cwd !== 'string' || !cwd) throw new Error('splitWindow: cwd required');
|
|
400
|
+
const args = [
|
|
401
|
+
'split-window',
|
|
402
|
+
'-d', // do not switch focus to the new pane
|
|
403
|
+
'-v', // stack below the source pane
|
|
404
|
+
'-l', size,
|
|
405
|
+
'-t', windowTarget,
|
|
406
|
+
'-c', cwd,
|
|
407
|
+
'-P',
|
|
408
|
+
'-F', '#{session_name}:#{window_index}.#{pane_index}',
|
|
409
|
+
];
|
|
410
|
+
const { stdout } = await runTmux(args);
|
|
411
|
+
const target = stdout.trim();
|
|
412
|
+
if (!isValidTarget(target)) {
|
|
413
|
+
throw new Error(`splitWindow: produced invalid target: ${JSON.stringify(target)}`);
|
|
414
|
+
}
|
|
415
|
+
return target;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Set a pane-scoped tmux option (e.g. a `@user` marker). Used to tag the sister
|
|
420
|
+
* shell pane so it can be found and reused later.
|
|
421
|
+
*
|
|
422
|
+
* @param {string} target pane target
|
|
423
|
+
* @param {string} name option name (e.g. "@cc_shell")
|
|
424
|
+
* @param {string} value
|
|
425
|
+
* @returns {Promise<void>}
|
|
426
|
+
*/
|
|
427
|
+
export async function setPaneOption(target, name, value) {
|
|
428
|
+
assertTarget(target);
|
|
429
|
+
await runTmux(['set-option', '-p', '-t', target, name, String(value)]);
|
|
430
|
+
}
|
|
431
|
+
|
|
380
432
|
// ---------------------------------------------------------------------------
|
|
381
433
|
// Rename window
|
|
382
434
|
// ---------------------------------------------------------------------------
|
|
@@ -416,6 +468,22 @@ export async function sendText(target, text) {
|
|
|
416
468
|
await runTmux(['send-keys', '-t', target, 'Enter']);
|
|
417
469
|
}
|
|
418
470
|
|
|
471
|
+
/**
|
|
472
|
+
* Send literal text WITHOUT a trailing Enter — for raw keystroke passthrough,
|
|
473
|
+
* where each character (or a paste) is forwarded as the user types and the pane
|
|
474
|
+
* itself is the echo. `-l` means no key-name interpretation, so this can't inject
|
|
475
|
+
* control keys (those go through sendRawKeys with the SHELL_KEYS allow-list).
|
|
476
|
+
*
|
|
477
|
+
* @param {string} target
|
|
478
|
+
* @param {string} text
|
|
479
|
+
* @returns {Promise<void>}
|
|
480
|
+
*/
|
|
481
|
+
export async function sendLiteral(target, text) {
|
|
482
|
+
assertTarget(target);
|
|
483
|
+
if (!text) return;
|
|
484
|
+
await runTmux(['send-keys', '-t', target, '-l', text]);
|
|
485
|
+
}
|
|
486
|
+
|
|
419
487
|
// ---------------------------------------------------------------------------
|
|
420
488
|
// Send raw key names (no -l)
|
|
421
489
|
// ---------------------------------------------------------------------------
|
|
@@ -468,16 +536,14 @@ export async function sendRawKeysSequenced(target, keys, delayMs = 160) {
|
|
|
468
536
|
* @param {number} [lines=40] How many history lines above the visible area to include.
|
|
469
537
|
* @returns {Promise<string>}
|
|
470
538
|
*/
|
|
471
|
-
export async function capturePane(target, lines = 40) {
|
|
539
|
+
export async function capturePane(target, lines = 40, escapes = false) {
|
|
472
540
|
assertTarget(target);
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
'-S', `-${lines}`, // start N lines above visible area
|
|
481
|
-
]);
|
|
541
|
+
const args = ['capture-pane', '-t', target, '-p'];
|
|
542
|
+
// `-e` keeps ANSI/SGR sequences so the client can render terminal colors. Off
|
|
543
|
+
// by default: LivePane / AskModal render plain text (escapes would show as
|
|
544
|
+
// garbage). The composer terminal view opts in to get a themed, colored pane.
|
|
545
|
+
if (escapes) args.push('-e');
|
|
546
|
+
args.push('-S', `-${lines}`); // start N lines above the visible area
|
|
547
|
+
const { stdout } = await runTmux(args);
|
|
482
548
|
return stdout;
|
|
483
549
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idl3/claude-control",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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": [
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"files": [
|
|
23
23
|
"server.js",
|
|
24
24
|
"lib/",
|
|
25
|
+
"hooks/",
|
|
26
|
+
"scripts/",
|
|
25
27
|
"public/",
|
|
26
28
|
"web/dist/",
|
|
27
29
|
"bin/",
|
|
@@ -32,6 +34,8 @@
|
|
|
32
34
|
"start": "node server.js",
|
|
33
35
|
"dev": "node --watch server.js",
|
|
34
36
|
"test": "node --test",
|
|
37
|
+
"eval:optimise": "node scripts/eval-optimize.mjs",
|
|
38
|
+
"install-hook": "node scripts/install-pane-hook.mjs",
|
|
35
39
|
"build:web": "cd web && npm install && npm run build",
|
|
36
40
|
"build": "npm run build:web",
|
|
37
41
|
"prepack": "npm run build"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* eval-optimize.mjs — offline scorecard for the prompt-optimiser acceptance gate.
|
|
4
|
+
* Runs lib/optimize.js → evaluateRewrite over the deterministic fixture set and
|
|
5
|
+
* prints a per-case pass/fail table plus an aggregate. Exits non-zero on any
|
|
6
|
+
* mismatch so it can gate CI / catch regressions in the guard logic.
|
|
7
|
+
*
|
|
8
|
+
* Run: npm run eval:optimise
|
|
9
|
+
*/
|
|
10
|
+
import { evaluateRewrite } from '../lib/optimize.js';
|
|
11
|
+
import { OPTIMIZE_CASES } from '../test/fixtures/optimize-cases.mjs';
|
|
12
|
+
|
|
13
|
+
let pass = 0;
|
|
14
|
+
const rows = [];
|
|
15
|
+
for (const c of OPTIMIZE_CASES) {
|
|
16
|
+
const ev = evaluateRewrite(c.draft, c.optimized);
|
|
17
|
+
const verdictOk = ev.ok === c.expectOk;
|
|
18
|
+
// If the case pins expected violations, require they all fired.
|
|
19
|
+
const violOk =
|
|
20
|
+
!c.expectViolations || c.expectViolations.every((v) => ev.violations.includes(v));
|
|
21
|
+
const ok = verdictOk && violOk;
|
|
22
|
+
if (ok) pass += 1;
|
|
23
|
+
rows.push({
|
|
24
|
+
name: c.name,
|
|
25
|
+
ok,
|
|
26
|
+
got: ev.ok ? 'accept' : `reject(${ev.violations.join(',')})`,
|
|
27
|
+
want: c.expectOk ? 'accept' : `reject(${(c.expectViolations || []).join(',') || 'any'})`,
|
|
28
|
+
ratio: ev.metrics.lengthRatio,
|
|
29
|
+
overlap: ev.metrics.contentOverlap,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const W = Math.max(...rows.map((r) => r.name.length));
|
|
34
|
+
console.log('Prompt-optimiser eval — acceptance gate\n');
|
|
35
|
+
for (const r of rows) {
|
|
36
|
+
console.log(
|
|
37
|
+
`${r.ok ? '✓' : '✗'} ${r.name.padEnd(W)} got=${r.got} want=${r.want} ` +
|
|
38
|
+
`ratio=${r.ratio} overlap=${r.overlap}`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
const total = OPTIMIZE_CASES.length;
|
|
42
|
+
console.log(`\n${pass}/${total} cases passed`);
|
|
43
|
+
if (pass !== total) {
|
|
44
|
+
console.error('EVAL FAILED — guard logic regressed');
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* install-pane-hook.mjs — idempotently register the pane-recording hook
|
|
4
|
+
* (hooks/record-pane.mjs) as a Claude Code SessionStart + SessionEnd hook in
|
|
5
|
+
* ~/.claude/settings.json. Lets Claude Control bind each tmux pane to its EXACT
|
|
6
|
+
* transcript with zero guessing.
|
|
7
|
+
*
|
|
8
|
+
* Safe to re-run: detects an existing record-pane hook (by command substring)
|
|
9
|
+
* and leaves the file untouched if already installed. Preserves all other hooks.
|
|
10
|
+
*/
|
|
11
|
+
import { readFile, writeFile, mkdir, copyFile } from 'node:fs/promises';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
|
|
16
|
+
const SETTINGS = path.join(homedir(), '.claude', 'settings.json');
|
|
17
|
+
const SRC_SCRIPT = path.resolve(fileURLToPath(import.meta.url), '..', '..', 'hooks', 'record-pane.mjs');
|
|
18
|
+
// Deploy to ~/.claude/scripts/ and reference it by $HOME — IDENTICAL to the
|
|
19
|
+
// atlas-toolbox olam-skills hook (members/idl3/hooks/record-pane.json), so the
|
|
20
|
+
// two install paths produce the same settings entry and never double-register.
|
|
21
|
+
const DEST_SCRIPT = path.join(homedir(), '.claude', 'scripts', 'record-pane.mjs');
|
|
22
|
+
const COMMAND = 'node "$HOME/.claude/scripts/record-pane.mjs"';
|
|
23
|
+
const EVENTS = ['SessionStart', 'SessionEnd'];
|
|
24
|
+
const MARKER = 'record-pane.mjs';
|
|
25
|
+
|
|
26
|
+
async function readSettings() {
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(await readFile(SETTINGS, 'utf8'));
|
|
29
|
+
} catch (err) {
|
|
30
|
+
if (err.code === 'ENOENT') return {};
|
|
31
|
+
throw new Error(`Could not parse ${SETTINGS}: ${err.message}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function alreadyInstalled(groups) {
|
|
36
|
+
return (groups || []).some((g) =>
|
|
37
|
+
(g.hooks || []).some((h) => typeof h.command === 'string' && h.command.includes(MARKER)),
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function main() {
|
|
42
|
+
// Deploy the script to ~/.claude/scripts/ (idempotent — always refresh it).
|
|
43
|
+
await mkdir(path.dirname(DEST_SCRIPT), { recursive: true });
|
|
44
|
+
await copyFile(SRC_SCRIPT, DEST_SCRIPT);
|
|
45
|
+
|
|
46
|
+
const settings = await readSettings();
|
|
47
|
+
settings.hooks ??= {};
|
|
48
|
+
let changed = false;
|
|
49
|
+
|
|
50
|
+
for (const event of EVENTS) {
|
|
51
|
+
const groups = (settings.hooks[event] ??= []);
|
|
52
|
+
if (alreadyInstalled(groups)) continue;
|
|
53
|
+
groups.push({ hooks: [{ type: 'command', command: COMMAND }] });
|
|
54
|
+
changed = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!changed) {
|
|
58
|
+
console.log(`✓ pane-recording hook already installed (${SETTINGS})`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
await mkdir(path.dirname(SETTINGS), { recursive: true });
|
|
63
|
+
await writeFile(SETTINGS, `${JSON.stringify(settings, null, 2)}\n`, 'utf8');
|
|
64
|
+
console.log(`✓ installed pane-recording hook → ${SETTINGS}`);
|
|
65
|
+
console.log(` command: ${COMMAND}`);
|
|
66
|
+
console.log(' Applies to Claude sessions started from now on.');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
main().catch((err) => {
|
|
70
|
+
console.error(`✗ ${err.message}`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
});
|
package/server.js
CHANGED
|
@@ -14,6 +14,7 @@ import { WebSocketServer } from 'ws';
|
|
|
14
14
|
|
|
15
15
|
import * as tmux from './lib/tmux.js';
|
|
16
16
|
import * as terminal from './lib/terminal.js';
|
|
17
|
+
import * as shell from './lib/shell.js';
|
|
17
18
|
import { TranscriptTailer } from './lib/transcript.js';
|
|
18
19
|
import { SubAgentsWatcher } from './lib/subagents.js';
|
|
19
20
|
import { parsePanePrompt } from './lib/prompt.js';
|
|
@@ -25,8 +26,16 @@ import { sweepUploads, resolveUploadPath } from './lib/uploads.js';
|
|
|
25
26
|
import { getVersionInfo, currentVersion } from './lib/version.js';
|
|
26
27
|
import * as push from './lib/push.js';
|
|
27
28
|
import { readConfig, writeConfig } from './lib/config.js';
|
|
28
|
-
import { optimizePrompt } from './lib/optimize.js';
|
|
29
|
+
import { optimizePrompt, rulesOptimize } from './lib/optimize.js';
|
|
29
30
|
import { complete as claudeCliComplete } from './lib/claude-cli.js';
|
|
31
|
+
import * as mlx from './lib/mlx.js';
|
|
32
|
+
import {
|
|
33
|
+
MLX_MODELS,
|
|
34
|
+
CLAUDE_MODELS,
|
|
35
|
+
detectMachine,
|
|
36
|
+
recommendMlxModel,
|
|
37
|
+
recommendClaudeModel,
|
|
38
|
+
} from './lib/models.js';
|
|
30
39
|
import { transcribe } from './lib/transcribe.js';
|
|
31
40
|
import { listSkills } from './lib/skills.js';
|
|
32
41
|
// Note: the client offers [WS_PROTOCOL, token] as subprotocols; the `ws`
|
|
@@ -255,6 +264,19 @@ const server = http.createServer((req, res) => {
|
|
|
255
264
|
if (!checkToken(req)) return endJson(res, 401, { error: 'unauthorized' });
|
|
256
265
|
return handleOptimize(req, res);
|
|
257
266
|
}
|
|
267
|
+
if (u.pathname === '/api/models') {
|
|
268
|
+
if (!checkToken(req)) return endJson(res, 401, { error: 'unauthorized' });
|
|
269
|
+
const machine = detectMachine();
|
|
270
|
+
return endJson(res, 200, {
|
|
271
|
+
machine,
|
|
272
|
+
// Mark which MLX models are already in the local HF cache so the UI can
|
|
273
|
+
// show downloaded vs. will-download (avoids a surprise multi-GB fetch).
|
|
274
|
+
mlxModels: MLX_MODELS.map((m) => ({ ...m, installed: mlx.isModelCached(m.id) })),
|
|
275
|
+
claudeModels: CLAUDE_MODELS,
|
|
276
|
+
recommendedMlxModel: recommendMlxModel(machine.ramGB),
|
|
277
|
+
recommendedClaudeModel: recommendClaudeModel(),
|
|
278
|
+
});
|
|
279
|
+
}
|
|
258
280
|
if (u.pathname === '/api/transcribe') {
|
|
259
281
|
if (req.method !== 'POST') return endJson(res, 405, { error: 'method not allowed' });
|
|
260
282
|
if (!checkToken(req)) return endJson(res, 401, { error: 'unauthorized' });
|
|
@@ -474,6 +496,13 @@ async function handleConfigSave(req, res) {
|
|
|
474
496
|
}
|
|
475
497
|
try {
|
|
476
498
|
const saved = writeConfig(body);
|
|
499
|
+
// If the MLX backend is active, (re)warm the selected model now — this
|
|
500
|
+
// restarts the local server with the new model and starts any needed
|
|
501
|
+
// download in the background, so the user doesn't hit a cold stall (or a
|
|
502
|
+
// wrong-model hang) on their next ✨ enhance.
|
|
503
|
+
if (saved.optimizeBackend === 'mlx' && mlx.resolveMlxPython()) {
|
|
504
|
+
mlx.warm();
|
|
505
|
+
}
|
|
477
506
|
return endJson(res, 200, saved);
|
|
478
507
|
} catch (err) {
|
|
479
508
|
return endJson(res, 400, { error: String(err?.message || err) });
|
|
@@ -495,13 +524,37 @@ async function handleOptimize(req, res) {
|
|
|
495
524
|
if (text.length > 8000) return endJson(res, 400, { error: 'text exceeds 8000 character limit' });
|
|
496
525
|
const intent = typeof body.intent === 'string' ? body.intent : undefined;
|
|
497
526
|
try {
|
|
498
|
-
const result = await
|
|
527
|
+
const result = await runOptimize(text, intent);
|
|
499
528
|
return endJson(res, 200, result);
|
|
500
529
|
} catch (err) {
|
|
501
530
|
return endJson(res, 500, { error: String(err?.message || err) });
|
|
502
531
|
}
|
|
503
532
|
}
|
|
504
533
|
|
|
534
|
+
// Run the enhancer through the configured backend chain, recording WHICH backend
|
|
535
|
+
// actually produced the result so the UI can label it accurately:
|
|
536
|
+
// - 'mlx' → try local MLX, then claude -p, then rules.
|
|
537
|
+
// - 'claude' → try claude -p, then rules.
|
|
538
|
+
// - 'rules' → deterministic rules optimiser only.
|
|
539
|
+
// optimizePrompt returns mode:'rules' when its injected complete() fails, so a
|
|
540
|
+
// non-'llm' mode means that backend fell through → try the next.
|
|
541
|
+
async function runOptimize(text, intent) {
|
|
542
|
+
const cfg = readConfig();
|
|
543
|
+
const backend = cfg.optimizeBackend;
|
|
544
|
+
if (backend === 'rules') {
|
|
545
|
+
return { ...rulesOptimize(text), backend: 'rules' };
|
|
546
|
+
}
|
|
547
|
+
const order = backend === 'claude' ? ['claude'] : ['mlx', 'claude'];
|
|
548
|
+
for (const b of order) {
|
|
549
|
+
const complete = b === 'mlx' ? (p) => mlx.complete(p) : claudeCliComplete;
|
|
550
|
+
const r = await optimizePrompt(text, { complete, intent });
|
|
551
|
+
if (r.mode === 'llm') {
|
|
552
|
+
return { ...r, backend: b, model: b === 'mlx' ? cfg.mlxModel : cfg.optimizeModel };
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return { ...rulesOptimize(text), backend: 'rules' };
|
|
556
|
+
}
|
|
557
|
+
|
|
505
558
|
// POST /api/transcribe — local speech-to-text. Accepts a raw audio body (the
|
|
506
559
|
// MediaRecorder blob from the voice dialog; ?ext=webm|mp4|wav names the format),
|
|
507
560
|
// caps the size, writes it to a temp file, and runs ffmpeg→whisper.cpp via
|
|
@@ -1342,9 +1395,28 @@ async function handleClientMessage(ws, msg) {
|
|
|
1342
1395
|
if (!session) throw new Error('unknown session');
|
|
1343
1396
|
if (!tmux.isValidTarget(session.target)) throw new Error('invalid tmux target');
|
|
1344
1397
|
const lines = Math.max(1, Math.min(10000, Number(msg.lines) || 40));
|
|
1345
|
-
|
|
1398
|
+
// Terminal-pane rows opt into ANSI escapes so colours render; the plain
|
|
1399
|
+
// LivePane omits the flag (escapes would show as garbage there).
|
|
1400
|
+
const text = await tmux.capturePane(session.target, lines, !!msg.escapes);
|
|
1346
1401
|
return send(ws, { type: 'capture', id: msg.id, text });
|
|
1347
1402
|
}
|
|
1403
|
+
// Interactive terminal panes: forward keystrokes to ANY pane by id (the
|
|
1404
|
+
// selected one). Mirrors the cc-shell shell-* ops but target-addressed.
|
|
1405
|
+
case 'pane-text': {
|
|
1406
|
+
const session = sessionById(msg.id);
|
|
1407
|
+
if (!session) throw new Error('unknown session');
|
|
1408
|
+
if (!tmux.isValidTarget(session.target)) throw new Error('invalid tmux target');
|
|
1409
|
+
await tmux.sendLiteral(session.target, String(msg.text ?? ''));
|
|
1410
|
+
return send(ws, { type: 'ack', op: 'pane-text', ok: true });
|
|
1411
|
+
}
|
|
1412
|
+
case 'pane-key': {
|
|
1413
|
+
const session = sessionById(msg.id);
|
|
1414
|
+
if (!session) throw new Error('unknown session');
|
|
1415
|
+
if (!tmux.isValidTarget(session.target)) throw new Error('invalid tmux target');
|
|
1416
|
+
if (!shell.SHELL_KEYS.has(String(msg.key ?? ''))) throw new Error('key not allowed');
|
|
1417
|
+
await tmux.sendRawKeys(session.target, [String(msg.key)]);
|
|
1418
|
+
return send(ws, { type: 'ack', op: 'pane-key', ok: true });
|
|
1419
|
+
}
|
|
1348
1420
|
case 'promptkey': {
|
|
1349
1421
|
// Respond to a live TUI selection prompt (permission/menu). Whitelisted
|
|
1350
1422
|
// keys only — never arbitrary text — so this can't be used to inject input.
|
|
@@ -1359,6 +1431,33 @@ async function handleClientMessage(ws, msg) {
|
|
|
1359
1431
|
if (sub) sub._lastPrompt = '__force__';
|
|
1360
1432
|
return send(ws, { type: 'ack', op: 'promptkey', ok: true });
|
|
1361
1433
|
}
|
|
1434
|
+
// Composer terminal mode (>_): each Claude session has its OWN sister shell
|
|
1435
|
+
// pane in its window. Resolve the session by id → its target + cwd, then act
|
|
1436
|
+
// on (or lazily create) that window's sister shell.
|
|
1437
|
+
case 'shell-input': {
|
|
1438
|
+
const s = sessionById(msg.id);
|
|
1439
|
+
if (!s) throw new Error('unknown session');
|
|
1440
|
+
await shell.shellInput(s.target, s.cwd, String(msg.line ?? ''));
|
|
1441
|
+
return send(ws, { type: 'ack', op: 'shell-input', ok: true });
|
|
1442
|
+
}
|
|
1443
|
+
case 'shell-text': {
|
|
1444
|
+
const s = sessionById(msg.id);
|
|
1445
|
+
if (!s) throw new Error('unknown session');
|
|
1446
|
+
await shell.shellText(s.target, s.cwd, String(msg.text ?? ''));
|
|
1447
|
+
return send(ws, { type: 'ack', op: 'shell-text', ok: true });
|
|
1448
|
+
}
|
|
1449
|
+
case 'shell-key': {
|
|
1450
|
+
const s = sessionById(msg.id);
|
|
1451
|
+
if (!s) throw new Error('unknown session');
|
|
1452
|
+
await shell.shellKey(s.target, s.cwd, String(msg.key ?? ''));
|
|
1453
|
+
return send(ws, { type: 'ack', op: 'shell-key', ok: true });
|
|
1454
|
+
}
|
|
1455
|
+
case 'shell-capture': {
|
|
1456
|
+
const s = sessionById(msg.id);
|
|
1457
|
+
if (!s) throw new Error('unknown session');
|
|
1458
|
+
const text = await shell.shellCapture(s.target, s.cwd, msg.lines);
|
|
1459
|
+
return send(ws, { type: 'shell-output', id: msg.id, text });
|
|
1460
|
+
}
|
|
1362
1461
|
default:
|
|
1363
1462
|
return;
|
|
1364
1463
|
}
|
|
@@ -1454,6 +1553,16 @@ async function main() {
|
|
|
1454
1553
|
} else {
|
|
1455
1554
|
console.log(' (no COCKPIT_TOKEN set — relying on 127.0.0.1 bind. This UI can type into your sessions.)');
|
|
1456
1555
|
}
|
|
1556
|
+
// Pre-warm the local MLX enhancer so the first ✨ enhance is fast (best-effort;
|
|
1557
|
+
// only when that backend is selected and an mlx python is available).
|
|
1558
|
+
try {
|
|
1559
|
+
if (readConfig().optimizeBackend === 'mlx' && mlx.resolveMlxPython()) {
|
|
1560
|
+
mlx.warm();
|
|
1561
|
+
console.log(' (pre-warming local MLX enhancer model…)');
|
|
1562
|
+
}
|
|
1563
|
+
} catch {
|
|
1564
|
+
/* best-effort */
|
|
1565
|
+
}
|
|
1457
1566
|
});
|
|
1458
1567
|
}
|
|
1459
1568
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{g as Ve}from"./index-BeJg6Cs1.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-DwmU8Yna.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};
|