sofia-cli 0.1.1 → 0.1.4

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 (136) hide show
  1. package/README.md +42 -20
  2. package/dist/infra/deploy.sh +193 -0
  3. package/dist/infra/gather-env.sh +211 -0
  4. package/dist/infra/infra/deploy.sh +193 -0
  5. package/dist/infra/infra/gather-env.sh +211 -0
  6. package/dist/infra/infra/main.bicep +90 -0
  7. package/dist/infra/infra/main.bicepparam +18 -0
  8. package/dist/infra/infra/resources.bicep +134 -0
  9. package/dist/infra/infra/teardown.sh +114 -0
  10. package/dist/infra/main.bicep +90 -0
  11. package/dist/infra/main.bicepparam +18 -0
  12. package/dist/infra/resources.bicep +134 -0
  13. package/dist/infra/teardown.sh +114 -0
  14. package/dist/src/cli/developCommand.js +0 -2
  15. package/dist/src/cli/index.js +8 -1
  16. package/dist/src/cli/workshopCommand.js +1 -1
  17. package/dist/src/develop/index.js +1 -1
  18. package/dist/src/develop/pocUtils.js +228 -0
  19. package/dist/src/develop/ralphLoop.js +3 -3
  20. package/dist/src/shared/data/cards.json +655 -670
  21. package/docs/architecture.md +2 -1
  22. package/package.json +5 -3
  23. package/src/cli/developCommand.ts +1 -3
  24. package/src/cli/index.ts +11 -1
  25. package/src/cli/workshopCommand.ts +21 -17
  26. package/src/develop/dynamicScaffolder.ts +36 -30
  27. package/src/develop/index.ts +13 -2
  28. package/src/develop/pocUtils.ts +296 -0
  29. package/src/develop/ralphLoop.ts +8 -28
  30. package/src/develop/templateRegistry.ts +19 -18
  31. package/src/shared/data/cards.json +655 -670
  32. package/tests/e2e/developE2e.spec.ts +3 -61
  33. package/tests/e2e/developFailureE2e.spec.ts +34 -38
  34. package/tests/integration/pocGithubMcp.spec.ts +29 -39
  35. package/tests/integration/pocLocalFallback.spec.ts +29 -39
  36. package/tests/integration/ralphLoopFlow.spec.ts +46 -66
  37. package/tests/integration/ralphLoopPartial.spec.ts +30 -37
  38. package/tests/unit/develop/githubMcpAdapter.spec.ts +0 -134
  39. package/tests/unit/develop/outputValidator.spec.ts +45 -21
  40. package/tests/unit/develop/ralphLoop.spec.ts +58 -94
  41. package/tsconfig.json +2 -1
  42. package/vitest.workspace.ts +5 -0
  43. package/dist/src/develop/pocScaffolder.js +0 -542
  44. package/dist/tests/e2e/developE2e.spec.js +0 -126
  45. package/dist/tests/e2e/developFailureE2e.spec.js +0 -247
  46. package/dist/tests/e2e/developPty.spec.js +0 -75
  47. package/dist/tests/e2e/discoveryWebSearchRelevance.spec.js +0 -84
  48. package/dist/tests/e2e/harness.spec.js +0 -83
  49. package/dist/tests/e2e/mcpLive.spec.js +0 -120
  50. package/dist/tests/e2e/newSession.e2e.spec.js +0 -177
  51. package/dist/tests/e2e/ralphLoopEnrichmentComparison.spec.js +0 -62
  52. package/dist/tests/e2e/workiqEnrichment.spec.js +0 -56
  53. package/dist/tests/e2e/zavaSimulation.spec.js +0 -452
  54. package/dist/tests/fixtures/test-fixture-project/src/add.js +0 -3
  55. package/dist/tests/fixtures/test-fixture-project/tests/failing.test.js +0 -6
  56. package/dist/tests/fixtures/test-fixture-project/tests/hanging.test.js +0 -8
  57. package/dist/tests/fixtures/test-fixture-project/tests/passing.test.js +0 -10
  58. package/dist/tests/fixtures/test-fixture-project/vitest.config.js +0 -6
  59. package/dist/tests/integration/autoStartConversation.spec.js +0 -138
  60. package/dist/tests/integration/defaultCommand.spec.js +0 -147
  61. package/dist/tests/integration/directCommandNonTty.spec.js +0 -224
  62. package/dist/tests/integration/directCommandTty.spec.js +0 -151
  63. package/dist/tests/integration/discoveryEnrichmentFlow.spec.js +0 -175
  64. package/dist/tests/integration/exportArtifacts.spec.js +0 -202
  65. package/dist/tests/integration/exportFallbackFlow.spec.js +0 -99
  66. package/dist/tests/integration/mcpDegradationFlow.spec.js +0 -190
  67. package/dist/tests/integration/mcpTransportFlow.spec.js +0 -139
  68. package/dist/tests/integration/newSessionFlow.spec.js +0 -343
  69. package/dist/tests/integration/pocGithubMcp.spec.js +0 -186
  70. package/dist/tests/integration/pocLocalFallback.spec.js +0 -171
  71. package/dist/tests/integration/pocScaffold.spec.js +0 -163
  72. package/dist/tests/integration/ralphLoopFlow.spec.js +0 -359
  73. package/dist/tests/integration/ralphLoopPartial.spec.js +0 -368
  74. package/dist/tests/integration/resumeAndBacktrack.spec.js +0 -247
  75. package/dist/tests/integration/spinnerLifecycle.spec.js +0 -220
  76. package/dist/tests/integration/summarizationFlow.spec.js +0 -115
  77. package/dist/tests/integration/testRunnerReal.spec.js +0 -52
  78. package/dist/tests/integration/webSearchAgent.spec.js +0 -128
  79. package/dist/tests/live/copilotSdkLive.spec.js +0 -107
  80. package/dist/tests/live/zavaFullWorkshop.spec.js +0 -392
  81. package/dist/tests/setup/loadEnv.js +0 -3
  82. package/dist/tests/unit/cli/developCommand.spec.js +0 -567
  83. package/dist/tests/unit/cli/directCommands.spec.js +0 -279
  84. package/dist/tests/unit/cli/envLoader.spec.js +0 -58
  85. package/dist/tests/unit/cli/ioContext.spec.js +0 -119
  86. package/dist/tests/unit/cli/preflight.spec.js +0 -108
  87. package/dist/tests/unit/cli/statusCommand.spec.js +0 -111
  88. package/dist/tests/unit/cli/workshopClientFallback.spec.js +0 -80
  89. package/dist/tests/unit/cli/workshopCommand.spec.js +0 -329
  90. package/dist/tests/unit/config/vitestEnvSetup.spec.js +0 -13
  91. package/dist/tests/unit/develop/checkpointState.spec.js +0 -315
  92. package/dist/tests/unit/develop/codeGenerator.spec.js +0 -355
  93. package/dist/tests/unit/develop/githubMcpAdapter.spec.js +0 -231
  94. package/dist/tests/unit/develop/mcpContextEnricher.spec.js +0 -433
  95. package/dist/tests/unit/develop/outputValidator.spec.js +0 -119
  96. package/dist/tests/unit/develop/pocScaffolder.spec.js +0 -353
  97. package/dist/tests/unit/develop/ralphLoop.spec.js +0 -1248
  98. package/dist/tests/unit/develop/templateRegistry.spec.js +0 -85
  99. package/dist/tests/unit/develop/testRunner.spec.js +0 -249
  100. package/dist/tests/unit/infraBicep.spec.js +0 -92
  101. package/dist/tests/unit/infraDeploy.spec.js +0 -82
  102. package/dist/tests/unit/infraTeardown.spec.js +0 -63
  103. package/dist/tests/unit/logging/logger.spec.js +0 -43
  104. package/dist/tests/unit/loop/conversationLoop.spec.js +0 -592
  105. package/dist/tests/unit/loop/phaseSummarizer.spec.js +0 -141
  106. package/dist/tests/unit/loop/streamingMarkdown.spec.js +0 -147
  107. package/dist/tests/unit/mcp/mcpManager.spec.js +0 -279
  108. package/dist/tests/unit/mcp/mcpTransport.spec.js +0 -529
  109. package/dist/tests/unit/mcp/retryPolicy.spec.js +0 -218
  110. package/dist/tests/unit/mcp/timeoutValidation.spec.js +0 -46
  111. package/dist/tests/unit/mcp/webSearch.spec.js +0 -567
  112. package/dist/tests/unit/phases/contextSummarizer.spec.js +0 -140
  113. package/dist/tests/unit/phases/discoveryEnricher.repeatCalls.spec.js +0 -93
  114. package/dist/tests/unit/phases/discoveryEnricher.spec.js +0 -411
  115. package/dist/tests/unit/phases/phaseExtractors.spec.js +0 -352
  116. package/dist/tests/unit/phases/phaseHandlers.spec.js +0 -425
  117. package/dist/tests/unit/prompts/promptLoader.spec.js +0 -118
  118. package/dist/tests/unit/schemas/pocSchemas.spec.js +0 -412
  119. package/dist/tests/unit/schemas/session.spec.js +0 -257
  120. package/dist/tests/unit/sessions/exportPaths.spec.js +0 -31
  121. package/dist/tests/unit/sessions/exportWriter.spec.js +0 -655
  122. package/dist/tests/unit/sessions/sessionManager.spec.js +0 -151
  123. package/dist/tests/unit/sessions/sessionStore.spec.js +0 -116
  124. package/dist/tests/unit/shared/activitySpinner.spec.js +0 -175
  125. package/dist/tests/unit/shared/cardsLoader.spec.js +0 -76
  126. package/dist/tests/unit/shared/copilotClient.spec.js +0 -155
  127. package/dist/tests/unit/shared/errorClassifier.spec.js +0 -131
  128. package/dist/tests/unit/shared/events.spec.js +0 -55
  129. package/dist/tests/unit/shared/markdownRenderer.spec.js +0 -35
  130. package/dist/tests/unit/shared/markdownRendererChunks.spec.js +0 -70
  131. package/dist/tests/unit/shared/tableRenderer.spec.js +0 -34
  132. package/dist/vitest.config.js +0 -14
  133. package/dist/vitest.live.config.js +0 -18
  134. package/src/develop/pocScaffolder.ts +0 -646
  135. package/tests/integration/pocScaffold.spec.ts +0 -220
  136. package/tests/unit/develop/pocScaffolder.spec.ts +0 -451
