@integrity-labs/agt-cli 0.28.337 → 0.28.339
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-J2WYEOBH.js → chunk-J6QDPXGS.js} +32 -1
- package/dist/{chunk-J2WYEOBH.js.map → chunk-J6QDPXGS.js.map} +1 -1
- package/dist/{chunk-N7XPDFCW.js → chunk-UVMGRGRO.js} +16 -5
- package/dist/{chunk-N7XPDFCW.js.map → chunk-UVMGRGRO.js.map} +1 -1
- package/dist/{claude-pair-runtime-T7EFAWS5.js → claude-pair-runtime-F55PDOWQ.js} +2 -2
- package/dist/lib/manager-worker.js +10 -10
- package/dist/mcp/origami.js +30 -0
- package/dist/mcp/slack-channel.js +125 -6
- package/dist/{persistent-session-ENQXJNBJ.js → persistent-session-4UG3S54C.js} +2 -2
- package/dist/{responsiveness-probe-46XFHCPY.js → responsiveness-probe-TK47IXPX.js} +2 -2
- package/package.json +1 -1
- /package/dist/{claude-pair-runtime-T7EFAWS5.js.map → claude-pair-runtime-F55PDOWQ.js.map} +0 -0
- /package/dist/{persistent-session-ENQXJNBJ.js.map → persistent-session-4UG3S54C.js.map} +0 -0
- /package/dist/{responsiveness-probe-46XFHCPY.js.map → responsiveness-probe-TK47IXPX.js.map} +0 -0
|
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
|
|
|
100
100
|
return { ok: true };
|
|
101
101
|
} catch {
|
|
102
102
|
}
|
|
103
|
-
const { resolveClaudeBinary } = await import("./persistent-session-
|
|
103
|
+
const { resolveClaudeBinary } = await import("./persistent-session-4UG3S54C.js");
|
|
104
104
|
const claudeBin = resolveClaudeBinary();
|
|
105
105
|
const pairEnv = {
|
|
106
106
|
...process.env,
|
|
@@ -373,4 +373,4 @@ export {
|
|
|
373
373
|
startClaudePair,
|
|
374
374
|
submitClaudePairCode
|
|
375
375
|
};
|
|
376
|
-
//# sourceMappingURL=claude-pair-runtime-
|
|
376
|
+
//# sourceMappingURL=claude-pair-runtime-F55PDOWQ.js.map
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
requireHost,
|
|
46
46
|
safeWriteJsonAtomic,
|
|
47
47
|
setConfigHash
|
|
48
|
-
} from "../chunk-
|
|
48
|
+
} from "../chunk-UVMGRGRO.js";
|
|
49
49
|
import {
|
|
50
50
|
getProjectDir as getProjectDir2,
|
|
51
51
|
getReadyTasks,
|
|
@@ -134,7 +134,7 @@ import {
|
|
|
134
134
|
takeZombieDetection,
|
|
135
135
|
transcriptActivityAgeSeconds,
|
|
136
136
|
writeEgressAllowlist
|
|
137
|
-
} from "../chunk-
|
|
137
|
+
} from "../chunk-J6QDPXGS.js";
|
|
138
138
|
import {
|
|
139
139
|
reapOrphanChannelMcps
|
|
140
140
|
} from "../chunk-XWVM4KPK.js";
|
|
@@ -8388,7 +8388,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
8388
8388
|
var lastVersionCheckAt = 0;
|
|
8389
8389
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
8390
8390
|
var lastResponsivenessProbeAt = 0;
|
|
8391
|
-
var agtCliVersion = true ? "0.28.
|
|
8391
|
+
var agtCliVersion = true ? "0.28.339" : "dev";
|
|
8392
8392
|
function resolveBrewPath(execFileSync2) {
|
|
8393
8393
|
try {
|
|
8394
8394
|
const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -9343,7 +9343,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
|
|
|
9343
9343
|
if (codeNames.length === 0) return;
|
|
9344
9344
|
void (async () => {
|
|
9345
9345
|
try {
|
|
9346
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
9346
|
+
const { collectDiagnostics } = await import("../persistent-session-4UG3S54C.js");
|
|
9347
9347
|
await api.post("/host/heartbeat", {
|
|
9348
9348
|
host_id: hostId,
|
|
9349
9349
|
agent_diagnostics: collectDiagnostics(codeNames)
|
|
@@ -9442,7 +9442,7 @@ async function pollCycle() {
|
|
|
9442
9442
|
}
|
|
9443
9443
|
try {
|
|
9444
9444
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
9445
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
9445
|
+
const { collectDiagnostics } = await import("../persistent-session-4UG3S54C.js");
|
|
9446
9446
|
const diagCodeNames = [...agentState.persistentSessionAgents];
|
|
9447
9447
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
9448
9448
|
let tailscaleHostname;
|
|
@@ -9591,7 +9591,7 @@ async function pollCycle() {
|
|
|
9591
9591
|
const {
|
|
9592
9592
|
collectResponsivenessProbes,
|
|
9593
9593
|
getResponsivenessIntervalMs
|
|
9594
|
-
} = await import("../responsiveness-probe-
|
|
9594
|
+
} = await import("../responsiveness-probe-TK47IXPX.js");
|
|
9595
9595
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
9596
9596
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
9597
9597
|
const probeCodeNames = [...agentState.persistentSessionAgents];
|
|
@@ -9623,7 +9623,7 @@ async function pollCycle() {
|
|
|
9623
9623
|
collectResponsivenessProbes,
|
|
9624
9624
|
livePendingInboundOldestAgeSeconds,
|
|
9625
9625
|
parkPendingInbound
|
|
9626
|
-
} = await import("../responsiveness-probe-
|
|
9626
|
+
} = await import("../responsiveness-probe-TK47IXPX.js");
|
|
9627
9627
|
const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
|
|
9628
9628
|
const wedgeNow = /* @__PURE__ */ new Date();
|
|
9629
9629
|
const liveAgents = agentState.persistentSessionAgents;
|
|
@@ -12721,7 +12721,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
|
|
|
12721
12721
|
void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
|
|
12722
12722
|
void (async () => {
|
|
12723
12723
|
try {
|
|
12724
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
12724
|
+
const { collectDiagnostics } = await import("../persistent-session-4UG3S54C.js");
|
|
12725
12725
|
await api.post("/host/heartbeat", {
|
|
12726
12726
|
host_id: hostId,
|
|
12727
12727
|
agent_diagnostics: collectDiagnostics([codeName])
|
|
@@ -12771,7 +12771,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
|
|
|
12771
12771
|
}
|
|
12772
12772
|
try {
|
|
12773
12773
|
const hostId = await getHostId();
|
|
12774
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
12774
|
+
const { collectDiagnostics } = await import("../persistent-session-4UG3S54C.js");
|
|
12775
12775
|
await api.post("/host/heartbeat", {
|
|
12776
12776
|
host_id: hostId,
|
|
12777
12777
|
agent_diagnostics: collectDiagnostics([codeName])
|
|
@@ -13269,7 +13269,7 @@ async function processClaudePairSessions(agents) {
|
|
|
13269
13269
|
killPairSession,
|
|
13270
13270
|
pairTmuxSession,
|
|
13271
13271
|
finalizeClaudePairOnboarding
|
|
13272
|
-
} = await import("../claude-pair-runtime-
|
|
13272
|
+
} = await import("../claude-pair-runtime-F55PDOWQ.js");
|
|
13273
13273
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
13274
13274
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
13275
13275
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
package/dist/mcp/origami.js
CHANGED
|
@@ -40139,6 +40139,24 @@ var FLAG_REGISTRY = [
|
|
|
40139
40139
|
// change (ADR-0022 sensitive-flag confirm).
|
|
40140
40140
|
sensitive: true
|
|
40141
40141
|
},
|
|
40142
|
+
{
|
|
40143
|
+
key: "slack-hot-thread-guard",
|
|
40144
|
+
description: "Server-side hot-thread guard on the slack.reply surface (ENG-7462). Prevents an agent posting a NEW top-level Slack message when it meant to reply inside the thread it is already working in - a prompt/memory rule proved insufficient (the agent had the rule and still slipped). When a reply would otherwise post to channel ROOT (no thread_ts / message_ts / inbound_id, no active kanban card) and the agent has a recent active thread in that channel (its last bot-posted thread, from the persisted trackedThreads cache, within a freshness window), the reply is redirected into that thread. proactive:true no longer implies channel root; posting at root becomes a deliberate action (the to_channel_root flag, or the thread_ts:null sentinel). off = guard never runs, replies with no coords root exactly as today (ships dark). shadow = compute + log the would-redirect but STILL post to root (measure the fire rate before acting). enforce = apply the redirect (a soft-block: redirect + inform, never a hard rejection). Read live from the heartbeat flags-cache (or the env override); enforce is a deliberate per-org flip after a shadow soak.",
|
|
40145
|
+
flagType: "enum",
|
|
40146
|
+
allowedValues: ["off", "shadow", "enforce"],
|
|
40147
|
+
// Ships dark: off preserves today's behaviour exactly (a coordless reply
|
|
40148
|
+
// roots). shadow is a free local log line (no model spend, unlike ghost-reply)
|
|
40149
|
+
// so it is a cheap opt-in soak; enforce changes where a reply lands, so it is
|
|
40150
|
+
// the audited flip.
|
|
40151
|
+
defaultValue: "off",
|
|
40152
|
+
// Enum override AGT_SLACK_HOT_THREAD_GUARD_MODE (off|shadow|enforce),
|
|
40153
|
+
// resolved by resolveSlackHotThreadMode in the channel-server bundle.
|
|
40154
|
+
envVar: "AGT_SLACK_HOT_THREAD_GUARD_MODE",
|
|
40155
|
+
// enforce reroutes a message the agent asked to send to channel root into a
|
|
40156
|
+
// thread - a visible destination change, so flipping toward it is deliberate
|
|
40157
|
+
// (ADR-0022 sensitive-flag confirm).
|
|
40158
|
+
sensitive: true
|
|
40159
|
+
},
|
|
40142
40160
|
{
|
|
40143
40161
|
key: "compaction-notice",
|
|
40144
40162
|
description: 'Compaction courtesy notice (ENG-7339): when a managed Claude Code session compacts its context, the persistent session pauses and stops replying for a stretch, which looks identical to a dead agent from the channel. When ON, the generated PreCompact hook finds the conversation the user is actively on (the last <channel ...> tag in the transcript) and drops a notice into the matching <channel>-notice-outbox; the channel MCP server (alive while the Claude process compacts) posts a short "reorganizing my memory, back shortly" line. The notice path never clears the pending-inbound marker, so the genuine reply the agent still owes after compaction is unaffected. No active channel tag \u21D2 silent (idle agents never broadcast). Boolean gate; ships dark, canary per host before any fleet flip. When OFF the hook writes nothing and the consumer drops any stray notice unsent.',
|
|
@@ -40449,6 +40467,18 @@ var FLAG_REGISTRY = [
|
|
|
40449
40467
|
// egress + workflow change worth an explicit confirm.
|
|
40450
40468
|
sensitive: true
|
|
40451
40469
|
},
|
|
40470
|
+
{
|
|
40471
|
+
key: "email-guard-per-scope-stage",
|
|
40472
|
+
description: "Per-agent / per-team email-domain guardrail rollout stage (ENG-7830 / ADR-0048). When ON for an org, the effective email_guard_stage is resolved most-specific-non-null (agent ?? team ?? org, with time-boxed exemption decay), so one agent can run shadow while the org is enforce (and vice-versa). When OFF (default) the stage is org-grain only (pre-ENG-7830 behaviour) - the per-agent/team email_guard_stage columns are ignored. Gates the resolver seam (getEffectiveEmailGuardStage) and the owner/admin write routes. Evaluated per-org. Ships dark.",
|
|
40473
|
+
flagType: "boolean",
|
|
40474
|
+
// Declared safe value is `false` (org-only stage = today's behaviour). A flag-DB
|
|
40475
|
+
// read error degrades here, so the per-scope columns stay ignored and the org
|
|
40476
|
+
// policy governs - the fail-closed direction for a compliance control.
|
|
40477
|
+
defaultValue: false,
|
|
40478
|
+
// Enabling it lets a lower scope LOOSEN an email compliance control per-agent, so
|
|
40479
|
+
// flipping it on is worth an explicit confirm (ADR-0022 §4).
|
|
40480
|
+
sensitive: true
|
|
40481
|
+
},
|
|
40452
40482
|
{
|
|
40453
40483
|
key: "slack-reply-binding",
|
|
40454
40484
|
description: "Slack reply-target binding (ENG-7396 / WS2, cross-thread reply routing): the model names which inbound it answers (inbound_id) and the server resolves the destination from its own verified record. shadow = classify + count only, routing unchanged; warn = same routing plus a tool-result note so the model self-corrects; enforce = route a bound reply to the registry thread and REJECT a reply whose target matches no inbound this process delivered. The channel server can't evaluate flags, so the manager materializes the resolved value into the AGT_SLACK_REPLY_BINDING spawn env (the operator/canary override, ADR-0022). Ships shadow.",
|
|
@@ -14744,6 +14744,40 @@ function resolveGhostReplyMode(opts) {
|
|
|
14744
14744
|
if (cached2 !== void 0) return cached2;
|
|
14745
14745
|
return "off";
|
|
14746
14746
|
}
|
|
14747
|
+
var SLACK_HOT_THREAD_FLAG_KEY = "slack-hot-thread-guard";
|
|
14748
|
+
function parseSlackHotThreadMode(raw) {
|
|
14749
|
+
if (raw === void 0) return void 0;
|
|
14750
|
+
const v = raw.trim().toLowerCase();
|
|
14751
|
+
if (v === "") return void 0;
|
|
14752
|
+
if (v === "off" || v === "shadow" || v === "enforce") return v;
|
|
14753
|
+
const b = envBoolean(raw);
|
|
14754
|
+
if (b === true) return "enforce";
|
|
14755
|
+
if (b === false) return "off";
|
|
14756
|
+
return void 0;
|
|
14757
|
+
}
|
|
14758
|
+
function cachedSlackHotThreadMode(path) {
|
|
14759
|
+
try {
|
|
14760
|
+
if (!existsSync(path)) return void 0;
|
|
14761
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
14762
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
14763
|
+
const flags = parsed.flags;
|
|
14764
|
+
if (!flags || typeof flags !== "object") return void 0;
|
|
14765
|
+
const value = flags[SLACK_HOT_THREAD_FLAG_KEY];
|
|
14766
|
+
if (typeof value === "string") return parseSlackHotThreadMode(value);
|
|
14767
|
+
if (typeof value === "boolean") return value ? "enforce" : "off";
|
|
14768
|
+
return void 0;
|
|
14769
|
+
} catch {
|
|
14770
|
+
return void 0;
|
|
14771
|
+
}
|
|
14772
|
+
}
|
|
14773
|
+
function resolveSlackHotThreadMode(opts) {
|
|
14774
|
+
const env = opts?.env ?? process.env;
|
|
14775
|
+
const modeOverride = parseSlackHotThreadMode(env["AGT_SLACK_HOT_THREAD_GUARD_MODE"]);
|
|
14776
|
+
if (modeOverride !== void 0) return modeOverride;
|
|
14777
|
+
const cached2 = cachedSlackHotThreadMode(opts?.cachePath ?? defaultFlagsCachePath());
|
|
14778
|
+
if (cached2 !== void 0) return cached2;
|
|
14779
|
+
return "off";
|
|
14780
|
+
}
|
|
14747
14781
|
|
|
14748
14782
|
// src/maintenance-mode.ts
|
|
14749
14783
|
var FLAG_KEY = "platform-maintenance-mode";
|
|
@@ -16412,6 +16446,47 @@ function resolveReplyThreadTs(input) {
|
|
|
16412
16446
|
return input.activeCardThreadTs || void 0;
|
|
16413
16447
|
}
|
|
16414
16448
|
|
|
16449
|
+
// src/slack-hot-thread.ts
|
|
16450
|
+
function parseThreadKey(key2) {
|
|
16451
|
+
const idx = key2.indexOf(":");
|
|
16452
|
+
if (idx <= 0 || idx >= key2.length - 1) return null;
|
|
16453
|
+
return { channel: key2.slice(0, idx), threadTs: key2.slice(idx + 1) };
|
|
16454
|
+
}
|
|
16455
|
+
function resolveHotThread(input) {
|
|
16456
|
+
const { channel, trackedThreads: trackedThreads2, now, windowMs } = input;
|
|
16457
|
+
if (!channel || windowMs <= 0) return void 0;
|
|
16458
|
+
let bestThreadTs;
|
|
16459
|
+
let bestSeenMs = -Infinity;
|
|
16460
|
+
const floor = now - windowMs;
|
|
16461
|
+
for (const [key2, entry] of trackedThreads2) {
|
|
16462
|
+
if (entry?.bot_posted !== true) continue;
|
|
16463
|
+
const parsed = parseThreadKey(key2);
|
|
16464
|
+
if (!parsed || parsed.channel !== channel) continue;
|
|
16465
|
+
const seenMs = Date.parse(entry.last_seen_at);
|
|
16466
|
+
if (!Number.isFinite(seenMs)) continue;
|
|
16467
|
+
if (seenMs < floor || seenMs > now) continue;
|
|
16468
|
+
if (seenMs > bestSeenMs || seenMs === bestSeenMs && (bestThreadTs === void 0 || parsed.threadTs > bestThreadTs)) {
|
|
16469
|
+
bestSeenMs = seenMs;
|
|
16470
|
+
bestThreadTs = parsed.threadTs;
|
|
16471
|
+
}
|
|
16472
|
+
}
|
|
16473
|
+
if (bestThreadTs === void 0) return void 0;
|
|
16474
|
+
return { threadTs: bestThreadTs, ageMs: Math.max(0, now - bestSeenMs) };
|
|
16475
|
+
}
|
|
16476
|
+
function applyHotThreadGuard(input) {
|
|
16477
|
+
const { baseThreadTs, forcedRoot, hotThread } = input;
|
|
16478
|
+
if (forcedRoot) {
|
|
16479
|
+
return { threadTs: void 0, guard: "root_forced" };
|
|
16480
|
+
}
|
|
16481
|
+
if (baseThreadTs !== void 0) {
|
|
16482
|
+
return { threadTs: baseThreadTs, guard: "not_applicable" };
|
|
16483
|
+
}
|
|
16484
|
+
if (hotThread) {
|
|
16485
|
+
return { threadTs: hotThread.threadTs, guard: "redirected_to_hot_thread" };
|
|
16486
|
+
}
|
|
16487
|
+
return { threadTs: void 0, guard: "root_no_hot_thread" };
|
|
16488
|
+
}
|
|
16489
|
+
|
|
16415
16490
|
// src/restart-confirm.ts
|
|
16416
16491
|
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync4, renameSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
16417
16492
|
import { dirname } from "path";
|
|
@@ -20741,6 +20816,15 @@ var trackedThreads = /* @__PURE__ */ new Map();
|
|
|
20741
20816
|
var THREAD_STORE_PATH = resolveThreadStorePath();
|
|
20742
20817
|
var THREAD_STORE_TTL_DAYS = parseTtlDays(process.env.SLACK_THREAD_FOLLOW_TTL_DAYS);
|
|
20743
20818
|
var threadPersister = null;
|
|
20819
|
+
var SLACK_HOT_THREAD_DEFAULT_WINDOW_MS = 15 * 60 * 1e3;
|
|
20820
|
+
function parseHotThreadWindowMs(raw) {
|
|
20821
|
+
if (!raw) return SLACK_HOT_THREAD_DEFAULT_WINDOW_MS;
|
|
20822
|
+
const n = Number(raw);
|
|
20823
|
+
return Number.isFinite(n) && n > 0 ? n : SLACK_HOT_THREAD_DEFAULT_WINDOW_MS;
|
|
20824
|
+
}
|
|
20825
|
+
var SLACK_HOT_THREAD_WINDOW_MS = parseHotThreadWindowMs(
|
|
20826
|
+
process.env.AGT_SLACK_HOT_THREAD_WINDOW_MS
|
|
20827
|
+
);
|
|
20744
20828
|
function resolveThreadStorePath() {
|
|
20745
20829
|
if (!AGENT_CODE_NAME) return null;
|
|
20746
20830
|
return join16(homedir4(), ".augmented", AGENT_CODE_NAME, "slack-tracked-threads.json");
|
|
@@ -20913,7 +20997,15 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
20913
20997
|
},
|
|
20914
20998
|
proactive: {
|
|
20915
20999
|
type: "boolean",
|
|
20916
|
-
description:
|
|
21000
|
+
description: 'Set true ONLY when this message is NOT a reply to any inbound <channel> tag - a self-initiated outreach or scheduled-task output. Leave it off (default) for every reply to a user message. Note: proactive does NOT mean "post at the channel root". If you are actively working in a thread, a proactive message still threads into it. To deliberately start a NEW top-level message in the channel, also set to_channel_root:true.'
|
|
21001
|
+
},
|
|
21002
|
+
// ENG-7462: the explicit, deliberate escape to a channel-root post. The
|
|
21003
|
+
// server defaults a coordless reply INTO the thread you are actively
|
|
21004
|
+
// working in (the hot-thread guard); starting a genuinely new top-level
|
|
21005
|
+
// conversation is a separate, deliberate action signalled here.
|
|
21006
|
+
to_channel_root: {
|
|
21007
|
+
type: "boolean",
|
|
21008
|
+
description: "Set true to DELIBERATELY post a new top-level message at the channel root instead of threading into the conversation you are currently working in. Use it only when you genuinely want to start a new topic in the channel (not a reply to, or a continuation of, an existing thread). Leave it off (default) for anything that belongs in an ongoing thread."
|
|
20917
21009
|
}
|
|
20918
21010
|
},
|
|
20919
21011
|
required: ["channel", "text"]
|
|
@@ -21190,7 +21282,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
21190
21282
|
return buildImpersonationRefusal(name);
|
|
21191
21283
|
}
|
|
21192
21284
|
if (name === "slack.reply") {
|
|
21193
|
-
const { channel, text, thread_ts, message_ts, interim, inbound_id, proactive } = args;
|
|
21285
|
+
const { channel, text, thread_ts, message_ts, interim, inbound_id, proactive, to_channel_root } = args;
|
|
21194
21286
|
const bindingMode = slackReplyBindingMode();
|
|
21195
21287
|
const binding = resolveReplyBinding({
|
|
21196
21288
|
mode: bindingMode,
|
|
@@ -21259,13 +21351,37 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
21259
21351
|
};
|
|
21260
21352
|
}
|
|
21261
21353
|
const bindingFeedback = bindingMode === "warn" ? binding.agentFeedback : void 0;
|
|
21262
|
-
const
|
|
21263
|
-
const
|
|
21354
|
+
const forcedRoot = to_channel_root === true || thread_ts === null;
|
|
21355
|
+
const activeCardThreadTs = !scheduledDest && !enforceBound && !channelGuard.corrected && !forcedRoot && !thread_ts && !message_ts && kanbanCardActiveClient && typeof channel === "string" && channel ? await kanbanCardActiveClient.getActiveCardSourceThread("slack", channel) : void 0;
|
|
21356
|
+
const plainReply = !scheduledDest && !enforceBound && !channelGuard.corrected;
|
|
21357
|
+
const baseThreadTs = plainReply && !forcedRoot ? resolveReplyThreadTs({
|
|
21264
21358
|
channel,
|
|
21265
21359
|
threadTs: thread_ts,
|
|
21266
21360
|
messageTs: message_ts,
|
|
21267
21361
|
activeCardThreadTs
|
|
21268
|
-
});
|
|
21362
|
+
}) : void 0;
|
|
21363
|
+
let hotThreadMode = "off";
|
|
21364
|
+
let hotGuard = null;
|
|
21365
|
+
if (plainReply) {
|
|
21366
|
+
hotThreadMode = resolveSlackHotThreadMode();
|
|
21367
|
+
if (hotThreadMode !== "off") {
|
|
21368
|
+
const hotThread = resolveHotThread({
|
|
21369
|
+
channel,
|
|
21370
|
+
trackedThreads,
|
|
21371
|
+
now: Date.now(),
|
|
21372
|
+
windowMs: SLACK_HOT_THREAD_WINDOW_MS
|
|
21373
|
+
});
|
|
21374
|
+
hotGuard = applyHotThreadGuard({ baseThreadTs, forcedRoot, hotThread });
|
|
21375
|
+
if (hotGuard.guard === "redirected_to_hot_thread") {
|
|
21376
|
+
process.stderr.write(
|
|
21377
|
+
`slack-channel(${AGENT_CODE_NAME}): hot_thread_guard mode=${hotThreadMode} applied=${hotThreadMode === "enforce"} channel=${redactSlackId(channel)} hot_thread=${redactSlackId(hotGuard.threadTs)} proactive=${proactive === true} age_ms=${hotThread?.ageMs ?? ""}
|
|
21378
|
+
`
|
|
21379
|
+
);
|
|
21380
|
+
}
|
|
21381
|
+
}
|
|
21382
|
+
}
|
|
21383
|
+
const effectiveThreadTs = scheduledDest ? scheduledDest.thread_ts : enforceBound ? binding.threadTs : channelGuard.corrected ? channelGuard.threadTs : hotThreadMode === "enforce" && hotGuard ? hotGuard.threadTs : baseThreadTs;
|
|
21384
|
+
const hotThreadRedirected = hotThreadMode === "enforce" && hotGuard?.guard === "redirected_to_hot_thread";
|
|
21269
21385
|
if (effectiveChannel) {
|
|
21270
21386
|
recordReplyTargetClassification(
|
|
21271
21387
|
SLACK_AGENT_DIR,
|
|
@@ -21402,7 +21518,10 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
21402
21518
|
}
|
|
21403
21519
|
})();
|
|
21404
21520
|
}
|
|
21405
|
-
|
|
21521
|
+
let base = bindingFeedback ? `sent. ${bindingFeedback}` : "sent";
|
|
21522
|
+
if (hotThreadRedirected) {
|
|
21523
|
+
base += ". Note: this was threaded into the conversation you are actively working in rather than posted at the channel root. If you genuinely meant to start a NEW top-level topic, resend with to_channel_root:true.";
|
|
21524
|
+
}
|
|
21406
21525
|
const sentTs = typeof data.ts === "string" ? data.ts : void 0;
|
|
21407
21526
|
return {
|
|
21408
21527
|
content: [{ type: "text", text: sentTs ? `${base} (ts=${sentTs})` : base }]
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
writeDirectChatSessionState,
|
|
37
37
|
writeEgressAllowlist,
|
|
38
38
|
writePersistentClaudeWrapper
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-J6QDPXGS.js";
|
|
40
40
|
import "./chunk-XWVM4KPK.js";
|
|
41
41
|
export {
|
|
42
42
|
EGRESS_BASELINE_DOMAINS,
|
|
@@ -77,4 +77,4 @@ export {
|
|
|
77
77
|
writeEgressAllowlist,
|
|
78
78
|
writePersistentClaudeWrapper
|
|
79
79
|
};
|
|
80
|
-
//# sourceMappingURL=persistent-session-
|
|
80
|
+
//# sourceMappingURL=persistent-session-4UG3S54C.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
paneLogPath
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-J6QDPXGS.js";
|
|
4
4
|
import "./chunk-XWVM4KPK.js";
|
|
5
5
|
|
|
6
6
|
// src/lib/responsiveness-probe.ts
|
|
@@ -437,4 +437,4 @@ export {
|
|
|
437
437
|
readAndResetSlackReplyBindingClassifications,
|
|
438
438
|
readAndResetSlackReplyTargetClassifications
|
|
439
439
|
};
|
|
440
|
-
//# sourceMappingURL=responsiveness-probe-
|
|
440
|
+
//# sourceMappingURL=responsiveness-probe-TK47IXPX.js.map
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|