@integrity-labs/agt-cli 0.28.250 → 0.28.252
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
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
success,
|
|
39
39
|
table,
|
|
40
40
|
warn
|
|
41
|
-
} from "../chunk-
|
|
41
|
+
} from "../chunk-U2VQQ2UK.js";
|
|
42
42
|
import {
|
|
43
43
|
CHANNEL_REGISTRY,
|
|
44
44
|
DEFAULT_FRAMEWORK,
|
|
@@ -4826,7 +4826,7 @@ import { execFileSync, execSync } from "child_process";
|
|
|
4826
4826
|
import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
|
|
4827
4827
|
import chalk18 from "chalk";
|
|
4828
4828
|
import ora16 from "ora";
|
|
4829
|
-
var cliVersion = true ? "0.28.
|
|
4829
|
+
var cliVersion = true ? "0.28.252" : "dev";
|
|
4830
4830
|
async function fetchLatestVersion() {
|
|
4831
4831
|
const host2 = getHost();
|
|
4832
4832
|
if (!host2) return null;
|
|
@@ -5840,7 +5840,7 @@ function handleError(err) {
|
|
|
5840
5840
|
}
|
|
5841
5841
|
|
|
5842
5842
|
// src/bin/agt.ts
|
|
5843
|
-
var cliVersion2 = true ? "0.28.
|
|
5843
|
+
var cliVersion2 = true ? "0.28.252" : "dev";
|
|
5844
5844
|
var program = new Command();
|
|
5845
5845
|
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");
|
|
5846
5846
|
program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -5832,7 +5832,7 @@ function requireHost() {
|
|
|
5832
5832
|
}
|
|
5833
5833
|
|
|
5834
5834
|
// src/lib/api-client.ts
|
|
5835
|
-
var agtCliVersion = true ? "0.28.
|
|
5835
|
+
var agtCliVersion = true ? "0.28.252" : "dev";
|
|
5836
5836
|
var lastConfigHash = null;
|
|
5837
5837
|
function setConfigHash(hash) {
|
|
5838
5838
|
lastConfigHash = hash && hash.length > 0 ? hash : null;
|
|
@@ -8102,4 +8102,4 @@ export {
|
|
|
8102
8102
|
managerInstallSystemUnitCommand,
|
|
8103
8103
|
managerUninstallSystemUnitCommand
|
|
8104
8104
|
};
|
|
8105
|
-
//# sourceMappingURL=chunk-
|
|
8105
|
+
//# sourceMappingURL=chunk-U2VQQ2UK.js.map
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
requireHost,
|
|
38
38
|
safeWriteJsonAtomic,
|
|
39
39
|
setConfigHash
|
|
40
|
-
} from "../chunk-
|
|
40
|
+
} from "../chunk-U2VQQ2UK.js";
|
|
41
41
|
import {
|
|
42
42
|
getProjectDir as getProjectDir2,
|
|
43
43
|
getReadyTasks,
|
|
@@ -128,7 +128,7 @@ import {
|
|
|
128
128
|
} from "../chunk-XWVM4KPK.js";
|
|
129
129
|
|
|
130
130
|
// src/lib/manager-worker.ts
|
|
131
|
-
import { createHash as
|
|
131
|
+
import { createHash as createHash11 } from "crypto";
|
|
132
132
|
import { readFileSync as readFileSync14, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync8, rmSync as rmSync4, readdirSync as readdirSync5, statSync as statSync4, copyFileSync } from "fs";
|
|
133
133
|
import { execFileSync as syncExecFile } from "child_process";
|
|
134
134
|
import { join as join16, dirname as dirname5 } from "path";
|
|
@@ -318,6 +318,49 @@ function decideSenderPolicyRestart(input) {
|
|
|
318
318
|
return { restart: true, firstPoll: false, changed: true };
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
+
// src/lib/sender-policy-normalize.ts
|
|
322
|
+
import { createHash as createHash3 } from "crypto";
|
|
323
|
+
|
|
324
|
+
// src/lib/canonical-json.ts
|
|
325
|
+
function canonicalJson(value) {
|
|
326
|
+
return JSON.stringify(normalize(value));
|
|
327
|
+
}
|
|
328
|
+
function normalize(value) {
|
|
329
|
+
if (value === null || typeof value !== "object") return value;
|
|
330
|
+
if (Array.isArray(value)) return value.map(normalize);
|
|
331
|
+
const sorted = {};
|
|
332
|
+
const keys = Object.keys(value).sort();
|
|
333
|
+
for (const k of keys) {
|
|
334
|
+
sorted[k] = normalize(value[k]);
|
|
335
|
+
}
|
|
336
|
+
return sorted;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/lib/sender-policy-normalize.ts
|
|
340
|
+
var PRINCIPAL_ID_LIST_KEYS = [
|
|
341
|
+
"slack_user_ids",
|
|
342
|
+
"telegram_chat_ids",
|
|
343
|
+
"teams_aad_object_ids"
|
|
344
|
+
];
|
|
345
|
+
function normalizeSenderPolicyForHash(policy) {
|
|
346
|
+
if (policy === null || typeof policy !== "object") return policy;
|
|
347
|
+
const p = policy;
|
|
348
|
+
const tp = p.team_principals;
|
|
349
|
+
if (tp === null || typeof tp !== "object") return policy;
|
|
350
|
+
const src = tp;
|
|
351
|
+
const normalizedTeamPrincipals = { ...src };
|
|
352
|
+
for (const key of PRINCIPAL_ID_LIST_KEYS) {
|
|
353
|
+
const list = src[key];
|
|
354
|
+
if (Array.isArray(list)) {
|
|
355
|
+
normalizedTeamPrincipals[key] = [...list].sort();
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return { ...p, team_principals: normalizedTeamPrincipals };
|
|
359
|
+
}
|
|
360
|
+
function computeSenderPolicyRestartHash(policy) {
|
|
361
|
+
return createHash3("sha256").update(canonicalJson({ senderPolicy: normalizeSenderPolicyForHash(policy) })).digest("hex");
|
|
362
|
+
}
|
|
363
|
+
|
|
321
364
|
// src/lib/msteams-behaviour-restart.ts
|
|
322
365
|
function extractMsTeamsBehaviourSubset(config2) {
|
|
323
366
|
const adaptiveCardsEnabled = config2?.["adaptive_cards_enabled"] === true;
|
|
@@ -1405,7 +1448,7 @@ function isDirectChatMessageExpired(createdAt, nowMs, maxAgeMs) {
|
|
|
1405
1448
|
}
|
|
1406
1449
|
|
|
1407
1450
|
// ../../packages/core/dist/host-config/capture.js
|
|
1408
|
-
import { createHash as
|
|
1451
|
+
import { createHash as createHash4 } from "crypto";
|
|
1409
1452
|
var NON_SECRET_ENV_GATES = [
|
|
1410
1453
|
"AGT_MEMORY_EXTRACTION_ENABLED",
|
|
1411
1454
|
"AGT_CHANNEL_REPLAY_ENABLED",
|
|
@@ -2358,6 +2401,114 @@ function readRecentTurns(dir, nowMs) {
|
|
|
2358
2401
|
return turns;
|
|
2359
2402
|
}
|
|
2360
2403
|
|
|
2404
|
+
// src/lib/routine-candidate-extractor.ts
|
|
2405
|
+
var VALID_CADENCE_GUESSES = /* @__PURE__ */ new Set(["daily", "weekdays", "weekly", "unknown"]);
|
|
2406
|
+
var MAX_ASK_CHARS = 400;
|
|
2407
|
+
var MAX_INPUT_CHARS = 6e3;
|
|
2408
|
+
function buildUserAsksInput(turns) {
|
|
2409
|
+
const lines = [];
|
|
2410
|
+
let total = 0;
|
|
2411
|
+
for (const turn of turns) {
|
|
2412
|
+
if (turn.role !== "user") continue;
|
|
2413
|
+
const body = turn.text.length > MAX_ASK_CHARS ? `${turn.text.slice(0, MAX_ASK_CHARS)}\u2026` : turn.text;
|
|
2414
|
+
const line = `User: ${body}`;
|
|
2415
|
+
if (total + line.length > MAX_INPUT_CHARS) break;
|
|
2416
|
+
lines.push(line);
|
|
2417
|
+
total += line.length;
|
|
2418
|
+
}
|
|
2419
|
+
return lines.join("\n");
|
|
2420
|
+
}
|
|
2421
|
+
function buildRoutinePrompt(channel, userAsks) {
|
|
2422
|
+
return `You are looking for a DURABLE RECURRING ASK in the user's messages from one completed ${channel} conversation with an AI agent. A routine candidate is something the user asks for repeatedly or explicitly wants on a schedule ("every morning", "each Friday", "again" for the third time) - not a one-off task.
|
|
2423
|
+
|
|
2424
|
+
User messages (agent replies deliberately omitted):
|
|
2425
|
+
"""
|
|
2426
|
+
${userAsks}
|
|
2427
|
+
"""
|
|
2428
|
+
|
|
2429
|
+
Extract 0-2 routine candidates. For each:
|
|
2430
|
+
- description: the recurring ask, self-contained and generic (max 200 chars). No secrets, no personal data beyond what is needed to name the task.
|
|
2431
|
+
- cadence_guess: "daily", "weekdays", "weekly", or "unknown" if the messages imply repetition without a clear cadence
|
|
2432
|
+
- evidence_count: how many of the user messages above support this ask (integer >= 1)
|
|
2433
|
+
- confidence: 0.0-1.0 - how sure you are this is a genuine recurring responsibility
|
|
2434
|
+
|
|
2435
|
+
Most conversations contain NO routine candidate - return an empty array unless the recurrence signal is clear. Do NOT invent candidates.
|
|
2436
|
+
|
|
2437
|
+
Respond with ONLY a JSON array, no other text:
|
|
2438
|
+
[{"description":"...","cadence_guess":"daily","evidence_count":2,"confidence":0.7}]`;
|
|
2439
|
+
}
|
|
2440
|
+
function parseRoutineCandidates(raw) {
|
|
2441
|
+
const match = raw.match(/\[[\s\S]*\]/);
|
|
2442
|
+
if (!match) return null;
|
|
2443
|
+
let arr;
|
|
2444
|
+
try {
|
|
2445
|
+
arr = JSON.parse(match[0]);
|
|
2446
|
+
} catch {
|
|
2447
|
+
return null;
|
|
2448
|
+
}
|
|
2449
|
+
if (!Array.isArray(arr)) return null;
|
|
2450
|
+
const out = [];
|
|
2451
|
+
for (const entry of arr) {
|
|
2452
|
+
if (!entry || typeof entry !== "object") continue;
|
|
2453
|
+
const c = entry;
|
|
2454
|
+
const description = typeof c.description === "string" ? c.description.trim() : "";
|
|
2455
|
+
if (!description) continue;
|
|
2456
|
+
const confidence = typeof c.confidence === "number" && Number.isFinite(c.confidence) ? Math.max(0, Math.min(1, c.confidence)) : 0;
|
|
2457
|
+
if (confidence === 0) continue;
|
|
2458
|
+
const cadence = typeof c.cadence_guess === "string" && VALID_CADENCE_GUESSES.has(c.cadence_guess) ? c.cadence_guess : "unknown";
|
|
2459
|
+
const evidenceRaw = typeof c.evidence_count === "number" && Number.isFinite(c.evidence_count) ? Math.floor(c.evidence_count) : 1;
|
|
2460
|
+
out.push({
|
|
2461
|
+
// Bounded parse only - the FINAL 200-char truncation happens after
|
|
2462
|
+
// scrubbing (maybeEmitRoutineCandidates), because slicing first can
|
|
2463
|
+
// split a secret across the cut so the scrub regex no longer matches
|
|
2464
|
+
// and a fragment leaks onto the wire.
|
|
2465
|
+
description: description.slice(0, 500),
|
|
2466
|
+
cadence_guess: cadence,
|
|
2467
|
+
evidence_count: Math.max(1, Math.min(50, evidenceRaw)),
|
|
2468
|
+
confidence
|
|
2469
|
+
});
|
|
2470
|
+
}
|
|
2471
|
+
return out;
|
|
2472
|
+
}
|
|
2473
|
+
async function maybeEmitRoutineCandidates(args) {
|
|
2474
|
+
const { api: api2, backend, codeName, agentId, conversationId, channel, turns, log: log2 } = args;
|
|
2475
|
+
try {
|
|
2476
|
+
const userAsks = buildUserAsksInput(turns);
|
|
2477
|
+
if (!userAsks.trim()) return;
|
|
2478
|
+
let candidates;
|
|
2479
|
+
try {
|
|
2480
|
+
const out = await backend.run(buildRoutinePrompt(channel, userAsks));
|
|
2481
|
+
candidates = parseRoutineCandidates(out);
|
|
2482
|
+
} catch (err) {
|
|
2483
|
+
log2(`[routine-extract] ${codeName}: extraction failed: ${err.message}`);
|
|
2484
|
+
args.onModelCallError?.(err);
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
if (!candidates || candidates.length === 0) return;
|
|
2488
|
+
const scrubbed = candidates.map((c) => ({
|
|
2489
|
+
...c,
|
|
2490
|
+
description: scrubSensitive(c.description).slice(0, 200)
|
|
2491
|
+
}));
|
|
2492
|
+
try {
|
|
2493
|
+
const res = await api2.post(
|
|
2494
|
+
"/host/routines/candidates",
|
|
2495
|
+
{
|
|
2496
|
+
agent_id: agentId,
|
|
2497
|
+
conversation_id: conversationId,
|
|
2498
|
+
candidates: scrubbed
|
|
2499
|
+
}
|
|
2500
|
+
);
|
|
2501
|
+
log2(
|
|
2502
|
+
`[routine-extract] ${codeName}: ${conversationId.slice(0, 8)} \u2192 ${scrubbed.length} candidate(s)${res?.discarded ? " (discarded: feature off)" : ""}`
|
|
2503
|
+
);
|
|
2504
|
+
} catch (err) {
|
|
2505
|
+
log2(`[routine-extract] ${codeName}: report failed: ${err.message}`);
|
|
2506
|
+
}
|
|
2507
|
+
} catch (err) {
|
|
2508
|
+
log2(`[routine-extract] ${codeName}: unexpected error: ${err.message}`);
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2361
2512
|
// src/lib/memory-extractor.ts
|
|
2362
2513
|
var MIN_CHECK_INTERVAL_MS5 = 10 * 6e4;
|
|
2363
2514
|
var WINDOW_PAD_MS2 = 5 * 6e4;
|
|
@@ -2503,6 +2654,17 @@ async function maybeExtractMemories(args) {
|
|
|
2503
2654
|
} catch (err) {
|
|
2504
2655
|
log2(`[memory-extract] ${codeName}: report failed: ${err.message}`);
|
|
2505
2656
|
}
|
|
2657
|
+
await maybeEmitRoutineCandidates({
|
|
2658
|
+
api: api2,
|
|
2659
|
+
backend,
|
|
2660
|
+
codeName,
|
|
2661
|
+
agentId,
|
|
2662
|
+
conversationId: conv.conversation_id,
|
|
2663
|
+
channel: conv.channel,
|
|
2664
|
+
turns,
|
|
2665
|
+
log: log2,
|
|
2666
|
+
onModelCallError: args.onModelCallError
|
|
2667
|
+
});
|
|
2506
2668
|
}
|
|
2507
2669
|
}
|
|
2508
2670
|
async function reportSkip2(api2, agentId, conversationId, log2, codeName) {
|
|
@@ -2858,26 +3020,11 @@ function parseExpiresAt(raw) {
|
|
|
2858
3020
|
return null;
|
|
2859
3021
|
}
|
|
2860
3022
|
|
|
2861
|
-
// src/lib/canonical-json.ts
|
|
2862
|
-
function canonicalJson(value) {
|
|
2863
|
-
return JSON.stringify(normalize(value));
|
|
2864
|
-
}
|
|
2865
|
-
function normalize(value) {
|
|
2866
|
-
if (value === null || typeof value !== "object") return value;
|
|
2867
|
-
if (Array.isArray(value)) return value.map(normalize);
|
|
2868
|
-
const sorted = {};
|
|
2869
|
-
const keys = Object.keys(value).sort();
|
|
2870
|
-
for (const k of keys) {
|
|
2871
|
-
sorted[k] = normalize(value[k]);
|
|
2872
|
-
}
|
|
2873
|
-
return sorted;
|
|
2874
|
-
}
|
|
2875
|
-
|
|
2876
3023
|
// src/lib/channel-config-hash.ts
|
|
2877
|
-
import { createHash as
|
|
3024
|
+
import { createHash as createHash5 } from "crypto";
|
|
2878
3025
|
var CHANNEL_WRITE_VERSION = 9;
|
|
2879
3026
|
function computeChannelConfigHash(input) {
|
|
2880
|
-
return
|
|
3027
|
+
return createHash5("sha256").update(
|
|
2881
3028
|
canonicalJson({
|
|
2882
3029
|
writeVersion: CHANNEL_WRITE_VERSION,
|
|
2883
3030
|
cliVersion: input.cliVersion,
|
|
@@ -2885,7 +3032,9 @@ function computeChannelConfigHash(input) {
|
|
|
2885
3032
|
team: input.team,
|
|
2886
3033
|
peers: input.peers,
|
|
2887
3034
|
sessionMode: input.sessionMode ?? null,
|
|
2888
|
-
|
|
3035
|
+
// ENG-7435: value-blind on the team_principals id SETS so a reorder of
|
|
3036
|
+
// the same principals can't oscillate this hash into a false rewrite.
|
|
3037
|
+
senderPolicy: normalizeSenderPolicyForHash(input.senderPolicy)
|
|
2889
3038
|
})
|
|
2890
3039
|
).digest("hex");
|
|
2891
3040
|
}
|
|
@@ -3302,7 +3451,7 @@ function planGlobalSkillSync(globalSkills, prevIds, hashOf, knownHash) {
|
|
|
3302
3451
|
}
|
|
3303
3452
|
|
|
3304
3453
|
// src/lib/manager/runtime.ts
|
|
3305
|
-
import { createHash as
|
|
3454
|
+
import { createHash as createHash6 } from "crypto";
|
|
3306
3455
|
import { readFileSync as readFileSync11, appendFileSync, mkdirSync as mkdirSync4, chmodSync, existsSync as existsSync4 } from "fs";
|
|
3307
3456
|
import { join as join11, dirname as dirname4 } from "path";
|
|
3308
3457
|
import { homedir as homedir5 } from "os";
|
|
@@ -3351,7 +3500,7 @@ function log(msg) {
|
|
|
3351
3500
|
}
|
|
3352
3501
|
}
|
|
3353
3502
|
function sha256(content) {
|
|
3354
|
-
return
|
|
3503
|
+
return createHash6("sha256").update(content, "utf8").digest("hex");
|
|
3355
3504
|
}
|
|
3356
3505
|
function hashFile(filePath) {
|
|
3357
3506
|
try {
|
|
@@ -3815,7 +3964,7 @@ function formatBoardForPrompt(items, template) {
|
|
|
3815
3964
|
}
|
|
3816
3965
|
|
|
3817
3966
|
// src/lib/manager/kanban/notify.ts
|
|
3818
|
-
import { createHash as
|
|
3967
|
+
import { createHash as createHash7 } from "crypto";
|
|
3819
3968
|
async function enqueueKanbanNotice(opts) {
|
|
3820
3969
|
try {
|
|
3821
3970
|
const res = await api.post(
|
|
@@ -3830,7 +3979,7 @@ async function enqueueKanbanNotice(opts) {
|
|
|
3830
3979
|
return res.ok === true;
|
|
3831
3980
|
} catch (err) {
|
|
3832
3981
|
const errText = err instanceof Error ? err.message : String(err);
|
|
3833
|
-
const errId =
|
|
3982
|
+
const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
|
|
3834
3983
|
log(`[kanban] notice enqueue failed for agent_id=${opts.agentId} error_id=${errId}`);
|
|
3835
3984
|
return false;
|
|
3836
3985
|
}
|
|
@@ -4197,7 +4346,7 @@ function deriveScheduledTaskNotify(task) {
|
|
|
4197
4346
|
}
|
|
4198
4347
|
|
|
4199
4348
|
// src/lib/manager/scheduler/runs.ts
|
|
4200
|
-
import { createHash as
|
|
4349
|
+
import { createHash as createHash8 } from "crypto";
|
|
4201
4350
|
async function startRun(opts) {
|
|
4202
4351
|
try {
|
|
4203
4352
|
const res = await api.post(
|
|
@@ -4207,7 +4356,7 @@ async function startRun(opts) {
|
|
|
4207
4356
|
return { run_id: res.run_id ?? null, kanban_item_id: res.kanban_item_id ?? null };
|
|
4208
4357
|
} catch (err) {
|
|
4209
4358
|
const errText = err instanceof Error ? err.message : String(err);
|
|
4210
|
-
const errId =
|
|
4359
|
+
const errId = createHash8("sha256").update(errText).digest("hex").slice(0, 12);
|
|
4211
4360
|
log(`[runs] start failed for agent_id=${opts.agent_id} source_type=${opts.source_type} error_id=${errId}`);
|
|
4212
4361
|
return { run_id: null, kanban_item_id: null };
|
|
4213
4362
|
}
|
|
@@ -4224,7 +4373,7 @@ async function finishRun(runId, outcome, options = {}) {
|
|
|
4224
4373
|
});
|
|
4225
4374
|
} catch (err) {
|
|
4226
4375
|
const errText = err instanceof Error ? err.message : String(err);
|
|
4227
|
-
const errId =
|
|
4376
|
+
const errId = createHash8("sha256").update(errText).digest("hex").slice(0, 12);
|
|
4228
4377
|
log(`[runs] finish failed for run_id=${runId} outcome=${outcome} error_id=${errId}`);
|
|
4229
4378
|
}
|
|
4230
4379
|
}
|
|
@@ -4241,7 +4390,7 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
|
|
|
4241
4390
|
return rows.filter((r) => typeof r.output_text === "string" && r.output_text.length > 0).map((r) => ({ startedAt: r.started_at, output: r.output_text }));
|
|
4242
4391
|
} catch (err) {
|
|
4243
4392
|
const errText = err instanceof Error ? err.message : String(err);
|
|
4244
|
-
const errId =
|
|
4393
|
+
const errId = createHash8("sha256").update(errText).digest("hex").slice(0, 12);
|
|
4245
4394
|
log(`[runs] prior-runs lookup failed for task_id=${taskId} error_id=${errId}`);
|
|
4246
4395
|
return [];
|
|
4247
4396
|
}
|
|
@@ -4290,7 +4439,7 @@ function closeScheduledRunsForCode(codeName, outcome, reason) {
|
|
|
4290
4439
|
}
|
|
4291
4440
|
|
|
4292
4441
|
// src/lib/manager/scheduler/kanban-route.ts
|
|
4293
|
-
import { createHash as
|
|
4442
|
+
import { createHash as createHash9 } from "crypto";
|
|
4294
4443
|
|
|
4295
4444
|
// src/lib/delivery-schedule-link.ts
|
|
4296
4445
|
function envSuffixFor2(codeName) {
|
|
@@ -4722,24 +4871,24 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
|
|
|
4722
4871
|
const assertion = parseDeliverAssertion(rawOutput);
|
|
4723
4872
|
if (!assertion.deliver) {
|
|
4724
4873
|
const trimmed = (rawOutput ?? "").trim();
|
|
4725
|
-
const outputHash = trimmed.length === 0 ? "empty" :
|
|
4874
|
+
const outputHash = trimmed.length === 0 ? "empty" : createHash9("sha256").update(trimmed).digest("hex").slice(0, 12);
|
|
4726
4875
|
log(`[claude-scheduler] Suppressed by delivery_policy=conditional for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 ${assertion.vacuous ? "deliver marker had a vacuous reason" : "no deliver marker"}; output_len=${trimmed.length} output_hash=${outputHash}`);
|
|
4727
4876
|
if (delivery?.mode === "announce" && delivery.to) {
|
|
4728
4877
|
await reportDeliveryStatus(agentId, delivery.taskId, { status: "skipped", error_code: "SUPPRESSED_BY_POLICY" });
|
|
4729
4878
|
}
|
|
4730
4879
|
return { ok: true };
|
|
4731
4880
|
}
|
|
4732
|
-
const reasonHash =
|
|
4881
|
+
const reasonHash = createHash9("sha256").update(assertion.reason ?? "").digest("hex").slice(0, 12);
|
|
4733
4882
|
log(`[claude-scheduler] Delivering conditional run for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 agent asserted a concrete trigger (reason_len=${(assertion.reason ?? "").length} reason_hash=${reasonHash})`);
|
|
4734
4883
|
rawOutput = assertion.deliverable;
|
|
4735
4884
|
}
|
|
4736
4885
|
const classification = classifyOutput(rawOutput);
|
|
4737
4886
|
if (classification.action === "suppress") {
|
|
4738
4887
|
const trimmed = (rawOutput ?? "").trim();
|
|
4739
|
-
const outputHash = trimmed.length === 0 ? "empty" :
|
|
4888
|
+
const outputHash = trimmed.length === 0 ? "empty" : createHash9("sha256").update(trimmed).digest("hex").slice(0, 12);
|
|
4740
4889
|
log(`[claude-scheduler] Suppressing delivery for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 output_len=${trimmed.length} output_hash=${outputHash}`);
|
|
4741
4890
|
if (classification.suppressedNotes) {
|
|
4742
|
-
const notesHash =
|
|
4891
|
+
const notesHash = createHash9("sha256").update(classification.suppressedNotes).digest("hex").slice(0, 12);
|
|
4743
4892
|
log(`[claude-scheduler] Suppressed notes for '${codeName}' (task=${delivery?.taskId ?? "n/a"}) \u2014 notes_len=${classification.suppressedNotes.length} notes_hash=${notesHash}`);
|
|
4744
4893
|
}
|
|
4745
4894
|
if (delivery?.mode === "announce" && delivery.to) {
|
|
@@ -4805,7 +4954,7 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
|
|
|
4805
4954
|
}
|
|
4806
4955
|
|
|
4807
4956
|
// src/lib/manager/scheduler/execution.ts
|
|
4808
|
-
import { createHash as
|
|
4957
|
+
import { createHash as createHash10 } from "crypto";
|
|
4809
4958
|
import { homedir as homedir7 } from "os";
|
|
4810
4959
|
import { join as join14 } from "path";
|
|
4811
4960
|
function claudePidFilePath() {
|
|
@@ -4829,10 +4978,10 @@ function unregisterClaudeSpawn(pid) {
|
|
|
4829
4978
|
}
|
|
4830
4979
|
async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData) {
|
|
4831
4980
|
const codeName = agent.code_name;
|
|
4832
|
-
const stableTasksHash =
|
|
4833
|
-
const boardHash = boardItems.length > 0 ?
|
|
4981
|
+
const stableTasksHash = createHash10("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
|
|
4982
|
+
const boardHash = boardItems.length > 0 ? createHash10("sha256").update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable })))).digest("hex").slice(0, 16) : "empty";
|
|
4834
4983
|
const resolvedModels = resolveModelChain(refreshData);
|
|
4835
|
-
const modelsHash =
|
|
4984
|
+
const modelsHash = createHash10("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
|
|
4836
4985
|
const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
|
|
4837
4986
|
const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
4838
4987
|
if (combinedHash !== prevHash) {
|
|
@@ -6206,7 +6355,7 @@ var runningChannelSecretHashes = /* @__PURE__ */ new Map();
|
|
|
6206
6355
|
function projectMcpHash(_codeName, projectDir) {
|
|
6207
6356
|
try {
|
|
6208
6357
|
const raw = readFileSync14(join16(projectDir, ".mcp.json"), "utf-8");
|
|
6209
|
-
return
|
|
6358
|
+
return createHash11("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
|
|
6210
6359
|
} catch {
|
|
6211
6360
|
return null;
|
|
6212
6361
|
}
|
|
@@ -6520,7 +6669,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
6520
6669
|
var lastVersionCheckAt = 0;
|
|
6521
6670
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
6522
6671
|
var lastResponsivenessProbeAt = 0;
|
|
6523
|
-
var agtCliVersion = true ? "0.28.
|
|
6672
|
+
var agtCliVersion = true ? "0.28.252" : "dev";
|
|
6524
6673
|
function resolveBrewPath(execFileSync2) {
|
|
6525
6674
|
try {
|
|
6526
6675
|
const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -7498,7 +7647,7 @@ async function pollCycle() {
|
|
|
7498
7647
|
claudeAuth = await detectClaudeAuth();
|
|
7499
7648
|
} catch (err) {
|
|
7500
7649
|
const errText = err instanceof Error ? err.message : String(err);
|
|
7501
|
-
const errId =
|
|
7650
|
+
const errId = createHash11("sha256").update(errText).digest("hex").slice(0, 12);
|
|
7502
7651
|
log(`Claude auth detection failed (error_id=${errId})`);
|
|
7503
7652
|
}
|
|
7504
7653
|
const hostHasClaudeCode = state6.agents.some(
|
|
@@ -8825,7 +8974,7 @@ async function processAgent(agent, agentStates) {
|
|
|
8825
8974
|
if (channelConfigConverged) {
|
|
8826
8975
|
const hasSenderPolicyChannel = currentChannelIds.has("slack") || currentChannelIds.has("msteams");
|
|
8827
8976
|
const senderPolicyForRestartHash = refreshData.sender_policy ?? null;
|
|
8828
|
-
const senderPolicyHash =
|
|
8977
|
+
const senderPolicyHash = computeSenderPolicyRestartHash(senderPolicyForRestartHash);
|
|
8829
8978
|
const prevSenderPolicyHash = agentState.knownSenderPolicyHashes.get(agent.agent_id);
|
|
8830
8979
|
const senderPolicyDecision = hasSenderPolicyChannel ? decideSenderPolicyRestart({
|
|
8831
8980
|
previousHash: prevSenderPolicyHash,
|
|
@@ -8867,7 +9016,7 @@ async function processAgent(agent, agentStates) {
|
|
|
8867
9016
|
const behaviourSubset = extractMsTeamsBehaviourSubset(
|
|
8868
9017
|
msteamsEntry?.config
|
|
8869
9018
|
);
|
|
8870
|
-
const behaviourHash =
|
|
9019
|
+
const behaviourHash = createHash11("sha256").update(canonicalJson(behaviourSubset)).digest("hex");
|
|
8871
9020
|
const prevBehaviourHash = agentState.knownMsTeamsBehaviourHashes.get(agent.agent_id);
|
|
8872
9021
|
const behaviourDecision = decideSenderPolicyRestart({
|
|
8873
9022
|
previousHash: prevBehaviourHash,
|
|
@@ -8914,7 +9063,7 @@ async function processAgent(agent, agentStates) {
|
|
|
8914
9063
|
const slackBehaviourSubset = extractSlackBehaviourSubset(
|
|
8915
9064
|
slackEntry?.config
|
|
8916
9065
|
);
|
|
8917
|
-
const slackBehaviourHash =
|
|
9066
|
+
const slackBehaviourHash = createHash11("sha256").update(canonicalJson(slackBehaviourSubset)).digest("hex");
|
|
8918
9067
|
const prevSlackBehaviourHash = agentState.knownSlackBehaviourHashes.get(agent.agent_id);
|
|
8919
9068
|
const slackBehaviourDecision = decideSenderPolicyRestart({
|
|
8920
9069
|
previousHash: prevSlackBehaviourHash,
|
|
@@ -9213,10 +9362,10 @@ async function processAgent(agent, agentStates) {
|
|
|
9213
9362
|
desiredEntries.push({ serverId, url, headers: mcpHeaders, name: tk.toolkit_name });
|
|
9214
9363
|
}
|
|
9215
9364
|
const hashBasis = desiredEntries.slice().sort((a, b) => a.serverId.localeCompare(b.serverId)).map((e) => {
|
|
9216
|
-
const headersHash =
|
|
9365
|
+
const headersHash = createHash11("sha256").update(canonicalJson(e.headers ?? {})).digest("hex").slice(0, 16);
|
|
9217
9366
|
return `${e.serverId}|${e.url}|${headersHash}`;
|
|
9218
9367
|
}).join("\n");
|
|
9219
|
-
const mcpHash =
|
|
9368
|
+
const mcpHash = createHash11("sha256").update(hashBasis).digest("hex").slice(0, 16);
|
|
9220
9369
|
const prevMcpHash = agentState.knownManagedMcpHashes.get(agent.agent_id);
|
|
9221
9370
|
const structureHash = managedMcpStructureHash(desiredEntries);
|
|
9222
9371
|
const prevStructureHash = agentState.knownManagedMcpStructure.get(agent.agent_id);
|
|
@@ -9231,7 +9380,7 @@ async function processAgent(agent, agentStates) {
|
|
|
9231
9380
|
if (mcpHash !== prevMcpHash) {
|
|
9232
9381
|
for (const e of desiredEntries) {
|
|
9233
9382
|
frameworkAdapter.writeMcpServer(agent.code_name, e.serverId, { url: e.url, headers: e.headers });
|
|
9234
|
-
const urlHash =
|
|
9383
|
+
const urlHash = createHash11("sha256").update(e.url).digest("hex").slice(0, 12);
|
|
9235
9384
|
log(`[managed-toolkit] ${agent.code_name}: wrote '${e.name}' (serverId=${e.serverId}, url_hash=${urlHash})`);
|
|
9236
9385
|
}
|
|
9237
9386
|
if (frameworkAdapter.removeMcpServer && frameworkAdapter.getMcpPath) {
|
|
@@ -9333,7 +9482,7 @@ async function processAgent(agent, agentStates) {
|
|
|
9333
9482
|
if (frameworkAdapter.installSkillFiles) {
|
|
9334
9483
|
const currentIntegrationSkillIds = /* @__PURE__ */ new Set();
|
|
9335
9484
|
const installedIntegrationSkills = [];
|
|
9336
|
-
const { createHash:
|
|
9485
|
+
const { createHash: createHash12 } = await import("crypto");
|
|
9337
9486
|
const refreshAny = refreshData;
|
|
9338
9487
|
const contexts = refreshAny.integration_contexts ?? refreshAny.plugin_contexts ?? [];
|
|
9339
9488
|
const contextBySlug = /* @__PURE__ */ new Map();
|
|
@@ -9362,7 +9511,7 @@ async function processAgent(agent, agentStates) {
|
|
|
9362
9511
|
)
|
|
9363
9512
|
}));
|
|
9364
9513
|
const bundle = buildIntegrationBundle(renderedScopes);
|
|
9365
|
-
const contentHash =
|
|
9514
|
+
const contentHash = createHash12("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
|
|
9366
9515
|
const hashKey = `plugin-skill:${agent.agent_id}:${integrationSkillId}`;
|
|
9367
9516
|
if (agentState.knownSkillHashes.get(hashKey) === contentHash) continue;
|
|
9368
9517
|
frameworkAdapter.installSkillFiles(agent.code_name, integrationSkillId, bundle.files);
|
|
@@ -9419,7 +9568,7 @@ async function processAgent(agent, agentStates) {
|
|
|
9419
9568
|
const plan = planGlobalSkillSync(
|
|
9420
9569
|
[...refreshAny.global_skills ?? [], ...refreshAny.shared_skills ?? []],
|
|
9421
9570
|
agentState.knownGlobalSkillIds.get(agent.agent_id) ?? /* @__PURE__ */ new Set(),
|
|
9422
|
-
(content) =>
|
|
9571
|
+
(content) => createHash12("sha256").update(content).digest("hex").slice(0, 12),
|
|
9423
9572
|
(skillId) => agentState.knownSkillHashes.get(`global-skill:${agent.agent_id}:${skillId}`)
|
|
9424
9573
|
);
|
|
9425
9574
|
for (const { skillId, content, hash } of plan.installs) {
|
|
@@ -9462,7 +9611,7 @@ async function processAgent(agent, agentStates) {
|
|
|
9462
9611
|
const slug = hook.integration_slug ?? hook.plugin_slug;
|
|
9463
9612
|
if (!slug) continue;
|
|
9464
9613
|
try {
|
|
9465
|
-
const scriptHash =
|
|
9614
|
+
const scriptHash = createHash12("sha256").update(hook.script).digest("hex").slice(0, 12);
|
|
9466
9615
|
const hookKey = `${agent.agent_id}:${frameworkAdapter.id}:plugin-hook:${slug}:on_install`;
|
|
9467
9616
|
if (agentState.knownSkillHashes.get(hookKey) === scriptHash) continue;
|
|
9468
9617
|
const result = await frameworkAdapter.executePluginHook({
|
|
@@ -9477,9 +9626,9 @@ async function processAgent(agent, agentStates) {
|
|
|
9477
9626
|
} else if (result.timedOut) {
|
|
9478
9627
|
log(`Integration hook on_install '${slug}' TIMED OUT for '${agent.code_name}' after ${result.durationMs}ms`);
|
|
9479
9628
|
} else {
|
|
9480
|
-
const stderrHash =
|
|
9629
|
+
const stderrHash = createHash12("sha256").update(result.stderr).digest("hex").slice(0, 12);
|
|
9481
9630
|
const missingCmd = result.exitCode === 127 ? extractCommandNotFound(result.stderr) : null;
|
|
9482
|
-
const missingCmdHash = missingCmd ?
|
|
9631
|
+
const missingCmdHash = missingCmd ? createHash12("sha256").update(missingCmd).digest("hex").slice(0, 8) : null;
|
|
9483
9632
|
log(
|
|
9484
9633
|
`Integration hook on_install '${slug}' exited ${result.exitCode} for '${agent.code_name}' ` + (missingCmdHash ? `[missing_command_hash=${missingCmdHash}] ` : "") + `[stderr_hash=${stderrHash} stderr_len=${result.stderr.length}]`
|
|
9485
9634
|
);
|
|
@@ -10107,7 +10256,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
10107
10256
|
const ctx = getLastFailureContext(codeName);
|
|
10108
10257
|
const recovery = prepareForRespawn(codeName);
|
|
10109
10258
|
const tailSummary = !ctx.tail ? "" : KNOWN_SAFE_TAIL_SIGNATURES.has(ctx.signature) ? `; last pane output (${PANE_TAIL_PREVIEW_LINES} of ~20 lines):
|
|
10110
|
-
${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${
|
|
10259
|
+
${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash11("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
|
|
10111
10260
|
const sigSummary = ctx.signature !== "unknown" ? `; signature=${ctx.signature}` : "";
|
|
10112
10261
|
const recoverySummary = recovery ? `; recovery=${recovery}` : "";
|
|
10113
10262
|
log(
|
|
@@ -10121,7 +10270,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash10("sha256")
|
|
|
10121
10270
|
);
|
|
10122
10271
|
getHostId().then((hostId) => {
|
|
10123
10272
|
if (!hostId) return;
|
|
10124
|
-
const paneTailHash = zombie.paneTail ? `sha256:${
|
|
10273
|
+
const paneTailHash = zombie.paneTail ? `sha256:${createHash11("sha256").update(zombie.paneTail).digest("hex").slice(0, 12)}` : null;
|
|
10125
10274
|
return api.post("/host/events", {
|
|
10126
10275
|
host_id: hostId,
|
|
10127
10276
|
agent_code_name: codeName,
|
|
@@ -10257,7 +10406,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash10("sha256")
|
|
|
10257
10406
|
if (!claudeAuthTupleBySession.has(codeName)) {
|
|
10258
10407
|
claudeAuthTupleBySession.set(codeName, currentAuthTuple);
|
|
10259
10408
|
}
|
|
10260
|
-
const stableTasksHash =
|
|
10409
|
+
const stableTasksHash = createHash11("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
|
|
10261
10410
|
const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
|
|
10262
10411
|
if (stableTasksHash !== prevHash) {
|
|
10263
10412
|
const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
|
|
@@ -11178,7 +11327,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
11178
11327
|
if (!file.endsWith(".md")) continue;
|
|
11179
11328
|
try {
|
|
11180
11329
|
const raw = readFileSync14(join16(memoryDir, file), "utf-8");
|
|
11181
|
-
const fileHash =
|
|
11330
|
+
const fileHash = createHash11("sha256").update(raw).digest("hex").slice(0, 16);
|
|
11182
11331
|
currentHashes.set(file, fileHash);
|
|
11183
11332
|
if (prevHashes.get(file) === fileHash) continue;
|
|
11184
11333
|
const parsed = parseMemoryFile(raw, file.replace(/\.md$/, ""));
|
|
@@ -11216,14 +11365,14 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
11216
11365
|
}
|
|
11217
11366
|
async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
11218
11367
|
const localFiles = existsSync8(memoryDir) ? readdirSync5(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
|
|
11219
|
-
const localListHash =
|
|
11368
|
+
const localListHash = createHash11("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
|
|
11220
11369
|
const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
|
|
11221
11370
|
const prevDownload = lastDownloadHash.get(agent.agent_id);
|
|
11222
11371
|
try {
|
|
11223
11372
|
const dbMemories = await api.post("/host/memories", {
|
|
11224
11373
|
agent_id: agent.agent_id
|
|
11225
11374
|
});
|
|
11226
|
-
const responseHash =
|
|
11375
|
+
const responseHash = createHash11("sha256").update(JSON.stringify(dbMemories.memories ?? [])).digest("hex").slice(0, 16);
|
|
11227
11376
|
if (!force && prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
|
|
11228
11377
|
return true;
|
|
11229
11378
|
}
|
|
@@ -11262,7 +11411,7 @@ ${mem.content}
|
|
|
11262
11411
|
}
|
|
11263
11412
|
if (written > 0 || overwritten > 0) {
|
|
11264
11413
|
const updatedFiles = readdirSync5(memoryDir).filter((f) => f.endsWith(".md")).sort();
|
|
11265
|
-
lastLocalFileHash.set(agent.agent_id,
|
|
11414
|
+
lastLocalFileHash.set(agent.agent_id, createHash11("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
|
|
11266
11415
|
log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
|
|
11267
11416
|
}
|
|
11268
11417
|
}
|
|
@@ -11675,7 +11824,7 @@ function deployMcpAssets() {
|
|
|
11675
11824
|
const fileHash = (p) => {
|
|
11676
11825
|
try {
|
|
11677
11826
|
if (!existsSync8(p)) return null;
|
|
11678
|
-
return
|
|
11827
|
+
return createHash11("sha256").update(readFileSync14(p)).digest("hex");
|
|
11679
11828
|
} catch {
|
|
11680
11829
|
return null;
|
|
11681
11830
|
}
|