@integrity-labs/agt-cli 0.28.60 → 0.28.62

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.
@@ -3,7 +3,7 @@ import {
3
3
  formatMissingVar,
4
4
  isClaudeFastMode,
5
5
  probeMcpEnvSubstitution
6
- } from "./chunk-BCWB6A4G.js";
6
+ } from "./chunk-7F2K3RRD.js";
7
7
  import {
8
8
  reapOrphanChannelMcps
9
9
  } from "./chunk-XWVM4KPK.js";
@@ -1395,4 +1395,4 @@ export {
1395
1395
  stopAllSessionsAndWait,
1396
1396
  getProjectDir
1397
1397
  };
1398
- //# sourceMappingURL=chunk-IGP67S2Z.js.map
1398
+ //# sourceMappingURL=chunk-AKOF4VV5.js.map
@@ -22,7 +22,7 @@ import {
22
22
  resolveConnectivityProbe,
23
23
  worseConnectivityOutcome,
24
24
  wrapScheduledTaskPrompt
25
- } from "./chunk-BCWB6A4G.js";
25
+ } from "./chunk-7F2K3RRD.js";
26
26
 
27
27
  // ../../packages/core/dist/integrations/registry.js
28
28
  var INTEGRATION_REGISTRY = [
@@ -7347,7 +7347,7 @@ function requireHost() {
7347
7347
  }
7348
7348
 
7349
7349
  // src/lib/api-client.ts
7350
- var agtCliVersion = true ? "0.28.60" : "dev";
7350
+ var agtCliVersion = true ? "0.28.62" : "dev";
7351
7351
  var lastConfigHash = null;
7352
7352
  function setConfigHash(hash) {
7353
7353
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -8643,4 +8643,4 @@ export {
8643
8643
  managerInstallSystemUnitCommand,
8644
8644
  managerUninstallSystemUnitCommand
8645
8645
  };
8646
- //# sourceMappingURL=chunk-DC2QI6OD.js.map
8646
+ //# sourceMappingURL=chunk-QQGXIZVB.js.map
@@ -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-3W3TQK73.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-5PEPYSMG.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-EVJVZCRI.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-QSRMTD7I.js.map
@@ -27,7 +27,7 @@ import {
27
27
  requireHost,
28
28
  safeWriteJsonAtomic,
29
29
  setConfigHash
30
- } from "../chunk-DC2QI6OD.js";
30
+ } from "../chunk-QQGXIZVB.js";
31
31
  import {
32
32
  getProjectDir as getProjectDir2,
33
33
  getReadyTasks,
@@ -65,7 +65,7 @@ import {
65
65
  takeWatchdogGiveUpCount,
66
66
  takeZombieDetection,
67
67
  transcriptActivityAgeSeconds
68
- } from "../chunk-IGP67S2Z.js";
68
+ } from "../chunk-AKOF4VV5.js";
69
69
  import {
70
70
  FLAGS_SCHEMA_VERSION,
71
71
  FLAG_REGISTRY,
@@ -96,7 +96,7 @@ import {
96
96
  resolveDmTarget,
97
97
  sumTranscriptUsageInWindow,
98
98
  wrapScheduledTaskPrompt
99
- } from "../chunk-BCWB6A4G.js";
99
+ } from "../chunk-7F2K3RRD.js";
100
100
  import {
101
101
  parsePsRows,
102
102
  reapOrphanChannelMcps
@@ -6698,7 +6698,7 @@ var cachedMaintenanceWindow = null;
6698
6698
  var lastVersionCheckAt = 0;
6699
6699
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6700
6700
  var lastResponsivenessProbeAt = 0;
6701
- var agtCliVersion = true ? "0.28.60" : "dev";
6701
+ var agtCliVersion = true ? "0.28.62" : "dev";
6702
6702
  function resolveBrewPath(execFileSync4) {
6703
6703
  try {
6704
6704
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7806,7 +7806,7 @@ async function pollCycle() {
7806
7806
  }
7807
7807
  try {
7808
7808
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
7809
- const { collectDiagnostics } = await import("../persistent-session-3W3TQK73.js");
7809
+ const { collectDiagnostics } = await import("../persistent-session-5PEPYSMG.js");
7810
7810
  const diagCodeNames = [...agentState.persistentSessionAgents];
7811
7811
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
7812
7812
  let tailscaleHostname;
@@ -7907,7 +7907,7 @@ async function pollCycle() {
7907
7907
  const {
7908
7908
  collectResponsivenessProbes,
7909
7909
  getResponsivenessIntervalMs
7910
- } = await import("../responsiveness-probe-5MXY5KYZ.js");
7910
+ } = await import("../responsiveness-probe-HG23JDG2.js");
7911
7911
  const probeIntervalMs = getResponsivenessIntervalMs();
7912
7912
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
7913
7913
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -7939,7 +7939,7 @@ async function pollCycle() {
7939
7939
  collectResponsivenessProbes,
7940
7940
  livePendingInboundOldestAgeSeconds,
7941
7941
  parkPendingInbound
7942
- } = await import("../responsiveness-probe-5MXY5KYZ.js");
7942
+ } = await import("../responsiveness-probe-HG23JDG2.js");
7943
7943
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
7944
7944
  const wedgeNow = /* @__PURE__ */ new Date();
7945
7945
  const liveAgents = agentState.persistentSessionAgents;
@@ -11373,7 +11373,7 @@ async function processClaudePairSessions(agents) {
11373
11373
  killPairSession,
11374
11374
  pairTmuxSession,
11375
11375
  finalizeClaudePairOnboarding
11376
- } = await import("../claude-pair-runtime-EVJVZCRI.js");
11376
+ } = await import("../claude-pair-runtime-QSRMTD7I.js");
11377
11377
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
11378
11378
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
11379
11379
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -14175,7 +14175,39 @@ function resolveHostBooleanFlag(opts) {
14175
14175
  return opts.defaultValue;
14176
14176
  }
14177
14177
 
14178
+ // src/maintenance-mode.ts
14179
+ var FLAG_KEY = "platform-maintenance-mode";
14180
+ var MAINTENANCE_OFFLINE_MESSAGE = "The Augmented Team platform is offline for scheduled maintenance right now, so I can't pick this up \u2014 please try again shortly.";
14181
+ function isMaintenanceModeActive(opts) {
14182
+ return resolveHostBooleanFlag({
14183
+ key: FLAG_KEY,
14184
+ envVar: "",
14185
+ defaultValue: false,
14186
+ cachePath: opts?.cachePath,
14187
+ env: opts?.env
14188
+ });
14189
+ }
14190
+
14191
+ // src/sender-policy-decline.ts
14192
+ function decideDeclineReply(input) {
14193
+ const last = input.cache.get(input.key);
14194
+ if (last !== void 0) {
14195
+ const elapsed = input.now - last;
14196
+ if (elapsed < input.cooldownMs) {
14197
+ return { reply: false, remainingMs: input.cooldownMs - elapsed };
14198
+ }
14199
+ }
14200
+ input.cache.set(input.key, input.now);
14201
+ return { reply: true };
14202
+ }
14203
+
14178
14204
  // src/direct-chat-channel.ts
14205
+ var DIRECT_CHAT_MAINTENANCE_CACHE = /* @__PURE__ */ new Map();
14206
+ var DIRECT_CHAT_MAINTENANCE_COOLDOWN_MS = (() => {
14207
+ const raw = process.env["DIRECT_CHAT_MAINTENANCE_NOTICE_COOLDOWN_SEC"];
14208
+ const n = raw ? Number(raw) : NaN;
14209
+ return Number.isFinite(n) && n >= 0 ? n * 1e3 : 1800 * 1e3;
14210
+ })();
14179
14211
  var AGT_HOST = process.env.AGT_HOST;
14180
14212
  var AGT_API_KEY = process.env.AGT_API_KEY;
14181
14213
  var AGT_AGENT_ID = process.env.AGT_AGENT_ID;
@@ -14434,10 +14466,42 @@ async function pollForMessages(sinceMs) {
14434
14466
  for (const msg of data.messages ?? []) {
14435
14467
  if (processedIds.has(msg.id)) continue;
14436
14468
  const isNotice = msg.kind === "notice";
14437
- if (!isNotice) {
14469
+ const maintenanceActive = !isNotice && isMaintenanceModeActive();
14470
+ if (!isNotice && !maintenanceActive) {
14438
14471
  markProcessed(msg.id);
14439
14472
  claimTracker.track(msg.session_id, msg.id);
14440
14473
  }
14474
+ if (maintenanceActive) {
14475
+ const throttleKey = `${msg.session_id}|maintenance`;
14476
+ const throttle = decideDeclineReply({
14477
+ cache: DIRECT_CHAT_MAINTENANCE_CACHE,
14478
+ key: throttleKey,
14479
+ cooldownMs: DIRECT_CHAT_MAINTENANCE_COOLDOWN_MS,
14480
+ now: Date.now()
14481
+ });
14482
+ const route = throttle.reply ? "/host/direct-chat/reply" : "/host/direct-chat/consume";
14483
+ const body = throttle.reply ? { agent_id: AGT_AGENT_ID, session_id: msg.session_id, content: MAINTENANCE_OFFLINE_MESSAGE, message_ids: [msg.id] } : { agent_id: AGT_AGENT_ID, session_id: msg.session_id, message_ids: [msg.id] };
14484
+ try {
14485
+ const res2 = await apiPost(route, body);
14486
+ const data2 = await res2.json().catch(() => ({}));
14487
+ if (res2.ok && data2.error == null) {
14488
+ markProcessed(msg.id);
14489
+ } else {
14490
+ if (throttle.reply) DIRECT_CHAT_MAINTENANCE_CACHE.delete(throttleKey);
14491
+ process.stderr.write(
14492
+ `direct-chat-channel: maintenance ${throttle.reply ? "reply" : "consume"} failed: ${data2.error ?? `HTTP ${res2.status}`}
14493
+ `
14494
+ );
14495
+ }
14496
+ } catch (err) {
14497
+ if (throttle.reply) DIRECT_CHAT_MAINTENANCE_CACHE.delete(throttleKey);
14498
+ process.stderr.write(
14499
+ `direct-chat-channel: maintenance offline reply failed: ${err.message}
14500
+ `
14501
+ );
14502
+ }
14503
+ continue;
14504
+ }
14441
14505
  await mcp.notification({
14442
14506
  method: "notifications/claude/channel",
14443
14507
  params: {
@@ -14353,6 +14353,56 @@ function decideInboundAccess(input) {
14353
14353
  return { kind: "admit" };
14354
14354
  }
14355
14355
 
14356
+ // src/flags-cache-read.ts
14357
+ import { existsSync, readFileSync } from "fs";
14358
+ import { homedir } from "os";
14359
+ import { join } from "path";
14360
+ function defaultFlagsCachePath() {
14361
+ return join(homedir(), ".augmented", "flags-cache.json");
14362
+ }
14363
+ function envBoolean(raw) {
14364
+ if (raw === void 0) return void 0;
14365
+ const v = raw.trim().toLowerCase();
14366
+ if (v === "") return void 0;
14367
+ if (v === "1" || v === "true" || v === "yes" || v === "on") return true;
14368
+ if (v === "0" || v === "false" || v === "no" || v === "off") return false;
14369
+ return void 0;
14370
+ }
14371
+ function cachedBoolean(key2, path) {
14372
+ try {
14373
+ if (!existsSync(path)) return void 0;
14374
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
14375
+ if (!parsed || typeof parsed !== "object") return void 0;
14376
+ const flags = parsed.flags;
14377
+ if (!flags || typeof flags !== "object") return void 0;
14378
+ const value = flags[key2];
14379
+ return typeof value === "boolean" ? value : void 0;
14380
+ } catch {
14381
+ return void 0;
14382
+ }
14383
+ }
14384
+ function resolveHostBooleanFlag(opts) {
14385
+ const env = opts.env ?? process.env;
14386
+ const envValue = envBoolean(env[opts.envVar]);
14387
+ if (envValue !== void 0) return envValue;
14388
+ const cached2 = cachedBoolean(opts.key, opts.cachePath ?? defaultFlagsCachePath());
14389
+ if (cached2 !== void 0) return cached2;
14390
+ return opts.defaultValue;
14391
+ }
14392
+
14393
+ // src/maintenance-mode.ts
14394
+ var FLAG_KEY = "platform-maintenance-mode";
14395
+ var MAINTENANCE_OFFLINE_MESSAGE = "The Augmented Team platform is offline for scheduled maintenance right now, so I can't pick this up \u2014 please try again shortly.";
14396
+ function isMaintenanceModeActive(opts) {
14397
+ return resolveHostBooleanFlag({
14398
+ key: FLAG_KEY,
14399
+ envVar: "",
14400
+ defaultValue: false,
14401
+ cachePath: opts?.cachePath,
14402
+ env: opts?.env
14403
+ });
14404
+ }
14405
+
14356
14406
  // src/watch-command.ts
14357
14407
  var WATCH_DEFAULT_DURATION_MS = 2 * 60 * 60 * 1e3;
14358
14408
  var WATCH_MAX_DURATION_MS = 7 * 24 * 60 * 60 * 1e3;
@@ -14460,45 +14510,6 @@ function watchSuccessTextSlack(fileId, durationMs, reused) {
14460
14510
  // src/ack-reaction.ts
14461
14511
  import { readdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
14462
14512
  import { join as join2 } from "path";
14463
-
14464
- // src/flags-cache-read.ts
14465
- import { existsSync, readFileSync } from "fs";
14466
- import { homedir } from "os";
14467
- import { join } from "path";
14468
- function defaultFlagsCachePath() {
14469
- return join(homedir(), ".augmented", "flags-cache.json");
14470
- }
14471
- function envBoolean(raw) {
14472
- if (raw === void 0) return void 0;
14473
- const v = raw.trim().toLowerCase();
14474
- if (v === "") return void 0;
14475
- if (v === "1" || v === "true" || v === "yes" || v === "on") return true;
14476
- if (v === "0" || v === "false" || v === "no" || v === "off") return false;
14477
- return void 0;
14478
- }
14479
- function cachedBoolean(key2, path) {
14480
- try {
14481
- if (!existsSync(path)) return void 0;
14482
- const parsed = JSON.parse(readFileSync(path, "utf8"));
14483
- if (!parsed || typeof parsed !== "object") return void 0;
14484
- const flags = parsed.flags;
14485
- if (!flags || typeof flags !== "object") return void 0;
14486
- const value = flags[key2];
14487
- return typeof value === "boolean" ? value : void 0;
14488
- } catch {
14489
- return void 0;
14490
- }
14491
- }
14492
- function resolveHostBooleanFlag(opts) {
14493
- const env = opts.env ?? process.env;
14494
- const envValue = envBoolean(env[opts.envVar]);
14495
- if (envValue !== void 0) return envValue;
14496
- const cached2 = cachedBoolean(opts.key, opts.cachePath ?? defaultFlagsCachePath());
14497
- if (cached2 !== void 0) return cached2;
14498
- return opts.defaultValue;
14499
- }
14500
-
14501
- // src/ack-reaction.ts
14502
14513
  var REPLY_WEDGED_THRESHOLD_MS = 5 * 60 * 1e3;
14503
14514
  var ACK_STARTUP_GRACE_MS = 6e4;
14504
14515
  var ACK_PANE_FRESH_THRESHOLD_MS = 6e4;
@@ -16763,6 +16774,52 @@ async function maybeSendSenderPolicyDecline(args) {
16763
16774
  clearTimeout(timeoutId);
16764
16775
  }
16765
16776
  }
16777
+ var SLACK_MAINTENANCE_NOTICE_CACHE = /* @__PURE__ */ new Map();
16778
+ async function maybeSendMaintenanceNotice(args) {
16779
+ if (!BOT_TOKEN) return;
16780
+ if (!args.channel || !args.senderId) return;
16781
+ const key2 = `${args.channel}|${args.senderId}|maintenance`;
16782
+ const decision = decideDeclineReply({
16783
+ cache: SLACK_MAINTENANCE_NOTICE_CACHE,
16784
+ key: key2,
16785
+ cooldownMs: SLACK_POLICY_DECLINE_COOLDOWN_MS,
16786
+ now: Date.now()
16787
+ });
16788
+ if (!decision.reply) {
16789
+ process.stderr.write(
16790
+ `slack-channel(${AGENT_CODE_NAME}): maintenance notice suppressed by cooldown (channel=${redactSlackId(args.channel)}, sender=${redactSlackId(args.senderId)}, remaining=${decision.remainingMs}ms)
16791
+ `
16792
+ );
16793
+ return;
16794
+ }
16795
+ const controller = new AbortController();
16796
+ const timeoutId = setTimeout(() => controller.abort(), 1e4);
16797
+ try {
16798
+ const res = await fetch("https://slack.com/api/chat.postMessage", {
16799
+ method: "POST",
16800
+ signal: controller.signal,
16801
+ headers: {
16802
+ "Content-Type": "application/json",
16803
+ Authorization: `Bearer ${BOT_TOKEN}`
16804
+ },
16805
+ body: JSON.stringify({
16806
+ channel: args.channel,
16807
+ text: MAINTENANCE_OFFLINE_MESSAGE,
16808
+ ...args.threadTs ? { thread_ts: args.threadTs } : {}
16809
+ })
16810
+ });
16811
+ const data = await res.json();
16812
+ if (!data.ok) {
16813
+ SLACK_MAINTENANCE_NOTICE_CACHE.delete(key2);
16814
+ process.stderr.write(
16815
+ `slack-channel(${AGENT_CODE_NAME}): maintenance notice post failed: ${data.error ?? "unknown"}
16816
+ `
16817
+ );
16818
+ }
16819
+ } finally {
16820
+ clearTimeout(timeoutId);
16821
+ }
16822
+ }
16766
16823
  var BLOCK_KIT_DISABLED = process.env.SLACK_BLOCK_KIT_DISABLED === "true";
16767
16824
  var ALLOWED_USERS = parseAllowedUsersCsv(process.env.SLACK_ALLOWED_USERS);
16768
16825
  var THREAD_AUTO_FOLLOW = process.env.SLACK_THREAD_AUTO_FOLLOW ?? "off";
@@ -17666,7 +17723,8 @@ function buildSlackHelpMessage(codeName) {
17666
17723
  "All commands are real Slack slash commands (autocomplete via `/`). For backward compatibility, `/help` and the restart command can also be typed as plain messages in any channel where the bot is present:",
17667
17724
  `\u2022 \`${agentSlashCommand("/help")}\` (or type \`/help\`) \u2014 show this help`,
17668
17725
  `\u2022 \`${agentSlashCommand("/restart")}\` \u2014 restart this agent`,
17669
- `\u2022 \`${agentSlashCommand("/resume-onboarding")}\` \u2014 re-run this agent's onboarding interview (allowlisted users)`,
17726
+ `\u2022 \`${agentSlashCommand("/onboard")}\` \u2014 restart this agent's onboarding from scratch (allowlisted users)`,
17727
+ `\u2022 \`${agentSlashCommand("/resume-onboarding")}\` \u2014 resume this agent's onboarding where it left off (allowlisted users)`,
17670
17728
  `\u2022 \`${agentSlashCommand("/status")}\` \u2014 this agent's model, session origin, uptime + connectivity`,
17671
17729
  "\u2022 `/watch <google-doc-url> [duration]` (type it in chat) \u2014 watch a Google Doc for comments that mention me (default 2h, max 7d; auto-pauses when the window ends). In a shared channel, address me as `/watch-<my-name>`.",
17672
17730
  "\u2022 `/kill` \u2014 silence all agents in this thread for 6h (use as a thread reply)",
@@ -17775,6 +17833,50 @@ async function postEphemeralViaResponseUrl(responseUrl, text, logTag) {
17775
17833
  );
17776
17834
  }
17777
17835
  }
17836
+ async function forwardOnboardingSlashCommand(opts) {
17837
+ const { verb, path, userId, responseUrl, codeName } = opts;
17838
+ const allowed = getEffectiveAllowedUsers();
17839
+ if (allowed.size > 0 && (!userId || !allowed.has(userId))) {
17840
+ await postEphemeralViaResponseUrl(
17841
+ responseUrl,
17842
+ `\u{1F6AB} \`${verb}\` denied \u2014 your Slack user is not in the allowlist for \`${codeName}\`.`,
17843
+ codeName
17844
+ );
17845
+ return;
17846
+ }
17847
+ if (!AGT_HOST || !AGT_API_KEY || !AGT_AGENT_ID) {
17848
+ await postEphemeralViaResponseUrl(
17849
+ responseUrl,
17850
+ `:warning: This agent has no host API wiring \u2014 \`${verb}\` needs the host runtime to be reachable.`,
17851
+ codeName
17852
+ );
17853
+ return;
17854
+ }
17855
+ try {
17856
+ const res = await fetch(`${AGT_HOST}/host${path}`, {
17857
+ method: "POST",
17858
+ headers: {
17859
+ "Content-Type": "application/json; charset=utf-8",
17860
+ Authorization: `Bearer ${AGT_API_KEY}`
17861
+ },
17862
+ body: JSON.stringify({ agent_id: AGT_AGENT_ID }),
17863
+ signal: AbortSignal.timeout(SLACK_DOWNLOAD_TIMEOUT_MS)
17864
+ });
17865
+ const data = await res.json();
17866
+ const text = data.ok ? `\u{1F504} ${data.message ?? "Onboarding updated."}` : `:x: \`${verb}\` failed${data.error ? `: ${data.error}` : "."}`;
17867
+ await postEphemeralViaResponseUrl(responseUrl, text, codeName);
17868
+ } catch (err) {
17869
+ process.stderr.write(
17870
+ `slack-channel(${codeName}): ${verb} forward failed: ${redactAugmentedPaths2(err.message)}
17871
+ `
17872
+ );
17873
+ await postEphemeralViaResponseUrl(
17874
+ responseUrl,
17875
+ `:x: \`${verb}\` forwarding failed \u2014 host runtime unreachable. Try again in a moment.`,
17876
+ codeName
17877
+ );
17878
+ }
17879
+ }
17778
17880
  var DEBUG_TAIL_WINDOW_MS = 12e4;
17779
17881
  var DEBUG_TAIL_INTERVAL_MS = 3e3;
17780
17882
  var DEBUG_TAIL_MAX_CONSECUTIVE_FAILURES = 4;
@@ -18046,48 +18148,24 @@ async function handleSlashCommandEnvelope(payload) {
18046
18148
  }
18047
18149
  return;
18048
18150
  }
18151
+ if (matchesAgentCommand(command, "/onboard")) {
18152
+ await forwardOnboardingSlashCommand({
18153
+ verb: "/onboard",
18154
+ path: "/onboarding/reset",
18155
+ userId: payload.user_id,
18156
+ responseUrl,
18157
+ codeName
18158
+ });
18159
+ return;
18160
+ }
18049
18161
  if (matchesAgentCommand(command, "/resume-onboarding")) {
18050
- const allowed = getEffectiveAllowedUsers();
18051
- if (allowed.size > 0 && (!payload.user_id || !allowed.has(payload.user_id))) {
18052
- await postEphemeralViaResponseUrl(
18053
- responseUrl,
18054
- `\u{1F6AB} \`/resume-onboarding\` denied \u2014 your Slack user is not in the allowlist for \`${codeName}\`.`,
18055
- codeName
18056
- );
18057
- return;
18058
- }
18059
- if (!AGT_HOST || !AGT_API_KEY || !AGT_AGENT_ID) {
18060
- await postEphemeralViaResponseUrl(
18061
- responseUrl,
18062
- ":warning: This agent has no host API wiring \u2014 `/resume-onboarding` needs the host runtime to be reachable.",
18063
- codeName
18064
- );
18065
- return;
18066
- }
18067
- try {
18068
- const res = await fetch(`${AGT_HOST}/host/onboarding/reset`, {
18069
- method: "POST",
18070
- headers: {
18071
- "Content-Type": "application/json; charset=utf-8",
18072
- Authorization: `Bearer ${AGT_API_KEY}`
18073
- },
18074
- body: JSON.stringify({ agent_id: AGT_AGENT_ID }),
18075
- signal: AbortSignal.timeout(SLACK_DOWNLOAD_TIMEOUT_MS)
18076
- });
18077
- const data = await res.json();
18078
- const text = data.ok ? `\u{1F504} ${data.message ?? "Onboarding reset \u2014 I\u2019ll re-interview your manager."}` : `:x: \`/resume-onboarding\` failed${data.error ? `: ${data.error}` : "."}`;
18079
- await postEphemeralViaResponseUrl(responseUrl, text, codeName);
18080
- } catch (err) {
18081
- process.stderr.write(
18082
- `slack-channel(${codeName}): /resume-onboarding forward failed: ${err.message}
18083
- `
18084
- );
18085
- await postEphemeralViaResponseUrl(
18086
- responseUrl,
18087
- ":x: `/resume-onboarding` forwarding failed \u2014 host runtime unreachable. Try again in a moment.",
18088
- codeName
18089
- );
18090
- }
18162
+ await forwardOnboardingSlashCommand({
18163
+ verb: "/resume-onboarding",
18164
+ path: "/onboarding/resume",
18165
+ userId: payload.user_id,
18166
+ responseUrl,
18167
+ codeName
18168
+ });
18091
18169
  return;
18092
18170
  }
18093
18171
  if (command === "/debug" || matchesAgentCommand(command, "/investigate")) {
@@ -19949,6 +20027,23 @@ async function connectSocketMode() {
19949
20027
  }
19950
20028
  return;
19951
20029
  }
20030
+ if (!isBot && isMaintenanceModeActive()) {
20031
+ process.stderr.write(
20032
+ `slack-channel(${AGENT_CODE_NAME}): maintenance-mode active \u2014 offline notice, no dispatch (channel=${redactSlackId(evt.channel)})
20033
+ `
20034
+ );
20035
+ await maybeSendMaintenanceNotice({
20036
+ channel: evt.channel,
20037
+ senderId: evt.user,
20038
+ threadTs: evt.thread_ts
20039
+ }).catch((err) => {
20040
+ process.stderr.write(
20041
+ `slack-channel(${AGENT_CODE_NAME}): maintenance notice failed: ${err.message}
20042
+ `
20043
+ );
20044
+ });
20045
+ return;
20046
+ }
19952
20047
  const isDirectMessage = evt.channel?.startsWith("D");
19953
20048
  const isThreadReply = !!evt.thread_ts && evt.thread_ts !== evt.ts;
19954
20049
  const trackTs = evt.thread_ts ?? evt.ts ?? "";