@codeyam/codeyam-cli 0.1.0-staging.ea73141 → 0.1.0-staging.f3b710d
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 +7 -7
- 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 +39 -3
- package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js.map +1 -1
- package/codeyam-cli/src/commands/editor.js +365 -5
- package/codeyam-cli/src/commands/editor.js.map +1 -1
- package/codeyam-cli/src/commands/init.js +20 -0
- package/codeyam-cli/src/commands/init.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/devServerState.test.js +93 -1
- package/codeyam-cli/src/utils/__tests__/devServerState.test.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 +1108 -0
- package/codeyam-cli/src/utils/__tests__/editorRoadmap.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/envFile.test.js +125 -0
- package/codeyam-cli/src/utils/__tests__/envFile.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/handoffContext.test.js +500 -0
- package/codeyam-cli/src/utils/__tests__/handoffContext.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/devServerState.js +32 -0
- package/codeyam-cli/src/utils/devServerState.js.map +1 -1
- 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 +574 -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/envFile.js +90 -0
- package/codeyam-cli/src/utils/envFile.js.map +1 -0
- package/codeyam-cli/src/utils/handoffContext.js +257 -0
- package/codeyam-cli/src/utils/handoffContext.js.map +1 -0
- package/codeyam-cli/src/utils/install-skills.js +36 -6
- package/codeyam-cli/src/utils/install-skills.js.map +1 -1
- package/codeyam-cli/src/utils/techStackConfig.js +38 -0
- package/codeyam-cli/src/utils/techStackConfig.js.map +1 -0
- package/codeyam-cli/src/utils/techStackConfig.test.js +85 -0
- package/codeyam-cli/src/utils/techStackConfig.test.js.map +1 -0
- 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__/buildPtyEnv.test.js +119 -1
- package/codeyam-cli/src/webserver/__tests__/buildPtyEnv.test.js.map +1 -1
- package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +354 -1
- 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-Bs2_Oua4.js} +2 -2
- 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-database-verify-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-github-verify-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-handoff-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-hosting-verify-l0sNRNKZ.js +1 -0
- 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)-DhtVC4aI.js +161 -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._-pc-vc6wO.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-L-aUIeux.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-79d0d81a.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-L2V0jea7.js} +6 -6
- 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-QgInFGdU.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/{index-WHdB6WTN.js → index-zblh9auj.js} +1 -1
- package/codeyam-cli/src/webserver/build/server/assets/init-DaE0CBjk.js +14 -0
- package/codeyam-cli/src/webserver/build/server/assets/server-build-CNvgz1cC.js +853 -0
- 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 +255 -20
- 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 +102 -11
- package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
- package/codeyam-cli/templates/codeyam-editor-codex.md +61 -0
- package/codeyam-cli/templates/codeyam-editor-gemini.md +59 -0
- package/codeyam-cli/templates/editor-step-hook.py +4 -4
- package/codeyam-cli/templates/expo-react-native/MOBILE_SETUP.md +36 -1
- package/codeyam-cli/templates/expo-react-native/app.json +11 -0
- package/codeyam-cli/templates/expo-react-native/package.json +1 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/gitignore +1 -0
- package/codeyam-cli/templates/seed-adapters/supabase.ts +185 -84
- 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
- package/codeyam-cli/src/webserver/build/server/assets/server-build-DZbLY6O_.js +0 -690
|
@@ -24,7 +24,9 @@ import { buildEditorApiRequest, callEditorApi, EDITOR_API_SUBCOMMANDS, } from ".
|
|
|
24
24
|
import { parseRegisterArg } from "../utils/parseRegisterArg.js";
|
|
25
25
|
import { classifyRegistrationResult } from "../utils/registerScenarioResult.js";
|
|
26
26
|
import { sanitizeGlossaryEntries } from "../utils/editorLoaderHelpers.js";
|
|
27
|
+
import { updateHandoffProgress } from "../utils/handoffContext.js";
|
|
27
28
|
import { readMigrationState, writeMigrationState, advanceToNextPage, completePage, getMigrationResumeInfo, } from "../utils/editorMigration.js";
|
|
29
|
+
import { getDisplayVersion } from "../utils/versionInfo.js";
|
|
28
30
|
const __filename = fileURLToPath(import.meta.url);
|
|
29
31
|
const __dirname = path.dirname(__filename);
|
|
30
32
|
const STEP_LABELS = {
|
|
@@ -227,6 +229,143 @@ function getTechStackContext(root) {
|
|
|
227
229
|
: 'FEATURE_PATTERNS.md',
|
|
228
230
|
};
|
|
229
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* Returns a pre-populated tech stack for a given template ID.
|
|
234
|
+
* Written to .codeyam/config.json during `codeyam editor template`.
|
|
235
|
+
*/
|
|
236
|
+
function getTechStackForTemplate(templateId) {
|
|
237
|
+
switch (templateId) {
|
|
238
|
+
case 'nextjs-prisma-sqlite':
|
|
239
|
+
return {
|
|
240
|
+
languages: [
|
|
241
|
+
{
|
|
242
|
+
name: 'TypeScript',
|
|
243
|
+
url: 'https://typescriptlang.org',
|
|
244
|
+
description: 'Statically typed JavaScript superset',
|
|
245
|
+
version: '5',
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
frameworks: [
|
|
249
|
+
{
|
|
250
|
+
name: 'Next.js',
|
|
251
|
+
url: 'https://nextjs.org',
|
|
252
|
+
description: 'Full-stack React framework with App Router, SSR, and API routes',
|
|
253
|
+
version: '15',
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
name: 'React',
|
|
257
|
+
url: 'https://react.dev',
|
|
258
|
+
description: 'Component-based UI library',
|
|
259
|
+
version: '19',
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
databases: [
|
|
263
|
+
{
|
|
264
|
+
name: 'SQLite',
|
|
265
|
+
url: 'https://sqlite.org',
|
|
266
|
+
description: 'Embedded relational database — zero config, upgradeable to hosted DB',
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
libraries: [
|
|
270
|
+
{
|
|
271
|
+
name: 'Prisma',
|
|
272
|
+
url: 'https://prisma.io',
|
|
273
|
+
description: 'Type-safe database ORM and query builder',
|
|
274
|
+
version: '7',
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: 'Tailwind CSS',
|
|
278
|
+
url: 'https://tailwindcss.com',
|
|
279
|
+
description: 'Utility-first CSS framework',
|
|
280
|
+
version: '4',
|
|
281
|
+
},
|
|
282
|
+
],
|
|
283
|
+
};
|
|
284
|
+
case 'chrome-extension-react':
|
|
285
|
+
return {
|
|
286
|
+
languages: [
|
|
287
|
+
{
|
|
288
|
+
name: 'TypeScript',
|
|
289
|
+
url: 'https://typescriptlang.org',
|
|
290
|
+
description: 'Statically typed JavaScript superset',
|
|
291
|
+
version: '5',
|
|
292
|
+
},
|
|
293
|
+
],
|
|
294
|
+
frameworks: [
|
|
295
|
+
{
|
|
296
|
+
name: 'React',
|
|
297
|
+
url: 'https://react.dev',
|
|
298
|
+
description: 'Component-based UI library for the popup and options pages',
|
|
299
|
+
version: '19',
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
name: 'Vite',
|
|
303
|
+
url: 'https://vite.dev',
|
|
304
|
+
description: 'Fast build tool and dev server',
|
|
305
|
+
version: '6',
|
|
306
|
+
},
|
|
307
|
+
],
|
|
308
|
+
libraries: [
|
|
309
|
+
{
|
|
310
|
+
name: 'Tailwind CSS',
|
|
311
|
+
url: 'https://tailwindcss.com',
|
|
312
|
+
description: 'Utility-first CSS framework',
|
|
313
|
+
version: '4',
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
infrastructure: [
|
|
317
|
+
{
|
|
318
|
+
name: 'Chrome Manifest V3',
|
|
319
|
+
url: 'https://developer.chrome.com/docs/extensions/develop/migrate/what-is-mv3',
|
|
320
|
+
description: 'Extension platform with service workers, declarative APIs, and chrome.storage',
|
|
321
|
+
},
|
|
322
|
+
],
|
|
323
|
+
};
|
|
324
|
+
case 'expo-react-native':
|
|
325
|
+
return {
|
|
326
|
+
languages: [
|
|
327
|
+
{
|
|
328
|
+
name: 'TypeScript',
|
|
329
|
+
url: 'https://typescriptlang.org',
|
|
330
|
+
description: 'Statically typed JavaScript superset',
|
|
331
|
+
version: '5',
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
frameworks: [
|
|
335
|
+
{
|
|
336
|
+
name: 'Expo',
|
|
337
|
+
url: 'https://expo.dev',
|
|
338
|
+
description: 'React Native development platform with managed workflow and OTA updates',
|
|
339
|
+
version: 'SDK 54',
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: 'React Native',
|
|
343
|
+
url: 'https://reactnative.dev',
|
|
344
|
+
description: 'Cross-platform mobile UI framework',
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
name: 'Expo Router',
|
|
348
|
+
url: 'https://docs.expo.dev/router/introduction/',
|
|
349
|
+
description: 'File-based navigation for React Native apps',
|
|
350
|
+
},
|
|
351
|
+
],
|
|
352
|
+
libraries: [
|
|
353
|
+
{
|
|
354
|
+
name: 'NativeWind',
|
|
355
|
+
url: 'https://www.nativewind.dev',
|
|
356
|
+
description: 'Tailwind CSS for React Native',
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
name: 'AsyncStorage',
|
|
360
|
+
url: 'https://react-native-async-storage.github.io/async-storage/',
|
|
361
|
+
description: 'Persistent key-value storage for React Native',
|
|
362
|
+
},
|
|
363
|
+
],
|
|
364
|
+
};
|
|
365
|
+
default:
|
|
366
|
+
return {};
|
|
367
|
+
}
|
|
368
|
+
}
|
|
230
369
|
/**
|
|
231
370
|
* Print dimension guidance when the project has multiple screen sizes.
|
|
232
371
|
* Tells Claude to pick the right dimension for the content being previewed
|
|
@@ -250,11 +389,63 @@ function checkbox(text) {
|
|
|
250
389
|
const highlighted = text.replace(/`([^`]+)`/g, (_m, code) => chalk.cyan(code));
|
|
251
390
|
console.log(` ${chalk.dim('[ ]')} ${highlighted}`);
|
|
252
391
|
}
|
|
392
|
+
/**
|
|
393
|
+
* Print a checklist item for the handoff summary.
|
|
394
|
+
*/
|
|
395
|
+
function checkboxHandoff() {
|
|
396
|
+
checkbox('Update the handoff summary in `.codeyam/config.json` for the next session/AI: `codeyam editor handoff \'{"summary":"..."}\'`');
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Print the handoff context from a previous session or AI provider.
|
|
400
|
+
* Prefers the auto-generated handoff-context.md over the raw config summary.
|
|
401
|
+
*/
|
|
402
|
+
function printHandoffContext(root) {
|
|
403
|
+
try {
|
|
404
|
+
// Check for auto-generated handoff context (richer, includes progress timeline)
|
|
405
|
+
const handoffContextPath = path.join(root, '.codeyam', 'handoff-context.md');
|
|
406
|
+
if (fs.existsSync(handoffContextPath)) {
|
|
407
|
+
const content = fs.readFileSync(handoffContextPath, 'utf8');
|
|
408
|
+
console.log();
|
|
409
|
+
console.log(chalk.bold.magenta('━━━ PROVIDER HANDOFF CONTEXT ━━━'));
|
|
410
|
+
console.log(chalk.magenta(content));
|
|
411
|
+
console.log(chalk.bold.magenta('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
412
|
+
console.log();
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
// Fall back to config.json handoff summary
|
|
416
|
+
const configPath = path.join(root, '.codeyam', 'config.json');
|
|
417
|
+
if (!fs.existsSync(configPath))
|
|
418
|
+
return;
|
|
419
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
420
|
+
const handoff = config.handoff;
|
|
421
|
+
if (!handoff || !handoff.summary)
|
|
422
|
+
return;
|
|
423
|
+
console.log();
|
|
424
|
+
console.log(chalk.bold.magenta(`━━━ HANDOFF FROM ${String(handoff.lastProvider || 'unknown').toUpperCase()} (Step ${handoff.lastStep || 'unknown'}) ━━━`));
|
|
425
|
+
console.log(chalk.magenta(handoff.summary));
|
|
426
|
+
if (handoff.lastUpdated) {
|
|
427
|
+
console.log(chalk.dim(` Updated: ${handoff.lastUpdated}`));
|
|
428
|
+
}
|
|
429
|
+
console.log(chalk.bold.magenta('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
430
|
+
console.log();
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
// Non-fatal
|
|
434
|
+
}
|
|
435
|
+
}
|
|
253
436
|
/**
|
|
254
437
|
* Instructions for creating/updating .codeyam/data-structure.json.
|
|
255
438
|
* Only prints creation instructions if the file doesn't exist yet.
|
|
256
439
|
* If it exists, reminds Claude to update it if data models changed.
|
|
257
440
|
*/
|
|
441
|
+
function printServiceRecordingReminder(port) {
|
|
442
|
+
console.log(chalk.bold('Third-party services:'));
|
|
443
|
+
checkbox('When integrating any external service (auth, email, payments, storage, telemetry), update the tech stack');
|
|
444
|
+
console.log(chalk.dim(' Include the service name, URL, description, and envKeys (environment variable names it requires).'));
|
|
445
|
+
console.log(chalk.dim(` curl -s -X POST http://localhost:${port}/api/editor-project-info -H "Content-Type: application/json" \\`));
|
|
446
|
+
console.log(chalk.dim(` -d '{"techStack": {"services": [{"name":"Stripe","url":"https://stripe.com","description":"Payments","envKeys":["STRIPE_SECRET_KEY","STRIPE_PUBLISHABLE_KEY"]}]}}'`));
|
|
447
|
+
console.log(chalk.dim(' This ensures the deploy roadmap tracks all services that need production credentials.'));
|
|
448
|
+
}
|
|
258
449
|
function printDataStructureInstructions() {
|
|
259
450
|
const root = getProjectRoot();
|
|
260
451
|
const dsPath = path.join(root, '.codeyam', 'data-structure.json');
|
|
@@ -376,6 +567,12 @@ function printExtractionPlanInstructions() {
|
|
|
376
567
|
console.log(chalk.yellow(' Every component that renders multiple distinct sections should be split into sub-components.'));
|
|
377
568
|
console.log(chalk.yellow(' If a component has N visually distinct parts, it should compose N sub-components.'));
|
|
378
569
|
console.log();
|
|
570
|
+
console.log(chalk.bold.red('THE DECOMPOSITION RULE: All code should do one thing.'));
|
|
571
|
+
console.log(chalk.yellow(' Code either contains logic OR brings together smaller pieces to form a coordinated whole.'));
|
|
572
|
+
console.log(chalk.yellow(' Every opportunity to extract code into a sensible function, helper, or sub-component MUST be taken.'));
|
|
573
|
+
console.log(chalk.yellow(' Then extract AGAIN from the extracted code — keep going until each piece does one clearly defined thing.'));
|
|
574
|
+
console.log(chalk.yellow(' This applies to ALL code: backend routes, business logic, frontend components, utilities — everything.'));
|
|
575
|
+
console.log();
|
|
379
576
|
console.log(chalk.bold('Checklist:'));
|
|
380
577
|
checkbox('Read `.codeyam/glossary.json` — note reusable functions/components');
|
|
381
578
|
checkbox('Read EVERY file used by this page/feature');
|
|
@@ -386,6 +583,12 @@ function printExtractionPlanInstructions() {
|
|
|
386
583
|
console.log(chalk.yellow(' Functions: data transforms, calculations, formatting, validation,'));
|
|
387
584
|
console.log(chalk.yellow(' API response shaping, any logic that is not directly about rendering'));
|
|
388
585
|
console.log(chalk.yellow(' Hooks: data fetching, state management, side effects'));
|
|
586
|
+
console.log(chalk.yellow(' Inline logic — backend AND frontend (MUST be extracted as named functions):'));
|
|
587
|
+
console.log(chalk.yellow(' conditionals/ternaries, computed/derived values, data transformations,'));
|
|
588
|
+
console.log(chalk.yellow(' string formatting/interpolation, array filtering/sorting/mapping callbacks,'));
|
|
589
|
+
console.log(chalk.yellow(' default value logic, null/undefined guards, date/number formatting,'));
|
|
590
|
+
console.log(chalk.yellow(' permission/role checks, status derivation (e.g. isOverdue(task)),'));
|
|
591
|
+
console.log(chalk.yellow(' request/response shaping, error message construction, config lookups'));
|
|
389
592
|
console.log();
|
|
390
593
|
checkbox('Write a numbered extraction plan listing EVERYTHING you will extract');
|
|
391
594
|
console.log(chalk.yellow(' The end state: every page file is ONLY imports + component composition.'));
|
|
@@ -396,6 +599,15 @@ function printExtractionPlanInstructions() {
|
|
|
396
599
|
console.log(chalk.yellow(' — What it is (component, function, hook)'));
|
|
397
600
|
console.log(chalk.yellow(' — Where it currently lives (source file + approximate lines)'));
|
|
398
601
|
console.log(chalk.yellow(' — Where it will go (new file path)'));
|
|
602
|
+
console.log(chalk.yellow(' — How you will test it (key inputs/outputs and edge cases)'));
|
|
603
|
+
console.log(chalk.yellow(' — What logic inside it can be further extracted as a separate testable function'));
|
|
604
|
+
console.log();
|
|
605
|
+
console.log(chalk.bold.red('BEFORE FINALIZING THE PLAN:'));
|
|
606
|
+
console.log(chalk.yellow(' Re-read every file ONE MORE TIME. For each piece of code, ask:'));
|
|
607
|
+
console.log(chalk.yellow(' 1. Does this do more than one thing? → Split it into pieces that each do one thing.'));
|
|
608
|
+
console.log(chalk.yellow(' 2. Is there logic here that could be its own function with clear inputs/outputs? → Extract it.'));
|
|
609
|
+
console.log(chalk.yellow(' 3. Can the extracted code itself be broken down further? → Keep extracting.'));
|
|
610
|
+
console.log(chalk.yellow(' If your plan has fewer functions than components, you probably missed extractable logic.'));
|
|
399
611
|
console.log();
|
|
400
612
|
console.log(chalk.dim('Present the numbered plan, then proceed to step 7 to execute it.'));
|
|
401
613
|
}
|
|
@@ -1008,6 +1220,15 @@ function printStep1(root, feature, options, userPrompt) {
|
|
|
1008
1220
|
console.log(chalk.dim(' -H "Content-Type: application/json" \\'));
|
|
1009
1221
|
console.log(chalk.dim(' -d \'{"projectTitle":"My App","projectDescription":"A short description of what this app does"}\''));
|
|
1010
1222
|
console.log();
|
|
1223
|
+
checkbox('Detect and set the project tech stack:');
|
|
1224
|
+
console.log(chalk.dim(' Scan package.json, framework configs (.env, .env.example, tsconfig.json, next.config.*, prisma/schema.prisma, etc.)'));
|
|
1225
|
+
console.log(chalk.dim(' to detect languages, frameworks, databases, services, libraries, and infrastructure.'));
|
|
1226
|
+
console.log(chalk.dim(' Each item MUST have name, url, and description. version and envKeys are optional.'));
|
|
1227
|
+
console.log(chalk.dim(` curl -s -X POST http://localhost:${port}/api/editor-project-info \\`));
|
|
1228
|
+
console.log(chalk.dim(' -H "Content-Type: application/json" \\'));
|
|
1229
|
+
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":[]}}\''));
|
|
1230
|
+
console.log(chalk.dim(' Replace the example values with what you detect in this project. Omit empty categories.'));
|
|
1231
|
+
console.log();
|
|
1011
1232
|
const designSystem = readDesignSystem(root);
|
|
1012
1233
|
if (designSystem) {
|
|
1013
1234
|
console.log(chalk.bold.magenta('Design System (from .codeyam/design-system.md):'));
|
|
@@ -1021,6 +1242,8 @@ function printStep1(root, feature, options, userPrompt) {
|
|
|
1021
1242
|
console.log(chalk.yellow(' Option 2 label: "I\'d like some changes"') +
|
|
1022
1243
|
chalk.dim(' — user describes changes, you revise the plan, then re-present'));
|
|
1023
1244
|
console.log();
|
|
1245
|
+
checkboxHandoff();
|
|
1246
|
+
console.log();
|
|
1024
1247
|
console.log(chalk.dim('This step is for understanding user goals and getting buy-in. Code comes in Step 2.'));
|
|
1025
1248
|
console.log();
|
|
1026
1249
|
console.log(chalk.bold.red('━━━ STOP ━━━'));
|
|
@@ -1085,6 +1308,21 @@ function printStep2(root, feature) {
|
|
|
1085
1308
|
console.log();
|
|
1086
1309
|
console.log(chalk.dim(' Read MOBILE_SETUP.md for data storage, navigation, and testing patterns.'));
|
|
1087
1310
|
console.log();
|
|
1311
|
+
checkbox('Ask the user what to name the app (use AskUserQuestion), then update app.json');
|
|
1312
|
+
console.log(chalk.dim(' Update name, slug, scheme, ios.bundleIdentifier (com.codeyam.<slug>), and android.package'));
|
|
1313
|
+
console.log(chalk.dim(' Also set the projectTitle via: curl -s -X POST http://localhost:' +
|
|
1314
|
+
port +
|
|
1315
|
+
'/api/editor-project-info -H "Content-Type: application/json" -d \'{"projectTitle":"<name>"}\''));
|
|
1316
|
+
console.log();
|
|
1317
|
+
checkbox('Generate an app icon using `sharp`');
|
|
1318
|
+
console.log(chalk.dim(' Create `scripts/generate-icon.mjs` and `mkdir -p assets`'));
|
|
1319
|
+
console.log(chalk.yellow(' ICON DESIGN GOAL: The icon must look distinctive on a home screen full of other app icons.'));
|
|
1320
|
+
console.log(chalk.yellow(' Use multiple bold colors from the design system and complex, overlapping shapes.'));
|
|
1321
|
+
console.log(chalk.yellow(' NO simple/minimal icons — no single glyph on a flat background, no plain text, no basic circles.'));
|
|
1322
|
+
console.log(chalk.yellow(' Make it colorful, layered, and dense. Use gradients, multiple contrasting fills, and depth.'));
|
|
1323
|
+
console.log(chalk.dim(' Use sharp to render SVG to 1024x1024 PNG. iOS: flatten onto background (no alpha channel).'));
|
|
1324
|
+
console.log(chalk.dim(' Generate: icon.png, adaptive-icon.png, favicon.png (48x48). Run `node scripts/generate-icon.mjs`'));
|
|
1325
|
+
console.log();
|
|
1088
1326
|
}
|
|
1089
1327
|
else if (ctx.isChromeExt) {
|
|
1090
1328
|
// Chrome Extension: use chrome.storage
|
|
@@ -1133,6 +1371,10 @@ function printStep2(root, feature) {
|
|
|
1133
1371
|
console.log();
|
|
1134
1372
|
printDataStructureInstructions();
|
|
1135
1373
|
}
|
|
1374
|
+
console.log();
|
|
1375
|
+
printServiceRecordingReminder(port);
|
|
1376
|
+
console.log();
|
|
1377
|
+
checkboxHandoff();
|
|
1136
1378
|
stopGate(2);
|
|
1137
1379
|
}
|
|
1138
1380
|
// ─── Step 3: Prototype ────────────────────────────────────────────────
|
|
@@ -1219,6 +1461,10 @@ function printStep3(root, feature) {
|
|
|
1219
1461
|
console.log(chalk.dim(' Bad: color: "#333", fontSize: 14, padding: 12'));
|
|
1220
1462
|
console.log(chalk.dim(' Good: color: theme.colors.textPrimary, fontSize: theme.fontSize.sm, padding: theme.spacing.md'));
|
|
1221
1463
|
console.log(chalk.dim(' Do NOT use CSS custom properties (var(--token)) — they do not work in React Native.'));
|
|
1464
|
+
checkbox('Buttons: put backgroundColor, borderRadius, borderStyle on a wrapping <View>, NOT on <Pressable>');
|
|
1465
|
+
console.log(chalk.dim(' Pressable renders these styles on web but FAILS SILENTLY on native devices.'));
|
|
1466
|
+
console.log(chalk.dim(' Use a <View> with overflow:"hidden" for the visual shell, <Pressable> inside for touch only.'));
|
|
1467
|
+
console.log(chalk.dim(' For press feedback: use onPressIn/onPressOut + useState to toggle opacity, not function-style style.'));
|
|
1222
1468
|
}
|
|
1223
1469
|
else {
|
|
1224
1470
|
checkbox('Define ALL design tokens as CSS custom properties in globals.css — not just colors');
|
|
@@ -1245,6 +1491,9 @@ function printStep3(root, feature) {
|
|
|
1245
1491
|
console.log(chalk.red.bold(' NEVER claim "you should see X" or "the preview shows X" unless you just ran a preview command.'));
|
|
1246
1492
|
console.log(chalk.red(' The preview only updates when you explicitly refresh it. Verify, then describe.'));
|
|
1247
1493
|
console.log();
|
|
1494
|
+
printServiceRecordingReminder(port);
|
|
1495
|
+
console.log();
|
|
1496
|
+
checkboxHandoff();
|
|
1248
1497
|
stopGate(3);
|
|
1249
1498
|
}
|
|
1250
1499
|
// ─── Step 4: Verify Prototype ─────────────────────────────────────────
|
|
@@ -1302,6 +1551,8 @@ function printStep4(root, feature) {
|
|
|
1302
1551
|
console.log(chalk.dim(' A new clone should work with just: git clone → npm run setup → npm run dev'));
|
|
1303
1552
|
console.log();
|
|
1304
1553
|
console.log(chalk.dim('Focus on building the prototype. Scenarios and refactoring happen in later steps.'));
|
|
1554
|
+
console.log();
|
|
1555
|
+
checkboxHandoff();
|
|
1305
1556
|
stopGate(4);
|
|
1306
1557
|
}
|
|
1307
1558
|
// ─── Step 5: Confirm ──────────────────────────────────────────────────
|
|
@@ -1365,6 +1616,8 @@ function printStep5(root, feature) {
|
|
|
1365
1616
|
chalk.dim(' — make changes, refresh preview, re-run `codeyam editor 5`'));
|
|
1366
1617
|
console.log();
|
|
1367
1618
|
console.log(chalk.dim('Wait for user approval before moving on. Refactoring and scenarios happen in later steps.'));
|
|
1619
|
+
console.log();
|
|
1620
|
+
checkboxHandoff();
|
|
1368
1621
|
stopGate(5, { confirm: true });
|
|
1369
1622
|
}
|
|
1370
1623
|
// ─── Step 6: Deconstruct ──────────────────────────────────────────────
|
|
@@ -1390,6 +1643,8 @@ function printStep6(root, feature) {
|
|
|
1390
1643
|
console.log(chalk.yellow('This step is read and plan only. Code extraction happens in step 7.'));
|
|
1391
1644
|
console.log();
|
|
1392
1645
|
printExtractionPlanInstructions();
|
|
1646
|
+
console.log();
|
|
1647
|
+
checkboxHandoff();
|
|
1393
1648
|
stopGate(6);
|
|
1394
1649
|
}
|
|
1395
1650
|
// ─── Step 7: Extract ──────────────────────────────────────────────────
|
|
@@ -1426,6 +1681,9 @@ function printStep7(root, feature) {
|
|
|
1426
1681
|
checkbox('For each function/hook: write MULTIPLE failing tests FIRST, then extract to make them pass');
|
|
1427
1682
|
console.log(chalk.dim(' Cover: typical inputs, edge cases, empty/null inputs, error conditions'));
|
|
1428
1683
|
console.log(chalk.dim(' Aim for 3-8 test cases per function depending on complexity'));
|
|
1684
|
+
console.log(chalk.dim(' EVERY conditional branch in the function MUST have a test that exercises it'));
|
|
1685
|
+
console.log(chalk.dim(' EVERY return path MUST be tested — if a function can return 3 different things, write 3+ tests'));
|
|
1686
|
+
console.log(chalk.dim(' Boundary values: 0, 1, -1, empty string, empty array, undefined, null'));
|
|
1429
1687
|
console.log(chalk.dim(' Hooks count as functions — useDrinks, useAuth, etc. all need test files'));
|
|
1430
1688
|
console.log(chalk.dim(' Wrap all tests in a describe("FunctionName", ...) block — the audit matches on this name'));
|
|
1431
1689
|
if (ctx.isExpo) {
|
|
@@ -1442,6 +1700,23 @@ function printStep7(root, feature) {
|
|
|
1442
1700
|
console.log(chalk.yellow(` Check: does any file contain raw ${ctx.rawPrimitivesList}?`));
|
|
1443
1701
|
console.log(chalk.yellow(' If yes → that JSX section is a component waiting to be extracted.'));
|
|
1444
1702
|
console.log();
|
|
1703
|
+
console.log(chalk.bold('Decomposition pass (backend AND frontend):'));
|
|
1704
|
+
checkbox('Re-read EVERY file you created or modified. For each, extract a function/helper/sub-component for:');
|
|
1705
|
+
console.log(chalk.yellow(' — Conditionals (e.g. `isOverdue ? "red" : "green"` → `getStatusColor(date)`)'));
|
|
1706
|
+
console.log(chalk.yellow(' — Computed values (e.g. `items.filter(...).length` → `countActiveItems(items)`)'));
|
|
1707
|
+
console.log(chalk.yellow(' — Formatting (e.g. `${price.toFixed(2)}` → `formatPrice(price)`)'));
|
|
1708
|
+
console.log(chalk.yellow(' — Data transforms, validation, request/response shaping'));
|
|
1709
|
+
console.log(chalk.yellow(' — Anything doing more than one thing → split until each piece does one clearly defined thing'));
|
|
1710
|
+
checkbox('Then look at what you just extracted — can IT be broken down further? Keep going.');
|
|
1711
|
+
checkbox('Write tests for every extracted function (same TDD: failing tests FIRST)');
|
|
1712
|
+
console.log();
|
|
1713
|
+
console.log(chalk.bold.red('TEST QUALITY SELF-CHECK (before proceeding):'));
|
|
1714
|
+
checkbox('For EACH test file: count the test cases. Fewer than 3 tests for any function is a red flag.');
|
|
1715
|
+
checkbox('For EACH tested function: read the function, count the conditional branches. Every branch MUST have a test.');
|
|
1716
|
+
checkbox('For EACH tested function: verify you test at least one error/edge case, not just happy paths.');
|
|
1717
|
+
console.log(chalk.yellow(' If a function has an if/else, switch, or ternary — each path needs its own test case.'));
|
|
1718
|
+
console.log(chalk.yellow(' If a function handles null/undefined/empty — test those inputs explicitly.'));
|
|
1719
|
+
console.log();
|
|
1445
1720
|
console.log(chalk.bold('Verify before proceeding:'));
|
|
1446
1721
|
checkbox('Run all tests and verify they pass');
|
|
1447
1722
|
checkbox(`Page files contain ONLY imports + component composition — no raw ${ctx.isExpo ? 'React Native primitives' : 'HTML tags'}`);
|
|
@@ -1452,6 +1727,8 @@ function printStep7(root, feature) {
|
|
|
1452
1727
|
console.log(chalk.dim('Reuse glossary functions when they fit naturally. Extract a new function when the use case diverges.'));
|
|
1453
1728
|
console.log();
|
|
1454
1729
|
console.log(chalk.dim('Focus on TDD for functions and extraction for components. Scenarios come in later steps.'));
|
|
1730
|
+
console.log();
|
|
1731
|
+
checkboxHandoff();
|
|
1455
1732
|
stopGate(7);
|
|
1456
1733
|
}
|
|
1457
1734
|
// ─── Step 8: Glossary ─────────────────────────────────────────────────
|
|
@@ -1520,6 +1797,15 @@ function printStep9(root, feature) {
|
|
|
1520
1797
|
console.log();
|
|
1521
1798
|
console.log(chalk.dim('Do not proceed until both component isolations and library tests pass.'));
|
|
1522
1799
|
console.log();
|
|
1800
|
+
console.log(chalk.bold.red('DECOMPOSITION & COVERAGE REVIEW (before running audit):'));
|
|
1801
|
+
checkbox('Re-read every file. Extract any logic that could be its own function/helper/sub-component.');
|
|
1802
|
+
console.log(chalk.yellow(' Code either contains logic OR brings together smaller pieces.'));
|
|
1803
|
+
console.log(chalk.yellow(' Keep extracting until each piece does one clearly defined thing.'));
|
|
1804
|
+
console.log(chalk.yellow(' For each extraction: write failing test first, then extract, then make test pass.'));
|
|
1805
|
+
checkbox('Open each test file and verify: ≥3 test cases per function, happy path + edge case + error case');
|
|
1806
|
+
checkbox('If any function has fewer tests than conditional branches, add the missing tests NOW');
|
|
1807
|
+
checkbox('Update `.codeyam/glossary.json` with any new functions before running audit');
|
|
1808
|
+
console.log();
|
|
1523
1809
|
checkbox('Run `codeyam editor audit` to verify all components have scenarios and all functions/hooks have tests');
|
|
1524
1810
|
console.log(chalk.red.bold(' The audit is a HARD GATE — step 10 will refuse to run until the audit passes.'));
|
|
1525
1811
|
console.log(chalk.dim(' The audit auto-fixes incomplete entities by running targeted analysis on just the affected files.'));
|
|
@@ -1763,6 +2049,8 @@ function printStep14(root, feature) {
|
|
|
1763
2049
|
checkbox('Fix or remove any broken images before continuing');
|
|
1764
2050
|
checkbox('Recapture stale scenarios: `codeyam editor recapture-stale`');
|
|
1765
2051
|
checkbox('Run `codeyam editor audit` to verify completeness of scenarios and tests');
|
|
2052
|
+
checkbox('Verify tech stack is up to date: check for any new service imports (e.g. Stripe, Resend, Supabase) and ensure they appear in the tech stack with `envKeys`');
|
|
2053
|
+
console.log(chalk.dim(` Update via: curl -s -X POST http://localhost:${port}/api/editor-project-info -H "Content-Type: application/json" -d '{"techStack": {...}}'`));
|
|
1766
2054
|
checkbox('Do not proceed until all checks pass');
|
|
1767
2055
|
stopGate(14);
|
|
1768
2056
|
}
|
|
@@ -2502,11 +2790,11 @@ function printStep18(root, feature) {
|
|
|
2502
2790
|
console.log(chalk.dim(' If the user wants help, guide them through `gh repo create` or manual GitHub setup, then push.'));
|
|
2503
2791
|
console.log(chalk.dim(' Task management is handled by the ━━━ TASK ━━━ directive below.'));
|
|
2504
2792
|
console.log();
|
|
2505
|
-
|
|
2506
|
-
console.log(chalk.yellow('
|
|
2793
|
+
const port = getServerPort();
|
|
2794
|
+
console.log(chalk.bold.yellow('IMPORTANT: After the push succeeds (or the user skips it), the feature is DONE.'));
|
|
2795
|
+
console.log(chalk.yellow(` Signal the UI by running: curl -s -X POST http://localhost:${port}/api/editor-feature-complete`));
|
|
2796
|
+
console.log(chalk.yellow(' Then STOP and wait. Do NOT ask the user what to build next — the UI handles the transition.'));
|
|
2507
2797
|
console.log(chalk.yellow(' Do NOT use `codeyam editor change` or start building directly.'));
|
|
2508
|
-
console.log(chalk.yellow(' Ask the user what they want to build. Once they tell you, run `codeyam editor 1` yourself.'));
|
|
2509
|
-
console.log(chalk.yellow(' NEVER tell the user to run `codeyam editor` commands — these are internal. Just ask what to build.'));
|
|
2510
2798
|
console.log(chalk.yellow(' The change workflow is ONLY for modifications during steps 1-15, not after commit.'));
|
|
2511
2799
|
stopGate(18, { confirm: true });
|
|
2512
2800
|
}
|
|
@@ -3131,6 +3419,50 @@ function formatApiSubcommandResult(subcommand, data) {
|
|
|
3131
3419
|
return null; // journal-list, show/hide-results: keep full JSON
|
|
3132
3420
|
}
|
|
3133
3421
|
}
|
|
3422
|
+
/**
|
|
3423
|
+
* `codeyam editor handoff '{"summary":"..."}'`
|
|
3424
|
+
*
|
|
3425
|
+
* Update the handoff summary in .codeyam/config.json for other AI providers.
|
|
3426
|
+
*/
|
|
3427
|
+
function handleHandoff(jsonArg) {
|
|
3428
|
+
if (!jsonArg) {
|
|
3429
|
+
console.error(chalk.red('Error: JSON argument required.'));
|
|
3430
|
+
console.error(chalk.dim(' Usage: codeyam editor handoff \'{"summary":"Built the X component..."}\''));
|
|
3431
|
+
process.exit(1);
|
|
3432
|
+
}
|
|
3433
|
+
let summary;
|
|
3434
|
+
try {
|
|
3435
|
+
const parsed = JSON.parse(jsonArg);
|
|
3436
|
+
summary = parsed.summary;
|
|
3437
|
+
}
|
|
3438
|
+
catch {
|
|
3439
|
+
console.error(chalk.red('Error: Invalid JSON.'));
|
|
3440
|
+
process.exit(1);
|
|
3441
|
+
}
|
|
3442
|
+
if (!summary) {
|
|
3443
|
+
console.error(chalk.red('Error: "summary" field is required.'));
|
|
3444
|
+
process.exit(1);
|
|
3445
|
+
}
|
|
3446
|
+
const root = getProjectRoot();
|
|
3447
|
+
const configPath = path.join(root, '.codeyam', 'config.json');
|
|
3448
|
+
try {
|
|
3449
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
3450
|
+
const state = readState(root);
|
|
3451
|
+
const provider = config.provider || 'claude';
|
|
3452
|
+
config.handoff = {
|
|
3453
|
+
summary,
|
|
3454
|
+
lastProvider: provider,
|
|
3455
|
+
lastStep: state?.step,
|
|
3456
|
+
lastUpdated: new Date().toISOString(),
|
|
3457
|
+
};
|
|
3458
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
3459
|
+
console.log(chalk.green('✓ Handoff summary updated in .codeyam/config.json'));
|
|
3460
|
+
}
|
|
3461
|
+
catch (err) {
|
|
3462
|
+
console.error(chalk.red(`Error: Could not update config.json: ${err.message}`));
|
|
3463
|
+
process.exit(1);
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3134
3466
|
/**
|
|
3135
3467
|
* `codeyam editor register '{"name":"...","componentName":"...",...}'`
|
|
3136
3468
|
*
|
|
@@ -3999,7 +4331,12 @@ async function handleAudit(options) {
|
|
|
3999
4331
|
let detail;
|
|
4000
4332
|
switch (f.status) {
|
|
4001
4333
|
case 'ok':
|
|
4002
|
-
|
|
4334
|
+
if (f.testCaseCount !== undefined && f.testCaseCount < 3) {
|
|
4335
|
+
detail = chalk.yellow(` (${f.testFile}) — ⚠ only ${f.testCaseCount} test case${f.testCaseCount !== 1 ? 's' : ''}, consider adding more`);
|
|
4336
|
+
}
|
|
4337
|
+
else {
|
|
4338
|
+
detail = chalk.dim(` (${f.testFile}${f.testCaseCount !== undefined ? `, ${f.testCaseCount} tests` : ''})`);
|
|
4339
|
+
}
|
|
4003
4340
|
break;
|
|
4004
4341
|
case 'runner_error':
|
|
4005
4342
|
detail = chalk.red(` — test runner crashed: ${f.testFile}`);
|
|
@@ -4032,6 +4369,9 @@ async function handleAudit(options) {
|
|
|
4032
4369
|
}
|
|
4033
4370
|
console.log(` ${icon} ${f.name}${detail}`);
|
|
4034
4371
|
}
|
|
4372
|
+
if (summary.functionsThinCoverage > 0) {
|
|
4373
|
+
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.`));
|
|
4374
|
+
}
|
|
4035
4375
|
console.log();
|
|
4036
4376
|
}
|
|
4037
4377
|
// Missing from glossary
|
|
@@ -4605,6 +4945,10 @@ async function handleTemplate() {
|
|
|
4605
4945
|
if (stack?.supportedFormats) {
|
|
4606
4946
|
config.appFormats = stack.supportedFormats;
|
|
4607
4947
|
}
|
|
4948
|
+
// Pre-populate tech stack from template
|
|
4949
|
+
if (stack) {
|
|
4950
|
+
config.techStack = getTechStackForTemplate(stack.id);
|
|
4951
|
+
}
|
|
4608
4952
|
// Set mobile-first defaults for mobile-app projects
|
|
4609
4953
|
if (stack?.supportedFormats?.includes('mobile-app')) {
|
|
4610
4954
|
config.defaultScreenSize = {
|
|
@@ -5277,6 +5621,11 @@ const editorCommand = {
|
|
|
5277
5621
|
}
|
|
5278
5622
|
return;
|
|
5279
5623
|
}
|
|
5624
|
+
// Subcommand: codeyam editor handoff '{"summary":"..."}'
|
|
5625
|
+
if (argv.step === 'handoff') {
|
|
5626
|
+
await handleHandoff(argv.json || '');
|
|
5627
|
+
return;
|
|
5628
|
+
}
|
|
5280
5629
|
// Subcommand: codeyam editor register '{"name":"..."}'
|
|
5281
5630
|
if (argv.step === 'register') {
|
|
5282
5631
|
await handleRegister(argv.json || '');
|
|
@@ -5459,10 +5808,18 @@ const editorCommand = {
|
|
|
5459
5808
|
try {
|
|
5460
5809
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
5461
5810
|
const { projectSlug } = config;
|
|
5811
|
+
// Detect provider switch and inform the user
|
|
5812
|
+
const handoff = config.handoff;
|
|
5813
|
+
const currentProvider = config.provider || 'claude';
|
|
5814
|
+
if (handoff?.lastProvider && handoff.lastProvider !== currentProvider) {
|
|
5815
|
+
console.log(chalk.yellow(` Provider changed: ${handoff.lastProvider} → ${currentProvider}`));
|
|
5816
|
+
console.log(chalk.dim(' The editor will offer to continue with handoff context.'));
|
|
5817
|
+
}
|
|
5462
5818
|
if (!projectSlug) {
|
|
5463
5819
|
errorLog('Missing project slug. Try reinitializing with: `codeyam editor template`');
|
|
5464
5820
|
return;
|
|
5465
5821
|
}
|
|
5822
|
+
console.log(chalk.dim(` CodeYam Editor v${getDisplayVersion()}`));
|
|
5466
5823
|
const connectionOk = await withoutSpinner(() => testEnvironment());
|
|
5467
5824
|
if (!connectionOk) {
|
|
5468
5825
|
errorLog('Environment validation failed');
|
|
@@ -5874,6 +6231,9 @@ const editorCommand = {
|
|
|
5874
6231
|
process.exit(1);
|
|
5875
6232
|
}
|
|
5876
6233
|
}
|
|
6234
|
+
printHandoffContext(root);
|
|
6235
|
+
// Track step progress automatically for provider handoff
|
|
6236
|
+
updateHandoffProgress(root, step);
|
|
5877
6237
|
switch (step) {
|
|
5878
6238
|
case 1: {
|
|
5879
6239
|
const feature = argv.feature || undefined;
|