@codeyam/codeyam-cli 0.1.28 → 0.1.30
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/analyzer-template/.build-info.json +6 -6
- package/analyzer-template/log.txt +3 -3
- package/analyzer-template/package.json +2 -2
- package/analyzer-template/packages/aws/package.json +5 -5
- package/analyzer-template/packages/database/package.json +1 -1
- package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js +38 -3
- package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js.map +1 -1
- package/codeyam-cli/src/commands/editor.js +307 -5
- package/codeyam-cli/src/commands/editor.js.map +1 -1
- package/codeyam-cli/src/commands/init.js +19 -0
- package/codeyam-cli/src/commands/init.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +136 -0
- package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js +98 -1
- package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorRoadmap.test.js +398 -0
- package/codeyam-cli/src/utils/__tests__/editorRoadmap.test.js.map +1 -0
- package/codeyam-cli/src/utils/designSystemShowcase.js +810 -0
- package/codeyam-cli/src/utils/designSystemShowcase.js.map +1 -0
- package/codeyam-cli/src/utils/editorAudit.js +6 -1
- package/codeyam-cli/src/utils/editorAudit.js.map +1 -1
- package/codeyam-cli/src/utils/editorRoadmap.js +301 -0
- package/codeyam-cli/src/utils/editorRoadmap.js.map +1 -0
- package/codeyam-cli/src/utils/editorScenarios.js +10 -0
- package/codeyam-cli/src/utils/editorScenarios.js.map +1 -1
- package/codeyam-cli/src/utils/install-skills.js +27 -6
- package/codeyam-cli/src/utils/install-skills.js.map +1 -1
- package/codeyam-cli/src/webserver/__tests__/api.interactive-switch-scenario.test.js +1 -0
- package/codeyam-cli/src/webserver/__tests__/api.interactive-switch-scenario.test.js.map +1 -1
- package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +115 -0
- package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js.map +1 -1
- package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{CopyButton-CLe80MMu.js → CopyButton-DTBZZfSk.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-Crt_KN_U.js → EntityItem-BxclONWq.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-CD7lGABo.js → EntityTypeIcon-BsnEOJZ_.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InlineSpinner-CgTNOhnu.js → InlineSpinner-ByaELMbv.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-DtYTSPL2.js → InteractivePreview-6WjVfhxX.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{LibraryFunctionPreview-D3s1MFkb.js → LibraryFunctionPreview-ChX-Hp7W.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-CM5zg40N.js → LogViewer-C-9zQdXg.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{MiniClaudeChat-CQENLSrF.js → MiniClaudeChat-BusrvT2F.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-C2PLkej3.js → ReportIssueModal-DQsceHVv.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{SafeScreenshot-DanvyBPb.js → SafeScreenshot-DThcm_9M.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-CefgqbCr.js → ScenarioViewer-Cl4oOA3A.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{Spinner-Bc8BG-Lw.js → Spinner-CIil5-gb.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{ViewportInspectBar-BA_Ry-rs.js → ViewportInspectBar-BqkA9zyZ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{_index-C1YkzTAV.js → _index-DnOgyseQ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-yH46LLUz.js → activity.(_tab)-DqM9hbNE.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{addon-web-links-CHx25PAe.js → addon-web-links-C58dYPwR.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{agent-transcripts-Bg3e7q4S.js → agent-transcripts-B8NCeOrm.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-roadmap-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{book-open-CL-lMgHh.js → book-open-BFSIqZgO.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-GmAjGS9-.js → chevron-down-B9fDzFVh.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/chunk-UVKPFVEO-Bmq2apuh.js +43 -0
- package/codeyam-cli/src/webserver/build/client/assets/{circle-check-DFcQkN5j.js → circle-check-DLPObLUx.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{copy-C6iF61Xs.js → copy-DXEmO0TD.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{createLucideIcon-4ImjHTVC.js → createLucideIcon-BwyFiRot.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{dev.empty-CRepiabR.js → dev.empty-iRhRIFlp.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/editor._tab-BZPBzV73.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-CsYVRiNH.js +147 -0
- package/codeyam-cli/src/webserver/build/client/assets/{editorPreview-CluPkvXJ.js → editorPreview-C6fEYHrh.js} +6 -6
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-DYJRGiDI.js → entity._sha._-Ce1s4OQ1.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.dev-wdiwx5-Z.js → entity._sha.scenarios._scenarioId.dev-C8AyYgYT.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-BrkN-40Y.js → entity._sha.scenarios._scenarioId.fullscreen-DziaVQX1.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-DxfhekTZ.js → entity._sha_.create-scenario-BTcpgIpC.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-CRXJWmpB.js → entity._sha_.edit._scenarioId-D_O_ajfZ.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{entry.client-SuW9syRS.js → entry.client-j1Vi0bco.js} +6 -6
- package/codeyam-cli/src/webserver/build/client/assets/{files-D-xGrg29.js → files-kuny2Q_s.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{git-Bq_fbXP5.js → git-DgCZPMie.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/globals-Gp2o-NMc.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{index-Bp1l4hSv.js → index-BliGSSpl.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{index-DE3jI_dv.js → index-SqjQKTdH.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{index-CWV9XZiG.js → index-vyrZD2g4.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{labs-B_IX45ih.js → labs-c3yLxSEp.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-De-7qQ2u.js → loader-circle-D-q28GLF.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-ef0f624d.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{memory-Cx2xEx7s.js → memory-CEWIUC4t.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{pause-CFxEKL1u.js → pause-BP6fitdh.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{root-dKFRTYcy.js → root-Didv9PLi.js} +5 -5
- package/codeyam-cli/src/webserver/build/client/assets/{search-BdBb5aqc.js → search-BooqacKS.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{settings-DdE-Untf.js → settings-BM0nbryO.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{simulations-DSCdE99u.js → simulations-ovy6FjRY.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{terminal-CrplD4b1.js → terminal-DHemCJIs.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-DqJ0j69l.js → triangle-alert-D87ekDl8.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useCustomSizes-DhXHbEjP.js → useCustomSizes-Dk0Tciqg.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useLastLogLine-D9QZKaLJ.js → useLastLogLine-C8QvIe05.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useReportContext-Cy5Qg_UR.js → useReportContext-jkCytuYz.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{useToast-5HR2j9ZE.js → useToast-BgqkixU9.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{analysisRunner-OLsM110H.js → analysisRunner-BKMsxwqe.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{index-WHdB6WTN.js → index-CvuvIPEn.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/init-B3gVLAAJ.js +14 -0
- package/codeyam-cli/src/webserver/build/server/assets/{server-build-DZbLY6O_.js → server-build-B4LxStYP.js} +183 -132
- package/codeyam-cli/src/webserver/build/server/index.js +1 -1
- package/codeyam-cli/src/webserver/build-info.json +5 -5
- package/codeyam-cli/src/webserver/editorProxy.js +77 -4
- package/codeyam-cli/src/webserver/editorProxy.js.map +1 -1
- package/codeyam-cli/src/webserver/server.js +67 -0
- package/codeyam-cli/src/webserver/server.js.map +1 -1
- package/codeyam-cli/src/webserver/terminalServer.js +21 -0
- package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
- package/codeyam-cli/templates/codeyam-editor-gemini.md +59 -0
- package/codeyam-cli/templates/editor-step-hook.py +4 -4
- package/codeyam-cli/templates/seed-adapters/supabase.ts +42 -53
- package/package.json +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/chunk-JZWAC4HX-BAdwhyCx.js +0 -43
- package/codeyam-cli/src/webserver/build/client/assets/editor._tab-Gbk_i5Js.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-CRxPi2BB.js +0 -96
- package/codeyam-cli/src/webserver/build/client/assets/globals-BsGHu8WX.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-9032538f.js +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/init-DbSiZoE6.js +0 -10
|
@@ -227,6 +227,143 @@ function getTechStackContext(root) {
|
|
|
227
227
|
: 'FEATURE_PATTERNS.md',
|
|
228
228
|
};
|
|
229
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Returns a pre-populated tech stack for a given template ID.
|
|
232
|
+
* Written to .codeyam/config.json during `codeyam editor template`.
|
|
233
|
+
*/
|
|
234
|
+
function getTechStackForTemplate(templateId) {
|
|
235
|
+
switch (templateId) {
|
|
236
|
+
case 'nextjs-prisma-sqlite':
|
|
237
|
+
return {
|
|
238
|
+
languages: [
|
|
239
|
+
{
|
|
240
|
+
name: 'TypeScript',
|
|
241
|
+
url: 'https://typescriptlang.org',
|
|
242
|
+
description: 'Statically typed JavaScript superset',
|
|
243
|
+
version: '5',
|
|
244
|
+
},
|
|
245
|
+
],
|
|
246
|
+
frameworks: [
|
|
247
|
+
{
|
|
248
|
+
name: 'Next.js',
|
|
249
|
+
url: 'https://nextjs.org',
|
|
250
|
+
description: 'Full-stack React framework with App Router, SSR, and API routes',
|
|
251
|
+
version: '15',
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: 'React',
|
|
255
|
+
url: 'https://react.dev',
|
|
256
|
+
description: 'Component-based UI library',
|
|
257
|
+
version: '19',
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
databases: [
|
|
261
|
+
{
|
|
262
|
+
name: 'SQLite',
|
|
263
|
+
url: 'https://sqlite.org',
|
|
264
|
+
description: 'Embedded relational database — zero config, upgradeable to hosted DB',
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
libraries: [
|
|
268
|
+
{
|
|
269
|
+
name: 'Prisma',
|
|
270
|
+
url: 'https://prisma.io',
|
|
271
|
+
description: 'Type-safe database ORM and query builder',
|
|
272
|
+
version: '7',
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
name: 'Tailwind CSS',
|
|
276
|
+
url: 'https://tailwindcss.com',
|
|
277
|
+
description: 'Utility-first CSS framework',
|
|
278
|
+
version: '4',
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
};
|
|
282
|
+
case 'chrome-extension-react':
|
|
283
|
+
return {
|
|
284
|
+
languages: [
|
|
285
|
+
{
|
|
286
|
+
name: 'TypeScript',
|
|
287
|
+
url: 'https://typescriptlang.org',
|
|
288
|
+
description: 'Statically typed JavaScript superset',
|
|
289
|
+
version: '5',
|
|
290
|
+
},
|
|
291
|
+
],
|
|
292
|
+
frameworks: [
|
|
293
|
+
{
|
|
294
|
+
name: 'React',
|
|
295
|
+
url: 'https://react.dev',
|
|
296
|
+
description: 'Component-based UI library for the popup and options pages',
|
|
297
|
+
version: '19',
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: 'Vite',
|
|
301
|
+
url: 'https://vite.dev',
|
|
302
|
+
description: 'Fast build tool and dev server',
|
|
303
|
+
version: '6',
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
libraries: [
|
|
307
|
+
{
|
|
308
|
+
name: 'Tailwind CSS',
|
|
309
|
+
url: 'https://tailwindcss.com',
|
|
310
|
+
description: 'Utility-first CSS framework',
|
|
311
|
+
version: '4',
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
infrastructure: [
|
|
315
|
+
{
|
|
316
|
+
name: 'Chrome Manifest V3',
|
|
317
|
+
url: 'https://developer.chrome.com/docs/extensions/develop/migrate/what-is-mv3',
|
|
318
|
+
description: 'Extension platform with service workers, declarative APIs, and chrome.storage',
|
|
319
|
+
},
|
|
320
|
+
],
|
|
321
|
+
};
|
|
322
|
+
case 'expo-react-native':
|
|
323
|
+
return {
|
|
324
|
+
languages: [
|
|
325
|
+
{
|
|
326
|
+
name: 'TypeScript',
|
|
327
|
+
url: 'https://typescriptlang.org',
|
|
328
|
+
description: 'Statically typed JavaScript superset',
|
|
329
|
+
version: '5',
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
frameworks: [
|
|
333
|
+
{
|
|
334
|
+
name: 'Expo',
|
|
335
|
+
url: 'https://expo.dev',
|
|
336
|
+
description: 'React Native development platform with managed workflow and OTA updates',
|
|
337
|
+
version: 'SDK 54',
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
name: 'React Native',
|
|
341
|
+
url: 'https://reactnative.dev',
|
|
342
|
+
description: 'Cross-platform mobile UI framework',
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
name: 'Expo Router',
|
|
346
|
+
url: 'https://docs.expo.dev/router/introduction/',
|
|
347
|
+
description: 'File-based navigation for React Native apps',
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
libraries: [
|
|
351
|
+
{
|
|
352
|
+
name: 'NativeWind',
|
|
353
|
+
url: 'https://www.nativewind.dev',
|
|
354
|
+
description: 'Tailwind CSS for React Native',
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
name: 'AsyncStorage',
|
|
358
|
+
url: 'https://react-native-async-storage.github.io/async-storage/',
|
|
359
|
+
description: 'Persistent key-value storage for React Native',
|
|
360
|
+
},
|
|
361
|
+
],
|
|
362
|
+
};
|
|
363
|
+
default:
|
|
364
|
+
return {};
|
|
365
|
+
}
|
|
366
|
+
}
|
|
230
367
|
/**
|
|
231
368
|
* Print dimension guidance when the project has multiple screen sizes.
|
|
232
369
|
* Tells Claude to pick the right dimension for the content being previewed
|
|
@@ -250,6 +387,37 @@ function checkbox(text) {
|
|
|
250
387
|
const highlighted = text.replace(/`([^`]+)`/g, (_m, code) => chalk.cyan(code));
|
|
251
388
|
console.log(` ${chalk.dim('[ ]')} ${highlighted}`);
|
|
252
389
|
}
|
|
390
|
+
/**
|
|
391
|
+
* Print a checklist item for the handoff summary.
|
|
392
|
+
*/
|
|
393
|
+
function checkboxHandoff() {
|
|
394
|
+
checkbox('Update the handoff summary in `.codeyam/config.json` for the next session/AI: `codeyam editor handoff \'{"summary":"..."}\'`');
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Print the handoff context from a previous session or AI provider.
|
|
398
|
+
*/
|
|
399
|
+
function printHandoffContext(root) {
|
|
400
|
+
try {
|
|
401
|
+
const configPath = path.join(root, '.codeyam', 'config.json');
|
|
402
|
+
if (!fs.existsSync(configPath))
|
|
403
|
+
return;
|
|
404
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
405
|
+
const handoff = config.handoff;
|
|
406
|
+
if (!handoff || !handoff.summary)
|
|
407
|
+
return;
|
|
408
|
+
console.log();
|
|
409
|
+
console.log(chalk.bold.magenta(`━━━ HANDOFF FROM ${String(handoff.lastProvider || 'unknown').toUpperCase()} (Step ${handoff.lastStep || 'unknown'}) ━━━`));
|
|
410
|
+
console.log(chalk.magenta(handoff.summary));
|
|
411
|
+
if (handoff.lastUpdated) {
|
|
412
|
+
console.log(chalk.dim(` Updated: ${handoff.lastUpdated}`));
|
|
413
|
+
}
|
|
414
|
+
console.log(chalk.bold.magenta('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
415
|
+
console.log();
|
|
416
|
+
}
|
|
417
|
+
catch {
|
|
418
|
+
// Non-fatal
|
|
419
|
+
}
|
|
420
|
+
}
|
|
253
421
|
/**
|
|
254
422
|
* Instructions for creating/updating .codeyam/data-structure.json.
|
|
255
423
|
* Only prints creation instructions if the file doesn't exist yet.
|
|
@@ -376,6 +544,12 @@ function printExtractionPlanInstructions() {
|
|
|
376
544
|
console.log(chalk.yellow(' Every component that renders multiple distinct sections should be split into sub-components.'));
|
|
377
545
|
console.log(chalk.yellow(' If a component has N visually distinct parts, it should compose N sub-components.'));
|
|
378
546
|
console.log();
|
|
547
|
+
console.log(chalk.bold.red('THE DECOMPOSITION RULE: All code should do one thing.'));
|
|
548
|
+
console.log(chalk.yellow(' Code either contains logic OR brings together smaller pieces to form a coordinated whole.'));
|
|
549
|
+
console.log(chalk.yellow(' Every opportunity to extract code into a sensible function, helper, or sub-component MUST be taken.'));
|
|
550
|
+
console.log(chalk.yellow(' Then extract AGAIN from the extracted code — keep going until each piece does one clearly defined thing.'));
|
|
551
|
+
console.log(chalk.yellow(' This applies to ALL code: backend routes, business logic, frontend components, utilities — everything.'));
|
|
552
|
+
console.log();
|
|
379
553
|
console.log(chalk.bold('Checklist:'));
|
|
380
554
|
checkbox('Read `.codeyam/glossary.json` — note reusable functions/components');
|
|
381
555
|
checkbox('Read EVERY file used by this page/feature');
|
|
@@ -386,6 +560,12 @@ function printExtractionPlanInstructions() {
|
|
|
386
560
|
console.log(chalk.yellow(' Functions: data transforms, calculations, formatting, validation,'));
|
|
387
561
|
console.log(chalk.yellow(' API response shaping, any logic that is not directly about rendering'));
|
|
388
562
|
console.log(chalk.yellow(' Hooks: data fetching, state management, side effects'));
|
|
563
|
+
console.log(chalk.yellow(' Inline logic — backend AND frontend (MUST be extracted as named functions):'));
|
|
564
|
+
console.log(chalk.yellow(' conditionals/ternaries, computed/derived values, data transformations,'));
|
|
565
|
+
console.log(chalk.yellow(' string formatting/interpolation, array filtering/sorting/mapping callbacks,'));
|
|
566
|
+
console.log(chalk.yellow(' default value logic, null/undefined guards, date/number formatting,'));
|
|
567
|
+
console.log(chalk.yellow(' permission/role checks, status derivation (e.g. isOverdue(task)),'));
|
|
568
|
+
console.log(chalk.yellow(' request/response shaping, error message construction, config lookups'));
|
|
389
569
|
console.log();
|
|
390
570
|
checkbox('Write a numbered extraction plan listing EVERYTHING you will extract');
|
|
391
571
|
console.log(chalk.yellow(' The end state: every page file is ONLY imports + component composition.'));
|
|
@@ -396,6 +576,15 @@ function printExtractionPlanInstructions() {
|
|
|
396
576
|
console.log(chalk.yellow(' — What it is (component, function, hook)'));
|
|
397
577
|
console.log(chalk.yellow(' — Where it currently lives (source file + approximate lines)'));
|
|
398
578
|
console.log(chalk.yellow(' — Where it will go (new file path)'));
|
|
579
|
+
console.log(chalk.yellow(' — How you will test it (key inputs/outputs and edge cases)'));
|
|
580
|
+
console.log(chalk.yellow(' — What logic inside it can be further extracted as a separate testable function'));
|
|
581
|
+
console.log();
|
|
582
|
+
console.log(chalk.bold.red('BEFORE FINALIZING THE PLAN:'));
|
|
583
|
+
console.log(chalk.yellow(' Re-read every file ONE MORE TIME. For each piece of code, ask:'));
|
|
584
|
+
console.log(chalk.yellow(' 1. Does this do more than one thing? → Split it into pieces that each do one thing.'));
|
|
585
|
+
console.log(chalk.yellow(' 2. Is there logic here that could be its own function with clear inputs/outputs? → Extract it.'));
|
|
586
|
+
console.log(chalk.yellow(' 3. Can the extracted code itself be broken down further? → Keep extracting.'));
|
|
587
|
+
console.log(chalk.yellow(' If your plan has fewer functions than components, you probably missed extractable logic.'));
|
|
399
588
|
console.log();
|
|
400
589
|
console.log(chalk.dim('Present the numbered plan, then proceed to step 7 to execute it.'));
|
|
401
590
|
}
|
|
@@ -1008,6 +1197,15 @@ function printStep1(root, feature, options, userPrompt) {
|
|
|
1008
1197
|
console.log(chalk.dim(' -H "Content-Type: application/json" \\'));
|
|
1009
1198
|
console.log(chalk.dim(' -d \'{"projectTitle":"My App","projectDescription":"A short description of what this app does"}\''));
|
|
1010
1199
|
console.log();
|
|
1200
|
+
checkbox('Detect and set the project tech stack:');
|
|
1201
|
+
console.log(chalk.dim(' Scan package.json, framework configs (.env, .env.example, tsconfig.json, next.config.*, prisma/schema.prisma, etc.)'));
|
|
1202
|
+
console.log(chalk.dim(' to detect languages, frameworks, databases, services, libraries, and infrastructure.'));
|
|
1203
|
+
console.log(chalk.dim(' Each item MUST have name, url, and description. version and envKeys are optional.'));
|
|
1204
|
+
console.log(chalk.dim(` curl -s -X POST http://localhost:${port}/api/editor-project-info \\`));
|
|
1205
|
+
console.log(chalk.dim(' -H "Content-Type: application/json" \\'));
|
|
1206
|
+
console.log(chalk.dim(' -d \'{"techStack":{"languages":[{"name":"TypeScript","url":"https://typescriptlang.org","description":"Statically typed JavaScript superset","version":"5"}],"frameworks":[{"name":"Next.js","url":"https://nextjs.org","description":"Full-stack React framework with SSR and API routes","version":"15"}],"databases":[{"name":"SQLite","url":"https://sqlite.org","description":"Embedded relational database"}],"services":[{"name":"Stripe","url":"https://stripe.com","description":"Payment processing and billing","envKeys":["STRIPE_SECRET_KEY"]}],"libraries":[{"name":"Prisma","url":"https://prisma.io","description":"Type-safe database ORM","version":"7"}],"infrastructure":[]}}\''));
|
|
1207
|
+
console.log(chalk.dim(' Replace the example values with what you detect in this project. Omit empty categories.'));
|
|
1208
|
+
console.log();
|
|
1011
1209
|
const designSystem = readDesignSystem(root);
|
|
1012
1210
|
if (designSystem) {
|
|
1013
1211
|
console.log(chalk.bold.magenta('Design System (from .codeyam/design-system.md):'));
|
|
@@ -1021,6 +1219,8 @@ function printStep1(root, feature, options, userPrompt) {
|
|
|
1021
1219
|
console.log(chalk.yellow(' Option 2 label: "I\'d like some changes"') +
|
|
1022
1220
|
chalk.dim(' — user describes changes, you revise the plan, then re-present'));
|
|
1023
1221
|
console.log();
|
|
1222
|
+
checkboxHandoff();
|
|
1223
|
+
console.log();
|
|
1024
1224
|
console.log(chalk.dim('This step is for understanding user goals and getting buy-in. Code comes in Step 2.'));
|
|
1025
1225
|
console.log();
|
|
1026
1226
|
console.log(chalk.bold.red('━━━ STOP ━━━'));
|
|
@@ -1148,6 +1348,8 @@ function printStep2(root, feature) {
|
|
|
1148
1348
|
console.log();
|
|
1149
1349
|
printDataStructureInstructions();
|
|
1150
1350
|
}
|
|
1351
|
+
console.log();
|
|
1352
|
+
checkboxHandoff();
|
|
1151
1353
|
stopGate(2);
|
|
1152
1354
|
}
|
|
1153
1355
|
// ─── Step 3: Prototype ────────────────────────────────────────────────
|
|
@@ -1264,6 +1466,7 @@ function printStep3(root, feature) {
|
|
|
1264
1466
|
console.log(chalk.red.bold(' NEVER claim "you should see X" or "the preview shows X" unless you just ran a preview command.'));
|
|
1265
1467
|
console.log(chalk.red(' The preview only updates when you explicitly refresh it. Verify, then describe.'));
|
|
1266
1468
|
console.log();
|
|
1469
|
+
checkboxHandoff();
|
|
1267
1470
|
stopGate(3);
|
|
1268
1471
|
}
|
|
1269
1472
|
// ─── Step 4: Verify Prototype ─────────────────────────────────────────
|
|
@@ -1321,6 +1524,8 @@ function printStep4(root, feature) {
|
|
|
1321
1524
|
console.log(chalk.dim(' A new clone should work with just: git clone → npm run setup → npm run dev'));
|
|
1322
1525
|
console.log();
|
|
1323
1526
|
console.log(chalk.dim('Focus on building the prototype. Scenarios and refactoring happen in later steps.'));
|
|
1527
|
+
console.log();
|
|
1528
|
+
checkboxHandoff();
|
|
1324
1529
|
stopGate(4);
|
|
1325
1530
|
}
|
|
1326
1531
|
// ─── Step 5: Confirm ──────────────────────────────────────────────────
|
|
@@ -1384,6 +1589,8 @@ function printStep5(root, feature) {
|
|
|
1384
1589
|
chalk.dim(' — make changes, refresh preview, re-run `codeyam editor 5`'));
|
|
1385
1590
|
console.log();
|
|
1386
1591
|
console.log(chalk.dim('Wait for user approval before moving on. Refactoring and scenarios happen in later steps.'));
|
|
1592
|
+
console.log();
|
|
1593
|
+
checkboxHandoff();
|
|
1387
1594
|
stopGate(5, { confirm: true });
|
|
1388
1595
|
}
|
|
1389
1596
|
// ─── Step 6: Deconstruct ──────────────────────────────────────────────
|
|
@@ -1409,6 +1616,8 @@ function printStep6(root, feature) {
|
|
|
1409
1616
|
console.log(chalk.yellow('This step is read and plan only. Code extraction happens in step 7.'));
|
|
1410
1617
|
console.log();
|
|
1411
1618
|
printExtractionPlanInstructions();
|
|
1619
|
+
console.log();
|
|
1620
|
+
checkboxHandoff();
|
|
1412
1621
|
stopGate(6);
|
|
1413
1622
|
}
|
|
1414
1623
|
// ─── Step 7: Extract ──────────────────────────────────────────────────
|
|
@@ -1445,6 +1654,9 @@ function printStep7(root, feature) {
|
|
|
1445
1654
|
checkbox('For each function/hook: write MULTIPLE failing tests FIRST, then extract to make them pass');
|
|
1446
1655
|
console.log(chalk.dim(' Cover: typical inputs, edge cases, empty/null inputs, error conditions'));
|
|
1447
1656
|
console.log(chalk.dim(' Aim for 3-8 test cases per function depending on complexity'));
|
|
1657
|
+
console.log(chalk.dim(' EVERY conditional branch in the function MUST have a test that exercises it'));
|
|
1658
|
+
console.log(chalk.dim(' EVERY return path MUST be tested — if a function can return 3 different things, write 3+ tests'));
|
|
1659
|
+
console.log(chalk.dim(' Boundary values: 0, 1, -1, empty string, empty array, undefined, null'));
|
|
1448
1660
|
console.log(chalk.dim(' Hooks count as functions — useDrinks, useAuth, etc. all need test files'));
|
|
1449
1661
|
console.log(chalk.dim(' Wrap all tests in a describe("FunctionName", ...) block — the audit matches on this name'));
|
|
1450
1662
|
if (ctx.isExpo) {
|
|
@@ -1461,6 +1673,23 @@ function printStep7(root, feature) {
|
|
|
1461
1673
|
console.log(chalk.yellow(` Check: does any file contain raw ${ctx.rawPrimitivesList}?`));
|
|
1462
1674
|
console.log(chalk.yellow(' If yes → that JSX section is a component waiting to be extracted.'));
|
|
1463
1675
|
console.log();
|
|
1676
|
+
console.log(chalk.bold('Decomposition pass (backend AND frontend):'));
|
|
1677
|
+
checkbox('Re-read EVERY file you created or modified. For each, extract a function/helper/sub-component for:');
|
|
1678
|
+
console.log(chalk.yellow(' — Conditionals (e.g. `isOverdue ? "red" : "green"` → `getStatusColor(date)`)'));
|
|
1679
|
+
console.log(chalk.yellow(' — Computed values (e.g. `items.filter(...).length` → `countActiveItems(items)`)'));
|
|
1680
|
+
console.log(chalk.yellow(' — Formatting (e.g. `${price.toFixed(2)}` → `formatPrice(price)`)'));
|
|
1681
|
+
console.log(chalk.yellow(' — Data transforms, validation, request/response shaping'));
|
|
1682
|
+
console.log(chalk.yellow(' — Anything doing more than one thing → split until each piece does one clearly defined thing'));
|
|
1683
|
+
checkbox('Then look at what you just extracted — can IT be broken down further? Keep going.');
|
|
1684
|
+
checkbox('Write tests for every extracted function (same TDD: failing tests FIRST)');
|
|
1685
|
+
console.log();
|
|
1686
|
+
console.log(chalk.bold.red('TEST QUALITY SELF-CHECK (before proceeding):'));
|
|
1687
|
+
checkbox('For EACH test file: count the test cases. Fewer than 3 tests for any function is a red flag.');
|
|
1688
|
+
checkbox('For EACH tested function: read the function, count the conditional branches. Every branch MUST have a test.');
|
|
1689
|
+
checkbox('For EACH tested function: verify you test at least one error/edge case, not just happy paths.');
|
|
1690
|
+
console.log(chalk.yellow(' If a function has an if/else, switch, or ternary — each path needs its own test case.'));
|
|
1691
|
+
console.log(chalk.yellow(' If a function handles null/undefined/empty — test those inputs explicitly.'));
|
|
1692
|
+
console.log();
|
|
1464
1693
|
console.log(chalk.bold('Verify before proceeding:'));
|
|
1465
1694
|
checkbox('Run all tests and verify they pass');
|
|
1466
1695
|
checkbox(`Page files contain ONLY imports + component composition — no raw ${ctx.isExpo ? 'React Native primitives' : 'HTML tags'}`);
|
|
@@ -1471,6 +1700,8 @@ function printStep7(root, feature) {
|
|
|
1471
1700
|
console.log(chalk.dim('Reuse glossary functions when they fit naturally. Extract a new function when the use case diverges.'));
|
|
1472
1701
|
console.log();
|
|
1473
1702
|
console.log(chalk.dim('Focus on TDD for functions and extraction for components. Scenarios come in later steps.'));
|
|
1703
|
+
console.log();
|
|
1704
|
+
checkboxHandoff();
|
|
1474
1705
|
stopGate(7);
|
|
1475
1706
|
}
|
|
1476
1707
|
// ─── Step 8: Glossary ─────────────────────────────────────────────────
|
|
@@ -1539,6 +1770,15 @@ function printStep9(root, feature) {
|
|
|
1539
1770
|
console.log();
|
|
1540
1771
|
console.log(chalk.dim('Do not proceed until both component isolations and library tests pass.'));
|
|
1541
1772
|
console.log();
|
|
1773
|
+
console.log(chalk.bold.red('DECOMPOSITION & COVERAGE REVIEW (before running audit):'));
|
|
1774
|
+
checkbox('Re-read every file. Extract any logic that could be its own function/helper/sub-component.');
|
|
1775
|
+
console.log(chalk.yellow(' Code either contains logic OR brings together smaller pieces.'));
|
|
1776
|
+
console.log(chalk.yellow(' Keep extracting until each piece does one clearly defined thing.'));
|
|
1777
|
+
console.log(chalk.yellow(' For each extraction: write failing test first, then extract, then make test pass.'));
|
|
1778
|
+
checkbox('Open each test file and verify: ≥3 test cases per function, happy path + edge case + error case');
|
|
1779
|
+
checkbox('If any function has fewer tests than conditional branches, add the missing tests NOW');
|
|
1780
|
+
checkbox('Update `.codeyam/glossary.json` with any new functions before running audit');
|
|
1781
|
+
console.log();
|
|
1542
1782
|
checkbox('Run `codeyam editor audit` to verify all components have scenarios and all functions/hooks have tests');
|
|
1543
1783
|
console.log(chalk.red.bold(' The audit is a HARD GATE — step 10 will refuse to run until the audit passes.'));
|
|
1544
1784
|
console.log(chalk.dim(' The audit auto-fixes incomplete entities by running targeted analysis on just the affected files.'));
|
|
@@ -2521,11 +2761,11 @@ function printStep18(root, feature) {
|
|
|
2521
2761
|
console.log(chalk.dim(' If the user wants help, guide them through `gh repo create` or manual GitHub setup, then push.'));
|
|
2522
2762
|
console.log(chalk.dim(' Task management is handled by the ━━━ TASK ━━━ directive below.'));
|
|
2523
2763
|
console.log();
|
|
2524
|
-
|
|
2525
|
-
console.log(chalk.yellow('
|
|
2764
|
+
const port = getServerPort();
|
|
2765
|
+
console.log(chalk.bold.yellow('IMPORTANT: After the push succeeds (or the user skips it), the feature is DONE.'));
|
|
2766
|
+
console.log(chalk.yellow(` Signal the UI by running: curl -s -X POST http://localhost:${port}/api/editor-feature-complete`));
|
|
2767
|
+
console.log(chalk.yellow(' Then STOP and wait. Do NOT ask the user what to build next — the UI handles the transition.'));
|
|
2526
2768
|
console.log(chalk.yellow(' Do NOT use `codeyam editor change` or start building directly.'));
|
|
2527
|
-
console.log(chalk.yellow(' Ask the user what they want to build. Once they tell you, run `codeyam editor 1` yourself.'));
|
|
2528
|
-
console.log(chalk.yellow(' NEVER tell the user to run `codeyam editor` commands — these are internal. Just ask what to build.'));
|
|
2529
2769
|
console.log(chalk.yellow(' The change workflow is ONLY for modifications during steps 1-15, not after commit.'));
|
|
2530
2770
|
stopGate(18, { confirm: true });
|
|
2531
2771
|
}
|
|
@@ -3150,6 +3390,50 @@ function formatApiSubcommandResult(subcommand, data) {
|
|
|
3150
3390
|
return null; // journal-list, show/hide-results: keep full JSON
|
|
3151
3391
|
}
|
|
3152
3392
|
}
|
|
3393
|
+
/**
|
|
3394
|
+
* `codeyam editor handoff '{"summary":"..."}'`
|
|
3395
|
+
*
|
|
3396
|
+
* Update the handoff summary in .codeyam/config.json for other AI providers.
|
|
3397
|
+
*/
|
|
3398
|
+
function handleHandoff(jsonArg) {
|
|
3399
|
+
if (!jsonArg) {
|
|
3400
|
+
console.error(chalk.red('Error: JSON argument required.'));
|
|
3401
|
+
console.error(chalk.dim(' Usage: codeyam editor handoff \'{"summary":"Built the X component..."}\''));
|
|
3402
|
+
process.exit(1);
|
|
3403
|
+
}
|
|
3404
|
+
let summary;
|
|
3405
|
+
try {
|
|
3406
|
+
const parsed = JSON.parse(jsonArg);
|
|
3407
|
+
summary = parsed.summary;
|
|
3408
|
+
}
|
|
3409
|
+
catch {
|
|
3410
|
+
console.error(chalk.red('Error: Invalid JSON.'));
|
|
3411
|
+
process.exit(1);
|
|
3412
|
+
}
|
|
3413
|
+
if (!summary) {
|
|
3414
|
+
console.error(chalk.red('Error: "summary" field is required.'));
|
|
3415
|
+
process.exit(1);
|
|
3416
|
+
}
|
|
3417
|
+
const root = getProjectRoot();
|
|
3418
|
+
const configPath = path.join(root, '.codeyam', 'config.json');
|
|
3419
|
+
try {
|
|
3420
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
3421
|
+
const state = readState(root);
|
|
3422
|
+
const provider = config.provider || 'claude';
|
|
3423
|
+
config.handoff = {
|
|
3424
|
+
summary,
|
|
3425
|
+
lastProvider: provider,
|
|
3426
|
+
lastStep: state?.step,
|
|
3427
|
+
lastUpdated: new Date().toISOString(),
|
|
3428
|
+
};
|
|
3429
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
3430
|
+
console.log(chalk.green('✓ Handoff summary updated in .codeyam/config.json'));
|
|
3431
|
+
}
|
|
3432
|
+
catch (err) {
|
|
3433
|
+
console.error(chalk.red(`Error: Could not update config.json: ${err.message}`));
|
|
3434
|
+
process.exit(1);
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3153
3437
|
/**
|
|
3154
3438
|
* `codeyam editor register '{"name":"...","componentName":"...",...}'`
|
|
3155
3439
|
*
|
|
@@ -4018,7 +4302,12 @@ async function handleAudit(options) {
|
|
|
4018
4302
|
let detail;
|
|
4019
4303
|
switch (f.status) {
|
|
4020
4304
|
case 'ok':
|
|
4021
|
-
|
|
4305
|
+
if (f.testCaseCount !== undefined && f.testCaseCount < 3) {
|
|
4306
|
+
detail = chalk.yellow(` (${f.testFile}) — ⚠ only ${f.testCaseCount} test case${f.testCaseCount !== 1 ? 's' : ''}, consider adding more`);
|
|
4307
|
+
}
|
|
4308
|
+
else {
|
|
4309
|
+
detail = chalk.dim(` (${f.testFile}${f.testCaseCount !== undefined ? `, ${f.testCaseCount} tests` : ''})`);
|
|
4310
|
+
}
|
|
4022
4311
|
break;
|
|
4023
4312
|
case 'runner_error':
|
|
4024
4313
|
detail = chalk.red(` — test runner crashed: ${f.testFile}`);
|
|
@@ -4051,6 +4340,9 @@ async function handleAudit(options) {
|
|
|
4051
4340
|
}
|
|
4052
4341
|
console.log(` ${icon} ${f.name}${detail}`);
|
|
4053
4342
|
}
|
|
4343
|
+
if (summary.functionsThinCoverage > 0) {
|
|
4344
|
+
console.log(chalk.yellow.bold(` ⚠ ${summary.functionsThinCoverage} function${summary.functionsThinCoverage !== 1 ? 's' : ''} with thin test coverage (< 3 test cases). Add more tests to cover all branches.`));
|
|
4345
|
+
}
|
|
4054
4346
|
console.log();
|
|
4055
4347
|
}
|
|
4056
4348
|
// Missing from glossary
|
|
@@ -4624,6 +4916,10 @@ async function handleTemplate() {
|
|
|
4624
4916
|
if (stack?.supportedFormats) {
|
|
4625
4917
|
config.appFormats = stack.supportedFormats;
|
|
4626
4918
|
}
|
|
4919
|
+
// Pre-populate tech stack from template
|
|
4920
|
+
if (stack) {
|
|
4921
|
+
config.techStack = getTechStackForTemplate(stack.id);
|
|
4922
|
+
}
|
|
4627
4923
|
// Set mobile-first defaults for mobile-app projects
|
|
4628
4924
|
if (stack?.supportedFormats?.includes('mobile-app')) {
|
|
4629
4925
|
config.defaultScreenSize = {
|
|
@@ -5296,6 +5592,11 @@ const editorCommand = {
|
|
|
5296
5592
|
}
|
|
5297
5593
|
return;
|
|
5298
5594
|
}
|
|
5595
|
+
// Subcommand: codeyam editor handoff '{"summary":"..."}'
|
|
5596
|
+
if (argv.step === 'handoff') {
|
|
5597
|
+
await handleHandoff(argv.json || '');
|
|
5598
|
+
return;
|
|
5599
|
+
}
|
|
5299
5600
|
// Subcommand: codeyam editor register '{"name":"..."}'
|
|
5300
5601
|
if (argv.step === 'register') {
|
|
5301
5602
|
await handleRegister(argv.json || '');
|
|
@@ -5893,6 +6194,7 @@ const editorCommand = {
|
|
|
5893
6194
|
process.exit(1);
|
|
5894
6195
|
}
|
|
5895
6196
|
}
|
|
6197
|
+
printHandoffContext(root);
|
|
5896
6198
|
switch (step) {
|
|
5897
6199
|
case 1: {
|
|
5898
6200
|
const feature = argv.feature || undefined;
|