maskweaver 0.9.3 → 0.9.5
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.ko.md +279 -325
- package/README.md +109 -113
- package/assets/commands/meta/commands.json +34 -34
- package/assets/commands/weave-agents.md +12 -52
- package/assets/commands/weave-approve.md +12 -51
- package/assets/commands/weave-archive.md +21 -0
- package/assets/commands/weave-build.md +20 -89
- package/assets/commands/weave-craft.md +22 -43
- package/assets/commands/weave-help.md +37 -106
- package/assets/commands/weave-init.md +26 -108
- package/assets/commands/weave-interview.md +13 -111
- package/assets/commands/weave-map.md +13 -99
- package/assets/commands/weave-prepare.md +23 -69
- package/assets/commands/weave-refine-plan.md +26 -59
- package/assets/commands/weave-repair.md +22 -70
- package/assets/commands/weave-status.md +22 -155
- package/assets/commands/weave-troubleshoot.md +11 -47
- package/assets/commands/weave-verify.md +23 -44
- package/assets/commands/weave-worktree.md +27 -69
- package/dist/cli/doctor.js +5 -21
- package/dist/cli/install.d.ts +0 -8
- package/dist/cli/install.js +0 -39
- package/dist/context/config.d.ts +0 -22
- package/dist/context/config.js +0 -28
- package/dist/context/feature.d.ts +0 -39
- package/dist/context/feature.js +0 -77
- package/dist/context/files.d.ts +0 -13
- package/dist/context/files.js +1 -24
- package/dist/context/index.d.ts +0 -7
- package/dist/context/index.js +0 -12
- package/dist/context/project.d.ts +0 -21
- package/dist/context/project.js +0 -30
- package/dist/context/types.d.ts +0 -48
- package/dist/context/types.js +0 -12
- package/dist/context/utils.d.ts +0 -18
- package/dist/context/utils.js +0 -27
- package/dist/core/engine/promptBuilder.d.ts +0 -17
- package/dist/core/engine/promptBuilder.js +0 -28
- package/dist/core/index.d.ts +0 -6
- package/dist/core/index.js +0 -9
- package/dist/core/loader/MaskLoader.d.ts +0 -23
- package/dist/core/loader/MaskLoader.js +0 -29
- package/dist/core/schema/types.d.ts +0 -47
- package/dist/core/schema/types.js +0 -6
- package/dist/core/schema/validator.d.ts +0 -14
- package/dist/core/schema/validator.js +0 -18
- package/dist/i18n/index.d.ts +0 -18
- package/dist/i18n/index.js +4 -23
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -8
- package/dist/lib.d.ts +0 -5
- package/dist/lib.js +0 -12
- package/dist/memory/chunking.d.ts +0 -22
- package/dist/memory/chunking.js +2 -37
- package/dist/memory/core.d.ts +0 -29
- package/dist/memory/core.js +1 -52
- package/dist/memory/index.d.ts +0 -5
- package/dist/memory/index.js +0 -10
- package/dist/memory/indexer.d.ts +0 -21
- package/dist/memory/indexer.js +0 -44
- package/dist/memory/providers/examples.d.ts +0 -5
- package/dist/memory/providers/examples.js +4 -64
- package/dist/memory/providers/factory.d.ts +0 -44
- package/dist/memory/providers/factory.js +0 -46
- package/dist/memory/providers/index.d.ts +0 -26
- package/dist/memory/providers/index.js +0 -28
- package/dist/memory/providers/ollama.d.ts +0 -6
- package/dist/memory/providers/ollama.js +1 -8
- package/dist/memory/providers/openai.d.ts +0 -6
- package/dist/memory/providers/openai.js +1 -8
- package/dist/memory/providers/openrouter.d.ts +0 -6
- package/dist/memory/providers/openrouter.js +0 -8
- package/dist/memory/providers/text-only.d.ts +0 -13
- package/dist/memory/providers/text-only.js +0 -17
- package/dist/memory/providers/types.d.ts +0 -39
- package/dist/memory/providers/types.js +0 -7
- package/dist/memory/providers/voyage.d.ts +0 -22
- package/dist/memory/providers/voyage.js +1 -24
- package/dist/memory/search/hybrid.d.ts +0 -12
- package/dist/memory/search/hybrid.js +1 -22
- package/dist/memory/store/sqlite.d.ts +0 -72
- package/dist/memory/store/sqlite.js +4 -127
- package/dist/plugin/config/index.d.ts +0 -112
- package/dist/plugin/config/index.js +0 -115
- package/dist/plugin/index.d.ts +0 -13
- package/dist/plugin/index.js +1 -124
- package/dist/plugin/tools/command-registry.d.ts +0 -6
- package/dist/plugin/tools/command-registry.js +0 -14
- package/dist/plugin/tools/context.d.ts +0 -12
- package/dist/plugin/tools/context.js +0 -58
- package/dist/plugin/tools/maskSave.d.ts +0 -3
- package/dist/plugin/tools/maskSave.js +0 -3
- package/dist/plugin/tools/memoryGet.d.ts +0 -3
- package/dist/plugin/tools/memoryGet.js +0 -3
- package/dist/plugin/tools/memoryIndexer.d.ts +0 -3
- package/dist/plugin/tools/memoryIndexer.js +0 -10
- package/dist/plugin/tools/memorySearch.d.ts +0 -31
- package/dist/plugin/tools/memorySearch.js +0 -79
- package/dist/plugin/tools/memoryWrite.d.ts +0 -8
- package/dist/plugin/tools/memoryWrite.js +0 -32
- package/dist/plugin/tools/retrospect.d.ts +0 -3
- package/dist/plugin/tools/retrospect.js +0 -3
- package/dist/plugin/tools/slashcommand.d.ts +0 -11
- package/dist/plugin/tools/slashcommand.js +0 -38
- package/dist/plugin/tools/squad.d.ts +0 -12
- package/dist/plugin/tools/squad.js +11 -83
- package/dist/plugin/tools/weave.d.ts +0 -6
- package/dist/plugin/tools/weave.js +0 -78
- package/dist/plugin/types.d.ts +0 -20
- package/dist/plugin/types.js +0 -7
- package/dist/retrospect/index.d.ts +0 -7
- package/dist/retrospect/index.js +0 -9
- package/dist/retrospect/mask-save.d.ts +0 -12
- package/dist/retrospect/mask-save.js +1 -80
- package/dist/retrospect/retrospect.d.ts +0 -18
- package/dist/retrospect/retrospect.js +0 -63
- package/dist/retrospect/strategies/base.d.ts +0 -15
- package/dist/retrospect/strategies/base.js +0 -7
- package/dist/retrospect/strategies/deep.d.ts +0 -12
- package/dist/retrospect/strategies/deep.js +0 -24
- package/dist/retrospect/strategies/index.d.ts +0 -12
- package/dist/retrospect/strategies/index.js +0 -12
- package/dist/retrospect/strategies/quick.d.ts +0 -12
- package/dist/retrospect/strategies/quick.js +0 -19
- package/dist/retrospect/strategies/standard.d.ts +0 -12
- package/dist/retrospect/strategies/standard.js +0 -15
- package/dist/retrospect/types.d.ts +0 -7
- package/dist/retrospect/types.js +0 -7
- package/dist/shared/config.d.ts +0 -105
- package/dist/shared/config.js +0 -33
- package/dist/shared/errors.d.ts +0 -18
- package/dist/shared/errors.js +0 -19
- package/dist/shared/generate-agents.d.ts +0 -69
- package/dist/shared/generate-agents.js +2 -86
- package/dist/shared/image.d.ts +0 -67
- package/dist/shared/image.js +6 -104
- package/dist/shared/index.d.ts +0 -5
- package/dist/shared/index.js +0 -7
- package/dist/shared/model-registry.d.ts +0 -72
- package/dist/shared/model-registry.js +5 -95
- package/dist/shared/types.d.ts +0 -15
- package/dist/shared/types.js +0 -3
- package/dist/shared-context/dag.d.ts +0 -105
- package/dist/shared-context/dag.js +3 -114
- package/dist/shared-context/index.d.ts +0 -5
- package/dist/shared-context/index.js +0 -15
- package/dist/shared-context/logger.d.ts +0 -37
- package/dist/shared-context/logger.js +0 -41
- package/dist/shared-context/parallel-executor.d.ts +0 -54
- package/dist/shared-context/parallel-executor.js +4 -56
- package/dist/shared-context/session.d.ts +0 -56
- package/dist/shared-context/session.js +0 -47
- package/dist/shared-context/squad.d.ts +0 -68
- package/dist/shared-context/squad.js +0 -63
- package/dist/shared-context/storage.d.ts +0 -132
- package/dist/shared-context/storage.js +0 -116
- package/dist/shared-context/task.d.ts +0 -120
- package/dist/shared-context/task.js +0 -152
- package/dist/shared-context/test/dag.test.js +9 -14
- package/dist/shared-context/test/logger.test.d.ts +0 -8
- package/dist/shared-context/test/logger.test.js +0 -52
- package/dist/shared-context/test/session.test.d.ts +0 -7
- package/dist/shared-context/test/session.test.js +0 -63
- package/dist/shared-context/test/squad.test.d.ts +0 -10
- package/dist/shared-context/test/squad.test.js +2 -68
- package/dist/shared-context/test/storage.test.d.ts +0 -8
- package/dist/shared-context/test/storage.test.js +0 -68
- package/dist/shared-context/test/task.test.d.ts +0 -7
- package/dist/shared-context/test/task.test.js +0 -54
- package/dist/shared-context/test/watchdog.test.d.ts +0 -7
- package/dist/shared-context/test/watchdog.test.js +3 -58
- package/dist/shared-context/types.d.ts +0 -215
- package/dist/shared-context/types.js +0 -125
- package/dist/shared-context/watchdog.d.ts +0 -127
- package/dist/shared-context/watchdog.js +0 -148
- package/dist/shared-context/worktree.d.ts +0 -68
- package/dist/shared-context/worktree.js +2 -34
- package/dist/verify/budget.d.ts +0 -29
- package/dist/verify/budget.js +0 -34
- package/dist/verify/critical-files.d.ts +0 -17
- package/dist/verify/critical-files.js +0 -37
- package/dist/verify/escalation.d.ts +0 -20
- package/dist/verify/escalation.js +0 -22
- package/dist/verify/index.d.ts +0 -5
- package/dist/verify/index.js +0 -11
- package/dist/verify/prompts.d.ts +0 -20
- package/dist/verify/prompts.js +0 -20
- package/dist/verify/types.d.ts +0 -26
- package/dist/verify/types.js +1 -12
- package/dist/verify/verifier.d.ts +0 -29
- package/dist/verify/verifier.js +0 -54
- package/dist/version.d.ts +1 -16
- package/dist/version.js +1 -16
- package/dist/weave/bridge.d.ts +0 -35
- package/dist/weave/bridge.js +0 -51
- package/dist/weave/environment/detector.d.ts +0 -6
- package/dist/weave/environment/detector.js +4 -45
- package/dist/weave/environment/index.d.ts +0 -19
- package/dist/weave/environment/index.js +1 -39
- package/dist/weave/environment/issues.d.ts +0 -35
- package/dist/weave/environment/issues.js +0 -59
- package/dist/weave/git.d.ts +0 -8
- package/dist/weave/git.js +0 -8
- package/dist/weave/index.d.ts +0 -13
- package/dist/weave/index.js +2 -28
- package/dist/weave/knowledge/global.d.ts +0 -39
- package/dist/weave/knowledge/global.js +2 -78
- package/dist/weave/loop.js +0 -3
- package/dist/weave/orchestrator.d.ts +0 -69
- package/dist/weave/orchestrator.js +1 -101
- package/dist/weave/phase-manager.d.ts +0 -64
- package/dist/weave/phase-manager.js +0 -89
- package/dist/weave/security/secret-scan.d.ts +0 -14
- package/dist/weave/security/secret-scan.js +0 -19
- package/dist/weave/stages/build.js +0 -15
- package/dist/weave/stages/execute.d.ts +0 -42
- package/dist/weave/stages/execute.js +4 -86
- package/dist/weave/stages/handoff.d.ts +0 -7
- package/dist/weave/stages/handoff.js +0 -43
- package/dist/weave/stages/index.d.ts +0 -3
- package/dist/weave/stages/index.js +0 -3
- package/dist/weave/stages/intake.d.ts +0 -8
- package/dist/weave/stages/intake.js +5 -65
- package/dist/weave/stages/map.d.ts +0 -1
- package/dist/weave/stages/openspec.d.ts +0 -1
- package/dist/weave/stages/plan.d.ts +0 -11
- package/dist/weave/stages/plan.js +1 -53
- package/dist/weave/stages/refine.d.ts +0 -7
- package/dist/weave/stages/refine.js +0 -7
- package/dist/weave/stages/research.d.ts +0 -6
- package/dist/weave/stages/research.js +0 -6
- package/dist/weave/stages/spec.d.ts +0 -12
- package/dist/weave/stages/spec.js +0 -17
- package/dist/weave/types.d.ts +0 -20
- package/dist/weave/types.js +0 -5
- package/dist/weave/verification/commands.d.ts +0 -12
- package/dist/weave/verification/commands.js +0 -19
- package/dist/weave/verification/index.d.ts +0 -6
- package/dist/weave/verification/index.js +1 -19
- package/dist/weave/verification/playwright.d.ts +0 -47
- package/dist/weave/verification/playwright.js +1 -90
- package/dist/weave/worktree.d.ts +0 -16
- package/dist/weave/worktree.js +0 -23
- package/dist/weave/yaml-repair.d.ts +0 -39
- package/dist/weave/yaml-repair.js +13 -116
- package/package.json +1 -1
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Management Tests
|
|
3
|
-
*
|
|
4
|
-
* "Make it work, make it right, make it fast." - Kent Beck
|
|
5
|
-
*
|
|
6
|
-
* Red-Green-Refactor cycle for session.ts
|
|
7
|
-
*/
|
|
8
1
|
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
9
2
|
import { mkdtemp, rm } from "fs/promises";
|
|
10
3
|
import { existsSync } from "fs";
|
|
@@ -16,80 +9,59 @@ describe("Session Management", () => {
|
|
|
16
9
|
let tempDir;
|
|
17
10
|
let storage;
|
|
18
11
|
beforeEach(async () => {
|
|
19
|
-
// 각 테스트마다 깨끗한 임시 디렉토리 생성
|
|
20
12
|
tempDir = await mkdtemp(join(tmpdir(), "session-test-"));
|
|
21
13
|
storage = new FileStorageAdapter(tempDir);
|
|
22
14
|
});
|
|
23
15
|
afterEach(async () => {
|
|
24
|
-
// 테스트 후 정리
|
|
25
16
|
await rm(tempDir, { recursive: true, force: true });
|
|
26
17
|
});
|
|
27
|
-
// ==========================================================================
|
|
28
|
-
// createSession Tests
|
|
29
|
-
// ==========================================================================
|
|
30
18
|
describe("createSession", () => {
|
|
31
19
|
test("should generate UUID format sessionId", async () => {
|
|
32
|
-
// Arrange
|
|
33
20
|
const options = {
|
|
34
21
|
goal: "Test goal",
|
|
35
22
|
createdBy: "test-agent",
|
|
36
23
|
};
|
|
37
|
-
// Act
|
|
38
24
|
const session = await createSession(storage, options);
|
|
39
|
-
// Assert - UUID v4 format: 8-4-4-4-12 hex characters
|
|
40
25
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
41
26
|
expect(session.manifest.sessionId).toMatch(uuidRegex);
|
|
42
27
|
});
|
|
43
28
|
test("should create manifest.json file", async () => {
|
|
44
|
-
// Arrange
|
|
45
29
|
const options = {
|
|
46
30
|
goal: "Build feature X",
|
|
47
31
|
createdBy: "operator-1",
|
|
48
32
|
};
|
|
49
|
-
// Act
|
|
50
33
|
const session = await createSession(storage, options);
|
|
51
|
-
// Assert
|
|
52
34
|
const manifestPath = join(tempDir, "shared", session.manifest.sessionId, "manifest.json");
|
|
53
35
|
expect(existsSync(manifestPath)).toBe(true);
|
|
54
36
|
});
|
|
55
37
|
test("should create events/ directory", async () => {
|
|
56
|
-
// Arrange
|
|
57
38
|
const options = {
|
|
58
39
|
goal: "Test events dir",
|
|
59
40
|
createdBy: "test-agent",
|
|
60
41
|
};
|
|
61
|
-
// Act
|
|
62
42
|
const session = await createSession(storage, options);
|
|
63
|
-
// Assert
|
|
64
43
|
const eventsPath = join(tempDir, "shared", session.manifest.sessionId, "events");
|
|
65
44
|
expect(existsSync(eventsPath)).toBe(true);
|
|
66
45
|
});
|
|
67
46
|
test("should create squads/ directory", async () => {
|
|
68
|
-
// Arrange
|
|
69
47
|
const options = {
|
|
70
48
|
goal: "Test squads dir",
|
|
71
49
|
createdBy: "test-agent",
|
|
72
50
|
};
|
|
73
|
-
// Act
|
|
74
51
|
const session = await createSession(storage, options);
|
|
75
|
-
// Assert
|
|
76
52
|
const squadsPath = join(tempDir, "shared", session.manifest.sessionId, "squads");
|
|
77
53
|
expect(existsSync(squadsPath)).toBe(true);
|
|
78
54
|
});
|
|
79
55
|
test("should store goal and createdBy in manifest", async () => {
|
|
80
|
-
// Arrange
|
|
81
56
|
const options = {
|
|
82
57
|
goal: "Implement user authentication",
|
|
83
58
|
createdBy: "orchestrator-alpha",
|
|
84
59
|
};
|
|
85
|
-
// Act
|
|
86
60
|
const session = await createSession(storage, options);
|
|
87
|
-
// Assert
|
|
88
61
|
expect(session.manifest.goal).toBe("Implement user authentication");
|
|
89
62
|
expect(session.manifest.createdBy).toBe("orchestrator-alpha");
|
|
90
63
|
});
|
|
91
64
|
test("should store constraints in manifest when provided", async () => {
|
|
92
|
-
// Arrange
|
|
93
65
|
const options = {
|
|
94
66
|
goal: "Time-boxed task",
|
|
95
67
|
createdBy: "test-agent",
|
|
@@ -98,62 +70,47 @@ describe("Session Management", () => {
|
|
|
98
70
|
tokenBudget: 50000,
|
|
99
71
|
},
|
|
100
72
|
};
|
|
101
|
-
// Act
|
|
102
73
|
const session = await createSession(storage, options);
|
|
103
|
-
// Assert
|
|
104
74
|
expect(session.manifest.constraints).toBeDefined();
|
|
105
75
|
expect(session.manifest.constraints?.timeout).toBe("30m");
|
|
106
76
|
expect(session.manifest.constraints?.tokenBudget).toBe(50000);
|
|
107
77
|
});
|
|
108
78
|
test("should initialize version to 1", async () => {
|
|
109
|
-
// Arrange
|
|
110
79
|
const options = {
|
|
111
80
|
goal: "Test version",
|
|
112
81
|
createdBy: "test-agent",
|
|
113
82
|
};
|
|
114
|
-
// Act
|
|
115
83
|
const session = await createSession(storage, options);
|
|
116
|
-
// Assert
|
|
117
84
|
expect(session.manifest.version).toBe(1);
|
|
118
85
|
});
|
|
119
86
|
test("should initialize squads as empty array", async () => {
|
|
120
|
-
// Arrange
|
|
121
87
|
const options = {
|
|
122
88
|
goal: "Test squads init",
|
|
123
89
|
createdBy: "test-agent",
|
|
124
90
|
};
|
|
125
|
-
// Act
|
|
126
91
|
const session = await createSession(storage, options);
|
|
127
|
-
// Assert
|
|
128
92
|
expect(session.manifest.squads).toEqual([]);
|
|
129
93
|
});
|
|
130
94
|
test("should set createdAt as ISO timestamp", async () => {
|
|
131
|
-
// Arrange
|
|
132
95
|
const beforeCreate = new Date().toISOString();
|
|
133
96
|
const options = {
|
|
134
97
|
goal: "Test timestamp",
|
|
135
98
|
createdBy: "test-agent",
|
|
136
99
|
};
|
|
137
|
-
// Act
|
|
138
100
|
const session = await createSession(storage, options);
|
|
139
101
|
const afterCreate = new Date().toISOString();
|
|
140
|
-
// Assert - createdAt should be between before and after
|
|
141
102
|
expect(session.manifest.createdAt >= beforeCreate).toBe(true);
|
|
142
103
|
expect(session.manifest.createdAt <= afterCreate).toBe(true);
|
|
143
104
|
});
|
|
144
105
|
test("should return correct sessionPath", async () => {
|
|
145
|
-
// Arrange
|
|
146
106
|
const options = {
|
|
147
107
|
goal: "Test session path",
|
|
148
108
|
createdBy: "test-agent",
|
|
149
109
|
};
|
|
150
|
-
// Act
|
|
151
110
|
const session = await createSession(storage, options);
|
|
152
|
-
// Assert
|
|
153
111
|
expect(session.sessionPath).toBe(`shared/${session.manifest.sessionId}`);
|
|
154
112
|
});
|
|
155
113
|
test("should persist manifest that can be read back", async () => {
|
|
156
|
-
// Arrange
|
|
157
114
|
const options = {
|
|
158
115
|
goal: "Persistence test",
|
|
159
116
|
createdBy: "test-agent",
|
|
@@ -161,57 +118,42 @@ describe("Session Management", () => {
|
|
|
161
118
|
timeout: "1h",
|
|
162
119
|
},
|
|
163
120
|
};
|
|
164
|
-
// Act
|
|
165
121
|
const session = await createSession(storage, options);
|
|
166
122
|
const readManifest = await storage.read(`${session.sessionPath}/manifest.json`);
|
|
167
|
-
// Assert
|
|
168
123
|
expect(readManifest).not.toBeNull();
|
|
169
124
|
expect(readManifest?.sessionId).toBe(session.manifest.sessionId);
|
|
170
125
|
expect(readManifest?.goal).toBe("Persistence test");
|
|
171
126
|
expect(readManifest?.constraints?.timeout).toBe("1h");
|
|
172
127
|
});
|
|
173
128
|
});
|
|
174
|
-
// ==========================================================================
|
|
175
|
-
// loadSession Tests
|
|
176
|
-
// ==========================================================================
|
|
177
129
|
describe("loadSession", () => {
|
|
178
130
|
test("should load existing session successfully", async () => {
|
|
179
|
-
// Arrange - 먼저 세션 생성
|
|
180
131
|
const options = {
|
|
181
132
|
goal: "Load test",
|
|
182
133
|
createdBy: "creator-agent",
|
|
183
134
|
};
|
|
184
135
|
const created = await createSession(storage, options);
|
|
185
|
-
// Act - 세션 로드
|
|
186
136
|
const loaded = await loadSession(storage, created.manifest.sessionId);
|
|
187
|
-
// Assert
|
|
188
137
|
expect(loaded).not.toBeNull();
|
|
189
138
|
expect(loaded?.manifest.sessionId).toBe(created.manifest.sessionId);
|
|
190
139
|
expect(loaded?.manifest.goal).toBe("Load test");
|
|
191
140
|
expect(loaded?.manifest.createdBy).toBe("creator-agent");
|
|
192
141
|
});
|
|
193
142
|
test("should return null for non-existent session", async () => {
|
|
194
|
-
// Arrange - 존재하지 않는 sessionId
|
|
195
143
|
const fakeSessionId = "00000000-0000-0000-0000-000000000000";
|
|
196
|
-
// Act
|
|
197
144
|
const result = await loadSession(storage, fakeSessionId);
|
|
198
|
-
// Assert
|
|
199
145
|
expect(result).toBeNull();
|
|
200
146
|
});
|
|
201
147
|
test("should return correct sessionPath", async () => {
|
|
202
|
-
// Arrange
|
|
203
148
|
const options = {
|
|
204
149
|
goal: "Path test",
|
|
205
150
|
createdBy: "test-agent",
|
|
206
151
|
};
|
|
207
152
|
const created = await createSession(storage, options);
|
|
208
|
-
// Act
|
|
209
153
|
const loaded = await loadSession(storage, created.manifest.sessionId);
|
|
210
|
-
// Assert
|
|
211
154
|
expect(loaded?.sessionPath).toBe(`shared/${created.manifest.sessionId}`);
|
|
212
155
|
});
|
|
213
156
|
test("should load session with constraints", async () => {
|
|
214
|
-
// Arrange
|
|
215
157
|
const options = {
|
|
216
158
|
goal: "Constraints load test",
|
|
217
159
|
createdBy: "test-agent",
|
|
@@ -221,22 +163,17 @@ describe("Session Management", () => {
|
|
|
221
163
|
},
|
|
222
164
|
};
|
|
223
165
|
const created = await createSession(storage, options);
|
|
224
|
-
// Act
|
|
225
166
|
const loaded = await loadSession(storage, created.manifest.sessionId);
|
|
226
|
-
// Assert
|
|
227
167
|
expect(loaded?.manifest.constraints?.timeout).toBe("2h");
|
|
228
168
|
expect(loaded?.manifest.constraints?.tokenBudget).toBe(100000);
|
|
229
169
|
});
|
|
230
170
|
test("should return storage adapter reference", async () => {
|
|
231
|
-
// Arrange
|
|
232
171
|
const options = {
|
|
233
172
|
goal: "Storage ref test",
|
|
234
173
|
createdBy: "test-agent",
|
|
235
174
|
};
|
|
236
175
|
const created = await createSession(storage, options);
|
|
237
|
-
// Act
|
|
238
176
|
const loaded = await loadSession(storage, created.manifest.sessionId);
|
|
239
|
-
// Assert
|
|
240
177
|
expect(loaded?.storage).toBe(storage);
|
|
241
178
|
});
|
|
242
179
|
});
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Squad Management Tests
|
|
3
|
-
*
|
|
4
|
-
* Kent Beck의 TDD 원칙:
|
|
5
|
-
* - 작고 명확한 테스트
|
|
6
|
-
* - 하나의 테스트는 하나의 행동만 검증
|
|
7
|
-
* - Red-Green-Refactor 사이클
|
|
8
|
-
*
|
|
9
|
-
* @author Kent Beck's Dummy Human
|
|
10
|
-
*/
|
|
11
1
|
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
12
2
|
import { mkdtemp, rm } from "fs/promises";
|
|
13
3
|
import { tmpdir } from "os";
|
|
@@ -17,14 +7,10 @@ import { FileStorageAdapter } from "../storage.js";
|
|
|
17
7
|
import { createSession } from "../session.js";
|
|
18
8
|
import { createSquad, getSquad, updateSquadState } from "../squad.js";
|
|
19
9
|
import { LIMITS } from "../types.js";
|
|
20
|
-
// ============================================================================
|
|
21
|
-
// Test Fixtures
|
|
22
|
-
// ============================================================================
|
|
23
10
|
let tempDir;
|
|
24
11
|
let storage;
|
|
25
12
|
let session;
|
|
26
13
|
beforeEach(async () => {
|
|
27
|
-
// Arrange: 각 테스트 전에 깨끗한 임시 디렉토리 생성
|
|
28
14
|
tempDir = await mkdtemp(join(tmpdir(), "squad-test-"));
|
|
29
15
|
storage = new FileStorageAdapter(tempDir);
|
|
30
16
|
session = await createSession(storage, {
|
|
@@ -33,48 +19,37 @@ beforeEach(async () => {
|
|
|
33
19
|
});
|
|
34
20
|
});
|
|
35
21
|
afterEach(async () => {
|
|
36
|
-
// Cleanup: 테스트 후 임시 디렉토리 정리
|
|
37
22
|
if (tempDir && existsSync(tempDir)) {
|
|
38
23
|
await rm(tempDir, { recursive: true, force: true });
|
|
39
24
|
}
|
|
40
25
|
});
|
|
41
|
-
// ============================================================================
|
|
42
|
-
// createSquad Tests
|
|
43
|
-
// ============================================================================
|
|
44
26
|
describe("createSquad", () => {
|
|
45
27
|
test("should create spec.json and state.json files", async () => {
|
|
46
|
-
// Act
|
|
47
28
|
const { spec, state } = await createSquad(session, {
|
|
48
29
|
mission: "Implement feature X",
|
|
49
30
|
operator: "operator-agent",
|
|
50
31
|
});
|
|
51
|
-
// Assert: 파일 생성 확인
|
|
52
32
|
const squadPath = `${session.sessionPath}/squads/${spec.squadId}`;
|
|
53
33
|
expect(storage.exists(`${squadPath}/spec.json`)).toBe(true);
|
|
54
34
|
expect(storage.exists(`${squadPath}/state.json`)).toBe(true);
|
|
55
35
|
});
|
|
56
36
|
test("should add squadId to manifest.squads array", async () => {
|
|
57
|
-
// Act
|
|
58
37
|
const { spec } = await createSquad(session, {
|
|
59
38
|
mission: "Implement feature X",
|
|
60
39
|
operator: "operator-agent",
|
|
61
40
|
});
|
|
62
|
-
// Assert: manifest에 squadId 추가 확인
|
|
63
41
|
expect(session.manifest.squads).toContain(spec.squadId);
|
|
64
42
|
expect(session.manifest.squads.length).toBe(1);
|
|
65
43
|
});
|
|
66
44
|
test("should create scratch/ directory", async () => {
|
|
67
|
-
// Act
|
|
68
45
|
const { spec } = await createSquad(session, {
|
|
69
46
|
mission: "Implement feature X",
|
|
70
47
|
operator: "operator-agent",
|
|
71
48
|
});
|
|
72
|
-
// Assert: scratch 디렉토리 생성 확인
|
|
73
49
|
const scratchPath = `${session.sessionPath}/squads/${spec.squadId}/scratch`;
|
|
74
50
|
expect(existsSync(storage.getFullPath(scratchPath))).toBe(true);
|
|
75
51
|
});
|
|
76
52
|
test("should return spec with correct properties", async () => {
|
|
77
|
-
// Arrange
|
|
78
53
|
const options = {
|
|
79
54
|
mission: "Implement OAuth login",
|
|
80
55
|
operator: "operator-alpha",
|
|
@@ -88,9 +63,7 @@ describe("createSquad", () => {
|
|
|
88
63
|
directories: ["src/auth/"],
|
|
89
64
|
},
|
|
90
65
|
};
|
|
91
|
-
// Act
|
|
92
66
|
const { spec } = await createSquad(session, options);
|
|
93
|
-
// Assert: spec 속성 검증
|
|
94
67
|
expect(spec.squadId).toMatch(/^squad-[a-f0-9]{8}$/);
|
|
95
68
|
expect(spec.mission).toBe(options.mission);
|
|
96
69
|
expect(spec.operator).toBe(options.operator);
|
|
@@ -101,12 +74,10 @@ describe("createSquad", () => {
|
|
|
101
74
|
expect(spec.createdAt).toBeDefined();
|
|
102
75
|
});
|
|
103
76
|
test("should return state with initial values", async () => {
|
|
104
|
-
// Act
|
|
105
77
|
const { state } = await createSquad(session, {
|
|
106
78
|
mission: "Test mission",
|
|
107
79
|
operator: "operator",
|
|
108
80
|
});
|
|
109
|
-
// Assert: 초기 상태 검증
|
|
110
81
|
expect(state.status).toBe("pending");
|
|
111
82
|
expect(state.progress).toBe(0);
|
|
112
83
|
expect(state.tasks).toEqual([]);
|
|
@@ -114,35 +85,29 @@ describe("createSquad", () => {
|
|
|
114
85
|
expect(state.updatedAt).toBeDefined();
|
|
115
86
|
});
|
|
116
87
|
test("should use default maxWorkers from LIMITS when not specified", async () => {
|
|
117
|
-
// Act
|
|
118
88
|
const { spec } = await createSquad(session, {
|
|
119
89
|
mission: "Test mission",
|
|
120
90
|
operator: "operator",
|
|
121
91
|
});
|
|
122
|
-
// Assert
|
|
123
92
|
expect(spec.constraints?.maxWorkers).toBe(LIMITS.maxWorkersPerSquad);
|
|
124
93
|
});
|
|
125
94
|
test("should throw error when maxSquadsPerSession limit is reached", async () => {
|
|
126
|
-
// Arrange: 최대 개수만큼 Squad 생성
|
|
127
95
|
for (let i = 0; i < LIMITS.maxSquadsPerSession; i++) {
|
|
128
96
|
await createSquad(session, {
|
|
129
97
|
mission: `Mission ${i}`,
|
|
130
98
|
operator: "operator",
|
|
131
99
|
});
|
|
132
100
|
}
|
|
133
|
-
// Act & Assert: 한도 초과 시 에러
|
|
134
101
|
await expect(createSquad(session, {
|
|
135
102
|
mission: "One too many",
|
|
136
103
|
operator: "operator",
|
|
137
104
|
})).rejects.toThrow("Maximum squads per session exceeded");
|
|
138
105
|
});
|
|
139
106
|
test("should persist spec.json with correct data", async () => {
|
|
140
|
-
// Act
|
|
141
107
|
const { spec } = await createSquad(session, {
|
|
142
108
|
mission: "Persisted mission",
|
|
143
109
|
operator: "persistent-operator",
|
|
144
110
|
});
|
|
145
|
-
// Assert: 파일에서 직접 읽어서 검증
|
|
146
111
|
const squadPath = `${session.sessionPath}/squads/${spec.squadId}`;
|
|
147
112
|
const savedSpec = await storage.read(`${squadPath}/spec.json`);
|
|
148
113
|
expect(savedSpec).not.toBeNull();
|
|
@@ -150,129 +115,98 @@ describe("createSquad", () => {
|
|
|
150
115
|
expect(savedSpec?.operator).toBe("persistent-operator");
|
|
151
116
|
});
|
|
152
117
|
});
|
|
153
|
-
// ============================================================================
|
|
154
|
-
// getSquad Tests
|
|
155
|
-
// ============================================================================
|
|
156
118
|
describe("getSquad", () => {
|
|
157
119
|
test("should return squad when it exists", async () => {
|
|
158
|
-
// Arrange
|
|
159
120
|
const created = await createSquad(session, {
|
|
160
121
|
mission: "Find me",
|
|
161
122
|
operator: "operator",
|
|
162
123
|
});
|
|
163
|
-
// Act
|
|
164
124
|
const retrieved = await getSquad(session, created.spec.squadId);
|
|
165
|
-
// Assert
|
|
166
125
|
expect(retrieved).not.toBeNull();
|
|
167
126
|
expect(retrieved?.spec.squadId).toBe(created.spec.squadId);
|
|
168
127
|
expect(retrieved?.spec.mission).toBe("Find me");
|
|
169
128
|
expect(retrieved?.state.status).toBe("pending");
|
|
170
129
|
});
|
|
171
130
|
test("should return null when squad does not exist", async () => {
|
|
172
|
-
// Act
|
|
173
131
|
const result = await getSquad(session, "squad-nonexistent");
|
|
174
|
-
// Assert
|
|
175
132
|
expect(result).toBeNull();
|
|
176
133
|
});
|
|
177
134
|
test("should return both spec and state", async () => {
|
|
178
|
-
// Arrange
|
|
179
135
|
const created = await createSquad(session, {
|
|
180
136
|
mission: "Dual return test",
|
|
181
137
|
operator: "operator",
|
|
182
138
|
});
|
|
183
|
-
// Act
|
|
184
139
|
const result = await getSquad(session, created.spec.squadId);
|
|
185
|
-
// Assert
|
|
186
140
|
expect(result).toHaveProperty("spec");
|
|
187
141
|
expect(result).toHaveProperty("state");
|
|
188
142
|
expect(result?.spec.squadId).toBe(result?.state.squadId);
|
|
189
143
|
});
|
|
190
144
|
});
|
|
191
|
-
// ============================================================================
|
|
192
|
-
// updateSquadState Tests
|
|
193
|
-
// ============================================================================
|
|
194
145
|
describe("updateSquadState", () => {
|
|
195
146
|
test("should update state and reflect changes on subsequent get", async () => {
|
|
196
|
-
// Arrange
|
|
197
147
|
const { spec } = await createSquad(session, {
|
|
198
148
|
mission: "Update me",
|
|
199
149
|
operator: "operator",
|
|
200
150
|
});
|
|
201
|
-
// Act
|
|
202
151
|
await updateSquadState(session, spec.squadId, {
|
|
203
152
|
status: "active",
|
|
204
153
|
progress: 50,
|
|
205
154
|
});
|
|
206
|
-
// Assert: 업데이트된 값 확인
|
|
207
155
|
const retrieved = await getSquad(session, spec.squadId);
|
|
208
156
|
expect(retrieved?.state.status).toBe("active");
|
|
209
157
|
expect(retrieved?.state.progress).toBe(50);
|
|
210
158
|
});
|
|
211
159
|
test("should automatically update updatedAt timestamp", async () => {
|
|
212
|
-
// Arrange
|
|
213
160
|
const { spec, state: initialState } = await createSquad(session, {
|
|
214
161
|
mission: "Timestamp test",
|
|
215
162
|
operator: "operator",
|
|
216
163
|
});
|
|
217
164
|
const initialUpdatedAt = initialState.updatedAt;
|
|
218
|
-
// 시간 차이를 위해 약간 대기
|
|
219
165
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
220
|
-
// Act
|
|
221
166
|
const updatedState = await updateSquadState(session, spec.squadId, {
|
|
222
167
|
progress: 25,
|
|
223
168
|
});
|
|
224
|
-
// Assert: updatedAt이 갱신됨
|
|
225
169
|
expect(updatedState.updatedAt).not.toBe(initialUpdatedAt);
|
|
226
170
|
expect(new Date(updatedState.updatedAt).getTime()).toBeGreaterThan(new Date(initialUpdatedAt).getTime());
|
|
227
171
|
});
|
|
228
172
|
test("should throw error when squad does not exist", async () => {
|
|
229
|
-
// Act & Assert
|
|
230
173
|
await expect(updateSquadState(session, "squad-nonexistent", { status: "active" })).rejects.toThrow("Squad not found: squad-nonexistent");
|
|
231
174
|
});
|
|
232
175
|
test("should preserve unmodified fields", async () => {
|
|
233
|
-
// Arrange
|
|
234
176
|
const { spec } = await createSquad(session, {
|
|
235
177
|
mission: "Preserve fields",
|
|
236
178
|
operator: "operator",
|
|
237
179
|
});
|
|
238
|
-
// Act: status만 업데이트
|
|
239
180
|
await updateSquadState(session, spec.squadId, { status: "active" });
|
|
240
|
-
// Assert: 다른 필드는 유지
|
|
241
181
|
const retrieved = await getSquad(session, spec.squadId);
|
|
242
182
|
expect(retrieved?.state.status).toBe("active");
|
|
243
|
-
expect(retrieved?.state.progress).toBe(0);
|
|
244
|
-
expect(retrieved?.state.tasks).toEqual([]);
|
|
183
|
+
expect(retrieved?.state.progress).toBe(0);
|
|
184
|
+
expect(retrieved?.state.tasks).toEqual([]);
|
|
245
185
|
});
|
|
246
186
|
test("should return the updated state", async () => {
|
|
247
|
-
// Arrange
|
|
248
187
|
const { spec } = await createSquad(session, {
|
|
249
188
|
mission: "Return value test",
|
|
250
189
|
operator: "operator",
|
|
251
190
|
});
|
|
252
|
-
// Act
|
|
253
191
|
const result = await updateSquadState(session, spec.squadId, {
|
|
254
192
|
status: "completed",
|
|
255
193
|
progress: 100,
|
|
256
194
|
});
|
|
257
|
-
// Assert
|
|
258
195
|
expect(result.status).toBe("completed");
|
|
259
196
|
expect(result.progress).toBe(100);
|
|
260
197
|
expect(result.squadId).toBe(spec.squadId);
|
|
261
198
|
});
|
|
262
199
|
test("should update sharedContext", async () => {
|
|
263
|
-
// Arrange
|
|
264
200
|
const { spec } = await createSquad(session, {
|
|
265
201
|
mission: "Shared context test",
|
|
266
202
|
operator: "operator",
|
|
267
203
|
});
|
|
268
|
-
// Act
|
|
269
204
|
await updateSquadState(session, spec.squadId, {
|
|
270
205
|
sharedContext: {
|
|
271
206
|
apiEndpoint: "https://api.example.com",
|
|
272
207
|
authToken: "secret",
|
|
273
208
|
},
|
|
274
209
|
});
|
|
275
|
-
// Assert
|
|
276
210
|
const retrieved = await getSquad(session, spec.squadId);
|
|
277
211
|
expect(retrieved?.state.sharedContext).toEqual({
|
|
278
212
|
apiEndpoint: "https://api.example.com",
|