@integrity-labs/agt-cli 0.28.884 → 0.28.886

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
@@ -40,12 +40,12 @@ import {
40
40
  success,
41
41
  table,
42
42
  warn
43
- } from "../chunk-5P4R3IPC.js";
43
+ } from "../chunk-2E7GOSID.js";
44
44
  import {
45
45
  getProjectDir,
46
46
  isSessionResumeDisabled,
47
47
  readDirectChatSessionState
48
- } from "../chunk-YNYWVGHB.js";
48
+ } from "../chunk-FP5M5OVX.js";
49
49
  import {
50
50
  AnchorSessionClient,
51
51
  CHANNEL_REGISTRY,
@@ -5467,7 +5467,7 @@ import { execFileSync, execSync } from "child_process";
5467
5467
  import { existsSync as existsSync11, realpathSync as realpathSync2 } from "fs";
5468
5468
  import chalk18 from "chalk";
5469
5469
  import ora16 from "ora";
5470
- var cliVersion = true ? "0.28.884" : "dev";
5470
+ var cliVersion = true ? "0.28.886" : "dev";
5471
5471
  async function fetchLatestVersion() {
5472
5472
  const host2 = getHost();
5473
5473
  if (!host2) return null;
@@ -6658,7 +6658,7 @@ function handleError(err) {
6658
6658
  }
6659
6659
 
6660
6660
  // src/bin/agt.ts
6661
- var cliVersion2 = true ? "0.28.884" : "dev";
6661
+ var cliVersion2 = true ? "0.28.886" : "dev";
6662
6662
  var program = new Command();
6663
6663
  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");
6664
6664
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -16,7 +16,7 @@ import {
16
16
  parseEnvIntegrations,
17
17
  shellQuote,
18
18
  summarizeUnanswerablePane
19
- } from "./chunk-YNYWVGHB.js";
19
+ } from "./chunk-FP5M5OVX.js";
20
20
  import {
21
21
  BIND_FAILURE_QUARANTINE_THRESHOLD,
22
22
  INTEGRATIONS_SECTION_END,
@@ -3327,14 +3327,18 @@ function provisionStopHook(codeName) {
3327
3327
  writeFileSync4(settingsPath, JSON.stringify(settings, null, 2));
3328
3328
  }
3329
3329
  function provisionIsolationHook(codeName, agentId) {
3330
+ const homeDir = getHomeDir();
3331
+ const augmentedBase = join4(homeDir, ".augmented");
3332
+ if (/["'$`\\\n]/.test(augmentedBase)) {
3333
+ throw new Error(`provisionIsolationHook: home directory contains shell metacharacters: ${JSON.stringify(augmentedBase)}`);
3334
+ }
3330
3335
  const projectDir = getProjectDir2(codeName);
3331
3336
  const claudeDir = join4(projectDir, ".claude");
3332
3337
  mkdirSync3(claudeDir, { recursive: true });
3333
3338
  const hasAgentId = agentId !== void 0;
3334
3339
  if (hasAgentId)
3335
3340
  assertValidAgentId(agentId);
3336
- const homeDir = getHomeDir();
3337
- const augmentedBase = join4(homeDir, ".augmented");
3341
+ const augmentedBaseRe = augmentedBase.replace(/[.[\]()*+?{}|^$]/g, "\\$&");
3338
3342
  const ownAgentDir = getAgentDir(codeName);
3339
3343
  const logFile = join4(ownAgentDir, "isolation.log");
3340
3344
  const idAllowClause = hasAgentId ? ` && [ "$AGENT_DIR" != "${agentId}" ]` : "";
@@ -3355,82 +3359,154 @@ function provisionIsolationHook(codeName, agentId) {
3355
3359
  "# disables it. Moving the file elsewhere does not help: a root process",
3356
3360
  "# on a shared filesystem reaches wherever it is put.",
3357
3361
  "#",
3358
- "# 2. IT MATCHES RAW PRE-EXPANSION TEXT, and that fails in BOTH directions",
3359
- "# depending on WHERE the expansion sits. The two cases are different and",
3360
- "# worth keeping apart:",
3361
- "#",
3362
- "# HIDDEN BASE -> under-blocks (the hole). If the expansion hides the base",
3363
- "# path itself, the literal text this greps for never appears, the branch",
3364
- "# exits 0, and the shell expands afterwards. Verified:",
3365
- "# ~/.augmented/<other>/x does not fire, proceeds",
3366
- "# $HOME/.augmented/<other>/x does not fire, proceeds",
3367
- "# The platform's own CLAUDE.md documents working paths in tilde form, so",
3368
- "# the spelling agents are taught is the spelling this cannot see.",
3362
+ "# 2. THE BASH BRANCH READS PRE-EXPANSION TEXT. CS-1692 normalises the",
3363
+ "# spellings of a path that can be resolved from the text alone, so these",
3364
+ "# now resolve the same way as the literal absolute path and are refused:",
3365
+ '# ~/.augmented/<other>/x $HOME/... ${HOME}/... "$HOME"/...',
3366
+ "# <base>//<other>/x <home>/./.augmented/<other>/x",
3367
+ '# <base>/<self>/../<other>/x "<base>"/<other>/x <base>/oth\\er/x',
3368
+ "# <base>/<self>/a <base>/<other>/b (every match is checked,",
3369
+ "# not just the first)",
3370
+ "# cd <base>/<other> && cat MEMORY.md (a sibling DIRECTORY with no",
3371
+ "# trailing slash)",
3372
+ "# What text cannot tell it, it still cannot see. These are NOT closed:",
3373
+ "# cd <base> && cat <other>/x (relative to a cd)",
3374
+ "# cat <symlink-into-other>/x (symlinks)",
3375
+ "# cat /root/.augmented/$CN/x, $(...), ~user/, computed paths",
3376
+ "# And an unexpanded variable or glob as the agent segment is still",
3377
+ "# refused, because nothing here can know where it will point.",
3369
3378
  "#",
3370
- "# EXPANSION AFTER THE BASE -> over-blocks (a false positive). The literal",
3371
- "# base IS present, so the branch fires, takes the unexpanded token as the",
3372
- "# agent segment, finds it in no allowlist, and refuses. Verified:",
3373
- "# /root/.augmented/$CN/x fires, AGENT_DIR=[$CN] -> BLOCK",
3374
- "# /root/.augmented/${VAR}/x fires, AGENT_DIR=[${VAR}] -> BLOCK",
3375
- "# This refuses commands that were going nowhere near another agent.",
3379
+ "# The Read/Edit/Write/Glob/Grep branch has a single path to judge, so it",
3380
+ "# canonicalises it (tilde, relative, dot segments, doubled slashes and",
3381
+ "# symlinks, via realpath -m) before deciding. Where realpath is missing",
3382
+ "# it falls back to the raw string, and is back to matching text.",
3376
3383
  "#",
3377
- "# 3. IT OVER-BLOCKS ON PUNCTUATION TOO. [^/]+ does not stop at a shell",
3378
- "# metacharacter, so `ls /root/.augmented/<self> && echo hi` yields an",
3379
- "# AGENT_DIR of `<self> && echo hi`, which matches no allowlist entry and",
3380
- "# is refused. Agents have been blocked from their OWN directories this",
3381
- "# way, repeatedly. Check isolation.log before reading an entry as an",
3382
- "# attempted breach: most of them are not.",
3384
+ "# 3. OVER-BLOCKING ON PUNCTUATION IS FIXED (CS-1691, in part). The agent",
3385
+ "# segment now stops at whitespace and shell metacharacters, so",
3386
+ "# `cd <base>/<self> && ls x 2>/dev/null` is no longer read as an agent",
3387
+ "# named `<self> && ls x 2>`. Check isolation.log before reading an entry",
3388
+ "# as an attempted breach all the same.",
3383
3389
  "#",
3384
3390
  "# Real isolation between co-located agents needs OS enforcement - a uid per",
3385
3391
  "# agent, a mount namespace, or a container per agent (ENG-4745, ENG-6633).",
3386
3392
  "# Do not treat a passing hook as evidence that separation exists.",
3387
3393
  "#",
3388
- "# Exit 0 = allow, Exit 2 = block (with stderr message shown to agent)",
3394
+ "# Exit 0 = allow, Exit 2 = block (with stderr message shown to agent).",
3395
+ "# Any other exit is a hook ERROR, which Claude Code does not treat as a block:",
3396
+ "# every failure path below must end in 0 or 2, never fall out on set -e.",
3389
3397
  "set -euo pipefail",
3390
3398
  "INPUT=$(cat)",
3391
3399
  `TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')`,
3392
3400
  "",
3393
3401
  "# Only check file-access tools",
3394
3402
  'case "$TOOL" in',
3395
- " Read|Edit|Write|Glob|Grep|MultiEdit) ;;",
3396
- " Bash)",
3397
- " # For Bash, we can't reliably parse arbitrary commands \u2014 rely on allowedDirectories.",
3398
- " # But block obvious attempts to read other agent dirs.",
3399
- ` CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')`,
3400
- ` if echo "$CMD" | grep -qE '${augmentedBase}/[^/]+/' 2>/dev/null; then`,
3401
- ` MATCH=$(echo "$CMD" | grep -oE '${augmentedBase}/[^/]+' | head -1)`,
3402
- ` AGENT_DIR=$(basename "$MATCH")`,
3403
- ` if [ "$AGENT_DIR" != "${codeName}" ]${idAllowClause} && [ "$AGENT_DIR" != "_mcp" ]; then`,
3404
- ` echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) BLOCKED bash targeting $MATCH" >> "${logFile}"`,
3405
- ` echo "Access denied: you cannot access other agents' directories." >&2`,
3406
- " exit 2",
3407
- " fi",
3408
- " fi",
3409
- " exit 0 ;;",
3403
+ " Read|Edit|Write|Glob|Grep|MultiEdit|Bash) ;;",
3410
3404
  " *) exit 0 ;;",
3411
3405
  "esac",
3412
3406
  "",
3413
- "# Extract file_path from tool input",
3414
- `FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')`,
3415
- '[ -z "$FILE_PATH" ] && exit 0',
3407
+ `HOME_DIR="${homeDir}"`,
3408
+ `AUGMENTED_BASE="${augmentedBase}"`,
3409
+ `AUGMENTED_BASE_RE='${augmentedBaseRe}'`,
3410
+ `LOG_FILE="${logFile}"`,
3411
+ "# The directory this agent's codename actually resolves to. Under the",
3412
+ "# id-keyed layout the codename is a symlink to the agent_id, and a legacy-",
3413
+ "# provisioned hook has no agent_id baked in to recognise it by. Unlike the",
3414
+ "# codename and agent_id above, this is read from the filesystem on every",
3415
+ "# call: repoint the codename symlink and the allowlist moves with it. Fine",
3416
+ "# for an accident-guard; not something to lean on as a boundary.",
3417
+ `OWN_REAL=$(basename -- "$(realpath -m -- "$AUGMENTED_BASE/${codeName}" 2>/dev/null || printf '%s' "${codeName}")")`,
3418
+ "",
3419
+ "deny() {",
3420
+ ' echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) BLOCKED $1" >> "$LOG_FILE" 2>/dev/null || true',
3421
+ ` echo "Access denied: you cannot access other agents' directories." >&2`,
3422
+ " exit 2",
3423
+ "}",
3416
3424
  "",
3417
- "# Resolve to absolute path",
3418
- 'if [[ "$FILE_PATH" != /* ]]; then',
3419
- ` CWD=$(echo "$INPUT" | jq -r '.cwd // empty')`,
3420
- ' [ -n "$CWD" ] && FILE_PATH="$CWD/$FILE_PATH"',
3425
+ "# An agent segment that will be expanded later: nothing here can know where",
3426
+ "# it points, so it is treated as another agent.",
3427
+ "has_expansion() {",
3428
+ ` case "$1" in *'*'*|*'?'*|*'['*|*'{'*|*'$'*) return 0 ;; esac`,
3429
+ " return 1",
3430
+ "}",
3431
+ "",
3432
+ 'if [ "$TOOL" = "Bash" ]; then',
3433
+ ` CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')`,
3434
+ " # CS-1692: rewrite every spelling of a path that the TEXT can resolve into",
3435
+ " # the literal form, then judge that. Quotes and backslashes only split a",
3436
+ " # word, so they are dropped; home spellings become the home directory.",
3437
+ " NORM=$CMD",
3438
+ ' NORM=${NORM//\\"/}',
3439
+ " NORM=${NORM//\\'/}",
3440
+ " NORM=${NORM//\\\\/}",
3441
+ ' NORM=${NORM//\\$\\{HOME\\}/"$HOME_DIR"}',
3442
+ ' NORM=${NORM//\\$HOME/"$HOME_DIR"}',
3443
+ ' NORM=${NORM//\\~\\//"$HOME_DIR/"}',
3444
+ " # Doubled slashes, /./ and <segment>/.. collapse lexically. Each step only",
3445
+ " # ever shortens the string, so the loop terminates.",
3446
+ " DOTDOT_RE='/[^/[:space:]]+/\\.\\.(/|$)'",
3447
+ " PREV=",
3448
+ ' while [ "$NORM" != "$PREV" ]; do',
3449
+ " PREV=$NORM",
3450
+ " NORM=${NORM//\\/\\//\\/}",
3451
+ " NORM=${NORM//\\/.\\//\\/}",
3452
+ ' if [[ "$NORM" =~ $DOTDOT_RE ]]; then NORM=${NORM/"${BASH_REMATCH[0]}"/\\/}; fi',
3453
+ " done",
3454
+ " # EVERY occurrence is judged. The agent segment stops at whitespace and",
3455
+ " # shell metacharacters, so trailing redirects are not read as its name.",
3456
+ ' OCC_RE="${AUGMENTED_BASE_RE}/[^/[:space:];&|<>()]+/?"',
3457
+ ` OCCURRENCES=$(printf '%s\\n' "$NORM" | grep -oE "$OCC_RE" || true)`,
3458
+ " while IFS= read -r OCC; do",
3459
+ ' [ -z "$OCC" ] && continue',
3460
+ ' REST=${OCC#"$AUGMENTED_BASE"/}',
3461
+ " AGENT_DIR=${REST%/}",
3462
+ ' case "$AGENT_DIR" in .|..) continue ;; esac',
3463
+ ` if [ "$AGENT_DIR" != "${codeName}" ]${idAllowClause} && [ "$AGENT_DIR" != "$OWN_REAL" ] && [ "$AGENT_DIR" != "_mcp" ]; then`,
3464
+ " # Refuse a path INTO the segment, a segment that is a directory (an",
3465
+ " # agent dir named with no trailing slash), or one still to be expanded.",
3466
+ " # A plain file at the base, such as manager.log, is not an agent.",
3467
+ ' if [ "$REST" != "$AGENT_DIR" ] || [ -d "$AUGMENTED_BASE/$AGENT_DIR" ] || has_expansion "$AGENT_DIR"; then',
3468
+ ' deny "bash targeting $AUGMENTED_BASE/$AGENT_DIR"',
3469
+ " fi",
3470
+ " fi",
3471
+ ' done <<< "$OCCURRENCES"',
3472
+ " exit 0",
3421
3473
  "fi",
3422
3474
  "",
3423
- "# Check if path targets another agent's directory",
3424
- `AUGMENTED_BASE="${augmentedBase}"`,
3425
- 'case "$FILE_PATH" in',
3426
- ' "$AUGMENTED_BASE"/*/*) ',
3427
- ' AGENT_DIR=$(echo "$FILE_PATH" | sed "s|$AUGMENTED_BASE/||" | cut -d/ -f1)',
3428
- ` if [ "$AGENT_DIR" != "${codeName}" ]${idAllowClause} && [ "$AGENT_DIR" != "_mcp" ]; then`,
3429
- ` echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) BLOCKED $TOOL on $FILE_PATH" >> "${logFile}"`,
3430
- ` echo "Access denied: you cannot access other agents' directories." >&2`,
3431
- " exit 2",
3432
- " fi ;;",
3433
- "esac",
3475
+ `CWD=$(echo "$INPUT" | jq -r '.cwd // empty')`,
3476
+ `CANON_BASE=$(realpath -m -- "$AUGMENTED_BASE" 2>/dev/null || printf '%s' "$AUGMENTED_BASE")`,
3477
+ "",
3478
+ "# check_path PATH [RELATIVE_TO]: canonicalise one tool path, then judge it.",
3479
+ "check_path() {",
3480
+ " local P=$1",
3481
+ " local REL=${2:-$CWD}",
3482
+ ' [ -z "$P" ] && return 0',
3483
+ ' case "$P" in',
3484
+ ' "~") P=$HOME_DIR ;;',
3485
+ ' "~/"*) P="$HOME_DIR/${P#"~/"}" ;;',
3486
+ " esac",
3487
+ ' if [[ "$P" != /* ]] && [ -n "$REL" ]; then P="$REL/$P"; fi',
3488
+ ` P=$(realpath -m -- "$P" 2>/dev/null || printf '%s' "$P")`,
3489
+ ' case "$P" in',
3490
+ ' "$CANON_BASE"/?*)',
3491
+ ' local REST=${P#"$CANON_BASE"/}',
3492
+ " local AGENT_DIR=${REST%%/*}",
3493
+ ` if [ "$AGENT_DIR" != "${codeName}" ]${idAllowClause} && [ "$AGENT_DIR" != "$OWN_REAL" ] && [ "$AGENT_DIR" != "_mcp" ]; then`,
3494
+ ' if [ "$REST" != "$AGENT_DIR" ] || [ -d "$CANON_BASE/$AGENT_DIR" ] || has_expansion "$AGENT_DIR"; then',
3495
+ ' deny "$TOOL on $P"',
3496
+ " fi",
3497
+ " fi ;;",
3498
+ " esac",
3499
+ " return 0",
3500
+ "}",
3501
+ "",
3502
+ `TOOL_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // empty')`,
3503
+ 'check_path "$TOOL_PATH"',
3504
+ "# Glob also takes the path in its pattern. Grep's pattern is a regex, not a",
3505
+ "# path, so it is deliberately not judged.",
3506
+ 'if [ "$TOOL" = "Glob" ]; then',
3507
+ ` PATTERN=$(echo "$INPUT" | jq -r '.tool_input.pattern // empty')`,
3508
+ ' check_path "$PATTERN" "${TOOL_PATH:-$CWD}"',
3509
+ "fi",
3434
3510
  "",
3435
3511
  "exit 0"
3436
3512
  ].join("\n") + "\n";
@@ -6765,7 +6841,7 @@ function exchangeFailureKind(err) {
6765
6841
  }
6766
6842
 
6767
6843
  // src/lib/api-client.ts
6768
- var agtCliVersion = true ? "0.28.884" : "dev";
6844
+ var agtCliVersion = true ? "0.28.886" : "dev";
6769
6845
  var lastConfigHash = null;
6770
6846
  function setConfigHash(hash) {
6771
6847
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -11375,4 +11451,4 @@ export {
11375
11451
  managerInstallSystemUnitCommand,
11376
11452
  managerUninstallSystemUnitCommand
11377
11453
  };
11378
- //# sourceMappingURL=chunk-5P4R3IPC.js.map
11454
+ //# sourceMappingURL=chunk-2E7GOSID.js.map