@agentmeshhq/agent 0.2.0 → 0.3.0
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 +39 -0
- package/dist/__tests__/context-template.test.d.ts +4 -0
- package/dist/__tests__/context-template.test.js +233 -0
- package/dist/__tests__/context-template.test.js.map +1 -0
- package/dist/__tests__/loader.test.js +140 -28
- package/dist/__tests__/loader.test.js.map +1 -1
- package/dist/__tests__/no-respawn.test.d.ts +1 -0
- package/dist/__tests__/no-respawn.test.js +254 -0
- package/dist/__tests__/no-respawn.test.js.map +1 -0
- package/dist/__tests__/onboard.test.d.ts +5 -0
- package/dist/__tests__/onboard.test.js +341 -0
- package/dist/__tests__/onboard.test.js.map +1 -0
- package/dist/__tests__/orphan-process.test.d.ts +11 -0
- package/dist/__tests__/orphan-process.test.js +286 -0
- package/dist/__tests__/orphan-process.test.js.map +1 -0
- package/dist/__tests__/runner.test.js +16 -0
- package/dist/__tests__/runner.test.js.map +1 -1
- package/dist/__tests__/shared-resource-guards.test.d.ts +7 -0
- package/dist/__tests__/shared-resource-guards.test.js +260 -0
- package/dist/__tests__/shared-resource-guards.test.js.map +1 -0
- package/dist/__tests__/watchdog.test.js +138 -12
- package/dist/__tests__/watchdog.test.js.map +1 -1
- package/dist/cli/status.js +11 -0
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/stop.js +7 -2
- package/dist/cli/stop.js.map +1 -1
- package/dist/config/loader.d.ts +0 -4
- package/dist/config/loader.js +102 -42
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +6 -4
- package/dist/core/daemon/assignment-message.d.ts +12 -0
- package/dist/core/daemon/assignment-message.js +36 -0
- package/dist/core/daemon/assignment-message.js.map +1 -0
- package/dist/core/daemon/bootstrap.d.ts +35 -0
- package/dist/core/daemon/bootstrap.js +52 -0
- package/dist/core/daemon/bootstrap.js.map +1 -0
- package/dist/core/daemon/context-template.d.ts +11 -0
- package/dist/core/daemon/context-template.js +144 -0
- package/dist/core/daemon/context-template.js.map +1 -0
- package/dist/core/daemon/crash-log.d.ts +14 -0
- package/dist/core/daemon/crash-log.js +23 -0
- package/dist/core/daemon/crash-log.js.map +1 -0
- package/dist/core/daemon/git-auth.d.ts +18 -0
- package/dist/core/daemon/git-auth.js +88 -0
- package/dist/core/daemon/git-auth.js.map +1 -0
- package/dist/core/daemon/health-policy.d.ts +17 -0
- package/dist/core/daemon/health-policy.js +24 -0
- package/dist/core/daemon/health-policy.js.map +1 -0
- package/dist/core/daemon/sandbox-config.d.ts +9 -0
- package/dist/core/daemon/sandbox-config.js +17 -0
- package/dist/core/daemon/sandbox-config.js.map +1 -0
- package/dist/core/daemon/state.d.ts +33 -0
- package/dist/core/daemon/state.js +78 -0
- package/dist/core/daemon/state.js.map +1 -0
- package/dist/core/daemon/tmux-session.d.ts +17 -0
- package/dist/core/daemon/tmux-session.js +34 -0
- package/dist/core/daemon/tmux-session.js.map +1 -0
- package/dist/core/daemon/workspace.d.ts +23 -0
- package/dist/core/daemon/workspace.js +90 -0
- package/dist/core/daemon/workspace.js.map +1 -0
- package/dist/core/daemon.d.ts +9 -12
- package/dist/core/daemon.js +293 -393
- package/dist/core/daemon.js.map +1 -1
- package/dist/core/injector.d.ts +5 -1
- package/dist/core/injector.js +83 -0
- package/dist/core/injector.js.map +1 -1
- package/dist/core/registry.d.ts +62 -0
- package/dist/core/registry.js +18 -0
- package/dist/core/registry.js.map +1 -1
- package/dist/core/runner/build.d.ts +9 -0
- package/dist/core/runner/build.js +53 -0
- package/dist/core/runner/build.js.map +1 -0
- package/dist/core/runner/detect.d.ts +5 -0
- package/dist/core/runner/detect.js +14 -0
- package/dist/core/runner/detect.js.map +1 -0
- package/dist/core/runner/index.d.ts +5 -0
- package/dist/core/runner/index.js +5 -0
- package/dist/core/runner/index.js.map +1 -0
- package/dist/core/runner/model.d.ts +5 -0
- package/dist/core/runner/model.js +7 -0
- package/dist/core/runner/model.js.map +1 -0
- package/dist/core/runner/opencode-models.d.ts +15 -0
- package/dist/core/runner/opencode-models.js +70 -0
- package/dist/core/runner/opencode-models.js.map +1 -0
- package/dist/core/runner/types.d.ts +19 -0
- package/dist/core/runner/types.js +8 -0
- package/dist/core/runner/types.js.map +1 -0
- package/dist/core/runner.d.ts +5 -47
- package/dist/core/runner.js +5 -167
- package/dist/core/runner.js.map +1 -1
- package/dist/core/tmux-runtime.d.ts +13 -0
- package/dist/core/tmux-runtime.js +72 -0
- package/dist/core/tmux-runtime.js.map +1 -0
- package/dist/core/tmux.d.ts +7 -1
- package/dist/core/tmux.js +75 -45
- package/dist/core/tmux.js.map +1 -1
- package/dist/core/watchdog.d.ts +18 -1
- package/dist/core/watchdog.js +78 -29
- package/dist/core/watchdog.js.map +1 -1
- package/package.json +24 -4
- package/src/__tests__/context.test.ts +0 -464
- package/src/__tests__/injector.test.ts +0 -29
- package/src/__tests__/jwt.test.ts +0 -112
- package/src/__tests__/loader.test.ts +0 -239
- package/src/__tests__/runner.test.ts +0 -104
- package/src/__tests__/sandbox.test.ts +0 -435
- package/src/__tests__/watchdog.test.ts +0 -368
- package/src/cli/attach.ts +0 -22
- package/src/cli/build.ts +0 -145
- package/src/cli/config.ts +0 -148
- package/src/cli/context.ts +0 -231
- package/src/cli/deploy.ts +0 -155
- package/src/cli/index.ts +0 -376
- package/src/cli/init.ts +0 -75
- package/src/cli/list.ts +0 -70
- package/src/cli/local.ts +0 -183
- package/src/cli/logs.ts +0 -64
- package/src/cli/migrate.ts +0 -212
- package/src/cli/nudge.ts +0 -81
- package/src/cli/restart.ts +0 -59
- package/src/cli/slack.ts +0 -70
- package/src/cli/start.ts +0 -118
- package/src/cli/status.ts +0 -91
- package/src/cli/stop.ts +0 -48
- package/src/cli/test.ts +0 -143
- package/src/cli/token.ts +0 -188
- package/src/cli/whoami.ts +0 -142
- package/src/config/loader.ts +0 -121
- package/src/config/schema.ts +0 -68
- package/src/context/handoff.ts +0 -122
- package/src/context/index.ts +0 -8
- package/src/context/schema.ts +0 -111
- package/src/context/storage.ts +0 -197
- package/src/core/daemon.ts +0 -1317
- package/src/core/heartbeat.ts +0 -129
- package/src/core/injector.ts +0 -292
- package/src/core/registry.ts +0 -159
- package/src/core/runner.ts +0 -225
- package/src/core/sandbox.ts +0 -547
- package/src/core/session-id.ts +0 -111
- package/src/core/tmux.ts +0 -405
- package/src/core/watchdog.ts +0 -238
- package/src/core/websocket.ts +0 -94
- package/src/index.ts +0 -10
- package/src/utils/jwt.ts +0 -87
- package/tsconfig.json +0 -8
- package/vitest.config.ts +0 -12
package/src/cli/stop.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
import pc from "picocolors";
|
|
3
|
-
import { getAgentState, removeAgentFromState } from "../config/loader.js";
|
|
4
|
-
import { destroySession } from "../core/tmux.js";
|
|
5
|
-
|
|
6
|
-
export async function stop(name: string): Promise<void> {
|
|
7
|
-
if (!name) {
|
|
8
|
-
console.log(pc.red("Agent name is required."));
|
|
9
|
-
process.exit(1);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const state = getAgentState(name);
|
|
13
|
-
|
|
14
|
-
if (!state) {
|
|
15
|
-
console.log(pc.yellow(`Agent "${name}" is not running.`));
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Try to kill the daemon process
|
|
20
|
-
if (state.pid) {
|
|
21
|
-
try {
|
|
22
|
-
process.kill(state.pid, "SIGTERM");
|
|
23
|
-
console.log(`Sent SIGTERM to daemon process ${state.pid}`);
|
|
24
|
-
} catch {
|
|
25
|
-
// Process might already be dead
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Destroy tmux session
|
|
30
|
-
const destroyed = destroySession(name);
|
|
31
|
-
|
|
32
|
-
if (destroyed) {
|
|
33
|
-
console.log(pc.green(`Destroyed tmux session for "${name}"`));
|
|
34
|
-
}
|
|
35
|
-
|
|
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);
|
|
46
|
-
|
|
47
|
-
console.log(pc.green(`Agent "${name}" stopped (agentId preserved for restart).`));
|
|
48
|
-
}
|
package/src/cli/test.ts
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { execSync, spawnSync } from "node:child_process";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import pc from "picocolors";
|
|
4
|
-
|
|
5
|
-
function findProjectRoot(): string {
|
|
6
|
-
let dir = process.cwd();
|
|
7
|
-
for (let i = 0; i < 10; i++) {
|
|
8
|
-
const packageJson = path.join(dir, "package.json");
|
|
9
|
-
const pnpmWorkspace = path.join(dir, "pnpm-workspace.yaml");
|
|
10
|
-
try {
|
|
11
|
-
execSync(`test -f "${packageJson}" && test -f "${pnpmWorkspace}"`, { stdio: "ignore" });
|
|
12
|
-
return dir;
|
|
13
|
-
} catch {
|
|
14
|
-
dir = path.dirname(dir);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
throw new Error(
|
|
18
|
-
"Could not find AgentMesh project root. Make sure you're in the agentmesh repository.",
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function isLocalStackRunning(): boolean {
|
|
23
|
-
try {
|
|
24
|
-
const result = execSync(
|
|
25
|
-
'docker inspect --format="{{.State.Running}}" agentmesh_postgres 2>/dev/null',
|
|
26
|
-
{ encoding: "utf-8" },
|
|
27
|
-
).trim();
|
|
28
|
-
return result === "true";
|
|
29
|
-
} catch {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface TestOptions {
|
|
35
|
-
package?: string;
|
|
36
|
-
e2e?: boolean;
|
|
37
|
-
watch?: boolean;
|
|
38
|
-
coverage?: boolean;
|
|
39
|
-
updateSnapshots?: boolean;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export async function test(options: TestOptions = {}): Promise<void> {
|
|
43
|
-
const projectRoot = findProjectRoot();
|
|
44
|
-
|
|
45
|
-
if (options.e2e) {
|
|
46
|
-
await runE2ETests(projectRoot, options);
|
|
47
|
-
} else {
|
|
48
|
-
await runUnitTests(projectRoot, options);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async function runUnitTests(projectRoot: string, options: TestOptions): Promise<void> {
|
|
53
|
-
console.log(pc.cyan("Running unit tests..."));
|
|
54
|
-
|
|
55
|
-
// Check if local stack is running for integration tests
|
|
56
|
-
const localStackUp = isLocalStackRunning();
|
|
57
|
-
if (localStackUp) {
|
|
58
|
-
console.log(pc.dim("Local stack detected - integration tests will use local services"));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const args = ["pnpm"];
|
|
62
|
-
|
|
63
|
-
if (options.package) {
|
|
64
|
-
args.push("--filter", options.package);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
args.push("test");
|
|
68
|
-
|
|
69
|
-
if (options.watch) {
|
|
70
|
-
args.push("--", "--watch");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (options.coverage) {
|
|
74
|
-
args.push("--", "--coverage");
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (options.updateSnapshots) {
|
|
78
|
-
args.push("--", "-u");
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
console.log();
|
|
82
|
-
|
|
83
|
-
const result = spawnSync(args[0], args.slice(1), {
|
|
84
|
-
cwd: projectRoot,
|
|
85
|
-
stdio: "inherit",
|
|
86
|
-
env: {
|
|
87
|
-
...process.env,
|
|
88
|
-
// If local stack is running, use it for tests
|
|
89
|
-
...(localStackUp && {
|
|
90
|
-
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/agentmesh",
|
|
91
|
-
REDIS_URL: "redis://localhost:6380/0",
|
|
92
|
-
}),
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
if (result.status !== 0) {
|
|
97
|
-
console.error(pc.red("Tests failed"));
|
|
98
|
-
process.exit(1);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
console.log();
|
|
102
|
-
console.log(pc.green("All tests passed!"));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async function runE2ETests(projectRoot: string, options: TestOptions): Promise<void> {
|
|
106
|
-
console.log(pc.cyan("Running E2E tests..."));
|
|
107
|
-
|
|
108
|
-
// E2E tests require the local stack to be running
|
|
109
|
-
const localStackUp = isLocalStackRunning();
|
|
110
|
-
if (!localStackUp) {
|
|
111
|
-
console.log(pc.yellow("Warning: Local stack is not running."));
|
|
112
|
-
console.log(pc.dim("Start it with: agentmesh local up"));
|
|
113
|
-
console.log();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const args = ["pnpm", "--filter", "@agentmesh/admin", "test:e2e"];
|
|
117
|
-
|
|
118
|
-
if (options.updateSnapshots) {
|
|
119
|
-
args.push("--", "--update-snapshots");
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
console.log();
|
|
123
|
-
|
|
124
|
-
const result = spawnSync(args[0], args.slice(1), {
|
|
125
|
-
cwd: projectRoot,
|
|
126
|
-
stdio: "inherit",
|
|
127
|
-
env: {
|
|
128
|
-
...process.env,
|
|
129
|
-
// Point to local stack if running
|
|
130
|
-
...(localStackUp && {
|
|
131
|
-
PLAYWRIGHT_BASE_URL: "http://localhost:3000",
|
|
132
|
-
}),
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
if (result.status !== 0) {
|
|
137
|
-
console.error(pc.red("E2E tests failed"));
|
|
138
|
-
process.exit(1);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
console.log();
|
|
142
|
-
console.log(pc.green("E2E tests passed!"));
|
|
143
|
-
}
|
package/src/cli/token.ts
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import pc from "picocolors";
|
|
2
|
-
import { loadConfig, loadState, updateAgentInState } from "../config/loader.js";
|
|
3
|
-
import { registerAgent } from "../core/registry.js";
|
|
4
|
-
import { getSessionName, sessionExists, updateSessionEnvironment } from "../core/tmux.js";
|
|
5
|
-
import {
|
|
6
|
-
decodeToken,
|
|
7
|
-
getTokenExpiry,
|
|
8
|
-
getTokenTimeRemaining,
|
|
9
|
-
isTokenExpired,
|
|
10
|
-
} from "../utils/jwt.js";
|
|
11
|
-
|
|
12
|
-
export async function token(action: string, agentName?: string): Promise<void> {
|
|
13
|
-
const config = loadConfig();
|
|
14
|
-
|
|
15
|
-
if (!config) {
|
|
16
|
-
console.log(pc.red("No config found. Run 'agentmesh init' first."));
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Check if running inside an agent session
|
|
21
|
-
const envAgentId = process.env.AGENTMESH_AGENT_ID;
|
|
22
|
-
const envToken = process.env.AGENT_TOKEN;
|
|
23
|
-
|
|
24
|
-
switch (action) {
|
|
25
|
-
case "show":
|
|
26
|
-
await showToken(config, agentName, envAgentId, envToken);
|
|
27
|
-
break;
|
|
28
|
-
case "refresh":
|
|
29
|
-
await refreshToken(config, agentName, envAgentId);
|
|
30
|
-
break;
|
|
31
|
-
case "info":
|
|
32
|
-
await tokenInfo(config, agentName, envAgentId, envToken);
|
|
33
|
-
break;
|
|
34
|
-
default:
|
|
35
|
-
console.log(pc.red(`Unknown action: ${action}`));
|
|
36
|
-
console.log(pc.dim("Available actions: show, refresh, info"));
|
|
37
|
-
process.exit(1);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async function showToken(
|
|
42
|
-
_config: ReturnType<typeof loadConfig>,
|
|
43
|
-
agentName?: string,
|
|
44
|
-
_envAgentId?: string,
|
|
45
|
-
envToken?: string,
|
|
46
|
-
): Promise<void> {
|
|
47
|
-
// If running as agent, show env token
|
|
48
|
-
if (envToken && !agentName) {
|
|
49
|
-
console.log(envToken);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Find agent in state
|
|
54
|
-
const state = loadState();
|
|
55
|
-
const agent = agentName ? state.agents.find((a) => a.name === agentName) : state.agents[0];
|
|
56
|
-
|
|
57
|
-
if (!agent) {
|
|
58
|
-
if (agentName) {
|
|
59
|
-
console.log(pc.red(`Agent "${agentName}" not found.`));
|
|
60
|
-
} else {
|
|
61
|
-
console.log(pc.red("No agents registered."));
|
|
62
|
-
}
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (!agent.token) {
|
|
67
|
-
console.log(pc.red(`No token found for agent "${agent.name}".`));
|
|
68
|
-
console.log(pc.dim("Run 'agentmesh token refresh' to get a new token."));
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
console.log(agent.token);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function refreshToken(
|
|
76
|
-
config: ReturnType<typeof loadConfig>,
|
|
77
|
-
agentName?: string,
|
|
78
|
-
envAgentId?: string,
|
|
79
|
-
): Promise<void> {
|
|
80
|
-
if (!config) {
|
|
81
|
-
process.exit(1);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const state = loadState();
|
|
85
|
-
|
|
86
|
-
// Find the agent to refresh
|
|
87
|
-
const agent = agentName
|
|
88
|
-
? state.agents.find((a) => a.name === agentName)
|
|
89
|
-
: envAgentId
|
|
90
|
-
? state.agents.find((a) => a.agentId === envAgentId)
|
|
91
|
-
: state.agents[0];
|
|
92
|
-
|
|
93
|
-
if (!agent) {
|
|
94
|
-
console.log(pc.red("No agent found to refresh token for."));
|
|
95
|
-
process.exit(1);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
console.log(pc.dim(`Refreshing token for "${agent.name}"...`));
|
|
99
|
-
|
|
100
|
-
try {
|
|
101
|
-
const registration = await registerAgent({
|
|
102
|
-
url: config.hubUrl,
|
|
103
|
-
apiKey: config.apiKey,
|
|
104
|
-
workspace: config.workspace,
|
|
105
|
-
agentId: agent.agentId,
|
|
106
|
-
agentName: agent.name,
|
|
107
|
-
model: "claude-sonnet-4", // Default model
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// Update state
|
|
111
|
-
updateAgentInState(agent.name, {
|
|
112
|
-
token: registration.token,
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// Update tmux environment if session exists
|
|
116
|
-
if (sessionExists(getSessionName(agent.name))) {
|
|
117
|
-
updateSessionEnvironment(agent.name, {
|
|
118
|
-
AGENT_TOKEN: registration.token,
|
|
119
|
-
AGENTMESH_AGENT_ID: registration.agentId,
|
|
120
|
-
});
|
|
121
|
-
console.log(pc.dim("Updated tmux session environment."));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
console.log(pc.green("Token refreshed successfully."));
|
|
125
|
-
|
|
126
|
-
const expiry = getTokenExpiry(registration.token);
|
|
127
|
-
if (expiry) {
|
|
128
|
-
console.log(pc.dim(`New expiry: ${expiry.toISOString()}`));
|
|
129
|
-
}
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.log(pc.red(`Failed to refresh token: ${(error as Error).message}`));
|
|
132
|
-
process.exit(1);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async function tokenInfo(
|
|
137
|
-
_config: ReturnType<typeof loadConfig>,
|
|
138
|
-
agentName?: string,
|
|
139
|
-
_envAgentId?: string,
|
|
140
|
-
envToken?: string,
|
|
141
|
-
): Promise<void> {
|
|
142
|
-
// Get token to inspect
|
|
143
|
-
let tokenToInspect: string | null = null;
|
|
144
|
-
let source = "unknown";
|
|
145
|
-
|
|
146
|
-
if (envToken && !agentName) {
|
|
147
|
-
tokenToInspect = envToken;
|
|
148
|
-
source = "environment";
|
|
149
|
-
} else {
|
|
150
|
-
const state = loadState();
|
|
151
|
-
const agent = agentName ? state.agents.find((a) => a.name === agentName) : state.agents[0];
|
|
152
|
-
|
|
153
|
-
if (agent?.token) {
|
|
154
|
-
tokenToInspect = agent.token;
|
|
155
|
-
source = `agent: ${agent.name}`;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (!tokenToInspect) {
|
|
160
|
-
console.log(pc.red("No token found."));
|
|
161
|
-
process.exit(1);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const payload = decodeToken(tokenToInspect);
|
|
165
|
-
if (!payload) {
|
|
166
|
-
console.log(pc.red("Invalid token format."));
|
|
167
|
-
process.exit(1);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const expiry = getTokenExpiry(tokenToInspect);
|
|
171
|
-
const expired = isTokenExpired(tokenToInspect);
|
|
172
|
-
const remaining = getTokenTimeRemaining(tokenToInspect);
|
|
173
|
-
|
|
174
|
-
console.log(pc.bold("Token Info"));
|
|
175
|
-
console.log(` Source: ${pc.dim(source)}`);
|
|
176
|
-
console.log(` Agent ID: ${pc.cyan(payload.sub)}`);
|
|
177
|
-
console.log(` Type: ${pc.dim(payload.actorType)}`);
|
|
178
|
-
console.log(` Workspaces: ${pc.dim(payload.workspaceScopes.join(", "))}`);
|
|
179
|
-
console.log(` Issued: ${pc.dim(new Date(payload.iat * 1000).toISOString())}`);
|
|
180
|
-
console.log(` Expires: ${expiry ? pc.dim(expiry.toISOString()) : pc.red("unknown")}`);
|
|
181
|
-
console.log(` Status: ${expired ? pc.red("EXPIRED") : pc.green("VALID")}`);
|
|
182
|
-
|
|
183
|
-
if (!expired && remaining > 0) {
|
|
184
|
-
const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
|
|
185
|
-
const hours = Math.floor((remaining % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
|
186
|
-
console.log(` Remaining: ${pc.dim(`${days}d ${hours}h`)}`);
|
|
187
|
-
}
|
|
188
|
-
}
|
package/src/cli/whoami.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import pc from "picocolors";
|
|
2
|
-
import { loadConfig, loadState } from "../config/loader.js";
|
|
3
|
-
import type { RunnerType } from "../config/schema.js";
|
|
4
|
-
import { getRunnerDisplayName } from "../core/runner.js";
|
|
5
|
-
import { getTokenExpiry } from "../utils/jwt.js";
|
|
6
|
-
|
|
7
|
-
export async function whoami(agentName?: string): Promise<void> {
|
|
8
|
-
const config = loadConfig();
|
|
9
|
-
|
|
10
|
-
if (!config) {
|
|
11
|
-
console.log(pc.red("No config found. Run 'agentmesh init' first."));
|
|
12
|
-
process.exit(1);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const state = loadState();
|
|
16
|
-
|
|
17
|
-
// If no agent name provided, check environment or show all
|
|
18
|
-
if (!agentName) {
|
|
19
|
-
// Check if running as an agent (env vars set)
|
|
20
|
-
const envAgentId = process.env.AGENTMESH_AGENT_ID;
|
|
21
|
-
const envToken = process.env.AGENT_TOKEN;
|
|
22
|
-
|
|
23
|
-
if (envAgentId && envToken) {
|
|
24
|
-
// We're running inside an agent session
|
|
25
|
-
const expiry = getTokenExpiry(envToken);
|
|
26
|
-
const expiryStr = formatExpiry(expiry);
|
|
27
|
-
|
|
28
|
-
// Try to find agent in state for runtime info
|
|
29
|
-
const agentState = state.agents.find((a) => a.agentId === envAgentId);
|
|
30
|
-
|
|
31
|
-
console.log(pc.bold("Current Agent"));
|
|
32
|
-
console.log(` ID: ${pc.cyan(envAgentId)}`);
|
|
33
|
-
console.log(` Workspace: ${pc.dim(config.workspace)}`);
|
|
34
|
-
console.log(` Token: ${expiryStr}`);
|
|
35
|
-
console.log(` Hub: ${pc.dim(config.hubUrl)}`);
|
|
36
|
-
|
|
37
|
-
// Show runtime model info if available
|
|
38
|
-
if (agentState?.runtimeModel) {
|
|
39
|
-
const runnerName = agentState.runnerType
|
|
40
|
-
? getRunnerDisplayName(agentState.runnerType as RunnerType)
|
|
41
|
-
: "Unknown";
|
|
42
|
-
console.log(` Model: ${pc.cyan(agentState.runtimeModel)}`);
|
|
43
|
-
console.log(` Runner: ${pc.dim(runnerName)}`);
|
|
44
|
-
}
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Show all registered agents
|
|
49
|
-
if (state.agents.length === 0) {
|
|
50
|
-
console.log(pc.dim("No agents registered."));
|
|
51
|
-
console.log(pc.dim("Start an agent with: agentmesh start <name>"));
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
console.log(pc.bold("Registered Agents"));
|
|
56
|
-
console.log();
|
|
57
|
-
|
|
58
|
-
for (const agent of state.agents) {
|
|
59
|
-
const expiry = agent.token ? getTokenExpiry(agent.token) : null;
|
|
60
|
-
const expiryStr = formatExpiry(expiry);
|
|
61
|
-
const running = agent.pid ? isProcessRunning(agent.pid) : false;
|
|
62
|
-
|
|
63
|
-
console.log(` ${pc.cyan(agent.name)}`);
|
|
64
|
-
console.log(` ID: ${pc.dim(agent.agentId)}`);
|
|
65
|
-
console.log(` Status: ${running ? pc.green("running") : pc.yellow("stopped")}`);
|
|
66
|
-
console.log(` Token: ${expiryStr}`);
|
|
67
|
-
if (agent.runtimeModel) {
|
|
68
|
-
const runnerName = agent.runnerType
|
|
69
|
-
? getRunnerDisplayName(agent.runnerType as RunnerType)
|
|
70
|
-
: "Unknown";
|
|
71
|
-
console.log(` Model: ${pc.dim(agent.runtimeModel)} (${runnerName})`);
|
|
72
|
-
}
|
|
73
|
-
console.log();
|
|
74
|
-
}
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Show specific agent
|
|
79
|
-
const agent = state.agents.find((a) => a.name === agentName);
|
|
80
|
-
|
|
81
|
-
if (!agent) {
|
|
82
|
-
console.log(pc.red(`Agent "${agentName}" not found.`));
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const expiry = agent.token ? getTokenExpiry(agent.token) : null;
|
|
87
|
-
const expiryStr = formatExpiry(expiry);
|
|
88
|
-
const running = agent.pid ? isProcessRunning(agent.pid) : false;
|
|
89
|
-
|
|
90
|
-
console.log(pc.bold(`Agent: ${agent.name}`));
|
|
91
|
-
console.log(` ID: ${pc.cyan(agent.agentId)}`);
|
|
92
|
-
console.log(` Workspace: ${pc.dim(config.workspace)}`);
|
|
93
|
-
console.log(` Status: ${running ? pc.green("running") : pc.yellow("stopped")}`);
|
|
94
|
-
console.log(` Token: ${expiryStr}`);
|
|
95
|
-
console.log(` Session: ${pc.dim(agent.tmuxSession || "none")}`);
|
|
96
|
-
console.log(` Started: ${pc.dim(agent.startedAt || "unknown")}`);
|
|
97
|
-
console.log(` Hub: ${pc.dim(config.hubUrl)}`);
|
|
98
|
-
|
|
99
|
-
// Show runtime model info
|
|
100
|
-
if (agent.runtimeModel) {
|
|
101
|
-
const runnerName = agent.runnerType
|
|
102
|
-
? getRunnerDisplayName(agent.runnerType as RunnerType)
|
|
103
|
-
: "Unknown";
|
|
104
|
-
console.log(` Model: ${pc.cyan(agent.runtimeModel)}`);
|
|
105
|
-
console.log(` Runner: ${pc.dim(runnerName)}`);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function formatExpiry(expiry: Date | null): string {
|
|
110
|
-
if (!expiry) {
|
|
111
|
-
return pc.red("No token");
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const now = new Date();
|
|
115
|
-
const diffMs = expiry.getTime() - now.getTime();
|
|
116
|
-
|
|
117
|
-
if (diffMs <= 0) {
|
|
118
|
-
return pc.red("Expired");
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
|
122
|
-
const diffHours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
|
123
|
-
|
|
124
|
-
if (diffDays > 1) {
|
|
125
|
-
return pc.green(`Valid (expires in ${diffDays} days)`);
|
|
126
|
-
} else if (diffDays === 1) {
|
|
127
|
-
return pc.yellow(`Valid (expires in 1 day)`);
|
|
128
|
-
} else if (diffHours > 0) {
|
|
129
|
-
return pc.yellow(`Valid (expires in ${diffHours} hours)`);
|
|
130
|
-
} else {
|
|
131
|
-
return pc.red(`Expiring soon`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function isProcessRunning(pid: number): boolean {
|
|
136
|
-
try {
|
|
137
|
-
process.kill(pid, 0);
|
|
138
|
-
return true;
|
|
139
|
-
} catch {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
}
|
package/src/config/loader.ts
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
type AgentState,
|
|
5
|
-
CONFIG_PATH,
|
|
6
|
-
type Config,
|
|
7
|
-
DEFAULT_CONFIG,
|
|
8
|
-
STATE_PATH,
|
|
9
|
-
type State,
|
|
10
|
-
} from "./schema.js";
|
|
11
|
-
|
|
12
|
-
export function ensureConfigDir(): void {
|
|
13
|
-
const configDir = path.dirname(CONFIG_PATH);
|
|
14
|
-
if (!fs.existsSync(configDir)) {
|
|
15
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function loadConfig(): Config | null {
|
|
20
|
-
try {
|
|
21
|
-
if (!fs.existsSync(CONFIG_PATH)) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
const content = fs.readFileSync(CONFIG_PATH, "utf-8");
|
|
25
|
-
return JSON.parse(content) as Config;
|
|
26
|
-
} catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function saveConfig(config: Config): void {
|
|
32
|
-
ensureConfigDir();
|
|
33
|
-
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function loadState(): State {
|
|
37
|
-
try {
|
|
38
|
-
if (!fs.existsSync(STATE_PATH)) {
|
|
39
|
-
return { agents: [] };
|
|
40
|
-
}
|
|
41
|
-
const content = fs.readFileSync(STATE_PATH, "utf-8");
|
|
42
|
-
return JSON.parse(content) as State;
|
|
43
|
-
} catch {
|
|
44
|
-
return { agents: [] };
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function saveState(state: State): void {
|
|
49
|
-
ensureConfigDir();
|
|
50
|
-
fs.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function addAgentToState(agent: AgentState): void {
|
|
54
|
-
const state = loadState();
|
|
55
|
-
// Remove existing entry with same name
|
|
56
|
-
state.agents = state.agents.filter((a) => a.name !== agent.name);
|
|
57
|
-
state.agents.push(agent);
|
|
58
|
-
saveState(state);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function removeAgentFromState(name: string, preserveAgentId = false): void {
|
|
62
|
-
const state = loadState();
|
|
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
|
-
|
|
84
|
-
saveState(state);
|
|
85
|
-
}
|
|
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
|
-
|
|
94
|
-
export function getAgentState(name: string): AgentState | undefined {
|
|
95
|
-
const state = loadState();
|
|
96
|
-
return state.agents.find((a) => a.name === name);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function updateAgentInState(name: string, updates: Partial<AgentState>): void {
|
|
100
|
-
const state = loadState();
|
|
101
|
-
const agentIndex = state.agents.findIndex((a) => a.name === name);
|
|
102
|
-
|
|
103
|
-
if (agentIndex === -1) {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
state.agents[agentIndex] = {
|
|
108
|
-
...state.agents[agentIndex],
|
|
109
|
-
...updates,
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
saveState(state);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export function createDefaultConfig(apiKey: string, workspace: string): Config {
|
|
116
|
-
return {
|
|
117
|
-
...DEFAULT_CONFIG,
|
|
118
|
-
apiKey,
|
|
119
|
-
workspace,
|
|
120
|
-
} as Config;
|
|
121
|
-
}
|
package/src/config/schema.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
export interface AgentConfig {
|
|
2
|
-
name: string;
|
|
3
|
-
agentId?: string;
|
|
4
|
-
command: string;
|
|
5
|
-
workdir?: string;
|
|
6
|
-
model?: string;
|
|
7
|
-
teams?: string[];
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface Config {
|
|
11
|
-
apiKey: string;
|
|
12
|
-
workspace: string;
|
|
13
|
-
hubUrl: string;
|
|
14
|
-
defaults: {
|
|
15
|
-
command: string;
|
|
16
|
-
model: string;
|
|
17
|
-
};
|
|
18
|
-
agents: AgentConfig[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const DEFAULT_CONFIG: Partial<Config> = {
|
|
22
|
-
hubUrl: "https://agentmeshhq.dev",
|
|
23
|
-
defaults: {
|
|
24
|
-
command: "opencode",
|
|
25
|
-
model: "claude-sonnet-4",
|
|
26
|
-
},
|
|
27
|
-
agents: [],
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const CONFIG_PATH = `${process.env.HOME}/.agentmesh/config.json`;
|
|
31
|
-
export const STATE_PATH = `${process.env.HOME}/.agentmesh/state.json`;
|
|
32
|
-
|
|
33
|
-
export type RunnerType = "opencode" | "claude" | "custom";
|
|
34
|
-
|
|
35
|
-
export type AgentStatus = "running" | "stopped" | "failed" | "stuck";
|
|
36
|
-
|
|
37
|
-
export interface AgentState {
|
|
38
|
-
name: string;
|
|
39
|
-
agentId: string;
|
|
40
|
-
pid: number;
|
|
41
|
-
tmuxSession: string;
|
|
42
|
-
startedAt: string;
|
|
43
|
-
token?: string;
|
|
44
|
-
workdir?: string;
|
|
45
|
-
assignedProject?: string;
|
|
46
|
-
/** The effective runtime model (resolved from CLI > agent > defaults) */
|
|
47
|
-
runtimeModel?: string;
|
|
48
|
-
/** The runner type (opencode, claude, custom) */
|
|
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;
|
|
62
|
-
/** OpenCode session ID for native session resume */
|
|
63
|
-
opencodeSessionId?: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface State {
|
|
67
|
-
agents: AgentState[];
|
|
68
|
-
}
|