@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.
@@ -14982,6 +14982,17 @@ function politeDeclineCopy(reason) {
14982
14982
  return "Sorry, I only respond to other agents in this channel.";
14983
14983
  }
14984
14984
  }
14985
+ function decideDeclineReply(input) {
14986
+ const last = input.cache.get(input.key);
14987
+ if (last !== void 0) {
14988
+ const elapsed = input.now - last;
14989
+ if (elapsed < input.cooldownMs) {
14990
+ return { reply: false, remainingMs: input.cooldownMs - elapsed };
14991
+ }
14992
+ }
14993
+ input.cache.set(input.key, input.now);
14994
+ return { reply: true };
14995
+ }
14985
14996
 
14986
14997
  // src/inbound-access.ts
14987
14998
  function decideInboundAccess(input) {
@@ -15022,6 +15033,56 @@ function decideInboundAccess(input) {
15022
15033
  return { kind: "admit" };
15023
15034
  }
15024
15035
 
15036
+ // src/flags-cache-read.ts
15037
+ import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
15038
+ import { homedir as homedir2 } from "os";
15039
+ import { join as join2 } from "path";
15040
+ function defaultFlagsCachePath() {
15041
+ return join2(homedir2(), ".augmented", "flags-cache.json");
15042
+ }
15043
+ function envBoolean(raw) {
15044
+ if (raw === void 0) return void 0;
15045
+ const v = raw.trim().toLowerCase();
15046
+ if (v === "") return void 0;
15047
+ if (v === "1" || v === "true" || v === "yes" || v === "on") return true;
15048
+ if (v === "0" || v === "false" || v === "no" || v === "off") return false;
15049
+ return void 0;
15050
+ }
15051
+ function cachedBoolean(key2, path) {
15052
+ try {
15053
+ if (!existsSync2(path)) return void 0;
15054
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
15055
+ if (!parsed || typeof parsed !== "object") return void 0;
15056
+ const flags = parsed.flags;
15057
+ if (!flags || typeof flags !== "object") return void 0;
15058
+ const value = flags[key2];
15059
+ return typeof value === "boolean" ? value : void 0;
15060
+ } catch {
15061
+ return void 0;
15062
+ }
15063
+ }
15064
+ function resolveHostBooleanFlag(opts) {
15065
+ const env = opts.env ?? process.env;
15066
+ const envValue = envBoolean(env[opts.envVar]);
15067
+ if (envValue !== void 0) return envValue;
15068
+ const cached2 = cachedBoolean(opts.key, opts.cachePath ?? defaultFlagsCachePath());
15069
+ if (cached2 !== void 0) return cached2;
15070
+ return opts.defaultValue;
15071
+ }
15072
+
15073
+ // src/maintenance-mode.ts
15074
+ var FLAG_KEY = "platform-maintenance-mode";
15075
+ 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.";
15076
+ function isMaintenanceModeActive(opts) {
15077
+ return resolveHostBooleanFlag({
15078
+ key: FLAG_KEY,
15079
+ envVar: "",
15080
+ defaultValue: false,
15081
+ cachePath: opts?.cachePath,
15082
+ env: opts?.env
15083
+ });
15084
+ }
15085
+
15025
15086
  // src/watch-command.ts
15026
15087
  var WATCH_DEFAULT_DURATION_MS = 2 * 60 * 60 * 1e3;
15027
15088
  var WATCH_MAX_DURATION_MS = 7 * 24 * 60 * 60 * 1e3;
@@ -15633,15 +15694,15 @@ function buildCommandRegistrations() {
15633
15694
  }
15634
15695
 
15635
15696
  // src/agent-config-state.ts
15636
- import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
15637
- import { join as join2 } from "path";
15697
+ import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
15698
+ import { join as join3 } from "path";
15638
15699
  var SESSION_STATE_FILENAME = "session-state.json";
15639
15700
  function readAgentSessionState(stateDir) {
15640
15701
  if (!stateDir) return null;
15641
- const path = join2(stateDir, SESSION_STATE_FILENAME);
15642
- if (!existsSync2(path)) return null;
15702
+ const path = join3(stateDir, SESSION_STATE_FILENAME);
15703
+ if (!existsSync3(path)) return null;
15643
15704
  try {
15644
- const parsed = JSON.parse(readFileSync3(path, "utf-8"));
15705
+ const parsed = JSON.parse(readFileSync4(path, "utf-8"));
15645
15706
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
15646
15707
  return parsed;
15647
15708
  } catch {
@@ -16155,11 +16216,11 @@ var TELEGRAM_EGRESS_TOOLS = /* @__PURE__ */ new Set([
16155
16216
  ]);
16156
16217
 
16157
16218
  // src/telegram-pending-inbound-cleanup.ts
16158
- import { readdirSync, readFileSync as readFileSync4, statSync } from "fs";
16159
- import { join as join3 } from "path";
16219
+ import { readdirSync, readFileSync as readFileSync5, statSync } from "fs";
16220
+ import { join as join4 } from "path";
16160
16221
  function markerArrivalMs(fullPath) {
16161
16222
  try {
16162
- const received = JSON.parse(readFileSync4(fullPath, "utf-8")).received_at;
16223
+ const received = JSON.parse(readFileSync5(fullPath, "utf-8")).received_at;
16163
16224
  const parsed = received ? Date.parse(received) : Number.NaN;
16164
16225
  if (Number.isFinite(parsed)) return parsed;
16165
16226
  } catch {
@@ -16183,7 +16244,7 @@ function clearAllTelegramPendingMarkersForChat(pendingDir, chatId, clearMarkerFi
16183
16244
  for (const filename of filenames) {
16184
16245
  if (!filename.startsWith(prefix)) continue;
16185
16246
  if (!filename.endsWith(".json")) continue;
16186
- const fullPath = join3(pendingDir, filename);
16247
+ const fullPath = join4(pendingDir, filename);
16187
16248
  if (bounded && markerArrivalMs(fullPath) > cutoffMs) continue;
16188
16249
  clearMarkerFile(fullPath);
16189
16250
  cleared++;
@@ -16193,14 +16254,14 @@ function clearAllTelegramPendingMarkersForChat(pendingDir, chatId, clearMarkerFi
16193
16254
 
16194
16255
  // src/mcp-spawn-lock.ts
16195
16256
  import {
16196
- existsSync as existsSync3,
16257
+ existsSync as existsSync4,
16197
16258
  mkdirSync as mkdirSync4,
16198
- readFileSync as readFileSync5,
16259
+ readFileSync as readFileSync6,
16199
16260
  renameSync as renameSync3,
16200
16261
  unlinkSync as unlinkSync4,
16201
16262
  writeFileSync as writeFileSync4
16202
16263
  } from "fs";
16203
- import { join as join4 } from "path";
16264
+ import { join as join5 } from "path";
16204
16265
  function defaultIsPidAlive(pid) {
16205
16266
  if (!Number.isFinite(pid) || pid <= 0) return false;
16206
16267
  try {
@@ -16218,7 +16279,7 @@ function acquireMcpSpawnLock(args) {
16218
16279
  const isPidAlive = options.isPidAlive ?? defaultIsPidAlive;
16219
16280
  const selfPid = options.selfPid ?? process.pid;
16220
16281
  const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
16221
- const path = join4(agentDir, basename);
16282
+ const path = join5(agentDir, basename);
16222
16283
  const existing = readLockHolder(path);
16223
16284
  if (existing) {
16224
16285
  if (existing.pid === selfPid) {
@@ -16247,9 +16308,9 @@ function releaseMcpSpawnLock(lockPath, opts = {}) {
16247
16308
  }
16248
16309
  }
16249
16310
  function readLockHolder(path) {
16250
- if (!existsSync3(path)) return null;
16311
+ if (!existsSync4(path)) return null;
16251
16312
  try {
16252
- const raw = readFileSync5(path, "utf8");
16313
+ const raw = readFileSync6(path, "utf8");
16253
16314
  const parsed = JSON.parse(raw);
16254
16315
  const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
16255
16316
  if (!Number.isFinite(pid) || pid <= 0) return null;
@@ -16263,45 +16324,6 @@ function readLockHolder(path) {
16263
16324
  // src/ack-reaction.ts
16264
16325
  import { readdirSync as readdirSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
16265
16326
  import { join as join6 } from "path";
16266
-
16267
- // src/flags-cache-read.ts
16268
- import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
16269
- import { homedir as homedir2 } from "os";
16270
- import { join as join5 } from "path";
16271
- function defaultFlagsCachePath() {
16272
- return join5(homedir2(), ".augmented", "flags-cache.json");
16273
- }
16274
- function envBoolean(raw) {
16275
- if (raw === void 0) return void 0;
16276
- const v = raw.trim().toLowerCase();
16277
- if (v === "") return void 0;
16278
- if (v === "1" || v === "true" || v === "yes" || v === "on") return true;
16279
- if (v === "0" || v === "false" || v === "no" || v === "off") return false;
16280
- return void 0;
16281
- }
16282
- function cachedBoolean(key2, path) {
16283
- try {
16284
- if (!existsSync4(path)) return void 0;
16285
- const parsed = JSON.parse(readFileSync6(path, "utf8"));
16286
- if (!parsed || typeof parsed !== "object") return void 0;
16287
- const flags = parsed.flags;
16288
- if (!flags || typeof flags !== "object") return void 0;
16289
- const value = flags[key2];
16290
- return typeof value === "boolean" ? value : void 0;
16291
- } catch {
16292
- return void 0;
16293
- }
16294
- }
16295
- function resolveHostBooleanFlag(opts) {
16296
- const env = opts.env ?? process.env;
16297
- const envValue = envBoolean(env[opts.envVar]);
16298
- if (envValue !== void 0) return envValue;
16299
- const cached2 = cachedBoolean(opts.key, opts.cachePath ?? defaultFlagsCachePath());
16300
- if (cached2 !== void 0) return cached2;
16301
- return opts.defaultValue;
16302
- }
16303
-
16304
- // src/ack-reaction.ts
16305
16327
  var REPLY_WEDGED_THRESHOLD_MS = 5 * 60 * 1e3;
16306
16328
  var ACK_STARTUP_GRACE_MS = 6e4;
16307
16329
  var ACK_PANE_FRESH_THRESHOLD_MS = 6e4;
@@ -16667,6 +16689,53 @@ function telegramApiCall(method, body, timeoutMs) {
16667
16689
  req.end();
16668
16690
  });
16669
16691
  }
16692
+ var TELEGRAM_MAINTENANCE_NOTICE_CACHE = /* @__PURE__ */ new Map();
16693
+ var TELEGRAM_MAINTENANCE_COOLDOWN_MS = (() => {
16694
+ const raw = process.env["TELEGRAM_MAINTENANCE_NOTICE_COOLDOWN_SEC"];
16695
+ const n = raw ? Number(raw) : NaN;
16696
+ return Number.isFinite(n) && n >= 0 ? n * 1e3 : 1800 * 1e3;
16697
+ })();
16698
+ async function maybeSendTelegramMaintenanceNotice(args) {
16699
+ if (args.senderId === void 0) return;
16700
+ const key2 = `${args.chatId}|${args.senderId}|maintenance`;
16701
+ const decision = decideDeclineReply({
16702
+ cache: TELEGRAM_MAINTENANCE_NOTICE_CACHE,
16703
+ key: key2,
16704
+ cooldownMs: TELEGRAM_MAINTENANCE_COOLDOWN_MS,
16705
+ now: Date.now()
16706
+ });
16707
+ if (!decision.reply) {
16708
+ process.stderr.write(
16709
+ `telegram-channel(${AGENT_CODE_NAME}): maintenance notice suppressed by cooldown (chat=${redactId(String(args.chatId))}, remaining=${decision.remainingMs}ms)
16710
+ `
16711
+ );
16712
+ return;
16713
+ }
16714
+ try {
16715
+ const resp = await telegramApiCall(
16716
+ "sendMessage",
16717
+ {
16718
+ chat_id: args.chatId,
16719
+ text: MAINTENANCE_OFFLINE_MESSAGE,
16720
+ ...args.messageThreadId != null ? { message_thread_id: args.messageThreadId } : {}
16721
+ },
16722
+ 1e4
16723
+ );
16724
+ if (!resp.ok) {
16725
+ TELEGRAM_MAINTENANCE_NOTICE_CACHE.delete(key2);
16726
+ process.stderr.write(
16727
+ `telegram-channel(${AGENT_CODE_NAME}): maintenance notice rejected (chat=${redactId(String(args.chatId))}): ${resp.description ?? "unknown"}
16728
+ `
16729
+ );
16730
+ }
16731
+ } catch (err) {
16732
+ TELEGRAM_MAINTENANCE_NOTICE_CACHE.delete(key2);
16733
+ process.stderr.write(
16734
+ `telegram-channel(${AGENT_CODE_NAME}): maintenance notice failed: ${err.message}
16735
+ `
16736
+ );
16737
+ }
16738
+ }
16670
16739
  var ACK_EMOJI = (process.env.TELEGRAM_ACK_REACTION ?? "").trim() || "\u{1F440}";
16671
16740
  var TELEGRAM_SKIP_REACTION = (process.env.TELEGRAM_SKIP_REACTION ?? "").trim();
16672
16741
  async function setMessageReaction(chatId, messageId, emoji2) {
@@ -16903,6 +16972,8 @@ function buildTelegramHelpMessage(codeName) {
16903
16972
  `\u2022 /status \u2014 this agent's model, session origin, uptime + connectivity`,
16904
16973
  `\u2022 /watch <google-doc-url> [duration] \u2014 watch a Google Doc for comments that mention me (default 2h, max 7d; auto-pauses when the window ends)`,
16905
16974
  `\u2022 /restart \u2014 restart this agent`,
16975
+ `\u2022 /onboard \u2014 restart this agent's onboarding from scratch`,
16976
+ `\u2022 /resume-onboarding \u2014 resume this agent's onboarding where it left off`,
16906
16977
  `\u2022 /investigate-${codeName} \u2014 live tail of this agent's terminal pane (DM only; team owners/admins and the agent's reports-to person)`
16907
16978
  ].join("\n");
16908
16979
  }
@@ -17021,6 +17092,62 @@ async function handleStatusCommand(opts) {
17021
17092
  );
17022
17093
  }
17023
17094
  }
17095
+ async function handleOnboardingCommand(opts) {
17096
+ const verb = opts.mode === "reset" ? "/onboard" : "/resume-onboarding";
17097
+ const reply = async (text) => {
17098
+ try {
17099
+ const resp = await telegramApiCall(
17100
+ "sendMessage",
17101
+ { chat_id: opts.chatId, text, reply_to_message_id: Number(opts.messageId) },
17102
+ 1e4
17103
+ );
17104
+ if (!resp.ok) {
17105
+ process.stderr.write(
17106
+ `telegram-channel(${AGENT_CODE_NAME}): ${verb} reply rejected (chat ${redactId(opts.chatId)}): ${resp.description ?? "unknown"}
17107
+ `
17108
+ );
17109
+ }
17110
+ } catch (err) {
17111
+ process.stderr.write(
17112
+ `telegram-channel(${AGENT_CODE_NAME}): ${verb} reply send failed: ${redactAugmentedPaths(err.message)}
17113
+ `
17114
+ );
17115
+ }
17116
+ };
17117
+ if (!AGT_HOST || !AGT_API_KEY || !AGT_AGENT_ID) {
17118
+ process.stderr.write(
17119
+ `telegram-channel(${AGENT_CODE_NAME}): ${verb} missing AGT_* env \u2014 cannot reach host runtime
17120
+ `
17121
+ );
17122
+ await reply(`\u26A0\uFE0F This agent has no host API wiring \u2014 ${verb} needs the host runtime to be reachable.`);
17123
+ return;
17124
+ }
17125
+ try {
17126
+ const res = await fetch(`${AGT_HOST}/host/onboarding/${opts.mode}`, {
17127
+ method: "POST",
17128
+ headers: {
17129
+ "Content-Type": "application/json; charset=utf-8",
17130
+ Authorization: `Bearer ${AGT_API_KEY}`
17131
+ },
17132
+ body: JSON.stringify({ agent_id: AGT_AGENT_ID }),
17133
+ signal: AbortSignal.timeout(1e4)
17134
+ });
17135
+ const data = await res.json();
17136
+ process.stderr.write(
17137
+ `telegram-channel(${AGENT_CODE_NAME}): ${verb} forwarded (ok=${data.ok}) from chat ${redactId(opts.chatId)}
17138
+ `
17139
+ );
17140
+ await reply(
17141
+ data.ok ? `\u{1F504} ${data.message ?? "Onboarding updated."}` : `\u274C ${verb} failed${data.error ? `: ${data.error}` : "."}`
17142
+ );
17143
+ } catch (err) {
17144
+ process.stderr.write(
17145
+ `telegram-channel(${AGENT_CODE_NAME}): ${verb} forward failed: ${redactAugmentedPaths(err.message)}
17146
+ `
17147
+ );
17148
+ await reply(`\u274C ${verb} forwarding failed \u2014 host runtime unreachable. Try again in a moment.`);
17149
+ }
17150
+ }
17024
17151
  async function handleRestartCommand(opts) {
17025
17152
  try {
17026
17153
  if (!existsSync5(RESTART_FLAGS_DIR)) {
@@ -17397,6 +17524,14 @@ var WATCH_SYNTAX_RE = /^\/watch(?:@([A-Za-z0-9_]{1,64}))?(?:\s|$)/;
17397
17524
  function isWatchSyntax(text) {
17398
17525
  return WATCH_SYNTAX_RE.test(text);
17399
17526
  }
17527
+ var ONBOARD_SYNTAX_RE = /^\/onboard(?:@([A-Za-z0-9_]{1,64}))?(?:\s|$)/;
17528
+ var RESUME_ONBOARDING_SYNTAX_RE = /^\/resume-onboarding(?:@([A-Za-z0-9_]{1,64}))?(?:\s|$)/;
17529
+ function isOnboardSyntax(text) {
17530
+ return ONBOARD_SYNTAX_RE.test(text);
17531
+ }
17532
+ function isResumeOnboardingSyntax(text) {
17533
+ return RESUME_ONBOARDING_SYNTAX_RE.test(text);
17534
+ }
17400
17535
  function isRestartSyntax(text) {
17401
17536
  return RESTART_SYNTAX_RE.test(text);
17402
17537
  }
@@ -18722,7 +18857,11 @@ async function pollLoop() {
18722
18857
  const trimmedContent = content.trim();
18723
18858
  const isFromBot = !!msg.from?.is_bot;
18724
18859
  const nowMs = Date.now();
18725
- const telegramCommand = isHelpSyntax(trimmedContent) ? "help" : isStatusSyntax(trimmedContent) ? "status" : isWatchSyntax(trimmedContent) ? "watch" : isRestartSyntax(trimmedContent) ? "restart" : isInvestigateSyntax(trimmedContent) ? "investigate" : void 0;
18860
+ const telegramCommand = isHelpSyntax(trimmedContent) ? "help" : isStatusSyntax(trimmedContent) ? "status" : isWatchSyntax(trimmedContent) ? "watch" : (
18861
+ // ENG-6511: check /resume-onboarding before /onboard for clarity
18862
+ // (the prefixes are disjoint, so order is not load-bearing).
18863
+ isResumeOnboardingSyntax(trimmedContent) ? "resume-onboarding" : isOnboardSyntax(trimmedContent) ? "onboard" : isRestartSyntax(trimmedContent) ? "restart" : isInvestigateSyntax(trimmedContent) ? "investigate" : void 0
18864
+ );
18726
18865
  let classification;
18727
18866
  let peerLeaf;
18728
18867
  if (isFromBot) {
@@ -18820,6 +18959,23 @@ async function pollLoop() {
18820
18959
  }
18821
18960
  continue;
18822
18961
  }
18962
+ if (access.kind === "command" && (access.command === "onboard" || access.command === "resume-onboarding")) {
18963
+ const cmdToken = access.command === "onboard" ? "/onboard" : "/resume-onboarding";
18964
+ const disposition = await classifyRestartCommand(
18965
+ trimmedContent.replace(
18966
+ new RegExp(`^${cmdToken}(@[A-Za-z0-9_]{1,64})?`),
18967
+ "/restart$1"
18968
+ )
18969
+ );
18970
+ if (disposition === "act") {
18971
+ await handleOnboardingCommand({
18972
+ chatId,
18973
+ messageId: String(msg.message_id),
18974
+ mode: access.command === "onboard" ? "reset" : "resume"
18975
+ });
18976
+ }
18977
+ continue;
18978
+ }
18823
18979
  if (access.kind === "command" && access.command === "restart") {
18824
18980
  const disposition = await classifyRestartCommand(trimmedContent);
18825
18981
  if (disposition === "act") {
@@ -18908,6 +19064,18 @@ async function pollLoop() {
18908
19064
  }
18909
19065
  continue;
18910
19066
  }
19067
+ if (!isFromBot && isMaintenanceModeActive()) {
19068
+ process.stderr.write(
19069
+ `telegram-channel(${AGENT_CODE_NAME}): maintenance-mode active \u2014 offline notice, no dispatch (chat=${redactId(chatId)})
19070
+ `
19071
+ );
19072
+ await maybeSendTelegramMaintenanceNotice({
19073
+ chatId,
19074
+ senderId: userId,
19075
+ messageThreadId: msg.message_thread_id
19076
+ });
19077
+ continue;
19078
+ }
18911
19079
  if (isFromBot && classification?.kind === "peer-ingress") {
18912
19080
  const limit = await peerRateLimiter.recordInboundPeer(
18913
19081
  chatId,
@@ -25,8 +25,8 @@ import {
25
25
  takeZombieDetection,
26
26
  writeDirectChatSessionState,
27
27
  writePersistentClaudeWrapper
28
- } from "./chunk-IGP67S2Z.js";
29
- import "./chunk-BCWB6A4G.js";
28
+ } from "./chunk-AKOF4VV5.js";
29
+ import "./chunk-7F2K3RRD.js";
30
30
  import "./chunk-XWVM4KPK.js";
31
31
  export {
32
32
  SEND_KEYS_ENTER_DELAY_MS,
@@ -56,4 +56,4 @@ export {
56
56
  writeDirectChatSessionState,
57
57
  writePersistentClaudeWrapper
58
58
  };
59
- //# sourceMappingURL=persistent-session-3W3TQK73.js.map
59
+ //# sourceMappingURL=persistent-session-5PEPYSMG.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-IGP67S2Z.js";
4
- import "./chunk-BCWB6A4G.js";
3
+ } from "./chunk-AKOF4VV5.js";
4
+ import "./chunk-7F2K3RRD.js";
5
5
  import "./chunk-XWVM4KPK.js";
6
6
 
7
7
  // src/lib/responsiveness-probe.ts
@@ -250,4 +250,4 @@ export {
250
250
  parkPendingInbound,
251
251
  readAndResetChannelDeflections
252
252
  };
253
- //# sourceMappingURL=responsiveness-probe-5MXY5KYZ.js.map
253
+ //# sourceMappingURL=responsiveness-probe-HG23JDG2.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.60",
3
+ "version": "0.28.62",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {