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,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 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
- });