@integrity-labs/agt-cli 0.28.457 → 0.28.459
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/agt.js +4 -4
- package/dist/{chunk-QFBCK4ZH.js → chunk-BWH5XTDU.js} +55 -7
- package/dist/chunk-BWH5XTDU.js.map +1 -0
- package/dist/{chunk-WMGMLOPB.js → chunk-PKZMFA2U.js} +60 -22
- package/dist/{chunk-WMGMLOPB.js.map → chunk-PKZMFA2U.js.map} +1 -1
- package/dist/{claude-pair-runtime-QNOUSTW3.js → claude-pair-runtime-YNOY2ATX.js} +2 -2
- package/dist/lib/manager-worker.js +24 -11
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/direct-chat-channel.js +1134 -772
- package/dist/mcp/origami.js +27 -1
- package/dist/mcp/slack-channel.js +555 -139
- package/dist/mcp/telegram-channel.js +498 -94
- package/dist/{persistent-session-LEWM6BKO.js → persistent-session-KGRCIIS5.js} +2 -2
- package/dist/{responsiveness-probe-U6DPVIDD.js → responsiveness-probe-4FVGB6NY.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-QFBCK4ZH.js.map +0 -1
- /package/dist/{claude-pair-runtime-QNOUSTW3.js.map → claude-pair-runtime-YNOY2ATX.js.map} +0 -0
- /package/dist/{persistent-session-LEWM6BKO.js.map → persistent-session-KGRCIIS5.js.map} +0 -0
- /package/dist/{responsiveness-probe-U6DPVIDD.js.map → responsiveness-probe-4FVGB6NY.js.map} +0 -0
|
@@ -18906,7 +18906,7 @@ var require_filters = __commonJS({
|
|
|
18906
18906
|
return r.copySafeness(str, res);
|
|
18907
18907
|
}
|
|
18908
18908
|
_exports.indent = indent;
|
|
18909
|
-
function
|
|
18909
|
+
function join22(arr, del, attr) {
|
|
18910
18910
|
del = del || "";
|
|
18911
18911
|
if (attr) {
|
|
18912
18912
|
arr = lib.map(arr, function(v) {
|
|
@@ -18915,7 +18915,7 @@ var require_filters = __commonJS({
|
|
|
18915
18915
|
}
|
|
18916
18916
|
return arr.join(del);
|
|
18917
18917
|
}
|
|
18918
|
-
_exports.join =
|
|
18918
|
+
_exports.join = join22;
|
|
18919
18919
|
function last(arr) {
|
|
18920
18920
|
return arr[arr.length - 1];
|
|
18921
18921
|
}
|
|
@@ -22516,11 +22516,11 @@ async function waitForResolution(cfg, callbackId, opts) {
|
|
|
22516
22516
|
}
|
|
22517
22517
|
} catch {
|
|
22518
22518
|
}
|
|
22519
|
-
await
|
|
22519
|
+
await sleep3(interval);
|
|
22520
22520
|
}
|
|
22521
22521
|
return { kind: "timeout" };
|
|
22522
22522
|
}
|
|
22523
|
-
function
|
|
22523
|
+
function sleep3(ms) {
|
|
22524
22524
|
return new Promise((r) => setTimeout(r, ms));
|
|
22525
22525
|
}
|
|
22526
22526
|
function generateOptionToken() {
|
|
@@ -34052,6 +34052,160 @@ function classifyTranscriptRateLimit(jsonl, startMs, endMs, now) {
|
|
|
34052
34052
|
return newest;
|
|
34053
34053
|
}
|
|
34054
34054
|
|
|
34055
|
+
// ../core/dist/claude-code-usage/turn-failure-classifier.js
|
|
34056
|
+
var UNKNOWN_TURN_FAILURE = Object.freeze({
|
|
34057
|
+
outcome: "unknown",
|
|
34058
|
+
atMs: null,
|
|
34059
|
+
failureClass: null,
|
|
34060
|
+
httpStatus: null,
|
|
34061
|
+
attempt: null,
|
|
34062
|
+
maxAttempts: null
|
|
34063
|
+
});
|
|
34064
|
+
var EXCLUDED_STATUSES = /* @__PURE__ */ new Set([429]);
|
|
34065
|
+
function classifyTransientStatus(status) {
|
|
34066
|
+
if (!Number.isFinite(status))
|
|
34067
|
+
return null;
|
|
34068
|
+
if (EXCLUDED_STATUSES.has(status))
|
|
34069
|
+
return null;
|
|
34070
|
+
if (status === 529)
|
|
34071
|
+
return "overloaded";
|
|
34072
|
+
if (status >= 500 && status <= 599)
|
|
34073
|
+
return "server_error";
|
|
34074
|
+
return null;
|
|
34075
|
+
}
|
|
34076
|
+
function numberOrNull(value) {
|
|
34077
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
34078
|
+
}
|
|
34079
|
+
function isErrorShaped(record2) {
|
|
34080
|
+
if (record2.isApiErrorMessage === true)
|
|
34081
|
+
return true;
|
|
34082
|
+
if (record2.type === "system" && record2.level === "error")
|
|
34083
|
+
return true;
|
|
34084
|
+
if (record2.type === "assistant" && typeof record2.error === "string" && record2.error)
|
|
34085
|
+
return true;
|
|
34086
|
+
return false;
|
|
34087
|
+
}
|
|
34088
|
+
function classifyRecord(record2, tsMs) {
|
|
34089
|
+
if (record2.isSidechain === true)
|
|
34090
|
+
return null;
|
|
34091
|
+
if (record2.type === "system" && record2.subtype === "api_error") {
|
|
34092
|
+
const error2 = record2.error;
|
|
34093
|
+
const status = typeof error2 === "object" && error2 !== null ? numberOrNull(error2.status) : null;
|
|
34094
|
+
if (status === null)
|
|
34095
|
+
return null;
|
|
34096
|
+
const failureClass = classifyTransientStatus(status);
|
|
34097
|
+
if (!failureClass)
|
|
34098
|
+
return null;
|
|
34099
|
+
return {
|
|
34100
|
+
outcome: "retrying",
|
|
34101
|
+
atMs: tsMs,
|
|
34102
|
+
failureClass,
|
|
34103
|
+
httpStatus: status,
|
|
34104
|
+
attempt: numberOrNull(record2.retryAttempt),
|
|
34105
|
+
maxAttempts: numberOrNull(record2.maxRetries)
|
|
34106
|
+
};
|
|
34107
|
+
}
|
|
34108
|
+
if (record2.type !== "assistant")
|
|
34109
|
+
return null;
|
|
34110
|
+
if (record2.isApiErrorMessage === true) {
|
|
34111
|
+
const status = numberOrNull(record2.apiErrorStatus);
|
|
34112
|
+
const failureClass = status === null ? null : classifyTransientStatus(status);
|
|
34113
|
+
if (!failureClass)
|
|
34114
|
+
return null;
|
|
34115
|
+
return {
|
|
34116
|
+
outcome: "failed",
|
|
34117
|
+
atMs: tsMs,
|
|
34118
|
+
failureClass,
|
|
34119
|
+
httpStatus: status,
|
|
34120
|
+
attempt: null,
|
|
34121
|
+
maxAttempts: null
|
|
34122
|
+
};
|
|
34123
|
+
}
|
|
34124
|
+
const message = record2.message;
|
|
34125
|
+
if (typeof message !== "object" || message === null)
|
|
34126
|
+
return null;
|
|
34127
|
+
const msg = message;
|
|
34128
|
+
if (msg.model === "<synthetic>")
|
|
34129
|
+
return null;
|
|
34130
|
+
const usage = msg.usage;
|
|
34131
|
+
if (typeof usage !== "object" || usage === null)
|
|
34132
|
+
return null;
|
|
34133
|
+
const u = usage;
|
|
34134
|
+
const spent = Number(u.input_tokens ?? 0) + Number(u.output_tokens ?? 0) + Number(u.cache_creation_input_tokens ?? 0) + Number(u.cache_read_input_tokens ?? 0);
|
|
34135
|
+
if (!Number.isFinite(spent) || spent <= 0)
|
|
34136
|
+
return null;
|
|
34137
|
+
return {
|
|
34138
|
+
outcome: "served",
|
|
34139
|
+
atMs: tsMs,
|
|
34140
|
+
failureClass: null,
|
|
34141
|
+
httpStatus: null,
|
|
34142
|
+
attempt: null,
|
|
34143
|
+
maxAttempts: null
|
|
34144
|
+
};
|
|
34145
|
+
}
|
|
34146
|
+
function pickNewerTurnFailure(current, next) {
|
|
34147
|
+
if (next.outcome === "unknown")
|
|
34148
|
+
return current;
|
|
34149
|
+
if (current.outcome === "unknown")
|
|
34150
|
+
return next;
|
|
34151
|
+
return (next.atMs ?? 0) >= (current.atMs ?? 0) ? next : current;
|
|
34152
|
+
}
|
|
34153
|
+
function isShapeRecognised(record2) {
|
|
34154
|
+
if (record2.type === "system" && record2.subtype === "api_error") {
|
|
34155
|
+
const error2 = record2.error;
|
|
34156
|
+
return typeof error2 === "object" && error2 !== null && numberOrNull(error2.status) !== null;
|
|
34157
|
+
}
|
|
34158
|
+
if (record2.type === "assistant" && record2.isApiErrorMessage === true) {
|
|
34159
|
+
return numberOrNull(record2.apiErrorStatus) !== null;
|
|
34160
|
+
}
|
|
34161
|
+
return false;
|
|
34162
|
+
}
|
|
34163
|
+
function analyzeTranscriptTurnFailure(jsonl, startMs, endMs, opts = {}) {
|
|
34164
|
+
const maxKeys = opts.maxKeys ?? 40;
|
|
34165
|
+
let newest = UNKNOWN_TURN_FAILURE;
|
|
34166
|
+
let coarse = 0;
|
|
34167
|
+
let fine = 0;
|
|
34168
|
+
const keys = /* @__PURE__ */ new Set();
|
|
34169
|
+
for (const line of jsonl.split("\n")) {
|
|
34170
|
+
const trimmed = line.trim();
|
|
34171
|
+
if (!trimmed)
|
|
34172
|
+
continue;
|
|
34173
|
+
let obj;
|
|
34174
|
+
try {
|
|
34175
|
+
obj = JSON.parse(trimmed);
|
|
34176
|
+
} catch {
|
|
34177
|
+
continue;
|
|
34178
|
+
}
|
|
34179
|
+
if (typeof obj !== "object" || obj === null)
|
|
34180
|
+
continue;
|
|
34181
|
+
const record2 = obj;
|
|
34182
|
+
const ts = record2.timestamp;
|
|
34183
|
+
if (typeof ts !== "string" || !ts)
|
|
34184
|
+
continue;
|
|
34185
|
+
const tsMs = new Date(ts).getTime();
|
|
34186
|
+
if (!Number.isFinite(tsMs) || tsMs < startMs || tsMs > endMs)
|
|
34187
|
+
continue;
|
|
34188
|
+
const classified = classifyRecord(record2, tsMs);
|
|
34189
|
+
if (classified)
|
|
34190
|
+
newest = pickNewerTurnFailure(newest, classified);
|
|
34191
|
+
if (!isErrorShaped(record2) || record2.isSidechain === true)
|
|
34192
|
+
continue;
|
|
34193
|
+
coarse++;
|
|
34194
|
+
if (isShapeRecognised(record2)) {
|
|
34195
|
+
fine++;
|
|
34196
|
+
continue;
|
|
34197
|
+
}
|
|
34198
|
+
if (keys.size < maxKeys) {
|
|
34199
|
+
for (const key2 of Object.keys(record2)) {
|
|
34200
|
+
if (keys.size >= maxKeys)
|
|
34201
|
+
break;
|
|
34202
|
+
keys.add(key2);
|
|
34203
|
+
}
|
|
34204
|
+
}
|
|
34205
|
+
}
|
|
34206
|
+
return { result: newest, coarse, fine, unrecognisedKeys: [...keys].sort() };
|
|
34207
|
+
}
|
|
34208
|
+
|
|
34055
34209
|
// ../core/dist/claude-code-usage/transcript-location.js
|
|
34056
34210
|
function encodeClaudeProjectPath(projectDir) {
|
|
34057
34211
|
return "-" + projectDir.replace(/^\//, "").replace(/[/.]/g, "-");
|
|
@@ -34908,7 +35062,7 @@ var FLAG_REGISTRY = [
|
|
|
34908
35062
|
},
|
|
34909
35063
|
{
|
|
34910
35064
|
key: "wedge-transient-notice",
|
|
34911
|
-
description:
|
|
35065
|
+
description: `Tell the person waiting when their turn dies on a transient LLM-API failure (529 overloaded / 5xx). TWO consumers now share this gate. (1) ENG-7360: a wedge-respawn preceded by such an error writes the ENG-6058 give-up signal tagged reason=transient_overload so the channel sweeps post a "please resend" notice. (2) ENG-8269: the channel MCPs watch the dispatched turn in Claude Code's own transcript and notify the conversation that was actually waiting \u2014 Slack, Telegram AND direct chat \u2014 plus a "still working on this" notice after ~3min on Slack/Telegram only (direct chat already shows a client-side one at 90s). NOTE: (2) fires on a MUCH larger population than (1) \u2014 any dispatched turn that dies, not only one that also wedged the session \u2014 and (1) has never actually been able to fire, because its pane.log detector cannot match the banner Claude Code renders today. So flipping this on is in practice enabling (2) for the first time. Boolean gate; ships dark \u2014 channel-visible copy soaks per host before going wide. Materialized into the channel-MCP spawn env: a Docker-isolated agent never mounts the host flags-cache, so a central flip reaches it only that way.`,
|
|
34912
35066
|
flagType: "boolean",
|
|
34913
35067
|
defaultValue: false,
|
|
34914
35068
|
envVar: "AGT_WEDGE_TRANSIENT_NOTICE_ENABLED"
|
|
@@ -35402,6 +35556,22 @@ var FLAG_REGISTRY = [
|
|
|
35402
35556
|
// registry-only (ADR-0022). NOT `public`: it is resolved server-side only, so it
|
|
35403
35557
|
// must never be serialized into the browser map.
|
|
35404
35558
|
defaultValue: false
|
|
35559
|
+
},
|
|
35560
|
+
{
|
|
35561
|
+
key: "ninjafy-brand",
|
|
35562
|
+
description: 'Present the product under the Ninjafy brand instead of Augmented Team (ENG-8250). This is the UMBRELLA brand gate, not a one-off nav toggle: every subsequent rebrand surface (page titles, email templates, marketing-facing copy) reads THIS key rather than adding its own flag, so the whole rebrand keeps a single kill switch. First surface is the left-hand nav wordmark \u2014 ON replaces the human+robot mark and the "augmented.team" text with italic lowercase "ninjafy"; OFF renders exactly what shipped before. Scope is USER-FACING BRAND TEXT ONLY: it must never gate a code identifier, package name, env var or CLI name, which stay `Augmented`/`agt` per the CLAUDE.md naming contract (the deep code rename is workstream C of docs/runbooks/rebrand-ninjafy-migration.md and is out of scope here). Set the stage-wide default to flip a whole environment, or add a feature_flag_overrides row to pilot one organization while every other org still sees Augmented. Ships dark.',
|
|
35563
|
+
flagType: "boolean",
|
|
35564
|
+
// Declared safe value is `false`: the pre-rebrand brand. `false` is also the
|
|
35565
|
+
// fail-closed direction — if the flag DB is unreachable we must show the brand
|
|
35566
|
+
// that is currently live and contractually correct, never leak an unannounced
|
|
35567
|
+
// rebrand to every customer at once.
|
|
35568
|
+
defaultValue: false,
|
|
35569
|
+
// Read CLIENT-SIDE: sidebar.tsx is a "use client" component and resolves this
|
|
35570
|
+
// via usePublicBooleanFlag, so the key must be in the browser-exposed public
|
|
35571
|
+
// map. Unlike onboarding-msteams-channel above there is no wrong-org hazard —
|
|
35572
|
+
// the sidebar renders inside the active-org cookie's scope, which is exactly
|
|
35573
|
+
// the org whose brand should be shown.
|
|
35574
|
+
public: true
|
|
35405
35575
|
}
|
|
35406
35576
|
];
|
|
35407
35577
|
var REGISTRY_BY_KEY = new Map(FLAG_REGISTRY.map((definition) => [definition.key, definition]));
|
|
@@ -35715,6 +35885,12 @@ function giveUpNoticeText(reason = null) {
|
|
|
35715
35885
|
}
|
|
35716
35886
|
return "\u26A0\uFE0F I couldn't read your last message \u2014 please resend it.";
|
|
35717
35887
|
}
|
|
35888
|
+
function turnFailedNoticeText() {
|
|
35889
|
+
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.";
|
|
35890
|
+
}
|
|
35891
|
+
function turnRetryingNoticeText() {
|
|
35892
|
+
return "\u23F3 Still working on this \u2014 things are running slower than usual on my side. I\u2019ll reply as soon as I have it.";
|
|
35893
|
+
}
|
|
35718
35894
|
function oldestPendingMarkerAgeMs(dir, now = Date.now(), opts) {
|
|
35719
35895
|
if (!dir) return null;
|
|
35720
35896
|
let names;
|
|
@@ -36690,6 +36866,149 @@ async function watchForRateLimitRefusal(opts) {
|
|
|
36690
36866
|
}
|
|
36691
36867
|
}
|
|
36692
36868
|
|
|
36869
|
+
// src/turn-failure-watch.ts
|
|
36870
|
+
import { readFileSync as readFileSync7, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
|
|
36871
|
+
import { join as join8 } from "path";
|
|
36872
|
+
function turnFailureNoticeEnabled(env2) {
|
|
36873
|
+
return resolveHostBooleanFlag({
|
|
36874
|
+
key: "wedge-transient-notice",
|
|
36875
|
+
envVar: "AGT_WEDGE_TRANSIENT_NOTICE_ENABLED",
|
|
36876
|
+
defaultValue: false,
|
|
36877
|
+
...env2 ? { env: env2 } : {}
|
|
36878
|
+
});
|
|
36879
|
+
}
|
|
36880
|
+
var DEFAULT_FAILURE_WATCH_MS = 5 * 6e4;
|
|
36881
|
+
var FAST_POLL_MS = 500;
|
|
36882
|
+
var SLOW_POLL_MS = 3e3;
|
|
36883
|
+
var FAST_PHASE_MS = 1e4;
|
|
36884
|
+
var RETRYING_NOTICE_AFTER_MS = 3 * 6e4;
|
|
36885
|
+
var sleep2 = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
36886
|
+
function classifyTurnFailureSince(opts) {
|
|
36887
|
+
const dir = opts.transcriptDir ?? agentTranscriptDir({ cwd: opts.cwd, home: opts.home });
|
|
36888
|
+
let entries;
|
|
36889
|
+
try {
|
|
36890
|
+
entries = readdirSync3(dir);
|
|
36891
|
+
} catch {
|
|
36892
|
+
return { result: UNKNOWN_TURN_FAILURE, coarse: 0, fine: 0, unrecognisedKeys: [] };
|
|
36893
|
+
}
|
|
36894
|
+
let newest = UNKNOWN_TURN_FAILURE;
|
|
36895
|
+
let coarse = 0;
|
|
36896
|
+
let fine = 0;
|
|
36897
|
+
const unrecognised = /* @__PURE__ */ new Set();
|
|
36898
|
+
for (const name of entries) {
|
|
36899
|
+
if (!name.endsWith(".jsonl")) continue;
|
|
36900
|
+
const path = join8(dir, name);
|
|
36901
|
+
let fingerprint;
|
|
36902
|
+
try {
|
|
36903
|
+
const st = statSync2(path);
|
|
36904
|
+
if (!st.isFile() || st.mtimeMs < opts.sinceMs) continue;
|
|
36905
|
+
fingerprint = `${st.mtimeMs}:${st.size}`;
|
|
36906
|
+
} catch {
|
|
36907
|
+
continue;
|
|
36908
|
+
}
|
|
36909
|
+
const cached2 = opts.cache?.get(path);
|
|
36910
|
+
let scan;
|
|
36911
|
+
if (cached2 && cached2.fingerprint === fingerprint) {
|
|
36912
|
+
scan = cached2.scan;
|
|
36913
|
+
} else {
|
|
36914
|
+
let content;
|
|
36915
|
+
try {
|
|
36916
|
+
content = readFileSync7(path, "utf-8");
|
|
36917
|
+
} catch {
|
|
36918
|
+
continue;
|
|
36919
|
+
}
|
|
36920
|
+
const analysis = analyzeTranscriptTurnFailure(content, opts.sinceMs, opts.nowMs);
|
|
36921
|
+
scan = {
|
|
36922
|
+
result: analysis.result,
|
|
36923
|
+
coarse: analysis.coarse,
|
|
36924
|
+
fine: analysis.fine,
|
|
36925
|
+
unrecognisedKeys: analysis.unrecognisedKeys
|
|
36926
|
+
};
|
|
36927
|
+
opts.cache?.set(path, { fingerprint, scan });
|
|
36928
|
+
}
|
|
36929
|
+
newest = pickNewerTurnFailure(newest, scan.result);
|
|
36930
|
+
coarse += scan.coarse;
|
|
36931
|
+
fine += scan.fine;
|
|
36932
|
+
for (const key2 of scan.unrecognisedKeys) unrecognised.add(key2);
|
|
36933
|
+
}
|
|
36934
|
+
return { result: newest, coarse, fine, unrecognisedKeys: [...unrecognised].sort() };
|
|
36935
|
+
}
|
|
36936
|
+
function emitDriftTelemetryIfBlind(args) {
|
|
36937
|
+
if (args.coarse <= 0 || args.fine > 0) return;
|
|
36938
|
+
try {
|
|
36939
|
+
process.stderr.write(
|
|
36940
|
+
`agt.transcript.api_error.unclassified ${JSON.stringify({
|
|
36941
|
+
channel: args.channel,
|
|
36942
|
+
agent_code: process.env.AGT_AGENT_CODE_NAME ?? "unknown",
|
|
36943
|
+
coarse: args.coarse,
|
|
36944
|
+
keys: args.unrecognisedKeys.slice(0, 20)
|
|
36945
|
+
})}
|
|
36946
|
+
`
|
|
36947
|
+
);
|
|
36948
|
+
} catch {
|
|
36949
|
+
}
|
|
36950
|
+
}
|
|
36951
|
+
async function watchForTurnFailure(opts) {
|
|
36952
|
+
const now = opts.now ?? (() => Date.now());
|
|
36953
|
+
const wait = opts.wait ?? sleep2;
|
|
36954
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_FAILURE_WATCH_MS;
|
|
36955
|
+
const fastPollMs = opts.fastPollMs ?? FAST_POLL_MS;
|
|
36956
|
+
const slowPollMs = opts.slowPollMs ?? SLOW_POLL_MS;
|
|
36957
|
+
const fastPhaseMs = opts.fastPhaseMs ?? FAST_PHASE_MS;
|
|
36958
|
+
const retryingAfterMs = opts.retryingNoticeAfterMs ?? RETRYING_NOTICE_AFTER_MS;
|
|
36959
|
+
const startedAt = now();
|
|
36960
|
+
const deadline = startedAt + timeoutMs;
|
|
36961
|
+
let longRetryFired = false;
|
|
36962
|
+
let driftEmitted = false;
|
|
36963
|
+
const cache = /* @__PURE__ */ new Map();
|
|
36964
|
+
for (; ; ) {
|
|
36965
|
+
let scan;
|
|
36966
|
+
try {
|
|
36967
|
+
scan = classifyTurnFailureSince({
|
|
36968
|
+
sinceMs: opts.sinceMs,
|
|
36969
|
+
// No upper bound, deliberately. Two reasons, and the second is a
|
|
36970
|
+
// correctness requirement of the cache above:
|
|
36971
|
+
// 1. For a post-dispatch watch the question is "has anything since the
|
|
36972
|
+
// dispatch killed this turn?" — a future-dated entry is still an
|
|
36973
|
+
// answer, and rejecting it on clock skew would drop the notice.
|
|
36974
|
+
// 2. A window that widens each poll makes a cached scan unsound: an
|
|
36975
|
+
// entry stamped a hair ahead of our clock would be parsed as
|
|
36976
|
+
// out-of-window, cached as "not seen", and — because a DEAD turn
|
|
36977
|
+
// produces no further appends to invalidate the entry — never looked
|
|
36978
|
+
// at again. That is exactly the silence this feature exists to end.
|
|
36979
|
+
nowMs: Number.POSITIVE_INFINITY,
|
|
36980
|
+
transcriptDir: opts.transcriptDir,
|
|
36981
|
+
cwd: opts.cwd,
|
|
36982
|
+
home: opts.home,
|
|
36983
|
+
cache
|
|
36984
|
+
});
|
|
36985
|
+
} catch {
|
|
36986
|
+
return null;
|
|
36987
|
+
}
|
|
36988
|
+
if (!driftEmitted && scan.coarse > 0 && scan.fine === 0) {
|
|
36989
|
+
driftEmitted = true;
|
|
36990
|
+
emitDriftTelemetryIfBlind({
|
|
36991
|
+
channel: opts.channel ?? "unknown",
|
|
36992
|
+
coarse: scan.coarse,
|
|
36993
|
+
fine: scan.fine,
|
|
36994
|
+
unrecognisedKeys: scan.unrecognisedKeys
|
|
36995
|
+
});
|
|
36996
|
+
}
|
|
36997
|
+
const { result } = scan;
|
|
36998
|
+
if (result.outcome === "failed") return result;
|
|
36999
|
+
if (result.outcome === "served") return null;
|
|
37000
|
+
if (result.outcome === "retrying" && !longRetryFired && opts.onLongRetry && now() - startedAt >= retryingAfterMs) {
|
|
37001
|
+
longRetryFired = true;
|
|
37002
|
+
try {
|
|
37003
|
+
await opts.onLongRetry(result);
|
|
37004
|
+
} catch {
|
|
37005
|
+
}
|
|
37006
|
+
}
|
|
37007
|
+
if (now() >= deadline) return null;
|
|
37008
|
+
await wait(now() - startedAt < fastPhaseMs ? fastPollMs : slowPollMs);
|
|
37009
|
+
}
|
|
37010
|
+
}
|
|
37011
|
+
|
|
36693
37012
|
// src/usage-limit-reactive-decision.ts
|
|
36694
37013
|
import { createHash } from "crypto";
|
|
36695
37014
|
function shouldReadPredictiveMarker(mode) {
|
|
@@ -36716,7 +37035,7 @@ function describeUnparsedRefusal(text) {
|
|
|
36716
37035
|
import { execFile as execFile2 } from "child_process";
|
|
36717
37036
|
import { existsSync as existsSync3, mkdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
36718
37037
|
import { homedir as homedir6 } from "os";
|
|
36719
|
-
import { join as
|
|
37038
|
+
import { join as join9 } from "path";
|
|
36720
37039
|
var DEFAULT_CLAUDE_EVAL_MODEL = "claude-haiku-4-5-20251001";
|
|
36721
37040
|
var DEFAULT_ANTHROPIC_MESSAGES_URL = "https://api.anthropic.com/v1/messages";
|
|
36722
37041
|
var ANTHROPIC_API_VERSION = "2023-06-01";
|
|
@@ -36815,12 +37134,12 @@ async function runAnthropicMessages(prompt, opts) {
|
|
|
36815
37134
|
var emptyMcpConfigPath = null;
|
|
36816
37135
|
function ensureEmptyMcpConfig() {
|
|
36817
37136
|
if (emptyMcpConfigPath && existsSync3(emptyMcpConfigPath)) return emptyMcpConfigPath;
|
|
36818
|
-
const dir =
|
|
37137
|
+
const dir = join9(homedir6(), ".augmented");
|
|
36819
37138
|
try {
|
|
36820
37139
|
mkdirSync(dir, { recursive: true });
|
|
36821
37140
|
} catch {
|
|
36822
37141
|
}
|
|
36823
|
-
const p2 =
|
|
37142
|
+
const p2 = join9(dir, ".reply-intent-empty-mcp.json");
|
|
36824
37143
|
writeFileSync2(p2, JSON.stringify({ mcpServers: {} }));
|
|
36825
37144
|
emptyMcpConfigPath = p2;
|
|
36826
37145
|
return p2;
|
|
@@ -36967,8 +37286,8 @@ function emitTransientApiErrorTelemetry(channel, match, original) {
|
|
|
36967
37286
|
}
|
|
36968
37287
|
|
|
36969
37288
|
// src/slack-pending-inbound-cleanup.ts
|
|
36970
|
-
import { existsSync as existsSync4, readdirSync as
|
|
36971
|
-
import { join as
|
|
37289
|
+
import { existsSync as existsSync4, readdirSync as readdirSync4, statSync as statSync3, unlinkSync } from "fs";
|
|
37290
|
+
import { join as join10 } from "path";
|
|
36972
37291
|
function sanitizeMarkerSegment(value) {
|
|
36973
37292
|
return value.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
36974
37293
|
}
|
|
@@ -36982,9 +37301,9 @@ function applyToMatchingMarkers(dir, prefix, suffix, op) {
|
|
|
36982
37301
|
if (!dir) return 0;
|
|
36983
37302
|
let applied = 0;
|
|
36984
37303
|
try {
|
|
36985
|
-
for (const f of
|
|
37304
|
+
for (const f of readdirSync4(dir)) {
|
|
36986
37305
|
if (!f.startsWith(prefix) || !f.endsWith(suffix)) continue;
|
|
36987
|
-
op(
|
|
37306
|
+
op(join10(dir, f));
|
|
36988
37307
|
applied += 1;
|
|
36989
37308
|
}
|
|
36990
37309
|
} catch {
|
|
@@ -37013,11 +37332,11 @@ function clearOldestSlackPendingMarkerInChannel(dir, channel, clear = defaultCle
|
|
|
37013
37332
|
if (!dir) return null;
|
|
37014
37333
|
const channelPrefix = `${sanitizeMarkerSegment(channel)}__`;
|
|
37015
37334
|
try {
|
|
37016
|
-
const entries =
|
|
37017
|
-
const full =
|
|
37335
|
+
const entries = readdirSync4(dir).filter((f) => f.startsWith(channelPrefix) && f.endsWith(".json")).map((f) => {
|
|
37336
|
+
const full = join10(dir, f);
|
|
37018
37337
|
let mtime = 0;
|
|
37019
37338
|
try {
|
|
37020
|
-
mtime =
|
|
37339
|
+
mtime = statSync3(full).mtimeMs;
|
|
37021
37340
|
} catch {
|
|
37022
37341
|
}
|
|
37023
37342
|
return { name: f, full, mtime };
|
|
@@ -37033,12 +37352,12 @@ function clearOldestSlackPendingMarkerInChannel(dir, channel, clear = defaultCle
|
|
|
37033
37352
|
|
|
37034
37353
|
// src/recovery-ledger.ts
|
|
37035
37354
|
import { existsSync as existsSync5, unlinkSync as unlinkSync2 } from "fs";
|
|
37036
|
-
import { join as
|
|
37355
|
+
import { join as join11 } from "path";
|
|
37037
37356
|
function recoveryLedgerEntryExists(ledgerDir, markerName, exists = (p2) => existsSync5(p2)) {
|
|
37038
37357
|
if (!ledgerDir || !markerName) return false;
|
|
37039
37358
|
if (markerName.includes("/") || markerName.includes("\\") || markerName.includes("..")) return false;
|
|
37040
37359
|
try {
|
|
37041
|
-
return exists(
|
|
37360
|
+
return exists(join11(ledgerDir, markerName));
|
|
37042
37361
|
} catch {
|
|
37043
37362
|
return false;
|
|
37044
37363
|
}
|
|
@@ -37049,7 +37368,7 @@ function removeRecoveryLedgerEntry(ledgerDir, markerName, unlink = (p2) => {
|
|
|
37049
37368
|
if (!ledgerDir || !markerName) return;
|
|
37050
37369
|
if (markerName.includes("/") || markerName.includes("\\") || markerName.includes("..")) return;
|
|
37051
37370
|
try {
|
|
37052
|
-
unlink(
|
|
37371
|
+
unlink(join11(ledgerDir, markerName));
|
|
37053
37372
|
} catch {
|
|
37054
37373
|
}
|
|
37055
37374
|
}
|
|
@@ -37286,18 +37605,18 @@ function applyHotThreadGuard(input) {
|
|
|
37286
37605
|
}
|
|
37287
37606
|
|
|
37288
37607
|
// src/slack-hot-thread-telemetry.ts
|
|
37289
|
-
import { readFileSync as
|
|
37290
|
-
import { join as
|
|
37608
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "fs";
|
|
37609
|
+
import { join as join12 } from "path";
|
|
37291
37610
|
var HOT_THREAD_CLASSIFICATION_COUNTER_SUFFIX = "-hot-thread-classifications.json";
|
|
37292
37611
|
function hotThreadKey(mode, outcome, proactive) {
|
|
37293
37612
|
return `${mode}|${outcome}|${proactive ? "true" : "false"}`;
|
|
37294
37613
|
}
|
|
37295
37614
|
function recordHotThreadClassification(agentDir, channel, classification) {
|
|
37296
37615
|
if (!agentDir || !channel) return;
|
|
37297
|
-
const path =
|
|
37616
|
+
const path = join12(agentDir, `${channel}${HOT_THREAD_CLASSIFICATION_COUNTER_SUFFIX}`);
|
|
37298
37617
|
let counts = {};
|
|
37299
37618
|
try {
|
|
37300
|
-
const parsed = JSON.parse(
|
|
37619
|
+
const parsed = JSON.parse(readFileSync8(path, "utf-8"));
|
|
37301
37620
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
37302
37621
|
for (const [k, v] of Object.entries(parsed)) {
|
|
37303
37622
|
if (typeof v === "number" && Number.isInteger(v) && v >= 0) counts[k] = v;
|
|
@@ -37314,7 +37633,7 @@ function recordHotThreadClassification(agentDir, channel, classification) {
|
|
|
37314
37633
|
}
|
|
37315
37634
|
|
|
37316
37635
|
// src/restart-confirm.ts
|
|
37317
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as
|
|
37636
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync9, renameSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
37318
37637
|
import { dirname } from "path";
|
|
37319
37638
|
import { randomUUID } from "crypto";
|
|
37320
37639
|
var RESTART_CONFIRM_MAX_AGE_MS = 10 * 60 * 1e3;
|
|
@@ -37340,7 +37659,7 @@ function writeRestartConfirmMarker(filePath, marker) {
|
|
|
37340
37659
|
function readRestartConfirmMarker(filePath) {
|
|
37341
37660
|
try {
|
|
37342
37661
|
if (!existsSync6(filePath)) return null;
|
|
37343
|
-
const parsed = JSON.parse(
|
|
37662
|
+
const parsed = JSON.parse(readFileSync9(filePath, "utf8"));
|
|
37344
37663
|
if (!parsed || typeof parsed !== "object") return null;
|
|
37345
37664
|
return parsed;
|
|
37346
37665
|
} catch {
|
|
@@ -37485,21 +37804,21 @@ import {
|
|
|
37485
37804
|
ftruncateSync,
|
|
37486
37805
|
mkdirSync as mkdirSync9,
|
|
37487
37806
|
openSync,
|
|
37488
|
-
readFileSync as
|
|
37489
|
-
readdirSync as
|
|
37807
|
+
readFileSync as readFileSync21,
|
|
37808
|
+
readdirSync as readdirSync7,
|
|
37490
37809
|
renameSync as renameSync5,
|
|
37491
|
-
statSync as
|
|
37810
|
+
statSync as statSync5,
|
|
37492
37811
|
unlinkSync as unlinkSync7,
|
|
37493
37812
|
watch,
|
|
37494
37813
|
writeFileSync as writeFileSync14,
|
|
37495
37814
|
writeSync
|
|
37496
37815
|
} from "fs";
|
|
37497
|
-
import { basename, join as
|
|
37816
|
+
import { basename, join as join21, resolve as resolve2 } from "path";
|
|
37498
37817
|
import { homedir as homedir7 } from "os";
|
|
37499
37818
|
import { createHash as createHash3, randomUUID as randomUUID2 } from "crypto";
|
|
37500
37819
|
|
|
37501
37820
|
// src/slack-thread-store.ts
|
|
37502
|
-
import { mkdirSync as mkdirSync3, readFileSync as
|
|
37821
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "fs";
|
|
37503
37822
|
import { dirname as dirname2 } from "path";
|
|
37504
37823
|
function isParticipatingThread(entry) {
|
|
37505
37824
|
if (!entry) return false;
|
|
@@ -37514,7 +37833,7 @@ function loadThreadStore(filePath, opts = {}) {
|
|
|
37514
37833
|
const ttlMs = ttlDays * 24 * 60 * 60 * 1e3;
|
|
37515
37834
|
let raw;
|
|
37516
37835
|
try {
|
|
37517
|
-
raw =
|
|
37836
|
+
raw = readFileSync10(filePath, "utf-8");
|
|
37518
37837
|
} catch {
|
|
37519
37838
|
return { threads: /* @__PURE__ */ new Map(), pruned: 0 };
|
|
37520
37839
|
}
|
|
@@ -37615,7 +37934,7 @@ function isThreadEntry(value) {
|
|
|
37615
37934
|
}
|
|
37616
37935
|
|
|
37617
37936
|
// src/dm-restart-notice.ts
|
|
37618
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
37937
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync11, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
37619
37938
|
import { dirname as dirname3 } from "path";
|
|
37620
37939
|
var RECENT_DM_VERSION = 1;
|
|
37621
37940
|
var DEFAULT_RECENT_DM_TTL_MS = 30 * 60 * 1e3;
|
|
@@ -37639,7 +37958,7 @@ function loadRecentDms(filePath, opts = {}) {
|
|
|
37639
37958
|
const ttlMs = opts.ttlMs ?? DEFAULT_RECENT_DM_TTL_MS;
|
|
37640
37959
|
let raw;
|
|
37641
37960
|
try {
|
|
37642
|
-
raw =
|
|
37961
|
+
raw = readFileSync11(filePath, "utf-8");
|
|
37643
37962
|
} catch (err) {
|
|
37644
37963
|
const code = err.code;
|
|
37645
37964
|
if (code !== "ENOENT") {
|
|
@@ -37724,7 +38043,7 @@ var CHANNEL_ADD_RESTART_MAX_AGE_MS = 15 * 60 * 1e3;
|
|
|
37724
38043
|
function readChannelAddRestartMarker(filePath) {
|
|
37725
38044
|
let raw;
|
|
37726
38045
|
try {
|
|
37727
|
-
raw =
|
|
38046
|
+
raw = readFileSync11(filePath, "utf-8");
|
|
37728
38047
|
} catch {
|
|
37729
38048
|
return null;
|
|
37730
38049
|
}
|
|
@@ -37782,13 +38101,13 @@ async function runOrRetry(fn, opts) {
|
|
|
37782
38101
|
}
|
|
37783
38102
|
|
|
37784
38103
|
// src/turn-initiator-marker.ts
|
|
37785
|
-
import { writeFileSync as writeFileSync7, readFileSync as
|
|
37786
|
-
import { dirname as dirname4, join as
|
|
38104
|
+
import { writeFileSync as writeFileSync7, readFileSync as readFileSync12, mkdirSync as mkdirSync5, renameSync as renameSync2 } from "fs";
|
|
38105
|
+
import { dirname as dirname4, join as join13 } from "path";
|
|
37787
38106
|
var TURN_INITIATOR_MAX_AGE_MS = 5 * 60 * 1e3;
|
|
37788
38107
|
var TURN_INITIATOR_LEDGER_MAX_ENTRIES = 20;
|
|
37789
38108
|
var TURN_INITIATOR_LEDGER_FILENAME = ".turn-initiator-ledger.json";
|
|
37790
38109
|
function turnInitiatorLedgerPath(singleSlotFile) {
|
|
37791
|
-
return
|
|
38110
|
+
return join13(dirname4(singleSlotFile), TURN_INITIATOR_LEDGER_FILENAME);
|
|
37792
38111
|
}
|
|
37793
38112
|
function foldTurnInitiatorLedger(existing, marker, maxAgeMs = TURN_INITIATOR_MAX_AGE_MS, maxEntries = TURN_INITIATOR_LEDGER_MAX_ENTRIES) {
|
|
37794
38113
|
const now = marker.ts;
|
|
@@ -37813,7 +38132,7 @@ function updateTurnInitiatorLedger(singleSlotFile, marker) {
|
|
|
37813
38132
|
const ledgerFile = turnInitiatorLedgerPath(singleSlotFile);
|
|
37814
38133
|
let existing = null;
|
|
37815
38134
|
try {
|
|
37816
|
-
const parsed = JSON.parse(
|
|
38135
|
+
const parsed = JSON.parse(readFileSync12(ledgerFile, "utf8"));
|
|
37817
38136
|
if (parsed && parsed.v === 1 && Array.isArray(parsed.entries)) existing = parsed;
|
|
37818
38137
|
} catch {
|
|
37819
38138
|
}
|
|
@@ -37840,7 +38159,7 @@ function writeTurnInitiatorMarker(input) {
|
|
|
37840
38159
|
}
|
|
37841
38160
|
|
|
37842
38161
|
// src/slack-bot-photo.ts
|
|
37843
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as
|
|
38162
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "fs";
|
|
37844
38163
|
import { dirname as dirname5 } from "path";
|
|
37845
38164
|
async function applyBotPhoto(opts) {
|
|
37846
38165
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
@@ -37850,7 +38169,7 @@ async function applyBotPhoto(opts) {
|
|
|
37850
38169
|
const { token, avatarUrl, markerPath } = opts;
|
|
37851
38170
|
if (markerPath && existsSync7(markerPath)) {
|
|
37852
38171
|
try {
|
|
37853
|
-
if (
|
|
38172
|
+
if (readFileSync13(markerPath, "utf-8").trim() === avatarUrl) {
|
|
37854
38173
|
return { status: "skipped-unchanged" };
|
|
37855
38174
|
}
|
|
37856
38175
|
} catch {
|
|
@@ -37975,8 +38294,8 @@ function conversationalLaneMeta(expectsReply = true) {
|
|
|
37975
38294
|
}
|
|
37976
38295
|
|
|
37977
38296
|
// src/inbound-lane-telemetry.ts
|
|
37978
|
-
import { readFileSync as
|
|
37979
|
-
import { join as
|
|
38297
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "fs";
|
|
38298
|
+
import { join as join14 } from "path";
|
|
37980
38299
|
var LANE_CLASSIFICATION_COUNTER_SUFFIX = "-lane-classifications.json";
|
|
37981
38300
|
var SUSPECTED_MISCLASSIFICATION_KEY = "suspected_misclassification";
|
|
37982
38301
|
var HUMAN_CHANNEL_SOURCES = /* @__PURE__ */ new Set([
|
|
@@ -37993,10 +38312,10 @@ function isSuspectedMisclassification(lane, source) {
|
|
|
37993
38312
|
}
|
|
37994
38313
|
function recordLaneClassification(agentDir, channel, classification) {
|
|
37995
38314
|
if (!agentDir) return;
|
|
37996
|
-
const path =
|
|
38315
|
+
const path = join14(agentDir, `${channel}${LANE_CLASSIFICATION_COUNTER_SUFFIX}`);
|
|
37997
38316
|
let counts = {};
|
|
37998
38317
|
try {
|
|
37999
|
-
const parsed = JSON.parse(
|
|
38318
|
+
const parsed = JSON.parse(readFileSync14(path, "utf-8"));
|
|
38000
38319
|
if (parsed && typeof parsed === "object") counts = parsed;
|
|
38001
38320
|
} catch {
|
|
38002
38321
|
}
|
|
@@ -38012,8 +38331,8 @@ function recordLaneClassification(agentDir, channel, classification) {
|
|
|
38012
38331
|
}
|
|
38013
38332
|
|
|
38014
38333
|
// src/slack-inbound-registry.ts
|
|
38015
|
-
import { readdirSync as
|
|
38016
|
-
import { join as
|
|
38334
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync15 } from "fs";
|
|
38335
|
+
import { join as join15 } from "path";
|
|
38017
38336
|
var DEFAULT_MAX_ENTRIES = 500;
|
|
38018
38337
|
var DEFAULT_CLEARED_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
38019
38338
|
function entryKey(channel, messageTs) {
|
|
@@ -38125,7 +38444,7 @@ function createInboundRegistry(opts = {}) {
|
|
|
38125
38444
|
function seedFromMarkerDir(dir) {
|
|
38126
38445
|
let names;
|
|
38127
38446
|
try {
|
|
38128
|
-
names =
|
|
38447
|
+
names = readdirSync5(dir);
|
|
38129
38448
|
} catch {
|
|
38130
38449
|
return;
|
|
38131
38450
|
}
|
|
@@ -38134,7 +38453,7 @@ function createInboundRegistry(opts = {}) {
|
|
|
38134
38453
|
if (name.includes(".retry-") || name.includes(".poison")) continue;
|
|
38135
38454
|
let marker;
|
|
38136
38455
|
try {
|
|
38137
|
-
marker = JSON.parse(
|
|
38456
|
+
marker = JSON.parse(readFileSync15(join15(dir, name), "utf-8"));
|
|
38138
38457
|
} catch {
|
|
38139
38458
|
continue;
|
|
38140
38459
|
}
|
|
@@ -38179,8 +38498,8 @@ function slackInboundId(channel, threadTs, messageTs) {
|
|
|
38179
38498
|
}
|
|
38180
38499
|
|
|
38181
38500
|
// src/inbound-delivery-ledger.ts
|
|
38182
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync7, readdirSync as
|
|
38183
|
-
import { join as
|
|
38501
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync7, readdirSync as readdirSync6, readFileSync as readFileSync16, renameSync as renameSync3, writeFileSync as writeFileSync10 } from "fs";
|
|
38502
|
+
import { join as join16 } from "path";
|
|
38184
38503
|
function safeInboundId(inboundId) {
|
|
38185
38504
|
return inboundId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
38186
38505
|
}
|
|
@@ -38188,8 +38507,8 @@ var defaultDeps = {
|
|
|
38188
38507
|
mkdir: (dir) => mkdirSync7(dir, { recursive: true }),
|
|
38189
38508
|
writeFile: (path, data) => writeFileSync10(path, data, "utf8"),
|
|
38190
38509
|
rename: (from, to) => renameSync3(from, to),
|
|
38191
|
-
readdir: (dir) =>
|
|
38192
|
-
readFile: (path) =>
|
|
38510
|
+
readdir: (dir) => readdirSync6(dir),
|
|
38511
|
+
readFile: (path) => readFileSync16(path, "utf8"),
|
|
38193
38512
|
exists: (path) => existsSync8(path)
|
|
38194
38513
|
};
|
|
38195
38514
|
function writeInboundDeliveryLedgerEntry(dir, record2, deps = defaultDeps) {
|
|
@@ -38198,7 +38517,7 @@ function writeInboundDeliveryLedgerEntry(dir, record2, deps = defaultDeps) {
|
|
|
38198
38517
|
if (!safe || safe.includes("/") || safe.includes("\\") || safe.includes("..")) return;
|
|
38199
38518
|
try {
|
|
38200
38519
|
deps.mkdir(dir);
|
|
38201
|
-
const final =
|
|
38520
|
+
const final = join16(dir, `${safe}.json`);
|
|
38202
38521
|
const tmp = `${final}.tmp`;
|
|
38203
38522
|
deps.writeFile(tmp, JSON.stringify(record2));
|
|
38204
38523
|
deps.rename(tmp, final);
|
|
@@ -38354,8 +38673,8 @@ function describeChannelRedirect(input) {
|
|
|
38354
38673
|
}
|
|
38355
38674
|
|
|
38356
38675
|
// src/slack-reply-binding-telemetry.ts
|
|
38357
|
-
import { readFileSync as
|
|
38358
|
-
import { join as
|
|
38676
|
+
import { readFileSync as readFileSync17, writeFileSync as writeFileSync11 } from "fs";
|
|
38677
|
+
import { join as join17 } from "path";
|
|
38359
38678
|
var REPLY_BINDING_CLASSIFICATION_COUNTER_SUFFIX = "-reply-binding-classifications.json";
|
|
38360
38679
|
var UNKNOWN_INBOUND_ID_KEY = "unknown_inbound_id";
|
|
38361
38680
|
var CHANNEL_MISTARGET_CORRECTED_KEY = "channel_mistarget_corrected";
|
|
@@ -38370,10 +38689,10 @@ function slackReplyBindingMode() {
|
|
|
38370
38689
|
}
|
|
38371
38690
|
function recordReplyBindingClassification(agentDir, channel, input) {
|
|
38372
38691
|
if (!agentDir) return;
|
|
38373
|
-
const path =
|
|
38692
|
+
const path = join17(agentDir, `${channel}${REPLY_BINDING_CLASSIFICATION_COUNTER_SUFFIX}`);
|
|
38374
38693
|
let counts = {};
|
|
38375
38694
|
try {
|
|
38376
|
-
const parsed = JSON.parse(
|
|
38695
|
+
const parsed = JSON.parse(readFileSync17(path, "utf-8"));
|
|
38377
38696
|
if (parsed && typeof parsed === "object") counts = parsed;
|
|
38378
38697
|
} catch {
|
|
38379
38698
|
}
|
|
@@ -38388,10 +38707,10 @@ function recordReplyBindingClassification(agentDir, channel, input) {
|
|
|
38388
38707
|
}
|
|
38389
38708
|
function recordScheduledChannelOverride(agentDir, channel, input) {
|
|
38390
38709
|
if (!agentDir) return;
|
|
38391
|
-
const path =
|
|
38710
|
+
const path = join17(agentDir, `${channel}${REPLY_BINDING_CLASSIFICATION_COUNTER_SUFFIX}`);
|
|
38392
38711
|
let counts = {};
|
|
38393
38712
|
try {
|
|
38394
|
-
const parsed = JSON.parse(
|
|
38713
|
+
const parsed = JSON.parse(readFileSync17(path, "utf-8"));
|
|
38395
38714
|
if (parsed && typeof parsed === "object") counts = parsed;
|
|
38396
38715
|
} catch {
|
|
38397
38716
|
}
|
|
@@ -38404,10 +38723,10 @@ function recordScheduledChannelOverride(agentDir, channel, input) {
|
|
|
38404
38723
|
}
|
|
38405
38724
|
function recordChannelMistarget(agentDir, channel, input) {
|
|
38406
38725
|
if (!agentDir) return;
|
|
38407
|
-
const path =
|
|
38726
|
+
const path = join17(agentDir, `${channel}${REPLY_BINDING_CLASSIFICATION_COUNTER_SUFFIX}`);
|
|
38408
38727
|
let counts = {};
|
|
38409
38728
|
try {
|
|
38410
|
-
const parsed = JSON.parse(
|
|
38729
|
+
const parsed = JSON.parse(readFileSync17(path, "utf-8"));
|
|
38411
38730
|
if (parsed && typeof parsed === "object") counts = parsed;
|
|
38412
38731
|
} catch {
|
|
38413
38732
|
}
|
|
@@ -38422,8 +38741,8 @@ function recordChannelMistarget(agentDir, channel, input) {
|
|
|
38422
38741
|
}
|
|
38423
38742
|
|
|
38424
38743
|
// src/slack-reply-target-telemetry.ts
|
|
38425
|
-
import { readFileSync as
|
|
38426
|
-
import { join as
|
|
38744
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12 } from "fs";
|
|
38745
|
+
import { join as join18 } from "path";
|
|
38427
38746
|
var REPLY_TARGET_CLASSIFICATION_COUNTER_SUFFIX = "-reply-target-classifications.json";
|
|
38428
38747
|
function pendingThreadsBucket(n) {
|
|
38429
38748
|
if (n <= 0) return "0";
|
|
@@ -38456,10 +38775,10 @@ function classifyReplyTarget(input) {
|
|
|
38456
38775
|
}
|
|
38457
38776
|
function recordReplyTargetClassification(agentDir, channel, classification) {
|
|
38458
38777
|
if (!agentDir) return;
|
|
38459
|
-
const path =
|
|
38778
|
+
const path = join18(agentDir, `${channel}${REPLY_TARGET_CLASSIFICATION_COUNTER_SUFFIX}`);
|
|
38460
38779
|
let counts = {};
|
|
38461
38780
|
try {
|
|
38462
|
-
const parsed = JSON.parse(
|
|
38781
|
+
const parsed = JSON.parse(readFileSync18(path, "utf-8"));
|
|
38463
38782
|
if (parsed && typeof parsed === "object") counts = parsed;
|
|
38464
38783
|
} catch {
|
|
38465
38784
|
}
|
|
@@ -38475,8 +38794,8 @@ function recordReplyTargetClassification(agentDir, channel, classification) {
|
|
|
38475
38794
|
}
|
|
38476
38795
|
|
|
38477
38796
|
// src/scheduled-turn-marker.ts
|
|
38478
|
-
import { readFileSync as
|
|
38479
|
-
import { join as
|
|
38797
|
+
import { readFileSync as readFileSync19, unlinkSync as unlinkSync5 } from "fs";
|
|
38798
|
+
import { join as join19 } from "path";
|
|
38480
38799
|
var SCHEDULED_TURN_MARKER_FILENAME2 = ".current-scheduled-turn.json";
|
|
38481
38800
|
var SCHEDULED_TURN_MAX_AGE_MS = 15 * 60 * 1e3;
|
|
38482
38801
|
function validateScheduledTurnMarker(raw, now, maxAgeMs = SCHEDULED_TURN_MAX_AGE_MS) {
|
|
@@ -38514,7 +38833,7 @@ function readScheduledTurnMarker(agentDir, now = Date.now()) {
|
|
|
38514
38833
|
if (!agentDir) return null;
|
|
38515
38834
|
try {
|
|
38516
38835
|
const raw = JSON.parse(
|
|
38517
|
-
|
|
38836
|
+
readFileSync19(join19(agentDir, SCHEDULED_TURN_MARKER_FILENAME2), "utf8")
|
|
38518
38837
|
);
|
|
38519
38838
|
return validateScheduledTurnMarker(raw, now);
|
|
38520
38839
|
} catch {
|
|
@@ -38524,7 +38843,7 @@ function readScheduledTurnMarker(agentDir, now = Date.now()) {
|
|
|
38524
38843
|
function clearScheduledTurnMarker(agentDir) {
|
|
38525
38844
|
if (!agentDir) return;
|
|
38526
38845
|
try {
|
|
38527
|
-
unlinkSync5(
|
|
38846
|
+
unlinkSync5(join19(agentDir, SCHEDULED_TURN_MARKER_FILENAME2));
|
|
38528
38847
|
} catch {
|
|
38529
38848
|
}
|
|
38530
38849
|
}
|
|
@@ -39322,14 +39641,14 @@ async function actuateHostRestart(opts) {
|
|
|
39322
39641
|
import {
|
|
39323
39642
|
existsSync as existsSync9,
|
|
39324
39643
|
mkdirSync as mkdirSync8,
|
|
39325
|
-
readFileSync as
|
|
39644
|
+
readFileSync as readFileSync20,
|
|
39326
39645
|
renameSync as renameSync4,
|
|
39327
|
-
statSync as
|
|
39646
|
+
statSync as statSync4,
|
|
39328
39647
|
unlinkSync as unlinkSync6,
|
|
39329
39648
|
utimesSync,
|
|
39330
39649
|
writeFileSync as writeFileSync13
|
|
39331
39650
|
} from "fs";
|
|
39332
|
-
import { join as
|
|
39651
|
+
import { join as join20 } from "path";
|
|
39333
39652
|
var STALE_LOCK_MS = 9e4;
|
|
39334
39653
|
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
39335
39654
|
function defaultIsPidAlive(pid) {
|
|
@@ -39352,7 +39671,7 @@ function acquireMcpSpawnLock(args) {
|
|
|
39352
39671
|
const nowMs = options.nowMs ?? (() => Date.now());
|
|
39353
39672
|
const lockMtimeMs = options.lockMtimeMs ?? defaultLockMtimeMs;
|
|
39354
39673
|
const staleMs = options.staleMs ?? STALE_LOCK_MS;
|
|
39355
|
-
const path =
|
|
39674
|
+
const path = join20(agentDir, basename2);
|
|
39356
39675
|
const existing = readLockHolder(path);
|
|
39357
39676
|
if (existing) {
|
|
39358
39677
|
if (existing.pid === selfPid) {
|
|
@@ -39411,7 +39730,7 @@ function startMcpSpawnLockHeartbeat(lockPath, opts = {}) {
|
|
|
39411
39730
|
}
|
|
39412
39731
|
function defaultLockMtimeMs(path) {
|
|
39413
39732
|
try {
|
|
39414
|
-
return
|
|
39733
|
+
return statSync4(path).mtimeMs;
|
|
39415
39734
|
} catch {
|
|
39416
39735
|
return null;
|
|
39417
39736
|
}
|
|
@@ -39419,7 +39738,7 @@ function defaultLockMtimeMs(path) {
|
|
|
39419
39738
|
function readLockHolder(path) {
|
|
39420
39739
|
if (!existsSync9(path)) return null;
|
|
39421
39740
|
try {
|
|
39422
|
-
const raw =
|
|
39741
|
+
const raw = readFileSync20(path, "utf8");
|
|
39423
39742
|
const parsed = JSON.parse(raw);
|
|
39424
39743
|
const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
|
|
39425
39744
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
@@ -39868,18 +40187,18 @@ var SLACK_TEAM_PEER_USER_IDS = parseTeamPeerUserIdsEnv(
|
|
|
39868
40187
|
process.env.SLACK_TEAM_PEER_USER_IDS
|
|
39869
40188
|
);
|
|
39870
40189
|
var PEER_HINT_SEEN = /* @__PURE__ */ new Set();
|
|
39871
|
-
var SLACK_AGENT_DIR = AGENT_CODE_NAME ?
|
|
39872
|
-
var SLACK_MCP_CONFIG_PATH = SLACK_AGENT_DIR ?
|
|
40190
|
+
var SLACK_AGENT_DIR = AGENT_CODE_NAME ? join21(homedir7(), ".augmented", AGENT_CODE_NAME) : null;
|
|
40191
|
+
var SLACK_MCP_CONFIG_PATH = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, "project", ".mcp.json") : null;
|
|
39873
40192
|
var liveAllowedUsersCache = null;
|
|
39874
40193
|
function readLiveAllowedUsers() {
|
|
39875
40194
|
if (!SLACK_MCP_CONFIG_PATH) return null;
|
|
39876
40195
|
try {
|
|
39877
|
-
const mtimeMs =
|
|
40196
|
+
const mtimeMs = statSync5(SLACK_MCP_CONFIG_PATH).mtimeMs;
|
|
39878
40197
|
if (liveAllowedUsersCache && liveAllowedUsersCache.mtimeMs === mtimeMs) {
|
|
39879
40198
|
return liveAllowedUsersCache.value;
|
|
39880
40199
|
}
|
|
39881
40200
|
const value = extractAllowedUsersFromMcpJson(
|
|
39882
|
-
|
|
40201
|
+
readFileSync21(SLACK_MCP_CONFIG_PATH, "utf-8")
|
|
39883
40202
|
);
|
|
39884
40203
|
if (value === null) return null;
|
|
39885
40204
|
liveAllowedUsersCache = { mtimeMs, value };
|
|
@@ -39895,12 +40214,12 @@ var livePingAllowedUsersCache = null;
|
|
|
39895
40214
|
function readLivePingAllowedUsers() {
|
|
39896
40215
|
if (!SLACK_MCP_CONFIG_PATH) return null;
|
|
39897
40216
|
try {
|
|
39898
|
-
const mtimeMs =
|
|
40217
|
+
const mtimeMs = statSync5(SLACK_MCP_CONFIG_PATH).mtimeMs;
|
|
39899
40218
|
if (livePingAllowedUsersCache && livePingAllowedUsersCache.mtimeMs === mtimeMs) {
|
|
39900
40219
|
return livePingAllowedUsersCache.value;
|
|
39901
40220
|
}
|
|
39902
40221
|
const value = extractPingAllowedUsersFromMcpJson(
|
|
39903
|
-
|
|
40222
|
+
readFileSync21(SLACK_MCP_CONFIG_PATH, "utf-8")
|
|
39904
40223
|
);
|
|
39905
40224
|
if (value === null) return null;
|
|
39906
40225
|
livePingAllowedUsersCache = { mtimeMs, value };
|
|
@@ -39912,17 +40231,17 @@ function readLivePingAllowedUsers() {
|
|
|
39912
40231
|
function getEffectivePingAllowedUsers() {
|
|
39913
40232
|
return readLivePingAllowedUsers() ?? PING_ALLOWED_USERS;
|
|
39914
40233
|
}
|
|
39915
|
-
var SLACK_PENDING_INBOUND_DIR = SLACK_AGENT_DIR ?
|
|
39916
|
-
var SLACK_RESTART_CONTEXT_DIR = SLACK_AGENT_DIR ?
|
|
39917
|
-
var SLACK_RECOVERY_OUTBOX_DIR = SLACK_AGENT_DIR ?
|
|
39918
|
-
var SLACK_RECOVERY_LEDGER_DIR = SLACK_AGENT_DIR ?
|
|
39919
|
-
var SLACK_DELIVERY_LEDGER_DIR = SLACK_AGENT_DIR ?
|
|
40234
|
+
var SLACK_PENDING_INBOUND_DIR = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, "slack-pending-inbound") : null;
|
|
40235
|
+
var SLACK_RESTART_CONTEXT_DIR = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, "slack-restart-context") : null;
|
|
40236
|
+
var SLACK_RECOVERY_OUTBOX_DIR = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, "slack-recovery-outbox") : null;
|
|
40237
|
+
var SLACK_RECOVERY_LEDGER_DIR = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, ".agt-slack-recovery-ledger") : null;
|
|
40238
|
+
var SLACK_DELIVERY_LEDGER_DIR = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, ".agt-inbound-delivery-ledger") : null;
|
|
39920
40239
|
var slackInboundRegistry = createInboundRegistry();
|
|
39921
|
-
var SLACK_RESTART_CONFIRM_FILE = SLACK_AGENT_DIR ?
|
|
39922
|
-
var SLACK_RECENT_DMS_FILE = SLACK_AGENT_DIR ?
|
|
39923
|
-
var SLACK_CHANNEL_ADD_RESTART_FILE = SLACK_AGENT_DIR ?
|
|
40240
|
+
var SLACK_RESTART_CONFIRM_FILE = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, "slack-restart-confirm.json") : null;
|
|
40241
|
+
var SLACK_RECENT_DMS_FILE = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, "slack-recent-dms.json") : null;
|
|
40242
|
+
var SLACK_CHANNEL_ADD_RESTART_FILE = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, "slack-channel-add-restart.json") : null;
|
|
39924
40243
|
var SLACK_MAX_RECOVERY_ATTEMPTS = 3;
|
|
39925
|
-
var SLACK_AVATAR_MARKER_PATH = SLACK_AGENT_DIR ?
|
|
40244
|
+
var SLACK_AVATAR_MARKER_PATH = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, "slack-avatar-applied") : null;
|
|
39926
40245
|
function redactSlackId(id) {
|
|
39927
40246
|
if (!id) return "<none>";
|
|
39928
40247
|
return createHash3("sha256").update(id).digest("hex").slice(0, 8);
|
|
@@ -39933,7 +40252,7 @@ function safeSlackMarkerName(channel, threadTs, messageTs) {
|
|
|
39933
40252
|
}
|
|
39934
40253
|
function slackPendingInboundPath(channel, threadTs, messageTs) {
|
|
39935
40254
|
if (!SLACK_PENDING_INBOUND_DIR) return null;
|
|
39936
|
-
return
|
|
40255
|
+
return join21(SLACK_PENDING_INBOUND_DIR, safeSlackMarkerName(channel, threadTs, messageTs));
|
|
39937
40256
|
}
|
|
39938
40257
|
function writeSlackPendingInboundMarker(channel, threadTs, messageTs, undeliverable = false, discretionary = false, payload) {
|
|
39939
40258
|
const path = slackPendingInboundPath(channel, threadTs, messageTs);
|
|
@@ -39984,7 +40303,7 @@ function rewriteSlackMarkerInPlace(path, marker) {
|
|
|
39984
40303
|
function markSlackMarkerSeenInPlace(fullPath) {
|
|
39985
40304
|
let marker;
|
|
39986
40305
|
try {
|
|
39987
|
-
marker = JSON.parse(
|
|
40306
|
+
marker = JSON.parse(readFileSync21(fullPath, "utf-8"));
|
|
39988
40307
|
} catch {
|
|
39989
40308
|
return;
|
|
39990
40309
|
}
|
|
@@ -39998,7 +40317,7 @@ function attachSlackReplayPayload(channel, threadTs, messageTs, payload) {
|
|
|
39998
40317
|
if (!path) return;
|
|
39999
40318
|
let marker;
|
|
40000
40319
|
try {
|
|
40001
|
-
marker = JSON.parse(
|
|
40320
|
+
marker = JSON.parse(readFileSync21(path, "utf-8"));
|
|
40002
40321
|
} catch {
|
|
40003
40322
|
return;
|
|
40004
40323
|
}
|
|
@@ -40009,7 +40328,7 @@ function readSlackPendingInboundMarker(channel, threadTs, messageTs) {
|
|
|
40009
40328
|
const path = slackPendingInboundPath(channel, threadTs, messageTs);
|
|
40010
40329
|
if (!path || !existsSync10(path)) return null;
|
|
40011
40330
|
try {
|
|
40012
|
-
return JSON.parse(
|
|
40331
|
+
return JSON.parse(readFileSync21(path, "utf-8"));
|
|
40013
40332
|
} catch {
|
|
40014
40333
|
return null;
|
|
40015
40334
|
}
|
|
@@ -40125,7 +40444,7 @@ function scheduleBusyAck(channel, threadTs, messageTs, isThreadReply, arrivedWhi
|
|
|
40125
40444
|
let paneLogFreshAgeMs = null;
|
|
40126
40445
|
if (SLACK_AGENT_DIR) {
|
|
40127
40446
|
try {
|
|
40128
|
-
const paneMtimeMs =
|
|
40447
|
+
const paneMtimeMs = statSync5(join21(SLACK_AGENT_DIR, "pane.log")).mtimeMs;
|
|
40129
40448
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
40130
40449
|
} catch {
|
|
40131
40450
|
}
|
|
@@ -40158,7 +40477,7 @@ function __resetSlackBusyAckNoticeThrottle() {
|
|
|
40158
40477
|
function clearSlackMarkerFileWithHeal(fullPath) {
|
|
40159
40478
|
let marker = null;
|
|
40160
40479
|
try {
|
|
40161
|
-
marker = JSON.parse(
|
|
40480
|
+
marker = JSON.parse(readFileSync21(fullPath, "utf-8"));
|
|
40162
40481
|
} catch {
|
|
40163
40482
|
}
|
|
40164
40483
|
if (marker && decideRecoveryHeal({
|
|
@@ -40176,7 +40495,7 @@ function clearSlackMarkerFileWithHeal(fullPath) {
|
|
|
40176
40495
|
function markSlackMarkerSeenWithHeal(fullPath) {
|
|
40177
40496
|
let marker = null;
|
|
40178
40497
|
try {
|
|
40179
|
-
marker = JSON.parse(
|
|
40498
|
+
marker = JSON.parse(readFileSync21(fullPath, "utf-8"));
|
|
40180
40499
|
} catch {
|
|
40181
40500
|
return;
|
|
40182
40501
|
}
|
|
@@ -40245,10 +40564,10 @@ function slackNextRetryName(filename) {
|
|
|
40245
40564
|
async function processSlackRecoveryOutboxFile(filename) {
|
|
40246
40565
|
if (!SLACK_RECOVERY_OUTBOX_DIR) return;
|
|
40247
40566
|
if (filename.endsWith(".poison.json") || filename.endsWith(".tmp")) return;
|
|
40248
|
-
const fullPath =
|
|
40567
|
+
const fullPath = join21(SLACK_RECOVERY_OUTBOX_DIR, filename);
|
|
40249
40568
|
let payload;
|
|
40250
40569
|
try {
|
|
40251
|
-
payload = JSON.parse(
|
|
40570
|
+
payload = JSON.parse(readFileSync21(fullPath, "utf-8"));
|
|
40252
40571
|
} catch (err) {
|
|
40253
40572
|
process.stderr.write(
|
|
40254
40573
|
`slack-channel(${AGENT_CODE_NAME}): recovery outbox parse failed (${filename}): ${err.message}
|
|
@@ -40352,7 +40671,7 @@ async function processSlackRecoveryOutboxFile(filename) {
|
|
|
40352
40671
|
const next = slackNextRetryName(filename);
|
|
40353
40672
|
if (next) {
|
|
40354
40673
|
try {
|
|
40355
|
-
renameSync5(fullPath,
|
|
40674
|
+
renameSync5(fullPath, join21(SLACK_RECOVERY_OUTBOX_DIR, next.next));
|
|
40356
40675
|
if (next.attempt >= SLACK_MAX_RECOVERY_ATTEMPTS) {
|
|
40357
40676
|
process.stderr.write(
|
|
40358
40677
|
`slack-channel(${AGENT_CODE_NAME}): ghost-reply recovery exhausted retries \u2014 moved to ${next.next}
|
|
@@ -40383,7 +40702,7 @@ function scanSlackRecoveryRetries() {
|
|
|
40383
40702
|
if (!SLACK_RECOVERY_OUTBOX_DIR) return;
|
|
40384
40703
|
let entries;
|
|
40385
40704
|
try {
|
|
40386
|
-
entries =
|
|
40705
|
+
entries = readdirSync7(SLACK_RECOVERY_OUTBOX_DIR);
|
|
40387
40706
|
} catch {
|
|
40388
40707
|
return;
|
|
40389
40708
|
}
|
|
@@ -40392,7 +40711,7 @@ function scanSlackRecoveryRetries() {
|
|
|
40392
40711
|
if (!f.includes(".retry-") || f.endsWith(".poison.json")) continue;
|
|
40393
40712
|
let mtimeMs;
|
|
40394
40713
|
try {
|
|
40395
|
-
mtimeMs =
|
|
40714
|
+
mtimeMs = statSync5(join21(SLACK_RECOVERY_OUTBOX_DIR, f)).mtimeMs;
|
|
40396
40715
|
} catch {
|
|
40397
40716
|
continue;
|
|
40398
40717
|
}
|
|
@@ -40413,7 +40732,7 @@ function startSlackRecoveryOutboxWatcher() {
|
|
|
40413
40732
|
return;
|
|
40414
40733
|
}
|
|
40415
40734
|
try {
|
|
40416
|
-
for (const f of
|
|
40735
|
+
for (const f of readdirSync7(SLACK_RECOVERY_OUTBOX_DIR)) {
|
|
40417
40736
|
if (isFirstAttemptSlackOutboxFile(f)) void processSlackRecoveryOutboxFile(f);
|
|
40418
40737
|
}
|
|
40419
40738
|
} catch {
|
|
@@ -40422,7 +40741,7 @@ function startSlackRecoveryOutboxWatcher() {
|
|
|
40422
40741
|
const watcher = watch(SLACK_RECOVERY_OUTBOX_DIR, (event, filename) => {
|
|
40423
40742
|
if (event !== "rename" || !filename) return;
|
|
40424
40743
|
if (!isFirstAttemptSlackOutboxFile(filename)) return;
|
|
40425
|
-
if (existsSync10(
|
|
40744
|
+
if (existsSync10(join21(SLACK_RECOVERY_OUTBOX_DIR, filename))) {
|
|
40426
40745
|
void processSlackRecoveryOutboxFile(filename);
|
|
40427
40746
|
}
|
|
40428
40747
|
});
|
|
@@ -40437,7 +40756,7 @@ function startSlackRecoveryOutboxWatcher() {
|
|
|
40437
40756
|
retryTimer.unref?.();
|
|
40438
40757
|
}
|
|
40439
40758
|
startSlackRecoveryOutboxWatcher();
|
|
40440
|
-
var SLACK_NOTICE_OUTBOX_DIR = SLACK_AGENT_DIR ?
|
|
40759
|
+
var SLACK_NOTICE_OUTBOX_DIR = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, "slack-notice-outbox") : null;
|
|
40441
40760
|
var SLACK_NOTICE_MAX_AGE_MS = 9e4;
|
|
40442
40761
|
var SLACK_NOTICE_INFLIGHT = /* @__PURE__ */ new Set();
|
|
40443
40762
|
async function processSlackNoticeOutboxFile(filename) {
|
|
@@ -40445,11 +40764,11 @@ async function processSlackNoticeOutboxFile(filename) {
|
|
|
40445
40764
|
if (filename.startsWith(".") || filename.endsWith(".tmp") || !filename.endsWith(".json")) return;
|
|
40446
40765
|
if (SLACK_NOTICE_INFLIGHT.has(filename)) return;
|
|
40447
40766
|
SLACK_NOTICE_INFLIGHT.add(filename);
|
|
40448
|
-
const fullPath =
|
|
40767
|
+
const fullPath = join21(SLACK_NOTICE_OUTBOX_DIR, filename);
|
|
40449
40768
|
try {
|
|
40450
40769
|
let mtimeMs;
|
|
40451
40770
|
try {
|
|
40452
|
-
mtimeMs =
|
|
40771
|
+
mtimeMs = statSync5(fullPath).mtimeMs;
|
|
40453
40772
|
} catch {
|
|
40454
40773
|
return;
|
|
40455
40774
|
}
|
|
@@ -40462,7 +40781,7 @@ async function processSlackNoticeOutboxFile(filename) {
|
|
|
40462
40781
|
}
|
|
40463
40782
|
let payload;
|
|
40464
40783
|
try {
|
|
40465
|
-
const parsed = JSON.parse(
|
|
40784
|
+
const parsed = JSON.parse(readFileSync21(fullPath, "utf-8"));
|
|
40466
40785
|
if (!parsed || typeof parsed !== "object") throw new Error("not an object");
|
|
40467
40786
|
payload = parsed;
|
|
40468
40787
|
} catch {
|
|
@@ -40545,13 +40864,13 @@ function startSlackNoticeOutboxWatcher() {
|
|
|
40545
40864
|
return;
|
|
40546
40865
|
}
|
|
40547
40866
|
try {
|
|
40548
|
-
for (const f of
|
|
40867
|
+
for (const f of readdirSync7(SLACK_NOTICE_OUTBOX_DIR)) void processSlackNoticeOutboxFile(f);
|
|
40549
40868
|
} catch {
|
|
40550
40869
|
}
|
|
40551
40870
|
try {
|
|
40552
40871
|
const watcher = watch(SLACK_NOTICE_OUTBOX_DIR, (event, filename) => {
|
|
40553
40872
|
if (event !== "rename" || !filename) return;
|
|
40554
|
-
if (existsSync10(
|
|
40873
|
+
if (existsSync10(join21(SLACK_NOTICE_OUTBOX_DIR, filename))) {
|
|
40555
40874
|
void processSlackNoticeOutboxFile(filename);
|
|
40556
40875
|
}
|
|
40557
40876
|
});
|
|
@@ -40574,7 +40893,7 @@ function sweepSlackStaleMarkers(thresholdMs) {
|
|
|
40574
40893
|
if (!existsSync10(SLACK_PENDING_INBOUND_DIR)) return;
|
|
40575
40894
|
let filenames;
|
|
40576
40895
|
try {
|
|
40577
|
-
filenames =
|
|
40896
|
+
filenames = readdirSync7(SLACK_PENDING_INBOUND_DIR);
|
|
40578
40897
|
} catch (err) {
|
|
40579
40898
|
process.stderr.write(
|
|
40580
40899
|
`slack-channel(${AGENT_CODE_NAME}): stale-marker readdir failed: ${err.message}
|
|
@@ -40588,10 +40907,10 @@ function sweepSlackStaleMarkers(thresholdMs) {
|
|
|
40588
40907
|
for (const filename of filenames) {
|
|
40589
40908
|
if (!filename.endsWith(".json")) continue;
|
|
40590
40909
|
if (filename.endsWith(".tmp")) continue;
|
|
40591
|
-
const fullPath =
|
|
40910
|
+
const fullPath = join21(SLACK_PENDING_INBOUND_DIR, filename);
|
|
40592
40911
|
let marker;
|
|
40593
40912
|
try {
|
|
40594
|
-
marker = JSON.parse(
|
|
40913
|
+
marker = JSON.parse(readFileSync21(fullPath, "utf-8"));
|
|
40595
40914
|
} catch (err) {
|
|
40596
40915
|
process.stderr.write(
|
|
40597
40916
|
`slack-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactSlackId(filename)}: ${err.message}
|
|
@@ -40649,13 +40968,13 @@ var slackOrphanSweepTimer = setInterval(() => {
|
|
|
40649
40968
|
checkSlackWatchdogGiveUpNotice();
|
|
40650
40969
|
}, orphanSweepIntervalMs());
|
|
40651
40970
|
slackOrphanSweepTimer.unref?.();
|
|
40652
|
-
var SLACK_PROGRESS_HEARTBEAT_PATH = SLACK_AGENT_DIR ?
|
|
40971
|
+
var SLACK_PROGRESS_HEARTBEAT_PATH = SLACK_AGENT_DIR ? join21(SLACK_AGENT_DIR, "channel-progress-heartbeat.json") : null;
|
|
40653
40972
|
var slackTrackedProgress = null;
|
|
40654
40973
|
var slackProgressTickRunning = false;
|
|
40655
40974
|
function readSlackProgressHeartbeat() {
|
|
40656
40975
|
if (!SLACK_PROGRESS_HEARTBEAT_PATH || !existsSync10(SLACK_PROGRESS_HEARTBEAT_PATH)) return null;
|
|
40657
40976
|
try {
|
|
40658
|
-
return parseProgressHeartbeat(
|
|
40977
|
+
return parseProgressHeartbeat(readFileSync21(SLACK_PROGRESS_HEARTBEAT_PATH, "utf-8"));
|
|
40659
40978
|
} catch {
|
|
40660
40979
|
return null;
|
|
40661
40980
|
}
|
|
@@ -40678,11 +40997,11 @@ function findSlackProgressTarget() {
|
|
|
40678
40997
|
let best = null;
|
|
40679
40998
|
let bestMs = Infinity;
|
|
40680
40999
|
try {
|
|
40681
|
-
for (const name of
|
|
41000
|
+
for (const name of readdirSync7(SLACK_PENDING_INBOUND_DIR)) {
|
|
40682
41001
|
if (!name.endsWith(".json")) continue;
|
|
40683
41002
|
let m;
|
|
40684
41003
|
try {
|
|
40685
|
-
m = JSON.parse(
|
|
41004
|
+
m = JSON.parse(readFileSync21(join21(SLACK_PENDING_INBOUND_DIR, name), "utf-8"));
|
|
40686
41005
|
} catch {
|
|
40687
41006
|
continue;
|
|
40688
41007
|
}
|
|
@@ -40829,11 +41148,11 @@ function listPendingSlackConversations() {
|
|
|
40829
41148
|
if (!SLACK_PENDING_INBOUND_DIR || !existsSync10(SLACK_PENDING_INBOUND_DIR)) return [];
|
|
40830
41149
|
const byKey = /* @__PURE__ */ new Map();
|
|
40831
41150
|
try {
|
|
40832
|
-
for (const name of
|
|
41151
|
+
for (const name of readdirSync7(SLACK_PENDING_INBOUND_DIR)) {
|
|
40833
41152
|
if (!name.endsWith(".json")) continue;
|
|
40834
41153
|
try {
|
|
40835
41154
|
const marker = JSON.parse(
|
|
40836
|
-
|
|
41155
|
+
readFileSync21(join21(SLACK_PENDING_INBOUND_DIR, name), "utf8")
|
|
40837
41156
|
);
|
|
40838
41157
|
if (typeof marker.channel !== "string" || !marker.channel) continue;
|
|
40839
41158
|
if (typeof marker.thread_ts !== "string" || !marker.thread_ts) continue;
|
|
@@ -40852,6 +41171,95 @@ function listPendingSlackConversations() {
|
|
|
40852
41171
|
}
|
|
40853
41172
|
return [...byKey.values()];
|
|
40854
41173
|
}
|
|
41174
|
+
var lastSlackTurnFailedNoticeAt = /* @__PURE__ */ new Map();
|
|
41175
|
+
var lastSlackTurnRetryingNoticeAt = /* @__PURE__ */ new Map();
|
|
41176
|
+
async function postSlackTurnNotice(args) {
|
|
41177
|
+
if (!BOT_TOKEN || !args.channel) return { ok: false, error: "no_bot_token_or_channel" };
|
|
41178
|
+
try {
|
|
41179
|
+
const res = await fetch("https://slack.com/api/chat.postMessage", {
|
|
41180
|
+
method: "POST",
|
|
41181
|
+
headers: {
|
|
41182
|
+
"Content-Type": "application/json",
|
|
41183
|
+
Authorization: `Bearer ${BOT_TOKEN}`
|
|
41184
|
+
},
|
|
41185
|
+
body: JSON.stringify({
|
|
41186
|
+
channel: args.channel,
|
|
41187
|
+
text: args.text,
|
|
41188
|
+
// Anchor to the originating message, matching the give-up notice: the
|
|
41189
|
+
// user must see this against the message it concerns.
|
|
41190
|
+
...args.threadTs ? { thread_ts: args.threadTs } : {}
|
|
41191
|
+
}),
|
|
41192
|
+
signal: AbortSignal.timeout(1e4)
|
|
41193
|
+
});
|
|
41194
|
+
const body = await res.json().catch(() => ({}));
|
|
41195
|
+
if (body.ok === true) return { ok: true };
|
|
41196
|
+
return { ok: false, error: body.error ?? `http_${res.status}` };
|
|
41197
|
+
} catch (err) {
|
|
41198
|
+
return { ok: false, error: err.name || "fetch_failed" };
|
|
41199
|
+
}
|
|
41200
|
+
}
|
|
41201
|
+
function armSlackTurnFailureWatch(args) {
|
|
41202
|
+
const channel = args.channel;
|
|
41203
|
+
if (!channel) return;
|
|
41204
|
+
const conversationKey = args.threadTs ? `${channel}:${args.threadTs}` : channel;
|
|
41205
|
+
void (async () => {
|
|
41206
|
+
try {
|
|
41207
|
+
const failure = await watchForTurnFailure({
|
|
41208
|
+
sinceMs: args.sinceMs,
|
|
41209
|
+
channel: "slack",
|
|
41210
|
+
onLongRetry: async () => {
|
|
41211
|
+
const now2 = Date.now();
|
|
41212
|
+
if (!shouldPostUndeliverableNotice(lastSlackTurnRetryingNoticeAt.get(conversationKey), now2)) {
|
|
41213
|
+
return;
|
|
41214
|
+
}
|
|
41215
|
+
lastSlackTurnRetryingNoticeAt.set(conversationKey, now2);
|
|
41216
|
+
const posted2 = await postSlackTurnNotice({
|
|
41217
|
+
channel,
|
|
41218
|
+
threadTs: args.threadTs,
|
|
41219
|
+
text: turnRetryingNoticeText()
|
|
41220
|
+
});
|
|
41221
|
+
if (!posted2.ok) lastSlackTurnRetryingNoticeAt.delete(conversationKey);
|
|
41222
|
+
process.stderr.write(
|
|
41223
|
+
`slack-channel(${AGENT_CODE_NAME}): [turn-failure] retrying notice ${posted2.ok ? "posted" : `FAILED (${posted2.error})`} channel=${redactSlackId(channel)}
|
|
41224
|
+
`
|
|
41225
|
+
);
|
|
41226
|
+
}
|
|
41227
|
+
});
|
|
41228
|
+
if (!failure) return;
|
|
41229
|
+
const now = Date.now();
|
|
41230
|
+
if (!shouldPostUndeliverableNotice(lastSlackTurnFailedNoticeAt.get(conversationKey), now)) {
|
|
41231
|
+
process.stderr.write(
|
|
41232
|
+
`slack-channel(${AGENT_CODE_NAME}): [turn-failure] suppressed (throttled) channel=${redactSlackId(channel)} class=${failure.failureClass}
|
|
41233
|
+
`
|
|
41234
|
+
);
|
|
41235
|
+
return;
|
|
41236
|
+
}
|
|
41237
|
+
lastSlackTurnFailedNoticeAt.set(conversationKey, now);
|
|
41238
|
+
const posted = await postSlackTurnNotice({
|
|
41239
|
+
channel,
|
|
41240
|
+
threadTs: args.threadTs,
|
|
41241
|
+
text: turnFailedNoticeText()
|
|
41242
|
+
});
|
|
41243
|
+
if (!posted.ok) {
|
|
41244
|
+
lastSlackTurnFailedNoticeAt.delete(conversationKey);
|
|
41245
|
+
process.stderr.write(
|
|
41246
|
+
`slack-channel(${AGENT_CODE_NAME}): [turn-failure] NOTICE POST FAILED (${posted.error}) channel=${redactSlackId(channel)} - the user is still waiting on a dead turn
|
|
41247
|
+
`
|
|
41248
|
+
);
|
|
41249
|
+
return;
|
|
41250
|
+
}
|
|
41251
|
+
process.stderr.write(
|
|
41252
|
+
`slack-channel(${AGENT_CODE_NAME}): [turn-failure] notified channel=${redactSlackId(channel)} ts=${redactSlackId(args.messageTs)} class=${failure.failureClass} status=${failure.httpStatus}
|
|
41253
|
+
`
|
|
41254
|
+
);
|
|
41255
|
+
} catch (err) {
|
|
41256
|
+
process.stderr.write(
|
|
41257
|
+
`slack-channel(${AGENT_CODE_NAME}): [turn-failure] watch error: ${err.message}
|
|
41258
|
+
`
|
|
41259
|
+
);
|
|
41260
|
+
}
|
|
41261
|
+
})();
|
|
41262
|
+
}
|
|
40855
41263
|
function postSlackWatchdogGiveUpNotice(channel, threadTs, isThreadReply, reason) {
|
|
40856
41264
|
if (!BOT_TOKEN || !channel) return;
|
|
40857
41265
|
const now = Date.now();
|
|
@@ -40885,7 +41293,7 @@ function postSlackWatchdogGiveUpNotice(channel, threadTs, isThreadReply, reason)
|
|
|
40885
41293
|
}
|
|
40886
41294
|
function checkSlackWatchdogGiveUpNotice() {
|
|
40887
41295
|
if (!SLACK_AGENT_DIR) return;
|
|
40888
|
-
const signal = readGiveUpSignal(
|
|
41296
|
+
const signal = readGiveUpSignal(join21(SLACK_AGENT_DIR, GIVE_UP_SIGNAL_FILENAME));
|
|
40889
41297
|
const signalAtMs = signal?.atMs ?? null;
|
|
40890
41298
|
const act = decideGiveUpNotice({
|
|
40891
41299
|
signalAtMs,
|
|
@@ -40917,7 +41325,7 @@ function readRestartTopicForMarker(filename, channel, threadTs) {
|
|
|
40917
41325
|
if (!SLACK_RESTART_CONTEXT_DIR) return null;
|
|
40918
41326
|
let raw;
|
|
40919
41327
|
try {
|
|
40920
|
-
raw =
|
|
41328
|
+
raw = readFileSync21(join21(SLACK_RESTART_CONTEXT_DIR, filename), "utf-8");
|
|
40921
41329
|
} catch {
|
|
40922
41330
|
return null;
|
|
40923
41331
|
}
|
|
@@ -40926,7 +41334,7 @@ function readRestartTopicForMarker(filename, channel, threadTs) {
|
|
|
40926
41334
|
function removeRestartContextHint(filename) {
|
|
40927
41335
|
if (!SLACK_RESTART_CONTEXT_DIR) return;
|
|
40928
41336
|
try {
|
|
40929
|
-
unlinkSync7(
|
|
41337
|
+
unlinkSync7(join21(SLACK_RESTART_CONTEXT_DIR, filename));
|
|
40930
41338
|
} catch {
|
|
40931
41339
|
}
|
|
40932
41340
|
}
|
|
@@ -40934,14 +41342,14 @@ function clearAllRestartContextHints() {
|
|
|
40934
41342
|
if (!SLACK_RESTART_CONTEXT_DIR) return;
|
|
40935
41343
|
let names;
|
|
40936
41344
|
try {
|
|
40937
|
-
names =
|
|
41345
|
+
names = readdirSync7(SLACK_RESTART_CONTEXT_DIR);
|
|
40938
41346
|
} catch {
|
|
40939
41347
|
return;
|
|
40940
41348
|
}
|
|
40941
41349
|
for (const name of names) {
|
|
40942
41350
|
if (!name.endsWith(".json")) continue;
|
|
40943
41351
|
try {
|
|
40944
|
-
unlinkSync7(
|
|
41352
|
+
unlinkSync7(join21(SLACK_RESTART_CONTEXT_DIR, name));
|
|
40945
41353
|
} catch {
|
|
40946
41354
|
}
|
|
40947
41355
|
}
|
|
@@ -40958,7 +41366,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
|
|
|
40958
41366
|
if (!SLACK_PENDING_INBOUND_DIR || !existsSync10(SLACK_PENDING_INBOUND_DIR)) return;
|
|
40959
41367
|
let filenames;
|
|
40960
41368
|
try {
|
|
40961
|
-
filenames =
|
|
41369
|
+
filenames = readdirSync7(SLACK_PENDING_INBOUND_DIR);
|
|
40962
41370
|
} catch {
|
|
40963
41371
|
hadFailure = true;
|
|
40964
41372
|
return;
|
|
@@ -40968,10 +41376,10 @@ async function notifyStrandedInboundsOnFirstConnect() {
|
|
|
40968
41376
|
let notified = 0;
|
|
40969
41377
|
for (const filename of filenames) {
|
|
40970
41378
|
if (!filename.endsWith(".json")) continue;
|
|
40971
|
-
const fullPath =
|
|
41379
|
+
const fullPath = join21(SLACK_PENDING_INBOUND_DIR, filename);
|
|
40972
41380
|
let marker;
|
|
40973
41381
|
try {
|
|
40974
|
-
marker = JSON.parse(
|
|
41382
|
+
marker = JSON.parse(readFileSync21(fullPath, "utf-8"));
|
|
40975
41383
|
} catch {
|
|
40976
41384
|
continue;
|
|
40977
41385
|
}
|
|
@@ -41145,7 +41553,7 @@ function noteThreadActivityByMessageTs(channel, messageTs) {
|
|
|
41145
41553
|
markSeenAllSlackPendingMarkersForThread2(channel, messageTs);
|
|
41146
41554
|
markSeenSlackPendingMarkerByMessageTs2(channel, messageTs);
|
|
41147
41555
|
}
|
|
41148
|
-
var RESTART_FLAGS_DIR =
|
|
41556
|
+
var RESTART_FLAGS_DIR = join21(homedir7(), ".augmented", "restart-flags");
|
|
41149
41557
|
function actuateHostRestartSlack() {
|
|
41150
41558
|
return actuateHostRestart({
|
|
41151
41559
|
agtHost: AGT_HOST,
|
|
@@ -41750,7 +42158,7 @@ async function handleSlashCommandEnvelope(payload) {
|
|
|
41750
42158
|
if (!existsSync10(RESTART_FLAGS_DIR)) {
|
|
41751
42159
|
mkdirSync9(RESTART_FLAGS_DIR, { recursive: true });
|
|
41752
42160
|
}
|
|
41753
|
-
const flagPath =
|
|
42161
|
+
const flagPath = join21(RESTART_FLAGS_DIR, `${codeName}.flag`);
|
|
41754
42162
|
const flag = {
|
|
41755
42163
|
codeName,
|
|
41756
42164
|
source: "slack",
|
|
@@ -41893,7 +42301,7 @@ async function handleRestartCommand(opts) {
|
|
|
41893
42301
|
if (!existsSync10(RESTART_FLAGS_DIR)) {
|
|
41894
42302
|
mkdirSync9(RESTART_FLAGS_DIR, { recursive: true });
|
|
41895
42303
|
}
|
|
41896
|
-
const flagPath =
|
|
42304
|
+
const flagPath = join21(RESTART_FLAGS_DIR, `${codeName}.flag`);
|
|
41897
42305
|
const flag = {
|
|
41898
42306
|
codeName,
|
|
41899
42307
|
source: "slack",
|
|
@@ -42015,7 +42423,7 @@ var SLACK_HOT_THREAD_WINDOW_MS = parseHotThreadWindowMs(
|
|
|
42015
42423
|
);
|
|
42016
42424
|
function resolveThreadStorePath() {
|
|
42017
42425
|
if (!AGENT_CODE_NAME) return null;
|
|
42018
|
-
return
|
|
42426
|
+
return join21(homedir7(), ".augmented", AGENT_CODE_NAME, "slack-tracked-threads.json");
|
|
42019
42427
|
}
|
|
42020
42428
|
function parseTtlDays(raw) {
|
|
42021
42429
|
if (!raw) return void 0;
|
|
@@ -42054,9 +42462,9 @@ if (!BOT_TOKEN || !APP_TOKEN) {
|
|
|
42054
42462
|
var slackStderrLogStream = null;
|
|
42055
42463
|
if (AGENT_CODE_NAME) {
|
|
42056
42464
|
try {
|
|
42057
|
-
const logDir =
|
|
42465
|
+
const logDir = join21(homedir7(), ".augmented", AGENT_CODE_NAME);
|
|
42058
42466
|
mkdirSync9(logDir, { recursive: true });
|
|
42059
|
-
slackStderrLogStream = createWriteStream(
|
|
42467
|
+
slackStderrLogStream = createWriteStream(join21(logDir, "slack-channel-stderr.log"), {
|
|
42060
42468
|
flags: "a",
|
|
42061
42469
|
mode: 384
|
|
42062
42470
|
});
|
|
@@ -42946,7 +43354,7 @@ ${result.formatted}` : "No messages in range, or the bot is not a member of this
|
|
|
42946
43354
|
let bytes;
|
|
42947
43355
|
let size;
|
|
42948
43356
|
try {
|
|
42949
|
-
const stat2 =
|
|
43357
|
+
const stat2 = statSync5(resolvedPath);
|
|
42950
43358
|
if (!stat2.isFile()) {
|
|
42951
43359
|
return {
|
|
42952
43360
|
content: [{ type: "text", text: `Upload refused: ${resolvedPath} is not a regular file.` }],
|
|
@@ -42954,7 +43362,7 @@ ${result.formatted}` : "No messages in range, or the bot is not a member of this
|
|
|
42954
43362
|
};
|
|
42955
43363
|
}
|
|
42956
43364
|
size = stat2.size;
|
|
42957
|
-
bytes =
|
|
43365
|
+
bytes = readFileSync21(resolvedPath);
|
|
42958
43366
|
} catch (err) {
|
|
42959
43367
|
return {
|
|
42960
43368
|
content: [{ type: "text", text: `Failed to read file: ${err.message}` }],
|
|
@@ -43729,7 +44137,7 @@ async function replayPendingSlackMarkers() {
|
|
|
43729
44137
|
if (!sessionAlive) return;
|
|
43730
44138
|
let filenames;
|
|
43731
44139
|
try {
|
|
43732
|
-
filenames =
|
|
44140
|
+
filenames = readdirSync7(SLACK_PENDING_INBOUND_DIR);
|
|
43733
44141
|
} catch {
|
|
43734
44142
|
return;
|
|
43735
44143
|
}
|
|
@@ -43737,7 +44145,7 @@ async function replayPendingSlackMarkers() {
|
|
|
43737
44145
|
let paneFreshAgeMs = null;
|
|
43738
44146
|
if (SLACK_AGENT_DIR) {
|
|
43739
44147
|
try {
|
|
43740
|
-
paneFreshAgeMs = Math.max(0, now -
|
|
44148
|
+
paneFreshAgeMs = Math.max(0, now - statSync5(join21(SLACK_AGENT_DIR, "pane.log")).mtimeMs);
|
|
43741
44149
|
} catch {
|
|
43742
44150
|
}
|
|
43743
44151
|
}
|
|
@@ -43745,10 +44153,10 @@ async function replayPendingSlackMarkers() {
|
|
|
43745
44153
|
const entries = [];
|
|
43746
44154
|
for (const name of filenames) {
|
|
43747
44155
|
if (!name.endsWith(".json") || name.endsWith(".tmp")) continue;
|
|
43748
|
-
const fullPath =
|
|
44156
|
+
const fullPath = join21(SLACK_PENDING_INBOUND_DIR, name);
|
|
43749
44157
|
let marker;
|
|
43750
44158
|
try {
|
|
43751
|
-
marker = JSON.parse(
|
|
44159
|
+
marker = JSON.parse(readFileSync21(fullPath, "utf-8"));
|
|
43752
44160
|
} catch {
|
|
43753
44161
|
continue;
|
|
43754
44162
|
}
|
|
@@ -44346,7 +44754,7 @@ async function connectSocketMode() {
|
|
|
44346
44754
|
let paneLogFreshAgeMs = null;
|
|
44347
44755
|
if (SLACK_AGENT_DIR) {
|
|
44348
44756
|
try {
|
|
44349
|
-
const paneMtimeMs =
|
|
44757
|
+
const paneMtimeMs = statSync5(join21(SLACK_AGENT_DIR, "pane.log")).mtimeMs;
|
|
44350
44758
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
44351
44759
|
} catch {
|
|
44352
44760
|
}
|
|
@@ -44532,6 +44940,14 @@ ${forwarded.text}` : forwarded.text;
|
|
|
44532
44940
|
sinceMs: dispatchedAtMs
|
|
44533
44941
|
});
|
|
44534
44942
|
}
|
|
44943
|
+
if (shouldEngage && !isFromBot && turnFailureNoticeEnabled()) {
|
|
44944
|
+
armSlackTurnFailureWatch({
|
|
44945
|
+
channel,
|
|
44946
|
+
threadTs,
|
|
44947
|
+
messageTs: ts,
|
|
44948
|
+
sinceMs: dispatchedAtMs
|
|
44949
|
+
});
|
|
44950
|
+
}
|
|
44535
44951
|
if (shouldEngage) seedSlackProgressHeartbeat();
|
|
44536
44952
|
if (channel) {
|
|
44537
44953
|
conversationIngestClient?.ingest({
|