@termhub/agent 0.6.0 → 0.7.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.
Files changed (2) hide show
  1. package/dist/cli.js +56 -3
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -85,6 +85,12 @@ var RPC = {
85
85
  recursive: z.boolean().optional()
86
86
  }), z.object({ stdout: z.string() })),
87
87
  "ai.credential": def(z.object({ provider: aiProvider, config_dir: machinePath.nullable() }), z.object({ stdout: z.string() }), 1e4),
88
+ /** Symlinks a Claude Code transcript into another account's config dir so `claude --resume` finds it there (since agent 0.7.0). */
89
+ "claude.linkSession": def(z.object({
90
+ transcript_path: machinePath,
91
+ session_id: z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/),
92
+ config_dir: machinePath.nullable()
93
+ }), z.object({ status: z.enum(["linked", "same_account", "no_transcript", "no_config_dir", "conflict"]) }), 1e4),
88
94
  "file.paste": def(z.object({ name: pasteName, data_b64: z.string().min(1).max(28 * 1024 * 1024) }), z.object({ path: z.string() }), 6e4),
89
95
  /** Monitor hooks (see @termhub/machine-ops hooks.ts): the agent writes the script, env and config entries under its own $HOME. */
90
96
  /** `claude_dirs`: Claude config dirs besides ~/.claude (accounts with CLAUDE_CONFIG_DIR), hooked when they exist; since agent 0.1.5. */
@@ -664,7 +670,7 @@ function claudeConfigDirs(accountDirs) {
664
670
  function expandHome(dir, home) {
665
671
  return dir.startsWith("~/") ? `${home}/${dir.slice(2)}` : dir;
666
672
  }
667
- var CLAUDE_HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PermissionRequest", "Notification", "Stop", "SessionEnd"];
673
+ var CLAUDE_HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PermissionRequest", "Notification", "Stop", "StopFailure", "SessionEnd"];
668
674
  var CLAUDE_TOOL_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PermissionRequest"]);
669
675
  var CURSOR_HOOK_EVENTS = ["sessionStart", "beforeSubmitPrompt", "afterAgentResponse", "stop", "sessionEnd"];
670
676
  var HOOK_SCRIPT = `#!/bin/sh
@@ -909,6 +915,32 @@ function stripCursorHooks(current) {
909
915
  `;
910
916
  }
911
917
 
918
+ // ../../packages/machine-ops/dist/claude-session.js
919
+ var CLAUDE_LINK_STATUSES = ["linked", "same_account", "no_transcript", "no_config_dir", "conflict"];
920
+ function claudeLinkScript(transcriptPath, sessionId, configDir) {
921
+ return [
922
+ configDirPrefix(configDir, ".claude"),
923
+ `SRC=${shellQuote(transcriptPath)}; SID=${shellQuote(sessionId)}`,
924
+ '[ -f "$SRC" ] || { echo no_transcript; exit 0; }',
925
+ 'SLUGDIR=$(dirname "$SRC"); SLUG=$(basename "$SLUGDIR"); SRCROOT=$(dirname "$(dirname "$SLUGDIR")")',
926
+ '[ -d "$D" ] || { echo no_config_dir; exit 0; }',
927
+ 'if [ "$(cd "$SRCROOT" && pwd -P)" = "$(cd "$D" && pwd -P)" ]; then echo same_account; exit 0; fi',
928
+ 'mkdir -p "$D/projects/$SLUG" 2>/dev/null || { echo no_config_dir; exit 0; }',
929
+ 'T="$D/projects/$SLUG/$SID.jsonl"',
930
+ 'if [ -e "$T" ] || [ -L "$T" ]; then [ "$T" -ef "$SRC" ] || { echo conflict; exit 0; }; else ln -s "$SRC" "$T" 2>/dev/null || { echo conflict; exit 0; }; fi',
931
+ 'if [ -d "$SLUGDIR/$SID" ] && [ ! -e "$D/projects/$SLUG/$SID" ] && [ ! -L "$D/projects/$SLUG/$SID" ]; then ln -s "$SLUGDIR/$SID" "$D/projects/$SLUG/$SID" 2>/dev/null; fi',
932
+ "echo linked"
933
+ ].join("\n");
934
+ }
935
+ function parseClaudeLinkStatus(stdout) {
936
+ const words = stdout.split(/\s+/).filter(Boolean);
937
+ for (let i = words.length - 1; i >= 0; i--) {
938
+ if (CLAUDE_LINK_STATUSES.includes(words[i]))
939
+ return words[i];
940
+ }
941
+ return null;
942
+ }
943
+
912
944
  // ../../packages/machine-ops/dist/discover.js
913
945
  var CLAUDE_MARKERS = ["settings.json", "projects", ".credentials.json"];
