@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.
- package/README.md +6 -0
- package/dist/__tests__/context-template.test.d.ts +4 -0
- package/dist/__tests__/context-template.test.js +235 -0
- package/dist/__tests__/context-template.test.js.map +1 -0
- package/dist/__tests__/default-branch-fallback.test.d.ts +10 -0
- package/dist/__tests__/default-branch-fallback.test.js +123 -0
- package/dist/__tests__/default-branch-fallback.test.js.map +1 -0
- package/dist/__tests__/default-repo-fallback.test.d.ts +12 -0
- package/dist/__tests__/default-repo-fallback.test.js +156 -0
- package/dist/__tests__/default-repo-fallback.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 +343 -0
- package/dist/__tests__/onboard.test.js.map +1 -0
- package/dist/__tests__/project-flag.test.d.ts +9 -0
- package/dist/__tests__/project-flag.test.js +140 -0
- package/dist/__tests__/project-flag.test.js.map +1 -0
- 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/cli/index.js +6 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/start.d.ts +4 -0
- package/dist/cli/start.js +6 -0
- package/dist/cli/start.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 +2 -2
- package/dist/core/daemon/bootstrap.d.ts +4 -0
- package/dist/core/daemon/bootstrap.js +2 -0
- package/dist/core/daemon/bootstrap.js.map +1 -1
- 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 +0 -2
- package/dist/core/daemon/crash-log.js +0 -1
- package/dist/core/daemon/crash-log.js.map +1 -1
- package/dist/core/daemon/git-auth.d.ts +18 -0
- package/dist/core/daemon/git-auth.js +94 -0
- package/dist/core/daemon/git-auth.js.map +1 -0
- package/dist/core/daemon/health-policy.d.ts +0 -4
- package/dist/core/daemon/health-policy.js +0 -8
- package/dist/core/daemon/health-policy.js.map +1 -1
- package/dist/core/daemon/state.js +1 -0
- package/dist/core/daemon/state.js.map +1 -1
- package/dist/core/daemon/workspace.d.ts +13 -0
- package/dist/core/daemon/workspace.js +39 -0
- package/dist/core/daemon/workspace.js.map +1 -1
- package/dist/core/daemon.d.ts +19 -6
- package/dist/core/daemon.js +337 -199
- package/dist/core/daemon.js.map +1 -1
- package/dist/core/injector.d.ts +5 -1
- package/dist/core/injector.js +77 -0
- package/dist/core/injector.js.map +1 -1
- package/dist/core/registry.d.ts +97 -0
- package/dist/core/registry.js +59 -0
- package/dist/core/registry.js.map +1 -1
- package/dist/core/tmux-runtime.js +4 -0
- package/dist/core/tmux-runtime.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -154,6 +154,12 @@ In Feb 2026, `0.2.0` was published manually with `npm publish` from a commit who
|
|
|
154
154
|
|
|
155
155
|
The fix was to bump past `0.2.0` → `0.2.1` using the correct automated pipeline.
|
|
156
156
|
|
|
157
|
+
### March 2026: v0.3.0 manual publish (same mistake repeated)
|
|
158
|
+
|
|
159
|
+
Published `0.3.0` manually via `npm publish` during E2E verification of PR #304 (unique workdirs + deploy key cloning). The brew formula was also updated manually with an incorrect tarball URL (`agentmeshhq-agent-0.3.0.tgz` → 404; correct is `agent-0.3.0.tgz`). Additional issues found: deploy key credential inactive, orphaned GitHub deploy key, missing `repo_id` on agent assignments, FK violation on HQ deploy-key endpoint.
|
|
160
|
+
|
|
161
|
+
Fix: Corrected brew formula URL + SHA. Tagged `agent-v0.3.0` retroactively. Full post-mortem in `~/Dev/infra-docs/agent-release-ops.md`.
|
|
162
|
+
|
|
157
163
|
## License
|
|
158
164
|
|
|
159
165
|
MIT
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for context-template.ts — CLAUDE.md generation, write, and removal.
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
|
+
import { generateClaudeMd, removeClaudeMd, writeClaudeMd, } from "../core/daemon/context-template.js";
|
|
8
|
+
vi.mock("node:fs");
|
|
9
|
+
const mockFs = vi.mocked(fs);
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Shared test data
|
|
12
|
+
// ============================================================================
|
|
13
|
+
const baseOnboard = {
|
|
14
|
+
agent: {
|
|
15
|
+
agent_id: "agent-123",
|
|
16
|
+
display_name: "test-agent",
|
|
17
|
+
model: "claude-sonnet-4",
|
|
18
|
+
capabilities: ["coding", "review"],
|
|
19
|
+
},
|
|
20
|
+
assignment: {
|
|
21
|
+
assignment_id: "asn-1",
|
|
22
|
+
role: "contributor",
|
|
23
|
+
priority: 8,
|
|
24
|
+
notes: "Primary dev",
|
|
25
|
+
},
|
|
26
|
+
project: {
|
|
27
|
+
project_id: "prj-1",
|
|
28
|
+
name: "TestProject",
|
|
29
|
+
code: "TP",
|
|
30
|
+
description: "A test project",
|
|
31
|
+
workdir: "/workspace",
|
|
32
|
+
default_branch: null,
|
|
33
|
+
default_repo_id: null,
|
|
34
|
+
instructions: "Follow coding guidelines.",
|
|
35
|
+
workflow_config: {
|
|
36
|
+
branch_prefix: "feat/",
|
|
37
|
+
pr_target_branch: "dev",
|
|
38
|
+
commit_convention: "conventional",
|
|
39
|
+
protected_branches: ["main", "dev"],
|
|
40
|
+
code_review_required: true,
|
|
41
|
+
custom_rules: ["Run tests first"],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
repos: [
|
|
45
|
+
{
|
|
46
|
+
repo_id: "rep-1",
|
|
47
|
+
provider: "github",
|
|
48
|
+
full_name: "org/repo",
|
|
49
|
+
url: "https://github.com/org/repo.git",
|
|
50
|
+
default_branch: "main",
|
|
51
|
+
credential: { type: "pat", value: "ghp_SECRET" },
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
team: [
|
|
55
|
+
{
|
|
56
|
+
agent_id: "agent-456",
|
|
57
|
+
display_name: "review-bot",
|
|
58
|
+
model: "claude-opus-4-5",
|
|
59
|
+
role: "reviewer",
|
|
60
|
+
status: "online",
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
hub_api: {
|
|
64
|
+
handoffs: "POST /api/v1/workspaces/:workspace/handoffs",
|
|
65
|
+
claims: "POST /api/v1/workspaces/:workspace/claims",
|
|
66
|
+
blockers: "POST /api/v1/workspaces/:workspace/blockers",
|
|
67
|
+
inbox: "GET /api/v1/workspaces/:workspace/inbox",
|
|
68
|
+
heartbeat: "POST /api/v1/agents/heartbeat",
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
// ============================================================================
|
|
72
|
+
// generateClaudeMd
|
|
73
|
+
// ============================================================================
|
|
74
|
+
describe("generateClaudeMd", () => {
|
|
75
|
+
it("renders full output with all sections", () => {
|
|
76
|
+
const md = generateClaudeMd(baseOnboard);
|
|
77
|
+
// Auto-generated header
|
|
78
|
+
expect(md).toContain("AUTO-GENERATED by AgentMesh");
|
|
79
|
+
// Identity
|
|
80
|
+
expect(md).toContain("test-agent");
|
|
81
|
+
expect(md).toContain("claude-sonnet-4");
|
|
82
|
+
expect(md).toContain("contributor");
|
|
83
|
+
expect(md).toContain("coding, review");
|
|
84
|
+
// Project
|
|
85
|
+
expect(md).toContain("TestProject");
|
|
86
|
+
expect(md).toContain("`TP`");
|
|
87
|
+
expect(md).toContain("A test project");
|
|
88
|
+
// Workflow
|
|
89
|
+
expect(md).toContain("`feat/`");
|
|
90
|
+
expect(md).toContain("`dev`");
|
|
91
|
+
expect(md).toContain("conventional");
|
|
92
|
+
expect(md).toContain("NEVER push directly");
|
|
93
|
+
expect(md).toContain("Run tests first");
|
|
94
|
+
// Team
|
|
95
|
+
expect(md).toContain("review-bot");
|
|
96
|
+
expect(md).toContain("reviewer");
|
|
97
|
+
// Hub API
|
|
98
|
+
expect(md).toContain("handoffs");
|
|
99
|
+
expect(md).toContain("heartbeat");
|
|
100
|
+
// Repos
|
|
101
|
+
expect(md).toContain("`org/repo`");
|
|
102
|
+
expect(md).toContain("github");
|
|
103
|
+
// Instructions
|
|
104
|
+
expect(md).toContain("Follow coding guidelines.");
|
|
105
|
+
// Footer
|
|
106
|
+
expect(md).toContain("Generated at");
|
|
107
|
+
});
|
|
108
|
+
it("never includes credential values", () => {
|
|
109
|
+
const md = generateClaudeMd(baseOnboard);
|
|
110
|
+
expect(md).not.toContain("ghp_SECRET");
|
|
111
|
+
expect(md).not.toContain("credential");
|
|
112
|
+
});
|
|
113
|
+
it("handles no project", () => {
|
|
114
|
+
const noProject = {
|
|
115
|
+
...baseOnboard,
|
|
116
|
+
project: null,
|
|
117
|
+
assignment: null,
|
|
118
|
+
repos: [],
|
|
119
|
+
team: [],
|
|
120
|
+
};
|
|
121
|
+
const md = generateClaudeMd(noProject);
|
|
122
|
+
expect(md).toContain("test-agent");
|
|
123
|
+
expect(md).not.toContain("TestProject");
|
|
124
|
+
expect(md).not.toContain("Git Workflow Rules");
|
|
125
|
+
});
|
|
126
|
+
it("handles no team", () => {
|
|
127
|
+
const noTeam = { ...baseOnboard, team: [] };
|
|
128
|
+
const md = generateClaudeMd(noTeam);
|
|
129
|
+
expect(md).not.toContain("| Agent |");
|
|
130
|
+
expect(md).not.toContain("review-bot");
|
|
131
|
+
});
|
|
132
|
+
it("handles no instructions", () => {
|
|
133
|
+
const noInstructions = {
|
|
134
|
+
...baseOnboard,
|
|
135
|
+
project: { ...baseOnboard.project, instructions: null },
|
|
136
|
+
};
|
|
137
|
+
const md = generateClaudeMd(noInstructions);
|
|
138
|
+
expect(md).not.toContain("Project Instructions");
|
|
139
|
+
});
|
|
140
|
+
it("handles custom rules", () => {
|
|
141
|
+
const multiRules = {
|
|
142
|
+
...baseOnboard,
|
|
143
|
+
project: {
|
|
144
|
+
...baseOnboard.project,
|
|
145
|
+
workflow_config: {
|
|
146
|
+
...baseOnboard.project.workflow_config,
|
|
147
|
+
custom_rules: ["Rule A", "Rule B"],
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
const md = generateClaudeMd(multiRules);
|
|
152
|
+
expect(md).toContain("Rule A");
|
|
153
|
+
expect(md).toContain("Rule B");
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// writeClaudeMd
|
|
158
|
+
// ============================================================================
|
|
159
|
+
describe("writeClaudeMd", () => {
|
|
160
|
+
beforeEach(() => {
|
|
161
|
+
vi.clearAllMocks();
|
|
162
|
+
mockFs.writeFileSync.mockReturnValue(undefined);
|
|
163
|
+
mockFs.appendFileSync.mockReturnValue(undefined);
|
|
164
|
+
});
|
|
165
|
+
it("writes CLAUDE.md and returns path", () => {
|
|
166
|
+
mockFs.existsSync.mockImplementation((p) => {
|
|
167
|
+
if (String(p) === "/workspace")
|
|
168
|
+
return true;
|
|
169
|
+
if (String(p).endsWith(".gitignore"))
|
|
170
|
+
return false;
|
|
171
|
+
return false;
|
|
172
|
+
});
|
|
173
|
+
mockFs.readFileSync.mockReturnValue("");
|
|
174
|
+
const result = writeClaudeMd({ workdir: "/workspace", onboard: baseOnboard });
|
|
175
|
+
expect(result).toBe(path.join("/workspace", "CLAUDE.md"));
|
|
176
|
+
expect(mockFs.writeFileSync).toHaveBeenCalledWith(path.join("/workspace", "CLAUDE.md"), expect.stringContaining("AUTO-GENERATED"), expect.objectContaining({ encoding: "utf-8" }));
|
|
177
|
+
});
|
|
178
|
+
it("returns null if workdir does not exist", () => {
|
|
179
|
+
mockFs.existsSync.mockReturnValue(false);
|
|
180
|
+
const result = writeClaudeMd({ workdir: "/nonexistent", onboard: baseOnboard });
|
|
181
|
+
expect(result).toBeNull();
|
|
182
|
+
expect(mockFs.writeFileSync).not.toHaveBeenCalled();
|
|
183
|
+
});
|
|
184
|
+
it("appends CLAUDE.md to .gitignore if not present", () => {
|
|
185
|
+
mockFs.existsSync.mockImplementation((p) => {
|
|
186
|
+
if (String(p) === "/workspace")
|
|
187
|
+
return true;
|
|
188
|
+
if (String(p).endsWith(".gitignore"))
|
|
189
|
+
return true;
|
|
190
|
+
return false;
|
|
191
|
+
});
|
|
192
|
+
mockFs.readFileSync.mockReturnValue("node_modules\n.env\n");
|
|
193
|
+
writeClaudeMd({ workdir: "/workspace", onboard: baseOnboard });
|
|
194
|
+
expect(mockFs.appendFileSync).toHaveBeenCalledWith(path.join("/workspace", ".gitignore"), "CLAUDE.md\n");
|
|
195
|
+
});
|
|
196
|
+
it("does not duplicate CLAUDE.md in .gitignore", () => {
|
|
197
|
+
mockFs.existsSync.mockImplementation((p) => {
|
|
198
|
+
if (String(p) === "/workspace")
|
|
199
|
+
return true;
|
|
200
|
+
if (String(p).endsWith(".gitignore"))
|
|
201
|
+
return true;
|
|
202
|
+
return false;
|
|
203
|
+
});
|
|
204
|
+
mockFs.readFileSync.mockReturnValue("node_modules\nCLAUDE.md\n");
|
|
205
|
+
writeClaudeMd({ workdir: "/workspace", onboard: baseOnboard });
|
|
206
|
+
expect(mockFs.appendFileSync).not.toHaveBeenCalled();
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
// ============================================================================
|
|
210
|
+
// removeClaudeMd
|
|
211
|
+
// ============================================================================
|
|
212
|
+
describe("removeClaudeMd", () => {
|
|
213
|
+
beforeEach(() => {
|
|
214
|
+
vi.clearAllMocks();
|
|
215
|
+
});
|
|
216
|
+
it("removes existing CLAUDE.md", () => {
|
|
217
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
218
|
+
mockFs.unlinkSync.mockReturnValue(undefined);
|
|
219
|
+
removeClaudeMd("/workspace");
|
|
220
|
+
expect(mockFs.unlinkSync).toHaveBeenCalledWith(path.join("/workspace", "CLAUDE.md"));
|
|
221
|
+
});
|
|
222
|
+
it("handles missing file gracefully", () => {
|
|
223
|
+
mockFs.existsSync.mockReturnValue(false);
|
|
224
|
+
expect(() => removeClaudeMd("/workspace")).not.toThrow();
|
|
225
|
+
expect(mockFs.unlinkSync).not.toHaveBeenCalled();
|
|
226
|
+
});
|
|
227
|
+
it("handles unlink errors gracefully", () => {
|
|
228
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
229
|
+
mockFs.unlinkSync.mockImplementation(() => {
|
|
230
|
+
throw new Error("permission denied");
|
|
231
|
+
});
|
|
232
|
+
expect(() => removeClaudeMd("/workspace")).not.toThrow();
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
//# sourceMappingURL=context-template.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-template.test.js","sourceRoot":"","sources":["../../src/__tests__/context-template.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for project default_branch fallback logic.
|
|
3
|
+
*
|
|
4
|
+
* Resolution order (highest priority first):
|
|
5
|
+
* 1. Assignment repo.default_branch (agent assigned to specific repo)
|
|
6
|
+
* 2. project.default_branch (project-level override)
|
|
7
|
+
* 3. onboardData.repos[0].default_branch (first onboard repo)
|
|
8
|
+
* 4. "main" (hardcoded fallback)
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for project default_branch fallback logic.
|
|
3
|
+
*
|
|
4
|
+
* Resolution order (highest priority first):
|
|
5
|
+
* 1. Assignment repo.default_branch (agent assigned to specific repo)
|
|
6
|
+
* 2. project.default_branch (project-level override)
|
|
7
|
+
* 3. onboardData.repos[0].default_branch (first onboard repo)
|
|
8
|
+
* 4. "main" (hardcoded fallback)
|
|
9
|
+
*/
|
|
10
|
+
import { describe, expect, it } from "vitest";
|
|
11
|
+
/**
|
|
12
|
+
* Extracts the branch resolution logic from daemon.ts checkAssignments()
|
|
13
|
+
* for isolated unit testing. This mirrors the actual code paths.
|
|
14
|
+
*/
|
|
15
|
+
function resolveBranch(assignments, onboardRepos) {
|
|
16
|
+
const repoAssignment = assignments.find((a) => a.repo !== null);
|
|
17
|
+
// If agent has a specific repo assignment, use that repo's branch
|
|
18
|
+
if (repoAssignment?.repo) {
|
|
19
|
+
return repoAssignment.repo.default_branch;
|
|
20
|
+
}
|
|
21
|
+
// Fallback: project default_branch > onboard repo branch > "main"
|
|
22
|
+
const projectDefaultBranch = assignments[0]?.project.default_branch ?? null;
|
|
23
|
+
return projectDefaultBranch ?? onboardRepos[0]?.default_branch ?? "main";
|
|
24
|
+
}
|
|
25
|
+
function makeAssignment(overrides) {
|
|
26
|
+
return {
|
|
27
|
+
assignment_id: "asn-1",
|
|
28
|
+
role: "dev",
|
|
29
|
+
status: "active",
|
|
30
|
+
notes: null,
|
|
31
|
+
priority: 5,
|
|
32
|
+
created_at: new Date().toISOString(),
|
|
33
|
+
project: {
|
|
34
|
+
project_id: "prj-1",
|
|
35
|
+
name: "Test",
|
|
36
|
+
code: "TEST",
|
|
37
|
+
description: null,
|
|
38
|
+
workdir: "/workspace",
|
|
39
|
+
default_branch: overrides.project_default_branch ?? null,
|
|
40
|
+
default_repo_id: null,
|
|
41
|
+
},
|
|
42
|
+
repo: overrides.repo
|
|
43
|
+
? {
|
|
44
|
+
repo_id: "rep-1",
|
|
45
|
+
provider: "github",
|
|
46
|
+
full_name: "org/repo",
|
|
47
|
+
url: "https://github.com/org/repo.git",
|
|
48
|
+
default_branch: overrides.repo.default_branch,
|
|
49
|
+
}
|
|
50
|
+
: null,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
describe("default_branch fallback resolution", () => {
|
|
54
|
+
it("uses repo assignment branch when agent has a specific repo", () => {
|
|
55
|
+
const assignments = [
|
|
56
|
+
makeAssignment({
|
|
57
|
+
project_default_branch: "dev",
|
|
58
|
+
repo: { default_branch: "feature/special" },
|
|
59
|
+
}),
|
|
60
|
+
];
|
|
61
|
+
const branch = resolveBranch(assignments, [{ default_branch: "staging" }]);
|
|
62
|
+
expect(branch).toBe("feature/special");
|
|
63
|
+
});
|
|
64
|
+
it("uses project default_branch when no repo assignment", () => {
|
|
65
|
+
const assignments = [
|
|
66
|
+
makeAssignment({
|
|
67
|
+
project_default_branch: "dev",
|
|
68
|
+
repo: null,
|
|
69
|
+
}),
|
|
70
|
+
];
|
|
71
|
+
const branch = resolveBranch(assignments, [{ default_branch: "main" }]);
|
|
72
|
+
expect(branch).toBe("dev");
|
|
73
|
+
});
|
|
74
|
+
it("uses onboard repo branch when project default_branch is null", () => {
|
|
75
|
+
const assignments = [
|
|
76
|
+
makeAssignment({
|
|
77
|
+
project_default_branch: null,
|
|
78
|
+
repo: null,
|
|
79
|
+
}),
|
|
80
|
+
];
|
|
81
|
+
const branch = resolveBranch(assignments, [{ default_branch: "staging" }]);
|
|
82
|
+
expect(branch).toBe("staging");
|
|
83
|
+
});
|
|
84
|
+
it("falls back to 'main' when everything is null/empty", () => {
|
|
85
|
+
const assignments = [
|
|
86
|
+
makeAssignment({
|
|
87
|
+
project_default_branch: null,
|
|
88
|
+
repo: null,
|
|
89
|
+
}),
|
|
90
|
+
];
|
|
91
|
+
const branch = resolveBranch(assignments, []);
|
|
92
|
+
expect(branch).toBe("main");
|
|
93
|
+
});
|
|
94
|
+
it("falls back to 'main' when onboard repo branch is null and no project default", () => {
|
|
95
|
+
const assignments = [
|
|
96
|
+
makeAssignment({
|
|
97
|
+
project_default_branch: null,
|
|
98
|
+
repo: null,
|
|
99
|
+
}),
|
|
100
|
+
];
|
|
101
|
+
const branch = resolveBranch(assignments, [{ default_branch: null }]);
|
|
102
|
+
expect(branch).toBe("main");
|
|
103
|
+
});
|
|
104
|
+
it("prefers project default_branch over onboard repo branch", () => {
|
|
105
|
+
const assignments = [
|
|
106
|
+
makeAssignment({
|
|
107
|
+
project_default_branch: "dev",
|
|
108
|
+
repo: null,
|
|
109
|
+
}),
|
|
110
|
+
];
|
|
111
|
+
const branch = resolveBranch(assignments, [{ default_branch: "main" }]);
|
|
112
|
+
expect(branch).toBe("dev");
|
|
113
|
+
});
|
|
114
|
+
it("handles empty assignments array", () => {
|
|
115
|
+
const branch = resolveBranch([], [{ default_branch: "staging" }]);
|
|
116
|
+
expect(branch).toBe("staging");
|
|
117
|
+
});
|
|
118
|
+
it("handles empty assignments and empty repos", () => {
|
|
119
|
+
const branch = resolveBranch([], []);
|
|
120
|
+
expect(branch).toBe("main");
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
//# sourceMappingURL=default-branch-fallback.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default-branch-fallback.test.js","sourceRoot":"","sources":["../../src/__tests__/default-branch-fallback.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for project default_repo_id fallback logic.
|
|
3
|
+
*
|
|
4
|
+
* Resolution order (highest priority first):
|
|
5
|
+
* 1. Assignment repo (agent assigned to a specific repo)
|
|
6
|
+
* 2. project.default_repo_id (project-level default repo)
|
|
7
|
+
* 3. onboardData.repos[0] (first onboard repo — no ordering guarantee)
|
|
8
|
+
*
|
|
9
|
+
* The default_repo_id allows a project with multiple repos to specify
|
|
10
|
+
* which repo agents should use when they don't have a specific repo assignment.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for project default_repo_id fallback logic.
|
|
3
|
+
*
|
|
4
|
+
* Resolution order (highest priority first):
|
|
5
|
+
* 1. Assignment repo (agent assigned to a specific repo)
|
|
6
|
+
* 2. project.default_repo_id (project-level default repo)
|
|
7
|
+
* 3. onboardData.repos[0] (first onboard repo — no ordering guarantee)
|
|
8
|
+
*
|
|
9
|
+
* The default_repo_id allows a project with multiple repos to specify
|
|
10
|
+
* which repo agents should use when they don't have a specific repo assignment.
|
|
11
|
+
*/
|
|
12
|
+
import { describe, expect, it } from "vitest";
|
|
13
|
+
/**
|
|
14
|
+
* Mirrors the fallback logic from daemon.ts checkAssignments()
|
|
15
|
+
* for isolated unit testing.
|
|
16
|
+
*/
|
|
17
|
+
function resolveRepo(assignments, onboardRepos) {
|
|
18
|
+
// If agent has a specific repo assignment, use that
|
|
19
|
+
const repoAssignment = assignments.find((a) => a.repo !== null);
|
|
20
|
+
if (repoAssignment?.repo) {
|
|
21
|
+
return {
|
|
22
|
+
repo_id: repoAssignment.repo.repo_id,
|
|
23
|
+
provider: repoAssignment.repo.provider,
|
|
24
|
+
full_name: repoAssignment.repo.full_name,
|
|
25
|
+
url: repoAssignment.repo.url,
|
|
26
|
+
default_branch: repoAssignment.repo.default_branch,
|
|
27
|
+
credential: null,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// Fallback: default_repo_id > repos[0]
|
|
31
|
+
const projectDefaultRepoId = assignments[0]?.project.default_repo_id ?? null;
|
|
32
|
+
const defaultRepo = projectDefaultRepoId
|
|
33
|
+
? onboardRepos.find((r) => r.repo_id === projectDefaultRepoId)
|
|
34
|
+
: null;
|
|
35
|
+
return defaultRepo ?? onboardRepos[0] ?? null;
|
|
36
|
+
}
|
|
37
|
+
function makeAssignment(overrides) {
|
|
38
|
+
return {
|
|
39
|
+
assignment_id: "asn-1",
|
|
40
|
+
role: "dev",
|
|
41
|
+
status: "active",
|
|
42
|
+
notes: null,
|
|
43
|
+
priority: 5,
|
|
44
|
+
created_at: new Date().toISOString(),
|
|
45
|
+
project: {
|
|
46
|
+
project_id: "prj-1",
|
|
47
|
+
name: "Test",
|
|
48
|
+
code: "TEST",
|
|
49
|
+
description: null,
|
|
50
|
+
workdir: "/workspace",
|
|
51
|
+
default_branch: null,
|
|
52
|
+
default_repo_id: overrides.project_default_repo_id ?? null,
|
|
53
|
+
},
|
|
54
|
+
repo: overrides.repo
|
|
55
|
+
? {
|
|
56
|
+
repo_id: overrides.repo.repo_id,
|
|
57
|
+
provider: "github",
|
|
58
|
+
full_name: "org/repo",
|
|
59
|
+
url: "https://github.com/org/repo.git",
|
|
60
|
+
default_branch: overrides.repo.default_branch,
|
|
61
|
+
}
|
|
62
|
+
: null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const REPOS = [
|
|
66
|
+
{
|
|
67
|
+
repo_id: "rep-alpha",
|
|
68
|
+
provider: "github",
|
|
69
|
+
full_name: "org/alpha",
|
|
70
|
+
url: "https://github.com/org/alpha.git",
|
|
71
|
+
default_branch: "main",
|
|
72
|
+
credential: null,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
repo_id: "rep-beta",
|
|
76
|
+
provider: "github",
|
|
77
|
+
full_name: "org/beta",
|
|
78
|
+
url: "https://github.com/org/beta.git",
|
|
79
|
+
default_branch: "develop",
|
|
80
|
+
credential: null,
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
describe("default_repo_id fallback resolution", () => {
|
|
84
|
+
it("uses repo assignment when agent has a specific repo", () => {
|
|
85
|
+
const assignments = [
|
|
86
|
+
makeAssignment({
|
|
87
|
+
project_default_repo_id: "rep-beta",
|
|
88
|
+
repo: { repo_id: "rep-gamma", default_branch: "feature/x" },
|
|
89
|
+
}),
|
|
90
|
+
];
|
|
91
|
+
const repo = resolveRepo(assignments, REPOS);
|
|
92
|
+
expect(repo?.repo_id).toBe("rep-gamma");
|
|
93
|
+
});
|
|
94
|
+
it("uses default_repo_id when no repo assignment", () => {
|
|
95
|
+
const assignments = [
|
|
96
|
+
makeAssignment({
|
|
97
|
+
project_default_repo_id: "rep-beta",
|
|
98
|
+
repo: null,
|
|
99
|
+
}),
|
|
100
|
+
];
|
|
101
|
+
const repo = resolveRepo(assignments, REPOS);
|
|
102
|
+
expect(repo?.repo_id).toBe("rep-beta");
|
|
103
|
+
expect(repo?.full_name).toBe("org/beta");
|
|
104
|
+
});
|
|
105
|
+
it("falls back to repos[0] when default_repo_id is null", () => {
|
|
106
|
+
const assignments = [
|
|
107
|
+
makeAssignment({
|
|
108
|
+
project_default_repo_id: null,
|
|
109
|
+
repo: null,
|
|
110
|
+
}),
|
|
111
|
+
];
|
|
112
|
+
const repo = resolveRepo(assignments, REPOS);
|
|
113
|
+
expect(repo?.repo_id).toBe("rep-alpha");
|
|
114
|
+
});
|
|
115
|
+
it("falls back to repos[0] when default_repo_id doesn't match any repo", () => {
|
|
116
|
+
const assignments = [
|
|
117
|
+
makeAssignment({
|
|
118
|
+
project_default_repo_id: "rep-nonexistent",
|
|
119
|
+
repo: null,
|
|
120
|
+
}),
|
|
121
|
+
];
|
|
122
|
+
const repo = resolveRepo(assignments, REPOS);
|
|
123
|
+
expect(repo?.repo_id).toBe("rep-alpha");
|
|
124
|
+
});
|
|
125
|
+
it("returns null when no repos and no assignment", () => {
|
|
126
|
+
const assignments = [
|
|
127
|
+
makeAssignment({
|
|
128
|
+
project_default_repo_id: null,
|
|
129
|
+
repo: null,
|
|
130
|
+
}),
|
|
131
|
+
];
|
|
132
|
+
const repo = resolveRepo(assignments, []);
|
|
133
|
+
expect(repo).toBeNull();
|
|
134
|
+
});
|
|
135
|
+
it("handles empty assignments array", () => {
|
|
136
|
+
const repo = resolveRepo([], REPOS);
|
|
137
|
+
expect(repo?.repo_id).toBe("rep-alpha");
|
|
138
|
+
});
|
|
139
|
+
it("handles empty assignments and empty repos", () => {
|
|
140
|
+
const repo = resolveRepo([], []);
|
|
141
|
+
expect(repo).toBeNull();
|
|
142
|
+
});
|
|
143
|
+
it("prefers default_repo_id over repos[0]", () => {
|
|
144
|
+
const assignments = [
|
|
145
|
+
makeAssignment({
|
|
146
|
+
project_default_repo_id: "rep-beta",
|
|
147
|
+
repo: null,
|
|
148
|
+
}),
|
|
149
|
+
];
|
|
150
|
+
const repo = resolveRepo(assignments, REPOS);
|
|
151
|
+
// Should pick beta (default_repo_id), not alpha (repos[0])
|
|
152
|
+
expect(repo?.repo_id).toBe("rep-beta");
|
|
153
|
+
expect(repo?.default_branch).toBe("develop");
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
//# sourceMappingURL=default-repo-fallback.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default-repo-fallback.test.js","sourceRoot":"","sources":["../../src/__tests__/default-repo-fallback.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAG9C;;;GAGG;AACH,SAAS,WAAW,CAClB,WAAgC,EAChC,YAA2B;IAE3B,oDAAoD;IACpD,MAAM,cAAc,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAChE,IAAI,cAAc,EAAE,IAAI,EAAE,CAAC;QACzB,OAAO;YACL,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,OAAO;YACpC,QAAQ,EAAE,cAAc,CAAC,IAAI,CAAC,QAAQ;YACtC,SAAS,EAAE,cAAc,CAAC,IAAI,CAAC,SAAS;YACxC,GAAG,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG;YAC5B,cAAc,EAAE,cAAc,CAAC,IAAI,CAAC,cAAc;YAClD,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;IAED,uCAAuC;IACvC,MAAM,oBAAoB,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,eAAe,IAAI,IAAI,CAAC;IAC7E,MAAM,WAAW,GAAG,oBAAoB;QACtC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,oBAAoB,CAAC;QAC9D,CAAC,CAAC,IAAI,CAAC;IACT,OAAO,WAAW,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAChD,CAAC;AAED,SAAS,cAAc,CAAC,SAGvB;IACC,OAAO;QACL,aAAa,EAAE,OAAO;QACtB,IAAI,EAAE,KAAK;QACX,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,IAAI;QACX,QAAQ,EAAE,CAAC;QACX,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,OAAO,EAAE;YACP,UAAU,EAAE,OAAO;YACnB,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,IAAI;YACjB,OAAO,EAAE,YAAY;YACrB,cAAc,EAAE,IAAI;YACpB,eAAe,EAAE,SAAS,CAAC,uBAAuB,IAAI,IAAI;SAC3D;QACD,IAAI,EAAE,SAAS,CAAC,IAAI;YAClB,CAAC,CAAC;gBACE,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO;gBAC/B,QAAQ,EAAE,QAAQ;gBAClB,SAAS,EAAE,UAAU;gBACrB,GAAG,EAAE,iCAAiC;gBACtC,cAAc,EAAE,SAAS,CAAC,IAAI,CAAC,cAAc;aAC9C;YACH,CAAC,CAAC,IAAI;KACT,CAAC;AACJ,CAAC;AAED,MAAM,KAAK,GAAkB;IAC3B;QACE,OAAO,EAAE,WAAW;QACpB,QAAQ,EAAE,QAAQ;QAClB,SAAS,EAAE,WAAW;QACtB,GAAG,EAAE,kCAAkC;QACvC,cAAc,EAAE,MAAM;QACtB,UAAU,EAAE,IAAI;KACjB;IACD;QACE,OAAO,EAAE,UAAU;QACnB,QAAQ,EAAE,QAAQ;QAClB,SAAS,EAAE,UAAU;QACrB,GAAG,EAAE,iCAAiC;QACtC,cAAc,EAAE,SAAS;QACzB,UAAU,EAAE,IAAI;KACjB;CACF,CAAC;AAEF,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;IACnD,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,WAAW,GAAG;YAClB,cAAc,CAAC;gBACb,uBAAuB,EAAE,UAAU;gBACnC,IAAI,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE;aAC5D,CAAC;SACH,CAAC;QAEF,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,WAAW,GAAG;YAClB,cAAc,CAAC;gBACb,uBAAuB,EAAE,UAAU;gBACnC,IAAI,EAAE,IAAI;aACX,CAAC;SACH,CAAC;QAEF,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,WAAW,GAAG;YAClB,cAAc,CAAC;gBACb,uBAAuB,EAAE,IAAI;gBAC7B,IAAI,EAAE,IAAI;aACX,CAAC;SACH,CAAC;QAEF,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,WAAW,GAAG;YAClB,cAAc,CAAC;gBACb,uBAAuB,EAAE,iBAAiB;gBAC1C,IAAI,EAAE,IAAI;aACX,CAAC;SACH,CAAC;QAEF,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,WAAW,GAAG;YAClB,cAAc,CAAC;gBACb,uBAAuB,EAAE,IAAI;gBAC7B,IAAI,EAAE,IAAI;aACX,CAAC;SACH,CAAC;QAEF,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,WAAW,GAAG;YAClB,cAAc,CAAC;gBACb,uBAAuB,EAAE,UAAU;gBACnC,IAAI,EAAE,IAAI;aACX,CAAC;SACH,CAAC;QAEF,MAAM,IAAI,GAAG,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAC7C,2DAA2D;QAC3D,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|