@coralai/sps-cli 0.24.4 → 0.24.6

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 (69) hide show
  1. package/dist/core/config.d.ts.map +1 -1
  2. package/dist/core/config.js +3 -70
  3. package/dist/core/config.js.map +1 -1
  4. package/dist/core/config.test.d.ts +2 -0
  5. package/dist/core/config.test.d.ts.map +1 -0
  6. package/dist/core/config.test.js +363 -0
  7. package/dist/core/config.test.js.map +1 -0
  8. package/dist/core/lock.d.ts.map +1 -1
  9. package/dist/core/lock.js +8 -5
  10. package/dist/core/lock.js.map +1 -1
  11. package/dist/core/lock.test.d.ts +2 -0
  12. package/dist/core/lock.test.d.ts.map +1 -0
  13. package/dist/core/lock.test.js +103 -0
  14. package/dist/core/lock.test.js.map +1 -0
  15. package/dist/core/queue.test.d.ts +2 -0
  16. package/dist/core/queue.test.d.ts.map +1 -0
  17. package/dist/core/queue.test.js +99 -0
  18. package/dist/core/queue.test.js.map +1 -0
  19. package/dist/core/shellEnv.d.ts +20 -0
  20. package/dist/core/shellEnv.d.ts.map +1 -0
  21. package/dist/core/shellEnv.js +78 -0
  22. package/dist/core/shellEnv.js.map +1 -0
  23. package/dist/core/shellEnv.test.d.ts +2 -0
  24. package/dist/core/shellEnv.test.d.ts.map +1 -0
  25. package/dist/core/shellEnv.test.js +101 -0
  26. package/dist/core/shellEnv.test.js.map +1 -0
  27. package/dist/core/state.test.d.ts +2 -0
  28. package/dist/core/state.test.d.ts.map +1 -0
  29. package/dist/core/state.test.js +322 -0
  30. package/dist/core/state.test.js.map +1 -0
  31. package/dist/manager/completion-judge.d.ts.map +1 -1
  32. package/dist/manager/completion-judge.js +12 -2
  33. package/dist/manager/completion-judge.js.map +1 -1
  34. package/dist/manager/completion-judge.test.d.ts +2 -0
  35. package/dist/manager/completion-judge.test.d.ts.map +1 -0
  36. package/dist/manager/completion-judge.test.js +218 -0
  37. package/dist/manager/completion-judge.test.js.map +1 -0
  38. package/dist/manager/integration-queue.test.d.ts +2 -0
  39. package/dist/manager/integration-queue.test.d.ts.map +1 -0
  40. package/dist/manager/integration-queue.test.js +195 -0
  41. package/dist/manager/integration-queue.test.js.map +1 -0
  42. package/dist/manager/resource-limiter.test.d.ts +2 -0
  43. package/dist/manager/resource-limiter.test.d.ts.map +1 -0
  44. package/dist/manager/resource-limiter.test.js +103 -0
  45. package/dist/manager/resource-limiter.test.js.map +1 -0
  46. package/dist/manager/supervisor.d.ts +0 -1
  47. package/dist/manager/supervisor.d.ts.map +1 -1
  48. package/dist/manager/supervisor.js +5 -40
  49. package/dist/manager/supervisor.js.map +1 -1
  50. package/dist/manager/supervisor.test.d.ts +2 -0
  51. package/dist/manager/supervisor.test.d.ts.map +1 -0
  52. package/dist/manager/supervisor.test.js +245 -0
  53. package/dist/manager/supervisor.test.js.map +1 -0
  54. package/dist/manager/worker-manager-impl.d.ts.map +1 -1
  55. package/dist/manager/worker-manager-impl.js +7 -0
  56. package/dist/manager/worker-manager-impl.js.map +1 -1
  57. package/dist/manager/worker-manager-impl.test.d.ts +2 -0
  58. package/dist/manager/worker-manager-impl.test.d.ts.map +1 -0
  59. package/dist/manager/worker-manager-impl.test.js +528 -0
  60. package/dist/manager/worker-manager-impl.test.js.map +1 -0
  61. package/dist/providers/outputParser.test.d.ts +2 -0
  62. package/dist/providers/outputParser.test.d.ts.map +1 -0
  63. package/dist/providers/outputParser.test.js +203 -0
  64. package/dist/providers/outputParser.test.js.map +1 -0
  65. package/dist/test-setup.d.ts +2 -0
  66. package/dist/test-setup.d.ts.map +1 -0
  67. package/dist/test-setup.js +18 -0
  68. package/dist/test-setup.js.map +1 -0
  69. package/package.json +7 -2
