@termhub/agent 0.6.0 → 0.7.0

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 +50 -2
  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._-]*$/;
@@ -2001,6 +2033,21 @@ async function credential(params) {
2001
2033
  return { stdout: r.stdout };
2002
2034
  }
2003
2035
 
2036
+ // src/rpc/claude.ts
2037
+ async function linkSession(params) {
2038
+ let script;
2039
+ try {
2040
+ script = claudeLinkScript(params.transcript_path, params.session_id, params.config_dir);
2041
+ } catch (err) {
2042
+ throw new RpcFailure("invalid", err instanceof Error ? err.message : "invalid config dir");
2043
+ }
2044
+ const r = await sh(script);
2045
+ if (r.timedOut) throw new RpcFailure("timeout", "claude.linkSession timed out");
2046
+ const status4 = parseClaudeLinkStatus(r.stdout);
2047
+ if (r.code !== 0 || !status4) throw new RpcFailure("internal", `claude.linkSession exited with code ${r.code}`);
2048
+ return { status: status4 };
2049
+ }
2050
+
2004
2051
  // src/rpc/fs.ts
2005
2052
  function processFailure(method, r) {
2006
2053
  if (r.timedOut) return new RpcFailure("timeout", `${method} timed out`);
@@ -2384,7 +2431,7 @@ async function status3() {
2384
2431
  }
2385
2432
 
2386
2433
  // src/version.ts
2387
- var AGENT_VERSION = "0.6.0";
2434
+ var AGENT_VERSION = "0.7.0";
2388
2435
 
2389
2436
  // src/rpc/update.ts
2390
2437
  var PACKAGE = "@termhub/agent";
@@ -2504,6 +2551,7 @@ var handlers = {
2504
2551
  "fs.list": list,
2505
2552
  "fs.mkdir": mkdir2,
2506
2553
  "ai.credential": credential,
2554
+ "claude.linkSession": linkSession,
2507
2555
  "file.paste": pasteFile,
2508
2556
  "hooks.install": install,
2509
2557
  "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.0",
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,