@agentmeshhq/agent 0.2.1 → 0.4.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.
Files changed (65) hide show
  1. package/README.md +6 -0
  2. package/dist/__tests__/context-template.test.d.ts +4 -0
  3. package/dist/__tests__/context-template.test.js +235 -0
  4. package/dist/__tests__/context-template.test.js.map +1 -0
  5. package/dist/__tests__/default-branch-fallback.test.d.ts +10 -0
  6. package/dist/__tests__/default-branch-fallback.test.js +123 -0
  7. package/dist/__tests__/default-branch-fallback.test.js.map +1 -0
  8. package/dist/__tests__/default-repo-fallback.test.d.ts +12 -0
  9. package/dist/__tests__/default-repo-fallback.test.js +156 -0
  10. package/dist/__tests__/default-repo-fallback.test.js.map +1 -0
  11. package/dist/__tests__/loader.test.js +140 -28
  12. package/dist/__tests__/loader.test.js.map +1 -1
  13. package/dist/__tests__/no-respawn.test.d.ts +1 -0
  14. package/dist/__tests__/no-respawn.test.js +254 -0
  15. package/dist/__tests__/no-respawn.test.js.map +1 -0
  16. package/dist/__tests__/onboard.test.d.ts +5 -0
  17. package/dist/__tests__/onboard.test.js +343 -0
  18. package/dist/__tests__/onboard.test.js.map +1 -0
  19. package/dist/__tests__/project-flag.test.d.ts +9 -0
  20. package/dist/__tests__/project-flag.test.js +140 -0
  21. package/dist/__tests__/project-flag.test.js.map +1 -0
  22. package/dist/__tests__/shared-resource-guards.test.d.ts +7 -0
  23. package/dist/__tests__/shared-resource-guards.test.js +260 -0
  24. package/dist/__tests__/shared-resource-guards.test.js.map +1 -0
  25. package/dist/cli/index.js +6 -0
  26. package/dist/cli/index.js.map +1 -1
  27. package/dist/cli/start.d.ts +4 -0
  28. package/dist/cli/start.js +6 -0
  29. package/dist/cli/start.js.map +1 -1
  30. package/dist/config/loader.d.ts +0 -4
  31. package/dist/config/loader.js +102 -42
  32. package/dist/config/loader.js.map +1 -1
  33. package/dist/config/schema.d.ts +2 -2
  34. package/dist/core/daemon/bootstrap.d.ts +4 -0
  35. package/dist/core/daemon/bootstrap.js +2 -0
  36. package/dist/core/daemon/bootstrap.js.map +1 -1
  37. package/dist/core/daemon/context-template.d.ts +11 -0
  38. package/dist/core/daemon/context-template.js +144 -0
  39. package/dist/core/daemon/context-template.js.map +1 -0
  40. package/dist/core/daemon/crash-log.d.ts +0 -2
  41. package/dist/core/daemon/crash-log.js +0 -1
  42. package/dist/core/daemon/crash-log.js.map +1 -1
  43. package/dist/core/daemon/git-auth.d.ts +18 -0
  44. package/dist/core/daemon/git-auth.js +94 -0
  45. package/dist/core/daemon/git-auth.js.map +1 -0
  46. package/dist/core/daemon/health-policy.d.ts +0 -4
  47. package/dist/core/daemon/health-policy.js +0 -8
  48. package/dist/core/daemon/health-policy.js.map +1 -1
  49. package/dist/core/daemon/state.js +1 -0
  50. package/dist/core/daemon/state.js.map +1 -1
  51. package/dist/core/daemon/workspace.d.ts +13 -0
  52. package/dist/core/daemon/workspace.js +39 -0
  53. package/dist/core/daemon/workspace.js.map +1 -1
  54. package/dist/core/daemon.d.ts +19 -6
  55. package/dist/core/daemon.js +337 -199
  56. package/dist/core/daemon.js.map +1 -1
  57. package/dist/core/injector.d.ts +5 -1
  58. package/dist/core/injector.js +77 -0
  59. package/dist/core/injector.js.map +1 -1
  60. package/dist/core/registry.d.ts +97 -0
  61. package/dist/core/registry.js +59 -0
  62. package/dist/core/registry.js.map +1 -1
  63. package/dist/core/tmux-runtime.js +4 -0
  64. package/dist/core/tmux-runtime.js.map +1 -1
  65. package/package.json +1 -1
