@cydm/magic-shell-agent-node 0.1.3 → 0.1.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.
@@ -1,5 +1,5 @@
1
1
  import { spawn } from "node-pty";
2
- import { dirname } from "path";
2
+ import { delimiter, dirname, join } from "path";
3
3
  import { fileURLToPath } from "url";
4
4
  const __filename = fileURLToPath(import.meta.url);
5
5
  const __dirname = dirname(__filename);
@@ -16,13 +16,26 @@ 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 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
- });
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
+ }
26
39
  const agent = {
27
40
  id: agentId,
28
41
  pty,
@@ -97,3 +110,21 @@ export class PtyAdapter {
97
110
  this.exitCallbacks.push(callback);
98
111
  }
99
112
  }
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
+ }
package/dist/node.js CHANGED
@@ -641,11 +641,13 @@ 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 || "")}`);
644
645
  try {
645
646
  await this.spawnWorker({ sessionId, pluginName, cwd, displayName, taskSummary });
646
647
  if (taskSummary) {
647
648
  this.rememberNodeSpawn(taskSummary, sessionId);
648
649
  }
650
+ console.log(`[AgentNode] control spawn_worker success: session=${sessionId} plugin=${pluginName}`);
649
651
  this.sendControlResult(source, message.requestId, name, true, {
650
652
  sessionId,
651
653
  pluginName,
@@ -654,6 +656,7 @@ export class AgentNode {
654
656
  });
655
657
  }
656
658
  catch (err) {
659
+ console.error(`[AgentNode] control spawn_worker failed: session=${sessionId} plugin=${pluginName}`, err instanceof Error ? err.stack || err.message : err);
657
660
  this.sendControlResult(source, message.requestId, name, false, {
658
661
  error: err instanceof Error ? err.message : String(err),
659
662
  });
@@ -1,6 +1,7 @@
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";
4
5
  /**
5
6
  * 加载单个插件配置
6
7
  */
@@ -29,12 +30,13 @@ export function loadPlugin(path) {
29
30
  if (!["stdio", "pty", "rpc"].includes(config.type)) {
30
31
  throw new Error(`Plugin ${path} invalid type: ${config.type}`);
31
32
  }
32
- return {
33
+ const normalized = {
33
34
  ...config,
34
35
  command: resolveCommandPath(config.command, configDir, repoRoot),
35
36
  args: resolveArgPaths(config.args, configDir, repoRoot),
36
37
  cwd: resolveOptionalPath(config.cwd, configDir, repoRoot),
37
38
  };
39
+ return maybeResolveBundledPieCommand(normalized, configDir, repoRoot);
38
40
  }
39
41
  function resolveOptionalPath(value, configDir, repoRoot) {
40
42
  if (!value)
@@ -82,6 +84,62 @@ function resolveArgPaths(args, configDir, repoRoot) {
82
84
  return arg;
83
85
  });
84
86
  }
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
+ }
85
143
  /**
86
144
  * 扫描目录加载所有插件
87
145
  */
@@ -16,6 +16,7 @@ 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 || "")}`);
19
20
  const plugin = deps.plugins.get(options.pluginName);
20
21
  if (!plugin) {
21
22
  throw new Error(`Plugin not found: ${options.pluginName}`);
@@ -27,7 +28,9 @@ export async function spawnManagedWorker(options, deps) {
27
28
  : plugin.args,
28
29
  cwd: normalizeWorkerCwd(options.cwd, plugin.cwd),
29
30
  };
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())}`);
30
32
  await deps.sessionManager.createSession(options.sessionId, runtimePlugin);
33
+ console.log(`[WorkerRuntime] session created: ${options.sessionId}`);
31
34
  const session = deps.sessionManager.getSession(options.sessionId);
32
35
  if (!session) {
33
36
  throw new Error(`Session failed to start: ${options.sessionId}`);
@@ -60,6 +63,7 @@ export async function spawnManagedWorker(options, deps) {
60
63
  deps.workerRegistry.updateWorkerStatus(session.agentId, "running", {
61
64
  startedAt: Date.now(),
62
65
  });
66
+ console.log(`[WorkerRuntime] worker record ready: session=${options.sessionId} agent=${session.agentId}`);
63
67
  return {
64
68
  type: "session",
65
69
  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.3",
3
+ "version": "0.1.4",
4
4
  "description": "Magic Shell Agent Node - Local agent connector",
5
5
  "homepage": "https://magicshell.ai",
6
6
  "keywords": [