sofia-cli 0.1.2 → 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 +8 -27
- 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 -328
- 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,171 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* T033: Integration test for local fallback flow.
|
|
3
|
-
*
|
|
4
|
-
* Mock McpManager to report GitHub unavailable;
|
|
5
|
-
* run Ralph loop; verify repoSource: "local", repoPath set, no repoUrl;
|
|
6
|
-
* verify log message explains fallback.
|
|
7
|
-
*/
|
|
8
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
9
|
-
import { mkdtemp, rm } from 'node:fs/promises';
|
|
10
|
-
import { join } from 'node:path';
|
|
11
|
-
import { tmpdir } from 'node:os';
|
|
12
|
-
import { createRequire } from 'node:module';
|
|
13
|
-
import { RalphLoop } from '../../src/develop/ralphLoop.js';
|
|
14
|
-
vi.mock('node:child_process', async (importOriginal) => {
|
|
15
|
-
const actual = await importOriginal();
|
|
16
|
-
return {
|
|
17
|
-
...actual,
|
|
18
|
-
spawn: vi.fn((cmd, args) => {
|
|
19
|
-
if (cmd === 'npm' && args.includes('install')) {
|
|
20
|
-
return {
|
|
21
|
-
stdout: { on: vi.fn() },
|
|
22
|
-
stderr: { on: vi.fn() },
|
|
23
|
-
on: vi.fn((event, cb) => {
|
|
24
|
-
if (event === 'close')
|
|
25
|
-
cb(0);
|
|
26
|
-
}),
|
|
27
|
-
kill: vi.fn(),
|
|
28
|
-
killed: false,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
return actual.spawn(cmd, args);
|
|
32
|
-
}),
|
|
33
|
-
};
|
|
34
|
-
});
|
|
35
|
-
const require = createRequire(import.meta.url);
|
|
36
|
-
const fixtureSession = require('../fixtures/completedSession.json');
|
|
37
|
-
function makeIo() {
|
|
38
|
-
const activityMessages = [];
|
|
39
|
-
return {
|
|
40
|
-
activityMessages,
|
|
41
|
-
write: vi.fn(),
|
|
42
|
-
writeActivity: vi.fn((msg) => {
|
|
43
|
-
activityMessages.push(msg);
|
|
44
|
-
}),
|
|
45
|
-
writeToolSummary: vi.fn(),
|
|
46
|
-
readInput: vi.fn().mockResolvedValue(null),
|
|
47
|
-
showDecisionGate: vi.fn(),
|
|
48
|
-
isJsonMode: false,
|
|
49
|
-
isTTY: false,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
function makeFakeScaffolder(outputDir) {
|
|
53
|
-
return {
|
|
54
|
-
scaffold: vi.fn().mockImplementation(async () => {
|
|
55
|
-
const { writeFile, mkdir } = await import('node:fs/promises');
|
|
56
|
-
await mkdir(join(outputDir, 'src'), { recursive: true });
|
|
57
|
-
await writeFile(join(outputDir, 'package.json'), JSON.stringify({
|
|
58
|
-
name: 'test',
|
|
59
|
-
scripts: { test: 'vitest run' },
|
|
60
|
-
dependencies: {},
|
|
61
|
-
devDependencies: {},
|
|
62
|
-
}), 'utf-8');
|
|
63
|
-
await writeFile(join(outputDir, 'src', 'index.ts'), 'export function main() {}', 'utf-8');
|
|
64
|
-
return {
|
|
65
|
-
createdFiles: ['package.json', 'src/index.ts'],
|
|
66
|
-
skippedFiles: [],
|
|
67
|
-
context: {
|
|
68
|
-
projectName: 'test',
|
|
69
|
-
ideaTitle: 'Test',
|
|
70
|
-
ideaDescription: 'Test',
|
|
71
|
-
techStack: { language: 'TypeScript', runtime: 'Node.js 20', testRunner: 'npm test' },
|
|
72
|
-
planSummary: 'Test',
|
|
73
|
-
sessionId: fixtureSession.sessionId,
|
|
74
|
-
outputDir,
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
}),
|
|
78
|
-
getTemplateFiles: () => [],
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
function makePassingClient() {
|
|
82
|
-
return {
|
|
83
|
-
createSession: vi.fn().mockResolvedValue({
|
|
84
|
-
send: vi.fn().mockReturnValue({
|
|
85
|
-
async *[Symbol.asyncIterator]() {
|
|
86
|
-
yield { type: 'TextDelta', text: '', timestamp: '' };
|
|
87
|
-
},
|
|
88
|
-
}),
|
|
89
|
-
getHistory: () => [],
|
|
90
|
-
}),
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
function makePassingTestRunner() {
|
|
94
|
-
return {
|
|
95
|
-
run: vi.fn().mockResolvedValue({
|
|
96
|
-
passed: 1,
|
|
97
|
-
failed: 0,
|
|
98
|
-
skipped: 0,
|
|
99
|
-
total: 1,
|
|
100
|
-
durationMs: 200,
|
|
101
|
-
failures: [],
|
|
102
|
-
rawOutput: '',
|
|
103
|
-
}),
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
describe('RalphLoop — local fallback (T033)', () => {
|
|
107
|
-
let tmpDir;
|
|
108
|
-
beforeEach(async () => {
|
|
109
|
-
tmpDir = await mkdtemp(join(tmpdir(), 'sofia-local-fallback-'));
|
|
110
|
-
});
|
|
111
|
-
afterEach(async () => {
|
|
112
|
-
await rm(tmpDir, { recursive: true, force: true });
|
|
113
|
-
vi.clearAllMocks();
|
|
114
|
-
});
|
|
115
|
-
it('sets repoSource=local when GitHub MCP unavailable', async () => {
|
|
116
|
-
const io = makeIo();
|
|
117
|
-
const client = makePassingClient();
|
|
118
|
-
const testRunner = makePassingTestRunner();
|
|
119
|
-
const scaffolder = makeFakeScaffolder(tmpDir);
|
|
120
|
-
const ralph = new RalphLoop({
|
|
121
|
-
client,
|
|
122
|
-
io,
|
|
123
|
-
session: fixtureSession,
|
|
124
|
-
outputDir: tmpDir,
|
|
125
|
-
maxIterations: 3,
|
|
126
|
-
testRunner,
|
|
127
|
-
scaffolder,
|
|
128
|
-
});
|
|
129
|
-
const result = await ralph.run();
|
|
130
|
-
expect(result.session.poc?.repoSource).toBe('local');
|
|
131
|
-
expect(result.session.poc?.repoUrl).toBeUndefined();
|
|
132
|
-
expect(result.session.poc?.repoPath).toBeDefined();
|
|
133
|
-
});
|
|
134
|
-
it('sets repoPath to outputDir when local', async () => {
|
|
135
|
-
const io = makeIo();
|
|
136
|
-
const client = makePassingClient();
|
|
137
|
-
const testRunner = makePassingTestRunner();
|
|
138
|
-
const scaffolder = makeFakeScaffolder(tmpDir);
|
|
139
|
-
const ralph = new RalphLoop({
|
|
140
|
-
client,
|
|
141
|
-
io,
|
|
142
|
-
session: fixtureSession,
|
|
143
|
-
outputDir: tmpDir,
|
|
144
|
-
maxIterations: 3,
|
|
145
|
-
testRunner,
|
|
146
|
-
scaffolder,
|
|
147
|
-
});
|
|
148
|
-
const result = await ralph.run();
|
|
149
|
-
expect(result.session.poc?.repoPath).toBe(tmpDir);
|
|
150
|
-
});
|
|
151
|
-
it('logs fallback message when GitHub MCP unavailable', async () => {
|
|
152
|
-
const io = makeIo();
|
|
153
|
-
const client = makePassingClient();
|
|
154
|
-
const testRunner = makePassingTestRunner();
|
|
155
|
-
const scaffolder = makeFakeScaffolder(tmpDir);
|
|
156
|
-
const ralph = new RalphLoop({
|
|
157
|
-
client,
|
|
158
|
-
io,
|
|
159
|
-
session: fixtureSession,
|
|
160
|
-
outputDir: tmpDir,
|
|
161
|
-
maxIterations: 3,
|
|
162
|
-
testRunner,
|
|
163
|
-
scaffolder,
|
|
164
|
-
});
|
|
165
|
-
await ralph.run();
|
|
166
|
-
// Should log message about local output
|
|
167
|
-
const ioWithMessages = io;
|
|
168
|
-
const fallbackMsg = ioWithMessages.activityMessages.find((m) => m.toLowerCase().includes('local'));
|
|
169
|
-
expect(fallbackMsg).toBeDefined();
|
|
170
|
-
});
|
|
171
|
-
});
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* T015: Integration test for scaffold-only flow.
|
|
3
|
-
*
|
|
4
|
-
* Runs scaffolder with fixture session → verify output directory structure
|
|
5
|
-
* matches poc-output contract → verify package.json has test script →
|
|
6
|
-
* verify .sofia-metadata.json links to session.
|
|
7
|
-
*/
|
|
8
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
9
|
-
import { mkdtemp, rm, readFile } from 'node:fs/promises';
|
|
10
|
-
import { join } from 'node:path';
|
|
11
|
-
import { tmpdir } from 'node:os';
|
|
12
|
-
import { existsSync } from 'node:fs';
|
|
13
|
-
import { createRequire } from 'node:module';
|
|
14
|
-
import { PocScaffolder, validatePocOutput } from '../../src/develop/pocScaffolder.js';
|
|
15
|
-
// ── Load fixture session ──────────────────────────────────────────────────────
|
|
16
|
-
const require = createRequire(import.meta.url);
|
|
17
|
-
const fixtureSession = require('../fixtures/completedSession.json');
|
|
18
|
-
describe('PoC Scaffold Integration', () => {
|
|
19
|
-
let tmpDir;
|
|
20
|
-
beforeEach(async () => {
|
|
21
|
-
tmpDir = await mkdtemp(join(tmpdir(), 'sofia-scaffold-integration-'));
|
|
22
|
-
});
|
|
23
|
-
afterEach(async () => {
|
|
24
|
-
await rm(tmpDir, { recursive: true, force: true });
|
|
25
|
-
});
|
|
26
|
-
it('creates valid directory structure from fixture session', async () => {
|
|
27
|
-
const scaffolder = new PocScaffolder();
|
|
28
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, tmpDir);
|
|
29
|
-
const result = await scaffolder.scaffold(ctx);
|
|
30
|
-
// Verify files were created
|
|
31
|
-
expect(result.createdFiles.length).toBeGreaterThan(0);
|
|
32
|
-
// Verify all required files per poc-output contract
|
|
33
|
-
const requiredFiles = [
|
|
34
|
-
'.gitignore',
|
|
35
|
-
'README.md',
|
|
36
|
-
'package.json',
|
|
37
|
-
'tsconfig.json',
|
|
38
|
-
'.sofia-metadata.json',
|
|
39
|
-
];
|
|
40
|
-
for (const file of requiredFiles) {
|
|
41
|
-
expect(existsSync(join(tmpDir, file)), `Expected ${file} to exist`).toBe(true);
|
|
42
|
-
}
|
|
43
|
-
// Verify src/ and tests/ directories
|
|
44
|
-
expect(existsSync(join(tmpDir, 'src', 'index.ts'))).toBe(true);
|
|
45
|
-
expect(existsSync(join(tmpDir, 'tests', 'index.test.ts'))).toBe(true);
|
|
46
|
-
});
|
|
47
|
-
it('package.json has required test script', async () => {
|
|
48
|
-
const scaffolder = new PocScaffolder();
|
|
49
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, tmpDir);
|
|
50
|
-
await scaffolder.scaffold(ctx);
|
|
51
|
-
const pkgContent = await readFile(join(tmpDir, 'package.json'), 'utf-8');
|
|
52
|
-
const pkg = JSON.parse(pkgContent);
|
|
53
|
-
expect(pkg.scripts.test).toBeDefined();
|
|
54
|
-
expect(pkg.scripts.test).toBe('vitest run');
|
|
55
|
-
expect(pkg.type).toBe('module');
|
|
56
|
-
expect(pkg.name).toBe('ai-powered-route-optimizer'); // from fixture
|
|
57
|
-
});
|
|
58
|
-
it('.sofia-metadata.json links to session', async () => {
|
|
59
|
-
const scaffolder = new PocScaffolder();
|
|
60
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, tmpDir);
|
|
61
|
-
await scaffolder.scaffold(ctx);
|
|
62
|
-
const metaContent = await readFile(join(tmpDir, '.sofia-metadata.json'), 'utf-8');
|
|
63
|
-
const meta = JSON.parse(metaContent);
|
|
64
|
-
expect(meta.sessionId).toBe(fixtureSession.sessionId);
|
|
65
|
-
expect(meta.featureSpec).toBe('002-poc-generation');
|
|
66
|
-
expect(meta.ideaTitle).toBe('AI-Powered Route Optimizer');
|
|
67
|
-
expect(meta.generatedAt).toBeDefined();
|
|
68
|
-
});
|
|
69
|
-
it('tsconfig.json is valid JSON with strict mode', async () => {
|
|
70
|
-
const scaffolder = new PocScaffolder();
|
|
71
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, tmpDir);
|
|
72
|
-
await scaffolder.scaffold(ctx);
|
|
73
|
-
const tsconfigContent = await readFile(join(tmpDir, 'tsconfig.json'), 'utf-8');
|
|
74
|
-
const tsconfig = JSON.parse(tsconfigContent);
|
|
75
|
-
expect(tsconfig.compilerOptions.strict).toBe(true);
|
|
76
|
-
expect(tsconfig.compilerOptions.module).toBe('Node16');
|
|
77
|
-
});
|
|
78
|
-
it('.gitignore contains required patterns', async () => {
|
|
79
|
-
const scaffolder = new PocScaffolder();
|
|
80
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, tmpDir);
|
|
81
|
-
await scaffolder.scaffold(ctx);
|
|
82
|
-
const gitignoreContent = await readFile(join(tmpDir, '.gitignore'), 'utf-8');
|
|
83
|
-
expect(gitignoreContent).toContain('node_modules/');
|
|
84
|
-
expect(gitignoreContent).toContain('dist/');
|
|
85
|
-
expect(gitignoreContent).toContain('coverage/');
|
|
86
|
-
});
|
|
87
|
-
it('README.md contains idea title and generated-by attribution', async () => {
|
|
88
|
-
const scaffolder = new PocScaffolder();
|
|
89
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, tmpDir);
|
|
90
|
-
await scaffolder.scaffold(ctx);
|
|
91
|
-
const readmeContent = await readFile(join(tmpDir, 'README.md'), 'utf-8');
|
|
92
|
-
expect(readmeContent).toContain('AI-Powered Route Optimizer');
|
|
93
|
-
expect(readmeContent).toContain(fixtureSession.sessionId);
|
|
94
|
-
expect(readmeContent).toContain('sofIA');
|
|
95
|
-
});
|
|
96
|
-
it('validatePocOutput returns valid=true for complete scaffold', async () => {
|
|
97
|
-
const scaffolder = new PocScaffolder();
|
|
98
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, tmpDir);
|
|
99
|
-
await scaffolder.scaffold(ctx);
|
|
100
|
-
const validation = await validatePocOutput(tmpDir);
|
|
101
|
-
expect(validation.valid).toBe(true);
|
|
102
|
-
expect(validation.missingFiles).toHaveLength(0);
|
|
103
|
-
expect(validation.errors).toHaveLength(0);
|
|
104
|
-
});
|
|
105
|
-
it('infers tech stack from plan architecture notes', async () => {
|
|
106
|
-
const _scaffolder = new PocScaffolder();
|
|
107
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, tmpDir);
|
|
108
|
-
// Fixture session has 'express' in architectureNotes
|
|
109
|
-
expect(ctx.techStack.language).toBe('TypeScript');
|
|
110
|
-
expect(ctx.techStack.runtime).toBe('Node.js 20');
|
|
111
|
-
expect(ctx.techStack.framework).toBe('Express');
|
|
112
|
-
});
|
|
113
|
-
it('src/index.ts exports a main function', async () => {
|
|
114
|
-
const scaffolder = new PocScaffolder();
|
|
115
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, tmpDir);
|
|
116
|
-
await scaffolder.scaffold(ctx);
|
|
117
|
-
const indexContent = await readFile(join(tmpDir, 'src', 'index.ts'), 'utf-8');
|
|
118
|
-
expect(indexContent).toContain('export async function main');
|
|
119
|
-
});
|
|
120
|
-
it('tests/index.test.ts contains vitest imports', async () => {
|
|
121
|
-
const scaffolder = new PocScaffolder();
|
|
122
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, tmpDir);
|
|
123
|
-
await scaffolder.scaffold(ctx);
|
|
124
|
-
const testContent = await readFile(join(tmpDir, 'tests', 'index.test.ts'), 'utf-8');
|
|
125
|
-
expect(testContent).toContain('vitest');
|
|
126
|
-
expect(testContent).toContain('describe');
|
|
127
|
-
expect(testContent).toContain('expect');
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
// ── python-pytest template integration (T037) ────────────────────────────
|
|
131
|
-
describe('python-pytest template', () => {
|
|
132
|
-
let tmpDir;
|
|
133
|
-
beforeEach(async () => {
|
|
134
|
-
tmpDir = await mkdtemp(join(tmpdir(), 'sofia-python-scaffold-'));
|
|
135
|
-
});
|
|
136
|
-
afterEach(async () => {
|
|
137
|
-
await rm(tmpDir, { recursive: true, force: true });
|
|
138
|
-
});
|
|
139
|
-
it('scaffolds expected Python project structure (T037)', async () => {
|
|
140
|
-
const { PYTHON_PYTEST_TEMPLATE } = await import('../../src/develop/templateRegistry.js');
|
|
141
|
-
const scaffolder = new PocScaffolder(PYTHON_PYTEST_TEMPLATE);
|
|
142
|
-
const ctx = PocScaffolder.buildContext(fixtureSession, tmpDir, PYTHON_PYTEST_TEMPLATE);
|
|
143
|
-
const result = await scaffolder.scaffold(ctx);
|
|
144
|
-
expect(result.createdFiles).toContain('requirements.txt');
|
|
145
|
-
expect(result.createdFiles).toContain('pytest.ini');
|
|
146
|
-
expect(result.createdFiles).toContain('src/__init__.py');
|
|
147
|
-
expect(result.createdFiles).toContain('src/main.py');
|
|
148
|
-
expect(result.createdFiles).toContain('tests/test_main.py');
|
|
149
|
-
expect(result.createdFiles).toContain('.sofia-metadata.json');
|
|
150
|
-
expect(result.createdFiles).toContain('README.md');
|
|
151
|
-
// Verify files exist on disk
|
|
152
|
-
expect(existsSync(join(tmpDir, 'requirements.txt'))).toBe(true);
|
|
153
|
-
expect(existsSync(join(tmpDir, 'src', 'main.py'))).toBe(true);
|
|
154
|
-
expect(existsSync(join(tmpDir, 'tests', 'test_main.py'))).toBe(true);
|
|
155
|
-
// Verify content
|
|
156
|
-
const reqContent = await readFile(join(tmpDir, 'requirements.txt'), 'utf-8');
|
|
157
|
-
expect(reqContent).toContain('pytest');
|
|
158
|
-
const mainContent = await readFile(join(tmpDir, 'src', 'main.py'), 'utf-8');
|
|
159
|
-
expect(mainContent).toContain('def main');
|
|
160
|
-
// Verify techStack uses Python
|
|
161
|
-
expect(ctx.techStack.language).toBe('Python');
|
|
162
|
-
});
|
|
163
|
-
});
|