914
946
  var CLAUDE_DIR_NAME = /^\.claude[A-Za-z0-9._-]*$/;
@@ -1305,7 +1337,8 @@ async function uninstall(params, home = os3.homedir()) {
1305
1337
  }
1306
1338
 
1307
1339
  // ../../packages/claude-cli/dist/index.js
1308
- var DISALLOWED_TOOLS = "Bash,Read,Write,Edit,WebFetch,WebSearch";
1340
+ var CONCIERGE_TOOLS = "Agent";
1341
+ var DISALLOWED_TOOLS = "Bash,PowerShell,Monitor,Read,Write,Edit,NotebookEdit,Glob,Grep,EnterWorktree,WebFetch,WebSearch,RemoteTrigger";
1309
1342
  var BACKGROUND_AGENT_HOOK = `input=$(cat); case "$input" in *'"agent_id"'*) exit 0;; esac; printf '%s' "$input" | grep -Eq '"run_in_background"[[:space:]]*:[[:space:]]*true' && exit 0; echo 'No chat do termhub todo subagente roda em segundo plano: repita esta chamada do Agent com run_in_background: true.' >&2; exit 2`;
1310
1343
  var CONCIERGE_SETTINGS = JSON.stringify({
1311
1344
  hooks: { PreToolUse: [{ matcher: "Agent|Task", hooks: [{ type: "command", command: BACKGROUND_AGENT_HOOK }] }] }
@@ -1332,6 +1365,8 @@ function buildClaudeArgs(spec) {
1332
1365
  "mcp__termhub__*",
1333
1366
  "--disallowed-tools",
1334
1367
  DISALLOWED_TOOLS,
1368
+ "--tools",
1369
+ CONCIERGE_TOOLS,
1335
1370
  ...spec.stream_input ? ["--input-format", "stream-json", "--replay-user-messages", "--settings", CONCIERGE_SETTINGS] : [],
1336
1371
  ...spec.model ? ["--model", spec.model] : [],
1337
1372
  // Last, and only when set: the account-wide chat's argv stays exactly what it was. It is our own
@@ -1348,6 +1383,8 @@ function classifyFailure(stderr) {
1348
1383
  return "missing_session";
1349
1384
  if (/^Error: --/m.test(stderr))
1350
1385
  return "cli_rejected";
1386
+ if (/^error: unknown option/m.test(stderr))
1387
+ return "cli_rejected";
1351
1388
  return "run_failed";
1352
1389
  }
1353
1390
 
@@ -2001,6 +2038,21 @@ async function credential(params) {
2001
2038
  return { stdout: r.stdout };
2002
2039
  }
2003
2040
 
2041
+ // src/rpc/claude.ts
2042
+ async function linkSession(params) {
2043
+ let script;
2044
+ try {
2045
+ script = claudeLinkScript(params.transcript_path, params.session_id, params.config_dir);
2046
+ } catch (err) {
2047
+ throw new RpcFailure("invalid", err instanceof Error ? err.message : "invalid config dir");
2048
+ }
2049
+ const r = await sh(script);
2050
+ if (r.timedOut) throw new RpcFailure("timeout", "claude.linkSession timed out");
2051
+ const status4 = parseClaudeLinkStatus(r.stdout);
2052
+ if (r.code !== 0 || !status4) throw new RpcFailure("internal", `claude.linkSession exited with code ${r.code}`);
2053
+ return { status: status4 };
2054
+ }
2055
+
2004
2056
  // src/rpc/fs.ts
2005
2057
  function processFailure(method, r) {
2006
2058
  if (r.timedOut) return new RpcFailure("timeout", `${method} timed out`);
@@ -2384,7 +2436,7 @@ async function status3() {
2384
2436
  }
2385
2437
 
2386
2438
  // src/version.ts
2387
- var AGENT_VERSION = "0.6.0";
2439
+ var AGENT_VERSION = "0.7.1";
2388
2440
 
2389
2441
  // src/rpc/update.ts
2390
2442
  var PACKAGE = "@termhub/agent";
@@ -2504,6 +2556,7 @@ var handlers = {
2504
2556
  "fs.list": list,
2505
2557
  "fs.mkdir": mkdir2,
2506
2558
  "ai.credential": credential,
2559
+ "claude.linkSession": linkSession,
2507
2560
  "file.paste": pasteFile,
2508
2561
  "hooks.install": install,
2509
2562
  "hooks.uninstall": uninstall,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@termhub/agent",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "Agente do termhub: conecta esta máquina ao servidor por WebSocket de saída (sem SSH) e expõe os terminais tmux no navegador.",
5
5
  "license": "MIT",
6
6
  "private": false,