@integrity-labs/agt-cli 0.27.0 → 0.27.1
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 +299 -82
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-BKLEFKUZ.js → chunk-CTWY2X4S.js} +32 -1
- package/dist/{chunk-BKLEFKUZ.js.map → chunk-CTWY2X4S.js.map} +1 -1
- package/dist/{chunk-YWXPSVI5.js → chunk-UVPB6TSJ.js} +2 -2
- package/dist/chunk-UVPB6TSJ.js.map +1 -0
- package/dist/{chunk-LJZK5RL3.js → chunk-WDCSMDQ4.js} +52 -8
- package/dist/chunk-WDCSMDQ4.js.map +1 -0
- package/dist/{claude-pair-runtime-3UQKYKMO.js → claude-pair-runtime-YRPKT45R.js} +2 -2
- package/dist/lib/manager-worker.js +33 -17
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/slack-channel.js +57 -3
- package/dist/{persistent-session-SE3E72ET.js → persistent-session-QJT7JE5P.js} +3 -3
- package/dist/{responsiveness-probe-MTMEIXEL.js → responsiveness-probe-ZERSZOZ2.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-LJZK5RL3.js.map +0 -1
- package/dist/chunk-YWXPSVI5.js.map +0 -1
- /package/dist/{claude-pair-runtime-3UQKYKMO.js.map → claude-pair-runtime-YRPKT45R.js.map} +0 -0
- /package/dist/{persistent-session-SE3E72ET.js.map → persistent-session-QJT7JE5P.js.map} +0 -0
- /package/dist/{responsiveness-probe-MTMEIXEL.js.map → responsiveness-probe-ZERSZOZ2.js.map} +0 -0
package/dist/bin/agt.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
success,
|
|
27
27
|
table,
|
|
28
28
|
warn
|
|
29
|
-
} from "../chunk-
|
|
29
|
+
} from "../chunk-UVPB6TSJ.js";
|
|
30
30
|
import {
|
|
31
31
|
CHANNEL_REGISTRY,
|
|
32
32
|
DEPLOYMENT_TEMPLATES,
|
|
@@ -52,10 +52,10 @@ import {
|
|
|
52
52
|
renderTemplate,
|
|
53
53
|
resolveChannels,
|
|
54
54
|
serializeManifestForSlackCli
|
|
55
|
-
} from "../chunk-
|
|
55
|
+
} from "../chunk-CTWY2X4S.js";
|
|
56
56
|
|
|
57
57
|
// src/bin/agt.ts
|
|
58
|
-
import { join as
|
|
58
|
+
import { join as join14 } from "path";
|
|
59
59
|
import { homedir as homedir5 } from "os";
|
|
60
60
|
import { Command } from "commander";
|
|
61
61
|
|
|
@@ -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 =
|
|
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()) {
|
|
@@ -1556,8 +1556,8 @@ async function provisionCommand(codeName, options) {
|
|
|
1556
1556
|
import chalk10 from "chalk";
|
|
1557
1557
|
import ora10 from "ora";
|
|
1558
1558
|
import { spawn } from "child_process";
|
|
1559
|
-
import { writeFileSync as
|
|
1560
|
-
import { join as
|
|
1559
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
1560
|
+
import { join as join9 } from "path";
|
|
1561
1561
|
|
|
1562
1562
|
// src/lib/impersonate-flag.ts
|
|
1563
1563
|
var ENV_VAR = "AGT_IMPERSONATE_ENABLED";
|
|
@@ -1621,6 +1621,11 @@ function ensureCodeNameDir(codeName) {
|
|
|
1621
1621
|
mkdirSync4(dir, { recursive: true });
|
|
1622
1622
|
return dir;
|
|
1623
1623
|
}
|
|
1624
|
+
function ensureImpersonateWorkdir(codeName) {
|
|
1625
|
+
const dir = join6(ensureCodeNameDir(codeName), "workdir");
|
|
1626
|
+
mkdirSync4(dir, { recursive: true });
|
|
1627
|
+
return dir;
|
|
1628
|
+
}
|
|
1624
1629
|
function readActiveManifest() {
|
|
1625
1630
|
if (!existsSync2(ACTIVE_MANIFEST_PATH)) return null;
|
|
1626
1631
|
try {
|
|
@@ -1668,8 +1673,19 @@ import {
|
|
|
1668
1673
|
unlinkSync
|
|
1669
1674
|
} from "fs";
|
|
1670
1675
|
import { homedir as homedir2 } from "os";
|
|
1671
|
-
import { sep } from "path";
|
|
1676
|
+
import { dirname, join as join7, parse, sep } from "path";
|
|
1672
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
|
+
}
|
|
1673
1689
|
function swapInPersonaFile(projectPath, personaPath) {
|
|
1674
1690
|
let kind;
|
|
1675
1691
|
if (!lstatSafe(projectPath)) {
|
|
@@ -1734,6 +1750,139 @@ function lstatSafe(path) {
|
|
|
1734
1750
|
}
|
|
1735
1751
|
}
|
|
1736
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
|
+
|
|
1737
1886
|
// src/commands/impersonate.ts
|
|
1738
1887
|
var SWAP_FILES = ["CLAUDE.md", ".mcp.json"];
|
|
1739
1888
|
var AGENT_IMPERSONATION_HEADER = "X-Agent-Impersonation";
|
|
@@ -1757,6 +1906,16 @@ async function impersonateConnectCommand(token, options = {}) {
|
|
|
1757
1906
|
process.exitCode = 1;
|
|
1758
1907
|
return;
|
|
1759
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
|
+
}
|
|
1760
1919
|
if (!json) console.log(chalk10.bold("\nAugmented \u2014 Impersonate\n"));
|
|
1761
1920
|
const spinner = ora10({
|
|
1762
1921
|
text: "Redeeming token\u2026",
|
|
@@ -1787,25 +1946,27 @@ async function impersonateConnectCommand(token, options = {}) {
|
|
|
1787
1946
|
}
|
|
1788
1947
|
spinner.text = "Writing persona files\u2026";
|
|
1789
1948
|
const personaDir = ensureCodeNameDir(bundle.agent.code_name);
|
|
1790
|
-
|
|
1791
|
-
|
|
1949
|
+
writeFileSync6(
|
|
1950
|
+
join9(personaDir, "CLAUDE.md"),
|
|
1792
1951
|
bundle.artifacts["CLAUDE.md"]
|
|
1793
1952
|
);
|
|
1794
|
-
|
|
1795
|
-
|
|
1953
|
+
writeFileSync6(
|
|
1954
|
+
join9(personaDir, ".mcp.json"),
|
|
1796
1955
|
bundle.artifacts[".mcp.json"]
|
|
1797
1956
|
);
|
|
1798
1957
|
spinner.text = "Swapping persona files\u2026";
|
|
1799
|
-
const projectCwd = process.cwd();
|
|
1958
|
+
const projectCwd = options.workdir ? ensureImpersonateWorkdir(bundle.agent.code_name) : process.cwd();
|
|
1800
1959
|
const backups = {};
|
|
1801
1960
|
const swapped = [];
|
|
1961
|
+
let hookBackup;
|
|
1802
1962
|
try {
|
|
1803
1963
|
for (const file of SWAP_FILES) {
|
|
1804
|
-
const projectPath =
|
|
1805
|
-
const kind = swapInPersonaFile(projectPath,
|
|
1964
|
+
const projectPath = join9(projectCwd, file);
|
|
1965
|
+
const kind = swapInPersonaFile(projectPath, join9(personaDir, file));
|
|
1806
1966
|
backups[file] = kind;
|
|
1807
1967
|
swapped.push({ file, kind });
|
|
1808
1968
|
}
|
|
1969
|
+
hookBackup = registerIntroduceHook(projectCwd);
|
|
1809
1970
|
const manifest = {
|
|
1810
1971
|
code_name: bundle.agent.code_name,
|
|
1811
1972
|
agent_id: bundle.agent.agent_id,
|
|
@@ -1816,13 +1977,20 @@ async function impersonateConnectCommand(token, options = {}) {
|
|
|
1816
1977
|
minted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1817
1978
|
project_cwd: projectCwd,
|
|
1818
1979
|
host: host2,
|
|
1819
|
-
backups
|
|
1980
|
+
backups,
|
|
1981
|
+
hook: hookBackup
|
|
1820
1982
|
};
|
|
1821
1983
|
writeActiveManifest(manifest);
|
|
1822
1984
|
} catch (err) {
|
|
1985
|
+
if (hookBackup) {
|
|
1986
|
+
try {
|
|
1987
|
+
unregisterIntroduceHook(hookBackup);
|
|
1988
|
+
} catch {
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1823
1991
|
for (const { file, kind } of [...swapped].reverse()) {
|
|
1824
1992
|
try {
|
|
1825
|
-
restoreSwapped(
|
|
1993
|
+
restoreSwapped(join9(projectCwd, file), kind);
|
|
1826
1994
|
} catch {
|
|
1827
1995
|
}
|
|
1828
1996
|
}
|
|
@@ -1856,6 +2024,9 @@ async function impersonateConnectCommand(token, options = {}) {
|
|
|
1856
2024
|
console.log(` Swapped: ${chalk10.dim(SWAP_FILES.join(", "))}`);
|
|
1857
2025
|
console.log();
|
|
1858
2026
|
if (!shouldLaunchClaude) {
|
|
2027
|
+
if (options.workdir) {
|
|
2028
|
+
info(`Start Claude Code in the impersonation workdir: \`cd ${projectCwd}\``);
|
|
2029
|
+
}
|
|
1859
2030
|
info(
|
|
1860
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)."
|
|
1861
2032
|
);
|
|
@@ -1968,7 +2139,7 @@ async function impersonateExitCommand() {
|
|
|
1968
2139
|
}
|
|
1969
2140
|
const restored = [];
|
|
1970
2141
|
for (const [file, kind] of Object.entries(manifest.backups)) {
|
|
1971
|
-
const projectPath =
|
|
2142
|
+
const projectPath = join9(manifest.project_cwd, file);
|
|
1972
2143
|
try {
|
|
1973
2144
|
restoreSwapped(projectPath, kind);
|
|
1974
2145
|
restored.push(file);
|
|
@@ -1977,6 +2148,14 @@ async function impersonateExitCommand() {
|
|
|
1977
2148
|
if (!json) error(`Failed to restore ${file}: ${msg}`);
|
|
1978
2149
|
}
|
|
1979
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
|
+
}
|
|
1980
2159
|
clearActiveManifest();
|
|
1981
2160
|
if (json) {
|
|
1982
2161
|
jsonOutput({
|
|
@@ -1998,6 +2177,37 @@ async function impersonateExitCommand() {
|
|
|
1998
2177
|
}
|
|
1999
2178
|
info("Restart Claude Code to pick up your original persona.");
|
|
2000
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
|
+
}
|
|
2001
2211
|
|
|
2002
2212
|
// src/commands/drift.ts
|
|
2003
2213
|
import chalk11 from "chalk";
|
|
@@ -2006,7 +2216,7 @@ import ora11 from "ora";
|
|
|
2006
2216
|
// ../../packages/core/dist/drift/live-state-reader.js
|
|
2007
2217
|
import { readFile } from "fs/promises";
|
|
2008
2218
|
import { createHash } from "crypto";
|
|
2009
|
-
import { join as
|
|
2219
|
+
import { join as join10 } from "path";
|
|
2010
2220
|
import JSON5 from "json5";
|
|
2011
2221
|
async function hashFile(filePath) {
|
|
2012
2222
|
try {
|
|
@@ -2030,8 +2240,8 @@ async function readLiveState(options) {
|
|
|
2030
2240
|
const toolsFile = trackedFiles.find((f) => f.includes("TOOLS")) ?? "TOOLS.md";
|
|
2031
2241
|
const [frameworkConfig, charterHash, toolsHash] = await Promise.all([
|
|
2032
2242
|
readJsonFile(options.configPath),
|
|
2033
|
-
hashFile(
|
|
2034
|
-
hashFile(
|
|
2243
|
+
hashFile(join10(options.teamDir, charterFile)),
|
|
2244
|
+
hashFile(join10(options.teamDir, toolsFile))
|
|
2035
2245
|
]);
|
|
2036
2246
|
return {
|
|
2037
2247
|
frameworkConfig,
|
|
@@ -2640,15 +2850,15 @@ function terminate(child) {
|
|
|
2640
2850
|
// src/commands/manager-watch.tsx
|
|
2641
2851
|
import { useEffect, useState, useMemo } from "react";
|
|
2642
2852
|
import { render, Box, Text, useApp, useInput } from "ink";
|
|
2643
|
-
import { existsSync as
|
|
2853
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, statSync, openSync, readSync, closeSync } from "fs";
|
|
2644
2854
|
import { homedir as homedir3 } from "os";
|
|
2645
|
-
import { join as
|
|
2855
|
+
import { join as join11 } from "path";
|
|
2646
2856
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2647
2857
|
var REFRESH_MS = 1e3;
|
|
2648
2858
|
var LOG_TAIL_LINES = 200;
|
|
2649
2859
|
var DETAIL_RECENT_LINES = 50;
|
|
2650
2860
|
function managerWatchCommand(opts = {}) {
|
|
2651
|
-
const configDir = opts.configDir ??
|
|
2861
|
+
const configDir = opts.configDir ?? join11(homedir3(), ".augmented");
|
|
2652
2862
|
const paths = getManagerPaths(configDir);
|
|
2653
2863
|
const isTty = process.stdout.isTTY === true && process.stdin.isTTY === true;
|
|
2654
2864
|
if (opts.noTui || !isTty) {
|
|
@@ -2672,15 +2882,15 @@ function managerWatchCommand(opts = {}) {
|
|
|
2672
2882
|
}
|
|
2673
2883
|
function readState(stateFile) {
|
|
2674
2884
|
try {
|
|
2675
|
-
if (!
|
|
2676
|
-
const raw =
|
|
2885
|
+
if (!existsSync5(stateFile)) return null;
|
|
2886
|
+
const raw = readFileSync5(stateFile, "utf-8");
|
|
2677
2887
|
return JSON.parse(raw);
|
|
2678
2888
|
} catch {
|
|
2679
2889
|
return null;
|
|
2680
2890
|
}
|
|
2681
2891
|
}
|
|
2682
2892
|
function tailLogFile(logFile, lines) {
|
|
2683
|
-
if (!
|
|
2893
|
+
if (!existsSync5(logFile)) return [];
|
|
2684
2894
|
try {
|
|
2685
2895
|
const fileSize = statSync(logFile).size;
|
|
2686
2896
|
if (fileSize === 0) return [];
|
|
@@ -2921,7 +3131,7 @@ function truncate(s, max) {
|
|
|
2921
3131
|
return s.length > max ? `${s.slice(0, Math.max(0, max - 1))}\u2026` : s;
|
|
2922
3132
|
}
|
|
2923
3133
|
function streamLogFile(logFile) {
|
|
2924
|
-
if (!
|
|
3134
|
+
if (!existsSync5(logFile)) {
|
|
2925
3135
|
process.stderr.write(`No manager log found at ${logFile}.
|
|
2926
3136
|
Start the manager first: agt manager start
|
|
2927
3137
|
`);
|
|
@@ -2930,7 +3140,7 @@ Start the manager first: agt manager start
|
|
|
2930
3140
|
}
|
|
2931
3141
|
let lastSize = 0;
|
|
2932
3142
|
try {
|
|
2933
|
-
const initial =
|
|
3143
|
+
const initial = readFileSync5(logFile, "utf-8");
|
|
2934
3144
|
process.stdout.write(initial);
|
|
2935
3145
|
lastSize = statSync(logFile).size;
|
|
2936
3146
|
} catch (err) {
|
|
@@ -2967,14 +3177,14 @@ Start the manager first: agt manager start
|
|
|
2967
3177
|
// src/commands/agent.ts
|
|
2968
3178
|
import chalk14 from "chalk";
|
|
2969
3179
|
import JSON52 from "json5";
|
|
2970
|
-
import { readFileSync as
|
|
2971
|
-
import { join as
|
|
3180
|
+
import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
|
|
3181
|
+
import { join as join12 } from "path";
|
|
2972
3182
|
async function agentShowCommand(codeName, opts) {
|
|
2973
3183
|
const json = isJsonMode();
|
|
2974
|
-
const unifiedDir =
|
|
2975
|
-
const legacyDir =
|
|
2976
|
-
const agentDir =
|
|
2977
|
-
const hasLocalConfig =
|
|
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);
|
|
2978
3188
|
let apiChannels = null;
|
|
2979
3189
|
let apiAgent = null;
|
|
2980
3190
|
if (getApiKey()) {
|
|
@@ -3007,34 +3217,34 @@ async function agentShowCommand(codeName, opts) {
|
|
|
3007
3217
|
let openclawConfig = null;
|
|
3008
3218
|
let agentState = null;
|
|
3009
3219
|
if (hasLocalConfig) {
|
|
3010
|
-
const charterPath =
|
|
3011
|
-
if (
|
|
3012
|
-
const raw =
|
|
3220
|
+
const charterPath = join12(agentDir, "CHARTER.md");
|
|
3221
|
+
if (existsSync6(charterPath)) {
|
|
3222
|
+
const raw = readFileSync6(charterPath, "utf-8");
|
|
3013
3223
|
const parsed = extractFrontmatter(raw);
|
|
3014
3224
|
if (parsed.frontmatter) {
|
|
3015
3225
|
charter = parsed.frontmatter;
|
|
3016
3226
|
}
|
|
3017
3227
|
}
|
|
3018
|
-
const toolsPath =
|
|
3019
|
-
if (
|
|
3020
|
-
const raw =
|
|
3228
|
+
const toolsPath = join12(agentDir, "TOOLS.md");
|
|
3229
|
+
if (existsSync6(toolsPath)) {
|
|
3230
|
+
const raw = readFileSync6(toolsPath, "utf-8");
|
|
3021
3231
|
const parsed = extractFrontmatter(raw);
|
|
3022
3232
|
if (parsed.frontmatter) {
|
|
3023
3233
|
tools = parsed.frontmatter;
|
|
3024
3234
|
}
|
|
3025
3235
|
}
|
|
3026
|
-
const openclawPath =
|
|
3027
|
-
if (
|
|
3236
|
+
const openclawPath = join12(agentDir, "openclaw.json5");
|
|
3237
|
+
if (existsSync6(openclawPath)) {
|
|
3028
3238
|
try {
|
|
3029
|
-
const raw =
|
|
3239
|
+
const raw = readFileSync6(openclawPath, "utf-8");
|
|
3030
3240
|
openclawConfig = JSON52.parse(raw);
|
|
3031
3241
|
} catch {
|
|
3032
3242
|
}
|
|
3033
3243
|
}
|
|
3034
|
-
const statePath =
|
|
3035
|
-
if (
|
|
3244
|
+
const statePath = join12(opts.configDir, "manager-state.json");
|
|
3245
|
+
if (existsSync6(statePath)) {
|
|
3036
3246
|
try {
|
|
3037
|
-
const raw =
|
|
3247
|
+
const raw = readFileSync6(statePath, "utf-8");
|
|
3038
3248
|
const state = JSON.parse(raw);
|
|
3039
3249
|
agentState = state.agents?.find((a) => a.codeName === codeName) ?? null;
|
|
3040
3250
|
} catch {
|
|
@@ -3371,8 +3581,8 @@ async function kanbanRecurringDisableCommand(titleOrId, opts) {
|
|
|
3371
3581
|
}
|
|
3372
3582
|
|
|
3373
3583
|
// src/commands/setup.ts
|
|
3374
|
-
import { existsSync as
|
|
3375
|
-
import { join as
|
|
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";
|
|
3376
3586
|
import { homedir as homedir4 } from "os";
|
|
3377
3587
|
import chalk16 from "chalk";
|
|
3378
3588
|
import ora14 from "ora";
|
|
@@ -3380,15 +3590,15 @@ function detectShellProfile() {
|
|
|
3380
3590
|
const shell = process.env["SHELL"] ?? "";
|
|
3381
3591
|
const home = homedir4();
|
|
3382
3592
|
if (shell.includes("zsh")) {
|
|
3383
|
-
return
|
|
3593
|
+
return join13(home, ".zshrc");
|
|
3384
3594
|
}
|
|
3385
3595
|
if (shell.includes("fish")) {
|
|
3386
|
-
const fishConfig =
|
|
3596
|
+
const fishConfig = join13(home, ".config", "fish", "config.fish");
|
|
3387
3597
|
return fishConfig;
|
|
3388
3598
|
}
|
|
3389
|
-
const bashrc =
|
|
3390
|
-
if (
|
|
3391
|
-
return
|
|
3599
|
+
const bashrc = join13(home, ".bashrc");
|
|
3600
|
+
if (existsSync7(bashrc)) return bashrc;
|
|
3601
|
+
return join13(home, ".bash_profile");
|
|
3392
3602
|
}
|
|
3393
3603
|
function maybeWriteSystemWideEnv(apiUrl, apiKey, consoleUrl) {
|
|
3394
3604
|
const empty = { etcEnvironment: false, profileD: false, bashrc: false };
|
|
@@ -3414,14 +3624,14 @@ function quoteForFishShell(value) {
|
|
|
3414
3624
|
}
|
|
3415
3625
|
function writeEtcEnvironment(apiUrl, apiKey, consoleUrl) {
|
|
3416
3626
|
const envPath = "/etc/environment";
|
|
3417
|
-
if (!
|
|
3627
|
+
if (!existsSync7(envPath)) return false;
|
|
3418
3628
|
try {
|
|
3419
3629
|
accessSync(envPath, fsConstants.W_OK);
|
|
3420
3630
|
} catch {
|
|
3421
3631
|
return false;
|
|
3422
3632
|
}
|
|
3423
3633
|
try {
|
|
3424
|
-
const current =
|
|
3634
|
+
const current = readFileSync7(envPath, "utf-8");
|
|
3425
3635
|
const stripped = current.split(/\r?\n/).filter((line) => !/^\s*(?:export\s+)?AGT_(?:HOST|API_KEY|CONSOLE_URL)=/.test(line)).join("\n");
|
|
3426
3636
|
const base = stripped.endsWith("\n") || stripped.length === 0 ? stripped : `${stripped}
|
|
3427
3637
|
`;
|
|
@@ -3432,7 +3642,7 @@ function writeEtcEnvironment(apiUrl, apiKey, consoleUrl) {
|
|
|
3432
3642
|
if (consoleUrl) lines.push(`AGT_CONSOLE_URL=${quoteForEtcEnvironment(consoleUrl)}`);
|
|
3433
3643
|
const appended = `${base}${lines.join("\n")}
|
|
3434
3644
|
`;
|
|
3435
|
-
|
|
3645
|
+
writeFileSync7(envPath, appended, { mode: 420 });
|
|
3436
3646
|
return true;
|
|
3437
3647
|
} catch {
|
|
3438
3648
|
return false;
|
|
@@ -3440,7 +3650,7 @@ function writeEtcEnvironment(apiUrl, apiKey, consoleUrl) {
|
|
|
3440
3650
|
}
|
|
3441
3651
|
function writeProfileDScript(apiUrl, apiKey, consoleUrl) {
|
|
3442
3652
|
const profileD = "/etc/profile.d";
|
|
3443
|
-
if (!
|
|
3653
|
+
if (!existsSync7(profileD)) return false;
|
|
3444
3654
|
try {
|
|
3445
3655
|
accessSync(profileD, fsConstants.W_OK);
|
|
3446
3656
|
} catch {
|
|
@@ -3455,7 +3665,7 @@ function writeProfileDScript(apiUrl, apiKey, consoleUrl) {
|
|
|
3455
3665
|
];
|
|
3456
3666
|
if (consoleUrl) lines.push(`export AGT_CONSOLE_URL=${quoteForPosixShell(consoleUrl)}`);
|
|
3457
3667
|
lines.push("");
|
|
3458
|
-
|
|
3668
|
+
writeFileSync7(scriptPath, lines.join("\n"), { mode: 420 });
|
|
3459
3669
|
return true;
|
|
3460
3670
|
} catch {
|
|
3461
3671
|
return false;
|
|
@@ -3463,14 +3673,14 @@ function writeProfileDScript(apiUrl, apiKey, consoleUrl) {
|
|
|
3463
3673
|
}
|
|
3464
3674
|
function ensureBashrcSourcesProfileD() {
|
|
3465
3675
|
const bashrc = "/etc/bashrc";
|
|
3466
|
-
if (!
|
|
3676
|
+
if (!existsSync7(bashrc)) return false;
|
|
3467
3677
|
try {
|
|
3468
3678
|
accessSync(bashrc, fsConstants.W_OK);
|
|
3469
3679
|
} catch {
|
|
3470
3680
|
return false;
|
|
3471
3681
|
}
|
|
3472
3682
|
try {
|
|
3473
|
-
const current =
|
|
3683
|
+
const current = readFileSync7(bashrc, "utf-8");
|
|
3474
3684
|
const marker = "# Augmented (agt) \u2014 source system-wide AGT env";
|
|
3475
3685
|
if (current.includes(marker)) return true;
|
|
3476
3686
|
const snippet = [
|
|
@@ -3481,7 +3691,7 @@ function ensureBashrcSourcesProfileD() {
|
|
|
3481
3691
|
"fi",
|
|
3482
3692
|
""
|
|
3483
3693
|
].join("\n");
|
|
3484
|
-
|
|
3694
|
+
writeFileSync7(bashrc, current + snippet);
|
|
3485
3695
|
return true;
|
|
3486
3696
|
} catch {
|
|
3487
3697
|
return false;
|
|
@@ -3596,12 +3806,12 @@ async function setupCommand(token) {
|
|
|
3596
3806
|
);
|
|
3597
3807
|
}
|
|
3598
3808
|
const exportLines = buildExportLines(shell, finalApiUrl, setupResult.api_key, consoleUrl);
|
|
3599
|
-
const profileDir =
|
|
3600
|
-
if (!
|
|
3601
|
-
|
|
3809
|
+
const profileDir = dirname2(profilePath);
|
|
3810
|
+
if (!existsSync7(profileDir)) {
|
|
3811
|
+
mkdirSync6(profileDir, { recursive: true });
|
|
3602
3812
|
}
|
|
3603
3813
|
const marker = "# Augmented (agt) host configuration";
|
|
3604
|
-
const current =
|
|
3814
|
+
const current = existsSync7(profilePath) ? readFileSync7(profilePath, "utf-8") : "";
|
|
3605
3815
|
let updated;
|
|
3606
3816
|
if (current.includes(marker)) {
|
|
3607
3817
|
updated = current.replace(
|
|
@@ -3614,7 +3824,7 @@ async function setupCommand(token) {
|
|
|
3614
3824
|
} else {
|
|
3615
3825
|
updated = current + exportLines;
|
|
3616
3826
|
}
|
|
3617
|
-
|
|
3827
|
+
writeFileSync7(profilePath, updated.endsWith("\n") ? updated : `${updated}
|
|
3618
3828
|
`);
|
|
3619
3829
|
if (!json) {
|
|
3620
3830
|
success(`Environment variables written to ${chalk16.bold(profilePath)}`);
|
|
@@ -3632,7 +3842,7 @@ async function setupCommand(token) {
|
|
|
3632
3842
|
const managerSpinner = ora14({ text: "Starting manager daemon\u2026", isSilent: json });
|
|
3633
3843
|
managerSpinner.start();
|
|
3634
3844
|
try {
|
|
3635
|
-
const configDir =
|
|
3845
|
+
const configDir = join13(homedir4(), ".augmented");
|
|
3636
3846
|
const { pid } = startWatchdog({ intervalMs: 1e4, configDir, detached: true });
|
|
3637
3847
|
managerSpinner.succeed(`Manager started (PID ${pid})`);
|
|
3638
3848
|
} catch (err) {
|
|
@@ -4180,10 +4390,10 @@ async function acpxCloseCommand(agent2, _opts, cmd) {
|
|
|
4180
4390
|
|
|
4181
4391
|
// src/commands/update.ts
|
|
4182
4392
|
import { execFileSync, execSync } from "child_process";
|
|
4183
|
-
import { existsSync as
|
|
4393
|
+
import { existsSync as existsSync8, realpathSync as realpathSync2 } from "fs";
|
|
4184
4394
|
import chalk18 from "chalk";
|
|
4185
4395
|
import ora16 from "ora";
|
|
4186
|
-
var cliVersion = true ? "0.27.
|
|
4396
|
+
var cliVersion = true ? "0.27.1" : "dev";
|
|
4187
4397
|
async function fetchLatestVersion() {
|
|
4188
4398
|
const host2 = getHost();
|
|
4189
4399
|
if (!host2) return null;
|
|
@@ -4203,9 +4413,9 @@ async function fetchLatestVersion() {
|
|
|
4203
4413
|
}
|
|
4204
4414
|
function isNewerVersion(local, remote) {
|
|
4205
4415
|
if (local === "dev") return false;
|
|
4206
|
-
const
|
|
4207
|
-
const lParts =
|
|
4208
|
-
const rParts =
|
|
4416
|
+
const parse2 = (v) => v.replace(/^v/, "").split(".").map(Number);
|
|
4417
|
+
const lParts = parse2(local);
|
|
4418
|
+
const rParts = parse2(remote);
|
|
4209
4419
|
const lMaj = lParts[0] ?? 0, lMin = lParts[1] ?? 0, lPat = lParts[2] ?? 0;
|
|
4210
4420
|
const rMaj = rParts[0] ?? 0, rMin = rParts[1] ?? 0, rPat = rParts[2] ?? 0;
|
|
4211
4421
|
if (rMaj !== lMaj) return rMaj > lMaj;
|
|
@@ -4287,7 +4497,7 @@ function performUpdate(version) {
|
|
|
4287
4497
|
function detectBrewOwner() {
|
|
4288
4498
|
for (const prefix of ["/home/linuxbrew/.linuxbrew", "/opt/homebrew", "/usr/local"]) {
|
|
4289
4499
|
const cellar = `${prefix}/Cellar`;
|
|
4290
|
-
if (!
|
|
4500
|
+
if (!existsSync8(cellar)) continue;
|
|
4291
4501
|
try {
|
|
4292
4502
|
return execSync(`stat -c %U "${cellar}" 2>/dev/null || stat -f %Su "${cellar}"`, { encoding: "utf-8" }).trim() || null;
|
|
4293
4503
|
} catch {
|
|
@@ -4715,7 +4925,7 @@ function handleError(err) {
|
|
|
4715
4925
|
}
|
|
4716
4926
|
|
|
4717
4927
|
// src/bin/agt.ts
|
|
4718
|
-
var cliVersion2 = true ? "0.27.
|
|
4928
|
+
var cliVersion2 = true ? "0.27.1" : "dev";
|
|
4719
4929
|
var program = new Command();
|
|
4720
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");
|
|
4721
4931
|
program.hook("preAction", (thisCommand) => {
|
|
@@ -4738,16 +4948,23 @@ impersonate.command("connect <token>").description(
|
|
|
4738
4948
|
).option(
|
|
4739
4949
|
"--no-launch",
|
|
4740
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"
|
|
4741
4954
|
).action(
|
|
4742
4955
|
(token, opts) => (
|
|
4743
4956
|
// Commander negates --no-FLAG into opts.flag, so --no-launch arrives
|
|
4744
4957
|
// as opts.launch === false. Translate to the command's noLaunch
|
|
4745
4958
|
// option, defaulting to launching when the flag isn't passed.
|
|
4746
|
-
impersonateConnectCommand(token, {
|
|
4959
|
+
impersonateConnectCommand(token, {
|
|
4960
|
+
noLaunch: opts.launch === false,
|
|
4961
|
+
workdir: opts.workdir === true
|
|
4962
|
+
})
|
|
4747
4963
|
)
|
|
4748
4964
|
);
|
|
4749
4965
|
impersonate.command("current").description('Print the active impersonation (or "none")').action(impersonateCurrentCommand);
|
|
4750
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);
|
|
4751
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);
|
|
4752
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);
|
|
4753
4970
|
var channels = program.command("channels").description("Manage and inspect channel configuration");
|
|
@@ -4780,16 +4997,16 @@ host.command("pair <host-name>").description("Start an SSM port-forward + shell
|
|
|
4780
4997
|
})
|
|
4781
4998
|
);
|
|
4782
4999
|
var manager = program.command("manager").description("Host config sync daemon \u2014 keeps local agent files in sync with API");
|
|
4783
|
-
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",
|
|
4784
|
-
manager.command("stop").description("Stop the running manager daemon").option("--config-dir <dir>", "Config directory for agent files",
|
|
4785
|
-
manager.command("status").description("Show the current manager daemon status and discovered agents").option("--config-dir <dir>", "Config directory for agent files",
|
|
4786
|
-
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",
|
|
4787
|
-
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",
|
|
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);
|
|
4788
5005
|
manager.command("uninstall").description("Remove the OS-level supervisor (launchctl unload + delete plist on macOS). Idempotent.").action(managerUninstallCommand);
|
|
4789
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);
|
|
4790
5007
|
manager.command("uninstall-system-unit").description("Remove the system-level systemd unit (Linux, root). Idempotent. (ENG-4706)").action(managerUninstallSystemUnitCommand);
|
|
4791
5008
|
var agent = program.command("agent").description("Inspect and manage agents");
|
|
4792
|
-
agent.command("show <code-name>").description("Display an agent's provisioned OpenClaw configuration").option("--config-dir <dir>", "Config directory",
|
|
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);
|
|
4793
5010
|
var kanban = program.command("kanban").description("Manage agent kanban boards");
|
|
4794
5011
|
kanban.command("list").description("List kanban board items for an agent").requiredOption("--agent <code-name>", "Agent code name").action(kanbanListCommand);
|
|
4795
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);
|