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
|
@@ -9,19 +9,18 @@
|
|
|
9
9
|
* It validates the CLI plumbing, argument parsing, and file creation.
|
|
10
10
|
*/
|
|
11
11
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
12
|
-
import { mkdtemp, rm,
|
|
12
|
+
import { mkdtemp, rm, writeFile, mkdir } from 'node:fs/promises';
|
|
13
13
|
import { join } from 'node:path';
|
|
14
14
|
import { tmpdir } from 'node:os';
|
|
15
15
|
import { createRequire } from 'node:module';
|
|
16
16
|
|
|
17
17
|
import { buildCli } from '../../src/cli/index.js';
|
|
18
18
|
import { validateSessionForDevelop } from '../../src/cli/developCommand.js';
|
|
19
|
-
import { PocScaffolder } from '../../src/develop/pocScaffolder.js';
|
|
20
|
-
import { validatePocOutput } from '../../src/develop/pocScaffolder.js';
|
|
21
19
|
import type { WorkshopSession } from '../../src/shared/schemas/session.js';
|
|
22
20
|
|
|
23
21
|
const require = createRequire(import.meta.url);
|
|
24
|
-
const fixtureSession: WorkshopSession =
|
|
22
|
+
const fixtureSession: WorkshopSession =
|
|
23
|
+
require('../fixtures/completedSession.json') as WorkshopSession;
|
|
25
24
|
|
|
26
25
|
describe('E2E: sofia dev command', () => {
|
|
27
26
|
let workDir: string;
|
|
@@ -92,61 +91,4 @@ describe('E2E: sofia dev command', () => {
|
|
|
92
91
|
expect(fixtureSession.plan!.milestones.length).toBeGreaterThan(0);
|
|
93
92
|
});
|
|
94
93
|
});
|
|
95
|
-
|
|
96
|
-
describe('PocScaffolder with fixture session', () => {
|
|
97
|
-
let outputDir: string;
|
|
98
|
-
|
|
99
|
-
beforeEach(async () => {
|
|
100
|
-
outputDir = await mkdtemp(join(tmpdir(), 'sofia-e2e-poc-'));
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
afterEach(async () => {
|
|
104
|
-
await rm(outputDir, { recursive: true, force: true });
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('scaffolds valid PoC output from fixture session', async () => {
|
|
108
|
-
const scaffolder = new PocScaffolder();
|
|
109
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, outputDir);
|
|
110
|
-
await scaffolder.scaffold(ctx);
|
|
111
|
-
|
|
112
|
-
const validation = await validatePocOutput(outputDir);
|
|
113
|
-
expect(validation.valid).toBe(true);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('generated package.json has correct project name from fixture', async () => {
|
|
117
|
-
const scaffolder = new PocScaffolder();
|
|
118
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, outputDir);
|
|
119
|
-
await scaffolder.scaffold(ctx);
|
|
120
|
-
|
|
121
|
-
const pkgContent = await readFile(join(outputDir, 'package.json'), 'utf-8');
|
|
122
|
-
const pkg = JSON.parse(pkgContent) as { name: string };
|
|
123
|
-
expect(pkg.name).toBe('ai-powered-route-optimizer');
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('session JSON would be updated with poc state after loop', () => {
|
|
127
|
-
// Verify the shape of poc state that RalphLoop would produce
|
|
128
|
-
const expectedPocShape = {
|
|
129
|
-
repoSource: 'local',
|
|
130
|
-
iterations: expect.arrayContaining([
|
|
131
|
-
expect.objectContaining({
|
|
132
|
-
outcome: 'scaffold',
|
|
133
|
-
}),
|
|
134
|
-
]),
|
|
135
|
-
};
|
|
136
|
-
// This test verifies the schema is correct
|
|
137
|
-
const poc = {
|
|
138
|
-
repoSource: 'local' as const,
|
|
139
|
-
repoPath: outputDir,
|
|
140
|
-
iterations: [
|
|
141
|
-
{
|
|
142
|
-
iteration: 1,
|
|
143
|
-
startedAt: new Date().toISOString(),
|
|
144
|
-
outcome: 'scaffold' as const,
|
|
145
|
-
filesChanged: ['package.json', 'src/index.ts'],
|
|
146
|
-
},
|
|
147
|
-
],
|
|
148
|
-
};
|
|
149
|
-
expect(poc).toMatchObject(expectedPocShape);
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
94
|
});
|
|
@@ -12,7 +12,7 @@ import { tmpdir } from 'node:os';
|
|
|
12
12
|
import { createRequire } from 'node:module';
|
|
13
13
|
|
|
14
14
|
import { RalphLoop } from '../../src/develop/ralphLoop.js';
|
|
15
|
-
import {
|
|
15
|
+
import { generateDynamicScaffold } from '../../src/develop/dynamicScaffolder.js';
|
|
16
16
|
import { TestRunner } from '../../src/develop/testRunner.js';
|
|
17
17
|
import type { WorkshopSession } from '../../src/shared/schemas/session.js';
|
|
18
18
|
import type { LoopIO } from '../../src/loop/conversationLoop.js';
|
|
@@ -40,8 +40,14 @@ vi.mock('node:child_process', async (importOriginal) => {
|
|
|
40
40
|
};
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
// Mock generateDynamicScaffold
|
|
44
|
+
vi.mock('../../src/develop/dynamicScaffolder.js', () => ({
|
|
45
|
+
generateDynamicScaffold: vi.fn(),
|
|
46
|
+
}));
|
|
47
|
+
|
|
43
48
|
const require = createRequire(import.meta.url);
|
|
44
|
-
const fixtureSession: WorkshopSession =
|
|
49
|
+
const fixtureSession: WorkshopSession =
|
|
50
|
+
require('../fixtures/completedSession.json') as WorkshopSession;
|
|
45
51
|
|
|
46
52
|
describe('E2E: failure/recovery (T050)', () => {
|
|
47
53
|
let tmpDir: string;
|
|
@@ -65,8 +71,12 @@ describe('E2E: failure/recovery (T050)', () => {
|
|
|
65
71
|
return {
|
|
66
72
|
writtenLines,
|
|
67
73
|
activityLines,
|
|
68
|
-
write: vi.fn((text: string) => {
|
|
69
|
-
|
|
74
|
+
write: vi.fn((text: string) => {
|
|
75
|
+
writtenLines.push(text);
|
|
76
|
+
}),
|
|
77
|
+
writeActivity: vi.fn((text: string) => {
|
|
78
|
+
activityLines.push(text);
|
|
79
|
+
}),
|
|
70
80
|
writeToolSummary: vi.fn(),
|
|
71
81
|
readInput: vi.fn().mockResolvedValue(null),
|
|
72
82
|
showDecisionGate: vi.fn(),
|
|
@@ -75,34 +85,26 @@ describe('E2E: failure/recovery (T050)', () => {
|
|
|
75
85
|
};
|
|
76
86
|
}
|
|
77
87
|
|
|
78
|
-
function
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
88
|
+
function setupDynamicScaffoldMock(outputDir: string): void {
|
|
89
|
+
vi.mocked(generateDynamicScaffold).mockImplementation(async () => {
|
|
90
|
+
const { writeFile, mkdir } = await import('node:fs/promises');
|
|
91
|
+
await mkdir(join(outputDir, 'src'), { recursive: true });
|
|
92
|
+
await writeFile(
|
|
93
|
+
join(outputDir, 'package.json'),
|
|
94
|
+
JSON.stringify({
|
|
84
95
|
name: 'test-poc',
|
|
85
96
|
scripts: { test: 'vitest run' },
|
|
86
97
|
dependencies: {},
|
|
87
98
|
devDependencies: {},
|
|
88
|
-
}),
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
techStack: { language: 'TypeScript', runtime: 'Node.js 20', testRunner: 'npm test' },
|
|
98
|
-
planSummary: 'Test',
|
|
99
|
-
sessionId: fixtureSession.sessionId,
|
|
100
|
-
outputDir,
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
}),
|
|
104
|
-
getTemplateFiles: () => [],
|
|
105
|
-
} as unknown as PocScaffolder;
|
|
99
|
+
}),
|
|
100
|
+
'utf-8',
|
|
101
|
+
);
|
|
102
|
+
await writeFile(join(outputDir, 'src', 'index.ts'), 'export function main() {}', 'utf-8');
|
|
103
|
+
return {
|
|
104
|
+
createdFiles: ['package.json', 'src/index.ts'],
|
|
105
|
+
techStack: { language: 'TypeScript', runtime: 'Node.js 20', testRunner: 'npm test' },
|
|
106
|
+
};
|
|
107
|
+
});
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
function makeAlwaysFailingClient(): CopilotClient {
|
|
@@ -134,7 +136,7 @@ describe('E2E: failure/recovery (T050)', () => {
|
|
|
134
136
|
|
|
135
137
|
it('terminates with max-iterations when all tests keep failing', async () => {
|
|
136
138
|
const io = makeIo();
|
|
137
|
-
|
|
139
|
+
setupDynamicScaffoldMock(tmpDir);
|
|
138
140
|
const client = makeAlwaysFailingClient();
|
|
139
141
|
const testRunner = makeAlwaysFailingTestRunner();
|
|
140
142
|
|
|
@@ -145,7 +147,6 @@ describe('E2E: failure/recovery (T050)', () => {
|
|
|
145
147
|
outputDir: tmpDir,
|
|
146
148
|
maxIterations: 2,
|
|
147
149
|
testRunner,
|
|
148
|
-
scaffolder,
|
|
149
150
|
});
|
|
150
151
|
|
|
151
152
|
const result = await ralph.run();
|
|
@@ -156,7 +157,7 @@ describe('E2E: failure/recovery (T050)', () => {
|
|
|
156
157
|
|
|
157
158
|
it('verifies terminationReason=max-iterations in session state', async () => {
|
|
158
159
|
const io = makeIo();
|
|
159
|
-
|
|
160
|
+
setupDynamicScaffoldMock(tmpDir);
|
|
160
161
|
const client = makeAlwaysFailingClient();
|
|
161
162
|
const testRunner = makeAlwaysFailingTestRunner();
|
|
162
163
|
|
|
@@ -167,7 +168,6 @@ describe('E2E: failure/recovery (T050)', () => {
|
|
|
167
168
|
outputDir: tmpDir,
|
|
168
169
|
maxIterations: 2,
|
|
169
170
|
testRunner,
|
|
170
|
-
scaffolder,
|
|
171
171
|
});
|
|
172
172
|
|
|
173
173
|
const result = await ralph.run();
|
|
@@ -177,7 +177,7 @@ describe('E2E: failure/recovery (T050)', () => {
|
|
|
177
177
|
|
|
178
178
|
it('session has iteration history after failed loop', async () => {
|
|
179
179
|
const io = makeIo();
|
|
180
|
-
|
|
180
|
+
setupDynamicScaffoldMock(tmpDir);
|
|
181
181
|
const client = makeAlwaysFailingClient();
|
|
182
182
|
const testRunner = makeAlwaysFailingTestRunner();
|
|
183
183
|
|
|
@@ -188,7 +188,6 @@ describe('E2E: failure/recovery (T050)', () => {
|
|
|
188
188
|
outputDir: tmpDir,
|
|
189
189
|
maxIterations: 2,
|
|
190
190
|
testRunner,
|
|
191
|
-
scaffolder,
|
|
192
191
|
});
|
|
193
192
|
|
|
194
193
|
const result = await ralph.run();
|
|
@@ -276,10 +275,7 @@ describe('E2E: failure/recovery (T050)', () => {
|
|
|
276
275
|
});
|
|
277
276
|
|
|
278
277
|
try {
|
|
279
|
-
await developCommand(
|
|
280
|
-
{ session: fixtureSession.sessionId },
|
|
281
|
-
{ store, io: devIo, client },
|
|
282
|
-
);
|
|
278
|
+
await developCommand({ session: fixtureSession.sessionId }, { store, io: devIo, client });
|
|
283
279
|
} finally {
|
|
284
280
|
RalphLoop.prototype.run = originalRun;
|
|
285
281
|
}
|
|
@@ -13,7 +13,7 @@ import { createRequire } from 'node:module';
|
|
|
13
13
|
|
|
14
14
|
import { RalphLoop } from '../../src/develop/ralphLoop.js';
|
|
15
15
|
import { GitHubMcpAdapter } from '../../src/develop/githubMcpAdapter.js';
|
|
16
|
-
import {
|
|
16
|
+
import { generateDynamicScaffold } from '../../src/develop/dynamicScaffolder.js';
|
|
17
17
|
import { TestRunner } from '../../src/develop/testRunner.js';
|
|
18
18
|
import type { WorkshopSession } from '../../src/shared/schemas/session.js';
|
|
19
19
|
import type { LoopIO } from '../../src/loop/conversationLoop.js';
|
|
@@ -42,6 +42,11 @@ vi.mock('node:child_process', async (importOriginal) => {
|
|
|
42
42
|
};
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
+
// Mock generateDynamicScaffold
|
|
46
|
+
vi.mock('../../src/develop/dynamicScaffolder.js', () => ({
|
|
47
|
+
generateDynamicScaffold: vi.fn(),
|
|
48
|
+
}));
|
|
49
|
+
|
|
45
50
|
const require = createRequire(import.meta.url);
|
|
46
51
|
const fixtureSession: WorkshopSession =
|
|
47
52
|
require('../fixtures/completedSession.json') as WorkshopSession;
|
|
@@ -58,38 +63,26 @@ function makeIo(): LoopIO {
|
|
|
58
63
|
};
|
|
59
64
|
}
|
|
60
65
|
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
projectName: 'ai-powered-route-optimizer',
|
|
82
|
-
ideaTitle: 'AI Route Optimizer',
|
|
83
|
-
ideaDescription: 'Optimize routes',
|
|
84
|
-
techStack: { language: 'TypeScript', runtime: 'Node.js 20', testRunner: 'npm test' },
|
|
85
|
-
planSummary: 'Route optimization',
|
|
86
|
-
sessionId: fixtureSession.sessionId,
|
|
87
|
-
outputDir,
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
}),
|
|
91
|
-
getTemplateFiles: () => [],
|
|
92
|
-
} as unknown as PocScaffolder;
|
|
66
|
+
function setupDynamicScaffoldMock(outputDir: string): void {
|
|
67
|
+
vi.mocked(generateDynamicScaffold).mockImplementation(async () => {
|
|
68
|
+
const { writeFile, mkdir } = await import('node:fs/promises');
|
|
69
|
+
await mkdir(join(outputDir, 'src'), { recursive: true });
|
|
70
|
+
await writeFile(
|
|
71
|
+
join(outputDir, 'package.json'),
|
|
72
|
+
JSON.stringify({
|
|
73
|
+
name: 'test',
|
|
74
|
+
scripts: { test: 'vitest run' },
|
|
75
|
+
dependencies: {},
|
|
76
|
+
devDependencies: {},
|
|
77
|
+
}),
|
|
78
|
+
'utf-8',
|
|
79
|
+
);
|
|
80
|
+
await writeFile(join(outputDir, 'src', 'index.ts'), 'export function main() {}', 'utf-8');
|
|
81
|
+
return {
|
|
82
|
+
createdFiles: ['package.json', 'src/index.ts'],
|
|
83
|
+
techStack: { language: 'TypeScript', runtime: 'Node.js 20', testRunner: 'npm test' },
|
|
84
|
+
};
|
|
85
|
+
});
|
|
93
86
|
}
|
|
94
87
|
|
|
95
88
|
function makePassingClient(): CopilotClient {
|
|
@@ -137,7 +130,7 @@ describe.skip('RalphLoop — GitHub MCP flow (T034)', () => {
|
|
|
137
130
|
const io = makeIo();
|
|
138
131
|
const client = makePassingClient();
|
|
139
132
|
const testRunner = makePassingTestRunner();
|
|
140
|
-
|
|
133
|
+
setupDynamicScaffoldMock(tmpDir);
|
|
141
134
|
|
|
142
135
|
// Available GitHub MCP
|
|
143
136
|
const availableMcpManager: McpManager = {
|
|
@@ -152,7 +145,6 @@ describe.skip('RalphLoop — GitHub MCP flow (T034)', () => {
|
|
|
152
145
|
outputDir: tmpDir,
|
|
153
146
|
maxIterations: 3,
|
|
154
147
|
testRunner,
|
|
155
|
-
scaffolder,
|
|
156
148
|
});
|
|
157
149
|
|
|
158
150
|
const result = await ralph.run();
|
|
@@ -164,7 +156,7 @@ describe.skip('RalphLoop — GitHub MCP flow (T034)', () => {
|
|
|
164
156
|
const io = makeIo();
|
|
165
157
|
const client = makePassingClient();
|
|
166
158
|
const testRunner = makePassingTestRunner();
|
|
167
|
-
|
|
159
|
+
setupDynamicScaffoldMock(tmpDir);
|
|
168
160
|
|
|
169
161
|
const availableMcpManager: McpManager = {
|
|
170
162
|
isAvailable: (name: string) => name === 'github',
|
|
@@ -180,7 +172,6 @@ describe.skip('RalphLoop — GitHub MCP flow (T034)', () => {
|
|
|
180
172
|
outputDir: tmpDir,
|
|
181
173
|
maxIterations: 3,
|
|
182
174
|
testRunner,
|
|
183
|
-
scaffolder,
|
|
184
175
|
});
|
|
185
176
|
|
|
186
177
|
const result = await ralph.run();
|
|
@@ -196,7 +187,7 @@ describe.skip('RalphLoop — GitHub MCP flow (T034)', () => {
|
|
|
196
187
|
const io = makeIo();
|
|
197
188
|
const client = makePassingClient();
|
|
198
189
|
const testRunner = makePassingTestRunner();
|
|
199
|
-
|
|
190
|
+
setupDynamicScaffoldMock(tmpDir);
|
|
200
191
|
|
|
201
192
|
const availableMcpManager: McpManager = {
|
|
202
193
|
isAvailable: (name: string) => name === 'github',
|
|
@@ -211,7 +202,6 @@ describe.skip('RalphLoop — GitHub MCP flow (T034)', () => {
|
|
|
211
202
|
outputDir: tmpDir,
|
|
212
203
|
maxIterations: 3,
|
|
213
204
|
testRunner,
|
|
214
|
-
scaffolder,
|
|
215
205
|
});
|
|
216
206
|
|
|
217
207
|
await ralph.run();
|
|
@@ -12,7 +12,7 @@ import { tmpdir } from 'node:os';
|
|
|
12
12
|
import { createRequire } from 'node:module';
|
|
13
13
|
|
|
14
14
|
import { RalphLoop } from '../../src/develop/ralphLoop.js';
|
|
15
|
-
import {
|
|
15
|
+
import { generateDynamicScaffold } from '../../src/develop/dynamicScaffolder.js';
|
|
16
16
|
import { TestRunner } from '../../src/develop/testRunner.js';
|
|
17
17
|
import type { WorkshopSession } from '../../src/shared/schemas/session.js';
|
|
18
18
|
import type { LoopIO } from '../../src/loop/conversationLoop.js';
|
|
@@ -40,6 +40,11 @@ vi.mock('node:child_process', async (importOriginal) => {
|
|
|
40
40
|
};
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
// Mock generateDynamicScaffold
|
|
44
|
+
vi.mock('../../src/develop/dynamicScaffolder.js', () => ({
|
|
45
|
+
generateDynamicScaffold: vi.fn(),
|
|
46
|
+
}));
|
|
47
|
+
|
|
43
48
|
const require = createRequire(import.meta.url);
|
|
44
49
|
const fixtureSession: WorkshopSession =
|
|
45
50
|
require('../fixtures/completedSession.json') as WorkshopSession;
|
|
@@ -60,38 +65,26 @@ function makeIo(): LoopIO & { activityMessages: string[] } {
|
|
|
60
65
|
};
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
projectName: 'test',
|
|
84
|
-
ideaTitle: 'Test',
|
|
85
|
-
ideaDescription: 'Test',
|
|
86
|
-
techStack: { language: 'TypeScript', runtime: 'Node.js 20', testRunner: 'npm test' },
|
|
87
|
-
planSummary: 'Test',
|
|
88
|
-
sessionId: fixtureSession.sessionId,
|
|
89
|
-
outputDir,
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
}),
|
|
93
|
-
getTemplateFiles: () => [],
|
|
94
|
-
} as unknown as PocScaffolder;
|
|
68
|
+
function setupDynamicScaffoldMock(outputDir: string): void {
|
|
69
|
+
vi.mocked(generateDynamicScaffold).mockImplementation(async () => {
|
|
70
|
+
const { writeFile, mkdir } = await import('node:fs/promises');
|
|
71
|
+
await mkdir(join(outputDir, 'src'), { recursive: true });
|
|
72
|
+
await writeFile(
|
|
73
|
+
join(outputDir, 'package.json'),
|
|
74
|
+
JSON.stringify({
|
|
75
|
+
name: 'test',
|
|
76
|
+
scripts: { test: 'vitest run' },
|
|
77
|
+
dependencies: {},
|
|
78
|
+
devDependencies: {},
|
|
79
|
+
}),
|
|
80
|
+
'utf-8',
|
|
81
|
+
);
|
|
82
|
+
await writeFile(join(outputDir, 'src', 'index.ts'), 'export function main() {}', 'utf-8');
|
|
83
|
+
return {
|
|
84
|
+
createdFiles: ['package.json', 'src/index.ts'],
|
|
85
|
+
techStack: { language: 'TypeScript', runtime: 'Node.js 20', testRunner: 'npm test' },
|
|
86
|
+
};
|
|
87
|
+
});
|
|
95
88
|
}
|
|
96
89
|
|
|
97
90
|
function makePassingClient(): CopilotClient {
|
|
@@ -137,7 +130,7 @@ describe('RalphLoop — local fallback (T033)', () => {
|
|
|
137
130
|
const io = makeIo();
|
|
138
131
|
const client = makePassingClient();
|
|
139
132
|
const testRunner = makePassingTestRunner();
|
|
140
|
-
|
|
133
|
+
setupDynamicScaffoldMock(tmpDir);
|
|
141
134
|
|
|
142
135
|
const ralph = new RalphLoop({
|
|
143
136
|
client,
|
|
@@ -146,7 +139,6 @@ describe('RalphLoop — local fallback (T033)', () => {
|
|
|
146
139
|
outputDir: tmpDir,
|
|
147
140
|
maxIterations: 3,
|
|
148
141
|
testRunner,
|
|
149
|
-
scaffolder,
|
|
150
142
|
});
|
|
151
143
|
|
|
152
144
|
const result = await ralph.run();
|
|
@@ -160,7 +152,7 @@ describe('RalphLoop — local fallback (T033)', () => {
|
|
|
160
152
|
const io = makeIo();
|
|
161
153
|
const client = makePassingClient();
|
|
162
154
|
const testRunner = makePassingTestRunner();
|
|
163
|
-
|
|
155
|
+
setupDynamicScaffoldMock(tmpDir);
|
|
164
156
|
|
|
165
157
|
const ralph = new RalphLoop({
|
|
166
158
|
client,
|
|
@@ -169,7 +161,6 @@ describe('RalphLoop — local fallback (T033)', () => {
|
|
|
169
161
|
outputDir: tmpDir,
|
|
170
162
|
maxIterations: 3,
|
|
171
163
|
testRunner,
|
|
172
|
-
scaffolder,
|
|
173
164
|
});
|
|
174
165
|
|
|
175
166
|
const result = await ralph.run();
|
|
@@ -181,7 +172,7 @@ describe('RalphLoop — local fallback (T033)', () => {
|
|
|
181
172
|
const io = makeIo();
|
|
182
173
|
const client = makePassingClient();
|
|
183
174
|
const testRunner = makePassingTestRunner();
|
|
184
|
-
|
|
175
|
+
setupDynamicScaffoldMock(tmpDir);
|
|
185
176
|
|
|
186
177
|
const ralph = new RalphLoop({
|
|
187
178
|
client,
|
|
@@ -190,7 +181,6 @@ describe('RalphLoop — local fallback (T033)', () => {
|
|
|
190
181
|
outputDir: tmpDir,
|
|
191
182
|
maxIterations: 3,
|
|
192
183
|
testRunner,
|
|
193
|
-
scaffolder,
|
|
194
184
|
});
|
|
195
185
|
|
|
196
186
|
await ralph.run();
|