@integrity-labs/agt-cli 0.26.2-eng5706.1 → 0.27.0-test.4

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
@@ -26,7 +26,7 @@ import {
26
26
  success,
27
27
  table,
28
28
  warn
29
- } from "../chunk-LBYU24PW.js";
29
+ } from "../chunk-CPZIFISH.js";
30
30
  import {
31
31
  CHANNEL_REGISTRY,
32
32
  DEPLOYMENT_TEMPLATES,
@@ -52,11 +52,11 @@ import {
52
52
  renderTemplate,
53
53
  resolveChannels,
54
54
  serializeManifestForSlackCli
55
- } from "../chunk-U3HCB23E.js";
55
+ } from "../chunk-CTWY2X4S.js";
56
56
 
57
57
  // src/bin/agt.ts
58
- import { join as join10 } from "path";
59
- import { homedir as homedir3 } from "os";
58
+ import { join as join14 } from "path";
59
+ import { homedir as homedir5 } from "os";
60
60
  import { Command } from "commander";
61
61
 
62
62
  // src/commands/whoami.ts
@@ -550,8 +550,8 @@ async function lintCommand(path) {
550
550
  process.exitCode = 1;
551
551
  return;
552
552
  }
553
- const { readdirSync, statSync: statSync2 } = await import("fs");
554
- const entries = readdirSync(augmentedDir);
553
+ const { readdirSync: readdirSync2, statSync: statSync2 } = await import("fs");
554
+ const entries = readdirSync2(augmentedDir);
555
555
  for (const entry of entries) {
556
556
  const entryPath = join2(augmentedDir, entry);
557
557
  if (statSync2(entryPath).isDirectory()) {
@@ -1552,14 +1552,671 @@ async function provisionCommand(codeName, options) {
1552
1552
  info(` agt drift check ${agentData.code_name}`);
1553
1553
  }
1554
1554
 
1555
- // src/commands/drift.ts
1555
+ // src/commands/impersonate.ts
1556
1556
  import chalk10 from "chalk";
1557
1557
  import ora10 from "ora";
1558
+ import { spawn } from "child_process";
1559
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync6 } from "fs";
1560
+ import { join as join9 } from "path";
1561
+
1562
+ // src/lib/impersonate-flag.ts
1563
+ var ENV_VAR = "AGT_IMPERSONATE_ENABLED";
1564
+ function impersonateEnabled() {
1565
+ const v = process.env[ENV_VAR];
1566
+ if (!v) return false;
1567
+ const trimmed = v.trim().toLowerCase();
1568
+ return !(trimmed === "" || trimmed === "0" || trimmed === "false" || trimmed === "no");
1569
+ }
1570
+ function requireImpersonateEnabled() {
1571
+ if (impersonateEnabled()) return;
1572
+ process.stderr.write(
1573
+ `
1574
+ The \`agt impersonate\` commands are gated behind a feature flag.
1575
+
1576
+ To enable them, set ${ENV_VAR}=1 in your environment:
1577
+
1578
+ export ${ENV_VAR}=1
1579
+
1580
+ These commands are part of the operator-impersonates-agent v0 flow
1581
+ (ENG-5687 / ENG-5688). The gating will be removed once the
1582
+ surrounding pieces (ENG-5689 channel-MCP refusal, ENG-5690 slash
1583
+ commands) land and the end-to-end smoke test has been run against
1584
+ production.
1585
+
1586
+ `
1587
+ );
1588
+ process.exit(2);
1589
+ }
1590
+
1591
+ // src/lib/impersonate-state.ts
1592
+ import {
1593
+ chmodSync,
1594
+ existsSync as existsSync2,
1595
+ mkdirSync as mkdirSync4,
1596
+ readFileSync as readFileSync2,
1597
+ renameSync,
1598
+ rmSync,
1599
+ writeFileSync as writeFileSync4
1600
+ } from "fs";
1601
+ import { homedir } from "os";
1602
+ import { join as join6 } from "path";
1603
+ var IMPERSONATE_ROOT = join6(homedir(), ".augmented-impersonate");
1604
+ var ACTIVE_DIR = join6(IMPERSONATE_ROOT, "active");
1605
+ var ACTIVE_MANIFEST_PATH = join6(ACTIVE_DIR, "manifest.json");
1606
+ var CODE_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
1607
+ function assertValidCodeName(codeName) {
1608
+ if (!CODE_NAME_RE.test(codeName)) {
1609
+ throw new Error(
1610
+ `Invalid agent code_name "${codeName}" \u2014 must be lowercase kebab-case (a-z, 0-9, hyphens; no leading/trailing/consecutive hyphens).`
1611
+ );
1612
+ }
1613
+ }
1614
+ function getImpersonateCodeNameDir(codeName) {
1615
+ assertValidCodeName(codeName);
1616
+ return join6(IMPERSONATE_ROOT, codeName);
1617
+ }
1618
+ function ensureCodeNameDir(codeName) {
1619
+ assertValidCodeName(codeName);
1620
+ const dir = getImpersonateCodeNameDir(codeName);
1621
+ mkdirSync4(dir, { recursive: true });
1622
+ return dir;
1623
+ }
1624
+ function ensureImpersonateWorkdir(codeName) {
1625
+ const dir = join6(ensureCodeNameDir(codeName), "workdir");
1626
+ mkdirSync4(dir, { recursive: true });
1627
+ return dir;
1628
+ }
1629
+ function readActiveManifest() {
1630
+ if (!existsSync2(ACTIVE_MANIFEST_PATH)) return null;
1631
+ try {
1632
+ const raw = readFileSync2(ACTIVE_MANIFEST_PATH, "utf-8");
1633
+ const parsed = JSON.parse(raw);
1634
+ const backupsOk = typeof parsed.backups === "object" && parsed.backups !== null && Object.values(parsed.backups).every(
1635
+ (v) => v === "had-file" || v === "was-symlink" || v === "didnt-exist"
1636
+ );
1637
+ if (typeof parsed.code_name !== "string" || typeof parsed.agent_id !== "string" || typeof parsed.team_id !== "string" || typeof parsed.token !== "string" || typeof parsed.expires_at !== "number" || typeof parsed.session_id !== "string" || typeof parsed.minted_at !== "string" || typeof parsed.project_cwd !== "string" || // ENG-5688 (redesigned): host required so `exit` calls /stop against
1638
+ // the right environment. Required, not optional, because writing the
1639
+ // wrong host on an existing session would point exit at a server
1640
+ // that has no record of the session — silently misleading.
1641
+ typeof parsed.host !== "string" || parsed.host.length === 0 || !backupsOk) {
1642
+ return null;
1643
+ }
1644
+ return parsed;
1645
+ } catch {
1646
+ return null;
1647
+ }
1648
+ }
1649
+ function writeActiveManifest(manifest) {
1650
+ mkdirSync4(ACTIVE_DIR, { recursive: true, mode: 448 });
1651
+ const tmp = ACTIVE_MANIFEST_PATH + ".tmp";
1652
+ writeFileSync4(tmp, JSON.stringify(manifest, null, 2), { mode: 384 });
1653
+ chmodSync(tmp, 384);
1654
+ renameSync(tmp, ACTIVE_MANIFEST_PATH);
1655
+ }
1656
+ function clearActiveManifest() {
1657
+ if (existsSync2(ACTIVE_MANIFEST_PATH)) {
1658
+ rmSync(ACTIVE_MANIFEST_PATH);
1659
+ }
1660
+ }
1661
+ function isExpired(manifest, now = Date.now()) {
1662
+ return manifest.expires_at * 1e3 <= now;
1663
+ }
1664
+
1665
+ // src/lib/impersonate-fs-ops.ts
1666
+ import {
1667
+ existsSync as existsSync3,
1668
+ lstatSync,
1669
+ readlinkSync,
1670
+ realpathSync,
1671
+ renameSync as renameSync2,
1672
+ symlinkSync,
1673
+ unlinkSync
1674
+ } from "fs";
1675
+ import { homedir as homedir2 } from "os";
1676
+ import { dirname, join as join7, parse, sep } from "path";
1677
+ var BACKUP_SUFFIX = ".pre-impersonate-backup";
1678
+ function findGitWorkTreeRoot(startDir) {
1679
+ const { root } = parse(startDir);
1680
+ let dir = startDir;
1681
+ for (; ; ) {
1682
+ if (existsSync3(join7(dir, ".git"))) return dir;
1683
+ if (dir === root) return null;
1684
+ const parent = dirname(dir);
1685
+ if (parent === dir) return null;
1686
+ dir = parent;
1687
+ }
1688
+ }
1689
+ function swapInPersonaFile(projectPath, personaPath) {
1690
+ let kind;
1691
+ if (!lstatSafe(projectPath)) {
1692
+ kind = "didnt-exist";
1693
+ } else {
1694
+ const stat = lstatSync(projectPath);
1695
+ if (stat.isSymbolicLink()) {
1696
+ const target = readlinkSync(projectPath);
1697
+ const ourRoot = realpathSync(homedir2()) + sep + ".augmented-impersonate" + sep;
1698
+ let resolvedTarget;
1699
+ try {
1700
+ resolvedTarget = realpathSync(projectPath);
1701
+ } catch {
1702
+ throw new Error(
1703
+ `${projectPath} is a broken symlink (target ${target}). Resolve manually and retry.`
1704
+ );
1705
+ }
1706
+ if (resolvedTarget.startsWith(ourRoot)) {
1707
+ unlinkSync(projectPath);
1708
+ kind = "was-symlink";
1709
+ } else {
1710
+ throw new Error(
1711
+ `${projectPath} is a symlink to ${target} (resolved: ${resolvedTarget}). Refusing to replace it \u2014 it doesn't live under ${ourRoot}. Resolve manually and retry.`
1712
+ );
1713
+ }
1714
+ } else {
1715
+ const backupPath = projectPath + BACKUP_SUFFIX;
1716
+ if (existsSync3(backupPath)) {
1717
+ throw new Error(
1718
+ `${backupPath} already exists from a previous run. Remove it manually if you're sure it's stale, then retry.`
1719
+ );
1720
+ }
1721
+ renameSync2(projectPath, backupPath);
1722
+ kind = "had-file";
1723
+ }
1724
+ }
1725
+ symlinkSync(personaPath, projectPath, "file");
1726
+ return kind;
1727
+ }
1728
+ function restoreSwapped(projectPath, kind) {
1729
+ if (lstatSafe(projectPath)) {
1730
+ const stat = lstatSync(projectPath);
1731
+ if (stat.isSymbolicLink()) {
1732
+ unlinkSync(projectPath);
1733
+ } else {
1734
+ return;
1735
+ }
1736
+ }
1737
+ if (kind === "had-file") {
1738
+ const backupPath = projectPath + BACKUP_SUFFIX;
1739
+ if (existsSync3(backupPath)) {
1740
+ renameSync2(backupPath, projectPath);
1741
+ }
1742
+ }
1743
+ }
1744
+ function lstatSafe(path) {
1745
+ try {
1746
+ lstatSync(path);
1747
+ return true;
1748
+ } catch {
1749
+ return false;
1750
+ }
1751
+ }
1752
+
1753
+ // src/lib/impersonate-hook.ts
1754
+ import {
1755
+ copyFileSync,
1756
+ existsSync as existsSync4,
1757
+ mkdirSync as mkdirSync5,
1758
+ readdirSync,
1759
+ readFileSync as readFileSync3,
1760
+ renameSync as renameSync3,
1761
+ rmdirSync,
1762
+ unlinkSync as unlinkSync2,
1763
+ writeFileSync as writeFileSync5
1764
+ } from "fs";
1765
+ import { join as join8 } from "path";
1766
+ var INTRODUCE_HOOK_COMMAND = "agt impersonate introduce";
1767
+ var SESSION_START_MATCHER = "startup";
1768
+ function registerIntroduceHook(projectCwd, command = INTRODUCE_HOOK_COMMAND) {
1769
+ const claudeDir = join8(projectCwd, ".claude");
1770
+ const createdClaudeDir = !existsSync4(claudeDir);
1771
+ mkdirSync5(claudeDir, { recursive: true });
1772
+ const settingsPath = join8(claudeDir, "settings.local.json");
1773
+ const settingsExisted = existsSync4(settingsPath);
1774
+ const backupPath = settingsPath + BACKUP_SUFFIX;
1775
+ let settings = {};
1776
+ if (settingsExisted) {
1777
+ if (!existsSync4(backupPath)) {
1778
+ copyFileSync(settingsPath, backupPath);
1779
+ }
1780
+ settings = asPlainObject(safeParseJson(readFileSync3(settingsPath, "utf-8")));
1781
+ }
1782
+ const hooks = asPlainObject(settings["hooks"]);
1783
+ const existing = Array.isArray(hooks[SESSION_START_KEY]) ? [...hooks[SESSION_START_KEY]] : [];
1784
+ const alreadyRegistered = existing.some(
1785
+ (entry) => entryMatchesCommand(entry, command)
1786
+ );
1787
+ if (!alreadyRegistered) {
1788
+ existing.push({
1789
+ matcher: SESSION_START_MATCHER,
1790
+ hooks: [{ type: "command", command }]
1791
+ });
1792
+ }
1793
+ hooks[SESSION_START_KEY] = existing;
1794
+ settings["hooks"] = hooks;
1795
+ writeFileSync5(settingsPath, JSON.stringify(settings, null, 2) + "\n");
1796
+ return {
1797
+ settings_path: settingsPath,
1798
+ settings_backup: settingsExisted ? "had-file" : "didnt-exist",
1799
+ created_claude_dir: createdClaudeDir
1800
+ };
1801
+ }
1802
+ function unregisterIntroduceHook(backup) {
1803
+ const { settings_path, settings_backup, created_claude_dir } = backup;
1804
+ const backupPath = settings_path + BACKUP_SUFFIX;
1805
+ if (settings_backup === "had-file") {
1806
+ if (existsSync4(backupPath)) {
1807
+ renameSync3(backupPath, settings_path);
1808
+ }
1809
+ } else {
1810
+ if (existsSync4(settings_path)) unlinkSync2(settings_path);
1811
+ if (existsSync4(backupPath)) unlinkSync2(backupPath);
1812
+ }
1813
+ if (created_claude_dir) {
1814
+ const claudeDir = dirOf(settings_path);
1815
+ try {
1816
+ if (existsSync4(claudeDir) && readdirSync(claudeDir).length === 0) {
1817
+ rmdirSync(claudeDir);
1818
+ }
1819
+ } catch {
1820
+ }
1821
+ }
1822
+ }
1823
+ var SESSION_START_KEY = "SessionStart";
1824
+ function entryMatchesCommand(entry, command) {
1825
+ if (entry.matcher !== SESSION_START_MATCHER) return false;
1826
+ const entryHooks = entry.hooks;
1827
+ return Array.isArray(entryHooks) && entryHooks.some(
1828
+ (h) => typeof h === "object" && h !== null && h.type === "command" && h.command === command
1829
+ );
1830
+ }
1831
+ function dirOf(filePath) {
1832
+ const idx = filePath.lastIndexOf("/");
1833
+ return idx === -1 ? filePath : filePath.slice(0, idx);
1834
+ }
1835
+ function safeParseJson(text) {
1836
+ try {
1837
+ return JSON.parse(text);
1838
+ } catch {
1839
+ return null;
1840
+ }
1841
+ }
1842
+ function asPlainObject(value) {
1843
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
1844
+ }
1845
+
1846
+ // src/lib/impersonate-introduce.ts
1847
+ function parseIdentityFromClaudeMd(content) {
1848
+ const headingMatch = content.match(/^#\s+(.+?)\s*$/m);
1849
+ const displayName = headingMatch?.[1]?.trim() || null;
1850
+ const roleMatch = content.match(
1851
+ /^You are \*\*[^*]+\*\*,\s*\*\*([^*]+)\*\*/m
1852
+ );
1853
+ const role = roleMatch?.[1]?.trim() || null;
1854
+ return { displayName, role };
1855
+ }
1856
+ function parseIntegrationsFromMcpJson(content) {
1857
+ let parsed;
1858
+ try {
1859
+ parsed = JSON.parse(content);
1860
+ } catch {
1861
+ return [];
1862
+ }
1863
+ const servers = parsed?.mcpServers;
1864
+ if (!servers || typeof servers !== "object" || Array.isArray(servers)) {
1865
+ return [];
1866
+ }
1867
+ return Object.keys(servers).map(prettifyServerName);
1868
+ }
1869
+ function prettifyServerName(key) {
1870
+ return key.split(/[-_]/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
1871
+ }
1872
+ function buildIntroduction(input4) {
1873
+ const { displayName, codeName, role, integrations } = input4;
1874
+ const spokenName = displayName || codeName;
1875
+ const codeSuffix = displayName && displayName !== codeName ? ` (${codeName})` : "";
1876
+ const roleClause = role ? `, ${role}` : "";
1877
+ const lines = [`I'm ${spokenName}${codeSuffix}${roleClause}.`, ""];
1878
+ if (integrations.length > 0) {
1879
+ lines.push(`Connected integrations: ${integrations.join(", ")}.`);
1880
+ } else {
1881
+ lines.push("No integrations are connected.");
1882
+ }
1883
+ return lines.join("\n");
1884
+ }
1885
+
1886
+ // src/commands/impersonate.ts
1887
+ var SWAP_FILES = ["CLAUDE.md", ".mcp.json"];
1888
+ var AGENT_IMPERSONATION_HEADER = "X-Agent-Impersonation";
1889
+ var REDEEM_TOKEN_RE = /^[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4}$/i;
1890
+ async function impersonateConnectCommand(token, options = {}) {
1891
+ requireImpersonateEnabled();
1892
+ const json = isJsonMode();
1893
+ const shouldLaunchClaude = !options.noLaunch && !json;
1894
+ if (!REDEEM_TOKEN_RE.test(token)) {
1895
+ const msg = "Token is not in the expected XXXX-XXXX format. Copy the full `agt impersonate connect <token>` command from the webapp.";
1896
+ if (json) jsonOutput({ ok: false, error: msg });
1897
+ else error(msg);
1898
+ process.exitCode = 1;
1899
+ return;
1900
+ }
1901
+ const existing = readActiveManifest();
1902
+ if (existing) {
1903
+ const msg = `An impersonation session is already active (${existing.code_name}). Run \`agt impersonate exit\` first.`;
1904
+ if (json) jsonOutput({ ok: false, error: msg });
1905
+ else error(msg);
1906
+ process.exitCode = 1;
1907
+ return;
1908
+ }
1909
+ if (!options.workdir) {
1910
+ const workTreeRoot = findGitWorkTreeRoot(process.cwd());
1911
+ if (workTreeRoot) {
1912
+ const msg = `Refusing to impersonate inside a git working tree (${workTreeRoot}). connect swaps the agent's ${SWAP_FILES.join(" + ")} into the current directory, which would overwrite the repo's own files. Re-run with \`--workdir\` to use an auto-provisioned dedicated directory, or run from a standalone empty directory.`;
1913
+ if (json) jsonOutput({ ok: false, error: msg });
1914
+ else error(msg);
1915
+ process.exitCode = 1;
1916
+ return;
1917
+ }
1918
+ }
1919
+ if (!json) console.log(chalk10.bold("\nAugmented \u2014 Impersonate\n"));
1920
+ const spinner = ora10({
1921
+ text: "Redeeming token\u2026",
1922
+ isSilent: json
1923
+ });
1924
+ spinner.start();
1925
+ const host2 = getHost();
1926
+ let bundle;
1927
+ try {
1928
+ const res = await fetch(`${host2}/impersonate/agent/redeem`, {
1929
+ method: "POST",
1930
+ headers: { "Content-Type": "application/json" },
1931
+ body: JSON.stringify({ redeem_token: token })
1932
+ });
1933
+ if (!res.ok) {
1934
+ const body = await res.json().catch(() => ({}));
1935
+ const detail = body["error"] ?? `HTTP ${res.status}`;
1936
+ throw new Error(`${detail} (HTTP ${res.status})`);
1937
+ }
1938
+ bundle = await res.json();
1939
+ } catch (err) {
1940
+ spinner.fail("Failed to redeem token.");
1941
+ const msg = err instanceof Error ? err.message : String(err);
1942
+ if (json) jsonOutput({ ok: false, error: msg });
1943
+ else error(msg);
1944
+ process.exitCode = 1;
1945
+ return;
1946
+ }
1947
+ spinner.text = "Writing persona files\u2026";
1948
+ const personaDir = ensureCodeNameDir(bundle.agent.code_name);
1949
+ writeFileSync6(
1950
+ join9(personaDir, "CLAUDE.md"),
1951
+ bundle.artifacts["CLAUDE.md"]
1952
+ );
1953
+ writeFileSync6(
1954
+ join9(personaDir, ".mcp.json"),
1955
+ bundle.artifacts[".mcp.json"]
1956
+ );
1957
+ spinner.text = "Swapping persona files\u2026";
1958
+ const projectCwd = options.workdir ? ensureImpersonateWorkdir(bundle.agent.code_name) : process.cwd();
1959
+ const backups = {};
1960
+ const swapped = [];
1961
+ let hookBackup;
1962
+ try {
1963
+ for (const file of SWAP_FILES) {
1964
+ const projectPath = join9(projectCwd, file);
1965
+ const kind = swapInPersonaFile(projectPath, join9(personaDir, file));
1966
+ backups[file] = kind;
1967
+ swapped.push({ file, kind });
1968
+ }
1969
+ hookBackup = registerIntroduceHook(projectCwd);
1970
+ const manifest = {
1971
+ code_name: bundle.agent.code_name,
1972
+ agent_id: bundle.agent.agent_id,
1973
+ team_id: bundle.agent.team_id,
1974
+ token: bundle.token,
1975
+ expires_at: bundle.expires_at,
1976
+ session_id: bundle.session_id,
1977
+ minted_at: (/* @__PURE__ */ new Date()).toISOString(),
1978
+ project_cwd: projectCwd,
1979
+ host: host2,
1980
+ backups,
1981
+ hook: hookBackup
1982
+ };
1983
+ writeActiveManifest(manifest);
1984
+ } catch (err) {
1985
+ if (hookBackup) {
1986
+ try {
1987
+ unregisterIntroduceHook(hookBackup);
1988
+ } catch {
1989
+ }
1990
+ }
1991
+ for (const { file, kind } of [...swapped].reverse()) {
1992
+ try {
1993
+ restoreSwapped(join9(projectCwd, file), kind);
1994
+ } catch {
1995
+ }
1996
+ }
1997
+ spinner.fail("Failed to enter impersonation; rolled back changes.");
1998
+ throw err;
1999
+ }
2000
+ spinner.stop();
2001
+ if (json) {
2002
+ jsonOutput({
2003
+ ok: true,
2004
+ code_name: bundle.agent.code_name,
2005
+ agent_id: bundle.agent.agent_id,
2006
+ session_id: bundle.session_id,
2007
+ expires_at: bundle.expires_at,
2008
+ project_cwd: projectCwd,
2009
+ host: host2,
2010
+ swapped_files: SWAP_FILES
2011
+ });
2012
+ return;
2013
+ }
2014
+ success(`Impersonating ${chalk10.bold(bundle.agent.code_name)}`);
2015
+ console.log();
2016
+ console.log(` Agent ID: ${chalk10.dim(bundle.agent.agent_id)}`);
2017
+ console.log(` Team: ${chalk10.dim(bundle.agent.team_id)}`);
2018
+ console.log(` Session: ${chalk10.dim(bundle.session_id)}`);
2019
+ console.log(
2020
+ ` Expires: ${chalk10.dim(new Date(bundle.expires_at * 1e3).toISOString())}`
2021
+ );
2022
+ console.log(` Project: ${chalk10.dim(projectCwd)}`);
2023
+ console.log(` Host: ${chalk10.dim(host2)}`);
2024
+ console.log(` Swapped: ${chalk10.dim(SWAP_FILES.join(", "))}`);
2025
+ console.log();
2026
+ if (!shouldLaunchClaude) {
2027
+ if (options.workdir) {
2028
+ info(`Start Claude Code in the impersonation workdir: \`cd ${projectCwd}\``);
2029
+ }
2030
+ info(
2031
+ "Restart Claude Code to pick up the agent's persona + MCP server set. Claude Code 2.1.152 does not honour `tools/list_changed` in-session (spike PoC, ENG-4733)."
2032
+ );
2033
+ console.log();
2034
+ info("When done: `agt impersonate exit`");
2035
+ return;
2036
+ }
2037
+ info("Launching Claude Code\u2026 (use `--no-launch` next time to skip)");
2038
+ console.log();
2039
+ await new Promise((resolve2) => {
2040
+ const child = spawn("claude", {
2041
+ stdio: "inherit",
2042
+ cwd: projectCwd
2043
+ });
2044
+ child.on("error", (err) => {
2045
+ if (err.code === "ENOENT") {
2046
+ error(
2047
+ `\`claude\` binary not found on PATH. Start Claude Code yourself from ${projectCwd}, or install the CLI from claude.ai/code.`
2048
+ );
2049
+ process.exitCode = 1;
2050
+ } else {
2051
+ error(`Failed to launch Claude Code: ${err.message}`);
2052
+ process.exitCode = 1;
2053
+ }
2054
+ resolve2();
2055
+ });
2056
+ child.on("exit", (code, signal) => {
2057
+ if (code !== null && code !== 0) process.exitCode = code;
2058
+ if (signal) process.exitCode = 130;
2059
+ resolve2();
2060
+ });
2061
+ });
2062
+ console.log();
2063
+ info("When done: `agt impersonate exit` (still active).");
2064
+ }
2065
+ async function impersonateCurrentCommand() {
2066
+ requireImpersonateEnabled();
2067
+ const json = isJsonMode();
2068
+ const manifest = readActiveManifest();
2069
+ if (!manifest) {
2070
+ if (json) jsonOutput({ ok: true, active: null });
2071
+ else info("No active impersonation.");
2072
+ return;
2073
+ }
2074
+ const expired = isExpired(manifest);
2075
+ if (json) {
2076
+ jsonOutput({
2077
+ ok: true,
2078
+ active: {
2079
+ code_name: manifest.code_name,
2080
+ agent_id: manifest.agent_id,
2081
+ team_id: manifest.team_id,
2082
+ session_id: manifest.session_id,
2083
+ minted_at: manifest.minted_at,
2084
+ expires_at: manifest.expires_at,
2085
+ expired,
2086
+ project_cwd: manifest.project_cwd,
2087
+ host: manifest.host
2088
+ }
2089
+ });
2090
+ return;
2091
+ }
2092
+ console.log();
2093
+ console.log(chalk10.bold(`Impersonating: ${manifest.code_name}`));
2094
+ console.log(` Agent ID: ${chalk10.dim(manifest.agent_id)}`);
2095
+ console.log(` Team: ${chalk10.dim(manifest.team_id)}`);
2096
+ console.log(` Session: ${chalk10.dim(manifest.session_id)}`);
2097
+ console.log(` Minted at: ${chalk10.dim(manifest.minted_at)}`);
2098
+ console.log(
2099
+ ` Expires at: ${chalk10.dim(new Date(manifest.expires_at * 1e3).toISOString())} ` + (expired ? chalk10.red("(EXPIRED \u2014 run `agt impersonate exit`)") : "")
2100
+ );
2101
+ console.log(` Project: ${chalk10.dim(manifest.project_cwd)}`);
2102
+ console.log(` Host: ${chalk10.dim(manifest.host)}`);
2103
+ console.log();
2104
+ }
2105
+ async function impersonateExitCommand() {
2106
+ requireImpersonateEnabled();
2107
+ const json = isJsonMode();
2108
+ const manifest = readActiveManifest();
2109
+ if (!manifest) {
2110
+ if (json) jsonOutput({ ok: true, was_active: false });
2111
+ else info("No active impersonation to exit.");
2112
+ return;
2113
+ }
2114
+ let stopOk = true;
2115
+ let stopDetail = null;
2116
+ try {
2117
+ if (process.env["AGT_API_KEY"]) {
2118
+ await api.post("/impersonate/agent/stop", void 0, {
2119
+ [AGENT_IMPERSONATION_HEADER]: manifest.token
2120
+ });
2121
+ } else {
2122
+ const res = await fetch(`${manifest.host}/impersonate/agent/stop`, {
2123
+ method: "POST",
2124
+ headers: {
2125
+ "Content-Type": "application/json",
2126
+ [AGENT_IMPERSONATION_HEADER]: manifest.token
2127
+ }
2128
+ });
2129
+ if (!res.ok) {
2130
+ const body = await res.json().catch(() => ({}));
2131
+ const detail = body["error"] ?? `HTTP ${res.status}`;
2132
+ stopOk = false;
2133
+ stopDetail = `${detail} (HTTP ${res.status})`;
2134
+ }
2135
+ }
2136
+ } catch (err) {
2137
+ stopOk = false;
2138
+ stopDetail = err instanceof ApiError ? `${err.message} (HTTP ${err.status})` : err instanceof Error ? err.message : String(err);
2139
+ }
2140
+ const restored = [];
2141
+ for (const [file, kind] of Object.entries(manifest.backups)) {
2142
+ const projectPath = join9(manifest.project_cwd, file);
2143
+ try {
2144
+ restoreSwapped(projectPath, kind);
2145
+ restored.push(file);
2146
+ } catch (err) {
2147
+ const msg = err instanceof Error ? err.message : String(err);
2148
+ if (!json) error(`Failed to restore ${file}: ${msg}`);
2149
+ }
2150
+ }
2151
+ if (manifest.hook) {
2152
+ try {
2153
+ unregisterIntroduceHook(manifest.hook);
2154
+ } catch (err) {
2155
+ const msg = err instanceof Error ? err.message : String(err);
2156
+ if (!json) error(`Failed to remove introduce hook: ${msg}`);
2157
+ }
2158
+ }
2159
+ clearActiveManifest();
2160
+ if (json) {
2161
+ jsonOutput({
2162
+ ok: true,
2163
+ was_active: true,
2164
+ session_id: manifest.session_id,
2165
+ stop_acknowledged: stopOk,
2166
+ stop_detail: stopDetail,
2167
+ restored
2168
+ });
2169
+ return;
2170
+ }
2171
+ success(`Exited impersonation: ${manifest.code_name}`);
2172
+ if (restored.length > 0) {
2173
+ info(`Restored: ${restored.join(", ")}`);
2174
+ }
2175
+ if (!stopOk) {
2176
+ info(`Note: server-side stop not acknowledged (${stopDetail}). Token will expire naturally.`);
2177
+ }
2178
+ info("Restart Claude Code to pick up your original persona.");
2179
+ }
2180
+ async function impersonateIntroduceCommand() {
2181
+ try {
2182
+ const manifest = readActiveManifest();
2183
+ if (!manifest || isExpired(manifest)) return;
2184
+ const cwd = manifest.project_cwd;
2185
+ const identity = readClaudeMdIdentity(join9(cwd, "CLAUDE.md"));
2186
+ const integrations = readMcpIntegrations(join9(cwd, ".mcp.json"));
2187
+ const intro = buildIntroduction({
2188
+ displayName: identity.displayName,
2189
+ codeName: manifest.code_name,
2190
+ role: identity.role,
2191
+ integrations
2192
+ });
2193
+ process.stdout.write(intro + "\n");
2194
+ } catch {
2195
+ }
2196
+ }
2197
+ function readClaudeMdIdentity(path) {
2198
+ try {
2199
+ return parseIdentityFromClaudeMd(readFileSync4(path, "utf-8"));
2200
+ } catch {
2201
+ return { displayName: null, role: null };
2202
+ }
2203
+ }
2204
+ function readMcpIntegrations(path) {
2205
+ try {
2206
+ return parseIntegrationsFromMcpJson(readFileSync4(path, "utf-8"));
2207
+ } catch {
2208
+ return [];
2209
+ }
2210
+ }
2211
+
2212
+ // src/commands/drift.ts
2213
+ import chalk11 from "chalk";
2214
+ import ora11 from "ora";
1558
2215
 
1559
2216
  // ../../packages/core/dist/drift/live-state-reader.js
1560
2217
  import { readFile } from "fs/promises";
1561
2218
  import { createHash } from "crypto";
1562
- import { join as join6 } from "path";
2219
+ import { join as join10 } from "path";
1563
2220
  import JSON5 from "json5";
1564
2221
  async function hashFile(filePath) {
1565
2222
  try {
@@ -1583,8 +2240,8 @@ async function readLiveState(options) {
1583
2240
  const toolsFile = trackedFiles.find((f) => f.includes("TOOLS")) ?? "TOOLS.md";
1584
2241
  const [frameworkConfig, charterHash, toolsHash] = await Promise.all([
1585
2242
  readJsonFile(options.configPath),
1586
- hashFile(join6(options.teamDir, charterFile)),
1587
- hashFile(join6(options.teamDir, toolsFile))
2243
+ hashFile(join10(options.teamDir, charterFile)),
2244
+ hashFile(join10(options.teamDir, toolsFile))
1588
2245
  ]);
1589
2246
  return {
1590
2247
  frameworkConfig,
@@ -1599,15 +2256,15 @@ var KEBAB_CASE_RE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
1599
2256
  function severityColor(severity) {
1600
2257
  switch (severity) {
1601
2258
  case "critical":
1602
- return chalk10.red(severity);
2259
+ return chalk11.red(severity);
1603
2260
  case "warning":
1604
- return chalk10.yellow(severity);
2261
+ return chalk11.yellow(severity);
1605
2262
  default:
1606
- return chalk10.dim(severity);
2263
+ return chalk11.dim(severity);
1607
2264
  }
1608
2265
  }
1609
2266
  function printDriftReport(report) {
1610
- console.log(chalk10.bold(`
2267
+ console.log(chalk11.bold(`
1611
2268
  Drift Report: ${report.codeName}
1612
2269
  `));
1613
2270
  info(`Agent ID: ${report.agentId}`);
@@ -1636,7 +2293,7 @@ async function driftCheckCommand(codeName, opts) {
1636
2293
  return;
1637
2294
  }
1638
2295
  const useJson = opts.json || isJsonMode();
1639
- const spinner = ora10({ text: `Checking drift for "${codeName}"\u2026`, isSilent: useJson });
2296
+ const spinner = ora11({ text: `Checking drift for "${codeName}"\u2026`, isSilent: useJson });
1640
2297
  spinner.start();
1641
2298
  try {
1642
2299
  const driftData = await api.get(`/agents/${encodeURIComponent(codeName)}/drift-data`);
@@ -1718,14 +2375,14 @@ async function driftWatchCommand(codeName, opts) {
1718
2375
  const trackedFiles = adapter.driftTrackedFiles();
1719
2376
  if (!useJson) {
1720
2377
  console.log(
1721
- chalk10.bold(`
2378
+ chalk11.bold(`
1722
2379
  Watching drift for "${codeName}" every ${intervalSec}s. Press Ctrl+C to stop.
1723
2380
  `)
1724
2381
  );
1725
2382
  }
1726
2383
  let previousFindingCount = -1;
1727
2384
  const runCheck = async () => {
1728
- const spinner = ora10({ text: `Checking drift for "${codeName}"\u2026`, isSilent: useJson });
2385
+ const spinner = ora11({ text: `Checking drift for "${codeName}"\u2026`, isSilent: useJson });
1729
2386
  spinner.start();
1730
2387
  try {
1731
2388
  const driftData = await api.get(`/agents/${encodeURIComponent(codeName)}/drift-data`);
@@ -1789,19 +2446,19 @@ Watching drift for "${codeName}" every ${intervalSec}s. Press Ctrl+C to stop.
1789
2446
  }, intervalSec * 1e3);
1790
2447
  process.on("SIGINT", () => {
1791
2448
  clearInterval(timer);
1792
- if (!useJson) console.log(chalk10.dim("\nStopped watching."));
2449
+ if (!useJson) console.log(chalk11.dim("\nStopped watching."));
1793
2450
  process.exit(0);
1794
2451
  });
1795
2452
  }
1796
2453
 
1797
2454
  // src/commands/host.ts
1798
- import chalk11 from "chalk";
1799
- import ora11 from "ora";
2455
+ import chalk12 from "chalk";
2456
+ import ora12 from "ora";
1800
2457
  async function hostListCommand() {
1801
2458
  const teamSlug = requireTeam();
1802
2459
  if (!teamSlug) return;
1803
2460
  const json = isJsonMode();
1804
- const spinner = ora11({ text: "Fetching hosts\u2026", isSilent: json });
2461
+ const spinner = ora12({ text: "Fetching hosts\u2026", isSilent: json });
1805
2462
  spinner.start();
1806
2463
  try {
1807
2464
  const data = await api.get("/hosts");
@@ -1819,10 +2476,10 @@ async function hostListCommand() {
1819
2476
  return;
1820
2477
  }
1821
2478
  const rows = data.hosts.map((h) => {
1822
- const status = h.status === "active" ? chalk11.green("active") : chalk11.red("decommissioned");
2479
+ const status = h.status === "active" ? chalk12.green("active") : chalk12.red("decommissioned");
1823
2480
  const agents = String(h.agents);
1824
- const lastSeen = h.last_seen_at ? new Date(h.last_seen_at).toLocaleDateString() : chalk11.dim("never");
1825
- const prefix = h.key_prefix ? `tlk_${h.key_prefix}\u2026` : chalk11.dim("none");
2481
+ const lastSeen = h.last_seen_at ? new Date(h.last_seen_at).toLocaleDateString() : chalk12.dim("never");
2482
+ const prefix = h.key_prefix ? `tlk_${h.key_prefix}\u2026` : chalk12.dim("none");
1826
2483
  return [h.name, status, agents, lastSeen, prefix];
1827
2484
  });
1828
2485
  table(["Name", "Status", "Agents", "Last Seen", "Key"], rows);
@@ -1849,14 +2506,14 @@ async function hostAssignCommand(hostName, agentCodeNames, opts) {
1849
2506
  process.exitCode = 1;
1850
2507
  return;
1851
2508
  }
1852
- const spinner = ora11({ text: "Assigning agents\u2026", isSilent: json });
2509
+ const spinner = ora12({ text: "Assigning agents\u2026", isSilent: json });
1853
2510
  spinner.start();
1854
2511
  try {
1855
2512
  await api.post(`/hosts/${encodeURIComponent(hostName)}/assign`, {
1856
2513
  agents: agentCodeNames,
1857
2514
  force: opts.force
1858
2515
  });
1859
- spinner.succeed(`Agents assigned to ${chalk11.bold(hostName)}.`);
2516
+ spinner.succeed(`Agents assigned to ${chalk12.bold(hostName)}.`);
1860
2517
  if (json) {
1861
2518
  jsonOutput({ ok: true, host: hostName, assigned: agentCodeNames });
1862
2519
  return;
@@ -1887,13 +2544,13 @@ async function hostUnassignCommand(hostName, agentCodeNames) {
1887
2544
  process.exitCode = 1;
1888
2545
  return;
1889
2546
  }
1890
- const spinner = ora11({ text: "Unassigning agents\u2026", isSilent: json });
2547
+ const spinner = ora12({ text: "Unassigning agents\u2026", isSilent: json });
1891
2548
  spinner.start();
1892
2549
  try {
1893
2550
  await api.post(`/hosts/${encodeURIComponent(hostName)}/unassign`, {
1894
2551
  agents: agentCodeNames
1895
2552
  });
1896
- spinner.succeed(`Agents unassigned from ${chalk11.bold(hostName)}.`);
2553
+ spinner.succeed(`Agents unassigned from ${chalk12.bold(hostName)}.`);
1897
2554
  if (json) {
1898
2555
  jsonOutput({ ok: true, host: hostName, unassigned: agentCodeNames });
1899
2556
  return;
@@ -1913,7 +2570,7 @@ async function hostUnassignCommand(hostName, agentCodeNames) {
1913
2570
  }
1914
2571
  async function hostAgentsCommand(hostName) {
1915
2572
  const json = isJsonMode();
1916
- const spinner = ora11({ text: "Fetching host agents\u2026", isSilent: json });
2573
+ const spinner = ora12({ text: "Fetching host agents\u2026", isSilent: json });
1917
2574
  spinner.start();
1918
2575
  try {
1919
2576
  const hostId = await getHostId();
@@ -1952,7 +2609,7 @@ async function hostAgentsCommand(hostName) {
1952
2609
  return;
1953
2610
  }
1954
2611
  const rows = agents.map((a) => {
1955
- const statusColor = a.status === "active" ? chalk11.green : chalk11.yellow;
2612
+ const statusColor = a.status === "active" ? chalk12.green : chalk12.yellow;
1956
2613
  return [
1957
2614
  a.code_name,
1958
2615
  a.display_name,
@@ -1975,11 +2632,11 @@ async function hostRotateKeyCommand(hostName) {
1975
2632
  const teamSlug = requireTeam();
1976
2633
  if (!teamSlug) return;
1977
2634
  const json = isJsonMode();
1978
- const spinner = ora11({ text: "Rotating host key\u2026", isSilent: json });
2635
+ const spinner = ora12({ text: "Rotating host key\u2026", isSilent: json });
1979
2636
  spinner.start();
1980
2637
  try {
1981
2638
  const data = await api.post(`/hosts/${encodeURIComponent(hostName)}/rotate-key`);
1982
- spinner.succeed(`Key rotated for ${chalk11.bold(hostName)}.`);
2639
+ spinner.succeed(`Key rotated for ${chalk12.bold(hostName)}.`);
1983
2640
  if (json) {
1984
2641
  jsonOutput({
1985
2642
  ok: true,
@@ -1989,12 +2646,12 @@ async function hostRotateKeyCommand(hostName) {
1989
2646
  return;
1990
2647
  }
1991
2648
  console.log();
1992
- info(`Host: ${chalk11.bold(hostName)}`);
2649
+ info(`Host: ${chalk12.bold(hostName)}`);
1993
2650
  info(`Prefix: ${data.key.prefix}`);
1994
2651
  console.log();
1995
- console.log(chalk11.yellow.bold(" Save this key now \u2014 it will not be shown again:"));
2652
+ console.log(chalk12.yellow.bold(" Save this key now \u2014 it will not be shown again:"));
1996
2653
  console.log();
1997
- console.log(` ${chalk11.green.bold(data.key.raw_key)}`);
2654
+ console.log(` ${chalk12.green.bold(data.key.raw_key)}`);
1998
2655
  console.log();
1999
2656
  } catch (err) {
2000
2657
  spinner.fail("Failed to rotate key.");
@@ -2010,11 +2667,11 @@ async function hostDecommissionCommand(hostName) {
2010
2667
  const teamSlug = requireTeam();
2011
2668
  if (!teamSlug) return;
2012
2669
  const json = isJsonMode();
2013
- const spinner = ora11({ text: "Decommissioning host\u2026", isSilent: json });
2670
+ const spinner = ora12({ text: "Decommissioning host\u2026", isSilent: json });
2014
2671
  spinner.start();
2015
2672
  try {
2016
2673
  await api.post(`/hosts/${encodeURIComponent(hostName)}/decommission`);
2017
- spinner.succeed(`Host "${chalk11.bold(hostName)}" decommissioned.`);
2674
+ spinner.succeed(`Host "${chalk12.bold(hostName)}" decommissioned.`);
2018
2675
  if (json) {
2019
2676
  jsonOutput({
2020
2677
  ok: true,
@@ -2024,7 +2681,7 @@ async function hostDecommissionCommand(hostName) {
2024
2681
  return;
2025
2682
  }
2026
2683
  info(`Host: ${hostName}`);
2027
- info(`Status: ${chalk11.red("decommissioned")}`);
2684
+ info(`Status: ${chalk12.red("decommissioned")}`);
2028
2685
  info("API key revoked. Agents remain assigned for audit visibility.");
2029
2686
  info("Reassign agents to another host with `agt host assign --force`.");
2030
2687
  } catch (err) {
@@ -2039,8 +2696,8 @@ async function hostDecommissionCommand(hostName) {
2039
2696
  }
2040
2697
 
2041
2698
  // src/commands/host-pair.ts
2042
- import { spawn, spawnSync } from "child_process";
2043
- import chalk12 from "chalk";
2699
+ import { spawn as spawn2, spawnSync } from "child_process";
2700
+ import chalk13 from "chalk";
2044
2701
  async function hostPairCommand(name, opts) {
2045
2702
  const teamSlug = requireTeam();
2046
2703
  if (!teamSlug) return;
@@ -2110,17 +2767,17 @@ async function hostPairCommand(name, opts) {
2110
2767
  });
2111
2768
  return;
2112
2769
  }
2113
- info(`Pairing Claude Code on ${chalk12.bold(name)} (${instanceId}, ${region})`);
2114
- info(`Local port ${chalk12.cyan(String(localPort))} will be forwarded to the host.`);
2770
+ info(`Pairing Claude Code on ${chalk13.bold(name)} (${instanceId}, ${region})`);
2771
+ info(`Local port ${chalk13.cyan(String(localPort))} will be forwarded to the host.`);
2115
2772
  console.log();
2116
- console.log(chalk12.dim("In the shell that opens, run:"));
2117
- console.log(` ${chalk12.cyan(`CLAUDE_CODE_OAUTH_PORT=${localPort} claude /login`)}`);
2118
- console.log(chalk12.dim("Then click the printed URL on this machine. The OAuth callback"));
2119
- console.log(chalk12.dim(`will reach Claude Code via the port-forward tunnel.`));
2773
+ console.log(chalk13.dim("In the shell that opens, run:"));
2774
+ console.log(` ${chalk13.cyan(`CLAUDE_CODE_OAUTH_PORT=${localPort} claude /login`)}`);
2775
+ console.log(chalk13.dim("Then click the printed URL on this machine. The OAuth callback"));
2776
+ console.log(chalk13.dim(`will reach Claude Code via the port-forward tunnel.`));
2120
2777
  console.log();
2121
- console.log(chalk12.dim("Exit the shell (Ctrl+D) when Claude Code reports successful login."));
2778
+ console.log(chalk13.dim("Exit the shell (Ctrl+D) when Claude Code reports successful login."));
2122
2779
  console.log();
2123
- const tunnel = spawn(
2780
+ const tunnel = spawn2(
2124
2781
  "aws",
2125
2782
  [
2126
2783
  "ssm",
@@ -2139,7 +2796,7 @@ async function hostPairCommand(name, opts) {
2139
2796
  tunnel.stderr?.on("data", (buf) => {
2140
2797
  const line = buf.toString().trim();
2141
2798
  if (line.startsWith("An error occurred")) {
2142
- console.error(chalk12.red(`[tunnel] ${line}`));
2799
+ console.error(chalk13.red(`[tunnel] ${line}`));
2143
2800
  }
2144
2801
  });
2145
2802
  await new Promise((r) => setTimeout(r, 1500));
@@ -2149,7 +2806,7 @@ async function hostPairCommand(name, opts) {
2149
2806
  return;
2150
2807
  }
2151
2808
  if (opts.noShell) {
2152
- console.log(chalk12.dim("--no-shell set; tunnel is running. Press Ctrl+C to exit."));
2809
+ console.log(chalk13.dim("--no-shell set; tunnel is running. Press Ctrl+C to exit."));
2153
2810
  await new Promise((resolve2) => {
2154
2811
  const onSignal = () => {
2155
2812
  terminate(tunnel);
@@ -2177,7 +2834,7 @@ function preflightAws() {
2177
2834
  }
2178
2835
  function runInteractive(cmd, args) {
2179
2836
  return new Promise((resolve2) => {
2180
- const child = spawn(cmd, args, { stdio: "inherit" });
2837
+ const child = spawn2(cmd, args, { stdio: "inherit" });
2181
2838
  child.on("exit", (code) => resolve2(code ?? 0));
2182
2839
  child.on("error", () => resolve2(1));
2183
2840
  });
@@ -2193,15 +2850,15 @@ function terminate(child) {
2193
2850
  // src/commands/manager-watch.tsx
2194
2851
  import { useEffect, useState, useMemo } from "react";
2195
2852
  import { render, Box, Text, useApp, useInput } from "ink";
2196
- import { existsSync as existsSync2, readFileSync as readFileSync2, statSync, openSync, readSync, closeSync } from "fs";
2197
- import { homedir } from "os";
2198
- import { join as join7 } from "path";
2853
+ import { existsSync as existsSync5, readFileSync as readFileSync5, statSync, openSync, readSync, closeSync } from "fs";
2854
+ import { homedir as homedir3 } from "os";
2855
+ import { join as join11 } from "path";
2199
2856
  import { jsx, jsxs } from "react/jsx-runtime";
2200
2857
  var REFRESH_MS = 1e3;
2201
2858
  var LOG_TAIL_LINES = 200;
2202
2859
  var DETAIL_RECENT_LINES = 50;
2203
2860
  function managerWatchCommand(opts = {}) {
2204
- const configDir = opts.configDir ?? join7(homedir(), ".augmented");
2861
+ const configDir = opts.configDir ?? join11(homedir3(), ".augmented");
2205
2862
  const paths = getManagerPaths(configDir);
2206
2863
  const isTty = process.stdout.isTTY === true && process.stdin.isTTY === true;
2207
2864
  if (opts.noTui || !isTty) {
@@ -2225,15 +2882,15 @@ function managerWatchCommand(opts = {}) {
2225
2882
  }
2226
2883
  function readState(stateFile) {
2227
2884
  try {
2228
- if (!existsSync2(stateFile)) return null;
2229
- const raw = readFileSync2(stateFile, "utf-8");
2885
+ if (!existsSync5(stateFile)) return null;
2886
+ const raw = readFileSync5(stateFile, "utf-8");
2230
2887
  return JSON.parse(raw);
2231
2888
  } catch {
2232
2889
  return null;
2233
2890
  }
2234
2891
  }
2235
2892
  function tailLogFile(logFile, lines) {
2236
- if (!existsSync2(logFile)) return [];
2893
+ if (!existsSync5(logFile)) return [];
2237
2894
  try {
2238
2895
  const fileSize = statSync(logFile).size;
2239
2896
  if (fileSize === 0) return [];
@@ -2474,7 +3131,7 @@ function truncate(s, max) {
2474
3131
  return s.length > max ? `${s.slice(0, Math.max(0, max - 1))}\u2026` : s;
2475
3132
  }
2476
3133
  function streamLogFile(logFile) {
2477
- if (!existsSync2(logFile)) {
3134
+ if (!existsSync5(logFile)) {
2478
3135
  process.stderr.write(`No manager log found at ${logFile}.
2479
3136
  Start the manager first: agt manager start
2480
3137
  `);
@@ -2483,7 +3140,7 @@ Start the manager first: agt manager start
2483
3140
  }
2484
3141
  let lastSize = 0;
2485
3142
  try {
2486
- const initial = readFileSync2(logFile, "utf-8");
3143
+ const initial = readFileSync5(logFile, "utf-8");
2487
3144
  process.stdout.write(initial);
2488
3145
  lastSize = statSync(logFile).size;
2489
3146
  } catch (err) {
@@ -2518,16 +3175,16 @@ Start the manager first: agt manager start
2518
3175
  }
2519
3176
 
2520
3177
  // src/commands/agent.ts
2521
- import chalk13 from "chalk";
3178
+ import chalk14 from "chalk";
2522
3179
  import JSON52 from "json5";
2523
- import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
2524
- import { join as join8 } from "path";
3180
+ import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
3181
+ import { join as join12 } from "path";
2525
3182
  async function agentShowCommand(codeName, opts) {
2526
3183
  const json = isJsonMode();
2527
- const unifiedDir = join8(opts.configDir, codeName, "provision");
2528
- const legacyDir = join8(opts.configDir, codeName, "claudecode", "provision");
2529
- const agentDir = existsSync3(unifiedDir) ? unifiedDir : legacyDir;
2530
- const hasLocalConfig = existsSync3(agentDir);
3184
+ const unifiedDir = join12(opts.configDir, codeName, "provision");
3185
+ const legacyDir = join12(opts.configDir, codeName, "claudecode", "provision");
3186
+ const agentDir = existsSync6(unifiedDir) ? unifiedDir : legacyDir;
3187
+ const hasLocalConfig = existsSync6(agentDir);
2531
3188
  let apiChannels = null;
2532
3189
  let apiAgent = null;
2533
3190
  if (getApiKey()) {
@@ -2560,34 +3217,34 @@ async function agentShowCommand(codeName, opts) {
2560
3217
  let openclawConfig = null;
2561
3218
  let agentState = null;
2562
3219
  if (hasLocalConfig) {
2563
- const charterPath = join8(agentDir, "CHARTER.md");
2564
- if (existsSync3(charterPath)) {
2565
- const raw = readFileSync3(charterPath, "utf-8");
3220
+ const charterPath = join12(agentDir, "CHARTER.md");
3221
+ if (existsSync6(charterPath)) {
3222
+ const raw = readFileSync6(charterPath, "utf-8");
2566
3223
  const parsed = extractFrontmatter(raw);
2567
3224
  if (parsed.frontmatter) {
2568
3225
  charter = parsed.frontmatter;
2569
3226
  }
2570
3227
  }
2571
- const toolsPath = join8(agentDir, "TOOLS.md");
2572
- if (existsSync3(toolsPath)) {
2573
- const raw = readFileSync3(toolsPath, "utf-8");
3228
+ const toolsPath = join12(agentDir, "TOOLS.md");
3229
+ if (existsSync6(toolsPath)) {
3230
+ const raw = readFileSync6(toolsPath, "utf-8");
2574
3231
  const parsed = extractFrontmatter(raw);
2575
3232
  if (parsed.frontmatter) {
2576
3233
  tools = parsed.frontmatter;
2577
3234
  }
2578
3235
  }
2579
- const openclawPath = join8(agentDir, "openclaw.json5");
2580
- if (existsSync3(openclawPath)) {
3236
+ const openclawPath = join12(agentDir, "openclaw.json5");
3237
+ if (existsSync6(openclawPath)) {
2581
3238
  try {
2582
- const raw = readFileSync3(openclawPath, "utf-8");
3239
+ const raw = readFileSync6(openclawPath, "utf-8");
2583
3240
  openclawConfig = JSON52.parse(raw);
2584
3241
  } catch {
2585
3242
  }
2586
3243
  }
2587
- const statePath = join8(opts.configDir, "manager-state.json");
2588
- if (existsSync3(statePath)) {
3244
+ const statePath = join12(opts.configDir, "manager-state.json");
3245
+ if (existsSync6(statePath)) {
2589
3246
  try {
2590
- const raw = readFileSync3(statePath, "utf-8");
3247
+ const raw = readFileSync6(statePath, "utf-8");
2591
3248
  const state = JSON.parse(raw);
2592
3249
  agentState = state.agents?.find((a) => a.codeName === codeName) ?? null;
2593
3250
  } catch {
@@ -2654,7 +3311,7 @@ async function agentShowCommand(codeName, opts) {
2654
3311
  return;
2655
3312
  }
2656
3313
  const displayName = apiAgent?.display_name ?? charter?.display_name ?? codeName;
2657
- console.log(chalk13.bold(`
3314
+ console.log(chalk14.bold(`
2658
3315
  Agent: ${codeName}`) + (displayName !== codeName ? ` (${displayName})` : "") + "\n");
2659
3316
  if (charter || apiAgent) {
2660
3317
  const agentId = apiAgent?.agent_id ?? charter?.agent_id;
@@ -2686,7 +3343,7 @@ Agent: ${codeName}`) + (displayName !== codeName ? ` (${displayName})` : "") + "
2686
3343
  info("No agent metadata available");
2687
3344
  }
2688
3345
  const filtered = opts.allChannels ? channelRows : channelRows.filter((c) => c.enabled);
2689
- console.log(chalk13.bold("\nChannels:"));
3346
+ console.log(chalk14.bold("\nChannels:"));
2690
3347
  if (filtered.length === 0) {
2691
3348
  info("(none enabled)");
2692
3349
  } else {
@@ -2702,7 +3359,7 @@ Agent: ${codeName}`) + (displayName !== codeName ? ` (${displayName})` : "") + "
2702
3359
  );
2703
3360
  }
2704
3361
  if (tools) {
2705
- console.log(chalk13.bold("\nTools:"));
3362
+ console.log(chalk14.bold("\nTools:"));
2706
3363
  if (tools.tools.length === 0) {
2707
3364
  info("(none configured)");
2708
3365
  } else {
@@ -2713,7 +3370,7 @@ Agent: ${codeName}`) + (displayName !== codeName ? ` (${displayName})` : "") + "
2713
3370
  }
2714
3371
  if (tools.global_controls) {
2715
3372
  const gc = tools.global_controls;
2716
- console.log(chalk13.bold("\nGlobal Controls:"));
3373
+ console.log(chalk14.bold("\nGlobal Controls:"));
2717
3374
  info(`Network: ${gc.default_network_policy === "deny" ? "deny-by-default" : "allow-by-default"}`);
2718
3375
  info(`Timeout: ${gc.default_timeout_ms}ms`);
2719
3376
  info(`Rate: ${gc.default_rate_limit_rpm} rpm`);
@@ -2729,8 +3386,8 @@ function formatTimestamp(iso) {
2729
3386
  }
2730
3387
 
2731
3388
  // src/commands/kanban-recurring.ts
2732
- import chalk14 from "chalk";
2733
- import ora12 from "ora";
3389
+ import chalk15 from "chalk";
3390
+ import ora13 from "ora";
2734
3391
  async function resolveAgentId(codeName) {
2735
3392
  try {
2736
3393
  const data = await api.get(`/agents/${codeName}`);
@@ -2741,10 +3398,10 @@ async function resolveAgentId(codeName) {
2741
3398
  }
2742
3399
  }
2743
3400
  function priorityLabel(p) {
2744
- return p === 1 ? chalk14.red("HIGH") : p === 3 ? chalk14.dim("LOW") : chalk14.yellow("MED");
3401
+ return p === 1 ? chalk15.red("HIGH") : p === 3 ? chalk15.dim("LOW") : chalk15.yellow("MED");
2745
3402
  }
2746
3403
  function formatSpawnTime(isoDate, timezone) {
2747
- if (!isoDate) return chalk14.dim("\u2014");
3404
+ if (!isoDate) return chalk15.dim("\u2014");
2748
3405
  try {
2749
3406
  return new Intl.DateTimeFormat("en-AU", {
2750
3407
  dateStyle: "medium",
@@ -2785,7 +3442,7 @@ async function kanbanRecurringAddCommand(title, opts) {
2785
3442
  return;
2786
3443
  }
2787
3444
  }
2788
- const spinner = ora12({ text: "Creating recurring template\u2026", isSilent: json });
3445
+ const spinner = ora13({ text: "Creating recurring template\u2026", isSilent: json });
2789
3446
  spinner.start();
2790
3447
  const agentId = await resolveAgentId(opts.agent);
2791
3448
  if (!agentId) {
@@ -2809,8 +3466,8 @@ async function kanbanRecurringAddCommand(title, opts) {
2809
3466
  jsonOutput({ ok: true, template: data.template });
2810
3467
  return;
2811
3468
  }
2812
- success(`Recurring task created: ${chalk14.bold(title)}`);
2813
- info(`Schedule: ${chalk14.cyan(data.template.natural_language ?? data.template.expression ?? data.template.every_interval ?? "")}`);
3469
+ success(`Recurring task created: ${chalk15.bold(title)}`);
3470
+ info(`Schedule: ${chalk15.cyan(data.template.natural_language ?? data.template.expression ?? data.template.every_interval ?? "")}`);
2814
3471
  info(`Next spawn: ${formatSpawnTime(data.template.next_spawn_at, data.template.timezone)}`);
2815
3472
  info(`Timezone: ${data.template.timezone}`);
2816
3473
  } catch (err) {
@@ -2827,7 +3484,7 @@ async function kanbanRecurringListCommand(opts) {
2827
3484
  const teamSlug = requireTeam();
2828
3485
  if (!teamSlug) return;
2829
3486
  const json = isJsonMode();
2830
- const spinner = ora12({ text: "Fetching recurring templates\u2026", isSilent: json });
3487
+ const spinner = ora13({ text: "Fetching recurring templates\u2026", isSilent: json });
2831
3488
  spinner.start();
2832
3489
  const agentId = await resolveAgentId(opts.agent);
2833
3490
  if (!agentId) {
@@ -2853,7 +3510,7 @@ async function kanbanRecurringListCommand(opts) {
2853
3510
  t.title,
2854
3511
  t.natural_language ?? t.expression ?? t.every_interval ?? "\u2014",
2855
3512
  priorityLabel(t.priority),
2856
- t.enabled ? chalk14.green("Active") : chalk14.dim("Disabled"),
3513
+ t.enabled ? chalk15.green("Active") : chalk15.dim("Disabled"),
2857
3514
  formatSpawnTime(t.next_spawn_at, t.timezone),
2858
3515
  String(t.spawn_count)
2859
3516
  ]);
@@ -2875,7 +3532,7 @@ async function kanbanRecurringDisableCommand(titleOrId, opts) {
2875
3532
  const teamSlug = requireTeam();
2876
3533
  if (!teamSlug) return;
2877
3534
  const json = isJsonMode();
2878
- const spinner = ora12({ text: "Disabling recurring template\u2026", isSilent: json });
3535
+ const spinner = ora13({ text: "Disabling recurring template\u2026", isSilent: json });
2879
3536
  spinner.start();
2880
3537
  const agentId = await resolveAgentId(opts.agent);
2881
3538
  if (!agentId) {
@@ -2910,7 +3567,7 @@ async function kanbanRecurringDisableCommand(titleOrId, opts) {
2910
3567
  if (json) {
2911
3568
  jsonOutput({ ok: true, id: match.id, title: match.title, enabled: false });
2912
3569
  } else {
2913
- success(`Disabled: ${chalk14.bold(match.title)}`);
3570
+ success(`Disabled: ${chalk15.bold(match.title)}`);
2914
3571
  }
2915
3572
  } catch (err) {
2916
3573
  spinner.fail("Failed to disable recurring template");
@@ -2924,24 +3581,24 @@ async function kanbanRecurringDisableCommand(titleOrId, opts) {
2924
3581
  }
2925
3582
 
2926
3583
  // src/commands/setup.ts
2927
- import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, accessSync, constants as fsConstants } from "fs";
2928
- import { join as join9, dirname } from "path";
2929
- import { homedir as homedir2 } from "os";
2930
- import chalk15 from "chalk";
2931
- import ora13 from "ora";
3584
+ import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, accessSync, constants as fsConstants } from "fs";
3585
+ import { join as join13, dirname as dirname2 } from "path";
3586
+ import { homedir as homedir4 } from "os";
3587
+ import chalk16 from "chalk";
3588
+ import ora14 from "ora";
2932
3589
  function detectShellProfile() {
2933
3590
  const shell = process.env["SHELL"] ?? "";
2934
- const home = homedir2();
3591
+ const home = homedir4();
2935
3592
  if (shell.includes("zsh")) {
2936
- return join9(home, ".zshrc");
3593
+ return join13(home, ".zshrc");
2937
3594
  }
2938
3595
  if (shell.includes("fish")) {
2939
- const fishConfig = join9(home, ".config", "fish", "config.fish");
3596
+ const fishConfig = join13(home, ".config", "fish", "config.fish");
2940
3597
  return fishConfig;
2941
3598
  }
2942
- const bashrc = join9(home, ".bashrc");
2943
- if (existsSync4(bashrc)) return bashrc;
2944
- return join9(home, ".bash_profile");
3599
+ const bashrc = join13(home, ".bashrc");
3600
+ if (existsSync7(bashrc)) return bashrc;
3601
+ return join13(home, ".bash_profile");
2945
3602
  }
2946
3603
  function maybeWriteSystemWideEnv(apiUrl, apiKey, consoleUrl) {
2947
3604
  const empty = { etcEnvironment: false, profileD: false, bashrc: false };
@@ -2967,14 +3624,14 @@ function quoteForFishShell(value) {
2967
3624
  }
2968
3625
  function writeEtcEnvironment(apiUrl, apiKey, consoleUrl) {
2969
3626
  const envPath = "/etc/environment";
2970
- if (!existsSync4(envPath)) return false;
3627
+ if (!existsSync7(envPath)) return false;
2971
3628
  try {
2972
3629
  accessSync(envPath, fsConstants.W_OK);
2973
3630
  } catch {
2974
3631
  return false;
2975
3632
  }
2976
3633
  try {
2977
- const current = readFileSync4(envPath, "utf-8");
3634
+ const current = readFileSync7(envPath, "utf-8");
2978
3635
  const stripped = current.split(/\r?\n/).filter((line) => !/^\s*(?:export\s+)?AGT_(?:HOST|API_KEY|CONSOLE_URL)=/.test(line)).join("\n");
2979
3636
  const base = stripped.endsWith("\n") || stripped.length === 0 ? stripped : `${stripped}
2980
3637
  `;
@@ -2985,7 +3642,7 @@ function writeEtcEnvironment(apiUrl, apiKey, consoleUrl) {
2985
3642
  if (consoleUrl) lines.push(`AGT_CONSOLE_URL=${quoteForEtcEnvironment(consoleUrl)}`);
2986
3643
  const appended = `${base}${lines.join("\n")}
2987
3644
  `;
2988
- writeFileSync4(envPath, appended, { mode: 420 });
3645
+ writeFileSync7(envPath, appended, { mode: 420 });
2989
3646
  return true;
2990
3647
  } catch {
2991
3648
  return false;
@@ -2993,7 +3650,7 @@ function writeEtcEnvironment(apiUrl, apiKey, consoleUrl) {
2993
3650
  }
2994
3651
  function writeProfileDScript(apiUrl, apiKey, consoleUrl) {
2995
3652
  const profileD = "/etc/profile.d";
2996
- if (!existsSync4(profileD)) return false;
3653
+ if (!existsSync7(profileD)) return false;
2997
3654
  try {
2998
3655
  accessSync(profileD, fsConstants.W_OK);
2999
3656
  } catch {
@@ -3008,7 +3665,7 @@ function writeProfileDScript(apiUrl, apiKey, consoleUrl) {
3008
3665
  ];
3009
3666
  if (consoleUrl) lines.push(`export AGT_CONSOLE_URL=${quoteForPosixShell(consoleUrl)}`);
3010
3667
  lines.push("");
3011
- writeFileSync4(scriptPath, lines.join("\n"), { mode: 420 });
3668
+ writeFileSync7(scriptPath, lines.join("\n"), { mode: 420 });
3012
3669
  return true;
3013
3670
  } catch {
3014
3671
  return false;
@@ -3016,14 +3673,14 @@ function writeProfileDScript(apiUrl, apiKey, consoleUrl) {
3016
3673
  }
3017
3674
  function ensureBashrcSourcesProfileD() {
3018
3675
  const bashrc = "/etc/bashrc";
3019
- if (!existsSync4(bashrc)) return false;
3676
+ if (!existsSync7(bashrc)) return false;
3020
3677
  try {
3021
3678
  accessSync(bashrc, fsConstants.W_OK);
3022
3679
  } catch {
3023
3680
  return false;
3024
3681
  }
3025
3682
  try {
3026
- const current = readFileSync4(bashrc, "utf-8");
3683
+ const current = readFileSync7(bashrc, "utf-8");
3027
3684
  const marker = "# Augmented (agt) \u2014 source system-wide AGT env";
3028
3685
  if (current.includes(marker)) return true;
3029
3686
  const snippet = [
@@ -3034,7 +3691,7 @@ function ensureBashrcSourcesProfileD() {
3034
3691
  "fi",
3035
3692
  ""
3036
3693
  ].join("\n");
3037
- writeFileSync4(bashrc, current + snippet);
3694
+ writeFileSync7(bashrc, current + snippet);
3038
3695
  return true;
3039
3696
  } catch {
3040
3697
  return false;
@@ -3081,10 +3738,10 @@ async function setupCommand(token) {
3081
3738
  if (!apiUrl) {
3082
3739
  apiUrl = "https://api.augmented.team";
3083
3740
  if (!json) {
3084
- info(`No AGT_HOST set \u2014 using default: ${chalk15.bold(apiUrl)}`);
3741
+ info(`No AGT_HOST set \u2014 using default: ${chalk16.bold(apiUrl)}`);
3085
3742
  }
3086
3743
  }
3087
- const spinner = ora13({ text: "Exchanging provisioning token\u2026", isSilent: json });
3744
+ const spinner = ora14({ text: "Exchanging provisioning token\u2026", isSilent: json });
3088
3745
  spinner.start();
3089
3746
  let setupResult;
3090
3747
  try {
@@ -3112,17 +3769,17 @@ async function setupCommand(token) {
3112
3769
  const finalApiUrl = setupResult.api_url || apiUrl;
3113
3770
  process.env["AGT_HOST"] = finalApiUrl;
3114
3771
  process.env["AGT_API_KEY"] = setupResult.api_key;
3115
- const verifySpinner = ora13({ text: "Verifying connection\u2026", isSilent: json });
3772
+ const verifySpinner = ora14({ text: "Verifying connection\u2026", isSilent: json });
3116
3773
  verifySpinner.start();
3117
3774
  try {
3118
3775
  const exchange = await exchangeApiKey(setupResult.api_key);
3119
3776
  verifySpinner.succeed("Connection verified");
3120
3777
  if (!json) {
3121
- info(`Host: ${chalk15.bold(setupResult.host_name)}`);
3778
+ info(`Host: ${chalk16.bold(setupResult.host_name)}`);
3122
3779
  info(`Host ID: ${exchange.hostId}`);
3123
- info(`Team: ${chalk15.bold(exchange.teamSlug ?? setupResult.team_slug ?? "unknown")}`);
3780
+ info(`Team: ${chalk16.bold(exchange.teamSlug ?? setupResult.team_slug ?? "unknown")}`);
3124
3781
  if (exchange.userEmail) {
3125
- info(`User: ${chalk15.bold(exchange.userEmail)}`);
3782
+ info(`User: ${chalk16.bold(exchange.userEmail)}`);
3126
3783
  }
3127
3784
  }
3128
3785
  } catch (err) {
@@ -3149,12 +3806,12 @@ async function setupCommand(token) {
3149
3806
  );
3150
3807
  }
3151
3808
  const exportLines = buildExportLines(shell, finalApiUrl, setupResult.api_key, consoleUrl);
3152
- const profileDir = dirname(profilePath);
3153
- if (!existsSync4(profileDir)) {
3154
- mkdirSync4(profileDir, { recursive: true });
3809
+ const profileDir = dirname2(profilePath);
3810
+ if (!existsSync7(profileDir)) {
3811
+ mkdirSync6(profileDir, { recursive: true });
3155
3812
  }
3156
3813
  const marker = "# Augmented (agt) host configuration";
3157
- const current = existsSync4(profilePath) ? readFileSync4(profilePath, "utf-8") : "";
3814
+ const current = existsSync7(profilePath) ? readFileSync7(profilePath, "utf-8") : "";
3158
3815
  let updated;
3159
3816
  if (current.includes(marker)) {
3160
3817
  updated = current.replace(
@@ -3167,10 +3824,10 @@ async function setupCommand(token) {
3167
3824
  } else {
3168
3825
  updated = current + exportLines;
3169
3826
  }
3170
- writeFileSync4(profilePath, updated.endsWith("\n") ? updated : `${updated}
3827
+ writeFileSync7(profilePath, updated.endsWith("\n") ? updated : `${updated}
3171
3828
  `);
3172
3829
  if (!json) {
3173
- success(`Environment variables written to ${chalk15.bold(profilePath)}`);
3830
+ success(`Environment variables written to ${chalk16.bold(profilePath)}`);
3174
3831
  }
3175
3832
  const sys = maybeWriteSystemWideEnv(finalApiUrl, setupResult.api_key, consoleUrl);
3176
3833
  const valueChannelsWritten = sys.etcEnvironment || sys.profileD;
@@ -3182,10 +3839,10 @@ async function setupCommand(token) {
3182
3839
  ].filter(Boolean).join(" + ");
3183
3840
  success(`System-wide env updated: ${channels2}`);
3184
3841
  }
3185
- const managerSpinner = ora13({ text: "Starting manager daemon\u2026", isSilent: json });
3842
+ const managerSpinner = ora14({ text: "Starting manager daemon\u2026", isSilent: json });
3186
3843
  managerSpinner.start();
3187
3844
  try {
3188
- const configDir = join9(homedir2(), ".augmented");
3845
+ const configDir = join13(homedir4(), ".augmented");
3189
3846
  const { pid } = startWatchdog({ intervalMs: 1e4, configDir, detached: true });
3190
3847
  managerSpinner.succeed(`Manager started (PID ${pid})`);
3191
3848
  } catch (err) {
@@ -3210,21 +3867,21 @@ async function setupCommand(token) {
3210
3867
  process.exit(0);
3211
3868
  } else {
3212
3869
  console.log();
3213
- console.log(chalk15.green.bold(" Setup complete!"));
3870
+ console.log(chalk16.green.bold(" Setup complete!"));
3214
3871
  console.log();
3215
3872
  if (setupResult.agents.length > 0) {
3216
- info(`Agents: ${setupResult.agents.map((a) => chalk15.cyan(a)).join(", ")}`);
3873
+ info(`Agents: ${setupResult.agents.map((a) => chalk16.cyan(a)).join(", ")}`);
3217
3874
  } else {
3218
3875
  info("No agents assigned yet. Assign agents in the dashboard or with: agt host assign");
3219
3876
  }
3220
3877
  console.log();
3221
- info(`Restart your shell or run: ${chalk15.bold(`source ${profilePath}`)}`);
3878
+ info(`Restart your shell or run: ${chalk16.bold(`source ${profilePath}`)}`);
3222
3879
  }
3223
3880
  }
3224
3881
 
3225
3882
  // src/commands/kanban.ts
3226
- import chalk16 from "chalk";
3227
- import ora14 from "ora";
3883
+ import chalk17 from "chalk";
3884
+ import ora15 from "ora";
3228
3885
  async function resolveAgentId2(codeName) {
3229
3886
  try {
3230
3887
  const data = await api.get(`/agents/${codeName}`);
@@ -3234,14 +3891,14 @@ async function resolveAgentId2(codeName) {
3234
3891
  }
3235
3892
  }
3236
3893
  function priorityLabel2(p) {
3237
- return p === 1 ? chalk16.red("HIGH") : p === 3 ? chalk16.dim("LOW") : chalk16.yellow("MED");
3894
+ return p === 1 ? chalk17.red("HIGH") : p === 3 ? chalk17.dim("LOW") : chalk17.yellow("MED");
3238
3895
  }
3239
3896
  function statusLabel(s) {
3240
3897
  const map = {
3241
- in_progress: chalk16.blue("In Progress"),
3242
- todo: chalk16.green("To Do"),
3243
- backlog: chalk16.dim("Backlog"),
3244
- done: chalk16.gray("Done")
3898
+ in_progress: chalk17.blue("In Progress"),
3899
+ todo: chalk17.green("To Do"),
3900
+ backlog: chalk17.dim("Backlog"),
3901
+ done: chalk17.gray("Done")
3245
3902
  };
3246
3903
  return map[s] ?? s;
3247
3904
  }
@@ -3249,7 +3906,7 @@ async function kanbanListCommand(opts) {
3249
3906
  const teamSlug = requireTeam();
3250
3907
  if (!teamSlug) return;
3251
3908
  const json = isJsonMode();
3252
- const spinner = ora14({ text: "Fetching kanban board\u2026", isSilent: json });
3909
+ const spinner = ora15({ text: "Fetching kanban board\u2026", isSilent: json });
3253
3910
  spinner.start();
3254
3911
  const agentId = await resolveAgentId2(opts.agent);
3255
3912
  if (!agentId) {
@@ -3277,7 +3934,7 @@ async function kanbanListCommand(opts) {
3277
3934
  item.estimated_minutes ? `~${item.estimated_minutes}min` : "",
3278
3935
  item.id.slice(0, 8)
3279
3936
  ]);
3280
- console.log(chalk16.bold(`
3937
+ console.log(chalk17.bold(`
3281
3938
  Kanban: ${opts.agent}
3282
3939
  `));
3283
3940
  table(["Pri", "Status", "Title", "Est", "ID"], rows);
@@ -3517,7 +4174,7 @@ function getAcpAgent(name) {
3517
4174
  }
3518
4175
 
3519
4176
  // ../../packages/core/dist/acp/client.js
3520
- import { spawn as spawn2 } from "child_process";
4177
+ import { spawn as spawn3 } from "child_process";
3521
4178
  function resolveAgentCommand(agentName) {
3522
4179
  const adapter = getAcpAgent(agentName);
3523
4180
  if (adapter) {
@@ -3533,7 +4190,7 @@ function resolveAgentCommand(agentName) {
3533
4190
  }
3534
4191
  async function runAcpx(args, options = {}) {
3535
4192
  return new Promise((resolve2) => {
3536
- const child = spawn2("acpx", args, {
4193
+ const child = spawn3("acpx", args, {
3537
4194
  cwd: options.cwd,
3538
4195
  stdio: ["pipe", "pipe", "pipe"],
3539
4196
  env: { ...process.env }
@@ -3733,10 +4390,10 @@ async function acpxCloseCommand(agent2, _opts, cmd) {
3733
4390
 
3734
4391
  // src/commands/update.ts
3735
4392
  import { execFileSync, execSync } from "child_process";
3736
- import { existsSync as existsSync5, realpathSync } from "fs";
3737
- import chalk17 from "chalk";
3738
- import ora15 from "ora";
3739
- var cliVersion = true ? "0.26.2-eng5706.1" : "dev";
4393
+ import { existsSync as existsSync8, realpathSync as realpathSync2 } from "fs";
4394
+ import chalk18 from "chalk";
4395
+ import ora16 from "ora";
4396
+ var cliVersion = true ? "0.27.0-test.4" : "dev";
3740
4397
  async function fetchLatestVersion() {
3741
4398
  const host2 = getHost();
3742
4399
  if (!host2) return null;
@@ -3756,9 +4413,9 @@ async function fetchLatestVersion() {
3756
4413
  }
3757
4414
  function isNewerVersion(local, remote) {
3758
4415
  if (local === "dev") return false;
3759
- const parse = (v) => v.replace(/^v/, "").split(".").map(Number);
3760
- const lParts = parse(local);
3761
- const rParts = parse(remote);
4416
+ const parse2 = (v) => v.replace(/^v/, "").split(".").map(Number);
4417
+ const lParts = parse2(local);
4418
+ const rParts = parse2(remote);
3762
4419
  const lMaj = lParts[0] ?? 0, lMin = lParts[1] ?? 0, lPat = lParts[2] ?? 0;
3763
4420
  const rMaj = rParts[0] ?? 0, rMin = rParts[1] ?? 0, rPat = rParts[2] ?? 0;
3764
4421
  if (rMaj !== lMaj) return rMaj > lMaj;
@@ -3800,7 +4457,7 @@ function detectActiveSessions() {
3800
4457
  }
3801
4458
  function detectInstallSource() {
3802
4459
  try {
3803
- const resolved = realpathSync(process.argv[1] ?? "");
4460
+ const resolved = realpathSync2(process.argv[1] ?? "");
3804
4461
  if (/\/Cellar\/[^/]+\//.test(resolved)) {
3805
4462
  return "brew";
3806
4463
  }
@@ -3840,7 +4497,7 @@ function performUpdate(version) {
3840
4497
  function detectBrewOwner() {
3841
4498
  for (const prefix of ["/home/linuxbrew/.linuxbrew", "/opt/homebrew", "/usr/local"]) {
3842
4499
  const cellar = `${prefix}/Cellar`;
3843
- if (!existsSync5(cellar)) continue;
4500
+ if (!existsSync8(cellar)) continue;
3844
4501
  try {
3845
4502
  return execSync(`stat -c %U "${cellar}" 2>/dev/null || stat -f %Su "${cellar}"`, { encoding: "utf-8" }).trim() || null;
3846
4503
  } catch {
@@ -3850,7 +4507,7 @@ function detectBrewOwner() {
3850
4507
  }
3851
4508
  async function updateCommand(opts = {}) {
3852
4509
  const json = isJsonMode();
3853
- const spinner = ora15({ text: "Checking for updates\u2026", isSilent: json });
4510
+ const spinner = ora16({ text: "Checking for updates\u2026", isSilent: json });
3854
4511
  spinner.start();
3855
4512
  const versionInfo = await fetchLatestVersion();
3856
4513
  if (!versionInfo) {
@@ -3869,13 +4526,13 @@ async function updateCommand(opts = {}) {
3869
4526
  if (json) {
3870
4527
  jsonOutput({ ok: true, current: cliVersion, latest: versionInfo.latest, update_available: false });
3871
4528
  } else {
3872
- success(`You're on the latest version (${chalk17.bold(cliVersion)})`);
4529
+ success(`You're on the latest version (${chalk18.bold(cliVersion)})`);
3873
4530
  }
3874
4531
  return;
3875
4532
  }
3876
4533
  spinner.stop();
3877
4534
  if (!json) {
3878
- info(`Update available: ${chalk17.dim(cliVersion)} \u2192 ${chalk17.bold.green(versionInfo.latest)}`);
4535
+ info(`Update available: ${chalk18.dim(cliVersion)} \u2192 ${chalk18.bold.green(versionInfo.latest)}`);
3879
4536
  if (versionInfo.changelog_url) {
3880
4537
  info(`Changelog: ${versionInfo.changelog_url}`);
3881
4538
  }
@@ -3886,16 +4543,16 @@ async function updateCommand(opts = {}) {
3886
4543
  if (!json) {
3887
4544
  warn("Active processes detected:");
3888
4545
  if (managerPid) {
3889
- console.error(chalk17.yellow(` \u2022 Manager process running (PID ${managerPid})`));
4546
+ console.error(chalk18.yellow(` \u2022 Manager process running (PID ${managerPid})`));
3890
4547
  }
3891
4548
  if (tmuxSessions.length > 0) {
3892
- console.error(chalk17.yellow(` \u2022 ${tmuxSessions.length} active agent session(s): ${tmuxSessions.join(", ")}`));
4549
+ console.error(chalk18.yellow(` \u2022 ${tmuxSessions.length} active agent session(s): ${tmuxSessions.join(", ")}`));
3893
4550
  }
3894
4551
  console.error();
3895
4552
  warn("Updating while the manager is running will leave it on the old version until restarted.");
3896
4553
  warn("Active agent sessions will continue with stale MCP servers.");
3897
4554
  console.error();
3898
- info(`Run ${chalk17.bold("agt update --force")} to update anyway, then restart the manager.`);
4555
+ info(`Run ${chalk18.bold("agt update --force")} to update anyway, then restart the manager.`);
3899
4556
  } else {
3900
4557
  jsonOutput({
3901
4558
  ok: false,
@@ -3913,7 +4570,7 @@ async function updateCommand(opts = {}) {
3913
4570
  return;
3914
4571
  }
3915
4572
  }
3916
- const updateSpinner = ora15({ text: "Installing update\u2026", isSilent: json });
4573
+ const updateSpinner = ora16({ text: "Installing update\u2026", isSilent: json });
3917
4574
  updateSpinner.start();
3918
4575
  try {
3919
4576
  performUpdate(versionInfo.latest);
@@ -3927,8 +4584,8 @@ async function updateCommand(opts = {}) {
3927
4584
  updated: true
3928
4585
  });
3929
4586
  } else {
3930
- success(`Updated to ${chalk17.bold(versionInfo.latest)}`);
3931
- info(`If you have a running manager, restart it: ${chalk17.bold("agt manager stop && agt manager start")}`);
4587
+ success(`Updated to ${chalk18.bold(versionInfo.latest)}`);
4588
+ info(`If you have a running manager, restart it: ${chalk18.bold("agt manager stop && agt manager start")}`);
3932
4589
  }
3933
4590
  } catch (err) {
3934
4591
  updateSpinner.fail("Update failed");
@@ -3959,8 +4616,8 @@ async function checkForUpdateOnStartup() {
3959
4616
  if (!versionInfo) return;
3960
4617
  if (isNewerVersion(cliVersion, versionInfo.latest)) {
3961
4618
  console.error(
3962
- chalk17.yellow(`
3963
- Update available: ${cliVersion} \u2192 ${versionInfo.latest}. Run ${chalk17.bold("agt update")} to install.`) + chalk17.dim("\n Note: Restart the manager after updating.\n")
4619
+ chalk18.yellow(`
4620
+ Update available: ${cliVersion} \u2192 ${versionInfo.latest}. Run ${chalk18.bold("agt update")} to install.`) + chalk18.dim("\n Note: Restart the manager after updating.\n")
3964
4621
  );
3965
4622
  }
3966
4623
  } catch {
@@ -3968,11 +4625,11 @@ async function checkForUpdateOnStartup() {
3968
4625
  }
3969
4626
 
3970
4627
  // src/commands/integration.ts
3971
- import chalk18 from "chalk";
3972
- import ora16 from "ora";
4628
+ import chalk19 from "chalk";
4629
+ import ora17 from "ora";
3973
4630
  async function integrationListCommand() {
3974
4631
  const json = isJsonMode();
3975
- const spinner = ora16({ text: "Fetching integrations\u2026", isSilent: json }).start();
4632
+ const spinner = ora17({ text: "Fetching integrations\u2026", isSilent: json }).start();
3976
4633
  try {
3977
4634
  const data = await api.get("/integrations/bindings");
3978
4635
  spinner.stop();
@@ -3984,11 +4641,11 @@ async function integrationListCommand() {
3984
4641
  info("No integrations found for this team.");
3985
4642
  return;
3986
4643
  }
3987
- console.log(chalk18.bold("\nAvailable Integrations:\n"));
4644
+ console.log(chalk19.bold("\nAvailable Integrations:\n"));
3988
4645
  for (const p of data) {
3989
- const statusColor = p.status === "published" ? chalk18.green : p.status === "archived" ? chalk18.gray : chalk18.yellow;
4646
+ const statusColor = p.status === "published" ? chalk19.green : p.status === "archived" ? chalk19.gray : chalk19.yellow;
3990
4647
  console.log(
3991
- ` ${chalk18.bold(p.name)} ${chalk18.dim(`(${p.slug})`)} ${statusColor(p.status)} v${p.version} ${chalk18.dim(`${p.skills?.length ?? 0} skills, ${p.defined_scopes?.length ?? 0} scopes`)}`
4648
+ ` ${chalk19.bold(p.name)} ${chalk19.dim(`(${p.slug})`)} ${statusColor(p.status)} v${p.version} ${chalk19.dim(`${p.skills?.length ?? 0} skills, ${p.defined_scopes?.length ?? 0} scopes`)}`
3992
4649
  );
3993
4650
  }
3994
4651
  console.log();
@@ -3999,7 +4656,7 @@ async function integrationListCommand() {
3999
4656
  }
4000
4657
  async function integrationShowCommand(slug) {
4001
4658
  const json = isJsonMode();
4002
- const spinner = ora16({ text: "Fetching integration\u2026", isSilent: json }).start();
4659
+ const spinner = ora17({ text: "Fetching integration\u2026", isSilent: json }).start();
4003
4660
  try {
4004
4661
  const all = await api.get("/integrations/bindings");
4005
4662
  const integration2 = all.find((p) => p.slug === slug);
@@ -4015,21 +4672,21 @@ async function integrationShowCommand(slug) {
4015
4672
  jsonOutput({ integration: integration2, scopes });
4016
4673
  return;
4017
4674
  }
4018
- console.log(chalk18.bold(`
4019
- ${integration2.name}`), chalk18.dim(`(${integration2.slug})`));
4020
- if (integration2.description) console.log(chalk18.dim(integration2.description));
4675
+ console.log(chalk19.bold(`
4676
+ ${integration2.name}`), chalk19.dim(`(${integration2.slug})`));
4677
+ if (integration2.description) console.log(chalk19.dim(integration2.description));
4021
4678
  console.log();
4022
4679
  console.log(` Status: ${integration2.status} v${integration2.version}`);
4023
4680
  console.log(` Category: ${integration2.category}`);
4024
4681
  console.log(` Toolkits: ${integration2.required_toolkits.join(", ") || "none"}`);
4025
4682
  console.log(` Skills: ${integration2.skills?.length ?? 0}`);
4026
4683
  if (scopes.length > 0) {
4027
- console.log(chalk18.bold("\n Permission Scopes:\n"));
4684
+ console.log(chalk19.bold("\n Permission Scopes:\n"));
4028
4685
  for (const s of scopes) {
4029
- const roleColor = s.can_grant ? chalk18.green : chalk18.red;
4030
- const overrideTag = s.is_overridden ? chalk18.cyan(" [team override]") : "";
4686
+ const roleColor = s.can_grant ? chalk19.green : chalk19.red;
4687
+ const overrideTag = s.is_overridden ? chalk19.cyan(" [team override]") : "";
4031
4688
  console.log(
4032
- ` ${chalk18.bold(s.id)} ${s.name} min: ${roleColor(s.effective_min_role)}${overrideTag} ${s.can_grant ? chalk18.green("\u2713 grantable") : chalk18.red("\u2717 needs approval")}`
4689
+ ` ${chalk19.bold(s.id)} ${s.name} min: ${roleColor(s.effective_min_role)}${overrideTag} ${s.can_grant ? chalk19.green("\u2713 grantable") : chalk19.red("\u2717 needs approval")}`
4033
4690
  );
4034
4691
  }
4035
4692
  }
@@ -4041,7 +4698,7 @@ ${integration2.name}`), chalk18.dim(`(${integration2.slug})`));
4041
4698
  }
4042
4699
  async function integrationInstallCommand(slug, options) {
4043
4700
  const json = isJsonMode();
4044
- const spinner = ora16({ text: "Installing integration\u2026", isSilent: json }).start();
4701
+ const spinner = ora17({ text: "Installing integration\u2026", isSilent: json }).start();
4045
4702
  try {
4046
4703
  const all = await api.get("/integrations/bindings");
4047
4704
  const integration2 = all.find((p) => p.slug === slug);
@@ -4080,7 +4737,7 @@ async function integrationInstallCommand(slug, options) {
4080
4737
  const needsApproval = err.body["needs_approval"];
4081
4738
  error("Some scopes exceed your role ceiling:");
4082
4739
  for (const s of needsApproval) {
4083
- console.log(chalk18.yellow(` - ${s}`));
4740
+ console.log(chalk19.yellow(` - ${s}`));
4084
4741
  }
4085
4742
  info("To request elevated scopes, use the web dashboard or contact your team admin.");
4086
4743
  process.exitCode = 1;
@@ -4091,7 +4748,7 @@ async function integrationInstallCommand(slug, options) {
4091
4748
  }
4092
4749
  async function integrationUninstallCommand(slug, options) {
4093
4750
  const json = isJsonMode();
4094
- const spinner = ora16({ text: "Uninstalling integration\u2026", isSilent: json }).start();
4751
+ const spinner = ora17({ text: "Uninstalling integration\u2026", isSilent: json }).start();
4095
4752
  try {
4096
4753
  const all = await api.get("/integrations/bindings");
4097
4754
  const integration2 = all.find((p) => p.slug === slug);
@@ -4122,7 +4779,7 @@ async function integrationUninstallCommand(slug, options) {
4122
4779
  }
4123
4780
  async function integrationRequestsCommand() {
4124
4781
  const json = isJsonMode();
4125
- const spinner = ora16({ text: "Fetching scope requests\u2026", isSilent: json }).start();
4782
+ const spinner = ora17({ text: "Fetching scope requests\u2026", isSilent: json }).start();
4126
4783
  try {
4127
4784
  const requests = await api.get("/integrations/bindings/scope-requests");
4128
4785
  spinner.stop();
@@ -4134,10 +4791,10 @@ async function integrationRequestsCommand() {
4134
4791
  info("No pending scope requests.");
4135
4792
  return;
4136
4793
  }
4137
- console.log(chalk18.bold("\nPending Scope Requests:\n"));
4794
+ console.log(chalk19.bold("\nPending Scope Requests:\n"));
4138
4795
  for (const r of requests) {
4139
- console.log(` ${chalk18.bold(r.id)} scopes: ${r.requested_scopes.join(", ")}`);
4140
- if (r.reason) console.log(` reason: ${chalk18.dim(r.reason)}`);
4796
+ console.log(` ${chalk19.bold(r.id)} scopes: ${r.requested_scopes.join(", ")}`);
4797
+ if (r.reason) console.log(` reason: ${chalk19.dim(r.reason)}`);
4141
4798
  console.log(` status: ${r.status} requested: ${r.created_at}`);
4142
4799
  console.log();
4143
4800
  }
@@ -4148,7 +4805,7 @@ async function integrationRequestsCommand() {
4148
4805
  }
4149
4806
  async function integrationApproveCommand(requestId, options) {
4150
4807
  const json = isJsonMode();
4151
- const spinner = ora16({ text: "Approving request\u2026", isSilent: json }).start();
4808
+ const spinner = ora17({ text: "Approving request\u2026", isSilent: json }).start();
4152
4809
  try {
4153
4810
  const result = await api.put(`/integrations/bindings/scope-requests/${requestId}`, {
4154
4811
  status: "approved",
@@ -4167,7 +4824,7 @@ async function integrationApproveCommand(requestId, options) {
4167
4824
  }
4168
4825
  async function integrationDenyCommand(requestId, options) {
4169
4826
  const json = isJsonMode();
4170
- const spinner = ora16({ text: "Denying request\u2026", isSilent: json }).start();
4827
+ const spinner = ora17({ text: "Denying request\u2026", isSilent: json }).start();
4171
4828
  try {
4172
4829
  const result = await api.put(`/integrations/bindings/scope-requests/${requestId}`, {
4173
4830
  status: "denied",
@@ -4209,7 +4866,7 @@ async function integrationEnrolCommand(options) {
4209
4866
  const [secretKey, secretValue] = secrets[0];
4210
4867
  const credentials = { [secretKey]: secretValue };
4211
4868
  const authType = options.authType ?? (options.webhookSecret ? "webhook" : options.apiKey ? "api_key" : "oauth2");
4212
- const spinner = ora16({ text: `Enrolling ${options.def} at ${apiScope} scope\u2026`, isSilent: json }).start();
4869
+ const spinner = ora17({ text: `Enrolling ${options.def} at ${apiScope} scope\u2026`, isSilent: json }).start();
4213
4870
  try {
4214
4871
  let agentId;
4215
4872
  if (apiScope === "agent") {
@@ -4268,7 +4925,7 @@ function handleError(err) {
4268
4925
  }
4269
4926
 
4270
4927
  // src/bin/agt.ts
4271
- var cliVersion2 = true ? "0.26.2-eng5706.1" : "dev";
4928
+ var cliVersion2 = true ? "0.27.0-test.4" : "dev";
4272
4929
  var program = new Command();
4273
4930
  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");
4274
4931
  program.hook("preAction", (thisCommand) => {
@@ -4283,6 +4940,31 @@ var team = program.command("team").description("Manage teams");
4283
4940
  team.command("list").description("List teams you belong to").action(teamListCommand);
4284
4941
  team.command("create <name>").description("Create a new team and set it as active").action(teamCreateCommand);
4285
4942
  team.command("switch <slug>").description("Switch the active team").action(teamSwitchCommand);
4943
+ var impersonate = program.command("impersonate").description(
4944
+ "Operate as a managed agent locally (experimental, gated by AGT_IMPERSONATE_ENABLED)"
4945
+ );
4946
+ impersonate.command("connect <token>").description(
4947
+ "Redeem a XXXX-XXXX token from the webapp, render the agent's CLAUDE.md + .mcp.json, swap them into the current project, and launch Claude Code (use --no-launch to skip the launch)"
4948
+ ).option(
4949
+ "--no-launch",
4950
+ "Skip launching Claude Code after the swap (operator manages their own session)"
4951
+ ).option(
4952
+ "--workdir",
4953
+ "Swap into an auto-provisioned dedicated directory (~/.augmented-impersonate/<agent>/workdir) instead of the current directory \u2014 required when the current directory is inside a git repo"
4954
+ ).action(
4955
+ (token, opts) => (
4956
+ // Commander negates --no-FLAG into opts.flag, so --no-launch arrives
4957
+ // as opts.launch === false. Translate to the command's noLaunch
4958
+ // option, defaulting to launching when the flag isn't passed.
4959
+ impersonateConnectCommand(token, {
4960
+ noLaunch: opts.launch === false,
4961
+ workdir: opts.workdir === true
4962
+ })
4963
+ )
4964
+ );
4965
+ impersonate.command("current").description('Print the active impersonation (or "none")').action(impersonateCurrentCommand);
4966
+ impersonate.command("exit").description("End the active impersonation, restore project files, and notify the server").action(impersonateExitCommand);
4967
+ impersonate.command("introduce", { hidden: true }).description("Print the impersonated agent's self-introduction (SessionStart hook target)").action(impersonateIntroduceCommand);
4286
4968
  program.command("init").description("Create a new agent (interactive wizard, or non-interactive with --name)").option("--name <display-name>", "Agent display name (triggers non-interactive mode)").option("--code-name <code-name>", "Agent code name (kebab-case, derived from --name if omitted)").option("--description <text>", "Short agent description").option("--env <environment>", "Environment: dev | stage | prod", "dev").option("--risk-tier <tier>", "Risk tier: Low | Medium | High", "Low").option("--budget-type <type>", "Budget type: tokens | dollars | both", "tokens").option("--budget-tokens <number>", "Token budget limit", "10000").option("--budget-dollars <number>", "Dollar budget limit", "10").option("--budget-window <window>", "Budget window: daily | weekly | monthly", "daily").option("--budget-enforcement <mode>", "Budget enforcement: block | throttle | alert | degrade", "block").option("--channels <list>", "Comma-separated channel IDs").option("--logging <mode>", "Logging mode: redacted | hash-only | full-local", "redacted").action(initCommand);
4287
4969
  program.command("lint").argument("[path]", "Path to agent directory (default: all agents in .augmented/)").description("Lint CHARTER.md and TOOLS.md files").action(lintCommand);
4288
4970
  var channels = program.command("channels").description("Manage and inspect channel configuration");
@@ -4315,16 +4997,16 @@ host.command("pair <host-name>").description("Start an SSM port-forward + shell
4315
4997
  })
4316
4998
  );
4317
4999
  var manager = program.command("manager").description("Host config sync daemon \u2014 keeps local agent files in sync with API");
4318
- manager.command("start").description("Start the manager daemon (polls API for config changes and detects local drift)").option("--interval <seconds>", "Poll interval in seconds (min 5)", "10").option("--config-dir <dir>", "Config directory for agent files", join10(homedir3(), ".augmented")).option("--supervise", "Wrap the manager in a respawn-on-clean-exit loop so auto-upgrades can restart it transparently (ENG-4488)", false).action(managerStartCommand);
4319
- manager.command("stop").description("Stop the running manager daemon").option("--config-dir <dir>", "Config directory for agent files", join10(homedir3(), ".augmented")).action(managerStopCommand);
4320
- manager.command("status").description("Show the current manager daemon status and discovered agents").option("--config-dir <dir>", "Config directory for agent files", join10(homedir3(), ".augmented")).action(managerStatusCommand);
4321
- manager.command("watch").description("Live TUI dashboard \u2014 per-agent boxes, drill-in, log tail. Read-only (ENG-4555).").option("--config-dir <dir>", "Config directory for agent files", join10(homedir3(), ".augmented")).option("--no-tui", "Skip the TUI and stream the manager log to stdout instead (CI / scripts)").action(managerWatchCommand);
4322
- manager.command("install").description("Install OS-level supervisor (launchd LaunchAgent on macOS) so the manager auto-restarts after crash, reboot, or self-update (ENG-4593)").option("--interval <seconds>", "Poll interval in seconds (min 5)", "10").option("--config-dir <dir>", "Config directory for agent files", join10(homedir3(), ".augmented")).action(managerInstallCommand);
5000
+ manager.command("start").description("Start the manager daemon (polls API for config changes and detects local drift)").option("--interval <seconds>", "Poll interval in seconds (min 5)", "10").option("--config-dir <dir>", "Config directory for agent files", join14(homedir5(), ".augmented")).option("--supervise", "Wrap the manager in a respawn-on-clean-exit loop so auto-upgrades can restart it transparently (ENG-4488)", false).action(managerStartCommand);
5001
+ manager.command("stop").description("Stop the running manager daemon").option("--config-dir <dir>", "Config directory for agent files", join14(homedir5(), ".augmented")).action(managerStopCommand);
5002
+ manager.command("status").description("Show the current manager daemon status and discovered agents").option("--config-dir <dir>", "Config directory for agent files", join14(homedir5(), ".augmented")).action(managerStatusCommand);
5003
+ manager.command("watch").description("Live TUI dashboard \u2014 per-agent boxes, drill-in, log tail. Read-only (ENG-4555).").option("--config-dir <dir>", "Config directory for agent files", join14(homedir5(), ".augmented")).option("--no-tui", "Skip the TUI and stream the manager log to stdout instead (CI / scripts)").action(managerWatchCommand);
5004
+ manager.command("install").description("Install OS-level supervisor (launchd LaunchAgent on macOS) so the manager auto-restarts after crash, reboot, or self-update (ENG-4593)").option("--interval <seconds>", "Poll interval in seconds (min 5)", "10").option("--config-dir <dir>", "Config directory for agent files", join14(homedir5(), ".augmented")).action(managerInstallCommand);
4323
5005
  manager.command("uninstall").description("Remove the OS-level supervisor (launchctl unload + delete plist on macOS). Idempotent.").action(managerUninstallCommand);
4324
5006
  manager.command("install-system-unit").description("Install a system-level systemd unit (Linux, root) so the manager auto-starts on every boot. For headless EC2 hosts \u2014 survives reboot without `loginctl enable-linger`. (ENG-4706)").option("--interval <seconds>", "Poll interval in seconds (min 5)", "10").option("--config-dir <dir>", "Config directory for agent files (defaults to /root/.augmented or /home/<user>/.augmented)").option("--user <name>", "Unix user the manager runs as", "root").action(managerInstallSystemUnitCommand);
4325
5007
  manager.command("uninstall-system-unit").description("Remove the system-level systemd unit (Linux, root). Idempotent. (ENG-4706)").action(managerUninstallSystemUnitCommand);
4326
5008
  var agent = program.command("agent").description("Inspect and manage agents");
4327
- agent.command("show <code-name>").description("Display an agent's provisioned OpenClaw configuration").option("--config-dir <dir>", "Config directory", join10(homedir3(), ".augmented")).option("--all-channels", "Show all channels (including disabled)").action(agentShowCommand);
5009
+ agent.command("show <code-name>").description("Display an agent's provisioned OpenClaw configuration").option("--config-dir <dir>", "Config directory", join14(homedir5(), ".augmented")).option("--all-channels", "Show all channels (including disabled)").action(agentShowCommand);
4328
5010
  var kanban = program.command("kanban").description("Manage agent kanban boards");
4329
5011
  kanban.command("list").description("List kanban board items for an agent").requiredOption("--agent <code-name>", "Agent code name").action(kanbanListCommand);
4330
5012
  kanban.command("add <title>").description("Add a new item to an agent kanban board").requiredOption("--agent <code-name>", "Agent code name").option("--priority <1|2|3>", "Priority: 1=high, 2=medium, 3=low", "2").option("--status <status>", "Initial status: backlog | todo | in_progress", "todo").option("--description <text>", "Item description").option("--estimate <minutes>", "Estimated time in minutes").option("--deliverable <text>", "Expected output/deliverable").action(kanbanAddCommand);