@integrity-labs/agt-cli 0.28.840 → 0.28.841
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 +5 -5
- package/dist/{chunk-24AILXID.js → chunk-43P6SG7L.js} +4 -4
- package/dist/{chunk-W4KAZQBS.js → chunk-CFLYGZOF.js} +2 -2
- package/dist/{chunk-DUOFKTAD.js → chunk-XBLODN73.js} +17 -11
- package/dist/chunk-XBLODN73.js.map +1 -0
- package/dist/{claude-pair-runtime-A52UZQ6V.js → claude-pair-runtime-XC3AQA4L.js} +2 -2
- package/dist/lib/manager-worker.js +13 -13
- package/dist/mcp/direct-chat-channel.js +752 -635
- package/dist/{persistent-session-N6FIS7UY.js → persistent-session-WLP5YTO2.js} +3 -3
- package/dist/{responsiveness-probe-OBQCSEFT.js → responsiveness-probe-7RYNNHKC.js} +3 -3
- package/dist/{session-auth-dead-LIPEYPBX.js → session-auth-dead-X6B6C3BR.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-DUOFKTAD.js.map +0 -1
- /package/dist/{chunk-24AILXID.js.map → chunk-43P6SG7L.js.map} +0 -0
- /package/dist/{chunk-W4KAZQBS.js.map → chunk-CFLYGZOF.js.map} +0 -0
- /package/dist/{claude-pair-runtime-A52UZQ6V.js.map → claude-pair-runtime-XC3AQA4L.js.map} +0 -0
- /package/dist/{persistent-session-N6FIS7UY.js.map → persistent-session-WLP5YTO2.js.map} +0 -0
- /package/dist/{responsiveness-probe-OBQCSEFT.js.map → responsiveness-probe-7RYNNHKC.js.map} +0 -0
- /package/dist/{session-auth-dead-LIPEYPBX.js.map → session-auth-dead-X6B6C3BR.js.map} +0 -0
|
@@ -29854,611 +29854,32 @@ var DirectChatClaimTracker = class {
|
|
|
29854
29854
|
}
|
|
29855
29855
|
};
|
|
29856
29856
|
|
|
29857
|
-
//
|
|
29858
|
-
|
|
29859
|
-
|
|
29860
|
-
|
|
29861
|
-
|
|
29862
|
-
|
|
29863
|
-
if (!existsSync(path)) return { fresh: false, startedAtMs: nowMs };
|
|
29864
|
-
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
29865
|
-
if (!parsed || typeof parsed !== "object") return { fresh: false, startedAtMs: nowMs };
|
|
29866
|
-
const o = parsed;
|
|
29867
|
-
const fresh = o.fresh === true;
|
|
29868
|
-
const startedAtMs = typeof o.startedAtMs === "number" && Number.isFinite(o.startedAtMs) ? o.startedAtMs : nowMs;
|
|
29869
|
-
return { fresh, startedAtMs };
|
|
29870
|
-
} catch {
|
|
29871
|
-
return { fresh: false, startedAtMs: nowMs };
|
|
29872
|
-
}
|
|
29873
|
-
}
|
|
29857
|
+
// ../core/dist/types/agent.js
|
|
29858
|
+
var FRAMEWORK_MODEL_SLOTS = {
|
|
29859
|
+
"claude-code": ["primary", "small_fast", "advisor"],
|
|
29860
|
+
"opencode": ["primary"]
|
|
29861
|
+
};
|
|
29862
|
+
var KNOWN_MODEL_SLOTS = new Set(Object.values(FRAMEWORK_MODEL_SLOTS).flat());
|
|
29874
29863
|
|
|
29875
|
-
//
|
|
29876
|
-
|
|
29877
|
-
|
|
29878
|
-
|
|
29879
|
-
|
|
29880
|
-
if (input.userRole) identity.user_role = input.userRole;
|
|
29881
|
-
const page = {};
|
|
29882
|
-
if (input.pageSlug) page.page_slug = input.pageSlug;
|
|
29883
|
-
if (input.pageTitle) page.page_title = input.pageTitle;
|
|
29884
|
-
if (input.pageUrl) page.page_url = input.pageUrl;
|
|
29885
|
-
if (input.pageContentUrl) page.page_content_url = input.pageContentUrl;
|
|
29886
|
-
if (input.pageArtefactId) page.page_artefact_id = input.pageArtefactId;
|
|
29887
|
-
if (input.pageGated != null) page.page_gated = input.pageGated ? "true" : "false";
|
|
29888
|
-
return {
|
|
29889
|
-
session_id: input.sessionId,
|
|
29890
|
-
user: "webapp",
|
|
29891
|
-
source: "direct-chat",
|
|
29892
|
-
...identity,
|
|
29893
|
-
...page,
|
|
29894
|
-
// String flag the agent's channel instructions (and the renderer) read:
|
|
29895
|
-
// 'false' = notice (do not reply), 'true' = normal message (reply expected).
|
|
29896
|
-
requires_reply: input.isNotice ? "false" : "true",
|
|
29897
|
-
// ENG-6407 / ADR-0024 Slice 1: provenance + reply-obligation as first-class
|
|
29898
|
-
// tag attributes. Direct chat is conversational; a notice owes no reply, so
|
|
29899
|
-
// expects_reply mirrors the existing requires_reply flag. Recorded only - no
|
|
29900
|
-
// consumer gates on these yet (Slice 2).
|
|
29901
|
-
lane: "conversational",
|
|
29902
|
-
expects_reply: input.isNotice ? "false" : "true"
|
|
29903
|
-
};
|
|
29904
|
-
}
|
|
29864
|
+
// ../core/dist/types/model-policy.js
|
|
29865
|
+
var KNOWN_MODEL_POLICY_SLOTS = [...KNOWN_MODEL_SLOTS].sort();
|
|
29866
|
+
var MODEL_POLICY_SLOTS_IN_ORDER = [...KNOWN_MODEL_SLOTS];
|
|
29867
|
+
var MODEL_POLICY_SLOTS_PENDING_ACTUATOR = /* @__PURE__ */ new Set();
|
|
29868
|
+
var OFFERABLE_MODEL_POLICY_SLOTS = MODEL_POLICY_SLOTS_IN_ORDER.filter((slot) => !MODEL_POLICY_SLOTS_PENDING_ACTUATOR.has(slot));
|
|
29905
29869
|
|
|
29906
|
-
//
|
|
29907
|
-
|
|
29908
|
-
|
|
29909
|
-
|
|
29910
|
-
|
|
29911
|
-
|
|
29912
|
-
|
|
29913
|
-
|
|
29914
|
-
|
|
29915
|
-
function foldTurnInitiatorLedger(existing, marker, maxAgeMs = TURN_INITIATOR_MAX_AGE_MS, maxEntries = TURN_INITIATOR_LEDGER_MAX_ENTRIES) {
|
|
29916
|
-
const now = marker.ts;
|
|
29917
|
-
const key = (e) => `${e.channel}\0${e.channel_ref ?? ""}`;
|
|
29918
|
-
const markerKey = key(marker);
|
|
29919
|
-
const prior = existing && Array.isArray(existing.entries) ? existing.entries : [];
|
|
29920
|
-
const kept = prior.filter(
|
|
29921
|
-
(e) => e && typeof e.ts === "number" && Number.isFinite(e.ts) && now - e.ts <= maxAgeMs && now - e.ts >= 0 && key(e) !== markerKey
|
|
29922
|
-
// the same thread is replaced by the new entry below
|
|
29923
|
-
);
|
|
29924
|
-
kept.push({
|
|
29925
|
-
channel: marker.channel,
|
|
29926
|
-
sender_id: marker.sender_id,
|
|
29927
|
-
...marker.sender_name ? { sender_name: marker.sender_name } : {},
|
|
29928
|
-
...marker.channel_ref ? { channel_ref: marker.channel_ref } : {},
|
|
29929
|
-
ts: marker.ts
|
|
29930
|
-
});
|
|
29931
|
-
kept.sort((a, b) => b.ts - a.ts);
|
|
29932
|
-
return { v: 1, entries: kept.slice(0, maxEntries) };
|
|
29933
|
-
}
|
|
29934
|
-
function updateTurnInitiatorLedger(singleSlotFile, marker) {
|
|
29935
|
-
const ledgerFile = turnInitiatorLedgerPath(singleSlotFile);
|
|
29936
|
-
let existing = null;
|
|
29937
|
-
try {
|
|
29938
|
-
const parsed = JSON.parse(readFileSync2(ledgerFile, "utf8"));
|
|
29939
|
-
if (parsed && parsed.v === 1 && Array.isArray(parsed.entries)) existing = parsed;
|
|
29940
|
-
} catch {
|
|
29941
|
-
}
|
|
29942
|
-
const next = foldTurnInitiatorLedger(existing, marker);
|
|
29943
|
-
const tmp = `${ledgerFile}.tmp`;
|
|
29944
|
-
writeFileSync(tmp, JSON.stringify(next), "utf8");
|
|
29945
|
-
renameSync(tmp, ledgerFile);
|
|
29946
|
-
}
|
|
29947
|
-
function writeTurnInitiatorMarker(input) {
|
|
29948
|
-
const file = process.env["AGT_TURN_INITIATOR_FILE"];
|
|
29949
|
-
if (!file || !input.sender_id) return;
|
|
29950
|
-
try {
|
|
29951
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
29952
|
-
const marker = { ...input, ts: Date.now() };
|
|
29953
|
-
const tmp = `${file}.tmp`;
|
|
29954
|
-
writeFileSync(tmp, JSON.stringify(marker), "utf8");
|
|
29955
|
-
renameSync(tmp, file);
|
|
29956
|
-
try {
|
|
29957
|
-
updateTurnInitiatorLedger(file, marker);
|
|
29958
|
-
} catch {
|
|
29959
|
-
}
|
|
29960
|
-
} catch {
|
|
29961
|
-
}
|
|
29962
|
-
}
|
|
29870
|
+
// ../core/dist/types/integration.js
|
|
29871
|
+
var HITL_TIER_ORDER = [
|
|
29872
|
+
"read",
|
|
29873
|
+
"write",
|
|
29874
|
+
"write_high_risk",
|
|
29875
|
+
"write_destructive",
|
|
29876
|
+
"admin"
|
|
29877
|
+
];
|
|
29878
|
+
var HITL_TIER_RANK = Object.freeze(Object.fromEntries(HITL_TIER_ORDER.map((tier, i) => [tier, i])));
|
|
29963
29879
|
|
|
29964
|
-
//
|
|
29965
|
-
|
|
29966
|
-
|
|
29967
|
-
var SCHEDULED_TURN_MARKER_FILENAME = ".current-scheduled-turn.json";
|
|
29968
|
-
var SCHEDULED_TURN_MAX_AGE_MS = 15 * 60 * 1e3;
|
|
29969
|
-
function clearScheduledTurnMarker(agentDir) {
|
|
29970
|
-
if (!agentDir) return;
|
|
29971
|
-
try {
|
|
29972
|
-
unlinkSync(join3(agentDir, SCHEDULED_TURN_MARKER_FILENAME));
|
|
29973
|
-
} catch {
|
|
29974
|
-
}
|
|
29975
|
-
}
|
|
29976
|
-
|
|
29977
|
-
// src/direct-chat-pending-inbound.ts
|
|
29978
|
-
import {
|
|
29979
|
-
existsSync as existsSync2,
|
|
29980
|
-
mkdirSync as mkdirSync2,
|
|
29981
|
-
readdirSync,
|
|
29982
|
-
readFileSync as readFileSync4,
|
|
29983
|
-
renameSync as renameSync2,
|
|
29984
|
-
unlinkSync as unlinkSync2,
|
|
29985
|
-
writeFileSync as writeFileSync2
|
|
29986
|
-
} from "fs";
|
|
29987
|
-
import { join as join4 } from "path";
|
|
29988
|
-
function hexEncodeSegment(value) {
|
|
29989
|
-
return Buffer.from(value, "utf8").toString("hex");
|
|
29990
|
-
}
|
|
29991
|
-
function directChatMarkerName(sessionId, messageId) {
|
|
29992
|
-
return `${hexEncodeSegment(sessionId)}__${hexEncodeSegment(messageId)}.json`;
|
|
29993
|
-
}
|
|
29994
|
-
var defaultClearMarkerFile = (fullPath) => {
|
|
29995
|
-
try {
|
|
29996
|
-
if (existsSync2(fullPath)) unlinkSync2(fullPath);
|
|
29997
|
-
} catch {
|
|
29998
|
-
}
|
|
29999
|
-
};
|
|
30000
|
-
function directChatInboundId(sessionId, messageId) {
|
|
30001
|
-
return `direct-chat|${sessionId.length}|${sessionId}|${messageId}`;
|
|
30002
|
-
}
|
|
30003
|
-
function writeDirectChatPendingInboundMarker(dir, sessionId, messageId) {
|
|
30004
|
-
if (!dir || !sessionId || !messageId) return;
|
|
30005
|
-
try {
|
|
30006
|
-
mkdirSync2(dir, { recursive: true });
|
|
30007
|
-
const marker = {
|
|
30008
|
-
channel: "direct-chat",
|
|
30009
|
-
session_id: sessionId,
|
|
30010
|
-
message_id: messageId,
|
|
30011
|
-
received_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30012
|
-
inbound_id: directChatInboundId(sessionId, messageId)
|
|
30013
|
-
};
|
|
30014
|
-
const final = join4(dir, directChatMarkerName(sessionId, messageId));
|
|
30015
|
-
const tmp = `${final}.tmp`;
|
|
30016
|
-
writeFileSync2(tmp, JSON.stringify(marker), "utf8");
|
|
30017
|
-
renameSync2(tmp, final);
|
|
30018
|
-
} catch {
|
|
30019
|
-
}
|
|
30020
|
-
}
|
|
30021
|
-
function clearDirectChatPendingMarkersForSession(dir, sessionId, op = defaultClearMarkerFile) {
|
|
30022
|
-
if (!dir || !sessionId) return 0;
|
|
30023
|
-
const prefix = `${hexEncodeSegment(sessionId)}__`;
|
|
30024
|
-
let cleared = 0;
|
|
30025
|
-
let names;
|
|
30026
|
-
try {
|
|
30027
|
-
names = readdirSync(dir);
|
|
30028
|
-
} catch {
|
|
30029
|
-
return 0;
|
|
30030
|
-
}
|
|
30031
|
-
for (const name of names) {
|
|
30032
|
-
if (!name.startsWith(prefix) || !name.endsWith(".json")) continue;
|
|
30033
|
-
op(join4(dir, name));
|
|
30034
|
-
cleared += 1;
|
|
30035
|
-
}
|
|
30036
|
-
return cleared;
|
|
30037
|
-
}
|
|
30038
|
-
function readDirectChatPendingInboundMarker(dir, sessionId, messageId, readFileImpl = (path) => readFileSync4(path, "utf8")) {
|
|
30039
|
-
if (!dir || !sessionId || !messageId) return null;
|
|
30040
|
-
try {
|
|
30041
|
-
const raw = readFileImpl(join4(dir, directChatMarkerName(sessionId, messageId)));
|
|
30042
|
-
return JSON.parse(raw);
|
|
30043
|
-
} catch {
|
|
30044
|
-
return null;
|
|
30045
|
-
}
|
|
30046
|
-
}
|
|
30047
|
-
var MAX_REPORTED_ORPHANS = 20;
|
|
30048
|
-
function sweepAgedDirectChatMarkers(dir, deps) {
|
|
30049
|
-
const result = {
|
|
30050
|
-
cleared: 0,
|
|
30051
|
-
orphaned: 0,
|
|
30052
|
-
orphanedIdentities: [],
|
|
30053
|
-
orphanedTruncated: false
|
|
30054
|
-
};
|
|
30055
|
-
if (!dir) return result;
|
|
30056
|
-
let names;
|
|
30057
|
-
try {
|
|
30058
|
-
names = deps.readdir(dir);
|
|
30059
|
-
} catch {
|
|
30060
|
-
return result;
|
|
30061
|
-
}
|
|
30062
|
-
for (const name of names) {
|
|
30063
|
-
if (!name.endsWith(".json") || name.startsWith(".")) continue;
|
|
30064
|
-
const full = join4(dir, name);
|
|
30065
|
-
let marker;
|
|
30066
|
-
try {
|
|
30067
|
-
marker = JSON.parse(deps.readFile(full));
|
|
30068
|
-
} catch {
|
|
30069
|
-
continue;
|
|
30070
|
-
}
|
|
30071
|
-
if (!deps.isAged(marker.received_at)) continue;
|
|
30072
|
-
const undelivered = !deps.hasDelivery(marker.inbound_id);
|
|
30073
|
-
try {
|
|
30074
|
-
deps.unlink(full);
|
|
30075
|
-
} catch {
|
|
30076
|
-
continue;
|
|
30077
|
-
}
|
|
30078
|
-
result.cleared += 1;
|
|
30079
|
-
if (undelivered) {
|
|
30080
|
-
const identity = {
|
|
30081
|
-
inboundId: marker.inbound_id,
|
|
30082
|
-
receivedAt: marker.received_at,
|
|
30083
|
-
sessionId: marker.session_id
|
|
30084
|
-
};
|
|
30085
|
-
try {
|
|
30086
|
-
deps.onOrphaned(identity);
|
|
30087
|
-
} catch {
|
|
30088
|
-
}
|
|
30089
|
-
result.orphaned += 1;
|
|
30090
|
-
if (result.orphanedIdentities.length < MAX_REPORTED_ORPHANS) {
|
|
30091
|
-
result.orphanedIdentities.push(identity);
|
|
30092
|
-
} else {
|
|
30093
|
-
result.orphanedTruncated = true;
|
|
30094
|
-
}
|
|
30095
|
-
}
|
|
30096
|
-
}
|
|
30097
|
-
return result;
|
|
30098
|
-
}
|
|
30099
|
-
|
|
30100
|
-
// src/direct-chat-recovery-outbox.ts
|
|
30101
|
-
async function consumeDirectChatRecoveryFile(fullPath, filename, deps) {
|
|
30102
|
-
if (filename.endsWith(".tmp") || filename.endsWith(".poison")) return "skipped";
|
|
30103
|
-
let payload;
|
|
30104
|
-
try {
|
|
30105
|
-
payload = JSON.parse(deps.readFile(fullPath));
|
|
30106
|
-
} catch (err) {
|
|
30107
|
-
deps.log(`recovery outbox parse failed (${filename}): ${err.message}`);
|
|
30108
|
-
try {
|
|
30109
|
-
deps.renameFile(fullPath, `${fullPath}.parse-error.poison`);
|
|
30110
|
-
} catch {
|
|
30111
|
-
}
|
|
30112
|
-
return "poison";
|
|
30113
|
-
}
|
|
30114
|
-
if (!payload || !payload.session_id || !payload.text) {
|
|
30115
|
-
deps.log(`recovery outbox malformed (${filename}): missing session_id or text`);
|
|
30116
|
-
if (payload && payload.marker_name) {
|
|
30117
|
-
try {
|
|
30118
|
-
deps.removeLedgerEntry(payload.marker_name);
|
|
30119
|
-
} catch {
|
|
30120
|
-
}
|
|
30121
|
-
}
|
|
30122
|
-
try {
|
|
30123
|
-
deps.renameFile(fullPath, `${fullPath}.malformed.poison`);
|
|
30124
|
-
} catch {
|
|
30125
|
-
}
|
|
30126
|
-
return "poison";
|
|
30127
|
-
}
|
|
30128
|
-
const content = deps.sanitize(payload.text);
|
|
30129
|
-
const messageIds = deps.peekClaims(payload.session_id);
|
|
30130
|
-
let result;
|
|
30131
|
-
try {
|
|
30132
|
-
result = await deps.deliver({
|
|
30133
|
-
sessionId: payload.session_id,
|
|
30134
|
-
content,
|
|
30135
|
-
messageIds
|
|
30136
|
-
});
|
|
30137
|
-
} catch (err) {
|
|
30138
|
-
result = { ok: false, error: err.message };
|
|
30139
|
-
}
|
|
30140
|
-
if (result.ok && !result.error) {
|
|
30141
|
-
deps.clearClaims(payload.session_id, messageIds);
|
|
30142
|
-
deps.clearMarkers(payload.session_id);
|
|
30143
|
-
if (payload.marker_name) deps.removeLedgerEntry(payload.marker_name);
|
|
30144
|
-
try {
|
|
30145
|
-
deps.unlinkFile(fullPath);
|
|
30146
|
-
} catch {
|
|
30147
|
-
}
|
|
30148
|
-
deps.log(`ghost-reply recovery sent (session=${payload.session_id})`);
|
|
30149
|
-
return "delivered";
|
|
30150
|
-
}
|
|
30151
|
-
if (payload.marker_name) deps.removeLedgerEntry(payload.marker_name);
|
|
30152
|
-
try {
|
|
30153
|
-
deps.unlinkFile(fullPath);
|
|
30154
|
-
} catch {
|
|
30155
|
-
}
|
|
30156
|
-
deps.log(
|
|
30157
|
-
`ghost-reply recovery send failed (session=${payload.session_id}): ${result.error ?? "unknown"} - re-armed for retry`
|
|
30158
|
-
);
|
|
30159
|
-
return "failed";
|
|
30160
|
-
}
|
|
30161
|
-
|
|
30162
|
-
// src/inbound-delivery-ledger.ts
|
|
30163
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync5, renameSync as renameSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
30164
|
-
import { join as join5 } from "path";
|
|
30165
|
-
function safeInboundId(inboundId) {
|
|
30166
|
-
return inboundId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
30167
|
-
}
|
|
30168
|
-
var defaultDeps = {
|
|
30169
|
-
mkdir: (dir) => mkdirSync3(dir, { recursive: true }),
|
|
30170
|
-
writeFile: (path, data) => writeFileSync3(path, data, "utf8"),
|
|
30171
|
-
rename: (from, to) => renameSync3(from, to),
|
|
30172
|
-
readdir: (dir) => readdirSync2(dir),
|
|
30173
|
-
readFile: (path) => readFileSync5(path, "utf8"),
|
|
30174
|
-
exists: (path) => existsSync3(path)
|
|
30175
|
-
};
|
|
30176
|
-
function writeInboundDeliveryLedgerEntry(dir, record2, deps = defaultDeps) {
|
|
30177
|
-
if (!dir || !record2.inbound_id || !record2.conv_key) return;
|
|
30178
|
-
const safe = safeInboundId(record2.inbound_id);
|
|
30179
|
-
if (!safe || safe.includes("/") || safe.includes("\\") || safe.includes("..")) return;
|
|
30180
|
-
try {
|
|
30181
|
-
deps.mkdir(dir);
|
|
30182
|
-
const final = join5(dir, `${safe}.json`);
|
|
30183
|
-
const tmp = `${final}.tmp`;
|
|
30184
|
-
deps.writeFile(tmp, JSON.stringify(record2));
|
|
30185
|
-
deps.rename(tmp, final);
|
|
30186
|
-
} catch {
|
|
30187
|
-
}
|
|
30188
|
-
}
|
|
30189
|
-
function inboundDeliveryLedgerHas(dir, inboundId, deps = defaultDeps) {
|
|
30190
|
-
if (!dir || !inboundId) return false;
|
|
30191
|
-
const safe = safeInboundId(inboundId);
|
|
30192
|
-
if (!safe || safe.includes("/") || safe.includes("\\") || safe.includes("..")) return false;
|
|
30193
|
-
try {
|
|
30194
|
-
return deps.exists(join5(dir, `${safe}.json`));
|
|
30195
|
-
} catch {
|
|
30196
|
-
return false;
|
|
30197
|
-
}
|
|
30198
|
-
}
|
|
30199
|
-
|
|
30200
|
-
// src/ack-reaction.ts
|
|
30201
|
-
import { readdirSync as readdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
30202
|
-
import { join as join7 } from "path";
|
|
30203
|
-
|
|
30204
|
-
// src/flags-cache-read.ts
|
|
30205
|
-
import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
|
|
30206
|
-
import { homedir } from "os";
|
|
30207
|
-
import { join as join6 } from "path";
|
|
30208
|
-
function defaultFlagsCachePath() {
|
|
30209
|
-
return join6(homedir(), ".augmented", "flags-cache.json");
|
|
30210
|
-
}
|
|
30211
|
-
function envBoolean(raw) {
|
|
30212
|
-
if (raw === void 0) return void 0;
|
|
30213
|
-
const v = raw.trim().toLowerCase();
|
|
30214
|
-
if (v === "") return void 0;
|
|
30215
|
-
if (v === "1" || v === "true" || v === "yes" || v === "on") return true;
|
|
30216
|
-
if (v === "0" || v === "false" || v === "no" || v === "off") return false;
|
|
30217
|
-
return void 0;
|
|
30218
|
-
}
|
|
30219
|
-
function cachedBoolean(key, path) {
|
|
30220
|
-
try {
|
|
30221
|
-
if (!existsSync4(path)) return void 0;
|
|
30222
|
-
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
30223
|
-
if (!parsed || typeof parsed !== "object") return void 0;
|
|
30224
|
-
const flags = parsed.flags;
|
|
30225
|
-
if (!flags || typeof flags !== "object") return void 0;
|
|
30226
|
-
const value = flags[key];
|
|
30227
|
-
return typeof value === "boolean" ? value : void 0;
|
|
30228
|
-
} catch {
|
|
30229
|
-
return void 0;
|
|
30230
|
-
}
|
|
30231
|
-
}
|
|
30232
|
-
function resolveHostBooleanFlag(opts) {
|
|
30233
|
-
const env2 = opts.env ?? process.env;
|
|
30234
|
-
const envValue = envBoolean(env2[opts.envVar]);
|
|
30235
|
-
if (envValue !== void 0) return envValue;
|
|
30236
|
-
const cached2 = cachedBoolean(opts.key, opts.cachePath ?? defaultFlagsCachePath());
|
|
30237
|
-
if (cached2 !== void 0) return cached2;
|
|
30238
|
-
return opts.defaultValue;
|
|
30239
|
-
}
|
|
30240
|
-
|
|
30241
|
-
// ../core/dist/channels/deflection-causes.js
|
|
30242
|
-
var DEFLECTION_CAUSES = [
|
|
30243
|
-
"integration_down",
|
|
30244
|
-
"session_dead",
|
|
30245
|
-
"wedged",
|
|
30246
|
-
"busy",
|
|
30247
|
-
"duplicate",
|
|
30248
|
-
// ENG-8387: an `app_mention` — the CANONICAL delivery of an @mention — dropped
|
|
30249
|
-
// by the fresh-ingress dedup. Split out of the generic `duplicate` bucket
|
|
30250
|
-
// because the two mean very different things: `duplicate` is dominated by the
|
|
30251
|
-
// deliberate, high-volume ENG-6378 echo drop and by routine reconnect
|
|
30252
|
-
// redelivery, both benign, while a dropped app_mention has the exact shape of
|
|
30253
|
-
// a lost mention. Conflated, the second is invisible inside the first — which
|
|
30254
|
-
// is how ENG-6378's silent loss ran unobserved.
|
|
30255
|
-
"duplicate_mention",
|
|
30256
|
-
"mention_echo_orphan",
|
|
30257
|
-
"replay_orphaned",
|
|
30258
|
-
"replay_exhausted",
|
|
30259
|
-
// ENG-9414 — see the type union above for why these two exist. Both are
|
|
30260
|
-
// message-loss classes the pre-existing causes were structurally unable to
|
|
30261
|
-
// observe, which is why four destroyed customer inbounds in one hour
|
|
30262
|
-
// produced zero alerts.
|
|
30263
|
-
"aged_out_unrecoverable",
|
|
30264
|
-
"marker_corrupt",
|
|
30265
|
-
"unknown"
|
|
30266
|
-
];
|
|
30267
|
-
var DEFLECTION_CAUSE_SET = new Set(DEFLECTION_CAUSES);
|
|
30268
|
-
|
|
30269
|
-
// src/ack-reaction.ts
|
|
30270
|
-
var REPLY_WEDGED_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
30271
|
-
var ACK_PANE_FRESH_THRESHOLD_MS = 6e4;
|
|
30272
|
-
function classifyUndeliverableCause(i) {
|
|
30273
|
-
if (!i.hasTarget) return null;
|
|
30274
|
-
if (!i.integrationReady) return "integration_down";
|
|
30275
|
-
if (i.tmux === "dead") return "session_dead";
|
|
30276
|
-
if (!i.withinStartupGrace && i.claude === "dead") return "session_dead";
|
|
30277
|
-
const threshold = i.pendingStaleThresholdMs ?? REPLY_WEDGED_THRESHOLD_MS;
|
|
30278
|
-
if (i.oldestPendingAgeMs != null && i.oldestPendingAgeMs > threshold) {
|
|
30279
|
-
const paneFreshThreshold = i.paneFreshThresholdMs ?? ACK_PANE_FRESH_THRESHOLD_MS;
|
|
30280
|
-
const paneIsFresh = i.paneLogFreshAgeMs != null && i.paneLogFreshAgeMs <= paneFreshThreshold;
|
|
30281
|
-
if (paneIsFresh && i.tmux === "alive" && i.claude === "alive") {
|
|
30282
|
-
return null;
|
|
30283
|
-
}
|
|
30284
|
-
return "wedged";
|
|
30285
|
-
}
|
|
30286
|
-
return null;
|
|
30287
|
-
}
|
|
30288
|
-
var UNDELIVERABLE_NOTICE_THROTTLE_MS = 5 * 60 * 1e3;
|
|
30289
|
-
function shouldPostUndeliverableNotice(lastNoticeAtMs, nowMs, throttleMs = UNDELIVERABLE_NOTICE_THROTTLE_MS) {
|
|
30290
|
-
return lastNoticeAtMs == null || nowMs - lastNoticeAtMs >= throttleMs;
|
|
30291
|
-
}
|
|
30292
|
-
function undeliverableNoticeText(replay) {
|
|
30293
|
-
const honest = noticePromiseIsHonest(replay);
|
|
30294
|
-
return honest ? "\u23F3 I can't get to this right now \u2014 no need to resend; I'll pick it up automatically as soon as I'm free." : "\u23F3 I can't get to this right now. Please resend in a few minutes \u2014 I may not see this one.";
|
|
30295
|
-
}
|
|
30296
|
-
function undeliverableNoticeTextForRepeat(i) {
|
|
30297
|
-
if (i.priorNotices <= 0) return undeliverableNoticeText(i.replay);
|
|
30298
|
-
if (i.priorNotices === 1) {
|
|
30299
|
-
return noticePromiseIsHonest(i.replay) ? "\u23F3 Still stuck on this one \u2014 the automatic pickup I mentioned has not happened. Please resend when you can." : "\u23F3 Still stuck on this one, and I still have not picked it up. Resending is the reliable way through.";
|
|
30300
|
-
}
|
|
30301
|
-
return null;
|
|
30302
|
-
}
|
|
30303
|
-
function noticePromiseIsHonest(replay) {
|
|
30304
|
-
if (replay === void 0) return false;
|
|
30305
|
-
if (typeof replay === "boolean") return replay;
|
|
30306
|
-
return markerReplayable({
|
|
30307
|
-
enabled: replay.enabled ?? channelReplayEnabled(),
|
|
30308
|
-
hasPayload: replay.hasPayload,
|
|
30309
|
-
discretionary: replay.discretionary
|
|
30310
|
-
});
|
|
30311
|
-
}
|
|
30312
|
-
var BUSY_ACK_THRESHOLD_MS = 12e4;
|
|
30313
|
-
var BUSY_ACK_NOTICE_THROTTLE_MS = 20 * 60 * 1e3;
|
|
30314
|
-
function channelBusyAckEnabled() {
|
|
30315
|
-
return resolveHostBooleanFlag({
|
|
30316
|
-
key: "channel-busy-ack",
|
|
30317
|
-
envVar: "AGT_CHANNEL_BUSY_ACK_ENABLED",
|
|
30318
|
-
defaultValue: false
|
|
30319
|
-
});
|
|
30320
|
-
}
|
|
30321
|
-
function channelBusyAckThresholdMs() {
|
|
30322
|
-
const raw = parseInt(process.env.AGT_CHANNEL_BUSY_ACK_THRESHOLD_MS ?? "", 10);
|
|
30323
|
-
return Number.isFinite(raw) && raw > 0 ? raw : BUSY_ACK_THRESHOLD_MS;
|
|
30324
|
-
}
|
|
30325
|
-
function decideBusyAck(i) {
|
|
30326
|
-
if (!i.hasTarget) return false;
|
|
30327
|
-
if (!i.arrivedWhileBusy) return false;
|
|
30328
|
-
if (!i.stillPending) return false;
|
|
30329
|
-
if (!Number.isFinite(i.pendingAgeMs)) return false;
|
|
30330
|
-
const threshold = i.thresholdMs ?? channelBusyAckThresholdMs();
|
|
30331
|
-
if (i.pendingAgeMs < threshold) return false;
|
|
30332
|
-
if (!i.sessionAlive) return false;
|
|
30333
|
-
const paneFreshThreshold = i.paneFreshThresholdMs ?? ACK_PANE_FRESH_THRESHOLD_MS;
|
|
30334
|
-
return i.paneLogFreshAgeMs != null && i.paneLogFreshAgeMs <= paneFreshThreshold;
|
|
30335
|
-
}
|
|
30336
|
-
function busyAckNoticeText() {
|
|
30337
|
-
return "\u{1F6E0}\uFE0F I'm in the middle of something right now \u2014 I'll follow up on this as soon as I'm free.";
|
|
30338
|
-
}
|
|
30339
|
-
var GIVE_UP_SIGNAL_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
30340
|
-
function turnFailedNoticeText(failureClass) {
|
|
30341
|
-
const cause = failureClass === "overloaded" ? "the service I run on is overloaded right now \u2014 nothing to do with you or what you asked for" : failureClass === "server_error" ? "something upstream of me is failing right now \u2014 nothing to do with you or what you asked for" : null;
|
|
30342
|
-
if (cause === null) {
|
|
30343
|
-
return "\u26A0\uFE0F Something went wrong on my side and I couldn\u2019t finish that. Sorry \u2014 send it again when you get a chance and I\u2019ll pick it straight up.";
|
|
30344
|
-
}
|
|
30345
|
-
return `\u26A0\uFE0F I couldn\u2019t finish that \u2014 ${cause}. Sorry \u2014 send it again when you get a chance and I\u2019ll pick it straight up.`;
|
|
30346
|
-
}
|
|
30347
|
-
function oldestPendingMarkerAgeMs(dir, now = Date.now(), opts) {
|
|
30348
|
-
if (!dir) return null;
|
|
30349
|
-
let names;
|
|
30350
|
-
try {
|
|
30351
|
-
names = readdirSync3(dir);
|
|
30352
|
-
} catch {
|
|
30353
|
-
return null;
|
|
30354
|
-
}
|
|
30355
|
-
let oldest = null;
|
|
30356
|
-
for (const name of names) {
|
|
30357
|
-
if (!name.endsWith(".json")) continue;
|
|
30358
|
-
let receivedAt;
|
|
30359
|
-
try {
|
|
30360
|
-
const raw = JSON.parse(readFileSync7(join7(dir, name), "utf-8"));
|
|
30361
|
-
if (raw.discretionary === true) continue;
|
|
30362
|
-
if (!opts?.includeSeen && typeof raw.seen_at === "string" && raw.seen_at) continue;
|
|
30363
|
-
receivedAt = raw.received_at;
|
|
30364
|
-
} catch {
|
|
30365
|
-
continue;
|
|
30366
|
-
}
|
|
30367
|
-
if (!receivedAt) continue;
|
|
30368
|
-
const t = Date.parse(receivedAt);
|
|
30369
|
-
if (Number.isNaN(t)) continue;
|
|
30370
|
-
const age = now - t;
|
|
30371
|
-
if (age < 0) continue;
|
|
30372
|
-
if (oldest == null || age > oldest) oldest = age;
|
|
30373
|
-
}
|
|
30374
|
-
return oldest;
|
|
30375
|
-
}
|
|
30376
|
-
function hasInFlightInbound(dir, now = Date.now()) {
|
|
30377
|
-
return oldestPendingMarkerAgeMs(dir, now, { includeSeen: true }) != null;
|
|
30378
|
-
}
|
|
30379
|
-
function channelOrphanMarkerMs() {
|
|
30380
|
-
const raw = parseInt(process.env.AGT_CHANNEL_ORPHAN_MARKER_MS ?? "", 10);
|
|
30381
|
-
return Number.isFinite(raw) && raw > 0 ? Math.max(raw, 12e4) : 30 * 6e4;
|
|
30382
|
-
}
|
|
30383
|
-
var ORPHAN_SWEEP_INTERVAL_MS = 30 * 60 * 1e3;
|
|
30384
|
-
function orphanSweepIntervalMs() {
|
|
30385
|
-
return Math.max(6e4, Math.min(ORPHAN_SWEEP_INTERVAL_MS, channelOrphanMarkerMs()));
|
|
30386
|
-
}
|
|
30387
|
-
var PANE_FRESH_DEFER_MAX_MS = 10 * 60 * 1e3;
|
|
30388
|
-
function channelReplayEnabled() {
|
|
30389
|
-
return resolveHostBooleanFlag({
|
|
30390
|
-
key: "channel-replay",
|
|
30391
|
-
envVar: "AGT_CHANNEL_REPLAY_ENABLED",
|
|
30392
|
-
defaultValue: true
|
|
30393
|
-
});
|
|
30394
|
-
}
|
|
30395
|
-
function combineMarkerReplayFacts(markers) {
|
|
30396
|
-
if (markers.length === 0) return null;
|
|
30397
|
-
return {
|
|
30398
|
-
hasPayload: markers.every((m) => m.hasPayload),
|
|
30399
|
-
discretionary: markers.some((m) => m.discretionary === true)
|
|
30400
|
-
};
|
|
30401
|
-
}
|
|
30402
|
-
function markerReplayable(i) {
|
|
30403
|
-
if (!i.enabled) return false;
|
|
30404
|
-
if (!i.hasPayload) return false;
|
|
30405
|
-
if (i.discretionary) return false;
|
|
30406
|
-
return true;
|
|
30407
|
-
}
|
|
30408
|
-
function isMarkerGenuinelyAged(receivedAt, nowMs, thresholdMs) {
|
|
30409
|
-
const t = Date.parse(receivedAt ?? "");
|
|
30410
|
-
return Number.isFinite(t) && t <= nowMs && nowMs - t >= thresholdMs;
|
|
30411
|
-
}
|
|
30412
|
-
var DEFLECTION_COUNTER_SUFFIX = "-deflections.json";
|
|
30413
|
-
function deflectionCounterPath(agentDir, channel) {
|
|
30414
|
-
return join7(agentDir, `${channel}${DEFLECTION_COUNTER_SUFFIX}`);
|
|
30415
|
-
}
|
|
30416
|
-
function recordChannelDeflection(agentDir, channel, cause) {
|
|
30417
|
-
if (!agentDir) return;
|
|
30418
|
-
const path = deflectionCounterPath(agentDir, channel);
|
|
30419
|
-
let counts = {};
|
|
30420
|
-
try {
|
|
30421
|
-
const parsed = JSON.parse(readFileSync7(path, "utf-8"));
|
|
30422
|
-
if (parsed && typeof parsed === "object") counts = parsed;
|
|
30423
|
-
} catch {
|
|
30424
|
-
}
|
|
30425
|
-
counts[cause] = (counts[cause] ?? 0) + 1;
|
|
30426
|
-
try {
|
|
30427
|
-
writeFileSync4(path, JSON.stringify(counts), { mode: 384 });
|
|
30428
|
-
} catch {
|
|
30429
|
-
}
|
|
30430
|
-
}
|
|
30431
|
-
|
|
30432
|
-
// src/turn-failure-watch.ts
|
|
30433
|
-
import { readdirSync as readdirSync5, statSync as statSync2 } from "fs";
|
|
30434
|
-
import { join as join9 } from "path";
|
|
30435
|
-
|
|
30436
|
-
// ../core/dist/types/agent.js
|
|
30437
|
-
var FRAMEWORK_MODEL_SLOTS = {
|
|
30438
|
-
"claude-code": ["primary", "small_fast", "advisor"],
|
|
30439
|
-
"opencode": ["primary"]
|
|
30440
|
-
};
|
|
30441
|
-
var KNOWN_MODEL_SLOTS = new Set(Object.values(FRAMEWORK_MODEL_SLOTS).flat());
|
|
30442
|
-
|
|
30443
|
-
// ../core/dist/types/model-policy.js
|
|
30444
|
-
var KNOWN_MODEL_POLICY_SLOTS = [...KNOWN_MODEL_SLOTS].sort();
|
|
30445
|
-
var MODEL_POLICY_SLOTS_IN_ORDER = [...KNOWN_MODEL_SLOTS];
|
|
30446
|
-
var MODEL_POLICY_SLOTS_PENDING_ACTUATOR = /* @__PURE__ */ new Set();
|
|
30447
|
-
var OFFERABLE_MODEL_POLICY_SLOTS = MODEL_POLICY_SLOTS_IN_ORDER.filter((slot) => !MODEL_POLICY_SLOTS_PENDING_ACTUATOR.has(slot));
|
|
30448
|
-
|
|
30449
|
-
// ../core/dist/types/integration.js
|
|
30450
|
-
var HITL_TIER_ORDER = [
|
|
30451
|
-
"read",
|
|
30452
|
-
"write",
|
|
30453
|
-
"write_high_risk",
|
|
30454
|
-
"write_destructive",
|
|
30455
|
-
"admin"
|
|
30456
|
-
];
|
|
30457
|
-
var HITL_TIER_RANK = Object.freeze(Object.fromEntries(HITL_TIER_ORDER.map((tier, i) => [tier, i])));
|
|
30458
|
-
|
|
30459
|
-
// ../core/dist/schemas/validators.js
|
|
30460
|
-
var import__ = __toESM(require__(), 1);
|
|
30461
|
-
var import_ajv_formats2 = __toESM(require_dist(), 1);
|
|
29880
|
+
// ../core/dist/schemas/validators.js
|
|
29881
|
+
var import__ = __toESM(require__(), 1);
|
|
29882
|
+
var import_ajv_formats2 = __toESM(require_dist(), 1);
|
|
30462
29883
|
|
|
30463
29884
|
// ../core/dist/schemas/charter.frontmatter.v1.json
|
|
30464
29885
|
var charter_frontmatter_v1_default = {
|
|
@@ -35109,6 +34530,28 @@ function formatCursorAdvanceShortfall(verdict, ctx) {
|
|
|
35109
34530
|
return `[direct-chat] cursor advance shortfall route=/${ctx.route} site=${ctx.site} session=${ctx.sessionId} expected=${verdict.expected} consumed=${verdict.consumed} reason=${verdict.reason} partial=${verdict.partial} cleared_anyway=${cleared}`;
|
|
35110
34531
|
}
|
|
35111
34532
|
|
|
34533
|
+
// ../core/dist/direct-chat/history-limit.js
|
|
34534
|
+
var DIRECT_CHAT_HISTORY_DEFAULT_LIMIT = 50;
|
|
34535
|
+
var DIRECT_CHAT_HISTORY_MAX_LIMIT = 200;
|
|
34536
|
+
function clampDirectChatHistoryLimit(raw) {
|
|
34537
|
+
let n;
|
|
34538
|
+
if (typeof raw === "number") {
|
|
34539
|
+
n = raw;
|
|
34540
|
+
} else if (typeof raw === "string" && raw.trim() !== "") {
|
|
34541
|
+
n = Number(raw);
|
|
34542
|
+
} else {
|
|
34543
|
+
return DIRECT_CHAT_HISTORY_DEFAULT_LIMIT;
|
|
34544
|
+
}
|
|
34545
|
+
if (!Number.isFinite(n))
|
|
34546
|
+
return DIRECT_CHAT_HISTORY_DEFAULT_LIMIT;
|
|
34547
|
+
const floored = Math.floor(n);
|
|
34548
|
+
if (floored < 1)
|
|
34549
|
+
return 1;
|
|
34550
|
+
if (floored > DIRECT_CHAT_HISTORY_MAX_LIMIT)
|
|
34551
|
+
return DIRECT_CHAT_HISTORY_MAX_LIMIT;
|
|
34552
|
+
return floored;
|
|
34553
|
+
}
|
|
34554
|
+
|
|
35112
34555
|
// ../core/dist/onboarding/state-machine.js
|
|
35113
34556
|
var AREA_ORDER = [
|
|
35114
34557
|
"framing",
|
|
@@ -37929,47 +37372,658 @@ var FLAG_REGISTRY = [
|
|
|
37929
37372
|
// the literal truth here rather than the trap it is one flag above.
|
|
37930
37373
|
}
|
|
37931
37374
|
];
|
|
37932
|
-
var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
|
|
37375
|
+
var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
|
|
37376
|
+
|
|
37377
|
+
// ../core/dist/feature-flags/schema-version.js
|
|
37378
|
+
function projectDefinition(definition) {
|
|
37379
|
+
const parts = [
|
|
37380
|
+
`k=${definition.key}`,
|
|
37381
|
+
`t=${definition.flagType}`,
|
|
37382
|
+
`d=${String(definition.defaultValue)}`,
|
|
37383
|
+
`p=${definition.public === true ? 1 : 0}`,
|
|
37384
|
+
`s=${definition.sensitive === true ? 1 : 0}`
|
|
37385
|
+
];
|
|
37386
|
+
if (definition.flagType === "enum") {
|
|
37387
|
+
parts.push(`a=${[...definition.allowedValues].sort().join(",")}`);
|
|
37388
|
+
}
|
|
37389
|
+
return parts.join("|");
|
|
37390
|
+
}
|
|
37391
|
+
function fnv1aHex(input) {
|
|
37392
|
+
let hash = 2166136261;
|
|
37393
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
37394
|
+
hash ^= input.charCodeAt(i);
|
|
37395
|
+
hash = Math.imul(hash, 16777619) >>> 0;
|
|
37396
|
+
}
|
|
37397
|
+
return hash.toString(16).padStart(8, "0");
|
|
37398
|
+
}
|
|
37399
|
+
function computeFlagsSchemaVersion() {
|
|
37400
|
+
const canonical = [...FLAG_REGISTRY].map(projectDefinition).sort().join("\n");
|
|
37401
|
+
return `v1:${fnv1aHex(canonical)}`;
|
|
37402
|
+
}
|
|
37403
|
+
var FLAGS_SCHEMA_VERSION = computeFlagsSchemaVersion();
|
|
37404
|
+
|
|
37405
|
+
// ../core/dist/restart/breaker-thresholds.js
|
|
37406
|
+
var RESTART_BREAKER_PROVISIONING_MAX = 5;
|
|
37407
|
+
var BIND_FAILURE_QUARANTINE_THRESHOLD = deriveBindFailureQuarantineThreshold(RESTART_BREAKER_PROVISIONING_MAX);
|
|
37408
|
+
function deriveBindFailureQuarantineThreshold(provisioningMax) {
|
|
37409
|
+
return Math.max(2, provisioningMax - 2);
|
|
37410
|
+
}
|
|
37411
|
+
var MIN_PROVISIONING_MAX_FOR_QUARANTINE_ORDERING = BIND_FAILURE_QUARANTINE_THRESHOLD + 1;
|
|
37412
|
+
|
|
37413
|
+
// ../core/dist/restart/forced-update-deadline.js
|
|
37414
|
+
var FORCED_UPDATE_RELAX_AFTER_MS = 7 * 6e4;
|
|
37415
|
+
var FORCED_UPDATE_HARD_DEADLINE_MS = 15 * 6e4;
|
|
37416
|
+
|
|
37417
|
+
// src/direct-chat-history.ts
|
|
37418
|
+
var clampHistoryLimit = clampDirectChatHistoryLimit;
|
|
37419
|
+
function formatDirectChatMessages(messages) {
|
|
37420
|
+
return messages.map((m) => {
|
|
37421
|
+
const who = m.role === "assistant" ? "You" : m.role === "user" ? "User" : m.role;
|
|
37422
|
+
return `[${m.created_at}] ${who}: ${m.content}`;
|
|
37423
|
+
}).join("\n");
|
|
37424
|
+
}
|
|
37425
|
+
function parseHistoryResponse(input) {
|
|
37426
|
+
if (!input.httpOk) {
|
|
37427
|
+
const message = input.body && typeof input.body === "object" && "error" in input.body ? String(input.body.error) : `http_${input.status}`;
|
|
37428
|
+
return { ok: false, error: message };
|
|
37429
|
+
}
|
|
37430
|
+
if (!input.body || typeof input.body !== "object" || Array.isArray(input.body)) {
|
|
37431
|
+
return { ok: false, error: "malformed_response" };
|
|
37432
|
+
}
|
|
37433
|
+
const raw = input.body.messages;
|
|
37434
|
+
if (!Array.isArray(raw)) return { ok: false, error: "malformed_response" };
|
|
37435
|
+
const messages = [];
|
|
37436
|
+
for (const row of raw) {
|
|
37437
|
+
if (!row || typeof row !== "object") continue;
|
|
37438
|
+
const r = row;
|
|
37439
|
+
if (typeof r.content !== "string") continue;
|
|
37440
|
+
messages.push({
|
|
37441
|
+
role: typeof r.role === "string" ? r.role : "unknown",
|
|
37442
|
+
content: r.content,
|
|
37443
|
+
created_at: typeof r.created_at === "string" ? r.created_at : ""
|
|
37444
|
+
});
|
|
37445
|
+
}
|
|
37446
|
+
return { ok: true, count: messages.length, formatted: formatDirectChatMessages(messages) };
|
|
37447
|
+
}
|
|
37448
|
+
|
|
37449
|
+
// src/direct-chat-session-state.ts
|
|
37450
|
+
import { existsSync, readFileSync } from "fs";
|
|
37451
|
+
import { join } from "path";
|
|
37452
|
+
function readDirectChatSessionState(agentDir, nowMs) {
|
|
37453
|
+
const path = join(agentDir, "direct-chat-session.json");
|
|
37454
|
+
try {
|
|
37455
|
+
if (!existsSync(path)) return { fresh: false, startedAtMs: nowMs };
|
|
37456
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
37457
|
+
if (!parsed || typeof parsed !== "object") return { fresh: false, startedAtMs: nowMs };
|
|
37458
|
+
const o = parsed;
|
|
37459
|
+
const fresh = o.fresh === true;
|
|
37460
|
+
const startedAtMs = typeof o.startedAtMs === "number" && Number.isFinite(o.startedAtMs) ? o.startedAtMs : nowMs;
|
|
37461
|
+
return { fresh, startedAtMs };
|
|
37462
|
+
} catch {
|
|
37463
|
+
return { fresh: false, startedAtMs: nowMs };
|
|
37464
|
+
}
|
|
37465
|
+
}
|
|
37466
|
+
|
|
37467
|
+
// src/direct-chat-channel-meta.ts
|
|
37468
|
+
function buildDirectChatChannelMeta(input) {
|
|
37469
|
+
const identity = {};
|
|
37470
|
+
if (input.userName) identity.user_name = input.userName;
|
|
37471
|
+
if (input.userEmail) identity.user_email = input.userEmail;
|
|
37472
|
+
if (input.userRole) identity.user_role = input.userRole;
|
|
37473
|
+
const page = {};
|
|
37474
|
+
if (input.pageSlug) page.page_slug = input.pageSlug;
|
|
37475
|
+
if (input.pageTitle) page.page_title = input.pageTitle;
|
|
37476
|
+
if (input.pageUrl) page.page_url = input.pageUrl;
|
|
37477
|
+
if (input.pageContentUrl) page.page_content_url = input.pageContentUrl;
|
|
37478
|
+
if (input.pageArtefactId) page.page_artefact_id = input.pageArtefactId;
|
|
37479
|
+
if (input.pageGated != null) page.page_gated = input.pageGated ? "true" : "false";
|
|
37480
|
+
return {
|
|
37481
|
+
session_id: input.sessionId,
|
|
37482
|
+
user: "webapp",
|
|
37483
|
+
source: "direct-chat",
|
|
37484
|
+
...identity,
|
|
37485
|
+
...page,
|
|
37486
|
+
// String flag the agent's channel instructions (and the renderer) read:
|
|
37487
|
+
// 'false' = notice (do not reply), 'true' = normal message (reply expected).
|
|
37488
|
+
requires_reply: input.isNotice ? "false" : "true",
|
|
37489
|
+
// ENG-6407 / ADR-0024 Slice 1: provenance + reply-obligation as first-class
|
|
37490
|
+
// tag attributes. Direct chat is conversational; a notice owes no reply, so
|
|
37491
|
+
// expects_reply mirrors the existing requires_reply flag. Recorded only - no
|
|
37492
|
+
// consumer gates on these yet (Slice 2).
|
|
37493
|
+
lane: "conversational",
|
|
37494
|
+
expects_reply: input.isNotice ? "false" : "true"
|
|
37495
|
+
};
|
|
37496
|
+
}
|
|
37497
|
+
|
|
37498
|
+
// src/turn-initiator-marker.ts
|
|
37499
|
+
import { writeFileSync, readFileSync as readFileSync2, mkdirSync, renameSync } from "fs";
|
|
37500
|
+
import { dirname, join as join2 } from "path";
|
|
37501
|
+
var TURN_INITIATOR_MAX_AGE_MS = 5 * 60 * 1e3;
|
|
37502
|
+
var TURN_INITIATOR_LEDGER_MAX_ENTRIES = 20;
|
|
37503
|
+
var TURN_INITIATOR_LEDGER_FILENAME = ".turn-initiator-ledger.json";
|
|
37504
|
+
function turnInitiatorLedgerPath(singleSlotFile) {
|
|
37505
|
+
return join2(dirname(singleSlotFile), TURN_INITIATOR_LEDGER_FILENAME);
|
|
37506
|
+
}
|
|
37507
|
+
function foldTurnInitiatorLedger(existing, marker, maxAgeMs = TURN_INITIATOR_MAX_AGE_MS, maxEntries = TURN_INITIATOR_LEDGER_MAX_ENTRIES) {
|
|
37508
|
+
const now = marker.ts;
|
|
37509
|
+
const key = (e) => `${e.channel}\0${e.channel_ref ?? ""}`;
|
|
37510
|
+
const markerKey = key(marker);
|
|
37511
|
+
const prior = existing && Array.isArray(existing.entries) ? existing.entries : [];
|
|
37512
|
+
const kept = prior.filter(
|
|
37513
|
+
(e) => e && typeof e.ts === "number" && Number.isFinite(e.ts) && now - e.ts <= maxAgeMs && now - e.ts >= 0 && key(e) !== markerKey
|
|
37514
|
+
// the same thread is replaced by the new entry below
|
|
37515
|
+
);
|
|
37516
|
+
kept.push({
|
|
37517
|
+
channel: marker.channel,
|
|
37518
|
+
sender_id: marker.sender_id,
|
|
37519
|
+
...marker.sender_name ? { sender_name: marker.sender_name } : {},
|
|
37520
|
+
...marker.channel_ref ? { channel_ref: marker.channel_ref } : {},
|
|
37521
|
+
ts: marker.ts
|
|
37522
|
+
});
|
|
37523
|
+
kept.sort((a, b) => b.ts - a.ts);
|
|
37524
|
+
return { v: 1, entries: kept.slice(0, maxEntries) };
|
|
37525
|
+
}
|
|
37526
|
+
function updateTurnInitiatorLedger(singleSlotFile, marker) {
|
|
37527
|
+
const ledgerFile = turnInitiatorLedgerPath(singleSlotFile);
|
|
37528
|
+
let existing = null;
|
|
37529
|
+
try {
|
|
37530
|
+
const parsed = JSON.parse(readFileSync2(ledgerFile, "utf8"));
|
|
37531
|
+
if (parsed && parsed.v === 1 && Array.isArray(parsed.entries)) existing = parsed;
|
|
37532
|
+
} catch {
|
|
37533
|
+
}
|
|
37534
|
+
const next = foldTurnInitiatorLedger(existing, marker);
|
|
37535
|
+
const tmp = `${ledgerFile}.tmp`;
|
|
37536
|
+
writeFileSync(tmp, JSON.stringify(next), "utf8");
|
|
37537
|
+
renameSync(tmp, ledgerFile);
|
|
37538
|
+
}
|
|
37539
|
+
function writeTurnInitiatorMarker(input) {
|
|
37540
|
+
const file = process.env["AGT_TURN_INITIATOR_FILE"];
|
|
37541
|
+
if (!file || !input.sender_id) return;
|
|
37542
|
+
try {
|
|
37543
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
37544
|
+
const marker = { ...input, ts: Date.now() };
|
|
37545
|
+
const tmp = `${file}.tmp`;
|
|
37546
|
+
writeFileSync(tmp, JSON.stringify(marker), "utf8");
|
|
37547
|
+
renameSync(tmp, file);
|
|
37548
|
+
try {
|
|
37549
|
+
updateTurnInitiatorLedger(file, marker);
|
|
37550
|
+
} catch {
|
|
37551
|
+
}
|
|
37552
|
+
} catch {
|
|
37553
|
+
}
|
|
37554
|
+
}
|
|
37555
|
+
|
|
37556
|
+
// src/scheduled-turn-marker.ts
|
|
37557
|
+
import { readFileSync as readFileSync3, unlinkSync } from "fs";
|
|
37558
|
+
import { join as join3 } from "path";
|
|
37559
|
+
var SCHEDULED_TURN_MARKER_FILENAME2 = ".current-scheduled-turn.json";
|
|
37560
|
+
var SCHEDULED_TURN_MAX_AGE_MS = 15 * 60 * 1e3;
|
|
37561
|
+
function clearScheduledTurnMarker(agentDir) {
|
|
37562
|
+
if (!agentDir) return;
|
|
37563
|
+
try {
|
|
37564
|
+
unlinkSync(join3(agentDir, SCHEDULED_TURN_MARKER_FILENAME2));
|
|
37565
|
+
} catch {
|
|
37566
|
+
}
|
|
37567
|
+
}
|
|
37568
|
+
|
|
37569
|
+
// src/direct-chat-pending-inbound.ts
|
|
37570
|
+
import {
|
|
37571
|
+
existsSync as existsSync2,
|
|
37572
|
+
mkdirSync as mkdirSync2,
|
|
37573
|
+
readdirSync,
|
|
37574
|
+
readFileSync as readFileSync4,
|
|
37575
|
+
renameSync as renameSync2,
|
|
37576
|
+
unlinkSync as unlinkSync2,
|
|
37577
|
+
writeFileSync as writeFileSync2
|
|
37578
|
+
} from "fs";
|
|
37579
|
+
import { join as join4 } from "path";
|
|
37580
|
+
function hexEncodeSegment(value) {
|
|
37581
|
+
return Buffer.from(value, "utf8").toString("hex");
|
|
37582
|
+
}
|
|
37583
|
+
function directChatMarkerName(sessionId, messageId) {
|
|
37584
|
+
return `${hexEncodeSegment(sessionId)}__${hexEncodeSegment(messageId)}.json`;
|
|
37585
|
+
}
|
|
37586
|
+
var defaultClearMarkerFile = (fullPath) => {
|
|
37587
|
+
try {
|
|
37588
|
+
if (existsSync2(fullPath)) unlinkSync2(fullPath);
|
|
37589
|
+
} catch {
|
|
37590
|
+
}
|
|
37591
|
+
};
|
|
37592
|
+
function directChatInboundId(sessionId, messageId) {
|
|
37593
|
+
return `direct-chat|${sessionId.length}|${sessionId}|${messageId}`;
|
|
37594
|
+
}
|
|
37595
|
+
function writeDirectChatPendingInboundMarker(dir, sessionId, messageId) {
|
|
37596
|
+
if (!dir || !sessionId || !messageId) return;
|
|
37597
|
+
try {
|
|
37598
|
+
mkdirSync2(dir, { recursive: true });
|
|
37599
|
+
const marker = {
|
|
37600
|
+
channel: "direct-chat",
|
|
37601
|
+
session_id: sessionId,
|
|
37602
|
+
message_id: messageId,
|
|
37603
|
+
received_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
37604
|
+
inbound_id: directChatInboundId(sessionId, messageId)
|
|
37605
|
+
};
|
|
37606
|
+
const final = join4(dir, directChatMarkerName(sessionId, messageId));
|
|
37607
|
+
const tmp = `${final}.tmp`;
|
|
37608
|
+
writeFileSync2(tmp, JSON.stringify(marker), "utf8");
|
|
37609
|
+
renameSync2(tmp, final);
|
|
37610
|
+
} catch {
|
|
37611
|
+
}
|
|
37612
|
+
}
|
|
37613
|
+
function clearDirectChatPendingMarkersForSession(dir, sessionId, op = defaultClearMarkerFile) {
|
|
37614
|
+
if (!dir || !sessionId) return 0;
|
|
37615
|
+
const prefix = `${hexEncodeSegment(sessionId)}__`;
|
|
37616
|
+
let cleared = 0;
|
|
37617
|
+
let names;
|
|
37618
|
+
try {
|
|
37619
|
+
names = readdirSync(dir);
|
|
37620
|
+
} catch {
|
|
37621
|
+
return 0;
|
|
37622
|
+
}
|
|
37623
|
+
for (const name of names) {
|
|
37624
|
+
if (!name.startsWith(prefix) || !name.endsWith(".json")) continue;
|
|
37625
|
+
op(join4(dir, name));
|
|
37626
|
+
cleared += 1;
|
|
37627
|
+
}
|
|
37628
|
+
return cleared;
|
|
37629
|
+
}
|
|
37630
|
+
function readDirectChatPendingInboundMarker(dir, sessionId, messageId, readFileImpl = (path) => readFileSync4(path, "utf8")) {
|
|
37631
|
+
if (!dir || !sessionId || !messageId) return null;
|
|
37632
|
+
try {
|
|
37633
|
+
const raw = readFileImpl(join4(dir, directChatMarkerName(sessionId, messageId)));
|
|
37634
|
+
return JSON.parse(raw);
|
|
37635
|
+
} catch {
|
|
37636
|
+
return null;
|
|
37637
|
+
}
|
|
37638
|
+
}
|
|
37639
|
+
var MAX_REPORTED_ORPHANS = 20;
|
|
37640
|
+
function sweepAgedDirectChatMarkers(dir, deps) {
|
|
37641
|
+
const result = {
|
|
37642
|
+
cleared: 0,
|
|
37643
|
+
orphaned: 0,
|
|
37644
|
+
orphanedIdentities: [],
|
|
37645
|
+
orphanedTruncated: false
|
|
37646
|
+
};
|
|
37647
|
+
if (!dir) return result;
|
|
37648
|
+
let names;
|
|
37649
|
+
try {
|
|
37650
|
+
names = deps.readdir(dir);
|
|
37651
|
+
} catch {
|
|
37652
|
+
return result;
|
|
37653
|
+
}
|
|
37654
|
+
for (const name of names) {
|
|
37655
|
+
if (!name.endsWith(".json") || name.startsWith(".")) continue;
|
|
37656
|
+
const full = join4(dir, name);
|
|
37657
|
+
let marker;
|
|
37658
|
+
try {
|
|
37659
|
+
marker = JSON.parse(deps.readFile(full));
|
|
37660
|
+
} catch {
|
|
37661
|
+
continue;
|
|
37662
|
+
}
|
|
37663
|
+
if (!deps.isAged(marker.received_at)) continue;
|
|
37664
|
+
const undelivered = !deps.hasDelivery(marker.inbound_id);
|
|
37665
|
+
try {
|
|
37666
|
+
deps.unlink(full);
|
|
37667
|
+
} catch {
|
|
37668
|
+
continue;
|
|
37669
|
+
}
|
|
37670
|
+
result.cleared += 1;
|
|
37671
|
+
if (undelivered) {
|
|
37672
|
+
const identity = {
|
|
37673
|
+
inboundId: marker.inbound_id,
|
|
37674
|
+
receivedAt: marker.received_at,
|
|
37675
|
+
sessionId: marker.session_id
|
|
37676
|
+
};
|
|
37677
|
+
try {
|
|
37678
|
+
deps.onOrphaned(identity);
|
|
37679
|
+
} catch {
|
|
37680
|
+
}
|
|
37681
|
+
result.orphaned += 1;
|
|
37682
|
+
if (result.orphanedIdentities.length < MAX_REPORTED_ORPHANS) {
|
|
37683
|
+
result.orphanedIdentities.push(identity);
|
|
37684
|
+
} else {
|
|
37685
|
+
result.orphanedTruncated = true;
|
|
37686
|
+
}
|
|
37687
|
+
}
|
|
37688
|
+
}
|
|
37689
|
+
return result;
|
|
37690
|
+
}
|
|
37691
|
+
|
|
37692
|
+
// src/direct-chat-recovery-outbox.ts
|
|
37693
|
+
async function consumeDirectChatRecoveryFile(fullPath, filename, deps) {
|
|
37694
|
+
if (filename.endsWith(".tmp") || filename.endsWith(".poison")) return "skipped";
|
|
37695
|
+
let payload;
|
|
37696
|
+
try {
|
|
37697
|
+
payload = JSON.parse(deps.readFile(fullPath));
|
|
37698
|
+
} catch (err) {
|
|
37699
|
+
deps.log(`recovery outbox parse failed (${filename}): ${err.message}`);
|
|
37700
|
+
try {
|
|
37701
|
+
deps.renameFile(fullPath, `${fullPath}.parse-error.poison`);
|
|
37702
|
+
} catch {
|
|
37703
|
+
}
|
|
37704
|
+
return "poison";
|
|
37705
|
+
}
|
|
37706
|
+
if (!payload || !payload.session_id || !payload.text) {
|
|
37707
|
+
deps.log(`recovery outbox malformed (${filename}): missing session_id or text`);
|
|
37708
|
+
if (payload && payload.marker_name) {
|
|
37709
|
+
try {
|
|
37710
|
+
deps.removeLedgerEntry(payload.marker_name);
|
|
37711
|
+
} catch {
|
|
37712
|
+
}
|
|
37713
|
+
}
|
|
37714
|
+
try {
|
|
37715
|
+
deps.renameFile(fullPath, `${fullPath}.malformed.poison`);
|
|
37716
|
+
} catch {
|
|
37717
|
+
}
|
|
37718
|
+
return "poison";
|
|
37719
|
+
}
|
|
37720
|
+
const content = deps.sanitize(payload.text);
|
|
37721
|
+
const messageIds = deps.peekClaims(payload.session_id);
|
|
37722
|
+
let result;
|
|
37723
|
+
try {
|
|
37724
|
+
result = await deps.deliver({
|
|
37725
|
+
sessionId: payload.session_id,
|
|
37726
|
+
content,
|
|
37727
|
+
messageIds
|
|
37728
|
+
});
|
|
37729
|
+
} catch (err) {
|
|
37730
|
+
result = { ok: false, error: err.message };
|
|
37731
|
+
}
|
|
37732
|
+
if (result.ok && !result.error) {
|
|
37733
|
+
deps.clearClaims(payload.session_id, messageIds);
|
|
37734
|
+
deps.clearMarkers(payload.session_id);
|
|
37735
|
+
if (payload.marker_name) deps.removeLedgerEntry(payload.marker_name);
|
|
37736
|
+
try {
|
|
37737
|
+
deps.unlinkFile(fullPath);
|
|
37738
|
+
} catch {
|
|
37739
|
+
}
|
|
37740
|
+
deps.log(`ghost-reply recovery sent (session=${payload.session_id})`);
|
|
37741
|
+
return "delivered";
|
|
37742
|
+
}
|
|
37743
|
+
if (payload.marker_name) deps.removeLedgerEntry(payload.marker_name);
|
|
37744
|
+
try {
|
|
37745
|
+
deps.unlinkFile(fullPath);
|
|
37746
|
+
} catch {
|
|
37747
|
+
}
|
|
37748
|
+
deps.log(
|
|
37749
|
+
`ghost-reply recovery send failed (session=${payload.session_id}): ${result.error ?? "unknown"} - re-armed for retry`
|
|
37750
|
+
);
|
|
37751
|
+
return "failed";
|
|
37752
|
+
}
|
|
37753
|
+
|
|
37754
|
+
// src/inbound-delivery-ledger.ts
|
|
37755
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync5, renameSync as renameSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
37756
|
+
import { join as join5 } from "path";
|
|
37757
|
+
function safeInboundId(inboundId) {
|
|
37758
|
+
return inboundId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
37759
|
+
}
|
|
37760
|
+
var defaultDeps = {
|
|
37761
|
+
mkdir: (dir) => mkdirSync3(dir, { recursive: true }),
|
|
37762
|
+
writeFile: (path, data) => writeFileSync3(path, data, "utf8"),
|
|
37763
|
+
rename: (from, to) => renameSync3(from, to),
|
|
37764
|
+
readdir: (dir) => readdirSync2(dir),
|
|
37765
|
+
readFile: (path) => readFileSync5(path, "utf8"),
|
|
37766
|
+
exists: (path) => existsSync3(path)
|
|
37767
|
+
};
|
|
37768
|
+
function writeInboundDeliveryLedgerEntry(dir, record2, deps = defaultDeps) {
|
|
37769
|
+
if (!dir || !record2.inbound_id || !record2.conv_key) return;
|
|
37770
|
+
const safe = safeInboundId(record2.inbound_id);
|
|
37771
|
+
if (!safe || safe.includes("/") || safe.includes("\\") || safe.includes("..")) return;
|
|
37772
|
+
try {
|
|
37773
|
+
deps.mkdir(dir);
|
|
37774
|
+
const final = join5(dir, `${safe}.json`);
|
|
37775
|
+
const tmp = `${final}.tmp`;
|
|
37776
|
+
deps.writeFile(tmp, JSON.stringify(record2));
|
|
37777
|
+
deps.rename(tmp, final);
|
|
37778
|
+
} catch {
|
|
37779
|
+
}
|
|
37780
|
+
}
|
|
37781
|
+
function inboundDeliveryLedgerHas(dir, inboundId, deps = defaultDeps) {
|
|
37782
|
+
if (!dir || !inboundId) return false;
|
|
37783
|
+
const safe = safeInboundId(inboundId);
|
|
37784
|
+
if (!safe || safe.includes("/") || safe.includes("\\") || safe.includes("..")) return false;
|
|
37785
|
+
try {
|
|
37786
|
+
return deps.exists(join5(dir, `${safe}.json`));
|
|
37787
|
+
} catch {
|
|
37788
|
+
return false;
|
|
37789
|
+
}
|
|
37790
|
+
}
|
|
37791
|
+
|
|
37792
|
+
// src/ack-reaction.ts
|
|
37793
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
37794
|
+
import { join as join7 } from "path";
|
|
37795
|
+
|
|
37796
|
+
// src/flags-cache-read.ts
|
|
37797
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
|
|
37798
|
+
import { homedir } from "os";
|
|
37799
|
+
import { join as join6 } from "path";
|
|
37800
|
+
function defaultFlagsCachePath() {
|
|
37801
|
+
return join6(homedir(), ".augmented", "flags-cache.json");
|
|
37802
|
+
}
|
|
37803
|
+
function envBoolean(raw) {
|
|
37804
|
+
if (raw === void 0) return void 0;
|
|
37805
|
+
const v = raw.trim().toLowerCase();
|
|
37806
|
+
if (v === "") return void 0;
|
|
37807
|
+
if (v === "1" || v === "true" || v === "yes" || v === "on") return true;
|
|
37808
|
+
if (v === "0" || v === "false" || v === "no" || v === "off") return false;
|
|
37809
|
+
return void 0;
|
|
37810
|
+
}
|
|
37811
|
+
function cachedBoolean(key, path) {
|
|
37812
|
+
try {
|
|
37813
|
+
if (!existsSync4(path)) return void 0;
|
|
37814
|
+
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
37815
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
37816
|
+
const flags = parsed.flags;
|
|
37817
|
+
if (!flags || typeof flags !== "object") return void 0;
|
|
37818
|
+
const value = flags[key];
|
|
37819
|
+
return typeof value === "boolean" ? value : void 0;
|
|
37820
|
+
} catch {
|
|
37821
|
+
return void 0;
|
|
37822
|
+
}
|
|
37823
|
+
}
|
|
37824
|
+
function resolveHostBooleanFlag(opts) {
|
|
37825
|
+
const env2 = opts.env ?? process.env;
|
|
37826
|
+
const envValue = envBoolean(env2[opts.envVar]);
|
|
37827
|
+
if (envValue !== void 0) return envValue;
|
|
37828
|
+
const cached2 = cachedBoolean(opts.key, opts.cachePath ?? defaultFlagsCachePath());
|
|
37829
|
+
if (cached2 !== void 0) return cached2;
|
|
37830
|
+
return opts.defaultValue;
|
|
37831
|
+
}
|
|
37832
|
+
|
|
37833
|
+
// ../core/dist/channels/deflection-causes.js
|
|
37834
|
+
var DEFLECTION_CAUSES = [
|
|
37835
|
+
"integration_down",
|
|
37836
|
+
"session_dead",
|
|
37837
|
+
"wedged",
|
|
37838
|
+
"busy",
|
|
37839
|
+
"duplicate",
|
|
37840
|
+
// ENG-8387: an `app_mention` — the CANONICAL delivery of an @mention — dropped
|
|
37841
|
+
// by the fresh-ingress dedup. Split out of the generic `duplicate` bucket
|
|
37842
|
+
// because the two mean very different things: `duplicate` is dominated by the
|
|
37843
|
+
// deliberate, high-volume ENG-6378 echo drop and by routine reconnect
|
|
37844
|
+
// redelivery, both benign, while a dropped app_mention has the exact shape of
|
|
37845
|
+
// a lost mention. Conflated, the second is invisible inside the first — which
|
|
37846
|
+
// is how ENG-6378's silent loss ran unobserved.
|
|
37847
|
+
"duplicate_mention",
|
|
37848
|
+
"mention_echo_orphan",
|
|
37849
|
+
"replay_orphaned",
|
|
37850
|
+
"replay_exhausted",
|
|
37851
|
+
// ENG-9414 — see the type union above for why these two exist. Both are
|
|
37852
|
+
// message-loss classes the pre-existing causes were structurally unable to
|
|
37853
|
+
// observe, which is why four destroyed customer inbounds in one hour
|
|
37854
|
+
// produced zero alerts.
|
|
37855
|
+
"aged_out_unrecoverable",
|
|
37856
|
+
"marker_corrupt",
|
|
37857
|
+
"unknown"
|
|
37858
|
+
];
|
|
37859
|
+
var DEFLECTION_CAUSE_SET = new Set(DEFLECTION_CAUSES);
|
|
37933
37860
|
|
|
37934
|
-
//
|
|
37935
|
-
|
|
37936
|
-
|
|
37937
|
-
|
|
37938
|
-
|
|
37939
|
-
|
|
37940
|
-
|
|
37941
|
-
|
|
37942
|
-
|
|
37943
|
-
if (
|
|
37944
|
-
|
|
37861
|
+
// src/ack-reaction.ts
|
|
37862
|
+
var REPLY_WEDGED_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
37863
|
+
var ACK_PANE_FRESH_THRESHOLD_MS = 6e4;
|
|
37864
|
+
function classifyUndeliverableCause(i) {
|
|
37865
|
+
if (!i.hasTarget) return null;
|
|
37866
|
+
if (!i.integrationReady) return "integration_down";
|
|
37867
|
+
if (i.tmux === "dead") return "session_dead";
|
|
37868
|
+
if (!i.withinStartupGrace && i.claude === "dead") return "session_dead";
|
|
37869
|
+
const threshold = i.pendingStaleThresholdMs ?? REPLY_WEDGED_THRESHOLD_MS;
|
|
37870
|
+
if (i.oldestPendingAgeMs != null && i.oldestPendingAgeMs > threshold) {
|
|
37871
|
+
const paneFreshThreshold = i.paneFreshThresholdMs ?? ACK_PANE_FRESH_THRESHOLD_MS;
|
|
37872
|
+
const paneIsFresh = i.paneLogFreshAgeMs != null && i.paneLogFreshAgeMs <= paneFreshThreshold;
|
|
37873
|
+
if (paneIsFresh && i.tmux === "alive" && i.claude === "alive") {
|
|
37874
|
+
return null;
|
|
37875
|
+
}
|
|
37876
|
+
return "wedged";
|
|
37945
37877
|
}
|
|
37946
|
-
return
|
|
37878
|
+
return null;
|
|
37947
37879
|
}
|
|
37948
|
-
|
|
37949
|
-
|
|
37950
|
-
|
|
37951
|
-
|
|
37952
|
-
|
|
37880
|
+
var UNDELIVERABLE_NOTICE_THROTTLE_MS = 5 * 60 * 1e3;
|
|
37881
|
+
function shouldPostUndeliverableNotice(lastNoticeAtMs, nowMs, throttleMs = UNDELIVERABLE_NOTICE_THROTTLE_MS) {
|
|
37882
|
+
return lastNoticeAtMs == null || nowMs - lastNoticeAtMs >= throttleMs;
|
|
37883
|
+
}
|
|
37884
|
+
function undeliverableNoticeText(replay) {
|
|
37885
|
+
const honest = noticePromiseIsHonest(replay);
|
|
37886
|
+
return honest ? "\u23F3 I can't get to this right now \u2014 no need to resend; I'll pick it up automatically as soon as I'm free." : "\u23F3 I can't get to this right now. Please resend in a few minutes \u2014 I may not see this one.";
|
|
37887
|
+
}
|
|
37888
|
+
function undeliverableNoticeTextForRepeat(i) {
|
|
37889
|
+
if (i.priorNotices <= 0) return undeliverableNoticeText(i.replay);
|
|
37890
|
+
if (i.priorNotices === 1) {
|
|
37891
|
+
return noticePromiseIsHonest(i.replay) ? "\u23F3 Still stuck on this one \u2014 the automatic pickup I mentioned has not happened. Please resend when you can." : "\u23F3 Still stuck on this one, and I still have not picked it up. Resending is the reliable way through.";
|
|
37953
37892
|
}
|
|
37954
|
-
return
|
|
37893
|
+
return null;
|
|
37955
37894
|
}
|
|
37956
|
-
function
|
|
37957
|
-
|
|
37958
|
-
|
|
37895
|
+
function noticePromiseIsHonest(replay) {
|
|
37896
|
+
if (replay === void 0) return false;
|
|
37897
|
+
if (typeof replay === "boolean") return replay;
|
|
37898
|
+
return markerReplayable({
|
|
37899
|
+
enabled: replay.enabled ?? channelReplayEnabled(),
|
|
37900
|
+
hasPayload: replay.hasPayload,
|
|
37901
|
+
discretionary: replay.discretionary
|
|
37902
|
+
});
|
|
37959
37903
|
}
|
|
37960
|
-
var
|
|
37961
|
-
|
|
37962
|
-
|
|
37963
|
-
|
|
37964
|
-
|
|
37965
|
-
|
|
37966
|
-
|
|
37904
|
+
var BUSY_ACK_THRESHOLD_MS = 12e4;
|
|
37905
|
+
var BUSY_ACK_NOTICE_THROTTLE_MS = 20 * 60 * 1e3;
|
|
37906
|
+
function channelBusyAckEnabled() {
|
|
37907
|
+
return resolveHostBooleanFlag({
|
|
37908
|
+
key: "channel-busy-ack",
|
|
37909
|
+
envVar: "AGT_CHANNEL_BUSY_ACK_ENABLED",
|
|
37910
|
+
defaultValue: false
|
|
37911
|
+
});
|
|
37912
|
+
}
|
|
37913
|
+
function channelBusyAckThresholdMs() {
|
|
37914
|
+
const raw = parseInt(process.env.AGT_CHANNEL_BUSY_ACK_THRESHOLD_MS ?? "", 10);
|
|
37915
|
+
return Number.isFinite(raw) && raw > 0 ? raw : BUSY_ACK_THRESHOLD_MS;
|
|
37916
|
+
}
|
|
37917
|
+
function decideBusyAck(i) {
|
|
37918
|
+
if (!i.hasTarget) return false;
|
|
37919
|
+
if (!i.arrivedWhileBusy) return false;
|
|
37920
|
+
if (!i.stillPending) return false;
|
|
37921
|
+
if (!Number.isFinite(i.pendingAgeMs)) return false;
|
|
37922
|
+
const threshold = i.thresholdMs ?? channelBusyAckThresholdMs();
|
|
37923
|
+
if (i.pendingAgeMs < threshold) return false;
|
|
37924
|
+
if (!i.sessionAlive) return false;
|
|
37925
|
+
const paneFreshThreshold = i.paneFreshThresholdMs ?? ACK_PANE_FRESH_THRESHOLD_MS;
|
|
37926
|
+
return i.paneLogFreshAgeMs != null && i.paneLogFreshAgeMs <= paneFreshThreshold;
|
|
37927
|
+
}
|
|
37928
|
+
function busyAckNoticeText() {
|
|
37929
|
+
return "\u{1F6E0}\uFE0F I'm in the middle of something right now \u2014 I'll follow up on this as soon as I'm free.";
|
|
37930
|
+
}
|
|
37931
|
+
var GIVE_UP_SIGNAL_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
37932
|
+
function turnFailedNoticeText(failureClass) {
|
|
37933
|
+
const cause = failureClass === "overloaded" ? "the service I run on is overloaded right now \u2014 nothing to do with you or what you asked for" : failureClass === "server_error" ? "something upstream of me is failing right now \u2014 nothing to do with you or what you asked for" : null;
|
|
37934
|
+
if (cause === null) {
|
|
37935
|
+
return "\u26A0\uFE0F Something went wrong on my side and I couldn\u2019t finish that. Sorry \u2014 send it again when you get a chance and I\u2019ll pick it straight up.";
|
|
37936
|
+
}
|
|
37937
|
+
return `\u26A0\uFE0F I couldn\u2019t finish that \u2014 ${cause}. Sorry \u2014 send it again when you get a chance and I\u2019ll pick it straight up.`;
|
|
37938
|
+
}
|
|
37939
|
+
function oldestPendingMarkerAgeMs(dir, now = Date.now(), opts) {
|
|
37940
|
+
if (!dir) return null;
|
|
37941
|
+
let names;
|
|
37942
|
+
try {
|
|
37943
|
+
names = readdirSync3(dir);
|
|
37944
|
+
} catch {
|
|
37945
|
+
return null;
|
|
37946
|
+
}
|
|
37947
|
+
let oldest = null;
|
|
37948
|
+
for (const name of names) {
|
|
37949
|
+
if (!name.endsWith(".json")) continue;
|
|
37950
|
+
let receivedAt;
|
|
37951
|
+
try {
|
|
37952
|
+
const raw = JSON.parse(readFileSync7(join7(dir, name), "utf-8"));
|
|
37953
|
+
if (raw.discretionary === true) continue;
|
|
37954
|
+
if (!opts?.includeSeen && typeof raw.seen_at === "string" && raw.seen_at) continue;
|
|
37955
|
+
receivedAt = raw.received_at;
|
|
37956
|
+
} catch {
|
|
37957
|
+
continue;
|
|
37958
|
+
}
|
|
37959
|
+
if (!receivedAt) continue;
|
|
37960
|
+
const t = Date.parse(receivedAt);
|
|
37961
|
+
if (Number.isNaN(t)) continue;
|
|
37962
|
+
const age = now - t;
|
|
37963
|
+
if (age < 0) continue;
|
|
37964
|
+
if (oldest == null || age > oldest) oldest = age;
|
|
37965
|
+
}
|
|
37966
|
+
return oldest;
|
|
37967
|
+
}
|
|
37968
|
+
function hasInFlightInbound(dir, now = Date.now()) {
|
|
37969
|
+
return oldestPendingMarkerAgeMs(dir, now, { includeSeen: true }) != null;
|
|
37970
|
+
}
|
|
37971
|
+
function channelOrphanMarkerMs() {
|
|
37972
|
+
const raw = parseInt(process.env.AGT_CHANNEL_ORPHAN_MARKER_MS ?? "", 10);
|
|
37973
|
+
return Number.isFinite(raw) && raw > 0 ? Math.max(raw, 12e4) : 30 * 6e4;
|
|
37974
|
+
}
|
|
37975
|
+
var ORPHAN_SWEEP_INTERVAL_MS = 30 * 60 * 1e3;
|
|
37976
|
+
function orphanSweepIntervalMs() {
|
|
37977
|
+
return Math.max(6e4, Math.min(ORPHAN_SWEEP_INTERVAL_MS, channelOrphanMarkerMs()));
|
|
37978
|
+
}
|
|
37979
|
+
var PANE_FRESH_DEFER_MAX_MS = 10 * 60 * 1e3;
|
|
37980
|
+
function channelReplayEnabled() {
|
|
37981
|
+
return resolveHostBooleanFlag({
|
|
37982
|
+
key: "channel-replay",
|
|
37983
|
+
envVar: "AGT_CHANNEL_REPLAY_ENABLED",
|
|
37984
|
+
defaultValue: true
|
|
37985
|
+
});
|
|
37986
|
+
}
|
|
37987
|
+
function combineMarkerReplayFacts(markers) {
|
|
37988
|
+
if (markers.length === 0) return null;
|
|
37989
|
+
return {
|
|
37990
|
+
hasPayload: markers.every((m) => m.hasPayload),
|
|
37991
|
+
discretionary: markers.some((m) => m.discretionary === true)
|
|
37992
|
+
};
|
|
37993
|
+
}
|
|
37994
|
+
function markerReplayable(i) {
|
|
37995
|
+
if (!i.enabled) return false;
|
|
37996
|
+
if (!i.hasPayload) return false;
|
|
37997
|
+
if (i.discretionary) return false;
|
|
37998
|
+
return true;
|
|
37999
|
+
}
|
|
38000
|
+
function isMarkerGenuinelyAged(receivedAt, nowMs, thresholdMs) {
|
|
38001
|
+
const t = Date.parse(receivedAt ?? "");
|
|
38002
|
+
return Number.isFinite(t) && t <= nowMs && nowMs - t >= thresholdMs;
|
|
38003
|
+
}
|
|
38004
|
+
var DEFLECTION_COUNTER_SUFFIX = "-deflections.json";
|
|
38005
|
+
function deflectionCounterPath(agentDir, channel) {
|
|
38006
|
+
return join7(agentDir, `${channel}${DEFLECTION_COUNTER_SUFFIX}`);
|
|
38007
|
+
}
|
|
38008
|
+
function recordChannelDeflection(agentDir, channel, cause) {
|
|
38009
|
+
if (!agentDir) return;
|
|
38010
|
+
const path = deflectionCounterPath(agentDir, channel);
|
|
38011
|
+
let counts = {};
|
|
38012
|
+
try {
|
|
38013
|
+
const parsed = JSON.parse(readFileSync7(path, "utf-8"));
|
|
38014
|
+
if (parsed && typeof parsed === "object") counts = parsed;
|
|
38015
|
+
} catch {
|
|
38016
|
+
}
|
|
38017
|
+
counts[cause] = (counts[cause] ?? 0) + 1;
|
|
38018
|
+
try {
|
|
38019
|
+
writeFileSync4(path, JSON.stringify(counts), { mode: 384 });
|
|
38020
|
+
} catch {
|
|
38021
|
+
}
|
|
37967
38022
|
}
|
|
37968
|
-
var MIN_PROVISIONING_MAX_FOR_QUARANTINE_ORDERING = BIND_FAILURE_QUARANTINE_THRESHOLD + 1;
|
|
37969
38023
|
|
|
37970
|
-
//
|
|
37971
|
-
|
|
37972
|
-
|
|
38024
|
+
// src/turn-failure-watch.ts
|
|
38025
|
+
import { readdirSync as readdirSync5, statSync as statSync2 } from "fs";
|
|
38026
|
+
import { join as join9 } from "path";
|
|
37973
38027
|
|
|
37974
38028
|
// src/rate-limit-watch.ts
|
|
37975
38029
|
import { closeSync, fstatSync, openSync, readSync, readdirSync as readdirSync4, statSync } from "fs";
|
|
@@ -39540,6 +39594,31 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
39540
39594
|
},
|
|
39541
39595
|
required: ["session_id"]
|
|
39542
39596
|
}
|
|
39597
|
+
},
|
|
39598
|
+
{
|
|
39599
|
+
// ENG-9797. The direct-chat half of ENG-9693: agents were told to re-read
|
|
39600
|
+
// a Slack thread when they lose the trail, and told that direct chat had
|
|
39601
|
+
// no way to do it. It does now.
|
|
39602
|
+
//
|
|
39603
|
+
// READ-ONLY, so it is deliberately absent from DIRECT_CHAT_EGRESS_TOOLS —
|
|
39604
|
+
// an impersonating operator may read a conversation back; what they may
|
|
39605
|
+
// not do is speak in it.
|
|
39606
|
+
name: "direct_chat.read_history",
|
|
39607
|
+
description: 'Re-read this direct-chat conversation from the beginning. Use it when the trail matters and you cannot see it: the user says "as I mentioned" or "like we discussed", a decision was made earlier and you are about to re-ask it, or a message arrives replayed="true" and you cannot recall the original. Making someone repeat themselves reads as not listening. Returns the stored turns oldest-to-newest for the session_id in the <channel> tag; it can only read conversations that belong to you.',
|
|
39608
|
+
inputSchema: {
|
|
39609
|
+
type: "object",
|
|
39610
|
+
properties: {
|
|
39611
|
+
session_id: {
|
|
39612
|
+
type: "string",
|
|
39613
|
+
description: "Session ID (from the session_id attribute in the <channel> tag)"
|
|
39614
|
+
},
|
|
39615
|
+
limit: {
|
|
39616
|
+
type: "number",
|
|
39617
|
+
description: `How many of the most recent messages to return (default ${DIRECT_CHAT_HISTORY_DEFAULT_LIMIT}, max ${DIRECT_CHAT_HISTORY_MAX_LIMIT}). The transcript still reads oldest-to-newest.`
|
|
39618
|
+
}
|
|
39619
|
+
},
|
|
39620
|
+
required: ["session_id"]
|
|
39621
|
+
}
|
|
39543
39622
|
}
|
|
39544
39623
|
]
|
|
39545
39624
|
}));
|
|
@@ -39735,6 +39814,44 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
39735
39814
|
};
|
|
39736
39815
|
}
|
|
39737
39816
|
}
|
|
39817
|
+
if (name === "direct_chat.read_history") {
|
|
39818
|
+
const { session_id, limit: rawLimit } = args;
|
|
39819
|
+
const limit = clampHistoryLimit(rawLimit);
|
|
39820
|
+
try {
|
|
39821
|
+
const res = await apiPost("/host/direct-chat/history", {
|
|
39822
|
+
agent_id: AGT_AGENT_ID,
|
|
39823
|
+
session_id,
|
|
39824
|
+
limit
|
|
39825
|
+
});
|
|
39826
|
+
let body = null;
|
|
39827
|
+
try {
|
|
39828
|
+
body = await res.json();
|
|
39829
|
+
} catch {
|
|
39830
|
+
}
|
|
39831
|
+
const result = parseHistoryResponse({ httpOk: res.ok, status: res.status, body });
|
|
39832
|
+
if (!result.ok) {
|
|
39833
|
+
return {
|
|
39834
|
+
content: [{ type: "text", text: `Could not read the conversation: ${result.error}` }],
|
|
39835
|
+
isError: true
|
|
39836
|
+
};
|
|
39837
|
+
}
|
|
39838
|
+
return {
|
|
39839
|
+
content: [
|
|
39840
|
+
{
|
|
39841
|
+
type: "text",
|
|
39842
|
+
text: result.count > 0 ? `Direct chat history (${result.count} messages, oldest\u2192newest):
|
|
39843
|
+
|
|
39844
|
+
${result.formatted}` : "No stored messages for this conversation yet."
|
|
39845
|
+
}
|
|
39846
|
+
]
|
|
39847
|
+
};
|
|
39848
|
+
} catch (err) {
|
|
39849
|
+
return {
|
|
39850
|
+
content: [{ type: "text", text: `Failed: ${err.message}` }],
|
|
39851
|
+
isError: true
|
|
39852
|
+
};
|
|
39853
|
+
}
|
|
39854
|
+
}
|
|
39738
39855
|
throw new Error(`Unknown tool: ${name}`);
|
|
39739
39856
|
});
|
|
39740
39857
|
await mcp.connect(new StdioServerTransport());
|