@integrity-labs/agt-cli 0.28.1170 → 0.28.1171
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
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
success,
|
|
41
41
|
table,
|
|
42
42
|
warn
|
|
43
|
-
} from "../chunk-
|
|
43
|
+
} from "../chunk-TJ4MVWNH.js";
|
|
44
44
|
import {
|
|
45
45
|
getProjectDir,
|
|
46
46
|
isSessionResumeDisabled,
|
|
@@ -5513,7 +5513,7 @@ import { execFileSync, execSync } from "child_process";
|
|
|
5513
5513
|
import { existsSync as existsSync11, realpathSync as realpathSync2 } from "fs";
|
|
5514
5514
|
import chalk18 from "chalk";
|
|
5515
5515
|
import ora16 from "ora";
|
|
5516
|
-
var cliVersion = true ? "0.28.
|
|
5516
|
+
var cliVersion = true ? "0.28.1171" : "dev";
|
|
5517
5517
|
async function fetchLatestVersion() {
|
|
5518
5518
|
const host2 = getHost();
|
|
5519
5519
|
if (!host2) return null;
|
|
@@ -6773,7 +6773,7 @@ function handleError(err) {
|
|
|
6773
6773
|
}
|
|
6774
6774
|
|
|
6775
6775
|
// src/bin/agt.ts
|
|
6776
|
-
var cliVersion2 = true ? "0.28.
|
|
6776
|
+
var cliVersion2 = true ? "0.28.1171" : "dev";
|
|
6777
6777
|
var program = new Command();
|
|
6778
6778
|
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");
|
|
6779
6779
|
program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -8078,7 +8078,7 @@ function exchangeFailureKind(err) {
|
|
|
8078
8078
|
}
|
|
8079
8079
|
|
|
8080
8080
|
// src/lib/api-client.ts
|
|
8081
|
-
var agtCliVersion = true ? "0.28.
|
|
8081
|
+
var agtCliVersion = true ? "0.28.1171" : "dev";
|
|
8082
8082
|
var lastConfigHash = null;
|
|
8083
8083
|
function setConfigHash(hash) {
|
|
8084
8084
|
lastConfigHash = hash && hash.length > 0 ? hash : null;
|
|
@@ -13235,4 +13235,4 @@ export {
|
|
|
13235
13235
|
managerInstallSystemUnitCommand,
|
|
13236
13236
|
managerUninstallSystemUnitCommand
|
|
13237
13237
|
};
|
|
13238
|
-
//# sourceMappingURL=chunk-
|
|
13238
|
+
//# sourceMappingURL=chunk-TJ4MVWNH.js.map
|
|
@@ -77,7 +77,7 @@ import {
|
|
|
77
77
|
setConfigHash,
|
|
78
78
|
shellGuard,
|
|
79
79
|
tripClass
|
|
80
|
-
} from "../chunk-
|
|
80
|
+
} from "../chunk-TJ4MVWNH.js";
|
|
81
81
|
import {
|
|
82
82
|
CLAUDE_CODE_SECURITY_FLOOR,
|
|
83
83
|
SELF_UPDATE_TIMEOUTS,
|
|
@@ -970,7 +970,9 @@ function claudeCodeUpgradeThrottled() {
|
|
|
970
970
|
|
|
971
971
|
// src/lib/claude-pair-loop.ts
|
|
972
972
|
var PAIR_LOOP_ACTIVE_INTERVAL_MS = 2e3;
|
|
973
|
-
var PAIR_LOOP_IDLE_INTERVAL_MS =
|
|
973
|
+
var PAIR_LOOP_IDLE_INTERVAL_MS = 3e4;
|
|
974
|
+
var PAIR_LOOP_FIRST_TICK_MS = 1e4;
|
|
975
|
+
var PAIR_LOOP_FAILURE_BASE_MS = 1e4;
|
|
974
976
|
var PAIR_LOOP_MAX_BACKOFF_MS = 12e4;
|
|
975
977
|
var PAIR_LOOP_ARMED_MAX_MS = 15 * 6e4;
|
|
976
978
|
function pairLoopArmed(opts) {
|
|
@@ -993,7 +995,8 @@ function pairLoopArmed(opts) {
|
|
|
993
995
|
function nextPairLoopDelayMs(armed, consecutiveFailures) {
|
|
994
996
|
if (consecutiveFailures > 0) {
|
|
995
997
|
const exp = Math.min(consecutiveFailures - 1, 16);
|
|
996
|
-
|
|
998
|
+
const backoff = Math.min(PAIR_LOOP_FAILURE_BASE_MS * 2 ** exp, PAIR_LOOP_MAX_BACKOFF_MS);
|
|
999
|
+
return armed ? backoff : Math.max(backoff, PAIR_LOOP_IDLE_INTERVAL_MS);
|
|
997
1000
|
}
|
|
998
1001
|
return armed ? PAIR_LOOP_ACTIVE_INTERVAL_MS : PAIR_LOOP_IDLE_INTERVAL_MS;
|
|
999
1002
|
}
|
|
@@ -1013,11 +1016,11 @@ var ClaudePairLoop = class {
|
|
|
1013
1016
|
inFlightTick = null;
|
|
1014
1017
|
setTimer;
|
|
1015
1018
|
clearTimer;
|
|
1016
|
-
/** Arm the loop. The first tick runs after
|
|
1019
|
+
/** Arm the loop. The first tick runs after {@link PAIR_LOOP_FIRST_TICK_MS}. Idempotent. */
|
|
1017
1020
|
start() {
|
|
1018
1021
|
if (this.started) return;
|
|
1019
1022
|
this.started = true;
|
|
1020
|
-
this.schedule(
|
|
1023
|
+
this.schedule(PAIR_LOOP_FIRST_TICK_MS);
|
|
1021
1024
|
}
|
|
1022
1025
|
/**
|
|
1023
1026
|
* Disarm the loop. No new tick starts, and a callback from this generation
|
|
@@ -7452,6 +7455,21 @@ function createTickBoardFetcher(fetchBoard) {
|
|
|
7452
7455
|
return inflight;
|
|
7453
7456
|
};
|
|
7454
7457
|
}
|
|
7458
|
+
async function fetchBoardThroughGate(opts) {
|
|
7459
|
+
const now = opts.now ?? Date.now;
|
|
7460
|
+
const token = opts.gate.beginFetch(opts.key);
|
|
7461
|
+
if (!opts.gate.shouldFetch(opts.key, now())) {
|
|
7462
|
+
const held = opts.held();
|
|
7463
|
+
if (held !== void 0) {
|
|
7464
|
+
opts.onDecision?.("gated");
|
|
7465
|
+
return held;
|
|
7466
|
+
}
|
|
7467
|
+
}
|
|
7468
|
+
const rows = await opts.fetch();
|
|
7469
|
+
opts.gate.markFetched(opts.key, token, now());
|
|
7470
|
+
opts.onDecision?.("fetched");
|
|
7471
|
+
return rows;
|
|
7472
|
+
}
|
|
7455
7473
|
|
|
7456
7474
|
// src/lib/kanban-board-token.ts
|
|
7457
7475
|
var BoardTokenCache = class {
|
|
@@ -7510,6 +7528,20 @@ var BoardTokenCache = class {
|
|
|
7510
7528
|
}
|
|
7511
7529
|
return rows;
|
|
7512
7530
|
}
|
|
7531
|
+
/**
|
|
7532
|
+
* ENG-11720: the raw rows of the last board a successful request returned, or
|
|
7533
|
+
* undefined when none is held. Served by the `/host/my-kanban` fetch gate
|
|
7534
|
+
* while it is closed. Returns the held array itself: the one caller re-maps
|
|
7535
|
+
* it through `sanitizeBoardItem` on every serve, which is what keeps the
|
|
7536
|
+
* consumers from aliasing it (see the header).
|
|
7537
|
+
*
|
|
7538
|
+
* Counts nothing. The stats above describe what the conditional REQUEST did,
|
|
7539
|
+
* and a gated pass made no request — counting it as `unchanged` would report
|
|
7540
|
+
* a server-confirmed hit that never happened.
|
|
7541
|
+
*/
|
|
7542
|
+
held(agentId) {
|
|
7543
|
+
return this.entries.get(agentId)?.rows;
|
|
7544
|
+
}
|
|
7513
7545
|
/**
|
|
7514
7546
|
* Drop an agent's board. Teardown must call this: a board left behind is
|
|
7515
7547
|
* served to the agent if it is later RE-ADDED, which is exactly when its work
|
|
@@ -7583,6 +7615,13 @@ function createFetchGate(ttlMs) {
|
|
|
7583
7615
|
}
|
|
7584
7616
|
};
|
|
7585
7617
|
}
|
|
7618
|
+
async function runIfDue(gate, key, fn, now = Date.now) {
|
|
7619
|
+
const token = gate.beginFetch(key);
|
|
7620
|
+
if (!gate.shouldFetch(key, now())) return { ran: false };
|
|
7621
|
+
const value = await fn();
|
|
7622
|
+
gate.markFetched(key, token, now());
|
|
7623
|
+
return { ran: true, value };
|
|
7624
|
+
}
|
|
7586
7625
|
function forceGates(gates, agentId) {
|
|
7587
7626
|
for (const gate of gates) {
|
|
7588
7627
|
if (agentId === void 0) gate.forceAll();
|
|
@@ -13898,7 +13937,15 @@ function recordLatency(ms) {
|
|
|
13898
13937
|
}
|
|
13899
13938
|
}
|
|
13900
13939
|
function startRealtimeKanban(config2) {
|
|
13901
|
-
const { agentIds, onTodayItem, onCompletion, log: log2 } = config2;
|
|
13940
|
+
const { agentIds, onTodayItem, onCompletion, onBoardChanged, log: log2 } = config2;
|
|
13941
|
+
const boardChanged = (agentId) => {
|
|
13942
|
+
if (!onBoardChanged || !agentId) return;
|
|
13943
|
+
try {
|
|
13944
|
+
onBoardChanged(agentId);
|
|
13945
|
+
} catch (err) {
|
|
13946
|
+
log2(`[realtime] Kanban board-change handler error: ${err.message}`);
|
|
13947
|
+
}
|
|
13948
|
+
};
|
|
13902
13949
|
if (agentIds.length === 0) return;
|
|
13903
13950
|
const sb = ensureClient(config2);
|
|
13904
13951
|
const filterStr = agentIds.length === 1 ? `agent_id=eq.${agentIds[0]}` : `agent_id=in.(${agentIds.join(",")})`;
|
|
@@ -13909,6 +13956,7 @@ function startRealtimeKanban(config2) {
|
|
|
13909
13956
|
filter: filterStr
|
|
13910
13957
|
}, (payload) => {
|
|
13911
13958
|
const item = payload.new;
|
|
13959
|
+
boardChanged(item?.agent_id);
|
|
13912
13960
|
if (item.status === "todo") {
|
|
13913
13961
|
log2(`[realtime] New kanban item in 'todo': item_id=${item.id} agent=${item.agent_id}`);
|
|
13914
13962
|
onTodayItem(item);
|
|
@@ -13921,6 +13969,7 @@ function startRealtimeKanban(config2) {
|
|
|
13921
13969
|
}, (payload) => {
|
|
13922
13970
|
const item = payload.new;
|
|
13923
13971
|
const old = payload.old;
|
|
13972
|
+
boardChanged(item?.agent_id);
|
|
13924
13973
|
if (item.status === "todo" && old.status !== "todo") {
|
|
13925
13974
|
log2(`[realtime] Kanban item moved to 'todo': item_id=${item.id} agent=${item.agent_id}`);
|
|
13926
13975
|
onTodayItem(item);
|
|
@@ -15830,6 +15879,7 @@ function clearAgentCaches(agentId, codeName) {
|
|
|
15830
15879
|
pendingRecoveryCost.delete(codeName);
|
|
15831
15880
|
lastRefreshPayload.delete(agentId);
|
|
15832
15881
|
boardTokenCache.forget(agentId);
|
|
15882
|
+
boardFetchGate.forget(agentId);
|
|
15833
15883
|
refreshFetchGate.forget(agentId);
|
|
15834
15884
|
memoriesFetchGate.forget(agentId);
|
|
15835
15885
|
secretsFetchGate.forget(agentId);
|
|
@@ -15878,7 +15928,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
15878
15928
|
var lastVersionCheckAt = 0;
|
|
15879
15929
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
15880
15930
|
var lastResponsivenessProbeAt = 0;
|
|
15881
|
-
var agtCliVersion = true ? "0.28.
|
|
15931
|
+
var agtCliVersion = true ? "0.28.1171" : "dev";
|
|
15882
15932
|
function resolveBrewPath(execFileSync3) {
|
|
15883
15933
|
try {
|
|
15884
15934
|
const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -17627,6 +17677,11 @@ var integrationsFetchGate = createFetchGate(DESIRED_STATE_FETCH_TTL_MS);
|
|
|
17627
17677
|
var lastIntegrationsPayload = /* @__PURE__ */ new Map();
|
|
17628
17678
|
var quarantinedFetchGate = createFetchGate(DESIRED_STATE_FETCH_TTL_MS);
|
|
17629
17679
|
var lastQuarantinedPayload = /* @__PURE__ */ new Map();
|
|
17680
|
+
var MY_KANBAN_FETCH_TTL_MS = 3e4;
|
|
17681
|
+
var boardFetchGate = createFetchGate(MY_KANBAN_FETCH_TTL_MS);
|
|
17682
|
+
var RECURRING_SPAWN_INTERVAL_MS = 6e4;
|
|
17683
|
+
var RECURRING_SPAWN_GATE_KEY = "host";
|
|
17684
|
+
var recurringSpawnGate = createFetchGate(RECURRING_SPAWN_INTERVAL_MS);
|
|
17630
17685
|
function forceIntegrationsFetch(agentId) {
|
|
17631
17686
|
integrationsFetchGate.forceNext(agentId);
|
|
17632
17687
|
quarantinedFetchGate.forceNext(agentId);
|
|
@@ -17639,13 +17694,20 @@ var pollCycleQuarantinedFetches = 0;
|
|
|
17639
17694
|
var pollCycleQuarantinedSkips = 0;
|
|
17640
17695
|
var pollCycleMemoriesUnchanged = 0;
|
|
17641
17696
|
var pollCycleMemoriesFull = 0;
|
|
17697
|
+
var pollCycleBoardFetched = 0;
|
|
17698
|
+
var pollCycleBoardGated = 0;
|
|
17642
17699
|
var DESIRED_STATE_FETCH_GATES = [
|
|
17643
17700
|
refreshFetchGate,
|
|
17644
17701
|
memoriesFetchGate,
|
|
17645
17702
|
secretsFetchGate,
|
|
17646
17703
|
defaultSchedulesFetchGate,
|
|
17647
17704
|
integrationsFetchGate,
|
|
17648
|
-
quarantinedFetchGate
|
|
17705
|
+
quarantinedFetchGate,
|
|
17706
|
+
// ENG-11720. None of the lanes reaching here changes the board (the board
|
|
17707
|
+
// has its own push, `onBoardChanged`), so this entry is the maintenance rule
|
|
17708
|
+
// above applied, not a freshness requirement. Cost: one board round trip for
|
|
17709
|
+
// the pushed agent, which is the pre-gate every-pass behaviour at worst.
|
|
17710
|
+
boardFetchGate
|
|
17649
17711
|
];
|
|
17650
17712
|
function forceRefreshFetch(agentId) {
|
|
17651
17713
|
forceGates(DESIRED_STATE_FETCH_GATES, agentId);
|
|
@@ -19062,6 +19124,8 @@ async function pollCycleInner() {
|
|
|
19062
19124
|
pollCycleQuarantinedSkips = 0;
|
|
19063
19125
|
pollCycleMemoriesUnchanged = 0;
|
|
19064
19126
|
pollCycleMemoriesFull = 0;
|
|
19127
|
+
pollCycleBoardFetched = 0;
|
|
19128
|
+
pollCycleBoardGated = 0;
|
|
19065
19129
|
boardTokenCache.resetStats();
|
|
19066
19130
|
for (const agent of processOrder) {
|
|
19067
19131
|
if (restartInFlight.has(agent.agent_id)) {
|
|
@@ -19103,7 +19167,7 @@ async function pollCycleInner() {
|
|
|
19103
19167
|
}
|
|
19104
19168
|
const boardStats = boardTokenCache.stats();
|
|
19105
19169
|
log(
|
|
19106
|
-
`[poll-cycle] agents=${processOrder.length} refresh_fetched=${pollCycleFetches} refresh_skipped=${pollCycleFetchSkips} memories_unchanged=${pollCycleMemoriesUnchanged} memories_full=${pollCycleMemoriesFull} board_unchanged=${boardStats.unchanged} board_full=${boardStats.full} board_refetch=${boardStats.refetch} integrations_fetched=${pollCycleIntegrationsFetches} integrations_skipped=${pollCycleIntegrationsSkips} quarantined_fetched=${pollCycleQuarantinedFetches} quarantined_skipped=${pollCycleQuarantinedSkips} duration_ms=${Date.now() - cycleStartedAt}`
|
|
19170
|
+
`[poll-cycle] agents=${processOrder.length} refresh_fetched=${pollCycleFetches} refresh_skipped=${pollCycleFetchSkips} memories_unchanged=${pollCycleMemoriesUnchanged} memories_full=${pollCycleMemoriesFull} board_unchanged=${boardStats.unchanged} board_full=${boardStats.full} board_refetch=${boardStats.refetch} board_fetched=${pollCycleBoardFetched} board_gated=${pollCycleBoardGated} integrations_fetched=${pollCycleIntegrationsFetches} integrations_skipped=${pollCycleIntegrationsSkips} quarantined_fetched=${pollCycleQuarantinedFetches} quarantined_skipped=${pollCycleQuarantinedSkips} duration_ms=${Date.now() - cycleStartedAt}`
|
|
19107
19171
|
);
|
|
19108
19172
|
void maybeReportActivityCache({ api, log });
|
|
19109
19173
|
const crossAgentPrune = managedPruneLedger.summarize();
|
|
@@ -19340,9 +19404,13 @@ async function pollCycleInner() {
|
|
|
19340
19404
|
ensureRealtimeKanbanStarted(agentStates);
|
|
19341
19405
|
ensureRealtimeIntegrationContextStarted(agentStates);
|
|
19342
19406
|
try {
|
|
19343
|
-
const
|
|
19344
|
-
|
|
19345
|
-
|
|
19407
|
+
const spawn = await runIfDue(
|
|
19408
|
+
recurringSpawnGate,
|
|
19409
|
+
RECURRING_SPAWN_GATE_KEY,
|
|
19410
|
+
() => api.post("/host/kanban/recurring/spawn")
|
|
19411
|
+
);
|
|
19412
|
+
if (spawn.ran && spawn.value.spawned > 0) {
|
|
19413
|
+
log(`Spawned ${spawn.value.spawned} recurring kanban item(s)`);
|
|
19346
19414
|
}
|
|
19347
19415
|
} catch {
|
|
19348
19416
|
}
|
|
@@ -21491,23 +21559,35 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
21491
21559
|
}
|
|
21492
21560
|
}
|
|
21493
21561
|
const fetchTickBoard = createTickBoardFetcher(async () => {
|
|
21494
|
-
const
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
21500
|
-
|
|
21501
|
-
|
|
21502
|
-
|
|
21503
|
-
|
|
21504
|
-
|
|
21562
|
+
const rawRows = await fetchBoardThroughGate({
|
|
21563
|
+
key: agent.agent_id,
|
|
21564
|
+
gate: boardFetchGate,
|
|
21565
|
+
held: () => boardTokenCache.held(agent.agent_id),
|
|
21566
|
+
onDecision: (decision) => {
|
|
21567
|
+
if (decision === "gated") pollCycleBoardGated += 1;
|
|
21568
|
+
else pollCycleBoardFetched += 1;
|
|
21569
|
+
},
|
|
21570
|
+
fetch: async () => {
|
|
21571
|
+
const knownToken = boardTokenCache.tokenFor(agent.agent_id);
|
|
21572
|
+
const post = (token) => api.post("/host/my-kanban", {
|
|
21573
|
+
agent_id: agent.agent_id,
|
|
21574
|
+
// ENG-9585: this is the ONLY caller that polls (every ~10s, per agent),
|
|
21575
|
+
// and it reads exactly `BoardItem`. `description` and `notes` are 57.8%
|
|
21576
|
+
// of the payload and are read here by nothing — but the `kanban_list` MCP
|
|
21577
|
+
// tool and `agt kanban` DO read them, so the route cannot simply drop
|
|
21578
|
+
// them. Asking for the lean shape is this caller saying what it needs;
|
|
21579
|
+
// every other caller keeps the full payload by default.
|
|
21580
|
+
detail: "board",
|
|
21581
|
+
...token ? { known_token: token } : {}
|
|
21582
|
+
});
|
|
21583
|
+
let rows = boardTokenCache.resolve(agent.agent_id, await post(knownToken));
|
|
21584
|
+
if (rows === null) {
|
|
21585
|
+
rows = boardTokenCache.resolve(agent.agent_id, await post(void 0)) ?? [];
|
|
21586
|
+
}
|
|
21587
|
+
return rows;
|
|
21588
|
+
}
|
|
21505
21589
|
});
|
|
21506
|
-
|
|
21507
|
-
if (rows === null) {
|
|
21508
|
-
rows = boardTokenCache.resolve(agent.agent_id, await post(void 0)) ?? [];
|
|
21509
|
-
}
|
|
21510
|
-
return rows.map(sanitizeBoardItem);
|
|
21590
|
+
return rawRows.map(sanitizeBoardItem);
|
|
21511
21591
|
});
|
|
21512
21592
|
let boardItems = [];
|
|
21513
21593
|
let boardItemsStale = false;
|
|
@@ -22110,6 +22190,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
|
|
|
22110
22190
|
reason: `Timed out \u2014 in progress for ${age} minutes with no update`
|
|
22111
22191
|
});
|
|
22112
22192
|
reapAction = reapResult.action ?? null;
|
|
22193
|
+
boardFetchGate.forceNext(agentId);
|
|
22113
22194
|
log(
|
|
22114
22195
|
`Reap result for item_id=${item.id}: updated=${reapResult.updated} action=${reapResult.action ?? reapResult.reason ?? "none"}`
|
|
22115
22196
|
);
|
|
@@ -23495,6 +23576,14 @@ function ensureRealtimeKanbanStarted(agentStates) {
|
|
|
23495
23576
|
supabaseAnonKey: exchange.supabaseAnonKey,
|
|
23496
23577
|
token: exchange.token,
|
|
23497
23578
|
agentIds: activeAgentIds,
|
|
23579
|
+
// ENG-11720: what makes the `/host/my-kanban` gate safe. Any change to one
|
|
23580
|
+
// of this agent's cards reopens it, so the next pass fetches — no early
|
|
23581
|
+
// poll, because a card change is not urgent enough to pull a whole cycle
|
|
23582
|
+
// forward, and forces are counters, so a burst of UPDATEs (embedding
|
|
23583
|
+
// writes, notes) still costs at most one fetch per pass.
|
|
23584
|
+
onBoardChanged: (agentId) => {
|
|
23585
|
+
boardFetchGate.forceNext(agentId);
|
|
23586
|
+
},
|
|
23498
23587
|
onTodayItem: (item) => {
|
|
23499
23588
|
if (item.source_type === "scheduled_task") return;
|
|
23500
23589
|
const agent = agentStates.find((a) => a.agentId === item.agent_id);
|