@agentmeshhq/agent 0.1.8 → 0.1.9

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.
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Runner Module
3
+ * Handles model resolution, validation, and runner-specific configuration
4
+ */
5
+ import { execSync } from "node:child_process";
6
+ // ============================================================================
7
+ // Runner Detection
8
+ // ============================================================================
9
+ /**
10
+ * Detects the runner type from the command
11
+ */
12
+ export function detectRunner(command) {
13
+ const cmd = command.toLowerCase().trim();
14
+ if (cmd === "opencode" || cmd.startsWith("opencode ")) {
15
+ return "opencode";
16
+ }
17
+ if (cmd === "claude" || cmd.startsWith("claude ")) {
18
+ return "claude";
19
+ }
20
+ return "custom";
21
+ }
22
+ // ============================================================================
23
+ // Model Resolution
24
+ // ============================================================================
25
+ /**
26
+ * Resolves the effective model from CLI > agent config > defaults
27
+ */
28
+ export function resolveModel(input) {
29
+ // Priority: CLI flag > agent config > default
30
+ return input.cliModel || input.agentModel || input.defaultModel;
31
+ }
32
+ // ============================================================================
33
+ // OpenCode Integration
34
+ // ============================================================================
35
+ let cachedOpenCodeModels = null;
36
+ /**
37
+ * Gets available OpenCode models (cached)
38
+ */
39
+ export function getOpenCodeModels() {
40
+ if (cachedOpenCodeModels) {
41
+ return cachedOpenCodeModels;
42
+ }
43
+ try {
44
+ const output = execSync("opencode models 2>/dev/null", {
45
+ encoding: "utf-8",
46
+ timeout: 10000,
47
+ });
48
+ cachedOpenCodeModels = output
49
+ .split("\n")
50
+ .map((line) => line.trim())
51
+ .filter((line) => line.length > 0 && !line.startsWith("#"));
52
+ return cachedOpenCodeModels;
53
+ }
54
+ catch {
55
+ // OpenCode not available or failed
56
+ return [];
57
+ }
58
+ }
59
+ /**
60
+ * Validates that a model is available in OpenCode
61
+ */
62
+ export function validateOpenCodeModel(model) {
63
+ const models = getOpenCodeModels();
64
+ // If we couldn't get models list, allow any (graceful degradation)
65
+ if (models.length === 0) {
66
+ return { valid: true };
67
+ }
68
+ if (models.includes(model)) {
69
+ return { valid: true };
70
+ }
71
+ // Check for partial match (e.g., "claude-sonnet-4" matches "anthropic/claude-sonnet-4")
72
+ const partialMatch = models.find((m) => m.endsWith(`/${model}`) || m === model || m.split("/").pop() === model);
73
+ if (partialMatch) {
74
+ return { valid: true };
75
+ }
76
+ return {
77
+ valid: false,
78
+ error: `Model "${model}" not found in OpenCode. Run 'opencode models' to see available models.`,
79
+ };
80
+ }
81
+ /**
82
+ * Normalizes a model name for OpenCode
83
+ * e.g., "claude-sonnet-4" -> "anthropic/claude-sonnet-4" if that's what OpenCode expects
84
+ */
85
+ export function normalizeOpenCodeModel(model) {
86
+ const models = getOpenCodeModels();
87
+ // Direct match
88
+ if (models.includes(model)) {
89
+ return model;
90
+ }
91
+ // Try to find full path version
92
+ const fullPath = models.find((m) => m.endsWith(`/${model}`) || m.split("/").pop() === model);
93
+ return fullPath || model;
94
+ }
95
+ // ============================================================================
96
+ // Runner Configuration
97
+ // ============================================================================
98
+ /**
99
+ * Builds the complete runner configuration including environment variables
100
+ */
101
+ export function buildRunnerConfig(input) {
102
+ const runnerType = detectRunner(input.command);
103
+ const model = resolveModel(input);
104
+ const env = {};
105
+ switch (runnerType) {
106
+ case "opencode": {
107
+ // Validate model for OpenCode
108
+ const validation = validateOpenCodeModel(model);
109
+ if (!validation.valid) {
110
+ console.warn(`Warning: ${validation.error}`);
111
+ }
112
+ // Normalize and set OPENCODE_MODEL
113
+ const normalizedModel = normalizeOpenCodeModel(model);
114
+ env.OPENCODE_MODEL = normalizedModel;
115
+ break;
116
+ }
117
+ case "claude": {
118
+ // Claude CLI uses ANTHROPIC_MODEL or similar
119
+ // For now, just pass the model - Claude CLI will handle it
120
+ env.CLAUDE_MODEL = model;
121
+ break;
122
+ }
123
+ case "custom":
124
+ // Custom runners don't get automatic model env
125
+ // User is responsible for configuring their tool
126
+ break;
127
+ }
128
+ return {
129
+ type: runnerType,
130
+ command: input.command,
131
+ model,
132
+ env,
133
+ };
134
+ }
135
+ /**
136
+ * Gets a human-readable runner name
137
+ */
138
+ export function getRunnerDisplayName(runnerType) {
139
+ switch (runnerType) {
140
+ case "opencode":
141
+ return "OpenCode";
142
+ case "claude":
143
+ return "Claude CLI";
144
+ case "custom":
145
+ return "Custom";
146
+ }
147
+ }
148
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,9 @@ export declare function sessionExists(sessionName: string): boolean;
3
3
  export interface SessionEnv {
4
4
  AGENT_TOKEN?: string;
5
5
  AGENTMESH_AGENT_ID?: string;
6
+ OPENCODE_MODEL?: string;
7
+ CLAUDE_MODEL?: string;
8
+ [key: string]: string | undefined;
6
9
  }
