@integrity-labs/agt-cli 0.27.73 → 0.27.75
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 +3 -3
- package/dist/{chunk-WBT4UEOY.js → chunk-AWAKTFWY.js} +1 -1
- package/dist/{chunk-7YM2F3DG.js → chunk-VTAXNSGS.js} +282 -51
- package/dist/chunk-VTAXNSGS.js.map +1 -0
- package/dist/{claude-pair-runtime-2XWSYFSY.js → claude-pair-runtime-XMX2QOGP.js} +2 -2
- package/dist/lib/manager-worker.js +39 -110
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/teams-channel.js +15932 -0
- package/dist/{persistent-session-S7OJTKKE.js → persistent-session-CXKB7FU3.js} +2 -2
- package/dist/{responsiveness-probe-LGNXOX43.js → responsiveness-probe-EKB5VBCX.js} +2 -2
- package/package.json +2 -2
- package/dist/chunk-7YM2F3DG.js.map +0 -1
- /package/dist/{chunk-WBT4UEOY.js.map → chunk-AWAKTFWY.js.map} +0 -0
- /package/dist/{claude-pair-runtime-2XWSYFSY.js.map → claude-pair-runtime-XMX2QOGP.js.map} +0 -0
- /package/dist/{persistent-session-S7OJTKKE.js.map → persistent-session-CXKB7FU3.js.map} +0 -0
- /package/dist/{responsiveness-probe-LGNXOX43.js.map → responsiveness-probe-EKB5VBCX.js.map} +0 -0
package/dist/bin/agt.js
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
success,
|
|
29
29
|
table,
|
|
30
30
|
warn
|
|
31
|
-
} from "../chunk-
|
|
31
|
+
} from "../chunk-AWAKTFWY.js";
|
|
32
32
|
import {
|
|
33
33
|
CHANNEL_REGISTRY,
|
|
34
34
|
DEPLOYMENT_TEMPLATES,
|
|
@@ -4930,7 +4930,7 @@ import { execFileSync, execSync } from "child_process";
|
|
|
4930
4930
|
import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
|
|
4931
4931
|
import chalk18 from "chalk";
|
|
4932
4932
|
import ora16 from "ora";
|
|
4933
|
-
var cliVersion = true ? "0.27.
|
|
4933
|
+
var cliVersion = true ? "0.27.75" : "dev";
|
|
4934
4934
|
async function fetchLatestVersion() {
|
|
4935
4935
|
const host2 = getHost();
|
|
4936
4936
|
if (!host2) return null;
|
|
@@ -5853,7 +5853,7 @@ function handleError(err) {
|
|
|
5853
5853
|
}
|
|
5854
5854
|
|
|
5855
5855
|
// src/bin/agt.ts
|
|
5856
|
-
var cliVersion2 = true ? "0.27.
|
|
5856
|
+
var cliVersion2 = true ? "0.27.75" : "dev";
|
|
5857
5857
|
var program = new Command();
|
|
5858
5858
|
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");
|
|
5859
5859
|
program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./chunk-XWVM4KPK.js";
|
|
8
8
|
|
|
9
9
|
// src/lib/persistent-session.ts
|
|
10
|
-
import { spawn, execSync, execFileSync as
|
|
10
|
+
import { spawn, execSync, execFileSync as execFileSync3 } from "child_process";
|
|
11
11
|
import { join as join2, dirname } from "path";
|
|
12
12
|
import { homedir as homedir2, platform, userInfo } from "os";
|
|
13
13
|
import { existsSync as existsSync3, readFileSync as readFileSync4, readdirSync, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync2, chmodSync, copyFileSync, rmSync } from "fs";
|
|
@@ -279,6 +279,216 @@ function probeClaudeProcessInTmux(tmuxSession) {
|
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
+
// src/lib/claude-dialogs.ts
|
|
283
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
284
|
+
function isLoginPickerVisible(screen) {
|
|
285
|
+
return screen.includes("Select login method") || screen.includes("Claude account with subscription") && screen.includes("Anthropic Console account");
|
|
286
|
+
}
|
|
287
|
+
function isResumeModeDialogVisible(screen) {
|
|
288
|
+
return screen.includes("Resume from summary") && screen.includes("Don't ask me again");
|
|
289
|
+
}
|
|
290
|
+
function isSessionFeedbackDialogVisible(screen) {
|
|
291
|
+
return screen.includes("How is Claude doing this session") && screen.includes("0: Dismiss");
|
|
292
|
+
}
|
|
293
|
+
function sweepDialogs(screen) {
|
|
294
|
+
if (screen.includes("Choose the text style") || screen.includes("Dark mode") && screen.includes("Light mode")) {
|
|
295
|
+
return {
|
|
296
|
+
kind: "theme-picker",
|
|
297
|
+
keys: ["Enter"],
|
|
298
|
+
interKeyDelayMs: 0,
|
|
299
|
+
logMessage: "Auto-accepted theme picker"
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
if (screen.includes("Yes, I trust this folder")) {
|
|
303
|
+
return {
|
|
304
|
+
kind: "folder-trust",
|
|
305
|
+
keys: ["Enter"],
|
|
306
|
+
interKeyDelayMs: 0,
|
|
307
|
+
logMessage: "Auto-accepted folder trust"
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
if (isResumeModeDialogVisible(screen)) {
|
|
311
|
+
return {
|
|
312
|
+
kind: "resume-mode",
|
|
313
|
+
keys: ["3", "Enter"],
|
|
314
|
+
interKeyDelayMs: 300,
|
|
315
|
+
logMessage: "Auto-dismissed resume-mode dialog (picked 'Don't ask me again')"
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
if (screen.includes("I am using this for local development")) {
|
|
319
|
+
return {
|
|
320
|
+
kind: "dev-channels",
|
|
321
|
+
keys: ["Enter"],
|
|
322
|
+
interKeyDelayMs: 0,
|
|
323
|
+
logMessage: "Auto-accepted dev channels"
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
if (screen.includes("Enter to confirm") && screen.includes("MCP")) {
|
|
327
|
+
return {
|
|
328
|
+
kind: "mcp-servers",
|
|
329
|
+
keys: ["Enter"],
|
|
330
|
+
interKeyDelayMs: 0,
|
|
331
|
+
logMessage: "Auto-accepted MCP servers"
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
if (screen.includes("Yes, I accept") && screen.includes("Bypass Permissions")) {
|
|
335
|
+
return {
|
|
336
|
+
kind: "bypass-permissions",
|
|
337
|
+
keys: ["2", "Enter"],
|
|
338
|
+
interKeyDelayMs: 300,
|
|
339
|
+
logMessage: "Auto-accepted bypass permissions"
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
if (isSessionFeedbackDialogVisible(screen)) {
|
|
343
|
+
return {
|
|
344
|
+
kind: "session-feedback",
|
|
345
|
+
keys: ["0"],
|
|
346
|
+
interKeyDelayMs: 0,
|
|
347
|
+
logMessage: "Auto-dismissed session-feedback dialog"
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
async function sendDialogKeys(tmuxSession, action) {
|
|
353
|
+
for (let i = 0; i < action.keys.length; i++) {
|
|
354
|
+
if (i > 0 && action.interKeyDelayMs > 0) {
|
|
355
|
+
await new Promise((r) => setTimeout(r, action.interKeyDelayMs));
|
|
356
|
+
}
|
|
357
|
+
execFileSync2("tmux", ["send-keys", "-t", tmuxSession, action.keys[i]], {
|
|
358
|
+
stdio: "ignore"
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function simpleTextHash(s) {
|
|
363
|
+
let h = 0;
|
|
364
|
+
for (let i = 0; i < s.length; i++) {
|
|
365
|
+
h = (h << 5) - h + s.charCodeAt(i) | 0;
|
|
366
|
+
}
|
|
367
|
+
return h.toString(16);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// src/lib/channel-input-watchdog.ts
|
|
371
|
+
var STUCK_THRESHOLD_MS = 5e3;
|
|
372
|
+
var MAX_ENTER_FIRES = 3;
|
|
373
|
+
var ATTACHED_STUCK_THRESHOLD_MS = 15e3;
|
|
374
|
+
var INPUT_BOX_DIVIDER = /^[─━]{10,}/;
|
|
375
|
+
var PROMPT_PREFIX = "\u276F ";
|
|
376
|
+
function decide(pane, prev, now, config = {}) {
|
|
377
|
+
const threshold = config.stuckThresholdMs ?? STUCK_THRESHOLD_MS;
|
|
378
|
+
const maxFires = config.maxEnterFires ?? MAX_ENTER_FIRES;
|
|
379
|
+
const dialogAction = sweepDialogs(pane);
|
|
380
|
+
if (dialogAction) {
|
|
381
|
+
return { fire: false, dialog: dialogAction, next: prev };
|
|
382
|
+
}
|
|
383
|
+
const inputText = extractInputBoxText(pane);
|
|
384
|
+
if (!inputText) {
|
|
385
|
+
return { fire: false, next: void 0 };
|
|
386
|
+
}
|
|
387
|
+
if (isActivelyProcessing(pane)) {
|
|
388
|
+
return { fire: false, next: prev };
|
|
389
|
+
}
|
|
390
|
+
const hash = simpleTextHash(inputText);
|
|
391
|
+
if (!prev || prev.lastInputHash !== hash) {
|
|
392
|
+
return {
|
|
393
|
+
fire: false,
|
|
394
|
+
next: { lastInputHash: hash, firstSeenAt: now, fires: 0, lastFireAt: 0, gaveUpLogged: false }
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
if (prev.fires >= maxFires) {
|
|
398
|
+
if (!prev.gaveUpLogged) {
|
|
399
|
+
return { fire: false, gaveUp: true, next: { ...prev, gaveUpLogged: true } };
|
|
400
|
+
}
|
|
401
|
+
return { fire: false, next: prev };
|
|
402
|
+
}
|
|
403
|
+
const sinceLastAttempt = prev.fires === 0 ? now - prev.firstSeenAt : now - prev.lastFireAt;
|
|
404
|
+
if (sinceLastAttempt < threshold) return { fire: false, next: prev };
|
|
405
|
+
return {
|
|
406
|
+
fire: true,
|
|
407
|
+
next: { ...prev, fires: prev.fires + 1, lastFireAt: now }
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
function extractInputBoxText(pane) {
|
|
411
|
+
const lines = pane.split("\n");
|
|
412
|
+
for (let i = 1; i < lines.length; i++) {
|
|
413
|
+
const line = lines[i] ?? "";
|
|
414
|
+
if (!line.startsWith(PROMPT_PREFIX)) continue;
|
|
415
|
+
let j = i - 1;
|
|
416
|
+
while (j >= 0 && (lines[j] ?? "").trim() === "") j--;
|
|
417
|
+
if (j < 0) continue;
|
|
418
|
+
if (!INPUT_BOX_DIVIDER.test((lines[j] ?? "").trim())) continue;
|
|
419
|
+
const text = line.slice(PROMPT_PREFIX.length).trim();
|
|
420
|
+
return text.length > 0 ? text : null;
|
|
421
|
+
}
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
function isActivelyProcessing(pane) {
|
|
425
|
+
const lines = pane.split("\n");
|
|
426
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
427
|
+
const line = (lines[i] ?? "").trim();
|
|
428
|
+
if (!line.startsWith("\u273B")) continue;
|
|
429
|
+
if (/\bfor\s+\d+s\s*$/.test(line)) return false;
|
|
430
|
+
if (/\b\w+ing[…\.]{0,3}\s*$/i.test(line)) return true;
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
function checkChannelInputs(codeNames, io, config = {}, states = sharedStates) {
|
|
436
|
+
const live = new Set(codeNames);
|
|
437
|
+
for (const codeName of codeNames) {
|
|
438
|
+
try {
|
|
439
|
+
checkOne(codeName, io, config, states);
|
|
440
|
+
} catch (err) {
|
|
441
|
+
io.log(`[channel-input-watchdog] '${codeName}': ${err.message}`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
for (const key of [...states.keys()]) {
|
|
445
|
+
if (!live.has(key)) states.delete(key);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
function checkOne(codeName, io, config, states) {
|
|
449
|
+
const pane = io.capturePane(codeName);
|
|
450
|
+
if (!pane) {
|
|
451
|
+
states.delete(codeName);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
const attached = io.isClientAttached(codeName);
|
|
455
|
+
const effectiveConfig = attached ? {
|
|
456
|
+
...config,
|
|
457
|
+
stuckThresholdMs: config.attachedStuckThresholdMs ?? ATTACHED_STUCK_THRESHOLD_MS
|
|
458
|
+
} : config;
|
|
459
|
+
const prev = states.get(codeName);
|
|
460
|
+
const { fire, dialog, gaveUp, next } = decide(pane, prev, io.now(), effectiveConfig);
|
|
461
|
+
if (next === void 0) {
|
|
462
|
+
states.delete(codeName);
|
|
463
|
+
} else {
|
|
464
|
+
states.set(codeName, next);
|
|
465
|
+
}
|
|
466
|
+
if (dialog) {
|
|
467
|
+
io.log(
|
|
468
|
+
`[channel-input-watchdog] '${codeName}': ${dialog.logMessage} (dialog was blocking the input box)`
|
|
469
|
+
);
|
|
470
|
+
io.sendKeys(codeName, dialog.keys, dialog.interKeyDelayMs);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
const text = extractInputBoxText(pane) ?? "";
|
|
474
|
+
const hash = next?.lastInputHash ?? simpleTextHash(text);
|
|
475
|
+
if (gaveUp) {
|
|
476
|
+
const maxFires = effectiveConfig.maxEnterFires ?? MAX_ENTER_FIRES;
|
|
477
|
+
io.log(
|
|
478
|
+
`[channel-input-watchdog] '${codeName}': GIVING UP after ${maxFires} Enter attempts \u2014 input remains unsubmitted (input_hash=${hash}, len=${text.length})`
|
|
479
|
+
);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
if (fire) {
|
|
483
|
+
const maxFires = effectiveConfig.maxEnterFires ?? MAX_ENTER_FIRES;
|
|
484
|
+
io.log(
|
|
485
|
+
`[channel-input-watchdog] '${codeName}': stuck channel input \u2014 firing Enter (attempt ${next?.fires ?? 1}/${maxFires}, input_hash=${hash}, len=${text.length})`
|
|
486
|
+
);
|
|
487
|
+
io.sendEnter(codeName);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
var sharedStates = /* @__PURE__ */ new Map();
|
|
491
|
+
|
|
282
492
|
// src/lib/persistent-session.ts
|
|
283
493
|
function syncClaudeCredsToRoot() {
|
|
284
494
|
if (platform() !== "linux") return true;
|
|
@@ -405,7 +615,7 @@ function getAcpxBin() {
|
|
|
405
615
|
}
|
|
406
616
|
function defaultAcpxSessionProbe(acpxBin, projectDir) {
|
|
407
617
|
try {
|
|
408
|
-
|
|
618
|
+
execFileSync3(acpxBin, ["claude", "list-sessions"], {
|
|
409
619
|
cwd: projectDir,
|
|
410
620
|
timeout: 5e3,
|
|
411
621
|
stdio: "ignore"
|
|
@@ -655,12 +865,6 @@ function spawnSession(config, session) {
|
|
|
655
865
|
session.restartCount++;
|
|
656
866
|
}
|
|
657
867
|
}
|
|
658
|
-
function isLoginPickerVisible(screen) {
|
|
659
|
-
return screen.includes("Select login method") || screen.includes("Claude account with subscription") && screen.includes("Anthropic Console account");
|
|
660
|
-
}
|
|
661
|
-
function isResumeModeDialogVisible(screen) {
|
|
662
|
-
return screen.includes("Resume from summary") && screen.includes("Don't ask me again");
|
|
663
|
-
}
|
|
664
868
|
function hasMcpChildren(tmuxSession) {
|
|
665
869
|
try {
|
|
666
870
|
const claudePidOut = execSync(
|
|
@@ -710,40 +914,10 @@ async function acceptDialogs(tmuxSession, codeName, log, primaryModel = null, se
|
|
|
710
914
|
continue;
|
|
711
915
|
}
|
|
712
916
|
dialogIterations++;
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
}
|
|
718
|
-
if (screen.includes("Yes, I trust this folder")) {
|
|
719
|
-
execSync(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: "ignore" });
|
|
720
|
-
log(`[persistent-session] Auto-accepted workspace trust for '${codeName}'`);
|
|
721
|
-
continue;
|
|
722
|
-
}
|
|
723
|
-
if (isResumeModeDialogVisible(screen)) {
|
|
724
|
-
execFileSync2("tmux", ["send-keys", "-t", tmuxSession, "3"], { stdio: "ignore" });
|
|
725
|
-
await new Promise((r) => setTimeout(r, 300));
|
|
726
|
-
execFileSync2("tmux", ["send-keys", "-t", tmuxSession, "Enter"], { stdio: "ignore" });
|
|
727
|
-
log(
|
|
728
|
-
`[persistent-session] Auto-dismissed resume-mode dialog for '${codeName}' (picked 'Don't ask me again')`
|
|
729
|
-
);
|
|
730
|
-
continue;
|
|
731
|
-
}
|
|
732
|
-
if (screen.includes("I am using this for local development")) {
|
|
733
|
-
execSync(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: "ignore" });
|
|
734
|
-
log(`[persistent-session] Auto-accepted dev channels for '${codeName}'`);
|
|
735
|
-
continue;
|
|
736
|
-
}
|
|
737
|
-
if (screen.includes("Enter to confirm") && screen.includes("MCP")) {
|
|
738
|
-
execSync(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: "ignore" });
|
|
739
|
-
log(`[persistent-session] Auto-accepted MCP servers for '${codeName}'`);
|
|
740
|
-
continue;
|
|
741
|
-
}
|
|
742
|
-
if (screen.includes("Yes, I accept") && screen.includes("Bypass Permissions")) {
|
|
743
|
-
execSync(`tmux send-keys -t ${tmuxSession} 2`, { stdio: "ignore" });
|
|
744
|
-
await new Promise((r) => setTimeout(r, 300));
|
|
745
|
-
execSync(`tmux send-keys -t ${tmuxSession} Enter`, { stdio: "ignore" });
|
|
746
|
-
log(`[persistent-session] Auto-accepted bypass permissions for '${codeName}'`);
|
|
917
|
+
const dialogAction = sweepDialogs(screen);
|
|
918
|
+
if (dialogAction) {
|
|
919
|
+
await sendDialogKeys(tmuxSession, dialogAction);
|
|
920
|
+
log(`[persistent-session] ${dialogAction.logMessage} for '${codeName}'`);
|
|
747
921
|
continue;
|
|
748
922
|
}
|
|
749
923
|
if (screen.includes("\u276F") && !screen.includes("Enter to confirm")) {
|
|
@@ -794,7 +968,7 @@ async function waitForPromptReady(tmuxSession) {
|
|
|
794
968
|
const deadline = Date.now() + 1e4;
|
|
795
969
|
while (Date.now() < deadline) {
|
|
796
970
|
try {
|
|
797
|
-
const screen =
|
|
971
|
+
const screen = execFileSync3(
|
|
798
972
|
"tmux",
|
|
799
973
|
["capture-pane", "-t", tmuxSession, "-p"],
|
|
800
974
|
{ encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
@@ -813,11 +987,11 @@ function sleepBlockingMs(ms) {
|
|
|
813
987
|
}
|
|
814
988
|
function defaultArmSender(tmuxSession, command) {
|
|
815
989
|
try {
|
|
816
|
-
|
|
990
|
+
execFileSync3("tmux", ["send-keys", "-t", tmuxSession, "-l", command], {
|
|
817
991
|
stdio: ["ignore", "ignore", "pipe"]
|
|
818
992
|
});
|
|
819
993
|
sleepBlockingMs(SEND_KEYS_ENTER_DELAY_MS);
|
|
820
|
-
|
|
994
|
+
execFileSync3("tmux", ["send-keys", "-t", tmuxSession, "Enter"], {
|
|
821
995
|
stdio: ["ignore", "ignore", "pipe"]
|
|
822
996
|
});
|
|
823
997
|
return true;
|
|
@@ -826,6 +1000,50 @@ function defaultArmSender(tmuxSession, command) {
|
|
|
826
1000
|
}
|
|
827
1001
|
}
|
|
828
1002
|
var armSender = defaultArmSender;
|
|
1003
|
+
function defaultPaneCapture(tmuxSession) {
|
|
1004
|
+
try {
|
|
1005
|
+
return execFileSync3("tmux", ["capture-pane", "-t", tmuxSession, "-p"], {
|
|
1006
|
+
encoding: "utf-8",
|
|
1007
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1008
|
+
timeout: 2e3
|
|
1009
|
+
});
|
|
1010
|
+
} catch {
|
|
1011
|
+
return null;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
var paneCapture = defaultPaneCapture;
|
|
1015
|
+
var defaultHygieneKeySender = async (tmuxSession, keys, interKeyDelayMs) => {
|
|
1016
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1017
|
+
if (i > 0 && interKeyDelayMs > 0) {
|
|
1018
|
+
await new Promise((r) => setTimeout(r, interKeyDelayMs));
|
|
1019
|
+
}
|
|
1020
|
+
execFileSync3("tmux", ["send-keys", "-t", tmuxSession, keys[i]], {
|
|
1021
|
+
stdio: "ignore"
|
|
1022
|
+
});
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
var hygieneKeySender = defaultHygieneKeySender;
|
|
1026
|
+
async function preSendPaneHygiene(tmuxSession, codeName, log) {
|
|
1027
|
+
try {
|
|
1028
|
+
let screen = paneCapture(tmuxSession);
|
|
1029
|
+
if (screen === null) return;
|
|
1030
|
+
const action = sweepDialogs(screen);
|
|
1031
|
+
if (action) {
|
|
1032
|
+
await hygieneKeySender(tmuxSession, action.keys, action.interKeyDelayMs);
|
|
1033
|
+
log(`[inject] ${action.logMessage} for '${codeName}' before injection`);
|
|
1034
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
1035
|
+
screen = paneCapture(tmuxSession) ?? "";
|
|
1036
|
+
}
|
|
1037
|
+
const orphan = extractInputBoxText(screen);
|
|
1038
|
+
if (orphan) {
|
|
1039
|
+
log(
|
|
1040
|
+
`[inject] clearing orphaned input for '${codeName}' before injection (input_hash=${simpleTextHash(orphan)}, len=${orphan.length})`
|
|
1041
|
+
);
|
|
1042
|
+
await hygieneKeySender(tmuxSession, ["C-u"], 0);
|
|
1043
|
+
}
|
|
1044
|
+
} catch {
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
829
1047
|
function sendToAgent(tmuxSession, command) {
|
|
830
1048
|
return armSender(tmuxSession, command);
|
|
831
1049
|
}
|
|
@@ -848,6 +1066,17 @@ var _internals = {
|
|
|
848
1066
|
__setArmSender(fn) {
|
|
849
1067
|
armSender = fn ?? defaultArmSender;
|
|
850
1068
|
},
|
|
1069
|
+
// ENG-6017 test seam: swap the pane capture used by the inject-time
|
|
1070
|
+
// hygiene so unit tests can simulate dialog overlays / orphaned input
|
|
1071
|
+
// without a tmux server. null restores the real capture.
|
|
1072
|
+
__setPaneCapture(fn) {
|
|
1073
|
+
paneCapture = fn ?? defaultPaneCapture;
|
|
1074
|
+
},
|
|
1075
|
+
// ENG-6017 test seam: swap the hygiene key sender (dialog dismissal +
|
|
1076
|
+
// C-u clear) so unit tests can assert keystrokes without tmux.
|
|
1077
|
+
__setHygieneKeySender(fn) {
|
|
1078
|
+
hygieneKeySender = fn ?? defaultHygieneKeySender;
|
|
1079
|
+
},
|
|
851
1080
|
// ENG-5758 test seam: swap the acpx session probe so unit tests can
|
|
852
1081
|
// simulate "session present" / "no session" without spawning acpx.
|
|
853
1082
|
__setAcpxSessionProbe(fn) {
|
|
@@ -922,6 +1151,7 @@ async function injectMessageWithStatus(codeName, type, content, meta, log) {
|
|
|
922
1151
|
_log(`[inject] acpx binary not found \u2014 falling back to tmux send-keys`);
|
|
923
1152
|
}
|
|
924
1153
|
const singleLineText = text.replace(/\s*\n+\s*/g, " ").trim();
|
|
1154
|
+
await preSendPaneHygiene(`agt-${codeName}`, codeName, _log);
|
|
925
1155
|
const sent = sendToAgent(`agt-${codeName}`, singleLineText);
|
|
926
1156
|
if (sent) {
|
|
927
1157
|
_log(`[inject] tmux send-keys sent for '${codeName}' \u2014 unverified (delivered=false, fallbackUsed=true)`);
|
|
@@ -942,7 +1172,7 @@ function stopPersistentSession(codeName, log) {
|
|
|
942
1172
|
try {
|
|
943
1173
|
const acpx = getAcpxBin();
|
|
944
1174
|
if (acpx) {
|
|
945
|
-
|
|
1175
|
+
execFileSync3(acpx, ["claude", "sessions", "close", `agt-${codeName}`], {
|
|
946
1176
|
cwd: getProjectDir(codeName),
|
|
947
1177
|
timeout: 5e3,
|
|
948
1178
|
stdio: "ignore"
|
|
@@ -1019,7 +1249,7 @@ function isSessionHealthy(codeName) {
|
|
|
1019
1249
|
if (!claudeAlive) {
|
|
1020
1250
|
const paneTail = readPaneLogTail(codeName);
|
|
1021
1251
|
try {
|
|
1022
|
-
|
|
1252
|
+
execFileSync3("tmux", ["kill-session", "-t", tmuxSession], { stdio: "ignore" });
|
|
1023
1253
|
} catch {
|
|
1024
1254
|
}
|
|
1025
1255
|
session.status = "crashed";
|
|
@@ -1059,13 +1289,13 @@ function collectDiagnostics(codeNames) {
|
|
|
1059
1289
|
let launchArgs = null;
|
|
1060
1290
|
let channelStatus = null;
|
|
1061
1291
|
try {
|
|
1062
|
-
|
|
1292
|
+
execFileSync3("tmux", ["has-session", "-t", tmuxSession], { stdio: "ignore" });
|
|
1063
1293
|
tmuxAlive = true;
|
|
1064
1294
|
} catch {
|
|
1065
1295
|
}
|
|
1066
1296
|
if (tmuxAlive) {
|
|
1067
1297
|
try {
|
|
1068
|
-
screenCapture =
|
|
1298
|
+
screenCapture = execFileSync3("tmux", ["capture-pane", "-t", tmuxSession, "-p", "-S", "-30"], {
|
|
1069
1299
|
encoding: "utf-8",
|
|
1070
1300
|
timeout: 3e3
|
|
1071
1301
|
}).trim();
|
|
@@ -1073,7 +1303,7 @@ function collectDiagnostics(codeNames) {
|
|
|
1073
1303
|
}
|
|
1074
1304
|
}
|
|
1075
1305
|
try {
|
|
1076
|
-
const psOutput =
|
|
1306
|
+
const psOutput = execFileSync3("ps", ["aux"], { encoding: "utf-8", timeout: 3e3 });
|
|
1077
1307
|
const line = psOutput.split("\n").find((l) => l.includes(`agt-${codeName}`) && !l.includes("grep"));
|
|
1078
1308
|
if (line) {
|
|
1079
1309
|
const match = line.match(/claude\s+.*/);
|
|
@@ -1187,6 +1417,7 @@ export {
|
|
|
1187
1417
|
isAgentIdle,
|
|
1188
1418
|
isStaleForToday,
|
|
1189
1419
|
peekCurrentSession,
|
|
1420
|
+
checkChannelInputs,
|
|
1190
1421
|
resolveClaudeBinary,
|
|
1191
1422
|
writePersistentClaudeWrapper,
|
|
1192
1423
|
paneLogPath,
|
|
@@ -1210,4 +1441,4 @@ export {
|
|
|
1210
1441
|
stopAllSessionsAndWait,
|
|
1211
1442
|
getProjectDir
|
|
1212
1443
|
};
|
|
1213
|
-
//# sourceMappingURL=chunk-
|
|
1444
|
+
//# sourceMappingURL=chunk-VTAXNSGS.js.map
|