@@ -0,0 +1,203 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import { tailFile, fileSize, parseClaudeSessionId, parseCodexSessionId, isProcessAlive, extractLastAssistantText, } from './outputParser.js';
6
+ // ─── Helpers ──────────────────────────────────────────────────────
7
+ function makeTempDir() {
8
+ return mkdtempSync(join(tmpdir(), 'sps-parser-test-'));
9
+ }
10
+ // ─── Tests ────────────────────────────────────────────────────────
11
+ describe('tailFile', () => {
12
+ let tempDir;
13
+ beforeEach(() => { tempDir = makeTempDir(); });
14
+ afterEach(() => { rmSync(tempDir, { recursive: true, force: true }); });
15
+ it('returns empty string for nonexistent file', () => {
16
+ expect(tailFile('/tmp/does-not-exist-12345.txt', 10)).toBe('');
17
+ });
18
+ it('returns last N lines', () => {
19
+ const file = join(tempDir, 'log.txt');
20
+ writeFileSync(file, 'line1\nline2\nline3\nline4\nline5\n');
21
+ const result = tailFile(file, 2);
22
+ expect(result).toBe('line5\n'); // last 2 entries include trailing empty
23
+ });
24
+ it('returns entire file when fewer lines than requested', () => {
25
+ const file = join(tempDir, 'short.txt');
26
+ writeFileSync(file, 'only\n');
27
+ const result = tailFile(file, 100);
28
+ expect(result).toContain('only');
29
+ });
30
+ });
31
+ describe('fileSize', () => {
32
+ let tempDir;
33
+ beforeEach(() => { tempDir = makeTempDir(); });
34
+ afterEach(() => { rmSync(tempDir, { recursive: true, force: true }); });
35
+ it('returns 0 for nonexistent file', () => {
36
+ expect(fileSize('/tmp/no-file-12345')).toBe(0);
37
+ });
38
+ it('returns correct size', () => {
39
+ const file = join(tempDir, 'data.bin');
40
+ writeFileSync(file, 'hello world'); // 11 bytes
41
+ expect(fileSize(file)).toBe(11);
42
+ });
43
+ it('returns 0 for empty file', () => {
44
+ const file = join(tempDir, 'empty.txt');
45
+ writeFileSync(file, '');
46
+ expect(fileSize(file)).toBe(0);
47
+ });
48
+ });
49
+ describe('parseClaudeSessionId', () => {
50
+ let tempDir;
51
+ beforeEach(() => { tempDir = makeTempDir(); });
52
+ afterEach(() => { rmSync(tempDir, { recursive: true, force: true }); });
53
+ it('returns null for nonexistent file', () => {
54
+ expect(parseClaudeSessionId('/tmp/no-file-12345')).toBeNull();
55
+ });
56
+ it('extracts session_id from stream-json output', () => {
57
+ const file = join(tempDir, 'output.jsonl');
58
+ writeFileSync(file, [
59
+ '{"type":"system","message":"starting"}',
60
+ '{"type":"assistant","message":{"content":"hello"}}',
61
+ '{"type":"result","result":"done","session_id":"sess-abc-123"}',
62
+ ].join('\n'));
63
+ expect(parseClaudeSessionId(file)).toBe('sess-abc-123');
64
+ });
65
+ it('returns null when no session_id present', () => {
66
+ const file = join(tempDir, 'output.jsonl');
67
+ writeFileSync(file, '{"type":"result","result":"done"}\n');
68
+ expect(parseClaudeSessionId(file)).toBeNull();
69
+ });
70
+ it('skips non-JSON lines gracefully', () => {
71
+ const file = join(tempDir, 'mixed.jsonl');
72
+ writeFileSync(file, [
73
+ 'not json at all',
74
+ '{"session_id":"found-it"}',
75
+ 'another bad line',
76
+ ].join('\n'));
77
+ expect(parseClaudeSessionId(file)).toBe('found-it');
78
+ });
79
+ it('returns first session_id found', () => {
80
+ const file = join(tempDir, 'multi.jsonl');
81
+ writeFileSync(file, [
82
+ '{"session_id":"first"}',
83
+ '{"session_id":"second"}',
84
+ ].join('\n'));
85
+ expect(parseClaudeSessionId(file)).toBe('first');
86
+ });
87
+ });
88
+ describe('parseCodexSessionId', () => {
89
+ let tempDir;
90
+ beforeEach(() => { tempDir = makeTempDir(); });
91
+ afterEach(() => { rmSync(tempDir, { recursive: true, force: true }); });
92
+ it('returns null for nonexistent file', () => {
93
+ expect(parseCodexSessionId('/tmp/no-file-12345')).toBeNull();
94
+ });
95
+ it('extracts conversation_id', () => {
96
+ const file = join(tempDir, 'codex.jsonl');
97
+ writeFileSync(file, '{"conversation_id":"conv-xyz-789"}\n');
98
+ expect(parseCodexSessionId(file)).toBe('conv-xyz-789');
99
+ });
100
+ it('extracts session_id', () => {
101
+ const file = join(tempDir, 'codex.jsonl');
102
+ writeFileSync(file, '{"session_id":"sess-xyz"}\n');
103
+ expect(parseCodexSessionId(file)).toBe('sess-xyz');
104
+ });
105
+ it('extracts id from session_start event', () => {
106
+ const file = join(tempDir, 'codex.jsonl');
107
+ writeFileSync(file, '{"type":"session_start","id":"start-id-123"}\n');
108
+ expect(parseCodexSessionId(file)).toBe('start-id-123');
109
+ });
110
+ it('prefers conversation_id over session_id', () => {
111
+ const file = join(tempDir, 'codex.jsonl');
112
+ writeFileSync(file, '{"conversation_id":"conv","session_id":"sess"}\n');
113
+ expect(parseCodexSessionId(file)).toBe('conv');
114
+ });
115
+ it('returns null when no IDs present', () => {
116
+ const file = join(tempDir, 'codex.jsonl');
117
+ writeFileSync(file, '{"type":"message","text":"hello"}\n');
118
+ expect(parseCodexSessionId(file)).toBeNull();
119
+ });
120
+ });
121
+ describe('isProcessAlive', () => {
122
+ it('returns true for current process', () => {
123
+ expect(isProcessAlive(process.pid)).toBe(true);
124
+ });
125
+ it('returns false for invalid PID', () => {
126
+ expect(isProcessAlive(0)).toBe(false);
127
+ expect(isProcessAlive(-1)).toBe(false);
128
+ });
129
+ it('returns false for non-existent PID', () => {
130
+ // Use a very high PID that almost certainly doesn't exist
131
+ expect(isProcessAlive(4_000_000)).toBe(false);
132
+ });
133
+ });
134
+ describe('extractLastAssistantText', () => {
135
+ let tempDir;
136
+ beforeEach(() => { tempDir = makeTempDir(); });
137
+ afterEach(() => { rmSync(tempDir, { recursive: true, force: true }); });
138
+ it('returns empty string for nonexistent file', () => {
139
+ expect(extractLastAssistantText('/tmp/no-file-12345')).toBe('');
140
+ });
141
+ it('extracts text from assistant message with content array', () => {
142
+ const file = join(tempDir, 'output.jsonl');
143
+ writeFileSync(file, JSON.stringify({
144
+ type: 'assistant',
145
+ message: {
146
+ content: [
147
+ { type: 'text', text: 'I have completed the task.' },
148
+ ],
149
+ },
150
+ }) + '\n');
151
+ expect(extractLastAssistantText(file)).toBe('I have completed the task.');
152
+ });
153
+ it('extracts text from assistant message with string content', () => {
154
+ const file = join(tempDir, 'output.jsonl');
155
+ writeFileSync(file, JSON.stringify({
156
+ type: 'assistant',
157
+ message: { content: 'Done! All tasks finished.' },
158
+ }) + '\n');
159
+ expect(extractLastAssistantText(file)).toBe('Done! All tasks finished.');
160
+ });
161
+ it('extracts from result type', () => {
162
+ const file = join(tempDir, 'output.jsonl');
163
+ writeFileSync(file, JSON.stringify({
164
+ type: 'result',
165
+ result: 'Task completed successfully 🎉',
166
+ }) + '\n');
167
+ expect(extractLastAssistantText(file)).toBe('Task completed successfully 🎉');
168
+ });
169
+ it('returns last assistant text when multiple messages', () => {
170
+ const file = join(tempDir, 'output.jsonl');
171
+ const lines = [
172
+ JSON.stringify({ type: 'assistant', message: { content: 'Starting...' } }),
173
+ JSON.stringify({ type: 'assistant', message: { content: 'Working...' } }),
174
+ JSON.stringify({ type: 'assistant', message: { content: '全部完成' } }),
175
+ ];
176
+ writeFileSync(file, lines.join('\n') + '\n');
177
+ expect(extractLastAssistantText(file)).toBe('全部完成');
178
+ });
179
+ it('accumulates content_block_delta text', () => {
180
+ const file = join(tempDir, 'output.jsonl');
181
+ const lines = [
182
+ JSON.stringify({ type: 'content_block_delta', delta: { text: 'Hello ' } }),
183
+ JSON.stringify({ type: 'content_block_delta', delta: { text: 'world' } }),
184
+ ];
185
+ writeFileSync(file, lines.join('\n') + '\n');
186
+ expect(extractLastAssistantText(file)).toBe('Hello world');
187
+ });
188
+ it('skips non-JSON lines without error', () => {
189
+ const file = join(tempDir, 'mixed.jsonl');
190
+ writeFileSync(file, [
191
+ 'garbage line',
192
+ JSON.stringify({ type: 'assistant', message: { content: 'valid' } }),
193
+ 'more garbage',
194
+ ].join('\n') + '\n');
195
+ expect(extractLastAssistantText(file)).toBe('valid');
196
+ });
197
+ it('returns empty string for empty file', () => {
198
+ const file = join(tempDir, 'empty.jsonl');
199
+ writeFileSync(file, '');
200
+ expect(extractLastAssistantText(file)).toBe('');
201
+ });
202
+ });
203
+ //# sourceMappingURL=outputParser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outputParser.test.js","sourceRoot":"","sources":["../../src/providers/outputParser.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=test-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-setup.d.ts","sourceRoot":"","sources":["../src/test-setup.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Vitest global setup — suppress stderr log noise during tests.
3
+ *
4
+ * Production modules write [worker-manager], [supervisor], [completion-judge]
5
+ * logs to stderr. This silences them in test output.
6
+ */
7
+ import { vi } from 'vitest';
8
+ const originalWrite = process.stderr.write.bind(process.stderr);
9
+ vi.spyOn(process.stderr, 'write').mockImplementation((chunk, ...rest) => {
10
+ const msg = typeof chunk === 'string' ? chunk : '';
11
+ // Suppress known log prefixes from production code
12
+ if (/^\[(worker-manager|supervisor|completion-judge|integration-queue)\]/.test(msg)) {
13
+ return true;
14
+ }
15
+ // Pass through everything else (test framework output, actual errors)
16
+ return originalWrite(chunk, ...rest);
17
+ });
18
+ //# sourceMappingURL=test-setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-setup.js","sourceRoot":"","sources":["../src/test-setup.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE5B,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AAEhE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,CAAC,KAAU,EAAE,GAAG,IAAW,EAAE,EAAE;IAClF,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACnD,mDAAmD;IACnD,IAAI,qEAAqE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACpF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,sEAAsE;IACtE,OAAQ,aAAqB,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coralai/sps-cli",
3
- "version": "0.24.4",
3
+ "version": "0.24.6",
4
4
  "description": "SPS CLI — AI-driven development pipeline orchestrator",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",
@@ -11,6 +11,9 @@
11
11
  "build": "tsc && rm -rf ./project-template && cp -r ../project-template ./project-template",
12
12
  "dev": "tsx src/main.ts",
13
13
  "typecheck": "tsc --noEmit",
14
+ "test": "vitest run",
15
+ "test:watch": "vitest",
16
+ "test:coverage": "vitest run --coverage",
14
17
  "prepublishOnly": "npm run build"
15
18
  },
16
19
  "engines": {
@@ -33,8 +36,10 @@
33
36
  "license": "MIT",
34
37
  "devDependencies": {
35
38
  "@types/node": "^25.5.0",
39
+ "@vitest/coverage-v8": "^4.1.2",
36
40
  "tsx": "^4.21.0",
37
- "typescript": "^5.9.3"
41
+ "typescript": "^5.9.3",
42
+ "vitest": "^4.1.2"
38
43
  },
39
44
  "dependencies": {
40
45
  "node-pty": "^1.2.0-beta.12",