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.
- package/README.md +42 -20
- package/dist/infra/deploy.sh +193 -0
- package/dist/infra/gather-env.sh +211 -0
- package/dist/infra/infra/deploy.sh +193 -0
- package/dist/infra/infra/gather-env.sh +211 -0
- package/dist/infra/infra/main.bicep +90 -0
- package/dist/infra/infra/main.bicepparam +18 -0
- package/dist/infra/infra/resources.bicep +134 -0
- package/dist/infra/infra/teardown.sh +114 -0
- package/dist/infra/main.bicep +90 -0
- package/dist/infra/main.bicepparam +18 -0
- package/dist/infra/resources.bicep +134 -0
- package/dist/infra/teardown.sh +114 -0
- package/dist/src/cli/developCommand.js +0 -2
- package/dist/src/cli/index.js +8 -1
- package/dist/src/cli/workshopCommand.js +1 -1
- package/dist/src/develop/index.js +1 -1
- package/dist/src/develop/pocUtils.js +228 -0
- package/dist/src/develop/ralphLoop.js +3 -3
- package/dist/src/shared/data/cards.json +655 -670
- package/docs/architecture.md +2 -1
- package/package.json +5 -3
- package/src/cli/developCommand.ts +1 -3
- package/src/cli/index.ts +11 -1
- package/src/cli/workshopCommand.ts +21 -17
- package/src/develop/dynamicScaffolder.ts +36 -30
- package/src/develop/index.ts +13 -2
- package/src/develop/pocUtils.ts +296 -0
- package/src/develop/ralphLoop.ts +8 -28
- package/src/develop/templateRegistry.ts +19 -18
- package/src/shared/data/cards.json +655 -670
- package/tests/e2e/developE2e.spec.ts +3 -61
- package/tests/e2e/developFailureE2e.spec.ts +34 -38
- package/tests/integration/pocGithubMcp.spec.ts +29 -39
- package/tests/integration/pocLocalFallback.spec.ts +29 -39
- package/tests/integration/ralphLoopFlow.spec.ts +46 -66
- package/tests/integration/ralphLoopPartial.spec.ts +30 -37
- package/tests/unit/develop/githubMcpAdapter.spec.ts +0 -134
- package/tests/unit/develop/outputValidator.spec.ts +45 -21
- package/tests/unit/develop/ralphLoop.spec.ts +58 -94
- package/tsconfig.json +2 -1
- package/vitest.workspace.ts +5 -0
- package/dist/src/develop/pocScaffolder.js +0 -542
- package/dist/tests/e2e/developE2e.spec.js +0 -126
- package/dist/tests/e2e/developFailureE2e.spec.js +0 -247
- package/dist/tests/e2e/developPty.spec.js +0 -75
- package/dist/tests/e2e/discoveryWebSearchRelevance.spec.js +0 -84
- package/dist/tests/e2e/harness.spec.js +0 -83
- package/dist/tests/e2e/mcpLive.spec.js +0 -120
- package/dist/tests/e2e/newSession.e2e.spec.js +0 -177
- package/dist/tests/e2e/ralphLoopEnrichmentComparison.spec.js +0 -62
- package/dist/tests/e2e/workiqEnrichment.spec.js +0 -56
- package/dist/tests/e2e/zavaSimulation.spec.js +0 -452
- package/dist/tests/fixtures/test-fixture-project/src/add.js +0 -3
- package/dist/tests/fixtures/test-fixture-project/tests/failing.test.js +0 -6
- package/dist/tests/fixtures/test-fixture-project/tests/hanging.test.js +0 -8
- package/dist/tests/fixtures/test-fixture-project/tests/passing.test.js +0 -10
- package/dist/tests/fixtures/test-fixture-project/vitest.config.js +0 -6
- package/dist/tests/integration/autoStartConversation.spec.js +0 -138
- package/dist/tests/integration/defaultCommand.spec.js +0 -147
- package/dist/tests/integration/directCommandNonTty.spec.js +0 -224
- package/dist/tests/integration/directCommandTty.spec.js +0 -151
- package/dist/tests/integration/discoveryEnrichmentFlow.spec.js +0 -175
- package/dist/tests/integration/exportArtifacts.spec.js +0 -202
- package/dist/tests/integration/exportFallbackFlow.spec.js +0 -99
- package/dist/tests/integration/mcpDegradationFlow.spec.js +0 -190
- package/dist/tests/integration/mcpTransportFlow.spec.js +0 -139
- package/dist/tests/integration/newSessionFlow.spec.js +0 -343
- package/dist/tests/integration/pocGithubMcp.spec.js +0 -186
- package/dist/tests/integration/pocLocalFallback.spec.js +0 -171
- package/dist/tests/integration/pocScaffold.spec.js +0 -163
- package/dist/tests/integration/ralphLoopFlow.spec.js +0 -359
- package/dist/tests/integration/ralphLoopPartial.spec.js +0 -368
- package/dist/tests/integration/resumeAndBacktrack.spec.js +0 -247
- package/dist/tests/integration/spinnerLifecycle.spec.js +0 -220
- package/dist/tests/integration/summarizationFlow.spec.js +0 -115
- package/dist/tests/integration/testRunnerReal.spec.js +0 -52
- package/dist/tests/integration/webSearchAgent.spec.js +0 -128
- package/dist/tests/live/copilotSdkLive.spec.js +0 -107
- package/dist/tests/live/zavaFullWorkshop.spec.js +0 -392
- package/dist/tests/setup/loadEnv.js +0 -3
- package/dist/tests/unit/cli/developCommand.spec.js +0 -567
- package/dist/tests/unit/cli/directCommands.spec.js +0 -279
- package/dist/tests/unit/cli/envLoader.spec.js +0 -58
- package/dist/tests/unit/cli/ioContext.spec.js +0 -119
- package/dist/tests/unit/cli/preflight.spec.js +0 -108
- package/dist/tests/unit/cli/statusCommand.spec.js +0 -111
- package/dist/tests/unit/cli/workshopClientFallback.spec.js +0 -80
- package/dist/tests/unit/cli/workshopCommand.spec.js +0 -329
- package/dist/tests/unit/config/vitestEnvSetup.spec.js +0 -13
- package/dist/tests/unit/develop/checkpointState.spec.js +0 -315
- package/dist/tests/unit/develop/codeGenerator.spec.js +0 -355
- package/dist/tests/unit/develop/githubMcpAdapter.spec.js +0 -231
- package/dist/tests/unit/develop/mcpContextEnricher.spec.js +0 -433
- package/dist/tests/unit/develop/outputValidator.spec.js +0 -119
- package/dist/tests/unit/develop/pocScaffolder.spec.js +0 -353
- package/dist/tests/unit/develop/ralphLoop.spec.js +0 -1248
- package/dist/tests/unit/develop/templateRegistry.spec.js +0 -85
- package/dist/tests/unit/develop/testRunner.spec.js +0 -249
- package/dist/tests/unit/infraBicep.spec.js +0 -92
- package/dist/tests/unit/infraDeploy.spec.js +0 -82
- package/dist/tests/unit/infraTeardown.spec.js +0 -63
- package/dist/tests/unit/logging/logger.spec.js +0 -43
- package/dist/tests/unit/loop/conversationLoop.spec.js +0 -592
- package/dist/tests/unit/loop/phaseSummarizer.spec.js +0 -141
- package/dist/tests/unit/loop/streamingMarkdown.spec.js +0 -147
- package/dist/tests/unit/mcp/mcpManager.spec.js +0 -279
- package/dist/tests/unit/mcp/mcpTransport.spec.js +0 -529
- package/dist/tests/unit/mcp/retryPolicy.spec.js +0 -218
- package/dist/tests/unit/mcp/timeoutValidation.spec.js +0 -46
- package/dist/tests/unit/mcp/webSearch.spec.js +0 -567
- package/dist/tests/unit/phases/contextSummarizer.spec.js +0 -140
- package/dist/tests/unit/phases/discoveryEnricher.repeatCalls.spec.js +0 -93
- package/dist/tests/unit/phases/discoveryEnricher.spec.js +0 -411
- package/dist/tests/unit/phases/phaseExtractors.spec.js +0 -352
- package/dist/tests/unit/phases/phaseHandlers.spec.js +0 -425
- package/dist/tests/unit/prompts/promptLoader.spec.js +0 -118
- package/dist/tests/unit/schemas/pocSchemas.spec.js +0 -412
- package/dist/tests/unit/schemas/session.spec.js +0 -257
- package/dist/tests/unit/sessions/exportPaths.spec.js +0 -31
- package/dist/tests/unit/sessions/exportWriter.spec.js +0 -655
- package/dist/tests/unit/sessions/sessionManager.spec.js +0 -151
- package/dist/tests/unit/sessions/sessionStore.spec.js +0 -116
- package/dist/tests/unit/shared/activitySpinner.spec.js +0 -175
- package/dist/tests/unit/shared/cardsLoader.spec.js +0 -76
- package/dist/tests/unit/shared/copilotClient.spec.js +0 -155
- package/dist/tests/unit/shared/errorClassifier.spec.js +0 -131
- package/dist/tests/unit/shared/events.spec.js +0 -55
- package/dist/tests/unit/shared/markdownRenderer.spec.js +0 -35
- package/dist/tests/unit/shared/markdownRendererChunks.spec.js +0 -70
- package/dist/tests/unit/shared/tableRenderer.spec.js +0 -34
- package/dist/vitest.config.js +0 -14
- package/dist/vitest.live.config.js +0 -18
- package/src/develop/pocScaffolder.ts +0 -646
- package/tests/integration/pocScaffold.spec.ts +0 -220
- 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
|
-
});
|