@cydm/magic-shell-agent-node 0.1.8 → 0.1.10
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/adapters/pty-adapter.js +8 -99
- package/dist/local-direct-server.js +5 -1
- package/dist/node.d.ts +0 -1
- package/dist/node.js +4 -10
- package/dist/plugin-loader.js +1 -59
- package/dist/workbench/index.html +4 -49
- package/dist/workbench/runtime-control.js +18 -20
- package/dist/workbench/runtime-messages.js +0 -3
- package/dist/worker-runtime.js +0 -4
- package/package.json +3 -2
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node-pty";
|
|
2
|
-
import {
|
|
3
|
-
import { delimiter, dirname, extname, join } from "path";
|
|
2
|
+
import { dirname } from "path";
|
|
4
3
|
import { fileURLToPath } from "url";
|
|
5
4
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
5
|
const __dirname = dirname(__filename);
|
|
@@ -17,31 +16,13 @@ export class PtyAdapter {
|
|
|
17
16
|
}
|
|
18
17
|
async start(config) {
|
|
19
18
|
const agentId = `pty-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const pathValue = spawnEnv.Path || spawnEnv.PATH;
|
|
28
|
-
console.log(`[PtyAdapter] Windows bare command probe for ${agentId}: ${JSON.stringify(findWindowsCommandCandidates(config.command, pathValue))}`);
|
|
29
|
-
console.log(`[PtyAdapter] Windows spawn plan for ${agentId}: command=${JSON.stringify(spawnPlan.command)} args=${JSON.stringify(spawnPlan.args)}`);
|
|
30
|
-
}
|
|
31
|
-
let pty;
|
|
32
|
-
try {
|
|
33
|
-
pty = spawn(spawnPlan.command, spawnPlan.args, {
|
|
34
|
-
name: "xterm-256color",
|
|
35
|
-
cols: 80,
|
|
36
|
-
rows: 24,
|
|
37
|
-
cwd: spawnCwd,
|
|
38
|
-
env: spawnEnv,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
console.error(`[PtyAdapter] Failed to start ${agentId}:`, error instanceof Error ? error.stack || error.message : error);
|
|
43
|
-
throw error;
|
|
44
|
-
}
|
|
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
|
+
});
|
|
45
26
|
const agent = {
|
|
46
27
|
id: agentId,
|
|
47
28
|
pty,
|
|
@@ -116,75 +97,3 @@ export class PtyAdapter {
|
|
|
116
97
|
this.exitCallbacks.push(callback);
|
|
117
98
|
}
|
|
118
99
|
}
|
|
119
|
-
function isAbsoluteOrQualifiedCommand(command) {
|
|
120
|
-
return command.includes("/") || command.includes("\\") || /\.(exe|cmd|bat|com|ps1)$/i.test(command);
|
|
121
|
-
}
|
|
122
|
-
function findWindowsCommandCandidates(command, pathValue) {
|
|
123
|
-
if (!pathValue)
|
|
124
|
-
return [];
|
|
125
|
-
const pathext = ((process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD;.PS1"))
|
|
126
|
-
.split(";")
|
|
127
|
-
.map((value) => value.trim())
|
|
128
|
-
.filter(Boolean);
|
|
129
|
-
const results = [];
|
|
130
|
-
for (const dir of pathValue.split(delimiter).filter(Boolean)) {
|
|
131
|
-
for (const ext of ["", ...pathext]) {
|
|
132
|
-
results.push(join(dir, ext ? `${command}${ext}` : command));
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return results.slice(0, 20);
|
|
136
|
-
}
|
|
137
|
-
function buildWindowsSpawnPlan(command, args, env) {
|
|
138
|
-
if (isAbsoluteOrQualifiedCommand(command)) {
|
|
139
|
-
return { command, args };
|
|
140
|
-
}
|
|
141
|
-
const resolved = resolveWindowsBareCommand(command, env);
|
|
142
|
-
if (resolved && isDirectlySpawnableWindowsBinary(resolved)) {
|
|
143
|
-
return { command: resolved, args };
|
|
144
|
-
}
|
|
145
|
-
const shellCommand = resolved || command;
|
|
146
|
-
return {
|
|
147
|
-
command: env.ComSpec || process.env.ComSpec || "cmd.exe",
|
|
148
|
-
args: ["/d", "/s", "/c", quoteWindowsCommand(shellCommand, args)],
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
function resolveWindowsBareCommand(command, env) {
|
|
152
|
-
const pathValue = env.Path || env.PATH;
|
|
153
|
-
if (!pathValue)
|
|
154
|
-
return null;
|
|
155
|
-
try {
|
|
156
|
-
const result = spawnSync("where", [command], {
|
|
157
|
-
env,
|
|
158
|
-
encoding: "utf8",
|
|
159
|
-
windowsHide: true,
|
|
160
|
-
});
|
|
161
|
-
if (result.status === 0) {
|
|
162
|
-
const first = String(result.stdout || "")
|
|
163
|
-
.split(/\r?\n/)
|
|
164
|
-
.map((line) => line.trim())
|
|
165
|
-
.find(Boolean);
|
|
166
|
-
if (first)
|
|
167
|
-
return first;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
catch {
|
|
171
|
-
// Fall through to manual candidates.
|
|
172
|
-
}
|
|
173
|
-
const candidate = findWindowsCommandCandidates(command, pathValue).find(Boolean);
|
|
174
|
-
return candidate || null;
|
|
175
|
-
}
|
|
176
|
-
function isDirectlySpawnableWindowsBinary(command) {
|
|
177
|
-
const ext = extname(command).toLowerCase();
|
|
178
|
-
return ext === ".exe" || ext === ".com";
|
|
179
|
-
}
|
|
180
|
-
function quoteWindowsCommand(command, args) {
|
|
181
|
-
return [command, ...args].map(quoteWindowsArg).join(" ");
|
|
182
|
-
}
|
|
183
|
-
function quoteWindowsArg(value) {
|
|
184
|
-
if (value.length === 0)
|
|
185
|
-
return '""';
|
|
186
|
-
if (!/[\s"]/u.test(value))
|
|
187
|
-
return value;
|
|
188
|
-
const escaped = value.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/g, "$1$1");
|
|
189
|
-
return `"${escaped}"`;
|
|
190
|
-
}
|
|
@@ -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,12 @@ 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 {
|
|
645
|
+
console.log(`[AgentNode] spawn_worker request session=${sessionId} plugin=${pluginName} cwd=${cwd || ""}`);
|
|
646
646
|
await this.spawnWorker({ sessionId, pluginName, cwd, displayName, taskSummary });
|
|
647
647
|
if (taskSummary) {
|
|
648
648
|
this.rememberNodeSpawn(taskSummary, sessionId);
|
|
649
649
|
}
|
|
650
|
-
console.log(`[AgentNode] control spawn_worker success: session=${sessionId} plugin=${pluginName}`);
|
|
651
650
|
this.sendControlResult(source, message.requestId, name, true, {
|
|
652
651
|
sessionId,
|
|
653
652
|
pluginName,
|
|
@@ -656,9 +655,11 @@ export class AgentNode {
|
|
|
656
655
|
});
|
|
657
656
|
}
|
|
658
657
|
catch (err) {
|
|
659
|
-
console.error(`[AgentNode]
|
|
658
|
+
console.error(`[AgentNode] spawn_worker failed session=${sessionId} plugin=${pluginName}:`, err);
|
|
660
659
|
this.sendControlResult(source, message.requestId, name, false, {
|
|
661
660
|
error: err instanceof Error ? err.message : String(err),
|
|
661
|
+
sessionId,
|
|
662
|
+
pluginName,
|
|
662
663
|
});
|
|
663
664
|
}
|
|
664
665
|
return;
|
|
@@ -973,7 +974,6 @@ export class AgentNode {
|
|
|
973
974
|
return {
|
|
974
975
|
pluginName: this.primaryAgent.pluginName,
|
|
975
976
|
preferredWorkerPluginName: this.preferredWorkerPluginName,
|
|
976
|
-
availableWorkerPlugins: this.getAvailableWorkerPluginNames(),
|
|
977
977
|
sessionId: this.primaryAgent.sessionId,
|
|
978
978
|
status: this.primaryAgent.status,
|
|
979
979
|
activityState: this.primaryAgent.activityState,
|
|
@@ -981,12 +981,6 @@ export class AgentNode {
|
|
|
981
981
|
capabilities: this.primaryAgent.capabilities || [],
|
|
982
982
|
};
|
|
983
983
|
}
|
|
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
984
|
isProtectedPrimarySession(sessionId) {
|
|
991
985
|
return !!sessionId && sessionId === this.primaryAgent.sessionId;
|
|
992
986
|
}
|
package/dist/plugin-loader.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
2435
|
+
return saved === 'claude-code' || saved === 'codex' ? saved : 'pie';
|
|
2450
2436
|
}
|
|
2451
2437
|
|
|
2452
2438
|
function persistSpawnPlugin(pluginName) {
|
|
2453
|
-
selectedSpawnPlugin =
|
|
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
|
-
|
|
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
|
}
|
|
@@ -148,6 +134,24 @@
|
|
|
148
134
|
return true;
|
|
149
135
|
}
|
|
150
136
|
|
|
137
|
+
if (msg.controlKind === "result" && msg.controlName === "spawn_worker") {
|
|
138
|
+
if (msg.ok === false) {
|
|
139
|
+
const requestedSessionId = msg.payload?.sessionId || msg.sessionId || ctx.pendingSpawnSessionId;
|
|
140
|
+
if (!requestedSessionId || requestedSessionId === ctx.pendingSpawnSessionId) {
|
|
141
|
+
ctx.pendingSpawnSessionId = null;
|
|
142
|
+
ctx.pendingSpawnAutoAttach = true;
|
|
143
|
+
ctx.resetSpawnButton();
|
|
144
|
+
}
|
|
145
|
+
ctx.writeSystemNotice(`WORKER SPAWN FAILED: ${msg.error || msg.payload?.error || "Unknown error"}`);
|
|
146
|
+
if (ctx.sessionId && ctx.sessionId === requestedSessionId) {
|
|
147
|
+
ctx.returnToPrimaryChat({ clearSession: true });
|
|
148
|
+
}
|
|
149
|
+
ctx.renderWorkers();
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
151
155
|
if (msg.controlKind === "result" && msg.controlName === "get_worker_detail" && msg.payload && msg.payload.worker) {
|
|
152
156
|
ctx.workerDetail = msg.payload.worker || null;
|
|
153
157
|
ctx.renderWorkerDetailPanel();
|
|
@@ -159,9 +163,6 @@
|
|
|
159
163
|
ctx.dirBrowserParentPath = msg.payload.parentPath || null;
|
|
160
164
|
ctx.dirBrowserRepoRoot = msg.payload.repoRoot || null;
|
|
161
165
|
ctx.dirBrowserEntries = msg.payload.entries || [];
|
|
162
|
-
if (!ctx.getSpawnCwd?.() && msg.payload.path) {
|
|
163
|
-
ctx.setSpawnCwd?.(msg.payload.path);
|
|
164
|
-
}
|
|
165
166
|
ctx.renderDirBrowser();
|
|
166
167
|
return true;
|
|
167
168
|
}
|
|
@@ -182,9 +183,6 @@
|
|
|
182
183
|
ctx.dirBrowserParentPath = msg.payload.parentPath || null;
|
|
183
184
|
ctx.dirBrowserRepoRoot = msg.payload.repoRoot || null;
|
|
184
185
|
ctx.dirBrowserEntries = msg.payload.entries || [];
|
|
185
|
-
if (!ctx.getSpawnCwd?.() && msg.payload.path) {
|
|
186
|
-
ctx.setSpawnCwd?.(msg.payload.path);
|
|
187
|
-
}
|
|
188
186
|
ctx.renderDirBrowser();
|
|
189
187
|
return true;
|
|
190
188
|
}
|
package/dist/worker-runtime.js
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "0.1.10",
|
|
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.
|
|
31
|
+
"@cydm/magic-shell-protocol": "0.1.1",
|
|
31
32
|
"node-pty": "^1.1.0",
|
|
32
33
|
"ws": "^8.18.0"
|
|
33
34
|
},
|