@@ -0,0 +1,343 @@
1
+ /**
2
+ * Onboard Tests - Epic #103
3
+ * Tests for git-auth setup/cleanup and onboard message injection.
4
+ */
5
+ import { execSync } from "node:child_process";
6
+ import * as fs from "node:fs";
7
+ import { beforeEach, describe, expect, it, vi } from "vitest";
8
+ import { cleanupGitAuth, setupGitAuth } from "../core/daemon/git-auth.js";
9
+ import { configureGitIdentity, validatePushAccess } from "../core/daemon/workspace.js";
10
+ import { injectOnboardMessage } from "../core/injector.js";
11
+ // ============================================================================
12
+ // Mock tmux sendKeys
13
+ // ============================================================================
14
+ const { sendKeysMock } = vi.hoisted(() => ({
15
+ sendKeysMock: vi.fn(),
16
+ }));
17
+ vi.mock("../core/tmux.js", () => ({
18
+ sendKeys: sendKeysMock,
19
+ }));
20
+ // ============================================================================
21
+ // Mock child_process for workspace tests
22
+ // ============================================================================
23
+ vi.mock("node:child_process", () => ({
24
+ execSync: vi.fn(),
25
+ }));
26
+ // ============================================================================
27
+ // Mock fs for git-auth tests
28
+ // ============================================================================
29
+ vi.mock("node:fs");
30
+ const mockFs = vi.mocked(fs);
31
+ // ============================================================================
32
+ // injectOnboardMessage tests
33
+ // ============================================================================
34
+ describe("injectOnboardMessage", () => {
35
+ beforeEach(() => {
36
+ vi.clearAllMocks();
37
+ });
38
+ const baseOnboard = {
39
+ agent: {
40
+ agent_id: "agent-123",
41
+ display_name: "test-agent",
42
+ model: "claude-sonnet-4",
43
+ capabilities: ["coding", "review"],
44
+ },
45
+ assignment: {
46
+ assignment_id: "asn-1",
47
+ role: "contributor",
48
+ priority: 8,
49
+ notes: "Primary dev",
50
+ },
51
+ project: {
52
+ project_id: "prj-1",
53
+ name: "TestProject",
54
+ code: "TP",
55
+ description: "A test project",
56
+ workdir: "/workspace",
57
+ default_branch: null,
58
+ default_repo_id: null,
59
+ instructions: "Follow coding guidelines.",
60
+ workflow_config: {
61
+ branch_prefix: "feat/",
62
+ pr_target_branch: "dev",
63
+ commit_convention: "conventional",
64
+ protected_branches: ["main", "dev"],
65
+ code_review_required: true,
66
+ custom_rules: ["Run tests first"],
67
+ },
68
+ },
69
+ repos: [
70
+ {
71
+ repo_id: "rep-1",
72
+ provider: "github",
73
+ full_name: "org/repo",
74
+ url: "https://github.com/org/repo.git",
75
+ default_branch: "main",
76
+ credential: null,
77
+ },
78
+ ],
79
+ team: [
80
+ {
81
+ agent_id: "agent-456",
82
+ display_name: "review-bot",
83
+ model: "claude-opus-4-5",
84
+ role: "reviewer",
85
+ status: "online",
86
+ },
87
+ ],
88
+ hub_api: {
89
+ handoffs: "POST /api/v1/workspaces/:workspace/handoffs",
90
+ claims: "POST /api/v1/workspaces/:workspace/claims",
91
+ blockers: "POST /api/v1/workspaces/:workspace/blockers",
92
+ inbox: "GET /api/v1/workspaces/:workspace/inbox",
93
+ heartbeat: "POST /api/v1/agents/heartbeat",
94
+ },
95
+ };
96
+ it("injects structured onboard message with all sections", () => {
97
+ injectOnboardMessage("test-agent", baseOnboard);
98
+ expect(sendKeysMock).toHaveBeenCalledTimes(1);
99
+ const message = String(sendKeysMock.mock.calls[0]?.[1] ?? "");
100
+ // Identity section
101
+ expect(message).toContain("test-agent");
102
+ expect(message).toContain("claude-sonnet-4");
103
+ expect(message).toContain("contributor");
104
+ // Project section
105
+ expect(message).toContain("TestProject");
106
+ expect(message).toContain("TP");
107
+ expect(message).toContain("A test project");
108
+ // Repository section
109
+ expect(message).toContain("org/repo");
110
+ expect(message).toContain("github");
111
+ // Workflow rules
112
+ expect(message).toContain("feat/");
113
+ expect(message).toContain("dev");
114
+ expect(message).toContain("conventional");
115
+ expect(message).toContain("Run tests first");
116
+ // Team section
117
+ expect(message).toContain("review-bot");
118
+ expect(message).toContain("reviewer");
119
+ expect(message).toContain("online");
120
+ // Hub API
121
+ expect(message).toContain("handoffs");
122
+ expect(message).toContain("heartbeat");
123
+ // Instructions
124
+ expect(message).toContain("Follow coding guidelines.");
125
+ });
126
+ it("handles agent with no assignment or project", () => {
127
+ const noProject = {
128
+ ...baseOnboard,
129
+ assignment: null,
130
+ project: null,
131
+ repos: [],
132
+ team: [],
133
+ };
134
+ injectOnboardMessage("lonely-agent", noProject);
135
+ expect(sendKeysMock).toHaveBeenCalledTimes(1);
136
+ const message = String(sendKeysMock.mock.calls[0]?.[1] ?? "");
137
+ // Should still have identity
138
+ expect(message).toContain("test-agent");
139
+ expect(message).toContain("claude-sonnet-4");
140
+ // Should NOT have project/team sections content
141
+ expect(message).not.toContain("TestProject");
142
+ expect(message).not.toContain("review-bot");
143
+ });
144
+ it("handles empty custom rules and no instructions", () => {
145
+ const minimal = {
146
+ ...baseOnboard,
147
+ project: {
148
+ ...baseOnboard.project,
149
+ instructions: null,
150
+ workflow_config: {
151
+ ...baseOnboard.project.workflow_config,
152
+ custom_rules: [],
153
+ },
154
+ },
155
+ };
156
+ injectOnboardMessage("test-agent", minimal);
157
+ expect(sendKeysMock).toHaveBeenCalledTimes(1);
158
+ const message = String(sendKeysMock.mock.calls[0]?.[1] ?? "");
159
+ expect(message).not.toContain("Project Instructions");
160
+ });
161
+ });
162
+ // ============================================================================
163
+ // setupGitAuth tests
164
+ // ============================================================================
165
+ describe("setupGitAuth", () => {
166
+ beforeEach(() => {
167
+ vi.clearAllMocks();
168
+ mockFs.existsSync.mockReturnValue(false);
169
+ mockFs.mkdirSync.mockReturnValue(undefined);
170
+ mockFs.writeFileSync.mockReturnValue(undefined);
171
+ mockFs.appendFileSync.mockReturnValue(undefined);
172
+ });
173
+ it("creates credentials directory if missing", () => {
174
+ setupGitAuth({
175
+ type: "pat",
176
+ value: "ghp_test123",
177
+ repoUrl: "https://github.com/org/repo.git",
178
+ agentName: "test-agent",
179
+ });
180
+ expect(mockFs.mkdirSync).toHaveBeenCalledWith(expect.stringContaining("credentials"), expect.objectContaining({ recursive: true, mode: 0o700 }));
181
+ });
182
+ it("configures PAT credential with git-credentials file", () => {
183
+ const result = setupGitAuth({
184
+ type: "pat",
185
+ value: "ghp_test123",
186
+ repoUrl: "https://github.com/org/repo.git",
187
+ agentName: "my-agent",
188
+ });
189
+ // Should write credential file
190
+ expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining("my-agent.git-credentials"), expect.stringContaining("https://x-access-token:ghp_test123@github.com"), expect.objectContaining({ mode: 0o600 }));
191
+ // Should return git config env vars
192
+ expect(result.GIT_CONFIG_KEY_0).toBe("credential.helper");
193
+ expect(result.GIT_CONFIG_VALUE_0).toContain("store");
194
+ expect(result.GIT_CONFIG_VALUE_0).toContain("my-agent.git-credentials");
195
+ });
196
+ it("configures SSH deploy key", () => {
197
+ const sshKey = "-----BEGIN OPENSSH PRIVATE KEY-----\ntest\n-----END OPENSSH PRIVATE KEY-----";
198
+ const result = setupGitAuth({
199
+ type: "ssh_deploy_key",
200
+ value: sshKey,
201
+ repoUrl: "git@github.com:org/repo.git",
202
+ agentName: "ssh-agent",
203
+ });
204
+ // Should write key file with correct permissions
205
+ expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining("ssh-agent.deploy-key"), sshKey, expect.objectContaining({ mode: 0o600 }));
206
+ // Should return GIT_SSH_COMMAND
207
+ expect(result.GIT_SSH_COMMAND).toContain("ssh -i");
208
+ expect(result.GIT_SSH_COMMAND).toContain("ssh-agent.deploy-key");
209
+ expect(result.GIT_SSH_COMMAND).toContain("StrictHostKeyChecking=no");
210
+ });
211
+ it("extracts host from repo URL for PAT", () => {
212
+ setupGitAuth({
213
+ type: "pat",
214
+ value: "token123",
215
+ repoUrl: "https://gitlab.com/org/repo.git",
216
+ agentName: "gitlab-agent",
217
+ });
218
+ expect(mockFs.writeFileSync).toHaveBeenCalledWith(expect.any(String), expect.stringContaining("@gitlab.com"), expect.any(Object));
219
+ });
220
+ it("returns empty object for unknown credential type", () => {
221
+ const result = setupGitAuth({
222
+ type: "unknown_type",
223
+ value: "something",
224
+ repoUrl: "https://github.com/org/repo.git",
225
+ agentName: "test-agent",
226
+ });
227
+ expect(result).toEqual({});
228
+ });
229
+ });
230
+ // ============================================================================
231
+ // cleanupGitAuth tests
232
+ // ============================================================================
233
+ describe("cleanupGitAuth", () => {
234
+ beforeEach(() => {
235
+ vi.clearAllMocks();
236
+ });
237
+ it("removes credential files for an agent", () => {
238
+ mockFs.existsSync.mockReturnValue(true);
239
+ mockFs.unlinkSync.mockReturnValue(undefined);
240
+ cleanupGitAuth("my-agent");
241
+ expect(mockFs.unlinkSync).toHaveBeenCalledTimes(2);
242
+ expect(mockFs.unlinkSync).toHaveBeenCalledWith(expect.stringContaining("my-agent.git-credentials"));
243
+ expect(mockFs.unlinkSync).toHaveBeenCalledWith(expect.stringContaining("my-agent.deploy-key"));
244
+ });
245
+ it("skips files that do not exist", () => {
246
+ mockFs.existsSync.mockReturnValue(false);
247
+ cleanupGitAuth("no-files-agent");
248
+ expect(mockFs.unlinkSync).not.toHaveBeenCalled();
249
+ });
250
+ it("handles unlink errors gracefully", () => {
251
+ mockFs.existsSync.mockReturnValue(true);
252
+ mockFs.unlinkSync.mockImplementation(() => {
253
+ throw new Error("permission denied");
254
+ });
255
+ // Should not throw
256
+ expect(() => cleanupGitAuth("error-agent")).not.toThrow();
257
+ });
258
+ });
259
+ // ============================================================================
260
+ // fetchOnboard type tests
261
+ // ============================================================================
262
+ describe("OnboardData types", () => {
263
+ it("OnboardData structure is valid", () => {
264
+ const data = {
265
+ agent: {
266
+ agent_id: "id",
267
+ display_name: "name",
268
+ model: "model",
269
+ capabilities: [],
270
+ },
271
+ assignment: null,
272
+ project: null,
273
+ repos: [],
274
+ team: [],
275
+ hub_api: {
276
+ handoffs: "",
277
+ claims: "",
278
+ blockers: "",
279
+ inbox: "",
280
+ heartbeat: "",
281
+ },
282
+ };
283
+ expect(data.agent.agent_id).toBe("id");
284
+ expect(data.assignment).toBeNull();
285
+ expect(data.repos).toHaveLength(0);
286
+ });
287
+ });
288
+ // ============================================================================
289
+ // configureGitIdentity tests
290
+ // ============================================================================
291
+ const mockExecSync = vi.mocked(execSync);
292
+ describe("configureGitIdentity", () => {
293
+ beforeEach(() => {
294
+ vi.clearAllMocks();
295
+ });
296
+ it("sets user.name and user.email via git config", () => {
297
+ mockExecSync.mockReturnValue(Buffer.from(""));
298
+ configureGitIdentity({
299
+ workspacePath: "/workspace",
300
+ agentName: "my-agent",
301
+ agentDisplayName: "My Agent",
302
+ });
303
+ expect(mockExecSync).toHaveBeenCalledWith('git config user.name "My Agent"', expect.objectContaining({ cwd: "/workspace" }));
304
+ expect(mockExecSync).toHaveBeenCalledWith('git config user.email "my-agent@agents.agentmeshhq.dev"', expect.objectContaining({ cwd: "/workspace" }));
305
+ });
306
+ it("handles errors gracefully", () => {
307
+ mockExecSync.mockImplementation(() => {
308
+ throw new Error("not a git repo");
309
+ });
310
+ expect(() => configureGitIdentity({
311
+ workspacePath: "/bad-path",
312
+ agentName: "agent",
313
+ agentDisplayName: "Agent",
314
+ })).not.toThrow();
315
+ });
316
+ });
317
+ // ============================================================================
318
+ // validatePushAccess tests
319
+ // ============================================================================
320
+ describe("validatePushAccess", () => {
321
+ beforeEach(() => {
322
+ vi.clearAllMocks();
323
+ });
324
+ it("returns true when dry-run succeeds", () => {
325
+ mockExecSync.mockReturnValue(Buffer.from(""));
326
+ const result = validatePushAccess("/workspace");
327
+ expect(result).toBe(true);
328
+ expect(mockExecSync).toHaveBeenCalledWith("git push --dry-run origin HEAD", expect.objectContaining({ cwd: "/workspace", timeout: 15_000 }));
329
+ });
330
+ it("returns false when dry-run fails", () => {
331
+ mockExecSync.mockImplementation(() => {
332
+ throw new Error("permission denied");
333
+ });
334
+ const result = validatePushAccess("/workspace");
335
+ expect(result).toBe(false);
336
+ });
337
+ it("uses custom remote branch when provided", () => {
338
+ mockExecSync.mockReturnValue(Buffer.from(""));
339
+ validatePushAccess("/workspace", "feature/test");
340
+ expect(mockExecSync).toHaveBeenCalledWith("git push --dry-run origin feature/test", expect.objectContaining({ cwd: "/workspace" }));
341
+ });
342
+ });
343
+ //# sourceMappingURL=onboard.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboard.test.js","sourceRoot":"","sources":["../../src/__tests__/onboard.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Tests for --project flag workdir resolution logic.
3
+ *
4
+ * When --project is passed, the daemon resolves the workdir from HQ:
5
+ * 1. Fetches project by code
6
+ * 2. Computes per-agent workdir from project.workdir or fallback path
7
+ * 3. Validates project + repo exist
8
+ */
9
+ export {};
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Tests for --project flag workdir resolution logic.
3
+ *
4
+ * When --project is passed, the daemon resolves the workdir from HQ:
5
+ * 1. Fetches project by code
6
+ * 2. Computes per-agent workdir from project.workdir or fallback path
7
+ * 3. Validates project + repo exist
8
+ */
9
+ import os from "node:os";
10
+ import path from "node:path";
11
+ import { describe, expect, it } from "vitest";
12
+ /**
13
+ * Mirrors the workdir computation from daemon.ts resolveProjectWorkdir()
14
+ */
15
+ function computeProjectWorkdir(result, agentName, workspace) {
16
+ const { project } = result;
17
+ if (project.workdir) {
18
+ return path.join(path.dirname(project.workdir), `${path.basename(project.workdir)}-${agentName}`);
19
+ }
20
+ return path.join(os.homedir(), ".agentmesh", "workspaces", workspace, project.code.toLowerCase(), agentName);
21
+ }
22
+ function makeLookupResult(overrides) {
23
+ return {
24
+ project: {
25
+ project_id: "prj-1",
26
+ name: "AgentMesh",
27
+ code: overrides.code ?? "MESH",
28
+ description: null,
29
+ workdir: overrides.workdir ?? null,
30
+ default_branch: "dev",
31
+ },
32
+ repo: overrides.repo !== undefined
33
+ ? overrides.repo
34
+ ? {
35
+ repo_id: "rep-1",
36
+ provider: "github",
37
+ full_name: "org/repo",
38
+ url: overrides.repo.url,
39
+ default_branch: overrides.repo.default_branch,
40
+ }
41
+ : null
42
+ : {
43
+ repo_id: "rep-1",
44
+ provider: "github",
45
+ full_name: "org/agentmesh",
46
+ url: "https://github.com/org/agentmesh.git",
47
+ default_branch: "dev",
48
+ },
49
+ };
50
+ }
51
+ describe("--project flag workdir resolution", () => {
52
+ it("computes sibling dir when project has workdir set", () => {
53
+ const result = makeLookupResult({ workdir: "/Users/raju/Dev/agentmesh" });
54
+ const workdir = computeProjectWorkdir(result, "fullstack-1", "default");
55
+ expect(workdir).toBe("/Users/raju/Dev/agentmesh-fullstack-1");
56
+ });
57
+ it("computes sibling dir preserving parent path", () => {
58
+ const result = makeLookupResult({ workdir: "/home/user/projects/myapp" });
59
+ const workdir = computeProjectWorkdir(result, "agent-2", "default");
60
+ expect(workdir).toBe("/home/user/projects/myapp-agent-2");
61
+ });
62
+ it("falls back to managed workspace path when no project workdir", () => {
63
+ const result = makeLookupResult({ workdir: null, code: "MESH" });
64
+ const workdir = computeProjectWorkdir(result, "test-agent", "acme");
65
+ expect(workdir).toBe(path.join(os.homedir(), ".agentmesh", "workspaces", "acme", "mesh", "test-agent"));
66
+ });
67
+ it("lowercases project code in fallback path", () => {
68
+ const result = makeLookupResult({ workdir: null, code: "DASHBOARD" });
69
+ const workdir = computeProjectWorkdir(result, "bot-1", "ws1");
70
+ expect(workdir).toContain("/dashboard/");
71
+ expect(workdir).not.toContain("/DASHBOARD/");
72
+ });
73
+ it("each agent gets a unique workdir from same project", () => {
74
+ const result = makeLookupResult({ workdir: "/Users/raju/Dev/agentmesh" });
75
+ const workdir1 = computeProjectWorkdir(result, "agent-1", "default");
76
+ const workdir2 = computeProjectWorkdir(result, "agent-2", "default");
77
+ const workdir3 = computeProjectWorkdir(result, "product-owner", "default");
78
+ expect(workdir1).toBe("/Users/raju/Dev/agentmesh-agent-1");
79
+ expect(workdir2).toBe("/Users/raju/Dev/agentmesh-agent-2");
80
+ expect(workdir3).toBe("/Users/raju/Dev/agentmesh-product-owner");
81
+ // All unique
82
+ const set = new Set([workdir1, workdir2, workdir3]);
83
+ expect(set.size).toBe(3);
84
+ });
85
+ });
86
+ describe("--project flag validation", () => {
87
+ it("rejects when project lookup returns null (not found)", () => {
88
+ const result = null;
89
+ expect(result).toBeNull();
90
+ // In daemon.ts this throws: `Project "${code}" not found`
91
+ });
92
+ it("rejects when project has no repo", () => {
93
+ const result = makeLookupResult({ repo: null });
94
+ expect(result.repo).toBeNull();
95
+ // In daemon.ts this throws: `Project "${name}" has no repositories configured`
96
+ });
97
+ it("accepts when project has repo", () => {
98
+ const result = makeLookupResult({
99
+ repo: { url: "https://github.com/org/repo.git", default_branch: "main" },
100
+ });
101
+ expect(result.repo).not.toBeNull();
102
+ expect(result.repo?.url).toBe("https://github.com/org/repo.git");
103
+ });
104
+ it("uses project default_branch as fallback when repo has none", () => {
105
+ const result = makeLookupResult({
106
+ repo: { url: "https://github.com/org/repo.git", default_branch: null },
107
+ });
108
+ // In daemon.ts: repo.default_branch ?? project.default_branch ?? "main"
109
+ const branch = result.repo?.default_branch ?? result.project.default_branch ?? "main";
110
+ expect(branch).toBe("dev"); // project.default_branch
111
+ });
112
+ it("falls back to 'main' when both are null", () => {
113
+ const result = makeLookupResult({
114
+ repo: { url: "https://github.com/org/repo.git", default_branch: null },
115
+ });
116
+ result.project.default_branch = null;
117
+ const branch = result.repo?.default_branch ?? result.project.default_branch ?? "main";
118
+ expect(branch).toBe("main");
119
+ });
120
+ });
121
+ describe("--project and --workdir mutual exclusivity", () => {
122
+ it("should not allow both --project and --workdir", () => {
123
+ // This validation happens in CLI index.ts before start() is called
124
+ const options = { project: "MESH", workdir: "/some/path" };
125
+ const hasBoth = !!(options.project && options.workdir);
126
+ expect(hasBoth).toBe(true);
127
+ // CLI exits with error: "Cannot use --project and --workdir together"
128
+ });
129
+ it("allows --project without --workdir", () => {
130
+ const options = { project: "MESH", workdir: undefined };
131
+ const hasBoth = !!(options.project && options.workdir);
132
+ expect(hasBoth).toBe(false);
133
+ });
134
+ it("allows --workdir without --project", () => {
135
+ const options = { project: undefined, workdir: "/some/path" };
136
+ const hasBoth = !!(options.project && options.workdir);
137
+ expect(hasBoth).toBe(false);
138
+ });
139
+ });
140
+ //# sourceMappingURL=project-flag.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-flag.test.js","sourceRoot":"","sources":["../../src/__tests__/project-flag.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Shared Resource Guards Tests
3
+ *
4
+ * Tests for workdir conflict detection, serve port collision detection,
5
+ * HQ workdir per-agent expansion, and servePort state persistence.
6
+ */
7
+ export {};