@wagemule/daemon 0.1.0 → 0.1.2
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/README.md +1 -2
- package/dist/main.cjs +180 -70
- package/dist/main.cjs.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Wage Mule local daemon connects local agent runtimes to a Workspace Server.
|
|
|
7
7
|
Use the command shown in the Wage Mule Web machine page. It pins the daemon version and includes the pairing token for the current space:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx -y @wagemule/daemon@0.1.
|
|
10
|
+
npx -y @wagemule/daemon@0.1.2 start --server-url "https://your-server" --api-key "daemon_xxx"
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
The v0.1 daemon runs in the foreground. Keep the terminal open while the machine should stay online.
|
|
@@ -28,7 +28,6 @@ wm-daemon start --server-url "https://your-server" --api-key "daemon_xxx"
|
|
|
28
28
|
|
|
29
29
|
- `--server-url`: Workspace Server HTTP URL.
|
|
30
30
|
- `--api-key`: daemon pairing or reconnect token from the Web machine page.
|
|
31
|
-
- `--space-id`: optional active space id. The Web command includes it when needed.
|
|
32
31
|
- `--name`: optional display name for this machine.
|
|
33
32
|
- `--root`: optional daemon root directory. Defaults to `~/.wm`.
|
|
34
33
|
|
package/dist/main.cjs
CHANGED
|
@@ -34,6 +34,7 @@ __export(main_exports, {
|
|
|
34
34
|
runCli: () => runCli
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(main_exports);
|
|
37
|
+
var import_node_os9 = __toESM(require("node:os"));
|
|
37
38
|
|
|
38
39
|
// src/process/command.ts
|
|
39
40
|
var import_node_child_process = require("node:child_process");
|
|
@@ -2136,7 +2137,7 @@ var import_node_os = __toESM(require("node:os"));
|
|
|
2136
2137
|
var import_node_path3 = __toESM(require("node:path"));
|
|
2137
2138
|
async function scanAgentSkills(input) {
|
|
2138
2139
|
const homeDir = input.homeDir ?? import_node_os.default.homedir();
|
|
2139
|
-
const workspaceDir = import_node_path3.default.join(input.rootDir, input.serverNamespace, input.machineId, input.agentId);
|
|
2140
|
+
const workspaceDir = input.machineDirectoryName ? import_node_path3.default.join(input.rootDir, input.machineDirectoryName, input.agentDirectoryName ?? input.agentId) : import_node_path3.default.join(input.rootDir, input.serverNamespace, input.machineId, input.agentId);
|
|
2140
2141
|
return {
|
|
2141
2142
|
global: await scanGroupedSkillRoots(runtimeSkillRoots(homeDir, input.runtime), "global"),
|
|
2142
2143
|
workspace: await scanGroupedSkillRoots(workspaceSkillRoots(workspaceDir, input.runtime), "workspace")
|
|
@@ -2289,8 +2290,8 @@ function skillTemplatesForWorkspace(input) {
|
|
|
2289
2290
|
|
|
2290
2291
|
// src/workspace/agent-workspace.ts
|
|
2291
2292
|
async function createAgentWorkspace(input) {
|
|
2292
|
-
const serverDir = input.machineId ? import_node_path4.default.join(input.rootDir, input.
|
|
2293
|
-
const agentDir = import_node_path4.default.join(serverDir, input.
|
|
2293
|
+
const serverDir = input.machineId ? import_node_path4.default.join(input.rootDir, input.machineDirectoryName) : import_node_path4.default.join(input.rootDir, input.serverNamespace);
|
|
2294
|
+
const agentDir = import_node_path4.default.join(serverDir, input.agentDirectoryName);
|
|
2294
2295
|
const wmDir = import_node_path4.default.join(agentDir, ".wm");
|
|
2295
2296
|
const notesDir = import_node_path4.default.join(agentDir, "notes");
|
|
2296
2297
|
const runtimeSessionsDir = import_node_path4.default.join(wmDir, "runtime-sessions");
|
|
@@ -2415,24 +2416,26 @@ async function buildSystemPrompt(input, paths) {
|
|
|
2415
2416
|
"",
|
|
2416
2417
|
"1. `wm message check` -- Non-blocking check for new channel, DM, or thread messages at natural breakpoints.",
|
|
2417
2418
|
"2. `wm message send` -- Send a channel, DM, or thread reply through the platform.",
|
|
2418
|
-
"3. `wm
|
|
2419
|
-
"4. `wm message
|
|
2420
|
-
"5. `wm
|
|
2421
|
-
"6. `wm
|
|
2422
|
-
"7. `wm
|
|
2423
|
-
"8. `wm
|
|
2424
|
-
"9. `wm task
|
|
2425
|
-
"10. `wm task
|
|
2426
|
-
"11. `wm task
|
|
2427
|
-
"12. `wm
|
|
2428
|
-
"13. `wm
|
|
2429
|
-
"14. `wm
|
|
2430
|
-
"15. `wm
|
|
2431
|
-
"16. `wm
|
|
2432
|
-
"17. `wm
|
|
2433
|
-
"18. `wm reminder
|
|
2434
|
-
"19. `wm reminder
|
|
2435
|
-
"20. `wm reminder
|
|
2419
|
+
"3. `wm dm send` -- Send a private agent-to-agent DM, optionally waiting for a reply.",
|
|
2420
|
+
"4. `wm message read` -- Read visible history with pagination or around a specific message.",
|
|
2421
|
+
"5. `wm message search` -- Search visible channel and DM history before answering historical questions.",
|
|
2422
|
+
"6. `wm server info` -- Inspect the current server, visible channels, humans, agents, and memberships.",
|
|
2423
|
+
"7. `wm channel members` -- Inspect members of a channel, DM, or thread target.",
|
|
2424
|
+
"8. `wm member find` -- Find platform members by Feishu open_id.",
|
|
2425
|
+
"9. `wm task list` -- View task messages for a channel or relevant target.",
|
|
2426
|
+
"10. `wm task claim` -- Claim a task before doing work that changes files, runs tools, or performs multi-step investigation.",
|
|
2427
|
+
"11. `wm task unclaim` -- Release a task you cannot or should not continue.",
|
|
2428
|
+
"12. `wm task update` -- Move a task through statuses such as todo, in_progress, in_review, and done.",
|
|
2429
|
+
"13. `wm task create` -- Create genuine new follow-up work when no canonical message/task exists.",
|
|
2430
|
+
"14. `wm attachment upload` -- Upload a local artifact and reference it in a platform message.",
|
|
2431
|
+
"15. `wm attachment view` -- Download and inspect a platform attachment.",
|
|
2432
|
+
"16. `wm profile show` -- Inspect your own profile or a visible human/agent profile.",
|
|
2433
|
+
"17. `wm profile update` -- Update your display name, description, or avatar when explicitly asked.",
|
|
2434
|
+
"18. `wm reminder schedule` -- Schedule a platform-visible reminder for follow-up work.",
|
|
2435
|
+
"19. `wm reminder list` -- List reminders and their lifecycle history.",
|
|
2436
|
+
"20. `wm reminder snooze` -- Push an existing reminder later.",
|
|
2437
|
+
"21. `wm reminder update` -- Change a reminder without creating a duplicate.",
|
|
2438
|
+
"22. `wm reminder cancel` -- Cancel a reminder that is no longer needed.",
|
|
2436
2439
|
"",
|
|
2437
2440
|
"Diagnostic command:",
|
|
2438
2441
|
"",
|
|
@@ -2444,6 +2447,7 @@ async function buildSystemPrompt(input, paths) {
|
|
|
2444
2447
|
"",
|
|
2445
2448
|
"- Other agents may be running on different machines. Do not use local processes, workspaces, server activity, task lists, or runtime sessions to answer what another agent is doing.",
|
|
2446
2449
|
'- When a human asks you to ask, check, confirm, contact, or get status from another agent, your first platform action is to ask that agent in the original message thread with `wm message send --target "#channel:<message>"` and an @mention.',
|
|
2450
|
+
"- When the request explicitly calls for a private agent DM, use `wm dm send --to-agent-id <agent_id>` instead of a thread mention.",
|
|
2447
2451
|
"- Wait for that agent's platform reply via delivered messages, `wm message check`, or recent unread output; then summarize the reply in the same thread.",
|
|
2448
2452
|
"- `wm server info`, `wm channel members`, and `wm task list` are discovery tools. They are not authoritative answers for another agent's current work.",
|
|
2449
2453
|
"",
|
|
@@ -2533,7 +2537,9 @@ async function buildWorkspaceSkillsSection(input) {
|
|
|
2533
2537
|
const result = await scanAgentSkills({
|
|
2534
2538
|
rootDir: input.rootDir,
|
|
2535
2539
|
serverNamespace: input.serverNamespace,
|
|
2540
|
+
machineDirectoryName: input.machineDirectoryName,
|
|
2536
2541
|
machineId: input.machineId ?? "",
|
|
2542
|
+
agentDirectoryName: input.agentDirectoryName,
|
|
2537
2543
|
agentId: input.agentId,
|
|
2538
2544
|
runtime: input.runtime
|
|
2539
2545
|
}).catch(() => ({ global: [], workspace: [] }));
|
|
@@ -2589,7 +2595,7 @@ if (fs.existsSync(envPath)) {
|
|
|
2589
2595
|
|
|
2590
2596
|
const args = process.argv.slice(2);
|
|
2591
2597
|
const [group, command] = args;
|
|
2592
|
-
const help = "Available commands: wm auth whoami; wm message send/check/read/search; wm server info; wm channel members; wm
|
|
2598
|
+
const help = "Available commands: wm auth whoami; wm message send/check/read/search; wm dm send; wm server info; wm channel members; wm member find; wm task list/claim/unclaim/update/create; wm attachment upload/view; wm profile show/update; wm reminder schedule/list/snooze/update/cancel";
|
|
2593
2599
|
|
|
2594
2600
|
function valueAfter(name) {
|
|
2595
2601
|
const index = args.indexOf(name);
|
|
@@ -2601,7 +2607,7 @@ function hasFlag(name) {
|
|
|
2601
2607
|
}
|
|
2602
2608
|
|
|
2603
2609
|
function positionalText() {
|
|
2604
|
-
const knownOptions = new Set(["--target", "--channel", "--text", "--content", "--attachment-ids", "--query", "--q", "--around", "--status", "--id", "--task-id", "--title", "--description", "--file", "--at", "--every", "--role", "--instructions", "--body"]);
|
|
2610
|
+
const knownOptions = new Set(["--target", "--channel", "--text", "--content", "--attachment-ids", "--query", "--q", "--around", "--status", "--id", "--task-id", "--title", "--description", "--file", "--at", "--every", "--role", "--instructions", "--body", "--to-agent-id", "--timeout", "--feishu-open-id", "--open-id"]);
|
|
2605
2611
|
const values = [];
|
|
2606
2612
|
for (let index = 2; index < args.length; index++) {
|
|
2607
2613
|
const arg = args[index];
|
|
@@ -2671,6 +2677,17 @@ function formatSendResult(result, target) {
|
|
|
2671
2677
|
return lines.join("\\n");
|
|
2672
2678
|
}
|
|
2673
2679
|
|
|
2680
|
+
function formatDmSendResult(payload) {
|
|
2681
|
+
const messageId = payload.messageId || payload.message?.id || "unknown";
|
|
2682
|
+
const lines = [\`DM sent. Message ID: \${messageId}\`];
|
|
2683
|
+
if (payload.reply) {
|
|
2684
|
+
lines.push("", "--- Reply ---", messageLine(payload.reply));
|
|
2685
|
+
} else if (payload.timed_out) {
|
|
2686
|
+
lines.push("Timed out waiting for reply.");
|
|
2687
|
+
}
|
|
2688
|
+
return lines.join("\\n");
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2674
2691
|
function formatMessages(payload) {
|
|
2675
2692
|
const messages = payload.messages || [];
|
|
2676
2693
|
if (!messages.length) return "No messages.";
|
|
@@ -2705,6 +2722,26 @@ function formatMembers(payload) {
|
|
|
2705
2722
|
return members.map((member) => \`- \${member.mention} type=\${member.type}\${member.runtime ? \` runtime=\${member.runtime}\` : ""}\`).join("\\n");
|
|
2706
2723
|
}
|
|
2707
2724
|
|
|
2725
|
+
function formatMemberFind(payload) {
|
|
2726
|
+
const lines = [];
|
|
2727
|
+
if (payload.human) {
|
|
2728
|
+
lines.push(\`Human: @\${payload.human.name} (\${payload.human.id})\`);
|
|
2729
|
+
if (payload.human.feishu_open_id) lines.push(\`Feishu open_id: \${payload.human.feishu_open_id}\`);
|
|
2730
|
+
if (payload.human.email) lines.push(\`Email: \${payload.human.email}\`);
|
|
2731
|
+
} else {
|
|
2732
|
+
lines.push("Human: not found");
|
|
2733
|
+
}
|
|
2734
|
+
lines.push("Agents:");
|
|
2735
|
+
if (payload.agents?.length) {
|
|
2736
|
+
for (const agent of payload.agents) {
|
|
2737
|
+
lines.push(\`- @\${agent.name} id=\${agent.agent_id} runtime=\${agent.runtime} machine=\${agent.machine_id} \${agent.online ? "online" : "offline"}\`);
|
|
2738
|
+
}
|
|
2739
|
+
} else {
|
|
2740
|
+
lines.push("- none");
|
|
2741
|
+
}
|
|
2742
|
+
return lines.join("\\n");
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2708
2745
|
async function main() {
|
|
2709
2746
|
const agentId = process.env.WM_AGENT_ID || process.env.WM_DAEMON_AGENT_ID;
|
|
2710
2747
|
if (group === "auth" && command === "whoami") {
|
|
@@ -2736,6 +2773,20 @@ async function main() {
|
|
|
2736
2773
|
printResult(payload, formatSendResult(payload, target));
|
|
2737
2774
|
return;
|
|
2738
2775
|
}
|
|
2776
|
+
if (group === "dm" && command === "send") {
|
|
2777
|
+
const toAgentId = valueAfter("--to-agent-id");
|
|
2778
|
+
if (!toAgentId) throw new Error("--to-agent-id is required");
|
|
2779
|
+
const text = (valueAfter("--text") || valueAfter("--content") || await stdin() || positionalText()).trim();
|
|
2780
|
+
if (!text) throw new Error("message text is required; use --text, --content, stdin, or a positional message");
|
|
2781
|
+
const payload = await request("POST", \`/internal/agent/\${agentId}/dm/send\`, {
|
|
2782
|
+
to_agent_id: toAgentId,
|
|
2783
|
+
text,
|
|
2784
|
+
wait_for_reply: hasFlag("--wait-for-reply"),
|
|
2785
|
+
timeout_ms: valueAfter("--timeout") ? Number(valueAfter("--timeout")) : undefined,
|
|
2786
|
+
});
|
|
2787
|
+
printResult(payload, formatDmSendResult(payload));
|
|
2788
|
+
return;
|
|
2789
|
+
}
|
|
2739
2790
|
if (group === "message" && command === "check") {
|
|
2740
2791
|
const payload = await request("GET", \`/internal/agent/\${agentId}/receive\`);
|
|
2741
2792
|
printResult(payload, formatMessages(payload).replace("No messages.", "No new messages."));
|
|
@@ -2774,6 +2825,13 @@ async function main() {
|
|
|
2774
2825
|
printResult(payload, formatMembers(payload));
|
|
2775
2826
|
return;
|
|
2776
2827
|
}
|
|
2828
|
+
if (group === "member" && command === "find") {
|
|
2829
|
+
const openId = (valueAfter("--feishu-open-id") || valueAfter("--open-id") || "").trim();
|
|
2830
|
+
if (!openId) throw new Error("--feishu-open-id is required");
|
|
2831
|
+
const payload = await request("GET", \`/internal/agent/\${agentId}/members/find?feishu_open_id=\${encodeURIComponent(openId)}\`);
|
|
2832
|
+
printResult(payload, formatMemberFind(payload));
|
|
2833
|
+
return;
|
|
2834
|
+
}
|
|
2777
2835
|
if (group === "task" && command === "list") {
|
|
2778
2836
|
const status = valueAfter("--status");
|
|
2779
2837
|
const suffix = status ? \`?status=\${encodeURIComponent(status)}\` : "";
|
|
@@ -2889,7 +2947,11 @@ async function runAdapterSmokeTest(input) {
|
|
|
2889
2947
|
input.runtime,
|
|
2890
2948
|
"adapter runtime must match requested runtime"
|
|
2891
2949
|
);
|
|
2892
|
-
const workspace = await createAgentWorkspace(
|
|
2950
|
+
const workspace = await createAgentWorkspace({
|
|
2951
|
+
...input,
|
|
2952
|
+
machineDirectoryName: input.machineDirectoryName ?? input.serverNamespace,
|
|
2953
|
+
agentDirectoryName: input.agentDirectoryName ?? input.agentId
|
|
2954
|
+
});
|
|
2893
2955
|
const runDir = input.runDir ?? workspace.agentDir;
|
|
2894
2956
|
const systemPrompt = await (0, import_promises5.readFile)(workspace.systemPromptPath, "utf8");
|
|
2895
2957
|
const result = await input.adapter.run({
|
|
@@ -3033,6 +3095,8 @@ async function createLabAgent(input) {
|
|
|
3033
3095
|
rootDir: input.rootDir,
|
|
3034
3096
|
serverNamespace: input.serverNamespace,
|
|
3035
3097
|
serverId: `lab:${input.serverNamespace}`,
|
|
3098
|
+
machineDirectoryName: input.serverNamespace,
|
|
3099
|
+
agentDirectoryName: agentId,
|
|
3036
3100
|
daemonId: import_node_os4.default.hostname() || "local",
|
|
3037
3101
|
agentId,
|
|
3038
3102
|
agentName: input.agentName,
|
|
@@ -3724,7 +3788,7 @@ var import_ws = __toESM(require("ws"));
|
|
|
3724
3788
|
// package.json
|
|
3725
3789
|
var package_default = {
|
|
3726
3790
|
name: "@wagemule/daemon",
|
|
3727
|
-
version: "0.1.
|
|
3791
|
+
version: "0.1.2",
|
|
3728
3792
|
private: false,
|
|
3729
3793
|
description: "Wage Mule local daemon for connecting local agent runtimes to Workspace Server.",
|
|
3730
3794
|
main: "./dist/main.cjs",
|
|
@@ -4706,9 +4770,7 @@ var WorkspaceBrowser = class {
|
|
|
4706
4770
|
}
|
|
4707
4771
|
rootDirForAgent(agentId, serverNamespace, machineId) {
|
|
4708
4772
|
if (typeof this.options === "function") return this.options(agentId);
|
|
4709
|
-
|
|
4710
|
-
if (!scope) return void 0;
|
|
4711
|
-
return import_node_path12.default.join(this.options.rootDir, scope.serverNamespace, scope.machineId, agentId);
|
|
4773
|
+
return this.options.workspaceDirectoryForAgent(agentId, serverNamespace, machineId);
|
|
4712
4774
|
}
|
|
4713
4775
|
resolveInside(base, relativePath) {
|
|
4714
4776
|
const resolved = import_node_path12.default.resolve(base, relativePath);
|
|
@@ -4723,6 +4785,21 @@ function isSafeWorkspaceDirectoryName(directoryName) {
|
|
|
4723
4785
|
directoryName && directoryName !== "." && directoryName !== ".." && !directoryName.includes("/") && !directoryName.includes("\\") && !directoryName.includes("..")
|
|
4724
4786
|
);
|
|
4725
4787
|
}
|
|
4788
|
+
function displayNameToWorkspaceDirectoryName(displayName, fallback = "machine") {
|
|
4789
|
+
const cleaned = displayName.trim().normalize("NFKC").replace(/[\/\\:]+/g, "-").replace(/\s+/g, "-").replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^[.-]+|[.-]+$/g, "").slice(0, 80);
|
|
4790
|
+
return cleaned || fallback;
|
|
4791
|
+
}
|
|
4792
|
+
function namedWorkspaceDirectoryName(displayName, id, fallback = "item") {
|
|
4793
|
+
const namePart = displayNameToWorkspaceDirectoryName(displayName, fallback);
|
|
4794
|
+
const idPart = workspaceDirectoryIdPart(namePart, id);
|
|
4795
|
+
return `${namePart}-${idPart}`;
|
|
4796
|
+
}
|
|
4797
|
+
function workspaceDirectoryIdPart(namePart, id) {
|
|
4798
|
+
let idPart = displayNameToWorkspaceDirectoryName(id, "id");
|
|
4799
|
+
if (idPart.startsWith(`${namePart}-`)) idPart = idPart.slice(namePart.length + 1);
|
|
4800
|
+
idPart = idPart.replace(/^(machine|agent|org)[_-]/, "");
|
|
4801
|
+
return idPart || displayNameToWorkspaceDirectoryName(id, "id");
|
|
4802
|
+
}
|
|
4726
4803
|
|
|
4727
4804
|
// src/agent-manager/agent-process-manager.ts
|
|
4728
4805
|
var AgentProcessManager = class {
|
|
@@ -4731,9 +4808,11 @@ var AgentProcessManager = class {
|
|
|
4731
4808
|
this.modelDetector = options.modelDetector ?? new RuntimeModelDetector();
|
|
4732
4809
|
this.browser = new WorkspaceBrowser({
|
|
4733
4810
|
rootDir: this.options.rootDir,
|
|
4734
|
-
|
|
4811
|
+
workspaceDirectoryForAgent: (agentId, serverNamespace, machineId) => {
|
|
4735
4812
|
const config = this.running.get(agentId)?.config ?? this.idleConfigs.get(agentId)?.config;
|
|
4736
|
-
|
|
4813
|
+
if (config) return this.resolveWorkspaceDirectory(config, agentId);
|
|
4814
|
+
if (serverNamespace && machineId) return this.resolveWorkspaceDirectoryForParts(machineId, machineId, agentId, agentId);
|
|
4815
|
+
return void 0;
|
|
4737
4816
|
}
|
|
4738
4817
|
});
|
|
4739
4818
|
this.reminderCache.onFire((job) => {
|
|
@@ -4801,9 +4880,9 @@ var AgentProcessManager = class {
|
|
|
4801
4880
|
} else if (message.type === "agent:workspace:list") {
|
|
4802
4881
|
await this.replyWorkspaceList(message.agentId, message.requestId, message.path, message.serverNamespace, message.machineId, message.config);
|
|
4803
4882
|
} else if (message.type === "agent:workspace:read") {
|
|
4804
|
-
await this.replyWorkspaceRead(message.agentId, message.requestId, message.path, message.serverNamespace, message.machineId);
|
|
4883
|
+
await this.replyWorkspaceRead(message.agentId, message.requestId, message.path, message.serverNamespace, message.machineId, message.config);
|
|
4805
4884
|
} else if (message.type === "agent:workspace:write") {
|
|
4806
|
-
await this.replyWorkspaceWrite(message.agentId, message.requestId, message.path, message.content, message.serverNamespace, message.machineId);
|
|
4885
|
+
await this.replyWorkspaceWrite(message.agentId, message.requestId, message.path, message.content, message.serverNamespace, message.machineId, message.config);
|
|
4807
4886
|
} else if (message.type === "agent:skills:list") {
|
|
4808
4887
|
await this.replyAgentSkillsList(message.agentId, message.requestId, message.runtime, message.serverNamespace, message.machineId, message.config);
|
|
4809
4888
|
} else if (message.type === "agent:workspace:init") {
|
|
@@ -4834,9 +4913,9 @@ var AgentProcessManager = class {
|
|
|
4834
4913
|
const results = await this.detectRuntimeModels(message.runtimes ?? ["cursor", "claude", "codex", "gemini", "kimi", "hermes", "opencode"]);
|
|
4835
4914
|
this.options.sendToServer({ type: "machine:runtime_models:result", requestId: message.requestId, results });
|
|
4836
4915
|
} else if (message.type === "machine:workspace:scan") {
|
|
4837
|
-
await this.replyMachineWorkspaceScan(message.requestId, message.serverNamespace, message.machineId, message.knownAgentIds ?? []);
|
|
4916
|
+
await this.replyMachineWorkspaceScan(message.requestId, message.serverNamespace, message.machineId, message.machineName, message.knownAgentIds ?? []);
|
|
4838
4917
|
} else if (message.type === "machine:workspace:delete") {
|
|
4839
|
-
await this.replyMachineWorkspaceDelete(message.requestId, message.serverNamespace, message.machineId, message.directoryName);
|
|
4918
|
+
await this.replyMachineWorkspaceDelete(message.requestId, message.serverNamespace, message.machineId, message.machineName, message.directoryName);
|
|
4840
4919
|
} else if (message.type === "agent:reset-workspace") {
|
|
4841
4920
|
await this.replyResetWorkspace(message.requestId, message.agentId, message.config);
|
|
4842
4921
|
} else if (message.type === "agent:diagnostic") {
|
|
@@ -4973,7 +5052,9 @@ var AgentProcessManager = class {
|
|
|
4973
5052
|
rootDir: this.options.rootDir,
|
|
4974
5053
|
serverNamespace: config.serverNamespace,
|
|
4975
5054
|
serverId: config.spaceId,
|
|
5055
|
+
machineDirectoryName: this.machineDirectoryName(config),
|
|
4976
5056
|
machineId: config.machineId,
|
|
5057
|
+
agentDirectoryName: this.agentDirectoryName(config, agentId),
|
|
4977
5058
|
daemonId: import_node_os8.default.hostname() || "local-daemon",
|
|
4978
5059
|
agentId,
|
|
4979
5060
|
agentName: config.agentName,
|
|
@@ -5043,16 +5124,18 @@ var AgentProcessManager = class {
|
|
|
5043
5124
|
}
|
|
5044
5125
|
async ensureAgentWorkspace(agentId, config) {
|
|
5045
5126
|
const running = this.running.get(agentId);
|
|
5046
|
-
if (running) return { workspace: running.workspace };
|
|
5127
|
+
if (running && !config?.feishuDelegationEnabled) return { workspace: running.workspace };
|
|
5047
5128
|
const idle = this.idleConfigs.get(agentId);
|
|
5048
|
-
if (idle?.workspace) return { workspace: idle.workspace };
|
|
5129
|
+
if (idle?.workspace && !config?.feishuDelegationEnabled) return { workspace: idle.workspace };
|
|
5049
5130
|
const effectiveConfig = config ?? idle?.config;
|
|
5050
5131
|
if (!effectiveConfig) return { missing: true };
|
|
5051
5132
|
const workspace = await createAgentWorkspace({
|
|
5052
5133
|
rootDir: this.options.rootDir,
|
|
5053
5134
|
serverNamespace: effectiveConfig.serverNamespace,
|
|
5054
5135
|
serverId: effectiveConfig.spaceId,
|
|
5136
|
+
machineDirectoryName: this.machineDirectoryName(effectiveConfig),
|
|
5055
5137
|
machineId: effectiveConfig.machineId,
|
|
5138
|
+
agentDirectoryName: this.agentDirectoryName(effectiveConfig, agentId),
|
|
5056
5139
|
daemonId: import_node_os8.default.hostname() || "local-daemon",
|
|
5057
5140
|
agentId,
|
|
5058
5141
|
agentName: effectiveConfig.agentName,
|
|
@@ -5060,6 +5143,10 @@ var AgentProcessManager = class {
|
|
|
5060
5143
|
role: effectiveConfig.role,
|
|
5061
5144
|
feishuDelegationEnabled: effectiveConfig.feishuDelegationEnabled
|
|
5062
5145
|
});
|
|
5146
|
+
if (running) {
|
|
5147
|
+
running.workspace = workspace;
|
|
5148
|
+
running.config = effectiveConfig;
|
|
5149
|
+
}
|
|
5063
5150
|
this.idleConfigs.set(agentId, { config: effectiveConfig, sessionId: effectiveConfig.sessionId, workspace });
|
|
5064
5151
|
return { workspace };
|
|
5065
5152
|
}
|
|
@@ -5071,7 +5158,7 @@ var AgentProcessManager = class {
|
|
|
5071
5158
|
requestId,
|
|
5072
5159
|
agentId,
|
|
5073
5160
|
ok: true,
|
|
5074
|
-
workspacePath: workspace ?
|
|
5161
|
+
workspacePath: workspace ? this.workspaceDisplayPath(config, agentId) : void 0
|
|
5075
5162
|
});
|
|
5076
5163
|
} catch (error) {
|
|
5077
5164
|
this.options.sendToServer({
|
|
@@ -5651,9 +5738,7 @@ var AgentProcessManager = class {
|
|
|
5651
5738
|
return;
|
|
5652
5739
|
}
|
|
5653
5740
|
const effectiveConfig = config ?? this.running.get(agentId)?.config ?? this.idleConfigs.get(agentId)?.config;
|
|
5654
|
-
const
|
|
5655
|
-
const machine = machineId ?? effectiveConfig?.machineId;
|
|
5656
|
-
const entries = await this.browser.listFiles(agentId, dirPath, namespace, machine);
|
|
5741
|
+
const entries = await this.browser.listFiles(agentId, dirPath, serverNamespace ?? effectiveConfig?.serverNamespace, machineId ?? effectiveConfig?.machineId);
|
|
5657
5742
|
this.options.sendToServer({ type: "agent:workspace:file_tree", agentId, requestId, entries });
|
|
5658
5743
|
} catch (error) {
|
|
5659
5744
|
this.log(`workspace list failed agent=${agentId} request=${requestId} error=${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -5666,10 +5751,11 @@ var AgentProcessManager = class {
|
|
|
5666
5751
|
});
|
|
5667
5752
|
}
|
|
5668
5753
|
}
|
|
5669
|
-
async replyWorkspaceRead(agentId, requestId, filePath, serverNamespace, machineId) {
|
|
5754
|
+
async replyWorkspaceRead(agentId, requestId, filePath, serverNamespace, machineId, config) {
|
|
5670
5755
|
try {
|
|
5671
5756
|
this.log(`workspace read agent=${agentId} request=${requestId} path=${filePath}`);
|
|
5672
|
-
const
|
|
5757
|
+
const effectiveConfig = config ?? this.running.get(agentId)?.config ?? this.idleConfigs.get(agentId)?.config;
|
|
5758
|
+
const file = await this.browser.readFile(agentId, filePath, serverNamespace ?? effectiveConfig?.serverNamespace, machineId ?? effectiveConfig?.machineId);
|
|
5673
5759
|
this.options.sendToServer({ type: "agent:workspace:file_content", agentId, requestId, file });
|
|
5674
5760
|
} catch (error) {
|
|
5675
5761
|
this.log(`workspace read failed agent=${agentId} request=${requestId} error=${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -5682,10 +5768,11 @@ var AgentProcessManager = class {
|
|
|
5682
5768
|
});
|
|
5683
5769
|
}
|
|
5684
5770
|
}
|
|
5685
|
-
async replyWorkspaceWrite(agentId, requestId, filePath, content, serverNamespace, machineId) {
|
|
5771
|
+
async replyWorkspaceWrite(agentId, requestId, filePath, content, serverNamespace, machineId, config) {
|
|
5686
5772
|
try {
|
|
5687
5773
|
this.log(`workspace write agent=${agentId} request=${requestId} path=${filePath}`);
|
|
5688
|
-
const
|
|
5774
|
+
const effectiveConfig = config ?? this.running.get(agentId)?.config ?? this.idleConfigs.get(agentId)?.config;
|
|
5775
|
+
const result = await this.browser.writeFile(agentId, filePath, content, serverNamespace ?? effectiveConfig?.serverNamespace, machineId ?? effectiveConfig?.machineId);
|
|
5689
5776
|
this.options.sendToServer({ type: "agent:workspace:write_result", agentId, requestId, ...result });
|
|
5690
5777
|
} catch (error) {
|
|
5691
5778
|
this.options.sendToServer({
|
|
@@ -5708,7 +5795,9 @@ var AgentProcessManager = class {
|
|
|
5708
5795
|
const result = await scanAgentSkills({
|
|
5709
5796
|
rootDir: this.options.rootDir,
|
|
5710
5797
|
serverNamespace: namespace,
|
|
5798
|
+
machineDirectoryName: this.machineDirectoryName(effectiveConfig),
|
|
5711
5799
|
machineId: machine,
|
|
5800
|
+
agentDirectoryName: effectiveConfig ? this.agentDirectoryName(effectiveConfig, agentId) : namedWorkspaceDirectoryName(agentId, agentId, "agent"),
|
|
5712
5801
|
agentId,
|
|
5713
5802
|
runtime
|
|
5714
5803
|
});
|
|
@@ -5724,9 +5813,9 @@ var AgentProcessManager = class {
|
|
|
5724
5813
|
});
|
|
5725
5814
|
}
|
|
5726
5815
|
}
|
|
5727
|
-
async replyMachineWorkspaceScan(requestId, serverNamespace, machineId, knownAgentIds) {
|
|
5816
|
+
async replyMachineWorkspaceScan(requestId, serverNamespace, machineId, machineName, knownAgentIds) {
|
|
5728
5817
|
try {
|
|
5729
|
-
const entries = await this.scanWorkspaces(serverNamespace, machineId, new Set(knownAgentIds));
|
|
5818
|
+
const entries = await this.scanWorkspaces(serverNamespace, machineId, machineName, new Set(knownAgentIds));
|
|
5730
5819
|
this.options.sendToServer({ type: "machine:workspace:scan/result", requestId, entries });
|
|
5731
5820
|
} catch (error) {
|
|
5732
5821
|
this.options.sendToServer({
|
|
@@ -5737,11 +5826,11 @@ var AgentProcessManager = class {
|
|
|
5737
5826
|
});
|
|
5738
5827
|
}
|
|
5739
5828
|
}
|
|
5740
|
-
async replyMachineWorkspaceDelete(requestId, serverNamespace, machineId, directoryName) {
|
|
5829
|
+
async replyMachineWorkspaceDelete(requestId, serverNamespace, machineId, machineName, directoryName) {
|
|
5741
5830
|
try {
|
|
5742
5831
|
if (!isSafeWorkspaceDirectoryName(directoryName)) throw new Error("unsafe workspace directory name");
|
|
5743
5832
|
if (this.running.has(directoryName) || this.starting.has(directoryName)) throw new Error("cannot delete a running workspace");
|
|
5744
|
-
const target = this.
|
|
5833
|
+
const target = this.resolveWorkspaceDirectoryName(machineName ?? machineId, machineId, directoryName);
|
|
5745
5834
|
await (0, import_promises12.rm)(target, { recursive: true, force: true });
|
|
5746
5835
|
this.options.sendToServer({ type: "machine:workspace:delete/result", requestId, directoryName, ok: true });
|
|
5747
5836
|
} catch (error) {
|
|
@@ -5757,13 +5846,15 @@ var AgentProcessManager = class {
|
|
|
5757
5846
|
async replyResetWorkspace(requestId, agentId, config) {
|
|
5758
5847
|
try {
|
|
5759
5848
|
await this.stopAgent(agentId, "reset-workspace");
|
|
5760
|
-
const target = this.resolveWorkspaceDirectory(config
|
|
5849
|
+
const target = this.resolveWorkspaceDirectory(config, agentId);
|
|
5761
5850
|
await (0, import_promises12.rm)(target, { recursive: true, force: true });
|
|
5762
5851
|
const workspace = await createAgentWorkspace({
|
|
5763
5852
|
rootDir: this.options.rootDir,
|
|
5764
5853
|
serverNamespace: config.serverNamespace,
|
|
5765
5854
|
serverId: config.spaceId,
|
|
5855
|
+
machineDirectoryName: this.machineDirectoryName(config),
|
|
5766
5856
|
machineId: config.machineId,
|
|
5857
|
+
agentDirectoryName: this.agentDirectoryName(config, agentId),
|
|
5767
5858
|
daemonId: import_node_os8.default.hostname() || "local-daemon",
|
|
5768
5859
|
agentId,
|
|
5769
5860
|
agentName: config.agentName,
|
|
@@ -5808,7 +5899,7 @@ var AgentProcessManager = class {
|
|
|
5808
5899
|
const idle = this.idleConfigs.get(agentId);
|
|
5809
5900
|
const effectiveConfig = running?.config ?? idle?.config ?? config;
|
|
5810
5901
|
const workspace = running?.workspace ?? idle?.workspace;
|
|
5811
|
-
const workspacePath = workspace?.agentDir ?? (effectiveConfig ? this.resolveWorkspaceDirectory(effectiveConfig
|
|
5902
|
+
const workspacePath = workspace?.agentDir ?? (effectiveConfig ? this.resolveWorkspaceDirectory(effectiveConfig, agentId) : void 0);
|
|
5812
5903
|
const workspaceExists = workspacePath ? await pathExists(workspacePath) : false;
|
|
5813
5904
|
return {
|
|
5814
5905
|
agentId,
|
|
@@ -5824,8 +5915,8 @@ var AgentProcessManager = class {
|
|
|
5824
5915
|
lastActivity: this.lastActivities.get(agentId)
|
|
5825
5916
|
};
|
|
5826
5917
|
}
|
|
5827
|
-
async scanWorkspaces(serverNamespace, machineId, knownAgentIds) {
|
|
5828
|
-
const machineRoot = this.resolveMachineRoot(
|
|
5918
|
+
async scanWorkspaces(serverNamespace, machineId, machineName, knownAgentIds) {
|
|
5919
|
+
const machineRoot = this.resolveMachineRoot(machineName ?? machineId, machineId);
|
|
5829
5920
|
const names = await (0, import_promises12.readdir)(machineRoot, { withFileTypes: true }).catch((error) => {
|
|
5830
5921
|
if (error.code === "ENOENT") return [];
|
|
5831
5922
|
throw error;
|
|
@@ -5833,14 +5924,15 @@ var AgentProcessManager = class {
|
|
|
5833
5924
|
const entries = [];
|
|
5834
5925
|
for (const entry of names) {
|
|
5835
5926
|
if (!entry.isDirectory() || !isSafeWorkspaceDirectoryName(entry.name)) continue;
|
|
5836
|
-
const fullPath = this.
|
|
5927
|
+
const fullPath = this.resolveWorkspaceDirectoryName(machineName ?? machineId, machineId, entry.name);
|
|
5837
5928
|
const summary = await summarizeDirectory(fullPath);
|
|
5929
|
+
const agentId = agentIdFromDirectoryName(entry.name, knownAgentIds);
|
|
5838
5930
|
entries.push({
|
|
5839
5931
|
directoryName: entry.name,
|
|
5840
|
-
agentId
|
|
5841
|
-
workspacePath: `~/.wm/${
|
|
5842
|
-
knownToServer: knownAgentIds.has(
|
|
5843
|
-
running: this.running.has(
|
|
5932
|
+
agentId,
|
|
5933
|
+
workspacePath: `~/.wm/${this.machineDirectoryNameForParts(machineName ?? machineId, machineId)}/${entry.name}/`,
|
|
5934
|
+
knownToServer: knownAgentIds.has(agentId),
|
|
5935
|
+
running: this.running.has(agentId) || this.starting.has(agentId),
|
|
5844
5936
|
fileCount: summary.fileCount,
|
|
5845
5937
|
totalSizeBytes: summary.totalSizeBytes,
|
|
5846
5938
|
lastModified: summary.lastModified
|
|
@@ -5848,25 +5940,36 @@ var AgentProcessManager = class {
|
|
|
5848
5940
|
}
|
|
5849
5941
|
return entries.sort((a, b) => b.lastModified - a.lastModified || a.directoryName.localeCompare(b.directoryName));
|
|
5850
5942
|
}
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5943
|
+
resolveMachineRoot(machineName, machineId) {
|
|
5944
|
+
const machineDirectoryName = this.machineDirectoryNameForParts(machineName, machineId);
|
|
5945
|
+
if (!isSafeWorkspaceDirectoryName(machineDirectoryName)) throw new Error("unsafe machine directory");
|
|
5946
|
+
const resolved = import_node_path13.default.resolve(this.options.rootDir, machineDirectoryName);
|
|
5854
5947
|
const base = import_node_path13.default.resolve(this.options.rootDir);
|
|
5855
5948
|
if (resolved !== base && !resolved.startsWith(`${base}${import_node_path13.default.sep}`)) throw new Error("workspace root escapes daemon root");
|
|
5856
5949
|
return resolved;
|
|
5857
5950
|
}
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
return
|
|
5951
|
+
machineDirectoryName(config) {
|
|
5952
|
+
return this.machineDirectoryNameForParts(config?.machineName ?? this.options.machineDisplayName, config?.machineId ?? "machine");
|
|
5953
|
+
}
|
|
5954
|
+
machineDirectoryNameForParts(machineName, machineId) {
|
|
5955
|
+
return namedWorkspaceDirectoryName(machineName, machineId, "machine");
|
|
5956
|
+
}
|
|
5957
|
+
agentDirectoryName(config, agentId) {
|
|
5958
|
+
return namedWorkspaceDirectoryName(config.agentName, agentId, "agent");
|
|
5959
|
+
}
|
|
5960
|
+
workspaceDisplayPath(config, agentId) {
|
|
5961
|
+
return `~/.wm/${this.machineDirectoryName(config)}/${this.agentDirectoryName(config, agentId)}/`;
|
|
5866
5962
|
}
|
|
5867
|
-
resolveWorkspaceDirectory(
|
|
5963
|
+
resolveWorkspaceDirectory(config, agentId) {
|
|
5964
|
+
return this.resolveWorkspaceDirectoryForParts(config.machineName ?? this.options.machineDisplayName, config.machineId, config.agentName, agentId);
|
|
5965
|
+
}
|
|
5966
|
+
resolveWorkspaceDirectoryForParts(machineName, machineId, agentName, agentId) {
|
|
5967
|
+
const directoryName = namedWorkspaceDirectoryName(agentName, agentId, "agent");
|
|
5968
|
+
return this.resolveWorkspaceDirectoryName(machineName, machineId, directoryName);
|
|
5969
|
+
}
|
|
5970
|
+
resolveWorkspaceDirectoryName(machineName, machineId, directoryName) {
|
|
5868
5971
|
if (!isSafeWorkspaceDirectoryName(directoryName)) throw new Error("unsafe workspace directory name");
|
|
5869
|
-
const machineRoot = this.resolveMachineRoot(
|
|
5972
|
+
const machineRoot = this.resolveMachineRoot(machineName, machineId);
|
|
5870
5973
|
const resolved = import_node_path13.default.resolve(machineRoot, directoryName);
|
|
5871
5974
|
if (resolved !== machineRoot && !resolved.startsWith(`${machineRoot}${import_node_path13.default.sep}`)) {
|
|
5872
5975
|
throw new Error("workspace directory escapes machine root");
|
|
@@ -6029,6 +6132,12 @@ async function summarizeDirectory(root) {
|
|
|
6029
6132
|
await visit(root);
|
|
6030
6133
|
return { fileCount, totalSizeBytes, lastModified };
|
|
6031
6134
|
}
|
|
6135
|
+
function agentIdFromDirectoryName(directoryName, knownAgentIds) {
|
|
6136
|
+
for (const agentId of knownAgentIds) {
|
|
6137
|
+
if (directoryName.endsWith(`-${agentId}`)) return agentId;
|
|
6138
|
+
}
|
|
6139
|
+
return directoryName;
|
|
6140
|
+
}
|
|
6032
6141
|
async function pathExists(targetPath) {
|
|
6033
6142
|
try {
|
|
6034
6143
|
await (0, import_promises12.stat)(targetPath);
|
|
@@ -6129,6 +6238,7 @@ async function runDaemon(input) {
|
|
|
6129
6238
|
let connection;
|
|
6130
6239
|
const manager = new AgentProcessManager({
|
|
6131
6240
|
rootDir: input.rootDir,
|
|
6241
|
+
machineDisplayName: input.name?.trim() || import_node_os9.default.hostname() || "machine",
|
|
6132
6242
|
sendToServer: (msg) => connection.send(msg),
|
|
6133
6243
|
log
|
|
6134
6244
|
});
|