@agentmeshhq/agent 0.1.13 → 0.1.14
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/__tests__/loader.test.js +44 -1
- package/dist/__tests__/loader.test.js.map +1 -1
- package/dist/__tests__/runner.test.js.map +1 -1
- package/dist/__tests__/sandbox.test.js.map +1 -1
- package/dist/__tests__/watchdog.test.d.ts +1 -0
- package/dist/__tests__/watchdog.test.js +290 -0
- package/dist/__tests__/watchdog.test.js.map +1 -0
- package/dist/cli/attach.js +20 -1
- package/dist/cli/attach.js.map +1 -1
- package/dist/cli/build.js +8 -2
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/context.js.map +1 -1
- package/dist/cli/deploy.js +1 -1
- package/dist/cli/deploy.js.map +1 -1
- package/dist/cli/init.js +1 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/list.js +3 -3
- package/dist/cli/list.js.map +1 -1
- package/dist/cli/local.js +5 -3
- package/dist/cli/local.js.map +1 -1
- package/dist/cli/migrate.js +1 -1
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/nudge.js +16 -3
- package/dist/cli/nudge.js.map +1 -1
- package/dist/cli/restart.js.map +1 -1
- package/dist/cli/slack.js +1 -1
- package/dist/cli/slack.js.map +1 -1
- package/dist/cli/stop.js +13 -5
- package/dist/cli/stop.js.map +1 -1
- package/dist/cli/test.js +1 -1
- package/dist/cli/test.js.map +1 -1
- package/dist/cli/token.js +2 -2
- package/dist/cli/token.js.map +1 -1
- package/dist/config/loader.d.ts +5 -1
- package/dist/config/loader.js +27 -2
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +13 -0
- package/dist/core/daemon.d.ts +32 -1
- package/dist/core/daemon.js +362 -19
- package/dist/core/daemon.js.map +1 -1
- package/dist/core/injector.d.ts +2 -2
- package/dist/core/injector.js +23 -4
- package/dist/core/injector.js.map +1 -1
- package/dist/core/runner.d.ts +1 -1
- package/dist/core/runner.js +23 -1
- package/dist/core/runner.js.map +1 -1
- package/dist/core/sandbox.d.ts +11 -0
- package/dist/core/sandbox.js +34 -2
- package/dist/core/sandbox.js.map +1 -1
- package/dist/core/tmux.d.ts +8 -0
- package/dist/core/tmux.js +28 -1
- package/dist/core/tmux.js.map +1 -1
- package/dist/core/watchdog.d.ts +41 -0
- package/dist/core/watchdog.js +198 -0
- package/dist/core/watchdog.js.map +1 -0
- package/dist/core/websocket.js +1 -1
- package/dist/core/websocket.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/loader.test.ts +52 -4
- package/src/__tests__/runner.test.ts +1 -2
- package/src/__tests__/sandbox.test.ts +1 -1
- package/src/__tests__/watchdog.test.ts +368 -0
- package/src/cli/attach.ts +22 -1
- package/src/cli/build.ts +12 -4
- package/src/cli/context.ts +0 -1
- package/src/cli/deploy.ts +7 -5
- package/src/cli/init.ts +7 -19
- package/src/cli/list.ts +6 -10
- package/src/cli/local.ts +21 -12
- package/src/cli/migrate.ts +6 -4
- package/src/cli/nudge.ts +29 -14
- package/src/cli/restart.ts +1 -1
- package/src/cli/slack.ts +16 -15
- package/src/cli/stop.ts +14 -5
- package/src/cli/test.ts +5 -3
- package/src/cli/token.ts +4 -4
- package/src/config/loader.ts +29 -2
- package/src/config/schema.ts +14 -0
- package/src/core/daemon.ts +439 -24
- package/src/core/injector.ts +27 -4
- package/src/core/runner.ts +26 -1
- package/src/core/sandbox.ts +47 -2
- package/src/core/tmux.ts +35 -2
- package/src/core/watchdog.ts +238 -0
- package/src/core/websocket.ts +2 -2
- package/src/index.ts +6 -5
package/src/cli/list.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { loadState, loadConfig } from "../config/loader.js";
|
|
2
|
-
import { sessionExists, getSessionName, getSessionInfo } from "../core/tmux.js";
|
|
3
|
-
import { checkInbox, fetchAssignments } from "../core/registry.js";
|
|
4
1
|
import pc from "picocolors";
|
|
2
|
+
import { loadConfig, loadState } from "../config/loader.js";
|
|
3
|
+
import { checkInbox, fetchAssignments } from "../core/registry.js";
|
|
4
|
+
import { getSessionInfo, getSessionName, sessionExists } from "../core/tmux.js";
|
|
5
5
|
|
|
6
6
|
export async function list(): Promise<void> {
|
|
7
7
|
const state = loadState();
|
|
@@ -15,7 +15,7 @@ export async function list(): Promise<void> {
|
|
|
15
15
|
|
|
16
16
|
console.log(pc.bold("Running Agents:\n"));
|
|
17
17
|
console.log(
|
|
18
|
-
`${"NAME".padEnd(20)} ${"STATUS".padEnd(10)} ${"SESSION".padEnd(25)} ${"PENDING ID".padEnd(18)} ${"WORKDIR".padEnd(38)} ${"PROJECT"}
|
|
18
|
+
`${"NAME".padEnd(20)} ${"STATUS".padEnd(10)} ${"SESSION".padEnd(25)} ${"PENDING ID".padEnd(18)} ${"WORKDIR".padEnd(38)} ${"PROJECT"}`,
|
|
19
19
|
);
|
|
20
20
|
console.log("-".repeat(140));
|
|
21
21
|
|
|
@@ -35,11 +35,7 @@ export async function list(): Promise<void> {
|
|
|
35
35
|
// Try to check inbox if we have a token
|
|
36
36
|
if (config && agent.token) {
|
|
37
37
|
try {
|
|
38
|
-
const items = await checkInbox(
|
|
39
|
-
config.hubUrl,
|
|
40
|
-
config.workspace,
|
|
41
|
-
agent.token
|
|
42
|
-
);
|
|
38
|
+
const items = await checkInbox(config.hubUrl, config.workspace, agent.token);
|
|
43
39
|
if (items.length > 0) {
|
|
44
40
|
const firstId = items[0]?.id || "-";
|
|
45
41
|
pendingId = pc.yellow(items.length === 1 ? firstId : `${firstId} (+${items.length - 1})`);
|
|
@@ -62,7 +58,7 @@ export async function list(): Promise<void> {
|
|
|
62
58
|
const workdir = agent.workdir || "-";
|
|
63
59
|
|
|
64
60
|
console.log(
|
|
65
|
-
`${agent.name.padEnd(20)} ${status.padEnd(19)} ${sessionName.padEnd(25)} ${pendingId.padEnd(18)} ${workdir.padEnd(38)} ${assignedProject}
|
|
61
|
+
`${agent.name.padEnd(20)} ${status.padEnd(19)} ${sessionName.padEnd(25)} ${pendingId.padEnd(18)} ${workdir.padEnd(38)} ${assignedProject}`,
|
|
66
62
|
);
|
|
67
63
|
|
|
68
64
|
if (command) {
|
package/src/cli/local.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execSync, spawn, spawnSync } from "node:child_process";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import pc from "picocolors";
|
|
4
4
|
|
|
@@ -24,14 +24,20 @@ function findProjectRoot(): string {
|
|
|
24
24
|
dir = path.dirname(dir);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
throw new Error(
|
|
27
|
+
throw new Error(
|
|
28
|
+
"Could not find AgentMesh project root. Make sure you're in the agentmesh repository.",
|
|
29
|
+
);
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
function getContainerStatus(containerName: string): {
|
|
32
|
+
function getContainerStatus(containerName: string): {
|
|
33
|
+
running: boolean;
|
|
34
|
+
healthy: boolean;
|
|
35
|
+
port?: string;
|
|
36
|
+
} {
|
|
31
37
|
try {
|
|
32
38
|
const result = execSync(
|
|
33
39
|
`docker inspect --format='{{.State.Running}}:{{.State.Health.Status}}' ${containerName} 2>/dev/null`,
|
|
34
|
-
{ encoding: "utf-8" }
|
|
40
|
+
{ encoding: "utf-8" },
|
|
35
41
|
).trim();
|
|
36
42
|
const [running, health] = result.split(":");
|
|
37
43
|
return {
|
|
@@ -45,10 +51,9 @@ function getContainerStatus(containerName: string): { running: boolean; healthy:
|
|
|
45
51
|
|
|
46
52
|
function getContainerPort(containerName: string, internalPort: number): string | null {
|
|
47
53
|
try {
|
|
48
|
-
const result = execSync(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
).trim();
|
|
54
|
+
const result = execSync(`docker port ${containerName} ${internalPort} 2>/dev/null | head -1`, {
|
|
55
|
+
encoding: "utf-8",
|
|
56
|
+
}).trim();
|
|
52
57
|
// Format: 0.0.0.0:5432 -> 5432
|
|
53
58
|
const match = result.match(/:(\d+)$/);
|
|
54
59
|
return match ? match[1] : null;
|
|
@@ -119,7 +124,7 @@ export async function localStatus(): Promise<void> {
|
|
|
119
124
|
|
|
120
125
|
console.log(pc.bold("AgentMesh Local Stack Status"));
|
|
121
126
|
console.log();
|
|
122
|
-
console.log(pc.dim("Service".padEnd(15) + "Status".padEnd(12) + "Health".padEnd(10)
|
|
127
|
+
console.log(pc.dim(`${"Service".padEnd(15) + "Status".padEnd(12) + "Health".padEnd(10)}Port`));
|
|
123
128
|
console.log(pc.dim("-".repeat(50)));
|
|
124
129
|
|
|
125
130
|
let anyRunning = false;
|
|
@@ -137,7 +142,7 @@ export async function localStatus(): Promise<void> {
|
|
|
137
142
|
const portText = port ? pc.cyan(port) : pc.dim("-");
|
|
138
143
|
|
|
139
144
|
console.log(
|
|
140
|
-
`${service.name.padEnd(15)}${statusText.padEnd(20)}${healthText.padEnd(18)}${portText}
|
|
145
|
+
`${service.name.padEnd(15)}${statusText.padEnd(20)}${healthText.padEnd(18)}${portText}`,
|
|
141
146
|
);
|
|
142
147
|
|
|
143
148
|
if (status.running) anyRunning = true;
|
|
@@ -153,13 +158,17 @@ export async function localStatus(): Promise<void> {
|
|
|
153
158
|
console.log();
|
|
154
159
|
console.log(pc.bold("Commands:"));
|
|
155
160
|
console.log(` Stop: ${pc.cyan("agentmesh local down")}`);
|
|
156
|
-
console.log(
|
|
161
|
+
console.log(
|
|
162
|
+
` Logs: ${pc.cyan("docker compose -f docker/docker-compose.local.yml logs -f")}`,
|
|
163
|
+
);
|
|
157
164
|
} else {
|
|
158
165
|
console.log(pc.dim("No services running. Start with: agentmesh local up"));
|
|
159
166
|
}
|
|
160
167
|
}
|
|
161
168
|
|
|
162
|
-
export async function localLogs(
|
|
169
|
+
export async function localLogs(
|
|
170
|
+
options: { follow?: boolean; service?: string } = {},
|
|
171
|
+
): Promise<void> {
|
|
163
172
|
const projectRoot = findProjectRoot();
|
|
164
173
|
const composePath = path.join(projectRoot, COMPOSE_FILE);
|
|
165
174
|
|
package/src/cli/migrate.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execSync, spawnSync } from "node:child_process";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import pc from "picocolors";
|
|
4
4
|
|
|
@@ -14,14 +14,16 @@ function findProjectRoot(): string {
|
|
|
14
14
|
dir = path.dirname(dir);
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
throw new Error(
|
|
17
|
+
throw new Error(
|
|
18
|
+
"Could not find AgentMesh project root. Make sure you're in the agentmesh repository.",
|
|
19
|
+
);
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
function isLocalStackRunning(): boolean {
|
|
21
23
|
try {
|
|
22
24
|
const result = execSync(
|
|
23
25
|
'docker inspect --format="{{.State.Running}}" agentmesh_postgres 2>/dev/null',
|
|
24
|
-
{ encoding: "utf-8" }
|
|
26
|
+
{ encoding: "utf-8" },
|
|
25
27
|
).trim();
|
|
26
28
|
return result === "true";
|
|
27
29
|
} catch {
|
|
@@ -84,7 +86,7 @@ async function generateMigration(projectRoot: string): Promise<void> {
|
|
|
84
86
|
|
|
85
87
|
async function migrationStatus(projectRoot: string, options: MigrateOptions): Promise<void> {
|
|
86
88
|
const env = getEnvironmentConfig(options);
|
|
87
|
-
|
|
89
|
+
|
|
88
90
|
console.log(pc.cyan(`Checking migration status for ${env.name}...`));
|
|
89
91
|
console.log();
|
|
90
92
|
|
package/src/cli/nudge.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { sendKeys, sessionExists, getSessionName } from "../core/tmux.js";
|
|
3
|
-
import { registerAgent } from "../core/registry.js";
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
4
2
|
import pc from "picocolors";
|
|
3
|
+
import { getAgentState, loadConfig, loadState } from "../config/loader.js";
|
|
4
|
+
import { registerAgent } from "../core/registry.js";
|
|
5
|
+
import { getSessionName, sendKeys, sessionExists } from "../core/tmux.js";
|
|
5
6
|
|
|
6
7
|
export async function nudge(name: string, message: string): Promise<void> {
|
|
7
8
|
const config = loadConfig();
|
|
@@ -24,6 +25,23 @@ export async function nudge(name: string, message: string): Promise<void> {
|
|
|
24
25
|
// Check if this is a local agent
|
|
25
26
|
const localAgent = getAgentState(name);
|
|
26
27
|
|
|
28
|
+
// Sandbox agent - route nudge through docker exec
|
|
29
|
+
if (localAgent?.sandboxContainer) {
|
|
30
|
+
const result = spawnSync(
|
|
31
|
+
"docker",
|
|
32
|
+
["exec", localAgent.sandboxContainer, "agentmesh", "nudge", name, message],
|
|
33
|
+
{ encoding: "utf-8", stdio: "pipe" },
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
if (result.status === 0) {
|
|
37
|
+
console.log(pc.green(`Nudged "${name}" in sandbox.`));
|
|
38
|
+
} else {
|
|
39
|
+
console.log(pc.red(`Failed to nudge "${name}" in sandbox: ${result.stderr}`));
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Local agent with tmux session on host
|
|
27
45
|
if (localAgent && sessionExists(getSessionName(name))) {
|
|
28
46
|
// Local nudge via tmux send-keys
|
|
29
47
|
const formatted = `[AgentMesh] Nudge from CLI:
|
|
@@ -60,17 +78,14 @@ ${message}`;
|
|
|
60
78
|
model: "cli",
|
|
61
79
|
});
|
|
62
80
|
|
|
63
|
-
const response = await fetch(
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
body: JSON.stringify({ message }),
|
|
72
|
-
}
|
|
73
|
-
);
|
|
81
|
+
const response = await fetch(`${config.hubUrl}/api/v1/agents/${agentState.agentId}/nudge`, {
|
|
82
|
+
method: "POST",
|
|
83
|
+
headers: {
|
|
84
|
+
Authorization: `Bearer ${registration.token}`,
|
|
85
|
+
"Content-Type": "application/json",
|
|
86
|
+
},
|
|
87
|
+
body: JSON.stringify({ message }),
|
|
88
|
+
});
|
|
74
89
|
|
|
75
90
|
if (response.ok) {
|
|
76
91
|
console.log(pc.green(`Nudged "${name}" via API.`));
|
package/src/cli/restart.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import pc from "picocolors";
|
|
2
2
|
import { getAgentState, loadConfig } from "../config/loader.js";
|
|
3
|
-
import {
|
|
3
|
+
import { getSessionName, sessionExists } from "../core/tmux.js";
|
|
4
4
|
import { start } from "./start.js";
|
|
5
5
|
import { stop } from "./stop.js";
|
|
6
6
|
|
package/src/cli/slack.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { loadConfig, getAgentState } from "../config/loader.js";
|
|
2
1
|
import pc from "picocolors";
|
|
2
|
+
import { getAgentState, loadConfig } from "../config/loader.js";
|
|
3
3
|
|
|
4
4
|
export async function slack(
|
|
5
5
|
action: string,
|
|
6
6
|
channel: string | undefined,
|
|
7
7
|
message: string | undefined,
|
|
8
|
-
options: { name?: string }
|
|
8
|
+
options: { name?: string },
|
|
9
9
|
): Promise<void> {
|
|
10
10
|
const config = loadConfig();
|
|
11
11
|
|
|
@@ -16,12 +16,16 @@ export async function slack(
|
|
|
16
16
|
|
|
17
17
|
if (action === "respond" || action === "reply") {
|
|
18
18
|
if (!channel) {
|
|
19
|
-
console.log(
|
|
19
|
+
console.log(
|
|
20
|
+
pc.red("Channel is required. Usage: agentmesh slack respond <channel> <message>"),
|
|
21
|
+
);
|
|
20
22
|
process.exit(1);
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
if (!message) {
|
|
24
|
-
console.log(
|
|
26
|
+
console.log(
|
|
27
|
+
pc.red("Message is required. Usage: agentmesh slack respond <channel> <message>"),
|
|
28
|
+
);
|
|
25
29
|
process.exit(1);
|
|
26
30
|
}
|
|
27
31
|
|
|
@@ -36,17 +40,14 @@ export async function slack(
|
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
try {
|
|
39
|
-
const response = await fetch(
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
body: JSON.stringify({ channel, text: message }),
|
|
48
|
-
}
|
|
49
|
-
);
|
|
43
|
+
const response = await fetch(`${config.hubUrl}/api/v1/integrations/slack/respond`, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: {
|
|
46
|
+
Authorization: `Bearer ${token}`,
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify({ channel, text: message }),
|
|
50
|
+
});
|
|
50
51
|
|
|
51
52
|
if (response.ok) {
|
|
52
53
|
console.log(pc.green(`Message sent to Slack channel ${channel}`));
|
package/src/cli/stop.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { removeAgentFromState, getAgentState } from "../config/loader.js";
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
3
2
|
import pc from "picocolors";
|
|
3
|
+
import { getAgentState, removeAgentFromState } from "../config/loader.js";
|
|
4
|
+
import { destroySession } from "../core/tmux.js";
|
|
4
5
|
|
|
5
6
|
export async function stop(name: string): Promise<void> {
|
|
6
7
|
if (!name) {
|
|
@@ -32,8 +33,16 @@ export async function stop(name: string): Promise<void> {
|
|
|
32
33
|
console.log(pc.green(`Destroyed tmux session for "${name}"`));
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
//
|
|
36
|
-
|
|
36
|
+
// Clean up Docker sandbox container if it exists
|
|
37
|
+
if (state.sandboxContainer) {
|
|
38
|
+
console.log(`Stopping sandbox container: ${state.sandboxContainer}`);
|
|
39
|
+
spawnSync("docker", ["stop", "-t", "5", state.sandboxContainer], { encoding: "utf-8" });
|
|
40
|
+
spawnSync("docker", ["rm", "-f", state.sandboxContainer], { encoding: "utf-8" });
|
|
41
|
+
console.log(pc.green(`Removed sandbox container`));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Remove from state but preserve agentId for re-registration
|
|
45
|
+
removeAgentFromState(name, true);
|
|
37
46
|
|
|
38
|
-
console.log(pc.green(`Agent "${name}" stopped.`));
|
|
47
|
+
console.log(pc.green(`Agent "${name}" stopped (agentId preserved for restart).`));
|
|
39
48
|
}
|
package/src/cli/test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execSync, spawnSync } from "node:child_process";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import pc from "picocolors";
|
|
4
4
|
|
|
@@ -14,14 +14,16 @@ function findProjectRoot(): string {
|
|
|
14
14
|
dir = path.dirname(dir);
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
throw new Error(
|
|
17
|
+
throw new Error(
|
|
18
|
+
"Could not find AgentMesh project root. Make sure you're in the agentmesh repository.",
|
|
19
|
+
);
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
function isLocalStackRunning(): boolean {
|
|
21
23
|
try {
|
|
22
24
|
const result = execSync(
|
|
23
25
|
'docker inspect --format="{{.State.Running}}" agentmesh_postgres 2>/dev/null',
|
|
24
|
-
{ encoding: "utf-8" }
|
|
26
|
+
{ encoding: "utf-8" },
|
|
25
27
|
).trim();
|
|
26
28
|
return result === "true";
|
|
27
29
|
} catch {
|
package/src/cli/token.ts
CHANGED
|
@@ -39,9 +39,9 @@ export async function token(action: string, agentName?: string): Promise<void> {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
async function showToken(
|
|
42
|
-
|
|
42
|
+
_config: ReturnType<typeof loadConfig>,
|
|
43
43
|
agentName?: string,
|
|
44
|
-
|
|
44
|
+
_envAgentId?: string,
|
|
45
45
|
envToken?: string,
|
|
46
46
|
): Promise<void> {
|
|
47
47
|
// If running as agent, show env token
|
|
@@ -134,9 +134,9 @@ async function refreshToken(
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
async function tokenInfo(
|
|
137
|
-
|
|
137
|
+
_config: ReturnType<typeof loadConfig>,
|
|
138
138
|
agentName?: string,
|
|
139
|
-
|
|
139
|
+
_envAgentId?: string,
|
|
140
140
|
envToken?: string,
|
|
141
141
|
): Promise<void> {
|
|
142
142
|
// Get token to inspect
|
package/src/config/loader.ts
CHANGED
|
@@ -58,12 +58,39 @@ export function addAgentToState(agent: AgentState): void {
|
|
|
58
58
|
saveState(state);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
export function removeAgentFromState(name: string): void {
|
|
61
|
+
export function removeAgentFromState(name: string, preserveAgentId = false): void {
|
|
62
62
|
const state = loadState();
|
|
63
|
-
|
|
63
|
+
|
|
64
|
+
if (preserveAgentId) {
|
|
65
|
+
// Keep minimal state with agentId for re-registration
|
|
66
|
+
const existing = state.agents.find((a) => a.name === name);
|
|
67
|
+
if (existing) {
|
|
68
|
+
state.agents = state.agents.filter((a) => a.name !== name);
|
|
69
|
+
// Save only the agentId and restartCount for next startup
|
|
70
|
+
state.agents.push({
|
|
71
|
+
name: existing.name,
|
|
72
|
+
agentId: existing.agentId,
|
|
73
|
+
pid: 0,
|
|
74
|
+
tmuxSession: "",
|
|
75
|
+
startedAt: existing.startedAt,
|
|
76
|
+
restartCount: existing.restartCount,
|
|
77
|
+
status: "stopped",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
state.agents = state.agents.filter((a) => a.name !== name);
|
|
82
|
+
}
|
|
83
|
+
|
|
64
84
|
saveState(state);
|
|
65
85
|
}
|
|
66
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Reset restart count for an agent (called on manual start or after stable period)
|
|
89
|
+
*/
|
|
90
|
+
export function resetAgentRestartCount(name: string): void {
|
|
91
|
+
updateAgentInState(name, { restartCount: 0, stuckSince: undefined, status: "running" });
|
|
92
|
+
}
|
|
93
|
+
|
|
67
94
|
export function getAgentState(name: string): AgentState | undefined {
|
|
68
95
|
const state = loadState();
|
|
69
96
|
return state.agents.find((a) => a.name === name);
|
package/src/config/schema.ts
CHANGED
|
@@ -32,6 +32,8 @@ export const STATE_PATH = `${process.env.HOME}/.agentmesh/state.json`;
|
|
|
32
32
|
|
|
33
33
|
export type RunnerType = "opencode" | "claude" | "custom";
|
|
34
34
|
|
|
35
|
+
export type AgentStatus = "running" | "stopped" | "failed" | "stuck";
|
|
36
|
+
|
|
35
37
|
export interface AgentState {
|
|
36
38
|
name: string;
|
|
37
39
|
agentId: string;
|
|
@@ -45,6 +47,18 @@ export interface AgentState {
|
|
|
45
47
|
runtimeModel?: string;
|
|
46
48
|
/** The runner type (opencode, claude, custom) */
|
|
47
49
|
runnerType?: RunnerType;
|
|
50
|
+
/** Docker container name if running in sandbox mode */
|
|
51
|
+
sandboxContainer?: string;
|
|
52
|
+
/** Number of auto-restart attempts since last manual start */
|
|
53
|
+
restartCount?: number;
|
|
54
|
+
/** ISO timestamp of last auto-restart */
|
|
55
|
+
lastRestartAt?: string;
|
|
56
|
+
/** ISO timestamp of last detected activity */
|
|
57
|
+
lastActivityAt?: string;
|
|
58
|
+
/** ISO timestamp when agent was detected as stuck */
|
|
59
|
+
stuckSince?: string;
|
|
60
|
+
/** Current agent status */
|
|
61
|
+
status?: AgentStatus;
|
|
48
62
|
}
|
|
49
63
|
|
|
50
64
|
export interface State {
|