@@ -1,218 +0,0 @@
1
- /**
2
- * T006: Unit tests for retryPolicy.
3
- *
4
- * Verifies:
5
- * - withRetry retries once on connection-refused
6
- * - withRetry retries once on timeout
7
- * - withRetry does NOT retry on auth-failure
8
- * - withRetry does NOT retry on unknown error
9
- * - Applies ±20% jitter to initial delay
10
- * - Logs warn on retry attempt
11
- */
12
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
13
- import { withRetry, isRetryable, classifyMcpError } from '../../../src/mcp/retryPolicy.js';
14
- // ── Helpers ──────────────────────────────────────────────────────────────────
15
- function makeLogger() {
16
- return {
17
- info: vi.fn(),
18
- warn: vi.fn(),
19
- error: vi.fn(),
20
- debug: vi.fn(),
21
- trace: vi.fn(),
22
- fatal: vi.fn(),
23
- child: vi.fn().mockReturnThis(),
24
- level: 'silent',
25
- };
26
- }
27
- function makeConnRefusedError() {
28
- const err = new Error('connect ECONNREFUSED 127.0.0.1:3000');
29
- err.code = 'ECONNREFUSED';
30
- return err;
31
- }
32
- function makeTimeoutError() {
33
- const err = new Error('connect ETIMEDOUT');
34
- err.code = 'ETIMEDOUT';
35
- return err;
36
- }
37
- function makeDnsError() {
38
- const err = new Error('getaddrinfo ENOTFOUND example.com');
39
- err.code = 'ENOTFOUND';
40
- return err;
41
- }
42
- function makeAuthError() {
43
- const err = new Error('401 Unauthorized');
44
- err.code = 'ERR_TLS_CERT_ALTNAME_INVALID';
45
- return err;
46
- }
47
- // ── Tests ────────────────────────────────────────────────────────────────────
48
- describe('withRetry()', () => {
49
- beforeEach(() => {
50
- vi.useFakeTimers();
51
- });
52
- afterEach(() => {
53
- vi.useRealTimers();
54
- });
55
- it('returns result when fn succeeds on first try', async () => {
56
- const fn = vi.fn().mockResolvedValue('success');
57
- const result = await withRetry(fn, {
58
- serverName: 'test',
59
- toolName: 'tool',
60
- });
61
- expect(result).toBe('success');
62
- expect(fn).toHaveBeenCalledTimes(1);
63
- });
64
- it('retries once on connection-refused and succeeds', async () => {
65
- const fn = vi
66
- .fn()
67
- .mockRejectedValueOnce(makeConnRefusedError())
68
- .mockResolvedValueOnce('recovered');
69
- const logger = makeLogger();
70
- const resultPromise = withRetry(fn, {
71
- serverName: 'ctx7',
72
- toolName: 'resolve',
73
- initialDelayMs: 100,
74
- logger,
75
- });
76
- // Advance past the delay
77
- await vi.advanceTimersByTimeAsync(200);
78
- const result = await resultPromise;
79
- expect(result).toBe('recovered');
80
- expect(fn).toHaveBeenCalledTimes(2);
81
- });
82
- it('retries once on timeout and succeeds', async () => {
83
- const fn = vi.fn().mockRejectedValueOnce(makeTimeoutError()).mockResolvedValueOnce('ok');
84
- const resultPromise = withRetry(fn, {
85
- serverName: 'github',
86
- toolName: 'create_repo',
87
- initialDelayMs: 100,
88
- });
89
- await vi.advanceTimersByTimeAsync(200);
90
- const result = await resultPromise;
91
- expect(result).toBe('ok');
92
- expect(fn).toHaveBeenCalledTimes(2);
93
- });
94
- it('retries once on dns-failure and succeeds', async () => {
95
- const fn = vi.fn().mockRejectedValueOnce(makeDnsError()).mockResolvedValueOnce('resolved');
96
- const resultPromise = withRetry(fn, {
97
- serverName: 'remote',
98
- toolName: 'call',
99
- initialDelayMs: 100,
100
- });
101
- await vi.advanceTimersByTimeAsync(200);
102
- const result = await resultPromise;
103
- expect(result).toBe('resolved');
104
- expect(fn).toHaveBeenCalledTimes(2);
105
- });
106
- it('does NOT retry on auth-failure — throws immediately', async () => {
107
- const fn = vi.fn().mockRejectedValue(makeAuthError());
108
- await expect(withRetry(fn, {
109
- serverName: 'github',
110
- toolName: 'create_repo',
111
- initialDelayMs: 100,
112
- })).rejects.toThrow('401 Unauthorized');
113
- expect(fn).toHaveBeenCalledTimes(1);
114
- });
115
- it('does NOT retry on unknown error — throws immediately', async () => {
116
- const fn = vi.fn().mockRejectedValue(new Error('something unexpected'));
117
- await expect(withRetry(fn, {
118
- serverName: 'test',
119
- toolName: 'tool',
120
- initialDelayMs: 100,
121
- })).rejects.toThrow('something unexpected');
122
- expect(fn).toHaveBeenCalledTimes(1);
123
- });
124
- it('throws the second error when retry also fails', async () => {
125
- const fn = vi
126
- .fn()
127
- .mockRejectedValueOnce(makeConnRefusedError())
128
- .mockRejectedValueOnce(new Error('second failure'));
129
- // Attach the rejection handler immediately to avoid unhandled rejection warning
130
- const resultPromise = withRetry(fn, {
131
- serverName: 'test',
132
- toolName: 'tool',
133
- initialDelayMs: 100,
134
- }).catch((err) => err);
135
- await vi.advanceTimersByTimeAsync(200);
136
- const err = await resultPromise;
137
- expect(err).toBeInstanceOf(Error);
138
- expect(err.message).toBe('second failure');
139
- expect(fn).toHaveBeenCalledTimes(2);
140
- });
141
- it('logs warn on retry attempt with server, tool, attempt, delayMs, errorClass', async () => {
142
- const fn = vi.fn().mockRejectedValueOnce(makeConnRefusedError()).mockResolvedValueOnce('ok');
143
- const logger = makeLogger();
144
- const resultPromise = withRetry(fn, {
145
- serverName: 'context7',
146
- toolName: 'resolve-library-id',
147
- initialDelayMs: 1000,
148
- logger,
149
- });
150
- await vi.advanceTimersByTimeAsync(1500);
151
- await resultPromise;
152
- expect(logger.warn).toHaveBeenCalledTimes(1);
153
- const warnCall = logger.warn.mock.calls[0];
154
- const logObj = warnCall[0];
155
- expect(logObj).toHaveProperty('server', 'context7');
156
- expect(logObj).toHaveProperty('tool', 'resolve-library-id');
157
- expect(logObj).toHaveProperty('attempt', 1);
158
- expect(logObj).toHaveProperty('delayMs');
159
- expect(logObj).toHaveProperty('errorClass', 'connection-refused');
160
- });
161
- it('applies ±20% jitter to delay', async () => {
162
- // We'll override Math.random to test jitter boundaries
163
- const originalRandom = Math.random;
164
- // First test: random = 0 → jitter factor = 1 + (0*2-1)*0.2 = 0.8
165
- Math.random = () => 0;
166
- const fn1 = vi.fn().mockRejectedValueOnce(makeConnRefusedError()).mockResolvedValueOnce('ok');
167
- const logger1 = makeLogger();
168
- const p1 = withRetry(fn1, {
169
- serverName: 'test',
170
- toolName: 'tool',
171
- initialDelayMs: 1000,
172
- jitter: 0.2,
173
- logger: logger1,
174
- });
175
- await vi.advanceTimersByTimeAsync(1500);
176
- await p1;
177
- const delay1 = logger1.warn.mock.calls[0][0].delayMs;
178
- expect(delay1).toBe(800); // 1000 * 0.8
179
- // Second test: random = 1 → jitter factor = 1 + (1*2-1)*0.2 = 1.2
180
- Math.random = () => 1;
181
- const fn2 = vi.fn().mockRejectedValueOnce(makeConnRefusedError()).mockResolvedValueOnce('ok');
182
- const logger2 = makeLogger();
183
- const p2 = withRetry(fn2, {
184
- serverName: 'test',
185
- toolName: 'tool',
186
- initialDelayMs: 1000,
187
- jitter: 0.2,
188
- logger: logger2,
189
- });
190
- await vi.advanceTimersByTimeAsync(1500);
191
- await p2;
192
- const delay2 = logger2.warn.mock.calls[0][0].delayMs;
193
- expect(delay2).toBe(1200); // 1000 * 1.2
194
- Math.random = originalRandom;
195
- });
196
- });
197
- describe('isRetryable()', () => {
198
- it('returns true for connection-refused', () => {
199
- expect(isRetryable(makeConnRefusedError())).toBe(true);
200
- });
201
- it('returns true for timeout', () => {
202
- expect(isRetryable(makeTimeoutError())).toBe(true);
203
- });
204
- it('returns true for dns-failure', () => {
205
- expect(isRetryable(makeDnsError())).toBe(true);
206
- });
207
- it('returns false for auth-failure', () => {
208
- expect(isRetryable(makeAuthError())).toBe(false);
209
- });
210
- it('returns false for unknown error', () => {
211
- expect(isRetryable(new Error('random'))).toBe(false);
212
- });
213
- });
214
- describe('classifyMcpError (re-export)', () => {
215
- it('classifies ECONNREFUSED as connection-refused', () => {
216
- expect(classifyMcpError(makeConnRefusedError())).toBe('connection-refused');
217
- });
218
- });
@@ -1,46 +0,0 @@
1
- /**
2
- * T044: Timeout validation test for SC-003-007.
3
- *
4
- * Forces a short timeoutMs on MCP calls and asserts that a classified
5
- * 'timeout' error is returned/thrown and handled gracefully by adapters.
6
- */
7
- import { describe, it, expect, vi } from 'vitest';
8
- import { classifyMcpError } from '../../../src/mcp/mcpManager.js';
9
- describe('Timeout validation (T044)', () => {
10
- it('classifyMcpError identifies AbortError as timeout', () => {
11
- const error = new DOMException('The operation was aborted', 'AbortError');
12
- const classification = classifyMcpError(error);
13
- expect(classification).toBe('timeout');
14
- });
15
- it('classifyMcpError identifies timeout message strings', () => {
16
- const error = new Error('Request timed out after 30000ms');
17
- const classification = classifyMcpError(error);
18
- expect(classification).toBe('timeout');
19
- });
20
- it('classifyMcpError identifies ETIMEDOUT errno as timeout', () => {
21
- const error = Object.assign(new Error('connect ETIMEDOUT'), { code: 'ETIMEDOUT' });
22
- const classification = classifyMcpError(error);
23
- expect(classification).toBe('timeout');
24
- });
25
- it('adapters handle timeout errors gracefully without crashing', async () => {
26
- const { GitHubMcpAdapter } = await import('../../../src/develop/githubMcpAdapter.js');
27
- const timeoutMcpManager = {
28
- isAvailable: vi.fn().mockReturnValue(true),
29
- callTool: vi
30
- .fn()
31
- .mockRejectedValue(new DOMException('The operation was aborted', 'AbortError')),
32
- markConnected: vi.fn(),
33
- markDisconnected: vi.fn(),
34
- disconnectAll: vi.fn(),
35
- };
36
- const adapter = new GitHubMcpAdapter(timeoutMcpManager);
37
- // createRepository should degrade gracefully
38
- const repoResult = await adapter.createRepository({
39
- name: 'test-repo',
40
- description: 'test',
41
- private: true,
42
- });
43
- // Should return a degraded result, not throw
44
- expect(repoResult).toBeDefined();
45
- });
46
- });