@cydm/magic-shell-agent-node 0.1.7 → 0.1.9

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.
@@ -1,5 +1,5 @@
1
1
  import { spawn } from "node-pty";
2
- import { delimiter, dirname, join } from "path";
2
+ import { dirname } from "path";
3
3
  import { fileURLToPath } from "url";
4
4
  const __filename = fileURLToPath(import.meta.url);
5
5
  const __dirname = dirname(__filename);
@@ -16,26 +16,13 @@ export class PtyAdapter {
16
16
  }
17
17
  async start(config) {
18
18
  const agentId = `pty-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
19
- const spawnCwd = config.cwd || process.cwd();
20
- const spawnEnv = { ...process.env, ...config.env };
21
- console.log(`[PtyAdapter] Starting ${agentId}: command=${JSON.stringify(config.command)} args=${JSON.stringify(config.args || [])} cwd=${JSON.stringify(spawnCwd)} platform=${process.platform}`);
22
- if (process.platform === "win32" && !isAbsoluteOrQualifiedCommand(config.command)) {
23
- console.log(`[PtyAdapter] Windows bare command probe for ${agentId}: ${JSON.stringify(findWindowsCommandCandidates(config.command, spawnEnv.PATH))}`);
24
- }
25
- let pty;
26
- try {
27
- pty = spawn(config.command, config.args || [], {
28
- name: "xterm-256color",
29
- cols: 80,
30
- rows: 24,
31
- cwd: spawnCwd,
32
- env: spawnEnv,
33
- });
34
- }
35
- catch (error) {
36
- console.error(`[PtyAdapter] Failed to start ${agentId}:`, error instanceof Error ? error.stack || error.message : error);
37
- throw error;
38
- }
19
+ const pty = spawn(config.command, config.args || [], {
20
+ name: "xterm-256color",
21
+ cols: 80,
22
+ rows: 24,
23
+ cwd: config.cwd || process.cwd(),
24
+ env: { ...process.env, ...config.env },
25
+ });
39
26
  const agent = {
40
27
  id: agentId,
41
28
  pty,
@@ -110,21 +97,3 @@ export class PtyAdapter {
110
97
  this.exitCallbacks.push(callback);
111
98
  }
112
99
  }
113
- function isAbsoluteOrQualifiedCommand(command) {
114
- return command.includes("/") || command.includes("\\") || /\.(exe|cmd|bat|com|ps1)$/i.test(command);
115
- }
116
- function findWindowsCommandCandidates(command, pathValue) {
117
- if (!pathValue)
118
- return [];
119
- const pathext = (process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD;.PS1")
120
- .split(";")
121
- .map((value) => value.trim())
122
- .filter(Boolean);
123
- const results = [];
124
- for (const dir of pathValue.split(delimiter).filter(Boolean)) {
125
- for (const ext of ["", ...pathext]) {
126
- results.push(join(dir, ext ? `${command}${ext}` : command));
127
- }
128
- }
129
- return results.slice(0, 20);
130
- }
@@ -23,12 +23,16 @@ function guessContentType(filePath) {
23
23
  }
24
24
  function findWorkbenchRoot() {
25
25
  const currentDir = path.dirname(fileURLToPath(import.meta.url));
26
+ const envOverride = process.env.MAGIC_SHELL_WORKBENCH_ROOT;
26
27
  const candidates = [
28
+ envOverride ? path.resolve(envOverride) : null,
27
29
  path.resolve(currentDir, "./workbench"),
30
+ path.resolve(currentDir, "../dist/workbench"),
31
+ path.resolve(currentDir, "../workbench"),
28
32
  path.resolve(currentDir, "../../../apps/web/src"),
29
33
  path.resolve(currentDir, "../../../../apps/web/src"),
30
34
  path.resolve(process.cwd(), "apps/web/src"),
31
- ];
35
+ ].filter((value) => Boolean(value));
32
36
  for (const candidate of candidates) {
33
37
  if (existsSync(path.join(candidate, "index.html"))) {
34
38
  return candidate;
package/dist/node.d.ts CHANGED
@@ -84,7 +84,6 @@ export declare class AgentNode {
84
84
  private sendControlResult;
85
85
  private buildRuntimeSnapshot;
86
86
  private buildPrimaryAgentStatus;
87
- private getAvailableWorkerPluginNames;
88
87
  private isProtectedPrimarySession;
89
88
  private runSessionTurn;
90
89
  private runClaudeWorkerTurn;
package/dist/node.js CHANGED
@@ -641,13 +641,11 @@ export class AgentNode {
641
641
  const cwd = this.readString(payload.cwd) || message.cwd;
642
642
  const displayName = this.readString(payload.displayName) || message.displayName;
643
643
  const sessionId = this.readString(payload.sessionId) || message.target?.sessionId || generateSessionId();
644
- console.log(`[AgentNode] control spawn_worker start: session=${sessionId} plugin=${pluginName} cwd=${JSON.stringify(cwd || "")} displayName=${JSON.stringify(displayName || "")} task=${JSON.stringify(taskSummary || "")}`);
645
644
  try {
646
645
  await this.spawnWorker({ sessionId, pluginName, cwd, displayName, taskSummary });
647
646
  if (taskSummary) {
648
647
  this.rememberNodeSpawn(taskSummary, sessionId);
649
648
  }
650
- console.log(`[AgentNode] control spawn_worker success: session=${sessionId} plugin=${pluginName}`);
651
649
  this.sendControlResult(source, message.requestId, name, true, {
652
650
  sessionId,
653
651
  pluginName,
@@ -656,7 +654,6 @@ export class AgentNode {
656
654
  });
657
655
  }
658
656
  catch (err) {
659
- console.error(`[AgentNode] control spawn_worker failed: session=${sessionId} plugin=${pluginName}`, err instanceof Error ? err.stack || err.message : err);
660
657
  this.sendControlResult(source, message.requestId, name, false, {
661
658
  error: err instanceof Error ? err.message : String(err),
662
659
  });
@@ -973,7 +970,6 @@ export class AgentNode {
973
970
  return {
974
971
  pluginName: this.primaryAgent.pluginName,
975
972
  preferredWorkerPluginName: this.preferredWorkerPluginName,
976
- availableWorkerPlugins: this.getAvailableWorkerPluginNames(),
977
973
  sessionId: this.primaryAgent.sessionId,
978
974
  status: this.primaryAgent.status,
979
975
  activityState: this.primaryAgent.activityState,
@@ -981,12 +977,6 @@ export class AgentNode {
981
977
  capabilities: this.primaryAgent.capabilities || [],
982
978
  };
983
979
  }
984
- getAvailableWorkerPluginNames() {
985
- return Array.from(this.plugins.values())
986
- .map((plugin) => plugin.name)
987
- .filter((name) => name !== this.primaryAgent.pluginName)
988
- .sort((a, b) => a.localeCompare(b));
989
- }
990
980
  isProtectedPrimarySession(sessionId) {
991
981
  return !!sessionId && sessionId === this.primaryAgent.sessionId;
992
982
  }
@@ -1,7 +1,6 @@
1
1
  import { readFileSync, readdirSync, existsSync } from "fs";
2
2
  import { join, extname, dirname, isAbsolute, resolve } from "path";
3
3
  import { fileURLToPath } from "url";
4
- import { createRequire } from "module";
5
4
  /**
6
5
  * 加载单个插件配置
7
6
  */
@@ -30,13 +29,12 @@ export function loadPlugin(path) {
30
29
  if (!["stdio", "pty", "rpc"].includes(config.type)) {
31
30
  throw new Error(`Plugin ${path} invalid type: ${config.type}`);
32
31
  }
33
- const normalized = {
32
+ return {
34
33
  ...config,
35
34
  command: resolveCommandPath(config.command, configDir, repoRoot),
36
35
  args: resolveArgPaths(config.args, configDir, repoRoot),
37
36
  cwd: resolveOptionalPath(config.cwd, configDir, repoRoot),
38
37
  };
39
- return maybeResolveBundledPieCommand(normalized, configDir, repoRoot);
40
38
  }
41
39
  function resolveOptionalPath(value, configDir, repoRoot) {
42
40
  if (!value)
@@ -84,62 +82,6 @@ function resolveArgPaths(args, configDir, repoRoot) {
84
82
  return arg;
85
83
  });
86
84
  }
87
- function maybeResolveBundledPieCommand(config, configDir, repoRoot) {
88
- if (config.name !== "pie" || config.command !== "pie") {
89
- return config;
90
- }
91
- const pieEntry = resolveInstalledPackageBin("@cydm/pie", configDir, repoRoot);
92
- if (!pieEntry) {
93
- return config;
94
- }
95
- return {
96
- ...config,
97
- command: process.execPath,
98
- args: [pieEntry, ...(config.args || [])],
99
- };
100
- }
101
- function resolveInstalledPackageBin(packageName, configDir, repoRoot) {
102
- const requireFromHere = createRequire(import.meta.url);
103
- try {
104
- const packageJsonPath = requireFromHere.resolve(`${packageName}/package.json`);
105
- const direct = readPackageBin(packageJsonPath);
106
- if (direct)
107
- return direct;
108
- }
109
- catch {
110
- // Fall through to alternate roots below.
111
- }
112
- const searchRoots = [
113
- configDir,
114
- repoRoot,
115
- process.cwd(),
116
- dirname(fileURLToPath(import.meta.url)),
117
- ];
118
- for (const root of searchRoots) {
119
- try {
120
- const packageJsonPath = requireFromHere.resolve(`${packageName}/package.json`, { paths: [resolve(root)] });
121
- const resolved = readPackageBin(packageJsonPath);
122
- if (resolved)
123
- return resolved;
124
- }
125
- catch {
126
- continue;
127
- }
128
- }
129
- return null;
130
- }
131
- function readPackageBin(packageJsonPath) {
132
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
133
- const packageRoot = dirname(packageJsonPath);
134
- const binField = packageJson.bin;
135
- const relativeBin = typeof binField === "string"
136
- ? binField
137
- : (binField && Object.values(binField)[0]) || null;
138
- if (!relativeBin)
139
- return null;
140
- const binPath = resolve(packageRoot, relativeBin);
141
- return existsSync(binPath) ? binPath : null;
142
- }
143
85
  /**
144
86
  * 扫描目录加载所有插件
145
87
  */
@@ -2372,7 +2372,6 @@
2372
2372
  let workers = [];
2373
2373
  let preferredSessionId = localStorage.getItem('preferredSessionId');
2374
2374
  let workerPollTimer = null;
2375
- let primaryAgent = null;
2376
2375
  let selectedSpawnPlugin = readStoredSpawnPlugin();
2377
2376
  let defaultSpawnCwd = localStorage.getItem('spawnCwd') || '';
2378
2377
  let recentCwds = [];
@@ -2391,6 +2390,7 @@
2391
2390
  let nodeDetailOpen = false;
2392
2391
  let runtimeSummary = null;
2393
2392
  let runtimeFocus = [];
2393
+ let primaryAgent = null;
2394
2394
  let pendingNodeReply = false;
2395
2395
  let nodeTranscript = [{
2396
2396
  id: `node-welcome-${Date.now()}`,
@@ -2429,45 +2429,18 @@
2429
2429
  document.cookie = `${name}=${encodeURIComponent(value)}; path=/; max-age=${60 * 60 * 24 * 365}`;
2430
2430
  }
2431
2431
 
2432
- function getAvailableSpawnPlugins() {
2433
- const plugins = Array.isArray(primaryAgent?.availableWorkerPlugins) && primaryAgent.availableWorkerPlugins.length
2434
- ? primaryAgent.availableWorkerPlugins
2435
- : ['pie'];
2436
- return Array.from(new Set(plugins.filter((item) => typeof item === 'string' && item.length > 0)));
2437
- }
2438
-
2439
- function normalizeSpawnPlugin(pluginName) {
2440
- const available = getAvailableSpawnPlugins();
2441
- if (pluginName && available.includes(pluginName)) return pluginName;
2442
- if (available.includes('pie')) return 'pie';
2443
- return available[0] || 'pie';
2444
- }
2445
-
2446
2432
  function readStoredSpawnPlugin() {
2447
2433
  const cookieValue = readCookie('spawnPlugin');
2448
2434
  const saved = cookieValue || localStorage.getItem('spawnPlugin') || 'pie';
2449
- return normalizeSpawnPlugin(saved);
2435
+ return saved === 'claude-code' || saved === 'codex' ? saved : 'pie';
2450
2436
  }
2451
2437
 
2452
2438
  function persistSpawnPlugin(pluginName) {
2453
- selectedSpawnPlugin = normalizeSpawnPlugin(pluginName);
2439
+ selectedSpawnPlugin = pluginName === 'claude-code' || pluginName === 'codex' ? pluginName : 'pie';
2454
2440
  localStorage.setItem('spawnPlugin', selectedSpawnPlugin);
2455
2441
  writeCookie('spawnPlugin', selectedSpawnPlugin);
2456
2442
  }
2457
2443
 
2458
- function renderSpawnPluginOptions() {
2459
- const select = document.getElementById('spawnPlugin');
2460
- if (!select) return;
2461
- const available = getAvailableSpawnPlugins();
2462
- const current = normalizeSpawnPlugin(selectedSpawnPlugin);
2463
- select.innerHTML = available.map((pluginName) => (
2464
- `<option value="${escapeHtml(pluginName)}">${escapeHtml(getSpawnPluginLabel(pluginName))}</option>`
2465
- )).join('');
2466
- selectedSpawnPlugin = current;
2467
- select.value = current;
2468
- resetSpawnButton();
2469
- }
2470
-
2471
2444
  function loadRecentCwds() {
2472
2445
  try {
2473
2446
  const stored = readCookie('recentCwds') || localStorage.getItem('recentCwds') || '[]';
@@ -2577,7 +2550,7 @@
2577
2550
  document.getElementById('nodeId').value = localStorage.getItem('nodeId') || '';
2578
2551
  document.getElementById('password').value = localStorage.getItem('password') || '';
2579
2552
  document.getElementById('spawnCwd').value = defaultSpawnCwd;
2580
- renderSpawnPluginOptions();
2553
+ document.getElementById('spawnPlugin').value = selectedSpawnPlugin;
2581
2554
  document.getElementById('spawnPlugin').addEventListener('change', (event) => {
2582
2555
  persistSpawnPlugin(event.target.value || 'pie');
2583
2556
  resetSpawnButton();
@@ -2618,17 +2591,6 @@
2618
2591
  }
2619
2592
  }
2620
2593
 
2621
- function setSpawnCwd(cwd, { remember = false } = {}) {
2622
- const next = (cwd || '').trim();
2623
- const input = document.getElementById('spawnCwd');
2624
- input.value = next;
2625
- defaultSpawnCwd = next;
2626
- localStorage.setItem('spawnCwd', defaultSpawnCwd);
2627
- if (remember && next) {
2628
- rememberCwd(next);
2629
- }
2630
- }
2631
-
2632
2594
  const searchParams = new URLSearchParams(window.location.search);
2633
2595
  const inferredRelayUrl = inferDefaultRelayUrl();
2634
2596
  document.getElementById('relayUrl').value = inferredRelayUrl;
@@ -3113,8 +3075,6 @@
3113
3075
  function getSpawnPluginLabel(pluginName) {
3114
3076
  if (pluginName === 'claude-code') return 'CLAUDE';
3115
3077
  if (pluginName === 'codex') return 'CODEX';
3116
- if (pluginName === 'pie-unity') return 'PIE UNITY';
3117
- if (pluginName === 'echo') return 'ECHO';
3118
3078
  return 'PIE';
3119
3079
  }
3120
3080
 
@@ -3698,11 +3658,6 @@
3698
3658
  pushNodeTranscript,
3699
3659
  renderWorkers,
3700
3660
  syncWorkerPluginPreference,
3701
- renderSpawnPluginOptions,
3702
- getSpawnCwd() {
3703
- return (document.getElementById('spawnCwd').value || '').trim();
3704
- },
3705
- setSpawnCwd,
3706
3661
  setSessionDisplay(value) {
3707
3662
  document.getElementById('session-display').textContent = value;
3708
3663
  },
@@ -19,7 +19,6 @@
19
19
  ctx.runtimeSummary = snapshot.runtime || null;
20
20
  ctx.runtimeFocus = snapshot.focus || [];
21
21
  ctx.primaryAgent = snapshot.primary || null;
22
- ctx.renderSpawnPluginOptions?.();
23
22
  ctx.syncNodeTranscriptFromServer(snapshot.nodeHistory);
24
23
 
25
24
  const liveSessionIds = new Set(ctx.workers.map((worker) => worker.sessionId));
@@ -106,21 +105,8 @@
106
105
  }
107
106
 
108
107
  function handleControlMessage(msg, ctx) {
109
- if (msg.controlKind === "result" && msg.controlName === "spawn_worker") {
110
- if (msg.ok === false) {
111
- ctx.pendingSpawnSessionId = null;
112
- ctx.pendingSpawnAutoAttach = true;
113
- ctx.resetSpawnButton();
114
- ctx.writeSystemNotice(`SPAWN FAILED: ${msg.payload?.error || msg.error || "Unknown error"}`);
115
- ctx.renderWorkers();
116
- return true;
117
- }
118
- return false;
119
- }
120
-
121
108
  if (msg.controlKind === "result" && msg.controlName === "get_primary_agent" && msg.payload && msg.payload.primary) {
122
109
  ctx.primaryAgent = msg.payload.primary || null;
123
- ctx.renderSpawnPluginOptions?.();
124
110
  ctx.renderNodeHome();
125
111
  return true;
126
112
  }
@@ -159,9 +145,6 @@
159
145
  ctx.dirBrowserParentPath = msg.payload.parentPath || null;
160
146
  ctx.dirBrowserRepoRoot = msg.payload.repoRoot || null;
161
147
  ctx.dirBrowserEntries = msg.payload.entries || [];
162
- if (!ctx.getSpawnCwd?.() && msg.payload.path) {
163
- ctx.setSpawnCwd?.(msg.payload.path);
164
- }
165
148
  ctx.renderDirBrowser();
166
149
  return true;
167
150
  }
@@ -182,9 +165,6 @@
182
165
  ctx.dirBrowserParentPath = msg.payload.parentPath || null;
183
166
  ctx.dirBrowserRepoRoot = msg.payload.repoRoot || null;
184
167
  ctx.dirBrowserEntries = msg.payload.entries || [];
185
- if (!ctx.getSpawnCwd?.() && msg.payload.path) {
186
- ctx.setSpawnCwd?.(msg.payload.path);
187
- }
188
168
  ctx.renderDirBrowser();
189
169
  return true;
190
170
  }
@@ -6,9 +6,6 @@
6
6
  ctx.sessionId = null;
7
7
  ctx.setSessionDisplay("----");
8
8
  ctx.syncWorkerPluginPreference?.();
9
- if (!ctx.getSpawnCwd?.()) {
10
- ctx.requestDirBrowse?.();
11
- }
12
9
  ctx.requestWorkerList();
13
10
  return true;
14
11
 
@@ -16,7 +16,6 @@ function normalizeWorkerCwd(cwd, pluginCwd) {
16
16
  return path.resolve(pluginCwd || process.cwd(), value);
17
17
  }
18
18
  export async function spawnManagedWorker(options, deps) {
19
- console.log(`[WorkerRuntime] spawnManagedWorker start: session=${options.sessionId} plugin=${options.pluginName} cwd=${JSON.stringify(options.cwd || "")} displayName=${JSON.stringify(options.displayName || "")}`);
20
19
  const plugin = deps.plugins.get(options.pluginName);
21
20
  if (!plugin) {
22
21
  throw new Error(`Plugin not found: ${options.pluginName}`);
@@ -28,9 +27,7 @@ export async function spawnManagedWorker(options, deps) {
28
27
  : plugin.args,
29
28
  cwd: normalizeWorkerCwd(options.cwd, plugin.cwd),
30
29
  };
31
- console.log(`[WorkerRuntime] resolved plugin: session=${options.sessionId} command=${JSON.stringify(runtimePlugin.command)} args=${JSON.stringify(runtimePlugin.args || [])} cwd=${JSON.stringify(runtimePlugin.cwd || process.cwd())}`);
32
30
  await deps.sessionManager.createSession(options.sessionId, runtimePlugin);
33
- console.log(`[WorkerRuntime] session created: ${options.sessionId}`);
34
31
  const session = deps.sessionManager.getSession(options.sessionId);
35
32
  if (!session) {
36
33
  throw new Error(`Session failed to start: ${options.sessionId}`);
@@ -63,7 +60,6 @@ export async function spawnManagedWorker(options, deps) {
63
60
  deps.workerRegistry.updateWorkerStatus(session.agentId, "running", {
64
61
  startedAt: Date.now(),
65
62
  });
66
- console.log(`[WorkerRuntime] worker record ready: session=${options.sessionId} agent=${session.agentId}`);
67
63
  return {
68
64
  type: "session",
69
65
  sessionId: options.sessionId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cydm/magic-shell-agent-node",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Magic Shell Agent Node - Local agent connector",
5
5
  "homepage": "https://magicshell.ai",
6
6
  "keywords": [
@@ -24,10 +24,11 @@
24
24
  "scripts": {
25
25
  "build": "tsc && node ./scripts/copy-default-plugins.mjs",
26
26
  "dev": "tsc --watch",
27
+ "prepack": "npm run build",
27
28
  "start": "node dist/node.js"
28
29
  },
29
30
  "dependencies": {
30
- "@cydm/magic-shell-protocol": "0.1.2",
31
+ "@cydm/magic-shell-protocol": "0.1.1",
31
32
  "node-pty": "^1.1.0",
32
33
  "ws": "^8.18.0"
33
34
  },