@integrity-labs/agt-cli 0.15.7 → 0.15.9

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 CHANGED
@@ -46,7 +46,7 @@ import {
46
46
  success,
47
47
  table,
48
48
  warn
49
- } from "../chunk-WIW5FIRY.js";
49
+ } from "../chunk-C6UBNLUC.js";
50
50
 
51
51
  // src/bin/agt.ts
52
52
  import { join as join10 } from "path";
@@ -3730,7 +3730,7 @@ import { execFileSync, execSync } from "child_process";
3730
3730
  import { existsSync as existsSync5, realpathSync } from "fs";
3731
3731
  import chalk17 from "chalk";
3732
3732
  import ora15 from "ora";
3733
- var cliVersion = true ? "0.15.7" : "dev";
3733
+ var cliVersion = true ? "0.15.9" : "dev";
3734
3734
  async function fetchLatestVersion() {
3735
3735
  const host2 = getHost();
3736
3736
  if (!host2) return null;
@@ -4179,7 +4179,7 @@ function handleError(err) {
4179
4179
  }
4180
4180
 
4181
4181
  // src/bin/agt.ts
4182
- var cliVersion2 = true ? "0.15.7" : "dev";
4182
+ var cliVersion2 = true ? "0.15.9" : "dev";
4183
4183
  var program = new Command();
4184
4184
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
4185
4185
  program.hook("preAction", (thisCommand) => {
@@ -3117,6 +3117,120 @@ function provisionStopHook(codeName) {
3117
3117
  "exit 0"
3118
3118
  ].join("\n") + "\n";
3119
3119
  writeFileSync4(hookScriptPath, hookScript, { mode: 493 });
3120
+ const ghostHookPath = join4(claudeDir, "agt-ghost-reply-hook.sh");
3121
+ const ghostHookScript = [
3122
+ "#!/bin/bash",
3123
+ "# Auto-generated by Augmented (ENG-4569) \u2014 detects ghost replies and",
3124
+ "# drops recovery files in the channel outbox dirs. Runs on every Stop.",
3125
+ "set -euo pipefail",
3126
+ "INPUT=$(cat)",
3127
+ `TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty')`,
3128
+ '[ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ] && exit 0',
3129
+ `CWD=$(echo "$INPUT" | jq -r '.cwd // empty')`,
3130
+ `CODE_NAME=$(echo "$CWD" | sed -nE 's|.*/\\.augmented/([^/]+)/project/?$|\\1|p')`,
3131
+ '[ -z "$CODE_NAME" ] && exit 0',
3132
+ 'AGENT_DIR="$(dirname "$CWD")"',
3133
+ 'TG_MARKER_DIR="${AGENT_DIR}/telegram-pending-inbound"',
3134
+ 'SL_MARKER_DIR="${AGENT_DIR}/slack-pending-inbound"',
3135
+ "# CodeRabbit ENG-4569 round-3: latest-marker correlation could leak chat",
3136
+ "# A's composed reply into chat B if B arrived later. Now correlate by",
3137
+ "# scanning the transcript for the LAST channel-source <channel ...> tag",
3138
+ "# in user/notification turns and routing recovery to the EXACT marker",
3139
+ "# whose chat_id+message_id (Telegram) / channel+thread_ts (Slack) match.",
3140
+ "# If the tag isn't found, skip recovery \u2014 the timeout will catch it.",
3141
+ "pending_markers_count() {",
3142
+ ' local dir="$1"',
3143
+ ' [ ! -d "$dir" ] && echo 0 && return',
3144
+ " shopt -s nullglob",
3145
+ ' local files=("$dir"/*.json)',
3146
+ ' echo "${#files[@]}"',
3147
+ "}",
3148
+ 'TG_PENDING=$(pending_markers_count "$TG_MARKER_DIR")',
3149
+ 'SL_PENDING=$(pending_markers_count "$SL_MARKER_DIR")',
3150
+ '[ "$TG_PENDING" = "0" ] && [ "$SL_PENDING" = "0" ] && exit 0',
3151
+ `LAST_ASSISTANT=$(tail -200 "$TRANSCRIPT_PATH" | jq -cs '[.[] | select(.type == "assistant" or .role == "assistant")] | last // empty' 2>/dev/null)`,
3152
+ '[ -z "$LAST_ASSISTANT" ] || [ "$LAST_ASSISTANT" = "null" ] && exit 0',
3153
+ `TEXT=$(echo "$LAST_ASSISTANT" | jq -r '(.message.content // .content // []) | map(select(.type == "text") | .text) | join("\\n\\n")' 2>/dev/null)`,
3154
+ "# Strip whitespace and bail only on truly-empty (vs the previous <4-char",
3155
+ '# threshold that dropped legit short replies like "ok", "yes", emoji).',
3156
+ '[ -z "${TEXT//[[:space:]]/}" ] && exit 0',
3157
+ `TOOL_NAMES=$(echo "$LAST_ASSISTANT" | jq -r '(.message.content // .content // []) | map(select(.type == "tool_use") | .name) | .[]' 2>/dev/null || true)`,
3158
+ "# Find the LAST <channel ...> tag in user/notification turns. Channel",
3159
+ "# notifications are forwarded into the session as text containing this",
3160
+ "# tag (slack-channel.ts:1247 / telegram-channel.ts:776 emit content +",
3161
+ "# meta which Claude Code wraps in a <channel ...> preamble). Searching",
3162
+ "# the raw text gives us the exact pending conversation key.",
3163
+ `CHANNEL_TAG=$(tail -400 "$TRANSCRIPT_PATH" | jq -r '(.message.content // .content // []) | map(select(.type == "text") | .text) | join(" ")' 2>/dev/null | grep -oE '<channel [^>]+>' | tail -1)`,
3164
+ 'TAG_SOURCE=""',
3165
+ `[ -n "$CHANNEL_TAG" ] && TAG_SOURCE=$(echo "$CHANNEL_TAG" | grep -oE 'source="[^"]+"' | head -1 | sed 's/source="\\(.*\\)"/\\1/')`,
3166
+ 'extract_attr() { echo "$1" | grep -oE "$2=\\"[^\\"]+\\"" | head -1 | sed -E "s/$2=\\"(.*)\\"/\\\\1/"; }',
3167
+ "# Atomic write helper: jq \u2192 tmp file in same dir, then rename. The",
3168
+ "# channel-side fs.watch only fires on rename, so the file is never",
3169
+ "# observed mid-write.",
3170
+ "atomic_write_payload() {",
3171
+ ' local out_dir="$1" final="$2" jq_expr="$3"; shift 3',
3172
+ ' mkdir -p "$out_dir"',
3173
+ ' local tmp="$out_dir/.${final##*/}.tmp"',
3174
+ ' jq -n "$jq_expr" "$@" > "$tmp"',
3175
+ ' chmod 600 "$tmp" 2>/dev/null || true',
3176
+ ' mv -f "$tmp" "$out_dir/$final"',
3177
+ "}",
3178
+ "# Sanitize an ID the same way the channel servers do (safeMarkerName /",
3179
+ "# safeSlackMarkerName): replace anything outside [A-Za-z0-9_-] with `_`.",
3180
+ `safe_id() { echo -n "$1" | sed -E 's|[^A-Za-z0-9_-]|_|g'; }`,
3181
+ "recover_telegram_for() {",
3182
+ ' local chat_id="$1" msg_id="$2"',
3183
+ ' [ -z "$chat_id" ] || [ -z "$msg_id" ] && return',
3184
+ " # If the agent DID call telegram.reply this turn, no recovery needed.",
3185
+ ` echo "$TOOL_NAMES" | grep -qE '^(telegram\\.reply|telegram\\.send_message)$' && return`,
3186
+ " local marker_name",
3187
+ ' marker_name="$(safe_id "$chat_id")__$(safe_id "$msg_id").json"',
3188
+ ' local marker_path="${TG_MARKER_DIR}/${marker_name}"',
3189
+ ' [ ! -f "$marker_path" ] && return',
3190
+ " local TS",
3191
+ " TS=$(date -u +%Y%m%dT%H%M%S%N)",
3192
+ ' atomic_write_payload "${AGENT_DIR}/telegram-recovery-outbox" "${TS}.json" \\',
3193
+ ` '{chat_id:$c, message_id:$m, text:$t, source:"ghost-reply-recovery"}' \\`,
3194
+ ' --arg c "$chat_id" --arg m "$msg_id" --arg t "$TEXT"',
3195
+ ' rm -f "$marker_path" 2>/dev/null || true',
3196
+ "}",
3197
+ "recover_slack_for() {",
3198
+ ' local channel="$1" thread_ts="$2"',
3199
+ ' [ -z "$channel" ] && return',
3200
+ " # If the agent DID call slack.reply this turn, no recovery needed.",
3201
+ ` echo "$TOOL_NAMES" | grep -qE '^slack\\.reply$' && return`,
3202
+ " # Find any marker for this channel+thread (in busy threads multiple",
3203
+ " # message_ts entries can be pending \u2014 recover the oldest, that's the",
3204
+ " # one closest to firing the timeout).",
3205
+ ' local prefix="$(safe_id "$channel")__$(safe_id "$thread_ts")__"',
3206
+ ' local marker_path=""',
3207
+ " shopt -s nullglob",
3208
+ ' for f in "$SL_MARKER_DIR"/${prefix}*.json; do',
3209
+ ' [ -z "$marker_path" ] && marker_path="$f"',
3210
+ " done",
3211
+ ' [ -z "$marker_path" ] && return',
3212
+ " local TS",
3213
+ " TS=$(date -u +%Y%m%dT%H%M%S%N)",
3214
+ ' atomic_write_payload "${AGENT_DIR}/slack-recovery-outbox" "${TS}.json" \\',
3215
+ ` '{channel:$c, thread_ts:$th, text:$t, source:"ghost-reply-recovery"}' \\`,
3216
+ ' --arg c "$channel" --arg th "$thread_ts" --arg t "$TEXT"',
3217
+ ' rm -f "$marker_path" 2>/dev/null || true',
3218
+ "}",
3219
+ "# Strict correlation: only recover if the last channel tag in the",
3220
+ "# transcript points at a channel/key that has an exact-match pending",
3221
+ "# marker. No tag found \u2192 skip; let timeout handle it.",
3222
+ 'if [ "$TAG_SOURCE" = "telegram" ]; then',
3223
+ ' CHAT_ID=$(extract_attr "$CHANNEL_TAG" "chat_id")',
3224
+ ' MSG_ID=$(extract_attr "$CHANNEL_TAG" "message_id")',
3225
+ ' recover_telegram_for "$CHAT_ID" "$MSG_ID"',
3226
+ 'elif [ "$TAG_SOURCE" = "slack" ]; then',
3227
+ ' CHANNEL=$(extract_attr "$CHANNEL_TAG" "channel")',
3228
+ ' THREAD_TS=$(extract_attr "$CHANNEL_TAG" "thread_ts")',
3229
+ ' recover_slack_for "$CHANNEL" "$THREAD_TS"',
3230
+ "fi",
3231
+ "exit 0"
3232
+ ].join("\n") + "\n";
3233
+ writeFileSync4(ghostHookPath, ghostHookScript, { mode: 493 });
3120
3234
  const settingsPath = join4(claudeDir, "settings.local.json");
3121
3235
  let settings = {};
3122
3236
  try {
@@ -3127,10 +3241,8 @@ function provisionStopHook(codeName) {
3127
3241
  hooks["Stop"] = [
3128
3242
  {
3129
3243
  hooks: [
3130
- {
3131
- type: "command",
3132
- command: hookScriptPath
3133
- }
3244
+ { type: "command", command: hookScriptPath },
3245
+ { type: "command", command: ghostHookPath }
3134
3246
  ]
3135
3247
  }
3136
3248
  ];
@@ -3280,6 +3392,13 @@ function buildMcpJson(input) {
3280
3392
  AGT_API_KEY: process.env["AGT_API_KEY"] ?? "",
3281
3393
  AGT_AGENT_ID: input.agent.agent_id,
3282
3394
  AGT_AGENT_CODE_NAME: input.agent.code_name,
3395
+ // ENG-4561: Claude Code substitutes `${VAR}` in .mcp.json env values
3396
+ // at MCP-launch time using the spawn environment, not at file-write
3397
+ // time. Manager-worker exports AGT_RUN_ID per Claude spawn so the
3398
+ // bridge can stamp run_id onto inserted rows (kanban, knowledge).
3399
+ // If AGT_RUN_ID isn't set in the environment, Claude leaves the
3400
+ // literal `${AGT_RUN_ID}` — the bridge filters that case out.
3401
+ AGT_RUN_ID: "${AGT_RUN_ID}",
3283
3402
  // Console origin so the MCP bridge can build absolute URLs (e.g.
3284
3403
  // dashboard links) in tool replies. Falls back to NEXT_PUBLIC_APP_URL
3285
3404
  // / AGT_CONSOLE_URL — same chain consoleUrl uses for kanban links.
@@ -7115,4 +7234,4 @@ export {
7115
7234
  managerStopCommand,
7116
7235
  managerStatusCommand
7117
7236
  };
7118
- //# sourceMappingURL=chunk-WIW5FIRY.js.map
7237
+ //# sourceMappingURL=chunk-C6UBNLUC.js.map