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,177 +0,0 @@
1
- /**
2
- * E2E test: New Session Flow — PTY-based (T021)
3
- *
4
- * Uses node-pty to drive the sofIA CLI interactively, simulating
5
- * user input and verifying streaming output for the New Session flow.
6
- *
7
- * Validates:
8
- * - Main menu is rendered in an interactive (TTY) terminal
9
- * - "Start a new workshop session" option is shown and selectable
10
- * - Selecting option 1 creates a new session and starts Discover phase
11
- * - Interactive prompts are displayed during the Discover phase
12
- * - Ctrl+C (SIGINT) cleanly exits the process
13
- * - Non-interactive mode with `--non-interactive` flag handles missing
14
- * Copilot credentials gracefully
15
- */
16
- import { describe, it, expect } from 'vitest';
17
- import * as pty from 'node-pty';
18
- import { join, dirname } from 'node:path';
19
- import { fileURLToPath } from 'node:url';
20
- import { spawn } from 'node:child_process';
21
- const __dirname = dirname(fileURLToPath(import.meta.url));
22
- const PROJECT_ROOT = join(__dirname, '..', '..');
23
- const CLI_ENTRY = join(PROJECT_ROOT, 'src', 'cli', 'index.ts');
24
- // ── Timing constants ─────────────────────────────────────────────────────────
25
- /** Time to wait for the interactive menu to render after TSX startup. */
26
- const MENU_RENDER_DELAY = 2_000;
27
- /** Time to wait after pressing a key before sending the next keystroke. */
28
- const INPUT_SUBMIT_DELAY = 200;
29
- /** Time to allow a phase initialisation attempt before aborting via Ctrl+C. */
30
- const PHASE_INIT_DELAY = 3_000;
31
- /** Extra delay used when waiting for the menu with a generous buffer. */
32
- const MENU_RENDER_DELAY_GENEROUS = 4_000;
33
- /**
34
- * Run the sofIA CLI in a PTY session, sending inputs with delays and
35
- * collecting all output until the process exits or times out.
36
- */
37
- function runCliPty(args, inputs = [], timeoutMs = 20_000) {
38
- return new Promise((resolve) => {
39
- const term = pty.spawn('npx', ['tsx', CLI_ENTRY, ...args], {
40
- name: 'xterm-color',
41
- cols: 120,
42
- rows: 30,
43
- cwd: PROJECT_ROOT,
44
- env: { ...process.env, NODE_ENV: 'test', FORCE_COLOR: '0' },
45
- });
46
- let output = '';
47
- term.onData((data) => { output += data; });
48
- let inputIdx = 0;
49
- function sendNextInput() {
50
- if (inputIdx >= inputs.length)
51
- return;
52
- const { text, delayMs } = inputs[inputIdx++];
53
- setTimeout(() => {
54
- term.write(text);
55
- sendNextInput();
56
- }, delayMs);
57
- }
58
- sendNextInput();
59
- const timer = setTimeout(() => {
60
- term.kill();
61
- resolve({ output, exitCode: -1 });
62
- }, timeoutMs);
63
- term.onExit(({ exitCode }) => {
64
- clearTimeout(timer);
65
- resolve({ output, exitCode });
66
- });
67
- });
68
- }
69
- /**
70
- * Run the sofIA CLI without PTY (non-interactive), suitable for flag-only
71
- * tests that do not require an interactive terminal.
72
- */
73
- function runCli(args, timeoutMs = 15_000) {
74
- return new Promise((resolve, reject) => {
75
- const child = spawn('npx', ['tsx', CLI_ENTRY, ...args], {
76
- cwd: PROJECT_ROOT,
77
- env: { ...process.env, NODE_ENV: 'test' },
78
- stdio: ['pipe', 'pipe', 'pipe'],
79
- });
80
- const stdout = [];
81
- const stderr = [];
82
- child.stdout.on('data', (chunk) => stdout.push(chunk));
83
- child.stderr.on('data', (chunk) => stderr.push(chunk));
84
- const timer = setTimeout(() => {
85
- child.kill('SIGTERM');
86
- reject(new Error(`CLI timed out after ${timeoutMs}ms`));
87
- }, timeoutMs);
88
- child.on('close', (code) => {
89
- clearTimeout(timer);
90
- resolve({
91
- stdout: Buffer.concat(stdout).toString('utf-8'),
92
- stderr: Buffer.concat(stderr).toString('utf-8'),
93
- exitCode: code,
94
- });
95
- });
96
- child.on('error', (err) => {
97
- clearTimeout(timer);
98
- reject(err);
99
- });
100
- });
101
- }
102
- // ── Tests ────────────────────────────────────────────────────────────────────
103
- describe('New Session E2E (PTY)', () => {
104
- it('renders the main menu with PTY when invoked interactively', async () => {
105
- // Select "3. Exit" immediately to avoid waiting for Copilot API
106
- const result = await runCliPty(['workshop'], [
107
- { text: '3', delayMs: MENU_RENDER_DELAY }, // wait for menu, then select Exit
108
- { text: '\r', delayMs: INPUT_SUBMIT_DELAY },
109
- ], 15_000);
110
- // Menu should render with sofIA branding and option 1
111
- expect(result.output).toMatch(/sofIA/i);
112
- expect(result.output).toMatch(/Start a new workshop session|1\./);
113
- }, 30_000);
114
- it('shows Exit option in the main menu', async () => {
115
- const result = await runCliPty(['workshop'], [
116
- { text: '3', delayMs: MENU_RENDER_DELAY },
117
- { text: '\r', delayMs: INPUT_SUBMIT_DELAY },
118
- ], 15_000);
119
- expect(result.output).toMatch(/Exit|3\./);
120
- }, 20_000);
121
- it('renders Goodbye message when user selects Exit from the menu', async () => {
122
- const result = await runCliPty(['workshop'], [
123
- { text: '3', delayMs: MENU_RENDER_DELAY_GENEROUS }, // wait for tsx startup + menu render
124
- { text: '\r', delayMs: INPUT_SUBMIT_DELAY },
125
- ], 20_000);
126
- // Either "Goodbye!" was emitted (process exited cleanly) or we can verify
127
- // the menu option "3" was rendered (confirming Exit is a valid choice).
128
- // Both outcomes confirm the menu interaction works end-to-end.
129
- const cleanExit = result.output.includes('Goodbye') || result.exitCode === 0;
130
- const menuRendered = /Exit|3\./i.test(result.output);
131
- expect(cleanExit || menuRendered).toBe(true);
132
- }, 25_000);
133
- it('exits cleanly on Ctrl+C from the main menu', async () => {
134
- const result = await runCliPty(['workshop'], [
135
- { text: '\x03', delayMs: MENU_RENDER_DELAY }, // Ctrl+C after menu renders
136
- ], 10_000);
137
- // Process should exit (any non-timeout exit code is acceptable)
138
- expect(result.exitCode).not.toBe(-1);
139
- }, 15_000);
140
- it('shows streaming output when option 1 is selected (until Copilot error or input prompt)', async () => {
141
- // Select "1" (New Session) — may fail at Copilot init but should show something
142
- const result = await runCliPty(['workshop'], [
143
- { text: '1', delayMs: MENU_RENDER_DELAY }, // select New Session
144
- { text: '\r', delayMs: INPUT_SUBMIT_DELAY },
145
- { text: '\x03', delayMs: PHASE_INIT_DELAY }, // Ctrl+C to abort
146
- ], 15_000);
147
- // Either a new session was created (shows session ID) or an error about
148
- // Copilot initialization was shown — either way the process handled option 1
149
- const gotSessionOrError = /session|error|copilot|discover/i.test(result.output);
150
- expect(gotSessionOrError).toBe(true);
151
- }, 20_000);
152
- it('--help flag works in a PTY context (streaming output check)', async () => {
153
- const result = await runCliPty(['--help'], [], 10_000);
154
- expect(result.output).toContain('sofIA');
155
- expect(result.output).toContain('workshop');
156
- expect(result.exitCode).toBe(0);
157
- }, 15_000);
158
- it('--version flag works in a PTY context', async () => {
159
- const result = await runCliPty(['--version'], [], 10_000);
160
- expect(result.output.trim()).toMatch(/\d+\.\d+\.\d+/);
161
- expect(result.exitCode).toBe(0);
162
- }, 15_000);
163
- it('status --json works in non-interactive mode (non-PTY verification)', async () => {
164
- const result = await runCli(['status', '--json'], 15_000);
165
- const parsed = JSON.parse(result.stdout);
166
- expect(parsed).toBeDefined();
167
- expect('sessions' in parsed || 'error' in parsed).toBe(true);
168
- }, 20_000);
169
- it('non-interactive mode with --json flag provides structured output', async () => {
170
- // status --json in non-interactive mode should return structured JSON quickly
171
- const result = await runCli(['status', '--json', '--non-interactive'], 10_000);
172
- const parsed = JSON.parse(result.stdout);
173
- expect(parsed).toBeDefined();
174
- // Must have at least one of the expected top-level fields
175
- expect('sessions' in parsed || 'error' in parsed).toBe(true);
176
- }, 15_000);
177
- });
@@ -1,62 +0,0 @@
1
- /**
2
- * T040: Controlled Ralph Loop enrichment comparison (SC-003-004).
3
- *
4
- * Validates that MCP context enrichment measurably improves the LLM's
5
- * ability to fix failing tests by comparing iteration counts with and
6
- * without enrichment. Gated behind SOFIA_LIVE_MCP_TESTS=true because
7
- * it requires real LLM and MCP server access.
8
- *
9
- * Acceptance criteria:
10
- * - Run the same plan + failing tests twice: once without enrichment, once with
11
- * - Enriched run should complete in fewer or equal iterations
12
- * - Both runs must eventually reach tests-passing state
13
- *
14
- * NOTE: This test requires GITHUB_TOKEN, working MCP servers, and a
15
- * CopilotClient connected to a real LLM. It is a manual validation procedure.
16
- *
17
- * To run manually:
18
- * SOFIA_LIVE_MCP_TESTS=true GITHUB_TOKEN=<token> npx vitest run tests/e2e/ralphLoopEnrichmentComparison.spec.ts
19
- */
20
- import { describe, it, expect } from 'vitest';
21
- const LIVE = process.env.SOFIA_LIVE_MCP_TESTS === 'true';
22
- describe.skipIf(!LIVE)('Ralph Loop enrichment comparison (T040 / SC-003-004)', () => {
23
- it('enrichment-enabled run uses McpContextEnricher and produces MCP context', async () => {
24
- // This test validates the enrichment wiring in the Ralph Loop.
25
- // A full iteration-count comparison requires real LLM calls.
26
- //
27
- // Validation procedure (manual):
28
- // 1. Create a RalphLoop with client, session, and a simple plan
29
- // 2. Run without enricher → record iterationsCompleted
30
- // 3. Run WITH McpContextEnricher (Context7 + web search) → record iterationsCompleted
31
- // 4. Assert: enriched iterations <= unenriched iterations
32
- //
33
- // The mechanism is:
34
- // - RalphLoop checks for enricher in the iteration loop
35
- // - If present, enricher.enrich() is called with stuckIterations and failingTests
36
- // - The mcpContext string is injected into the LLM prompt
37
- // - This gives the LLM additional documentation/examples to fix failing tests
38
- //
39
- // Unit test coverage for this wiring exists in:
40
- // - tests/unit/develop/ralphLoop.spec.ts (enricher interaction)
41
- // - tests/unit/develop/mcpContextEnricher.spec.ts (enrich method)
42
- // - tests/integration/mcpDegradationFlow.spec.ts (graceful degradation)
43
- const { McpManager, loadMcpConfig } = await import('../../src/mcp/mcpManager.js');
44
- const { McpContextEnricher } = await import('../../src/develop/mcpContextEnricher.js');
45
- const config = await loadMcpConfig('.vscode/mcp.json');
46
- const mcpManager = new McpManager(config);
47
- const enricher = new McpContextEnricher(mcpManager);
48
- // Verify enricher can produce context (basic smoke test)
49
- const result = await enricher.enrich({
50
- mcpManager,
51
- dependencies: ['express', 'vitest'],
52
- architectureNotes: 'REST API with Express and TypeScript',
53
- stuckIterations: 2,
54
- failingTests: ['GET /api/items returns 200', 'POST /api/items creates item'],
55
- });
56
- console.log('=== T040 Enrichment Smoke ===');
57
- console.log(`Combined context length: ${result.combined.length} chars`);
58
- // The enricher should produce non-empty context given real MCP servers
59
- expect(result.combined.length).toBeGreaterThan(0);
60
- await mcpManager.disconnectAll();
61
- }, 60_000);
62
- });
@@ -1,56 +0,0 @@
1
- /**
2
- * T043: Live WorkIQ enrichment validation (SC-003-006).
3
- *
4
- * Validates that WorkIQ enrichment completes within 10 seconds and
5
- * persists workiqInsights in the enrichment result.
6
- * Gated behind SOFIA_LIVE_MCP_TESTS=true.
7
- *
8
- * Requires:
9
- * - WorkIQ MCP server accessible (Microsoft 365 tenant with admin consent)
10
- * - SOFIA_LIVE_MCP_TESTS=true
11
- */
12
- import { describe, it, expect } from 'vitest';
13
- const LIVE = process.env.SOFIA_LIVE_MCP_TESTS === 'true';
14
- describe.skipIf(!LIVE)('WorkIQ enrichment validation (T043 / SC-003-006)', () => {
15
- it('WorkIQ enrichment completes within 10s and returns insights', async () => {
16
- const { DiscoveryEnricher } = await import('../../src/phases/discoveryEnricher.js');
17
- const { McpManager, loadMcpConfig } = await import('../../src/mcp/mcpManager.js');
18
- const config = await loadMcpConfig('.vscode/mcp.json');
19
- const mcpManager = new McpManager(config);
20
- // Skip if WorkIQ is not configured
21
- if (!mcpManager.isAvailable('workiq')) {
22
- console.log('WorkIQ not available — skipping T043');
23
- return;
24
- }
25
- const enricher = new DiscoveryEnricher();
26
- const io = {
27
- write: () => { },
28
- writeActivity: () => { },
29
- readInput: async () => 'y', // Auto-consent for live test
30
- };
31
- const start = Date.now();
32
- const result = await enricher.enrich({
33
- companySummary: 'Contoso Corp is a technology company developing cloud-based enterprise solutions.',
34
- mcpManager,
35
- io: io,
36
- });
37
- const elapsed = Date.now() - start;
38
- const wi = result.workiqInsights;
39
- console.log('=== T043 WorkIQ Enrichment Validation ===');
40
- console.log(`Elapsed: ${elapsed}ms`);
41
- console.log(`Sources used: ${result.sourcesUsed?.join(', ') ?? 'none'}`);
42
- console.log(`Team expertise items: ${wi?.teamExpertise?.length ?? 0}`);
43
- console.log(`Collaboration patterns: ${wi?.collaborationPatterns?.length ?? 0}`);
44
- console.log(`Documentation gaps: ${wi?.documentationGaps?.length ?? 0}`);
45
- // Must complete within 10 seconds
46
- expect(elapsed).toBeLessThan(10_000);
47
- // Must include WorkIQ as a source
48
- expect(result.sourcesUsed).toContain('workiq');
49
- // Must have at least some insight data
50
- const hasInsights = (wi?.teamExpertise?.length ?? 0) > 0 ||
51
- (wi?.collaborationPatterns?.length ?? 0) > 0 ||
52
- (wi?.documentationGaps?.length ?? 0) > 0;
53
- expect(hasInsights).toBe(true);
54
- await mcpManager.disconnectAll();
55
- }, 30_000);
56
- });