@termhub/agent 0.4.2 → 0.4.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/cli.js +171 -23
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -76,11 +76,18 @@ var RPC = {
|
|
|
76
76
|
"file.paste": def(z.object({ name: pasteName, data_b64: z.string().min(1).max(28 * 1024 * 1024) }), z.object({ path: z.string() }), 6e4),
|
|
77
77
|
/** Monitor hooks (see @termhub/machine-ops hooks.ts): the agent writes the script, env and config entries under its own $HOME. */
|
|
78
78
|
/** `claude_dirs`: Claude config dirs besides ~/.claude (accounts with CLAUDE_CONFIG_DIR), hooked when they exist; since agent 0.1.5. */
|
|
79
|
+
/** `cursor` in the result: ~/.cursor/hooks.json (Cursor CLI), written when ~/.cursor exists; since agent 0.4.3 (older agents leave it out). */
|
|
79
80
|
"hooks.install": def(z.object({
|
|
80
81
|
hooks_url: z.string().min(1).max(2048).regex(/^https?:\/\/[^\s'"]+$/),
|
|
81
82
|
token: z.string().min(1).max(256).regex(/^[A-Za-z0-9_-]+$/),
|
|
82
83
|
claude_dirs: z.array(machinePath).max(16).optional()
|
|
83
|
-
}), z.object({
|
|
84
|
+
}), z.object({
|
|
85
|
+
home: z.string(),
|
|
86
|
+
claude: z.enum(["installed", "skipped"]),
|
|
87
|
+
codex: z.enum(["installed", "skipped"]),
|
|
88
|
+
cursor: z.enum(["installed", "skipped"]).optional(),
|
|
89
|
+
claude_dirs: z.array(z.string()).optional()
|
|
90
|
+
}), 15e3),
|
|
84
91
|
"hooks.uninstall": def(z.object({ claude_dirs: z.array(machinePath).max(16).optional() }), z.object({ removed: z.boolean() }), 15e3),
|
|
85
92
|
/** Installs `version` of @termhub/agent with npm; when the agent runs as a service it then exits so the service relaunches the new code (since agent 0.2.1). */
|
|
86
93
|
"agent.update": def(z.object({ version: z.string().regex(/^\d+\.\d+\.\d+$/) }), z.object({ installed_version: z.string(), restart: z.enum(["service", "manual"]) }), 18e4)
|
|
@@ -95,6 +102,7 @@ var channel = z2.number().int().min(1).max(4294967295);
|
|
|
95
102
|
var rpcId = z2.string().min(1).max(64);
|
|
96
103
|
var closedReason = z2.enum(["cli_missing", "run_failed", "killed", "missing_session", "cli_rejected"]);
|
|
97
104
|
var CAPABILITY_CLAUDE = "claude";
|
|
105
|
+
var CAPABILITY_CLAUDE_SYSTEM_PROMPT = "claude.system_prompt";
|
|
98
106
|
var helloMessage = z2.object({
|
|
99
107
|
type: z2.literal("hello"),
|
|
100
108
|
protocol: z2.number().int().min(1),
|
|
@@ -137,7 +145,10 @@ var claudeOpenParams = z2.object({
|
|
|
137
145
|
// opening a channel to the user's own machine is exactly the trust boundary this grant
|
|
138
146
|
// belongs at, so there is no separate, later place to hand it over.
|
|
139
147
|
token: z2.string(),
|
|
140
|
-
model: z2.string().nullable().optional()
|
|
148
|
+
model: z2.string().nullable().optional(),
|
|
149
|
+
// Project chats only: the server-composed focus text forwarded onto the CLI's argv (see
|
|
150
|
+
// `CAPABILITY_CLAUDE_SYSTEM_PROMPT`). Absent for the account-wide chat, whose argv must not change.
|
|
151
|
+
append_system_prompt: z2.string().max(4e3).nullable().optional()
|
|
141
152
|
});
|
|
142
153
|
var openPty = z2.object({ type: z2.literal("open"), ch: channel, kind: z2.literal("pty"), params: ptyOpenParams });
|
|
143
154
|
var openClaude = z2.object({ type: z2.literal("open"), ch: channel, kind: z2.literal("claude"), params: claudeOpenParams });
|
|
@@ -420,7 +431,7 @@ function shellQuote(s) {
|
|
|
420
431
|
var REMOTE_PATH_PREFIX = 'export PATH="$HOME/.local/bin:/opt/homebrew/bin:/usr/local/bin:$PATH"; ';
|
|
421
432
|
|
|
422
433
|
// ../../packages/machine-ops/dist/detect.js
|
|
423
|
-
var DETECT_TOOLS = ["tmux", "claude", "codex", "gh", "git", "node", "pnpm", "xcodebuild", "docker", "adb", "python3"];
|
|
434
|
+
var DETECT_TOOLS = ["tmux", "claude", "codex", "cursor-agent", "gh", "git", "node", "pnpm", "xcodebuild", "docker", "adb", "python3"];
|
|
424
435
|
var WDA_RUNNER_APP = "$HOME/.termhub/WebDriverAgent/DerivedData/Build/Products/Debug-iphonesimulator/WebDriverAgentRunner-Runner.app";
|
|
425
436
|
var DETECT_SCRIPT = `echo OS:$(uname -s); for t in ${DETECT_TOOLS.join(" ")}; do command -v $t >/dev/null 2>&1 && echo CAP:$t; done; [ -d "${WDA_RUNNER_APP}" ] && echo CAP:wda; exit 0`;
|
|
426
437
|
function parseDetect(stdout) {
|
|
@@ -612,10 +623,12 @@ function expandHome(dir, home) {
|
|
|
612
623
|
return dir.startsWith("~/") ? `${home}/${dir.slice(2)}` : dir;
|
|
613
624
|
}
|
|
614
625
|
var CLAUDE_HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "Notification", "Stop", "SessionEnd"];
|
|
626
|
+
var CURSOR_HOOK_EVENTS = ["sessionStart", "beforeSubmitPrompt", "afterAgentResponse", "stop", "sessionEnd"];
|
|
615
627
|
var HOOK_SCRIPT = `#!/bin/sh
|
|
616
|
-
# termhub monitor hook \u2014 installed by termhub; forwards Claude Code / Codex
|
|
617
|
-
# termhub tagged with the tmux session, so the app knows which tab is waiting for you.
|
|
618
|
-
# Safe to delete (also remove the entries in ~/.claude/settings.json
|
|
628
|
+
# termhub monitor hook \u2014 installed by termhub; forwards Claude Code / Codex / Cursor CLI hook
|
|
629
|
+
# events to termhub tagged with the tmux session, so the app knows which tab is waiting for you.
|
|
630
|
+
# Safe to delete (also remove the entries in ~/.claude/settings.json, ~/.codex/config.toml and
|
|
631
|
+
# ~/.cursor/hooks.json).
|
|
619
632
|
TOOL="\${1:-claude}"
|
|
620
633
|
[ -f "$HOME/${HOOK_ENV_REL}" ] || exit 0
|
|
621
634
|
. "$HOME/${HOOK_ENV_REL}"
|
|
@@ -686,26 +699,35 @@ function hookEnvFile(hooksUrl, token) {
|
|
|
686
699
|
TERMHUB_HOOK_TOKEN=${shellQuote(token)}
|
|
687
700
|
`;
|
|
688
701
|
}
|
|
702
|
+
var asObject = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
703
|
+
var asHooksRecord = (v) => {
|
|
704
|
+
if (v == null || Array.isArray(v) && v.length === 0)
|
|
705
|
+
return {};
|
|
706
|
+
return asObject(v);
|
|
707
|
+
};
|
|
689
708
|
var isOurs = (e) => !!e && typeof e === "object" && Array.isArray(e.hooks) && e.hooks.some((h) => typeof h?.command === "string" && h.command.includes(HOOK_MARK));
|
|
690
|
-
function mergeClaudeSettings(current, scriptPath) {
|
|
709
|
+
function mergeClaudeSettings(current, scriptPath, shown = "~/.claude/settings.json") {
|
|
691
710
|
let settings = {};
|
|
692
711
|
if (current.trim()) {
|
|
693
712
|
const parsed = JSON.parse(current);
|
|
694
713
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
695
|
-
throw new Error(
|
|
714
|
+
throw new Error(`${shown} n\xE3o \xE9 um objeto JSON`);
|
|
696
715
|
settings = parsed;
|
|
697
716
|
}
|
|
698
|
-
const hooks =
|
|
717
|
+
const hooks = asHooksRecord(settings.hooks);
|
|
718
|
+
if (settings.hooks != null && hooks === null)
|
|
719
|
+
throw new Error(`${shown}: o campo "hooks" n\xE3o \xE9 um objeto`);
|
|
720
|
+
const next = hooks ?? {};
|
|
699
721
|
for (const event of CLAUDE_HOOK_EVENTS) {
|
|
700
|
-
const list3 = Array.isArray(
|
|
722
|
+
const list3 = Array.isArray(next[event]) ? next[event] : [];
|
|
701
723
|
const others = list3.filter((e) => !isOurs(e));
|
|
702
724
|
const entry = { hooks: [{ type: "command", command: `${scriptPath} claude`, timeout: 10 }] };
|
|
703
725
|
if (event === "PreToolUse")
|
|
704
726
|
entry.matcher = "*";
|
|
705
727
|
others.push(entry);
|
|
706
|
-
|
|
728
|
+
next[event] = others;
|
|
707
729
|
}
|
|
708
|
-
settings.hooks =
|
|
730
|
+
settings.hooks = next;
|
|
709
731
|
return `${JSON.stringify(settings, null, 2)}
|
|
710
732
|
`;
|
|
711
733
|
}
|
|
@@ -750,6 +772,50 @@ function stripCodexConfig(current) {
|
|
|
750
772
|
const lines = current.split("\n").filter((l) => !(/^\s*notify\s*=/.test(l) && l.includes(HOOK_MARK)));
|
|
751
773
|
return lines.join("\n");
|
|
752
774
|
}
|
|
775
|
+
var isOurCursorEntry = (e) => !!e && typeof e === "object" && typeof e.command === "string" && e.command.includes(HOOK_MARK);
|
|
776
|
+
function mergeCursorHooks(current, scriptPath, shown = "~/.cursor/hooks.json") {
|
|
777
|
+
let file = {};
|
|
778
|
+
if (current.trim()) {
|
|
779
|
+
const parsed = asObject(JSON.parse(current));
|
|
780
|
+
if (!parsed)
|
|
781
|
+
throw new Error(`${shown} n\xE3o \xE9 um objeto JSON`);
|
|
782
|
+
file = parsed;
|
|
783
|
+
}
|
|
784
|
+
const hooks = asHooksRecord(file.hooks);
|
|
785
|
+
if (file.hooks != null && hooks === null)
|
|
786
|
+
throw new Error(`${shown}: o campo "hooks" n\xE3o \xE9 um objeto`);
|
|
787
|
+
const next = hooks ?? {};
|
|
788
|
+
for (const event of CURSOR_HOOK_EVENTS) {
|
|
789
|
+
const others = (Array.isArray(next[event]) ? next[event] : []).filter((e) => !isOurCursorEntry(e));
|
|
790
|
+
others.push({ command: `${scriptPath} cursor` });
|
|
791
|
+
next[event] = others;
|
|
792
|
+
}
|
|
793
|
+
return `${JSON.stringify({ ...file, version: typeof file.version === "number" ? file.version : 1, hooks: next }, null, 2)}
|
|
794
|
+
`;
|
|
795
|
+
}
|
|
796
|
+
function stripCursorHooks(current) {
|
|
797
|
+
if (!current.trim())
|
|
798
|
+
return current;
|
|
799
|
+
const file = asObject(JSON.parse(current));
|
|
800
|
+
if (!file)
|
|
801
|
+
return current;
|
|
802
|
+
const hooks = asObject(file.hooks);
|
|
803
|
+
if (hooks) {
|
|
804
|
+
for (const key of Object.keys(hooks)) {
|
|
805
|
+
if (!Array.isArray(hooks[key]))
|
|
806
|
+
continue;
|
|
807
|
+
const kept = hooks[key].filter((e) => !isOurCursorEntry(e));
|
|
808
|
+
if (kept.length)
|
|
809
|
+
hooks[key] = kept;
|
|
810
|
+
else
|
|
811
|
+
delete hooks[key];
|
|
812
|
+
}
|
|
813
|
+
if (Object.keys(hooks).length === 0)
|
|
814
|
+
delete file.hooks;
|
|
815
|
+
}
|
|
816
|
+
return `${JSON.stringify(file, null, 2)}
|
|
817
|
+
`;
|
|
818
|
+
}
|
|
753
819
|
|
|
754
820
|
// ../../packages/machine-ops/dist/discover.js
|
|
755
821
|
var CLAUDE_MARKERS = ["settings.json", "projects", ".credentials.json"];
|
|
@@ -897,6 +963,8 @@ function sh(script, opts = {}) {
|
|
|
897
963
|
// src/rpc/hooks.ts
|
|
898
964
|
var CODEX_DIR_REL = ".codex";
|
|
899
965
|
var CODEX_CONFIG_REL = ".codex/config.toml";
|
|
966
|
+
var CURSOR_DIR_REL = ".cursor";
|
|
967
|
+
var CURSOR_HOOKS_REL = ".cursor/hooks.json";
|
|
900
968
|
var isEnoent = (err) => err?.code === "ENOENT";
|
|
901
969
|
async function readOrEmpty2(file) {
|
|
902
970
|
try {
|
|
@@ -934,6 +1002,15 @@ async function claudeTargets(dirs, home) {
|
|
|
934
1002
|
}
|
|
935
1003
|
return out;
|
|
936
1004
|
}
|
|
1005
|
+
async function mergedCursorHooks(home, scriptPath) {
|
|
1006
|
+
if (!await isDir2(path3.join(home, CURSOR_DIR_REL))) return null;
|
|
1007
|
+
try {
|
|
1008
|
+
return mergeCursorHooks(await readOrEmpty2(path3.join(home, CURSOR_HOOKS_REL)), scriptPath, `~/${CURSOR_HOOKS_REL}`);
|
|
1009
|
+
} catch (err) {
|
|
1010
|
+
const message2 = err instanceof SyntaxError || err instanceof Error && err.message.includes("n\xE3o \xE9 um objeto JSON") ? `~/${CURSOR_HOOKS_REL} n\xE3o \xE9 JSON v\xE1lido` : err instanceof Error ? err.message : String(err);
|
|
1011
|
+
throw new RpcFailure("failed", message2, CURSOR_HOOKS_REL);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
937
1014
|
async function install(params, home = os3.homedir()) {
|
|
938
1015
|
const scriptPath = path3.join(home, HOOK_SCRIPT_REL);
|
|
939
1016
|
const codexFile = path3.join(home, CODEX_CONFIG_REL);
|
|
@@ -941,7 +1018,7 @@ async function install(params, home = os3.homedir()) {
|
|
|
941
1018
|
const merged = [];
|
|
942
1019
|
for (const target of targets) {
|
|
943
1020
|
try {
|
|
944
|
-
merged.push({ target, body: mergeClaudeSettings(await readOrEmpty2(target.file), scriptPath) });
|
|
1021
|
+
merged.push({ target, body: mergeClaudeSettings(await readOrEmpty2(target.file), scriptPath, target.shown) });
|
|
945
1022
|
} catch (err) {
|
|
946
1023
|
const message2 = err instanceof SyntaxError || err instanceof Error && err.message.includes("n\xE3o \xE9 um objeto JSON") ? `${target.shown} n\xE3o \xE9 JSON v\xE1lido` : err instanceof Error ? err.message : String(err);
|
|
947
1024
|
throw new RpcFailure("failed", message2, relPath(target.shown));
|
|
@@ -949,6 +1026,7 @@ async function install(params, home = os3.homedir()) {
|
|
|
949
1026
|
}
|
|
950
1027
|
const hasCodex = await isDir2(path3.join(home, CODEX_DIR_REL));
|
|
951
1028
|
const mergedCodex = hasCodex ? mergeCodexConfig(await readOrEmpty2(codexFile), scriptPath) : null;
|
|
1029
|
+
const mergedCursor = await mergedCursorHooks(home, scriptPath);
|
|
952
1030
|
let current = `~/${HOOK_SCRIPT_REL}`;
|
|
953
1031
|
try {
|
|
954
1032
|
await mkdir(path3.dirname(scriptPath), { recursive: true });
|
|
@@ -965,6 +1043,10 @@ async function install(params, home = os3.homedir()) {
|
|
|
965
1043
|
current = `~/${CODEX_CONFIG_REL}`;
|
|
966
1044
|
await writeAtomic(codexFile, mergedCodex, 420);
|
|
967
1045
|
}
|
|
1046
|
+
if (mergedCursor !== null) {
|
|
1047
|
+
current = `~/${CURSOR_HOOKS_REL}`;
|
|
1048
|
+
await writeAtomic(path3.join(home, CURSOR_HOOKS_REL), mergedCursor, 420);
|
|
1049
|
+
}
|
|
968
1050
|
} catch (err) {
|
|
969
1051
|
throw fsFailure(err, current);
|
|
970
1052
|
}
|
|
@@ -972,6 +1054,7 @@ async function install(params, home = os3.homedir()) {
|
|
|
972
1054
|
home,
|
|
973
1055
|
claude: "installed",
|
|
974
1056
|
codex: mergedCodex !== null ? "installed" : "skipped",
|
|
1057
|
+
cursor: mergedCursor !== null ? "installed" : "skipped",
|
|
975
1058
|
claude_dirs: merged.map(({ target }) => target.shown.replace(/\/settings\.json$/, ""))
|
|
976
1059
|
};
|
|
977
1060
|
}
|
|
@@ -981,22 +1064,71 @@ async function heal(home = os3.homedir()) {
|
|
|
981
1064
|
const script = await readOrEmpty2(scriptPath);
|
|
982
1065
|
if (!env.trim() || !script) return [];
|
|
983
1066
|
if (script !== HOOK_SCRIPT) await writeAtomic(scriptPath, HOOK_SCRIPT, 493);
|
|
1067
|
+
const steps = [healClaudeDirs, healCursor, healCodex];
|
|
1068
|
+
const healed = [];
|
|
1069
|
+
for (const step of steps) {
|
|
1070
|
+
try {
|
|
1071
|
+
healed.push(...await step(home, scriptPath));
|
|
1072
|
+
} catch {
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
return healed;
|
|
1076
|
+
}
|
|
1077
|
+
var healSkipLogged = /* @__PURE__ */ new Set();
|
|
1078
|
+
function logHealSkip(shown, err, key = shown) {
|
|
1079
|
+
if (healSkipLogged.has(key)) return;
|
|
1080
|
+
healSkipLogged.add(key);
|
|
1081
|
+
const code = err?.code;
|
|
1082
|
+
console.error(
|
|
1083
|
+
`[termhub-agent] monitor hooks heal skipped ${JSON.stringify({ path: shown, error: code ?? (err instanceof Error ? err.message : String(err)) })}`
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
async function healClaudeDirs(home, scriptPath) {
|
|
984
1087
|
const healed = [];
|
|
985
1088
|
for (const dir of await discoverClaudeDirs(home)) {
|
|
986
1089
|
const file = path3.join(expandHome(dir, home), "settings.json");
|
|
987
|
-
const current = await readOrEmpty2(file);
|
|
988
|
-
let body;
|
|
989
1090
|
try {
|
|
990
|
-
|
|
991
|
-
|
|
1091
|
+
const current = await readOrEmpty2(file);
|
|
1092
|
+
const body = mergeClaudeSettings(current, scriptPath, `${dir}/settings.json`);
|
|
1093
|
+
if (body === current) continue;
|
|
1094
|
+
await writeAtomic(file, body, 420);
|
|
1095
|
+
} catch (err) {
|
|
1096
|
+
logHealSkip(dir, err, file);
|
|
992
1097
|
continue;
|
|
993
1098
|
}
|
|
994
|
-
if (body === current) continue;
|
|
995
|
-
await writeAtomic(file, body, 420);
|
|
996
1099
|
healed.push(dir);
|
|
997
1100
|
}
|
|
998
1101
|
return healed;
|
|
999
1102
|
}
|
|
1103
|
+
async function healCursor(home, scriptPath) {
|
|
1104
|
+
if (!await isDir2(path3.join(home, CURSOR_DIR_REL))) return [];
|
|
1105
|
+
const file = path3.join(home, CURSOR_HOOKS_REL);
|
|
1106
|
+
const shown = `~/${CURSOR_DIR_REL}`;
|
|
1107
|
+
try {
|
|
1108
|
+
const current = await readOrEmpty2(file);
|
|
1109
|
+
const body = mergeCursorHooks(current, scriptPath);
|
|
1110
|
+
if (body === current) return [];
|
|
1111
|
+
await writeAtomic(file, body, 420);
|
|
1112
|
+
} catch (err) {
|
|
1113
|
+
logHealSkip(shown, err, file);
|
|
1114
|
+
return [];
|
|
1115
|
+
}
|
|
1116
|
+
return [shown];
|
|
1117
|
+
}
|
|
1118
|
+
async function healCodex(home, scriptPath) {
|
|
1119
|
+
if (!await isDir2(path3.join(home, CODEX_DIR_REL))) return [];
|
|
1120
|
+
const shown = `~/${CODEX_DIR_REL}`;
|
|
1121
|
+
try {
|
|
1122
|
+
const file = path3.join(home, CODEX_CONFIG_REL);
|
|
1123
|
+
const current = await readOrEmpty2(file);
|
|
1124
|
+
if (/^\s*notify\s*=/m.test(current)) return [];
|
|
1125
|
+
await writeAtomic(file, mergeCodexConfig(current, scriptPath), 420);
|
|
1126
|
+
return [shown];
|
|
1127
|
+
} catch (err) {
|
|
1128
|
+
logHealSkip(shown, err, path3.join(home, CODEX_CONFIG_REL));
|
|
1129
|
+
return [];
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1000
1132
|
async function uninstall(params, home = os3.homedir()) {
|
|
1001
1133
|
const codexFile = path3.join(home, CODEX_CONFIG_REL);
|
|
1002
1134
|
const stripped = [];
|
|
@@ -1009,6 +1141,13 @@ async function uninstall(params, home = os3.homedir()) {
|
|
|
1009
1141
|
}
|
|
1010
1142
|
}
|
|
1011
1143
|
const codexConfig = await isDir2(path3.join(home, CODEX_DIR_REL)) ? await readOrEmpty2(codexFile) : "";
|
|
1144
|
+
const cursorFile = path3.join(home, CURSOR_HOOKS_REL);
|
|
1145
|
+
const cursorHooks = await readOrEmpty2(cursorFile);
|
|
1146
|
+
let strippedCursor = null;
|
|
1147
|
+
try {
|
|
1148
|
+
strippedCursor = cursorHooks.includes(HOOK_MARK) ? stripCursorHooks(cursorHooks) : null;
|
|
1149
|
+
} catch {
|
|
1150
|
+
}
|
|
1012
1151
|
let current = `~/${HOOK_SCRIPT_REL}`;
|
|
1013
1152
|
try {
|
|
1014
1153
|
await rm(path3.join(home, HOOK_SCRIPT_REL), { force: true });
|
|
@@ -1022,6 +1161,10 @@ async function uninstall(params, home = os3.homedir()) {
|
|
|
1022
1161
|
current = `~/${CODEX_CONFIG_REL}`;
|
|
1023
1162
|
await writeAtomic(codexFile, stripCodexConfig(codexConfig), 420);
|
|
1024
1163
|
}
|
|
1164
|
+
if (strippedCursor !== null) {
|
|
1165
|
+
current = `~/${CURSOR_HOOKS_REL}`;
|
|
1166
|
+
await writeAtomic(cursorFile, strippedCursor, 420);
|
|
1167
|
+
}
|
|
1025
1168
|
} catch (err) {
|
|
1026
1169
|
throw fsFailure(err, current);
|
|
1027
1170
|
}
|
|
@@ -1052,7 +1195,11 @@ function buildClaudeArgs(spec) {
|
|
|
1052
1195
|
"mcp__termhub__*",
|
|
1053
1196
|
"--disallowed-tools",
|
|
1054
1197
|
DISALLOWED_TOOLS,
|
|
1055
|
-
...spec.model ? ["--model", spec.model] : []
|
|
1198
|
+
...spec.model ? ["--model", spec.model] : [],
|
|
1199
|
+
// Last, and only when set: the account-wide chat's argv stays exactly what it was. It is our own
|
|
1200
|
+
// server-composed text (a project's name, key and paths), never the user's prompt, which still
|
|
1201
|
+
// travels on stdin only.
|
|
1202
|
+
...spec.append_system_prompt ? ["--append-system-prompt", spec.append_system_prompt] : []
|
|
1056
1203
|
];
|
|
1057
1204
|
}
|
|
1058
1205
|
function mcpConfig(url, token) {
|
|
@@ -1112,7 +1259,8 @@ function createClaudeManager(deps) {
|
|
|
1112
1259
|
session_id: params.session_id,
|
|
1113
1260
|
resume: params.resume,
|
|
1114
1261
|
mcp_config_path: mcpConfigPath,
|
|
1115
|
-
model: params.model ?? null
|
|
1262
|
+
model: params.model ?? null,
|
|
1263
|
+
append_system_prompt: params.append_system_prompt ?? null
|
|
1116
1264
|
});
|
|
1117
1265
|
let child;
|
|
1118
1266
|
try {
|
|
@@ -1888,7 +2036,7 @@ async function status3() {
|
|
|
1888
2036
|
}
|
|
1889
2037
|
|
|
1890
2038
|
// src/version.ts
|
|
1891
|
-
var AGENT_VERSION = "0.4.
|
|
2039
|
+
var AGENT_VERSION = "0.4.4";
|
|
1892
2040
|
|
|
1893
2041
|
// src/rpc/update.ts
|
|
1894
2042
|
var PACKAGE = "@termhub/agent";
|
|
@@ -1977,7 +2125,7 @@ function detectOs(platform = process.platform) {
|
|
|
1977
2125
|
if (platform === "linux") return "linux";
|
|
1978
2126
|
return null;
|
|
1979
2127
|
}
|
|
1980
|
-
var CAPABILITIES = [CAPABILITY_CLAUDE];
|
|
2128
|
+
var CAPABILITIES = [CAPABILITY_CLAUDE, CAPABILITY_CLAUDE_SYSTEM_PROMPT];
|
|
1981
2129
|
async function buildHello(osName) {
|
|
1982
2130
|
let tools = [];
|
|
1983
2131
|
try {
|
package/package.json
CHANGED