@mclawnet/swarm 0.1.0 → 0.1.2

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 (116) hide show
  1. package/dist/__tests__/action-parser.test.d.ts +2 -0
  2. package/dist/__tests__/action-parser.test.d.ts.map +1 -0
  3. package/dist/__tests__/action-parser.test.js +91 -0
  4. package/dist/__tests__/action-parser.test.js.map +1 -0
  5. package/dist/__tests__/migration-roles.test.d.ts +2 -0
  6. package/dist/__tests__/migration-roles.test.d.ts.map +1 -0
  7. package/dist/__tests__/migration-roles.test.js +213 -0
  8. package/dist/__tests__/migration-roles.test.js.map +1 -0
  9. package/dist/__tests__/retrospective.test.d.ts +2 -0
  10. package/dist/__tests__/retrospective.test.d.ts.map +1 -0
  11. package/dist/__tests__/retrospective.test.js +467 -0
  12. package/dist/__tests__/retrospective.test.js.map +1 -0
  13. package/dist/__tests__/role-loader.test.d.ts +2 -0
  14. package/dist/__tests__/role-loader.test.d.ts.map +1 -0
  15. package/dist/__tests__/role-loader.test.js +217 -0
  16. package/dist/__tests__/role-loader.test.js.map +1 -0
  17. package/dist/__tests__/swarm-coordinator-init.test.d.ts +2 -0
  18. package/dist/__tests__/swarm-coordinator-init.test.d.ts.map +1 -0
  19. package/dist/__tests__/swarm-coordinator-init.test.js +194 -0
  20. package/dist/__tests__/swarm-coordinator-init.test.js.map +1 -0
  21. package/dist/__tests__/swarm-coordinator-roleId.test.d.ts +2 -0
  22. package/dist/__tests__/swarm-coordinator-roleId.test.d.ts.map +1 -0
  23. package/dist/__tests__/swarm-coordinator-roleId.test.js +147 -0
  24. package/dist/__tests__/swarm-coordinator-roleId.test.js.map +1 -0
  25. package/dist/__tests__/template-loader.test.d.ts +2 -0
  26. package/dist/__tests__/template-loader.test.d.ts.map +1 -0
  27. package/dist/__tests__/template-loader.test.js +103 -0
  28. package/dist/__tests__/template-loader.test.js.map +1 -0
  29. package/dist/action-parser.d.ts.map +1 -1
  30. package/dist/action-parser.js +96 -6
  31. package/dist/action-parser.js.map +1 -1
  32. package/dist/index.d.ts +7 -3
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +4 -2
  35. package/dist/index.js.map +1 -1
  36. package/dist/message-router.d.ts +6 -2
  37. package/dist/message-router.d.ts.map +1 -1
  38. package/dist/message-router.js +13 -7
  39. package/dist/message-router.js.map +1 -1
  40. package/dist/persistence.d.ts +1 -0
  41. package/dist/persistence.d.ts.map +1 -1
  42. package/dist/persistence.js +26 -3
  43. package/dist/persistence.js.map +1 -1
  44. package/dist/retrospective.d.ts +42 -0
  45. package/dist/retrospective.d.ts.map +1 -0
  46. package/dist/retrospective.js +307 -0
  47. package/dist/retrospective.js.map +1 -0
  48. package/dist/roles/role-loader.d.ts +12 -1
  49. package/dist/roles/role-loader.d.ts.map +1 -1
  50. package/dist/roles/role-loader.js +160 -7
  51. package/dist/roles/role-loader.js.map +1 -1
  52. package/dist/roles/types.d.ts +26 -2
  53. package/dist/roles/types.d.ts.map +1 -1
  54. package/dist/swarm-coordinator.d.ts +10 -2
  55. package/dist/swarm-coordinator.d.ts.map +1 -1
  56. package/dist/swarm-coordinator.js +267 -38
  57. package/dist/swarm-coordinator.js.map +1 -1
  58. package/dist/templates/template-loader.d.ts +20 -0
  59. package/dist/templates/template-loader.d.ts.map +1 -0
  60. package/dist/templates/template-loader.js +117 -0
  61. package/dist/templates/template-loader.js.map +1 -0
  62. package/dist/templates/types.d.ts +25 -0
  63. package/dist/templates/types.d.ts.map +1 -0
  64. package/dist/templates/types.js +2 -0
  65. package/dist/templates/types.js.map +1 -0
  66. package/dist/types.d.ts +13 -2
  67. package/dist/types.d.ts.map +1 -1
  68. package/package.json +17 -11
  69. package/roles/analyst-livermore.md +112 -0
  70. package/roles/designer-rams.md +266 -0
  71. package/roles/dev-torvalds.md +214 -0
  72. package/roles/developer.md +22 -1
  73. package/roles/director-jia.md +286 -0
  74. package/roles/editor-boyong.md +148 -0
  75. package/roles/macro-dalio.md +115 -0
  76. package/roles/planner-maoni.md +306 -0
  77. package/roles/pm-jobs.md +326 -0
  78. package/roles/preset-analyst-simons.md +55 -0
  79. package/roles/preset-architect-knuth.md +55 -0
  80. package/roles/preset-designer-norman.md +55 -0
  81. package/roles/preset-designer.md +55 -0
  82. package/roles/preset-dev-carmack.md +55 -0
  83. package/roles/preset-dev-gosling.md +55 -0
  84. package/roles/preset-developer.md +68 -0
  85. package/roles/preset-manager-grove.md +55 -0
  86. package/roles/preset-manager-musk.md +55 -0
  87. package/roles/preset-pm.md +105 -0
  88. package/roles/preset-researcher-feynman.md +55 -0
  89. package/roles/preset-reviewer.md +62 -0
  90. package/roles/preset-strategist-buffett.md +55 -0
  91. package/roles/preset-strategist-munger.md +55 -0
  92. package/roles/preset-strategist-sunzi.md +55 -0
  93. package/roles/preset-tester-beck.md +56 -0
  94. package/roles/preset-tester.md +63 -0
  95. package/roles/preset-writer-orwell.md +55 -0
  96. package/roles/preset-writer.md +55 -0
  97. package/roles/quant-simons.md +136 -0
  98. package/roles/queen.md +27 -1
  99. package/roles/reviewer-martin.md +200 -0
  100. package/roles/reviewer.md +18 -1
  101. package/roles/rhythm-tangsan.md +135 -0
  102. package/roles/risk-taleb.md +112 -0
  103. package/roles/script-shitiesheng.md +129 -0
  104. package/roles/storyboard-xuke.md +138 -0
  105. package/roles/strategist-soros.md +257 -0
  106. package/roles/tester-beck.md +232 -0
  107. package/roles/tester.md +19 -1
  108. package/roles/trader-jones.md +124 -0
  109. package/roles/vfx-guchangwei.md +129 -0
  110. package/roles/writer-zhouzi.md +144 -0
  111. package/templates/dev-team-pro.md +21 -0
  112. package/templates/dev-team.md +19 -0
  113. package/templates/minimal.md +14 -0
  114. package/templates/trading-team.md +22 -0
  115. package/templates/video-team.md +18 -0
  116. package/templates/writing-team.md +18 -0