7
10
  export declare function createSession(agentName: string, command: string, workdir?: string, env?: SessionEnv): boolean;
8
11
  export declare function setSessionEnvironment(sessionName: string, env: SessionEnv): boolean;
package/dist/core/tmux.js CHANGED
@@ -19,13 +19,30 @@ export function createSession(agentName, command, workdir, env) {
19
19
  return false;
20
20
  }
21
21
  try {
22
+ // Build environment prefix for the command
23
+ // This ensures env vars are set BEFORE the process starts
24
+ let envPrefix = "";
25
+ if (env) {
26
+ const envParts = [];
27
+ for (const [key, value] of Object.entries(env)) {
28
+ if (value !== undefined && value !== "") {
29
+ // Escape special characters in value
30
+ const escapedValue = value.replace(/"/g, '\\"');
31
+ envParts.push(`${key}="${escapedValue}"`);
32
+ }
33
+ }
34
+ if (envParts.length > 0) {
35
+ envPrefix = envParts.join(" ") + " ";
36
+ }
37
+ }
38
+ const fullCommand = `${envPrefix}${command}`;
22
39
  const args = ["new-session", "-d", "-s", sessionName];
23
40
  if (workdir) {
24
41
  args.push("-c", workdir);
25
42
  }
26
- args.push(command);
43
+ args.push(fullCommand);
27
44
  execSync(`tmux ${args.join(" ")}`);
28
- // Inject environment variables after session creation
45
+ // Also set session environment for any subsequent processes/refreshes
29
46
  if (env) {
30
47
  setSessionEnvironment(sessionName, env);
31
48
  }
@@ -38,11 +55,10 @@ export function createSession(agentName, command, workdir, env) {
38
55
  }
39
56
  export function setSessionEnvironment(sessionName, env) {
40
57
  try {
41
- if (env.AGENT_TOKEN) {
42
- execSync(`tmux set-environment -t "${sessionName}" AGENT_TOKEN "${env.AGENT_TOKEN}"`);
43
- }
44
- if (env.AGENTMESH_AGENT_ID) {
45
- execSync(`tmux set-environment -t "${sessionName}" AGENTMESH_AGENT_ID "${env.AGENTMESH_AGENT_ID}"`);
58
+ for (const [key, value] of Object.entries(env)) {
59
+ if (value !== undefined && value !== "") {
60
+ execSync(`tmux set-environment -t "${sessionName}" ${key} "${value}"`);
61
+ }
46
62
  }
47
63
  return true;
48
64
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tmux.js","sourceRoot":"","sources":["../../src/core/tmux.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,QAAQ,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAExE,MAAM,cAAc,GAAG,YAAY,CAAC;AAEpC,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,OAAO,GAAG,cAAc,GAAG,SAAS,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,IAAI,CAAC;QACH,QAAQ,CAAC,wBAAwB,WAAW,eAAe,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAOD,MAAM,UAAU,aAAa,CAC3B,SAAiB,EACjB,OAAe,EACf,OAAgB,EAChB,GAAgB;IAEhB,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAE9C,IAAI,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,WAAW,WAAW,iBAAiB,CAAC,CAAC;QACvD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QAEtD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3B,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEnB,QAAQ,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEnC,sDAAsD;QACtD,IAAI,GAAG,EAAE,CAAC;YACR,qBAAqB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QAC1C,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,kCAAkC,KAAK,EAAE,CAAC,CAAC;QACzD,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,WAAmB,EAAE,GAAe;IACxE,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACpB,QAAQ,CAAC,4BAA4B,WAAW,kBAAkB,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC;QACxF,CAAC;QACD,IAAI,GAAG,CAAC,kBAAkB,EAAE,CAAC;YAC3B,QAAQ,CACN,4BAA4B,WAAW,yBAAyB,GAAG,CAAC,kBAAkB,GAAG,CAC1F,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,KAAK,EAAE,CAAC,CAAC;QAC7D,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,SAAiB,EAAE,GAAe;IACzE,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAE9C,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,WAAW,WAAW,iBAAiB,CAAC,CAAC;QACvD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,qBAAqB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAE9C,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC,CAAC,eAAe;IAC9B,CAAC;IAED,IAAI,CAAC;QACH,QAAQ,CAAC,yBAAyB,WAAW,GAAG,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,mCAAmC,KAAK,EAAE,CAAC,CAAC;QAC1D,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,SAAiB,EAAE,OAAe;IACzD,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAE9C,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,WAAW,WAAW,iBAAiB,CAAC,CAAC;QACvD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,qCAAqC;QACrC,MAAM,cAAc,GAAG,OAAO;aAC3B,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;aACtB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;aACpB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;aACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAExB,oEAAoE;QACpE,QAAQ,CAAC,sBAAsB,WAAW,MAAM,cAAc,GAAG,CAAC,CAAC;QACnE,QAAQ,CAAC,sBAAsB,WAAW,SAAS,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,wBAAwB,KAAK,EAAE,CAAC,CAAC;QAC/C,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAE9C,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,WAAW,WAAW,iBAAiB,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,mDAAmD;IACnD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,gBAAgB,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE;QAChE,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC;IAEH,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACvB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,yCAAyC,EAAE;YACjE,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,OAAO,MAAM;aACV,IAAI,EAAE;aACN,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;aAC3C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAE9C,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,QAAQ,CAAC,uBAAuB,WAAW,gCAAgC,EAAE;YAC3F,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;QAEV,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC1B,CAAC;AACH,CAAC;AAQD;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAiB;IACrD,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAE9C,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,8CAA8C;QAC9C,MAAM,OAAO,GAAG,QAAQ,CAAC,4BAA4B,WAAW,6BAA6B,EAAE;YAC7F,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;QAEV,MAAM,OAAO,GAAmB,EAAE,OAAO,EAAE,CAAC;QAE5C,uCAAuC;QACvC,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,QAAQ,CAAC,6CAA6C,EAAE;gBACxE,QAAQ,EAAE,OAAO;gBACjB,GAAG,EAAE,OAAO;aACb,CAAC,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;YAChC,CAAC;YAED,MAAM,SAAS,GAAG,QAAQ,CAAC,gCAAgC,EAAE;gBAC3D,QAAQ,EAAE,OAAO;gBACjB,GAAG,EAAE,OAAO;aACb,CAAC,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,SAAS,EAAE,CAAC;gBACd,uBAAuB;gBACvB,OAAO,CAAC,SAAS;oBACf,SAAS,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;YAC7E,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sCAAsC;QACxC,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,KAAK,EAAE,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB,EAAE,KAAK,GAAG,GAAG;IACjE,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAE9C,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,yBAAyB,WAAW,YAAY,KAAK,EAAE,EAAE;YAC/E,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qCAAqC,KAAK,EAAE,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"tmux.js","sourceRoot":"","sources":["../../src/core/tmux.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentmeshhq/agent",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "AgentMesh Agent Wrapper - Turn any AI coding assistant into a dispatchable, nudge-able agent",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,105 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import {
3
+ buildRunnerConfig,
4
+ detectRunner,
5
+ getRunnerDisplayName,
6
+ type RunnerType,
7
+ resolveModel,
8
+ } from "../core/runner.js";
9
+
10
+ describe("Runner Module", () => {
11
+ describe("detectRunner", () => {
12
+ it("should detect opencode runner", () => {
13
+ expect(detectRunner("opencode")).toBe("opencode");
14
+ expect(detectRunner("opencode --some-flag")).toBe("opencode");
15
+ expect(detectRunner("OPENCODE")).toBe("opencode");
16
+ });
17
+
18
+ it("should detect claude runner", () => {
19
+ expect(detectRunner("claude")).toBe("claude");
20
+ expect(detectRunner("claude --some-flag")).toBe("claude");
21
+ expect(detectRunner("CLAUDE")).toBe("claude");
22
+ });
23
+
24
+ it("should detect custom runner for unknown commands", () => {
25
+ expect(detectRunner("aider")).toBe("custom");
26
+ expect(detectRunner("cursor")).toBe("custom");
27
+ expect(detectRunner("my-custom-tool")).toBe("custom");
28
+ });
29
+ });
30
+
31
+ describe("resolveModel", () => {
32
+ it("should prioritize CLI model over all others", () => {
33
+ const result = resolveModel({
34
+ cliModel: "cli-model",
35
+ agentModel: "agent-model",
36
+ defaultModel: "default-model",
37
+ command: "opencode",
38
+ });
39
+ expect(result).toBe("cli-model");
40
+ });
41
+
42
+ it("should use agent model when CLI not provided", () => {
43
+ const result = resolveModel({
44
+ agentModel: "agent-model",
45
+ defaultModel: "default-model",
46
+ command: "opencode",
47
+ });
48
+ expect(result).toBe("agent-model");
49
+ });
50
+
51
+ it("should fall back to default model", () => {
52
+ const result = resolveModel({
53
+ defaultModel: "default-model",
54
+ command: "opencode",
55
+ });
56
+ expect(result).toBe("default-model");
57
+ });
58
+ });
59
+
60
+ describe("buildRunnerConfig", () => {
61
+ it("should build config for opencode with OPENCODE_MODEL env", () => {
62
+ const config = buildRunnerConfig({
63
+ cliModel: "claude-sonnet-4",
64
+ defaultModel: "claude-sonnet-4",
65
+ command: "opencode",
66
+ });
67
+
68
+ expect(config.type).toBe("opencode");
69
+ expect(config.model).toBe("claude-sonnet-4");
70
+ expect(config.env.OPENCODE_MODEL).toBeDefined();
71
+ });
72
+
73
+ it("should build config for claude with CLAUDE_MODEL env", () => {
74
+ const config = buildRunnerConfig({
75
+ cliModel: "claude-sonnet-4",
76
+ defaultModel: "claude-sonnet-4",
77
+ command: "claude",
78
+ });
79
+
80
+ expect(config.type).toBe("claude");
81
+ expect(config.model).toBe("claude-sonnet-4");
82
+ expect(config.env.CLAUDE_MODEL).toBe("claude-sonnet-4");
83
+ });
84
+
85
+ it("should build config for custom runner without env vars", () => {
86
+ const config = buildRunnerConfig({
87
+ cliModel: "gpt-4",
88
+ defaultModel: "claude-sonnet-4",
89
+ command: "aider",
90
+ });
91
+
92
+ expect(config.type).toBe("custom");
93
+ expect(config.model).toBe("gpt-4");
94
+ expect(Object.keys(config.env)).toHaveLength(0);
95
+ });
96
+ });
97
+
98
+ describe("getRunnerDisplayName", () => {
99
+ it("should return correct display names", () => {
100
+ expect(getRunnerDisplayName("opencode")).toBe("OpenCode");
101
+ expect(getRunnerDisplayName("claude")).toBe("Claude CLI");
102
+ expect(getRunnerDisplayName("custom")).toBe("Custom");
103
+ });
104
+ });
105
+ });
package/src/cli/index.ts CHANGED
@@ -168,9 +168,10 @@ program
168
168
  .command("restart")
169
169
  .description("Restart an agent (preserves agent ID)")
170
170
  .argument("<name>", "Agent name")
171
- .action(async (name) => {
171
+ .option("-m, --model <model>", "Model to use (default: preserve previous model)")
172
+ .action(async (name, options) => {
172
173
  try {
173
- await restart(name);
174
+ await restart(name, { model: options.model });
174
175
  } catch (error) {
175
176
  console.error(pc.red((error as Error).message));
176
177
  process.exit(1);
@@ -4,7 +4,11 @@ import { destroySession, getSessionName, sessionExists } from "../core/tmux.js";
4
4
  import { start } from "./start.js";
5
5
  import { stop } from "./stop.js";
6
6
 
7
- export async function restart(name: string): Promise<void> {
7
+ export interface RestartOptions {
8
+ model?: string;
9
+ }
10
+
11
+ export async function restart(name: string, options: RestartOptions = {}): Promise<void> {
8
12
  const config = loadConfig();
9
13
 
10
14
  if (!config) {
@@ -34,6 +38,9 @@ export async function restart(name: string): Promise<void> {
34
38
  // Find agent config to get workdir and other settings
35
39
  const agentConfig = config.agents.find((a) => a.name === name);
36
40
 
41
+ // Model priority: CLI option > previous runtime model > agent config
42
+ const effectiveModel = options.model || agent.runtimeModel || agentConfig?.model;
43
+
37
44
  console.log(pc.dim("Starting new session..."));
38
45
 
39
46
  // Start with the same settings, agent ID will be reused from state
@@ -41,7 +48,7 @@ export async function restart(name: string): Promise<void> {
41
48
  name,
42
49
  command: agentConfig?.command,
43
50
  workdir: agentConfig?.workdir,
44
- model: agentConfig?.model,
51
+ model: effectiveModel,
45
52
  foreground: false,
46
53
  });
47
54
 
package/src/cli/status.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import pc from "picocolors";
2
2
  import { loadConfig, loadState } from "../config/loader.js";
3
+ import { getRunnerDisplayName } from "../core/runner.js";
3
4
  import { getSessionName, sessionExists } from "../core/tmux.js";
4
5
 
5
6
  interface HealthResponse {
@@ -60,7 +61,11 @@ export async function status(): Promise<void> {
60
61
  console.log(` Total: ${pc.dim(String(state.agents.length))}`);
61
62
 
62
63
  if (runningAgents.length > 0) {
63
- console.log(` Names: ${pc.dim(runningAgents.map((a) => a.name).join(", "))}`);
64
+ console.log(` Active:`);
65
+ for (const agent of runningAgents) {
66
+ const modelInfo = agent.runtimeModel ? ` [${agent.runtimeModel}]` : "";
67
+ console.log(` - ${pc.cyan(agent.name)}${pc.dim(modelInfo)}`);
68
+ }
64
69
  }
65
70
 
66
71
  // Check tmux
package/src/cli/whoami.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import pc from "picocolors";
2
2
  import { loadConfig, loadState } from "../config/loader.js";
3
+ import { getRunnerDisplayName, type RunnerType } from "../core/runner.js";
3
4
  import { decodeToken, getTokenExpiry } from "../utils/jwt.js";
4
5
 
5
6
  export async function whoami(agentName?: string): Promise<void> {
@@ -23,9 +24,18 @@ export async function whoami(agentName?: string): Promise<void> {
23
24
  const expiry = getTokenExpiry(envToken);
24
25
  const expiryStr = formatExpiry(expiry);
25
26
 
27
+ // Find the agent in state to get model info
28
+ const agentState = state.agents.find((a) => a.agentId === envAgentId);
29
+
26
30
  console.log(pc.bold("Current Agent"));
27
31
  console.log(` ID: ${pc.cyan(envAgentId)}`);
28
32
  console.log(` Workspace: ${pc.dim(config.workspace)}`);
33
+ if (agentState?.runtimeModel) {
34
+ const runnerName = agentState.runnerType
35
+ ? getRunnerDisplayName(agentState.runnerType)
36
+ : "Unknown";
37
+ console.log(` Model: ${pc.cyan(agentState.runtimeModel)} (${pc.dim(runnerName)})`);
38
+ }
29
39
  console.log(` Token: ${expiryStr}`);
30
40
  console.log(` Hub: ${pc.dim(config.hubUrl)}`);
31
41
  return;
@@ -49,6 +59,10 @@ export async function whoami(agentName?: string): Promise<void> {
49
59
  console.log(` ${pc.cyan(agent.name)}`);
50
60
  console.log(` ID: ${pc.dim(agent.agentId)}`);
51
61
  console.log(` Status: ${running ? pc.green("running") : pc.yellow("stopped")}`);
62
+ if (agent.runtimeModel) {
63
+ const runnerName = agent.runnerType ? getRunnerDisplayName(agent.runnerType) : "Unknown";
64
+ console.log(` Model: ${pc.dim(agent.runtimeModel)} (${runnerName})`);
65
+ }
52
66
  console.log(` Token: ${expiryStr}`);
53
67
  console.log();
54
68
  }
@@ -71,6 +85,10 @@ export async function whoami(agentName?: string): Promise<void> {
71
85
  console.log(` ID: ${pc.cyan(agent.agentId)}`);
72
86
  console.log(` Workspace: ${pc.dim(config.workspace)}`);
73
87
  console.log(` Status: ${running ? pc.green("running") : pc.yellow("stopped")}`);
88
+ if (agent.runtimeModel) {
89
+ const runnerName = agent.runnerType ? getRunnerDisplayName(agent.runnerType) : "Unknown";
90
+ console.log(` Model: ${pc.cyan(agent.runtimeModel)} (${pc.dim(runnerName)})`);
91
+ }
74
92
  console.log(` Token: ${expiryStr}`);
75
93
  console.log(` Session: ${pc.dim(agent.tmuxSession || "none")}`);
76
94
  console.log(` Started: ${pc.dim(agent.startedAt || "unknown")}`);
@@ -30,6 +30,8 @@ export const DEFAULT_CONFIG: Partial<Config> = {
30
30
  export const CONFIG_PATH = `${process.env.HOME}/.agentmesh/config.json`;
31
31
  export const STATE_PATH = `${process.env.HOME}/.agentmesh/state.json`;
32
32
 
33
+ export type RunnerType = "opencode" | "claude" | "custom";
34
+
33
35
  export interface AgentState {
34
36
  name: string;
35
37
  agentId: string;
@@ -37,6 +39,10 @@ export interface AgentState {
37
39
  tmuxSession: string;
38
40
  startedAt: string;
39
41
  token?: string;
42
+ /** The effective runtime model (resolved from CLI > agent > defaults) */
43
+ runtimeModel?: string;
44
+ /** The runner type (opencode, claude, custom) */
45
+ runnerType?: RunnerType;
40
46
  }
41
47
 
42
48
  export interface State {
@@ -2,6 +2,7 @@ import {
2
2
  addAgentToState,
3
3
  getAgentState,
4
4
  loadConfig,
5
+ loadState,
5
6
  removeAgentFromState,
6
7
  updateAgentInState,
7
8
  } from "../config/loader.js";
@@ -10,6 +11,7 @@ import { loadContext, loadOrCreateContext, saveContext } from "../context/index.
10
11
  import { Heartbeat } from "./heartbeat.js";
11
12
  import { handleWebSocketEvent, injectRestoredContext, injectStartupMessage } from "./injector.js";
12
13
  import { checkInbox, registerAgent } from "./registry.js";
14
+ import { buildRunnerConfig, getRunnerDisplayName, type RunnerConfig } from "./runner.js";
13
15
  import {
14
16
  captureSessionContext,
15
17
  createSession,
@@ -34,6 +36,7 @@ export class AgentDaemon {
34
36
  private agentName: string;
35
37
  private config: Config;
36
38
  private agentConfig: AgentConfig;
39
+ private runnerConfig: RunnerConfig;
37
40
  private ws: AgentWebSocket | null = null;
38
41
  private heartbeat: Heartbeat | null = null;
39
42
  private token: string | null = null;
@@ -69,6 +72,58 @@ export class AgentDaemon {
69
72
  if (options.model) agentConfig.model = options.model;
70
73
 
71
74
  this.agentConfig = agentConfig;
75
+
76
+ // Build runner configuration with model resolution
77
+ this.runnerConfig = buildRunnerConfig({
78
+ cliModel: options.model,
79
+ agentModel: agentConfig.model,
80
+ defaultModel: config.defaults.model,
81
+ command: agentConfig.command,
82
+ });
83
+
84
+ const runnerName = getRunnerDisplayName(this.runnerConfig.type);
85
+ console.log(`Runner: ${runnerName}`);
86
+ console.log(`Effective model: ${this.runnerConfig.model}`);
87
+
88
+ // Check workdir conflicts - prevent multiple agents from using same directory
89
+ this.checkWorkdirConflict(agentConfig.workdir);
90
+ }
91
+
92
+ /**
93
+ * Checks if another agent is already using the specified workdir
94
+ */
95
+ private checkWorkdirConflict(workdir?: string): void {
96
+ if (!workdir) return;
97
+
98
+ const state = loadState();
99
+ const conflictingAgent = state.agents.find((a) => {
100
+ // Skip self
101
+ if (a.name === this.agentName) return false;
102
+
103
+ // Check if agent is actually running
104
+ if (!a.pid) return false;
105
+ try {
106
+ process.kill(a.pid, 0); // Check if process exists
107
+ } catch {
108
+ return false; // Process not running
109
+ }
110
+
111
+ // Check if session exists and has same workdir
112
+ // We need to check the config for this agent's workdir
113
+ const otherAgentConfig = this.config.agents.find((c) => c.name === a.name);
114
+ if (otherAgentConfig?.workdir === workdir) {
115
+ return true;
116
+ }
117
+
118
+ return false;
119
+ });
120
+
121
+ if (conflictingAgent) {
122
+ throw new Error(
123
+ `Workdir conflict: Agent "${conflictingAgent.name}" is already using "${workdir}".\n` +
124
+ `Use a different --workdir or stop the other agent first.`,
125
+ );
126
+ }
72
127
  }
73
128
 
74
129
  async start(): Promise<void> {
@@ -90,6 +145,7 @@ export class AgentDaemon {
90
145
  this.agentName,
91
146
  this.agentConfig.command,
92
147
  this.agentConfig.workdir,
148
+ this.runnerConfig.env, // Pass runner env vars (e.g., OPENCODE_MODEL)
93
149
  );
94
150
 
95
151
  if (!created) {
@@ -97,6 +153,10 @@ export class AgentDaemon {
97
153
  }
98
154
  } else {
99
155
  console.log(`Reconnecting to existing session: ${sessionName}`);
156
+ // Update environment for existing session
157
+ if (Object.keys(this.runnerConfig.env).length > 0) {
158
+ updateSessionEnvironment(this.agentName, this.runnerConfig.env);
159
+ }
100
160
  }
101
161
 
102
162
  // Register with hub
@@ -132,6 +192,8 @@ export class AgentDaemon {
132
192
  tmuxSession: sessionName,
133
193
  startedAt: new Date().toISOString(),
134
194
  token: this.token,
195
+ runtimeModel: this.runnerConfig.model,
196
+ runnerType: this.runnerConfig.type,
135
197
  });
136
198
 
137
199
  // Start heartbeat with auto-refresh