@integrity-labs/agt-cli 0.28.632 → 0.28.633
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/dist/bin/agt.js +4 -4
- package/dist/{chunk-IT2WYXBM.js → chunk-GNTCOXZG.js} +164 -18
- package/dist/{chunk-IT2WYXBM.js.map → chunk-GNTCOXZG.js.map} +1 -1
- package/dist/{chunk-QDIF33SF.js → chunk-IDERROFJ.js} +3 -3
- package/dist/{claude-pair-runtime-JYRAP5M3.js → claude-pair-runtime-DWNJWCSU.js} +2 -2
- package/dist/lib/manager-worker.js +36 -11
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/slack-channel.js +11 -5
- package/dist/mcp/telegram-channel.js +10 -5
- package/dist/{persistent-session-YER3H6R6.js → persistent-session-ORYBOIBQ.js} +2 -2
- package/dist/{responsiveness-probe-MWZBEJOS.js → responsiveness-probe-WYCKY2BJ.js} +2 -2
- package/package.json +1 -1
- /package/dist/{chunk-QDIF33SF.js.map → chunk-IDERROFJ.js.map} +0 -0
- /package/dist/{claude-pair-runtime-JYRAP5M3.js.map → claude-pair-runtime-DWNJWCSU.js.map} +0 -0
- /package/dist/{persistent-session-YER3H6R6.js.map → persistent-session-ORYBOIBQ.js.map} +0 -0
- /package/dist/{responsiveness-probe-MWZBEJOS.js.map → responsiveness-probe-WYCKY2BJ.js.map} +0 -0
package/dist/bin/agt.js
CHANGED
|
@@ -40,10 +40,10 @@ import {
|
|
|
40
40
|
success,
|
|
41
41
|
table,
|
|
42
42
|
warn
|
|
43
|
-
} from "../chunk-
|
|
43
|
+
} from "../chunk-IDERROFJ.js";
|
|
44
44
|
import {
|
|
45
45
|
readDirectChatSessionState
|
|
46
|
-
} from "../chunk-
|
|
46
|
+
} from "../chunk-GNTCOXZG.js";
|
|
47
47
|
import {
|
|
48
48
|
AnchorSessionClient,
|
|
49
49
|
CHANNEL_REGISTRY,
|
|
@@ -4909,7 +4909,7 @@ import { execFileSync, execSync } from "child_process";
|
|
|
4909
4909
|
import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
|
|
4910
4910
|
import chalk18 from "chalk";
|
|
4911
4911
|
import ora16 from "ora";
|
|
4912
|
-
var cliVersion = true ? "0.28.
|
|
4912
|
+
var cliVersion = true ? "0.28.633" : "dev";
|
|
4913
4913
|
async function fetchLatestVersion() {
|
|
4914
4914
|
const host2 = getHost();
|
|
4915
4915
|
if (!host2) return null;
|
|
@@ -6089,7 +6089,7 @@ function handleError(err) {
|
|
|
6089
6089
|
}
|
|
6090
6090
|
|
|
6091
6091
|
// src/bin/agt.ts
|
|
6092
|
-
var cliVersion2 = true ? "0.28.
|
|
6092
|
+
var cliVersion2 = true ? "0.28.633" : "dev";
|
|
6093
6093
|
var program = new Command();
|
|
6094
6094
|
program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
|
|
6095
6095
|
program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -2400,8 +2400,22 @@ function isSessionFeedbackDialogVisible(screen) {
|
|
|
2400
2400
|
return screen.includes("How is Claude doing this session") && screen.includes("0: Dismiss");
|
|
2401
2401
|
}
|
|
2402
2402
|
var USAGE_LIMIT_SAFE_OPTION = "Stop and wait for limit to reset";
|
|
2403
|
+
var USAGE_LIMIT_CONTINUE_OPTION = "Wait here, then continue automatically";
|
|
2404
|
+
var USAGE_LIMIT_SAFE_OPTIONS = [
|
|
2405
|
+
USAGE_LIMIT_CONTINUE_OPTION,
|
|
2406
|
+
USAGE_LIMIT_SAFE_OPTION
|
|
2407
|
+
];
|
|
2408
|
+
var USAGE_LIMIT_KNOWN_OPTIONS = [
|
|
2409
|
+
...USAGE_LIMIT_SAFE_OPTIONS,
|
|
2410
|
+
"Switch to usage credits",
|
|
2411
|
+
"Switch to Team plan",
|
|
2412
|
+
// ENG-9006: the two-option variant Claude Code shipped ~2026-08-17. Filed
|
|
2413
|
+
// with a wedged pane and four unanswered customer Telegram messages queued
|
|
2414
|
+
// behind it.
|
|
2415
|
+
"Upgrade your plan",
|
|
2416
|
+
"Ask your admin for more usage"
|
|
2417
|
+
];
|
|
2403
2418
|
var USAGE_LIMIT_BLOCK_LINES = 6;
|
|
2404
|
-
var BILLING_OPTIONS = ["Switch to usage credits", "Switch to Team plan"];
|
|
2405
2419
|
function optionRowDigit(line2, label) {
|
|
2406
2420
|
const m = line2.match(
|
|
2407
2421
|
new RegExp(
|
|
@@ -2410,6 +2424,27 @@ function optionRowDigit(line2, label) {
|
|
|
2410
2424
|
);
|
|
2411
2425
|
return m?.[1] ?? null;
|
|
2412
2426
|
}
|
|
2427
|
+
function focusedModalBlock(screen, blockLines) {
|
|
2428
|
+
const lines = screen.split("\n");
|
|
2429
|
+
let footer = -1;
|
|
2430
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
2431
|
+
if (lines[i].includes("Enter to confirm")) {
|
|
2432
|
+
footer = i;
|
|
2433
|
+
break;
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
if (footer < 0) return null;
|
|
2437
|
+
return lines.slice(Math.max(0, footer - blockLines), footer);
|
|
2438
|
+
}
|
|
2439
|
+
var MCP_DIALOG_OPTIONS = [
|
|
2440
|
+
"Use this and all future MCP servers in this project",
|
|
2441
|
+
"Continue without using these MCP servers"
|
|
2442
|
+
];
|
|
2443
|
+
function isMcpServersDialogVisible(screen) {
|
|
2444
|
+
const block = focusedModalBlock(screen, USAGE_LIMIT_BLOCK_LINES);
|
|
2445
|
+
if (!block) return false;
|
|
2446
|
+
return block.some((l) => MCP_DIALOG_OPTIONS.some((label) => optionRowDigit(l, label) !== null));
|
|
2447
|
+
}
|
|
2413
2448
|
function usageLimitModalBlock(screen) {
|
|
2414
2449
|
const lines = screen.split("\n");
|
|
2415
2450
|
let footer = -1;
|
|
@@ -2421,20 +2456,38 @@ function usageLimitModalBlock(screen) {
|
|
|
2421
2456
|
}
|
|
2422
2457
|
if (footer < 0) return null;
|
|
2423
2458
|
const block = lines.slice(Math.max(0, footer - USAGE_LIMIT_BLOCK_LINES), footer);
|
|
2424
|
-
const
|
|
2425
|
-
(l) =>
|
|
2459
|
+
const hasKnownOptionRow = block.some(
|
|
2460
|
+
(l) => USAGE_LIMIT_KNOWN_OPTIONS.some((label) => optionRowDigit(l, label) !== null)
|
|
2426
2461
|
);
|
|
2427
|
-
return
|
|
2462
|
+
return hasKnownOptionRow ? block : null;
|
|
2428
2463
|
}
|
|
2429
2464
|
function isUsageLimitChoiceDialogVisible(screen) {
|
|
2430
2465
|
return usageLimitModalBlock(screen) !== null;
|
|
2431
2466
|
}
|
|
2467
|
+
function findUsageLimitSafeOption(screen) {
|
|
2468
|
+
const block = usageLimitModalBlock(screen);
|
|
2469
|
+
if (!block) return null;
|
|
2470
|
+
for (const label of USAGE_LIMIT_SAFE_OPTIONS) {
|
|
2471
|
+
for (const line2 of block) {
|
|
2472
|
+
const digit = optionRowDigit(line2, label);
|
|
2473
|
+
if (digit !== null) return { key: digit, label };
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
return null;
|
|
2477
|
+
}
|
|
2432
2478
|
function findUsageLimitSafeOptionKey(screen) {
|
|
2479
|
+
return findUsageLimitSafeOption(screen)?.key ?? null;
|
|
2480
|
+
}
|
|
2481
|
+
function findUsageLimitResetHint(screen) {
|
|
2433
2482
|
const block = usageLimitModalBlock(screen);
|
|
2434
2483
|
if (!block) return null;
|
|
2435
2484
|
for (const line2 of block) {
|
|
2436
|
-
|
|
2437
|
-
|
|
2485
|
+
if (optionRowDigit(line2, USAGE_LIMIT_CONTINUE_OPTION) === null) continue;
|
|
2486
|
+
const idx = line2.indexOf(USAGE_LIMIT_CONTINUE_OPTION);
|
|
2487
|
+
const tail = line2.slice(idx + USAGE_LIMIT_CONTINUE_OPTION.length).trim();
|
|
2488
|
+
const when = tail.replace(/^at\s+/i, "").trim();
|
|
2489
|
+
if (!when) return null;
|
|
2490
|
+
return when.slice(0, 40);
|
|
2438
2491
|
}
|
|
2439
2492
|
return null;
|
|
2440
2493
|
}
|
|
@@ -2443,13 +2496,17 @@ function isUnanswerableUsageLimitDialog(screen) {
|
|
|
2443
2496
|
}
|
|
2444
2497
|
function sweepDialogs(screen) {
|
|
2445
2498
|
if (isUsageLimitChoiceDialogVisible(screen)) {
|
|
2446
|
-
const
|
|
2447
|
-
if (!
|
|
2499
|
+
const safe = findUsageLimitSafeOption(screen);
|
|
2500
|
+
if (!safe) return null;
|
|
2448
2501
|
return {
|
|
2449
2502
|
kind: "usage-limit-choice",
|
|
2450
|
-
|
|
2503
|
+
// The log names the option ACTUALLY picked, not a fixed literal. With two
|
|
2504
|
+
// selectable rows now, a constant string would make a fleet sweep unable
|
|
2505
|
+
// to tell an agent that will resume by itself from one parked until a
|
|
2506
|
+
// human touches it.
|
|
2507
|
+
keys: [safe.key, "Enter"],
|
|
2451
2508
|
interKeyDelayMs: 300,
|
|
2452
|
-
logMessage: `Auto-answered usage-limit choice dialog (picked '${
|
|
2509
|
+
logMessage: `Auto-answered usage-limit choice dialog (picked '${safe.label}')`
|
|
2453
2510
|
};
|
|
2454
2511
|
}
|
|
2455
2512
|
if (screen.includes("Choose the text style") || screen.includes("Dark mode") && screen.includes("Light mode")) {
|
|
@@ -2484,7 +2541,7 @@ function sweepDialogs(screen) {
|
|
|
2484
2541
|
logMessage: "Auto-accepted dev channels"
|
|
2485
2542
|
};
|
|
2486
2543
|
}
|
|
2487
|
-
if (
|
|
2544
|
+
if (isMcpServersDialogVisible(screen)) {
|
|
2488
2545
|
return {
|
|
2489
2546
|
kind: "mcp-servers",
|
|
2490
2547
|
keys: ["Enter"],
|
|
@@ -2520,6 +2577,24 @@ async function sendDialogKeys(tmuxSession, action) {
|
|
|
2520
2577
|
});
|
|
2521
2578
|
}
|
|
2522
2579
|
}
|
|
2580
|
+
function focusedConfirmDialogBlock(screen) {
|
|
2581
|
+
const lines = screen.split("\n");
|
|
2582
|
+
let footer = -1;
|
|
2583
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
2584
|
+
if (lines[i].includes("Enter to confirm")) {
|
|
2585
|
+
footer = i;
|
|
2586
|
+
break;
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
if (footer < 0) return null;
|
|
2590
|
+
return lines.slice(Math.max(0, footer - USAGE_LIMIT_BLOCK_LINES), footer + 1);
|
|
2591
|
+
}
|
|
2592
|
+
function isUnclaimedConfirmDialog(screen) {
|
|
2593
|
+
if (focusedConfirmDialogBlock(screen) === null) return false;
|
|
2594
|
+
if (sweepDialogs(screen) !== null) return false;
|
|
2595
|
+
if (isUnanswerableUsageLimitDialog(screen)) return false;
|
|
2596
|
+
return true;
|
|
2597
|
+
}
|
|
2523
2598
|
function simpleTextHash(s) {
|
|
2524
2599
|
let h = 0;
|
|
2525
2600
|
for (let i = 0; i < s.length; i++) {
|
|
@@ -2529,6 +2604,7 @@ function simpleTextHash(s) {
|
|
|
2529
2604
|
}
|
|
2530
2605
|
|
|
2531
2606
|
// src/lib/channel-input-watchdog.ts
|
|
2607
|
+
var UNCLAIMED_DIALOG_ALERT_MS = 12e4;
|
|
2532
2608
|
var STUCK_THRESHOLD_MS = 5e3;
|
|
2533
2609
|
var MAX_ENTER_FIRES = 3;
|
|
2534
2610
|
var DISTURB_HEAL_KEYS = ["x", "BSpace", "Enter"];
|
|
@@ -2554,30 +2630,39 @@ function decide(pane, prev, now, config = {}) {
|
|
|
2554
2630
|
next: prev
|
|
2555
2631
|
};
|
|
2556
2632
|
}
|
|
2633
|
+
const unclaimedBlock = isUnclaimedConfirmDialog(pane) ? focusedConfirmDialogBlock(pane) : null;
|
|
2634
|
+
const unclaimedDialogHash = unclaimedBlock ? simpleTextHash(unclaimedBlock.join("\n")) : void 0;
|
|
2557
2635
|
const inputText = extractInputBoxText(pane);
|
|
2558
2636
|
if (!inputText) {
|
|
2559
|
-
return { fire: false, next: void 0 };
|
|
2637
|
+
return { fire: false, unclaimedDialogHash, next: void 0 };
|
|
2560
2638
|
}
|
|
2561
2639
|
if (inputText === "\u2026") {
|
|
2562
|
-
return { fire: false, next: void 0 };
|
|
2640
|
+
return { fire: false, unclaimedDialogHash, next: void 0 };
|
|
2563
2641
|
}
|
|
2564
2642
|
const hash = simpleTextHash(inputText);
|
|
2565
2643
|
if (!prev || prev.lastInputHash !== hash) {
|
|
2566
2644
|
return {
|
|
2567
2645
|
fire: false,
|
|
2646
|
+
unclaimedDialogHash,
|
|
2568
2647
|
next: { lastInputHash: hash, firstSeenAt: now, fires: 0, lastFireAt: 0, gaveUpLogged: false }
|
|
2569
2648
|
};
|
|
2570
2649
|
}
|
|
2571
2650
|
if (prev.fires >= maxFires) {
|
|
2572
2651
|
if (!prev.gaveUpLogged) {
|
|
2573
|
-
return {
|
|
2652
|
+
return {
|
|
2653
|
+
fire: false,
|
|
2654
|
+
gaveUp: true,
|
|
2655
|
+
unclaimedDialogHash,
|
|
2656
|
+
next: { ...prev, gaveUpLogged: true }
|
|
2657
|
+
};
|
|
2574
2658
|
}
|
|
2575
|
-
return { fire: false, next: prev };
|
|
2659
|
+
return { fire: false, unclaimedDialogHash, next: prev };
|
|
2576
2660
|
}
|
|
2577
2661
|
const sinceLastAttempt = prev.fires === 0 ? now - prev.firstSeenAt : now - prev.lastFireAt;
|
|
2578
|
-
if (sinceLastAttempt < threshold) return { fire: false, next: prev };
|
|
2662
|
+
if (sinceLastAttempt < threshold) return { fire: false, unclaimedDialogHash, next: prev };
|
|
2579
2663
|
return {
|
|
2580
2664
|
fire: true,
|
|
2665
|
+
unclaimedDialogHash,
|
|
2581
2666
|
next: { ...prev, fires: prev.fires + 1, lastFireAt: now }
|
|
2582
2667
|
};
|
|
2583
2668
|
}
|
|
@@ -2622,6 +2707,15 @@ function checkChannelInputs(codeNames, io, config = {}, states = sharedStates) {
|
|
|
2622
2707
|
for (const key of [...giveUpCounts.keys()]) {
|
|
2623
2708
|
if (!live.has(key)) giveUpCounts.delete(key);
|
|
2624
2709
|
}
|
|
2710
|
+
for (const key of [...unclaimedDialogCounts.keys()]) {
|
|
2711
|
+
if (!live.has(key)) unclaimedDialogCounts.delete(key);
|
|
2712
|
+
}
|
|
2713
|
+
for (const key of [...unclaimedDialogSeen.keys()]) {
|
|
2714
|
+
if (!live.has(key)) unclaimedDialogSeen.delete(key);
|
|
2715
|
+
}
|
|
2716
|
+
for (const key of [...usageLimitSignalled.keys()]) {
|
|
2717
|
+
if (!live.has(key)) usageLimitSignalled.delete(key);
|
|
2718
|
+
}
|
|
2625
2719
|
}
|
|
2626
2720
|
function checkOne(codeName, io, config, states) {
|
|
2627
2721
|
const pane = io.capturePane(codeName);
|
|
@@ -2635,7 +2729,7 @@ function checkOne(codeName, io, config, states) {
|
|
|
2635
2729
|
stuckThresholdMs: config.attachedStuckThresholdMs ?? ATTACHED_STUCK_THRESHOLD_MS
|
|
2636
2730
|
} : config;
|
|
2637
2731
|
const prev = states.get(codeName);
|
|
2638
|
-
const { fire, dialog, gaveUp, blockedDialog, next } = decide(
|
|
2732
|
+
const { fire, dialog, gaveUp, blockedDialog, unclaimedDialogHash, next } = decide(
|
|
2639
2733
|
pane,
|
|
2640
2734
|
prev,
|
|
2641
2735
|
io.now(),
|
|
@@ -2651,14 +2745,23 @@ function checkOne(codeName, io, config, states) {
|
|
|
2651
2745
|
} else {
|
|
2652
2746
|
states.set(codeName, next);
|
|
2653
2747
|
}
|
|
2748
|
+
trackUnclaimedDialog(codeName, unclaimedDialogHash, io, effectiveConfig);
|
|
2749
|
+
const onUsageLimitModal = dialog?.kind === "usage-limit-choice" || blockedDialog === "usage-limit-choice-unrecognised-options";
|
|
2750
|
+
if (!onUsageLimitModal) usageLimitSignalled.delete(codeName);
|
|
2654
2751
|
if (dialog) {
|
|
2655
2752
|
io.log(
|
|
2656
2753
|
`[channel-input-watchdog] '${codeName}': ${dialog.logMessage} (dialog was blocking the input box)`
|
|
2657
2754
|
);
|
|
2755
|
+
if (dialog.kind === "usage-limit-choice") {
|
|
2756
|
+
maybeSignalUsageLimit(codeName, pane, io);
|
|
2757
|
+
}
|
|
2658
2758
|
io.sendKeys(codeName, dialog.keys, dialog.interKeyDelayMs);
|
|
2659
2759
|
return;
|
|
2660
2760
|
}
|
|
2661
2761
|
if (blockedDialog) {
|
|
2762
|
+
if (blockedDialog === "usage-limit-choice-unrecognised-options") {
|
|
2763
|
+
maybeSignalUsageLimit(codeName, pane, io);
|
|
2764
|
+
}
|
|
2662
2765
|
io.log(
|
|
2663
2766
|
`[channel-input-watchdog] '${codeName}': BLOCKED DIALOG (${blockedDialog}) \u2014 refusing to send any key; needs a human to attach to the pane`
|
|
2664
2767
|
);
|
|
@@ -2710,6 +2813,49 @@ function creditWatchdogGiveUpCount(codeName, count) {
|
|
|
2710
2813
|
if (count <= 0) return;
|
|
2711
2814
|
giveUpCounts.set(codeName, (giveUpCounts.get(codeName) ?? 0) + count);
|
|
2712
2815
|
}
|
|
2816
|
+
var usageLimitSignalled = /* @__PURE__ */ new Map();
|
|
2817
|
+
function maybeSignalUsageLimit(codeName, pane, io) {
|
|
2818
|
+
if (!io.signalUsageLimit) return;
|
|
2819
|
+
const hint = findUsageLimitResetHint(pane);
|
|
2820
|
+
const key = hint ?? "<no-reset-named>";
|
|
2821
|
+
if (usageLimitSignalled.get(codeName) === key) return;
|
|
2822
|
+
usageLimitSignalled.set(codeName, key);
|
|
2823
|
+
try {
|
|
2824
|
+
io.signalUsageLimit(codeName, hint);
|
|
2825
|
+
io.log(
|
|
2826
|
+
`[channel-input-watchdog] '${codeName}': usage-limit modal \u2014 signalled the channel servers so waiting people are told` + (hint ? ` (resets ${hint})` : " (modal named no reset)")
|
|
2827
|
+
);
|
|
2828
|
+
} catch (err) {
|
|
2829
|
+
io.log(
|
|
2830
|
+
`[channel-input-watchdog] '${codeName}': usage-limit signal write failed: ${err.message}`
|
|
2831
|
+
);
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
function trackUnclaimedDialog(codeName, hash, io, config) {
|
|
2835
|
+
if (!hash) {
|
|
2836
|
+
unclaimedDialogSeen.delete(codeName);
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
const thresholdMs = config.unclaimedDialogAlertMs ?? UNCLAIMED_DIALOG_ALERT_MS;
|
|
2840
|
+
const now = io.now();
|
|
2841
|
+
const prev = unclaimedDialogSeen.get(codeName);
|
|
2842
|
+
if (!prev || prev.hash !== hash) {
|
|
2843
|
+
unclaimedDialogSeen.set(codeName, { hash, firstSeenAt: now, alerted: false });
|
|
2844
|
+
return;
|
|
2845
|
+
}
|
|
2846
|
+
if (prev.alerted) return;
|
|
2847
|
+
const ageMs = now - prev.firstSeenAt;
|
|
2848
|
+
if (ageMs < thresholdMs) return;
|
|
2849
|
+
unclaimedDialogSeen.set(codeName, { ...prev, alerted: true });
|
|
2850
|
+
unclaimedDialogCounts.set(codeName, (unclaimedDialogCounts.get(codeName) ?? 0) + 1);
|
|
2851
|
+
io.log(
|
|
2852
|
+
`[channel-input-watchdog] '${codeName}': UNCLAIMED DIALOG on pane for ${Math.round(
|
|
2853
|
+
ageMs / 1e3
|
|
2854
|
+
)}s \u2014 a modal is focused and no handler in claude-dialogs.ts recognises it (dialog_hash=${hash}); sending nothing. Claude Code has likely reworded a dialog: attach to the pane, then add the new option labels.`
|
|
2855
|
+
);
|
|
2856
|
+
}
|
|
2857
|
+
var unclaimedDialogCounts = /* @__PURE__ */ new Map();
|
|
2858
|
+
var unclaimedDialogSeen = /* @__PURE__ */ new Map();
|
|
2713
2859
|
|
|
2714
2860
|
// src/lib/persistent-session.ts
|
|
2715
2861
|
var OPENROUTER_ANTHROPIC_BASE_URL = "https://openrouter.ai/api";
|
|
@@ -4167,4 +4313,4 @@ export {
|
|
|
4167
4313
|
stopAllSessionsAndWait,
|
|
4168
4314
|
getProjectDir
|
|
4169
4315
|
};
|
|
4170
|
-
//# sourceMappingURL=chunk-
|
|
4316
|
+
//# sourceMappingURL=chunk-GNTCOXZG.js.map
|