@@ -0,0 +1,217 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { parseRoleFile, buildRolePrompt } from "../roles/role-loader.js";
3
+ describe("parseRoleFile", () => {
4
+ it("should parse basic flat fields (backwards compat)", () => {
5
+ const content = `---
6
+ name: developer
7
+ shortName: dev
8
+ type: worker
9
+ description: 全栈开发工程师
10
+ capabilities: [code, debug, test]
11
+ color: "#FF6B35"
12
+ ---
13
+
14
+ You are a developer. Your instanceId is {instanceId}.`;
15
+ const role = parseRoleFile(content);
16
+ expect(role.name).toBe("developer");
17
+ expect(role.shortName).toBe("dev");
18
+ expect(role.type).toBe("worker");
19
+ expect(role.description).toBe("全栈开发工程师");
20
+ expect(role.capabilities).toEqual(["code", "debug", "test"]);
21
+ expect(role.color).toBe("#FF6B35");
22
+ expect(role.promptBody).toContain("You are a developer");
23
+ expect(role.delegation).toBeUndefined();
24
+ expect(role.protocol).toBeUndefined();
25
+ });
26
+ it("should parse delegation with all field types", () => {
27
+ const content = `---
28
+ name: queen
29
+ shortName: queen
30
+ type: queen
31
+ description: Manager
32
+ color: "#FFD700"
33
+ delegation:
34
+ reportsTo: user
35
+ delegatesTo:
36
+ - role: developer
37
+ purpose: 编码任务
38
+ - role: reviewer
39
+ purpose: 代码审查
40
+ collaboratesWith:
41
+ - role: tester
42
+ purpose: 测试协调
43
+ canRequestHelp:
44
+ - role: developer
45
+ purpose: 技术咨询
46
+ escalationTarget: true
47
+ ---
48
+
49
+ Body text.`;
50
+ const role = parseRoleFile(content);
51
+ expect(role.delegation).toBeDefined();
52
+ expect(role.delegation.reportsTo).toBe("user");
53
+ expect(role.delegation.delegatesTo).toEqual([
54
+ { role: "developer", purpose: "编码任务" },
55
+ { role: "reviewer", purpose: "代码审查" },
56
+ ]);
57
+ expect(role.delegation.collaboratesWith).toEqual([
58
+ { role: "tester", purpose: "测试协调" },
59
+ ]);
60
+ expect(role.delegation.canRequestHelp).toEqual([
61
+ { role: "developer", purpose: "技术咨询" },
62
+ ]);
63
+ expect(role.delegation.escalationTarget).toBe(true);
64
+ });
65
+ it("should parse protocol list", () => {
66
+ const content = `---
67
+ name: developer
68
+ shortName: dev
69
+ type: worker
70
+ description: Dev
71
+ color: "#FF6B35"
72
+ protocol:
73
+ - 收到任务后先理解需求
74
+ - 编码完成后请求审查
75
+ - 审查通过后汇报
76
+ ---
77
+
78
+ Body.`;
79
+ const role = parseRoleFile(content);
80
+ expect(role.protocol).toEqual([
81
+ "收到任务后先理解需求",
82
+ "编码完成后请求审查",
83
+ "审查通过后汇报",
84
+ ]);
85
+ });
86
+ it("should parse delegation + protocol together", () => {
87
+ const content = `---
88
+ name: reviewer
89
+ shortName: reviewer
90
+ type: worker
91
+ description: Reviewer
92
+ color: "#8B5CF6"
93
+ delegation:
94
+ reportsTo: queen
95
+ collaboratesWith:
96
+ - role: developer
97
+ purpose: 审查代码
98
+ protocol:
99
+ - 收到审查请求后阅读代码
100
+ - 通过则通知提交者
101
+ ---
102
+
103
+ Body.`;
104
+ const role = parseRoleFile(content);
105
+ expect(role.delegation.reportsTo).toBe("queen");
106
+ expect(role.delegation.collaboratesWith).toEqual([
107
+ { role: "developer", purpose: "审查代码" },
108
+ ]);
109
+ expect(role.protocol).toEqual([
110
+ "收到审查请求后阅读代码",
111
+ "通过则通知提交者",
112
+ ]);
113
+ });
114
+ it("should handle partial delegation (only reportsTo)", () => {
115
+ const content = `---
116
+ name: worker
117
+ shortName: wrk
118
+ type: worker
119
+ description: Worker
120
+ color: "#888"
121
+ delegation:
122
+ reportsTo: queen
123
+ ---
124
+
125
+ Body.`;
126
+ const role = parseRoleFile(content);
127
+ expect(role.delegation).toBeDefined();
128
+ expect(role.delegation.reportsTo).toBe("queen");
129
+ expect(role.delegation.delegatesTo).toBeUndefined();
130
+ expect(role.delegation.collaboratesWith).toBeUndefined();
131
+ });
132
+ it("should throw on missing frontmatter", () => {
133
+ expect(() => parseRoleFile("no frontmatter")).toThrow("missing YAML frontmatter");
134
+ });
135
+ });
136
+ describe("buildRolePrompt", () => {
137
+ it("should substitute placeholders", () => {
138
+ const role = parseRoleFile(`---
139
+ name: dev
140
+ shortName: dev
141
+ type: worker
142
+ description: Dev
143
+ color: "#888"
144
+ ---
145
+
146
+ Hello {instanceId}, members: {roleList}.`);
147
+ const prompt = buildRolePrompt(role, "dev-0", "dev-0, queen-0");
148
+ expect(prompt).toContain("Hello dev-0");
149
+ expect(prompt).toContain("members: dev-0, queen-0");
150
+ });
151
+ it("should inject delegation section", () => {
152
+ const role = parseRoleFile(`---
153
+ name: queen
154
+ shortName: queen
155
+ type: queen
156
+ description: Queen
157
+ color: "#FFD700"
158
+ delegation:
159
+ reportsTo: user
160
+ delegatesTo:
161
+ - role: developer
162
+ purpose: 编码
163
+ - role: reviewer
164
+ purpose: 审查
165
+ collaboratesWith:
166
+ - role: tester
167
+ purpose: 测试
168
+ canRequestHelp:
169
+ - role: developer
170
+ purpose: 咨询
171
+ ---
172
+
173
+ Base prompt.`);
174
+ const prompt = buildRolePrompt(role, "queen-0", "");
175
+ expect(prompt).toContain("### 协作关系");
176
+ expect(prompt).toContain("汇报给: user");
177
+ expect(prompt).toContain("可委派给: developer(编码)、reviewer(审查)");
178
+ expect(prompt).toContain("协作对象: tester(测试)");
179
+ expect(prompt).toContain("可请求协助: developer(咨询)");
180
+ });
181
+ it("should inject protocol section", () => {
182
+ const role = parseRoleFile(`---
183
+ name: dev
184
+ shortName: dev
185
+ type: worker
186
+ description: Dev
187
+ color: "#888"
188
+ protocol:
189
+ - Step A
190
+ - Step B
191
+ - Step C
192
+ ---
193
+
194
+ Base prompt.`);
195
+ const prompt = buildRolePrompt(role, "dev-0", "");
196
+ expect(prompt).toContain("### 标准工作流程");
197
+ expect(prompt).toContain("1. Step A");
198
+ expect(prompt).toContain("2. Step B");
199
+ expect(prompt).toContain("3. Step C");
200
+ });
201
+ it("should not inject sections when delegation/protocol absent", () => {
202
+ const role = parseRoleFile(`---
203
+ name: dev
204
+ shortName: dev
205
+ type: worker
206
+ description: Dev
207
+ color: "#888"
208
+ ---
209
+
210
+ Base prompt only.`);
211
+ const prompt = buildRolePrompt(role, "dev-0", "");
212
+ expect(prompt).not.toContain("### 协作关系");
213
+ expect(prompt).not.toContain("### 标准工作流程");
214
+ expect(prompt).toBe("Base prompt only.");
215
+ });
216
+ });
217
+ //# sourceMappingURL=role-loader.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role-loader.test.js","sourceRoot":"","sources":["../../src/__tests__/role-loader.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=swarm-coordinator-init.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swarm-coordinator-init.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/swarm-coordinator-init.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,194 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ // Mock logger
3
+ vi.mock("@mclawnet/logger", () => ({
4
+ createLogger: () => ({
5
+ info: vi.fn(),
6
+ warn: vi.fn(),
7
+ error: vi.fn(),
8
+ debug: vi.fn(),
9
+ }),
10
+ }));
11
+ // Mock persistence
12
+ vi.mock("../persistence.js", () => ({
13
+ saveSwarmSnapshot: vi.fn(),
14
+ deleteSwarmSnapshot: vi.fn(),
15
+ appendMessageLog: vi.fn(),
16
+ loadSwarmSnapshot: vi.fn(),
17
+ readMessageLog: vi.fn(() => []),
18
+ }));
19
+ // Mock retrospective
20
+ vi.mock("../retrospective.js", () => ({
21
+ runRetrospective: vi.fn(async () => ({})),
22
+ }));
23
+ // Mock template-loader for template-based tests
24
+ vi.mock("../templates/template-loader.js", () => ({
25
+ loadTemplate: vi.fn((name) => {
26
+ if (name === "dev-team") {
27
+ return {
28
+ name: "dev-team",
29
+ displayName: "全栈开发团队",
30
+ description: "Standard team",
31
+ roles: [
32
+ { roleName: "queen", count: 1, eager: true },
33
+ { roleName: "reviewer", count: 1, eager: true },
34
+ { roleName: "developer", count: 2 },
35
+ { roleName: "tester", count: 1 },
36
+ ],
37
+ body: "Description",
38
+ };
39
+ }
40
+ if (name === "minimal") {
41
+ return {
42
+ name: "minimal",
43
+ displayName: "极简团队",
44
+ description: "Minimal team",
45
+ roles: [
46
+ { roleName: "queen", count: 1, eager: true },
47
+ { roleName: "developer", count: 1 },
48
+ ],
49
+ body: "Minimal",
50
+ };
51
+ }
52
+ throw new Error(`Template not found: ${name}`);
53
+ }),
54
+ }));
55
+ import { SwarmCoordinator } from "../swarm-coordinator.js";
56
+ function createMockSessionAdapter() {
57
+ const calls = [];
58
+ const inputs = [];
59
+ return {
60
+ _calls: calls,
61
+ _inputs: inputs,
62
+ createSession: vi.fn(async (options) => {
63
+ calls.push(options);
64
+ return `proc-${options.sessionId}`;
65
+ }),
66
+ sendInput: vi.fn((sessionId, input) => {
67
+ inputs.push({ sessionId, input });
68
+ }),
69
+ closeSession: vi.fn(async () => { }),
70
+ };
71
+ }
72
+ function createMockHubAdapter() {
73
+ const msgs = [];
74
+ return {
75
+ _msgs: msgs,
76
+ send: vi.fn((msg) => msgs.push(msg)),
77
+ };
78
+ }
79
+ describe("SwarmCoordinator — two-phase initialization", () => {
80
+ let sessionAdapter;
81
+ let hubAdapter;
82
+ let coordinator;
83
+ beforeEach(() => {
84
+ sessionAdapter = createMockSessionAdapter();
85
+ hubAdapter = createMockHubAdapter();
86
+ coordinator = new SwarmCoordinator(sessionAdapter, hubAdapter);
87
+ });
88
+ it("should spawn non-queen eager roles before queen (reviewer before queen)", async () => {
89
+ await coordinator.create("swarm-phase", {
90
+ workDir: "/tmp/test",
91
+ roles: [
92
+ { roleName: "queen", count: 1, eager: true },
93
+ { roleName: "reviewer", count: 1, eager: true },
94
+ { roleName: "developer", count: 1 },
95
+ ],
96
+ task: "Build feature",
97
+ });
98
+ // Only eager roles spawned (queen + reviewer), developer is on-demand
99
+ const spawnedSessions = sessionAdapter._calls.map((c) => c.sessionId);
100
+ expect(spawnedSessions).toHaveLength(2);
101
+ // reviewer should be spawned BEFORE queen
102
+ const reviewerIdx = spawnedSessions.findIndex((s) => s.includes("reviewer-"));
103
+ const queenIdx = spawnedSessions.findIndex((s) => s.includes("queen-"));
104
+ expect(reviewerIdx).toBeLessThan(queenIdx);
105
+ });
106
+ it("should create swarm from templateName", async () => {
107
+ await coordinator.create("swarm-tpl", {
108
+ workDir: "/tmp/test",
109
+ templateName: "dev-team",
110
+ task: "Build feature",
111
+ });
112
+ // dev-team has queen(eager) + reviewer(eager) + developer(x2) + tester
113
+ // Only eager ones spawned: reviewer then queen
114
+ const spawnedSessions = sessionAdapter._calls.map((c) => c.sessionId);
115
+ expect(spawnedSessions).toHaveLength(2);
116
+ const reviewerIdx = spawnedSessions.findIndex((s) => s.includes("reviewer-"));
117
+ const queenIdx = spawnedSessions.findIndex((s) => s.includes("queen-"));
118
+ expect(reviewerIdx).toBeGreaterThanOrEqual(0);
119
+ expect(queenIdx).toBeGreaterThanOrEqual(0);
120
+ expect(reviewerIdx).toBeLessThan(queenIdx);
121
+ });
122
+ it("should send init-complete message to queen after all eager roles spawned", async () => {
123
+ await coordinator.create("swarm-init", {
124
+ workDir: "/tmp/test",
125
+ roles: [
126
+ { roleName: "queen", count: 1, eager: true },
127
+ { roleName: "reviewer", count: 1, eager: true },
128
+ ],
129
+ task: "Build feature",
130
+ });
131
+ // queen should receive init-complete system message + user task via sendInput
132
+ const queenInputs = sessionAdapter._inputs.filter((i) => i.sessionId.includes("queen-"));
133
+ expect(queenInputs.length).toBeGreaterThanOrEqual(2);
134
+ // First message should be the init-complete notification
135
+ const initMsg = queenInputs[0].input;
136
+ expect(initMsg).toContain("蜂群初始化完成");
137
+ expect(initMsg).toContain("reviewer-0");
138
+ // Second message should be the user task
139
+ const taskMsg = queenInputs[1].input;
140
+ expect(taskMsg).toContain("Build feature");
141
+ });
142
+ it("should ensure queen is always eager even if not explicitly marked", async () => {
143
+ await coordinator.create("swarm-queen-eager", {
144
+ workDir: "/tmp/test",
145
+ roles: [
146
+ { roleName: "queen", count: 1 }, // no eager flag
147
+ { roleName: "developer", count: 1 },
148
+ ],
149
+ task: "Test",
150
+ });
151
+ // Queen should still be spawned (always eager)
152
+ const queenCall = sessionAdapter._calls.find((c) => c.sessionId.includes("queen-"));
153
+ expect(queenCall).toBeDefined();
154
+ });
155
+ it("should not spawn non-eager roles during creation", async () => {
156
+ await coordinator.create("swarm-lazy", {
157
+ workDir: "/tmp/test",
158
+ roles: [
159
+ { roleName: "queen", count: 1, eager: true },
160
+ { roleName: "developer", count: 2 },
161
+ { roleName: "tester", count: 1 },
162
+ ],
163
+ task: "Test",
164
+ });
165
+ // Only queen spawned
166
+ expect(sessionAdapter._calls).toHaveLength(1);
167
+ expect(sessionAdapter._calls[0].sessionId).toContain("queen-");
168
+ });
169
+ it("should create minimal template with only queen eager", async () => {
170
+ await coordinator.create("swarm-minimal", {
171
+ workDir: "/tmp/test",
172
+ templateName: "minimal",
173
+ task: "Quick prototype",
174
+ });
175
+ // minimal: queen(eager) + developer (not eager)
176
+ expect(sessionAdapter._calls).toHaveLength(1);
177
+ expect(sessionAdapter._calls[0].sessionId).toContain("queen-");
178
+ });
179
+ it("should include queen's roleList with already-spawned reviewer", async () => {
180
+ await coordinator.create("swarm-rolelist", {
181
+ workDir: "/tmp/test",
182
+ roles: [
183
+ { roleName: "queen", count: 1, eager: true },
184
+ { roleName: "reviewer", count: 1, eager: true },
185
+ ],
186
+ task: "Test",
187
+ });
188
+ // Queen is spawned last, so her systemPrompt should include reviewer-0
189
+ const queenCall = sessionAdapter._calls.find((c) => c.sessionId.includes("queen-"));
190
+ expect(queenCall).toBeDefined();
191
+ expect(queenCall.systemPrompt).toContain("reviewer-0");
192
+ });
193
+ });
194
+ //# sourceMappingURL=swarm-coordinator-init.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swarm-coordinator-init.test.js","sourceRoot":"","sources":["../../src/__tests__/swarm-coordinator-init.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE9D,cAAc;AACd,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;QACnB,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;QACb,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;QACb,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;QACd,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;KACf,CAAC;CACH,CAAC,CAAC,CAAC;AAEJ,mBAAmB;AACnB,EAAE,CAAC,IAAI,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC;IAClC,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE;IAC1B,mBAAmB,EAAE,EAAE,CAAC,EAAE,EAAE;IAC5B,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE;IACzB,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE;IAC1B,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;CAChC,CAAC,CAAC,CAAC;AAEJ,qBAAqB;AACrB,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,CAAC;IACpC,gBAAgB,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;CAC1C,CAAC,CAAC,CAAC;AAEJ,gDAAgD;AAChD,EAAE,CAAC,IAAI,CAAC,iCAAiC,EAAE,GAAG,EAAE,CAAC,CAAC;IAChD,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAY,EAAE,EAAE;QACnC,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YACxB,OAAO;gBACL,IAAI,EAAE,UAAU;gBAChB,WAAW,EAAE,QAAQ;gBACrB,WAAW,EAAE,eAAe;gBAC5B,KAAK,EAAE;oBACL,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;oBAC5C,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;oBAC/C,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE;oBACnC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE;iBACjC;gBACD,IAAI,EAAE,aAAa;aACpB,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,MAAM;gBACnB,WAAW,EAAE,cAAc;gBAC3B,KAAK,EAAE;oBACL,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;oBAC5C,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE;iBACpC;gBACD,IAAI,EAAE,SAAS;aAChB,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC;CACH,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAG3D,SAAS,wBAAwB;IAI/B,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,OAAO;QACL,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YACrC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,OAAO,QAAQ,OAAO,CAAC,SAAS,EAAE,CAAC;QACrC,CAAC,CAAC;QACF,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;YACpC,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QACpC,CAAC,CAAC;QACF,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,GAAE,CAAC,CAAC;KACpC,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB;IAC3B,MAAM,IAAI,GAAU,EAAE,CAAC;IACvB,OAAO;QACL,KAAK,EAAE,IAAI;QACX,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KACrC,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,6CAA6C,EAAE,GAAG,EAAE;IAC3D,IAAI,cAA2D,CAAC;IAChE,IAAI,UAAmD,CAAC;IACxD,IAAI,WAA6B,CAAC;IAElC,UAAU,CAAC,GAAG,EAAE;QACd,cAAc,GAAG,wBAAwB,EAAE,CAAC;QAC5C,UAAU,GAAG,oBAAoB,EAAE,CAAC;QACpC,WAAW,GAAG,IAAI,gBAAgB,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACvF,MAAM,WAAW,CAAC,MAAM,CAAC,aAAa,EAAE;YACtC,OAAO,EAAE,WAAW;YACpB,KAAK,EAAE;gBACL,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;gBAC5C,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;gBAC/C,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE;aACpC;YACD,IAAI,EAAE,eAAe;SACtB,CAAC,CAAC;QAEH,sEAAsE;QACtE,MAAM,eAAe,GAAG,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACtE,MAAM,CAAC,eAAe,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAExC,0CAA0C;QAC1C,MAAM,WAAW,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;QAC9E,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxE,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,WAAW,CAAC,MAAM,CAAC,WAAW,EAAE;YACpC,OAAO,EAAE,WAAW;YACpB,YAAY,EAAE,UAAU;YACxB,IAAI,EAAE,eAAe;SACtB,CAAC,CAAC;QAEH,uEAAuE;QACvE,+CAA+C;QAC/C,MAAM,eAAe,GAAG,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACtE,MAAM,CAAC,eAAe,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAExC,MAAM,WAAW,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;QAC9E,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxE,MAAM,CAAC,WAAW,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,QAAQ,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,MAAM,WAAW,CAAC,MAAM,CAAC,YAAY,EAAE;YACrC,OAAO,EAAE,WAAW;YACpB,KAAK,EAAE;gBACL,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;gBAC5C,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;aAChD;YACD,IAAI,EAAE,eAAe;SACtB,CAAC,CAAC;QAEH,8EAA8E;QAC9E,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACtD,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAC/B,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QAErD,yDAAyD;QACzD,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACrC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACrC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAExC,yCAAyC;QACzC,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACrC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,WAAW,CAAC,MAAM,CAAC,mBAAmB,EAAE;YAC5C,OAAO,EAAE,WAAW;YACpB,KAAK,EAAE;gBACL,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,gBAAgB;gBACjD,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE;aACpC;YACD,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;QAEH,+CAA+C;QAC/C,MAAM,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACjD,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAC/B,CAAC;QACF,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,WAAW,CAAC,MAAM,CAAC,YAAY,EAAE;YACrC,OAAO,EAAE,WAAW;YACpB,KAAK,EAAE;gBACL,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;gBAC5C,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE;gBACnC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE;aACjC;YACD,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;QAEH,qBAAqB;QACrB,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,WAAW,CAAC,MAAM,CAAC,eAAe,EAAE;YACxC,OAAO,EAAE,WAAW;YACpB,YAAY,EAAE,SAAS;YACvB,IAAI,EAAE,iBAAiB;SACxB,CAAC,CAAC;QAEH,gDAAgD;QAChD,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,WAAW,CAAC,MAAM,CAAC,gBAAgB,EAAE;YACzC,OAAO,EAAE,WAAW;YACpB,KAAK,EAAE;gBACL,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;gBAC5C,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;aAChD;YACD,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;QAEH,uEAAuE;QACvE,MAAM,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACjD,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAC/B,CAAC;QACF,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAChC,MAAM,CAAC,SAAU,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=swarm-coordinator-roleId.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swarm-coordinator-roleId.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/swarm-coordinator-roleId.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,147 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ // Mock logger
3
+ vi.mock("@mclawnet/logger", () => ({
4
+ createLogger: () => ({
5
+ info: vi.fn(),
6
+ warn: vi.fn(),
7
+ error: vi.fn(),
8
+ debug: vi.fn(),
9
+ }),
10
+ }));
11
+ // Mock persistence — prevent file system side effects
12
+ vi.mock("../persistence.js", () => ({
13
+ saveSwarmSnapshot: vi.fn(),
14
+ deleteSwarmSnapshot: vi.fn(),
15
+ appendMessageLog: vi.fn(),
16
+ loadSwarmSnapshot: vi.fn(),
17
+ readMessageLog: vi.fn(() => []),
18
+ }));
19
+ // Mock retrospective
20
+ vi.mock("../retrospective.js", () => ({
21
+ runRetrospective: vi.fn(async () => ({})),
22
+ }));
23
+ import { SwarmCoordinator } from "../swarm-coordinator.js";
24
+ import { BUILTIN_ROLES } from "@mclawnet/memory";
25
+ // ── Mock adapters ───────────────────────────────────────────────────
26
+ function createMockSessionAdapter() {
27
+ const calls = [];
28
+ return {
29
+ _calls: calls,
30
+ createSession: vi.fn(async (options) => {
31
+ calls.push(options);
32
+ return `proc-${options.sessionId}`;
33
+ }),
34
+ sendInput: vi.fn(),
35
+ closeSession: vi.fn(async () => { }),
36
+ };
37
+ }
38
+ function createMockHubAdapter() {
39
+ return { send: vi.fn() };
40
+ }
41
+ // ── Tests ───────────────────────────────────────────────────────────
42
+ describe("SwarmCoordinator — roleId propagation", () => {
43
+ let sessionAdapter;
44
+ let hubAdapter;
45
+ let coordinator;
46
+ beforeEach(() => {
47
+ sessionAdapter = createMockSessionAdapter();
48
+ hubAdapter = createMockHubAdapter();
49
+ coordinator = new SwarmCoordinator(sessionAdapter, hubAdapter);
50
+ });
51
+ it("should pass correct roleId for builtin roles (queen eager, developer on-demand)", async () => {
52
+ await coordinator.create("swarm-1", {
53
+ workDir: "/tmp/test",
54
+ roles: [
55
+ { roleName: "queen", count: 1 },
56
+ { roleName: "developer", count: 1 },
57
+ ],
58
+ task: "Build something",
59
+ });
60
+ // Only queen is eager-spawned; developer is on-demand
61
+ expect(sessionAdapter._calls.length).toBe(1);
62
+ const queenCall = sessionAdapter._calls.find((c) => c.sessionId.includes("queen-"));
63
+ expect(queenCall).toBeDefined();
64
+ expect(queenCall.roleId).toBe(BUILTIN_ROLES["queen"]?.id ?? "role-queen");
65
+ // Manually spawn developer to verify roleId
66
+ await coordinator.spawnRole("swarm-1", "developer");
67
+ const devCall = sessionAdapter._calls.find((c) => c.sessionId.includes("dev-"));
68
+ expect(devCall).toBeDefined();
69
+ expect(devCall.roleId).toBe(BUILTIN_ROLES["developer"]?.id ?? "role-developer");
70
+ });
71
+ it("should pass systemPrompt without memory prefix (SessionManager handles it)", async () => {
72
+ await coordinator.create("swarm-2", {
73
+ workDir: "/tmp/test",
74
+ roles: [{ roleName: "queen", count: 1 }],
75
+ task: "Build feature",
76
+ });
77
+ const call = sessionAdapter._calls[0];
78
+ expect(call.systemPrompt).toBeDefined();
79
+ // systemPrompt should be the role prompt, NOT prefixed with memory section
80
+ // (that's SessionManager's job via roleId)
81
+ expect(call.systemPrompt).not.toContain("buildMemorySection");
82
+ });
83
+ it("should not pass mcpConfigPath (SessionManager generates it via roleId)", async () => {
84
+ await coordinator.create("swarm-3", {
85
+ workDir: "/tmp/test",
86
+ roles: [{ roleName: "queen", count: 1 }],
87
+ task: "Build feature",
88
+ });
89
+ const call = sessionAdapter._calls[0];
90
+ expect(call.mcpConfigPath).toBeUndefined();
91
+ });
92
+ it("should use fallback roleId for custom/unknown role names", async () => {
93
+ await coordinator.create("swarm-4", {
94
+ workDir: "/tmp/test",
95
+ roles: [
96
+ { roleName: "queen", count: 1 },
97
+ {
98
+ roleName: "data-engineer",
99
+ count: 1,
100
+ customDefinition: {
101
+ name: "data-engineer",
102
+ shortName: "de",
103
+ description: "Data pipeline engineer",
104
+ capabilities: ["etl", "sql"],
105
+ color: "#00FF00",
106
+ promptBody: "You build data pipelines.",
107
+ },
108
+ },
109
+ ],
110
+ task: "Build ETL",
111
+ });
112
+ // Manually spawn custom role (on-demand)
113
+ await coordinator.spawnRole("swarm-4", "data-engineer", undefined, undefined, undefined, {
114
+ name: "data-engineer",
115
+ shortName: "de",
116
+ description: "Data pipeline engineer",
117
+ capabilities: ["etl", "sql"],
118
+ color: "#00FF00",
119
+ promptBody: "You build data pipelines.",
120
+ });
121
+ const call = sessionAdapter._calls.find((c) => c.sessionId.includes("de-"));
122
+ expect(call).toBeDefined();
123
+ expect(call.roleId).toBe("role-data-engineer");
124
+ });
125
+ it("should pass workDir to each role session", async () => {
126
+ await coordinator.create("swarm-5", {
127
+ workDir: "/projects/myapp",
128
+ roles: [{ roleName: "queen", count: 1 }],
129
+ task: "Fix bug",
130
+ });
131
+ const call = sessionAdapter._calls[0];
132
+ expect(call.workDir).toBe("/projects/myapp");
133
+ });
134
+ it("should pass additionalDirs to createSession when provided via spawnRole", async () => {
135
+ await coordinator.create("swarm-dirs", {
136
+ workDir: "/tmp/test",
137
+ roles: [{ roleName: "queen", count: 1 }],
138
+ task: "Build feature",
139
+ });
140
+ // Manually spawn a role with additionalDirs
141
+ await coordinator.spawnRole("swarm-dirs", "developer", undefined, "Extra task", undefined, undefined, ["/extra/dir1", "/extra/dir2"]);
142
+ // Last call should have additionalDirs
143
+ const lastCall = sessionAdapter._calls[sessionAdapter._calls.length - 1];
144
+ expect(lastCall.additionalDirs).toEqual(["/extra/dir1", "/extra/dir2"]);
145
+ });
146
+ });
147
+ //# sourceMappingURL=swarm-coordinator-roleId.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swarm-coordinator-roleId.test.js","sourceRoot":"","sources":["../../src/__tests__/swarm-coordinator-roleId.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=template-loader.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-loader.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/template-loader.test.ts"],"names":[],"mappings":""}