@mr.dj2u/cli 0.1.14 → 0.1.16
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/bundles/claude-code/.claude-plugin/plugin.json +1 -1
- package/bundles/claude-code/.mcp.json +1 -1
- package/bundles/claude-code/commands/create-expo-super-stack.md +8 -10
- package/bundles/claude-code/skills/create-expo-super-stack/SKILL.md +8 -10
- package/bundles/codex/.codex-plugin/plugin.json +1 -1
- package/bundles/codex/.mcp.json +1 -1
- package/bundles/codex/commands/create-expo-super-stack.md +8 -10
- package/bundles/codex/skills/workflow-create-expo-super-stack/SKILL.md +8 -10
- package/bundles/vscode-copilot/.github/prompts/create-expo-super-stack.prompt.md +8 -10
- package/bundles/vscode-copilot/.vscode/mcp.json +1 -1
- package/bundles/vscode-copilot/user/.copilot/skills/workflow-create-expo-super-stack/SKILL.md +8 -10
- package/dist/cess-intake.d.ts +1 -1
- package/dist/cess-intake.d.ts.map +1 -1
- package/dist/cess-intake.js +470 -111
- package/dist/cess-intake.js.map +1 -1
- package/dist/cli.js +0 -0
- package/dist/commands/mcp-install.d.ts +2 -2
- package/dist/commands/mcp-install.js +1 -1
- package/dist/commands/onboard.d.ts +1 -1
- package/dist/commands/onboard.d.ts.map +1 -1
- package/dist/project-memory.d.ts +1 -1
- package/dist/project-memory.d.ts.map +1 -1
- package/dist/project-memory.js +93 -194
- package/dist/project-memory.js.map +1 -1
- package/dist/roadmap.d.ts.map +1 -1
- package/dist/roadmap.js +15 -11
- package/dist/roadmap.js.map +1 -1
- package/package.json +76 -73
package/dist/cess-intake.js
CHANGED
|
@@ -76,6 +76,7 @@ const CESS_QUESTIONS = [
|
|
|
76
76
|
options: () => [
|
|
77
77
|
{ value: 'uniwind', label: 'Uniwind', hint: 'Default and MDS preference' },
|
|
78
78
|
{ value: 'nativewind', label: 'NativeWind' },
|
|
79
|
+
{ value: 'nativewindui', label: 'NativeWindUI' },
|
|
79
80
|
{ value: 'tamagui', label: 'Tamagui' },
|
|
80
81
|
{ value: 'restyle', label: 'Restyle' },
|
|
81
82
|
{ value: 'stylesheet', label: 'StyleSheet only' },
|
|
@@ -350,137 +351,214 @@ const CESS_QUESTIONS = [
|
|
|
350
351
|
];
|
|
351
352
|
const CESS_SNAPSHOT_START = '<!-- MDS_CESS_SNAPSHOT_START -->';
|
|
352
353
|
const CESS_SNAPSHOT_END = '<!-- MDS_CESS_SNAPSHOT_END -->';
|
|
354
|
+
const SNAPSHOT_PRIORITY = 10;
|
|
355
|
+
const TECH_STACK_PRIORITY = 20;
|
|
356
|
+
const VISIBLE_SECTION_PRIORITY = 30;
|
|
357
|
+
const DERIVED_TITLE_PRIORITY = 40;
|
|
358
|
+
const EXPLICIT_INPUT_PRIORITY = 50;
|
|
353
359
|
export function extractCessInfoFromMarkdown(input) {
|
|
354
360
|
const infoMarkdown = normalizeLineEndings(input.infoMarkdown);
|
|
355
361
|
const sections = parseMarkdownSections(infoMarkdown);
|
|
356
362
|
const evidence = {};
|
|
357
363
|
const prefilledAnswers = {};
|
|
358
364
|
const ambiguousQuestionIds = new Set();
|
|
365
|
+
const assignedAnswerSources = new Map();
|
|
359
366
|
const usedSections = new Set();
|
|
360
367
|
const explicitAppName = normalizeText(input.appName);
|
|
361
368
|
let derivedDisplayName = explicitAppName;
|
|
369
|
+
let derivedDisplayNamePriority = explicitAppName ? EXPLICIT_INPUT_PRIORITY : undefined;
|
|
370
|
+
let derivedDisplayNameNote = explicitAppName ? 'Explicit app name input' : undefined;
|
|
362
371
|
let derivedFolderSlug = explicitAppName ? slugifyAppName(explicitAppName) : undefined;
|
|
363
372
|
const recordEvidence = (key, note) => {
|
|
364
373
|
evidence[key] = [...(evidence[key] ?? []), note];
|
|
365
374
|
};
|
|
366
|
-
const assignValue = (id, value, note) => {
|
|
375
|
+
const assignValue = (id, value, note, priority = VISIBLE_SECTION_PRIORITY) => {
|
|
367
376
|
const normalized = normalizeExtractedAnswerValue(id, value);
|
|
368
377
|
if (normalized === undefined) {
|
|
369
378
|
return;
|
|
370
379
|
}
|
|
380
|
+
if (isGenericExtractedAnswerValue(id, normalized)) {
|
|
381
|
+
recordEvidence(id, `${note} ignored because it looked like scaffold/default placeholder data`);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
371
384
|
if (ambiguousQuestionIds.has(id)) {
|
|
385
|
+
const ambiguousSource = assignedAnswerSources.get(id);
|
|
386
|
+
if (priority > (ambiguousSource?.priority ?? -1)) {
|
|
387
|
+
ambiguousQuestionIds.delete(id);
|
|
388
|
+
prefilledAnswers[id] = normalized;
|
|
389
|
+
assignedAnswerSources.set(id, { priority, note });
|
|
390
|
+
recordEvidence(id, `${note} selected over earlier lower-priority ambiguous values`);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
recordEvidence(id, `${note} ignored because ${ambiguousSource?.note ?? 'another visible source'} already made this field ambiguous`);
|
|
372
394
|
return;
|
|
373
395
|
}
|
|
374
396
|
const current = prefilledAnswers[id];
|
|
397
|
+
const currentSource = assignedAnswerSources.get(id);
|
|
375
398
|
if (current !== undefined && !areAnswerValuesEquivalent(id, current, normalized)) {
|
|
399
|
+
if (priority > (currentSource?.priority ?? -1)) {
|
|
400
|
+
prefilledAnswers[id] = normalized;
|
|
401
|
+
assignedAnswerSources.set(id, { priority, note });
|
|
402
|
+
recordEvidence(id, `${note} selected over lower-priority value from ${currentSource?.note ?? 'earlier extraction'}`);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
if (priority < (currentSource?.priority ?? -1)) {
|
|
406
|
+
recordEvidence(id, `${note} ignored because ${currentSource?.note ?? 'an earlier source'} had a higher-priority value`);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
376
409
|
delete prefilledAnswers[id];
|
|
377
410
|
ambiguousQuestionIds.add(id);
|
|
411
|
+
assignedAnswerSources.set(id, {
|
|
412
|
+
priority,
|
|
413
|
+
note: `${currentSource?.note ?? 'earlier extraction'} and ${note}`,
|
|
414
|
+
});
|
|
378
415
|
recordEvidence(id, `${note} (conflicts with earlier extracted value)`);
|
|
379
416
|
return;
|
|
380
417
|
}
|
|
381
418
|
prefilledAnswers[id] = normalized;
|
|
419
|
+
assignedAnswerSources.set(id, { priority, note });
|
|
382
420
|
recordEvidence(id, note);
|
|
383
421
|
};
|
|
384
422
|
const snapshot = parseCessSnapshot(infoMarkdown);
|
|
385
423
|
if (snapshot) {
|
|
386
424
|
recordEvidence('snapshot', 'Parsed machine-readable MDS snapshot block.');
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
425
|
+
}
|
|
426
|
+
const appNameSection = getMarkdownSection(sections, 'App Name');
|
|
427
|
+
if (!derivedDisplayName && appNameSection) {
|
|
428
|
+
const appNameFromSection = normalizeSectionText(appNameSection);
|
|
429
|
+
if (appNameFromSection && !isGenericTextValue(appNameFromSection)) {
|
|
430
|
+
derivedDisplayName = appNameFromSection;
|
|
431
|
+
derivedDisplayNamePriority = VISIBLE_SECTION_PRIORITY;
|
|
432
|
+
derivedDisplayNameNote = 'App Name section';
|
|
433
|
+
derivedFolderSlug = slugifyAppName(appNameFromSection);
|
|
434
|
+
recordEvidence('appName', `Derived app name from App Name section: ${appNameFromSection}`);
|
|
396
435
|
}
|
|
436
|
+
usedSections.add('App Name');
|
|
397
437
|
}
|
|
398
438
|
const title = extractProjectTitle(infoMarkdown);
|
|
399
439
|
if (!derivedDisplayName && title) {
|
|
400
440
|
derivedDisplayName = title;
|
|
441
|
+
derivedDisplayNamePriority = DERIVED_TITLE_PRIORITY;
|
|
442
|
+
derivedDisplayNameNote = `Derived app name from title: ${title}`;
|
|
401
443
|
recordEvidence('appName', `Derived app name from title: ${title}`);
|
|
402
444
|
}
|
|
403
445
|
if (!derivedFolderSlug && derivedDisplayName) {
|
|
404
446
|
derivedFolderSlug = slugifyAppName(derivedDisplayName);
|
|
405
447
|
}
|
|
406
|
-
const targetUsers = sections
|
|
448
|
+
const targetUsers = getMarkdownSection(sections, 'Target Users');
|
|
407
449
|
if (targetUsers) {
|
|
408
450
|
usedSections.add('Target Users');
|
|
409
|
-
assignValue('audience', normalizeSectionText(targetUsers), 'Target Users section');
|
|
451
|
+
assignValue('audience', normalizeSectionText(targetUsers), 'Target Users section', VISIBLE_SECTION_PRIORITY);
|
|
410
452
|
}
|
|
411
453
|
else {
|
|
412
|
-
const overview = sections
|
|
454
|
+
const overview = getMarkdownSection(sections, 'Overview');
|
|
413
455
|
const overviewAudience = extractAudienceFromOverview(overview);
|
|
414
456
|
if (overviewAudience) {
|
|
415
457
|
usedSections.add('Overview');
|
|
416
|
-
assignValue('audience', overviewAudience, 'Overview section');
|
|
458
|
+
assignValue('audience', overviewAudience, 'Overview section', VISIBLE_SECTION_PRIORITY);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
const firstUserFlow = getMarkdownSection(sections, 'First User Flow');
|
|
462
|
+
const coreFlowsAndFeatures = getMarkdownSection(sections, 'Core Flows and Features');
|
|
463
|
+
const coreUserFlows = getMarkdownSection(sections, 'Core User Flows');
|
|
464
|
+
if (firstUserFlow || coreFlowsAndFeatures) {
|
|
465
|
+
const combinedFlows = [normalizeListSection(firstUserFlow), normalizeListSection(coreFlowsAndFeatures)]
|
|
466
|
+
.filter(Boolean)
|
|
467
|
+
.join('\n');
|
|
468
|
+
if (combinedFlows) {
|
|
469
|
+
assignValue('coreFlows', combinedFlows, 'First User Flow and Core Flows and Features sections', VISIBLE_SECTION_PRIORITY);
|
|
470
|
+
}
|
|
471
|
+
if (firstUserFlow) {
|
|
472
|
+
usedSections.add('First User Flow');
|
|
473
|
+
}
|
|
474
|
+
if (coreFlowsAndFeatures) {
|
|
475
|
+
usedSections.add('Core Flows and Features');
|
|
417
476
|
}
|
|
418
477
|
}
|
|
419
|
-
|
|
420
|
-
if (coreUserFlows) {
|
|
478
|
+
else if (coreUserFlows) {
|
|
421
479
|
usedSections.add('Core User Flows');
|
|
422
|
-
assignValue('coreFlows', normalizeListSection(coreUserFlows), 'Core User Flows section');
|
|
480
|
+
assignValue('coreFlows', normalizeListSection(coreUserFlows), 'Core User Flows section', VISIBLE_SECTION_PRIORITY);
|
|
423
481
|
}
|
|
424
|
-
const mustIncludeScreens = sections
|
|
482
|
+
const mustIncludeScreens = getMarkdownSection(sections, 'Screens', 'Must-Include Screens Or Flows');
|
|
425
483
|
if (mustIncludeScreens) {
|
|
426
|
-
usedSections.add('Must-Include Screens Or Flows');
|
|
427
|
-
assignValue('screens', normalizeListSection(mustIncludeScreens), '
|
|
484
|
+
usedSections.add(sections.has('Screens') ? 'Screens' : 'Must-Include Screens Or Flows');
|
|
485
|
+
assignValue('screens', normalizeListSection(mustIncludeScreens), 'Screens section', VISIBLE_SECTION_PRIORITY);
|
|
428
486
|
}
|
|
429
|
-
const dataAndBackend = sections
|
|
487
|
+
const dataAndBackend = getMarkdownSection(sections, 'Data And Backend');
|
|
430
488
|
if (dataAndBackend) {
|
|
431
489
|
usedSections.add('Data And Backend');
|
|
432
490
|
const inferredDataNeeds = inferDataNeedSelections(dataAndBackend);
|
|
433
491
|
if (inferredDataNeeds.length > 0) {
|
|
434
|
-
assignValue('dataNeedSelections', inferredDataNeeds, 'Data And Backend section');
|
|
492
|
+
assignValue('dataNeedSelections', inferredDataNeeds, 'Data And Backend section', VISIBLE_SECTION_PRIORITY);
|
|
435
493
|
}
|
|
436
494
|
const dataStart = inferDataStart(dataAndBackend);
|
|
437
495
|
if (dataStart) {
|
|
438
|
-
assignValue('dataStart', dataStart, 'Data And Backend section');
|
|
496
|
+
assignValue('dataStart', dataStart, 'Data And Backend section', VISIBLE_SECTION_PRIORITY);
|
|
439
497
|
}
|
|
440
498
|
const authBackend = inferAuthBackend(dataAndBackend);
|
|
441
499
|
if (authBackend) {
|
|
442
|
-
assignValue('authBackend', authBackend, 'Data And Backend section');
|
|
500
|
+
assignValue('authBackend', authBackend, 'Data And Backend section', VISIBLE_SECTION_PRIORITY);
|
|
443
501
|
}
|
|
444
502
|
}
|
|
445
|
-
const platforms = sections
|
|
503
|
+
const platforms = getMarkdownSection(sections, 'Platforms');
|
|
446
504
|
if (platforms) {
|
|
447
505
|
usedSections.add('Platforms');
|
|
448
|
-
extractPlatformDecisions(platforms, assignValue);
|
|
506
|
+
extractPlatformDecisions(platforms, assignValue, VISIBLE_SECTION_PRIORITY);
|
|
449
507
|
}
|
|
450
|
-
const packageChoices = sections
|
|
508
|
+
const packageChoices = getMarkdownSection(sections, 'Package Choices');
|
|
451
509
|
if (packageChoices) {
|
|
452
510
|
usedSections.add('Package Choices');
|
|
453
|
-
extractPackageChoices(packageChoices, assignValue);
|
|
511
|
+
extractPackageChoices(packageChoices, assignValue, VISIBLE_SECTION_PRIORITY);
|
|
454
512
|
}
|
|
455
|
-
const releaseStrategy = sections
|
|
513
|
+
const releaseStrategy = getMarkdownSection(sections, 'Release Strategy');
|
|
456
514
|
if (releaseStrategy) {
|
|
457
515
|
usedSections.add('Release Strategy');
|
|
458
516
|
const deploymentTarget = extractBulletValue(releaseStrategy, 'Deployment plan');
|
|
459
517
|
if (deploymentTarget) {
|
|
460
|
-
assignValue('deploymentTarget', deploymentTarget, 'Release Strategy section');
|
|
518
|
+
assignValue('deploymentTarget', deploymentTarget, 'Release Strategy section', VISIBLE_SECTION_PRIORITY);
|
|
461
519
|
}
|
|
462
520
|
const easUses = inferEasUses(extractBulletValue(releaseStrategy, 'EAS usage') ?? releaseStrategy);
|
|
463
521
|
if (easUses.length > 0) {
|
|
464
|
-
assignValue('easUses', easUses, 'Release Strategy section');
|
|
465
|
-
assignValue('easSetup', true, 'Release Strategy section');
|
|
522
|
+
assignValue('easUses', easUses, 'Release Strategy section', VISIBLE_SECTION_PRIORITY);
|
|
523
|
+
assignValue('easSetup', true, 'Release Strategy section', VISIBLE_SECTION_PRIORITY);
|
|
466
524
|
}
|
|
467
525
|
const testToMain = parseBooleanValue(extractBulletValue(releaseStrategy, 'Test-to-main safeguards'));
|
|
468
526
|
if (typeof testToMain === 'boolean') {
|
|
469
|
-
assignValue('testToMainSafeguards', testToMain, 'Release Strategy section');
|
|
527
|
+
assignValue('testToMainSafeguards', testToMain, 'Release Strategy section', VISIBLE_SECTION_PRIORITY);
|
|
470
528
|
}
|
|
471
529
|
}
|
|
472
|
-
const techStackSection = sections
|
|
530
|
+
const techStackSection = getMarkdownSection(sections, 'Tech Stack & CESS Onboarding', 'Tech Stack & MDS Onboarding');
|
|
473
531
|
if (techStackSection) {
|
|
474
|
-
usedSections.add('Tech Stack & MDS Onboarding');
|
|
475
|
-
extractTechStackDecisions(techStackSection, assignValue);
|
|
532
|
+
usedSections.add(sections.has('Tech Stack & CESS Onboarding') ? 'Tech Stack & CESS Onboarding' : 'Tech Stack & MDS Onboarding');
|
|
533
|
+
extractTechStackDecisions(techStackSection, assignValue, TECH_STACK_PRIORITY);
|
|
476
534
|
}
|
|
477
535
|
const onboardingDecisionsSection = sections.get('Onboarding Decisions');
|
|
478
536
|
if (onboardingDecisionsSection) {
|
|
479
537
|
usedSections.add('Onboarding Decisions');
|
|
480
|
-
extractOnboardingDecisionLines(onboardingDecisionsSection, assignValue);
|
|
538
|
+
extractOnboardingDecisionLines(onboardingDecisionsSection, assignValue, VISIBLE_SECTION_PRIORITY);
|
|
539
|
+
}
|
|
540
|
+
if (!derivedDisplayName && snapshot?.displayAppName && !isGenericTextValue(snapshot.displayAppName)) {
|
|
541
|
+
derivedDisplayName = snapshot.displayAppName;
|
|
542
|
+
derivedDisplayNamePriority = SNAPSHOT_PRIORITY;
|
|
543
|
+
derivedDisplayNameNote = 'MDS snapshot metadata';
|
|
544
|
+
}
|
|
545
|
+
else if (!derivedDisplayName && snapshot?.displayAppName) {
|
|
546
|
+
recordEvidence('displayAppName', 'MDS snapshot metadata ignored because it looked like scaffold/default placeholder data');
|
|
547
|
+
}
|
|
548
|
+
if (!derivedFolderSlug && snapshot?.folderSlug && !isGenericTextValue(snapshot.folderSlug)) {
|
|
549
|
+
derivedFolderSlug = snapshot.folderSlug;
|
|
550
|
+
}
|
|
551
|
+
else if (!derivedFolderSlug && snapshot?.displayAppName && !isGenericTextValue(snapshot.displayAppName)) {
|
|
552
|
+
derivedFolderSlug = slugifyAppName(snapshot.displayAppName);
|
|
481
553
|
}
|
|
482
554
|
if (derivedDisplayName) {
|
|
483
|
-
assignValue('displayAppName', derivedDisplayName, 'Derived app name');
|
|
555
|
+
assignValue('displayAppName', derivedDisplayName, derivedDisplayNameNote ?? 'Derived app name', derivedDisplayNamePriority ?? DERIVED_TITLE_PRIORITY);
|
|
556
|
+
}
|
|
557
|
+
if (snapshot) {
|
|
558
|
+
const snapshotAnswers = normalizeCessIntakeAnswers(snapshot.answers);
|
|
559
|
+
for (const [key, value] of Object.entries(snapshotAnswers)) {
|
|
560
|
+
assignValue(key, value, 'MDS snapshot', SNAPSHOT_PRIORITY);
|
|
561
|
+
}
|
|
484
562
|
}
|
|
485
563
|
const preservedNotes = [...sections.entries()]
|
|
486
564
|
.filter(([heading, body]) => !usedSections.has(heading) && normalizeSectionText(body))
|
|
@@ -536,14 +614,16 @@ function extractProjectTitle(infoMarkdown) {
|
|
|
536
614
|
}
|
|
537
615
|
function parseMarkdownSections(markdown) {
|
|
538
616
|
const sections = new Map();
|
|
539
|
-
const matches = [...markdown.matchAll(
|
|
617
|
+
const matches = [...markdown.matchAll(/^(#{1,2})\s+(.+?)\s*$/gmu)].filter((match) => {
|
|
618
|
+
return !(match.index === 0 && match[1] === '#');
|
|
619
|
+
});
|
|
540
620
|
for (let index = 0; index < matches.length; index += 1) {
|
|
541
621
|
const match = matches[index];
|
|
542
622
|
const next = matches[index + 1];
|
|
543
623
|
if (!match) {
|
|
544
624
|
continue;
|
|
545
625
|
}
|
|
546
|
-
const heading = match?.[
|
|
626
|
+
const heading = match?.[2]?.trim();
|
|
547
627
|
if (!heading || match.index === undefined) {
|
|
548
628
|
continue;
|
|
549
629
|
}
|
|
@@ -553,6 +633,24 @@ function parseMarkdownSections(markdown) {
|
|
|
553
633
|
}
|
|
554
634
|
return sections;
|
|
555
635
|
}
|
|
636
|
+
function getMarkdownSection(sections, ...headings) {
|
|
637
|
+
for (const heading of headings) {
|
|
638
|
+
const exact = sections.get(heading);
|
|
639
|
+
if (exact !== undefined) {
|
|
640
|
+
return exact;
|
|
641
|
+
}
|
|
642
|
+
const normalizedHeading = normalizeHeadingKey(heading);
|
|
643
|
+
for (const [candidate, body] of sections.entries()) {
|
|
644
|
+
if (normalizeHeadingKey(candidate) === normalizedHeading) {
|
|
645
|
+
return body;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return undefined;
|
|
650
|
+
}
|
|
651
|
+
function normalizeHeadingKey(value) {
|
|
652
|
+
return value.trim().toLowerCase().replace(/\s+/gu, ' ');
|
|
653
|
+
}
|
|
556
654
|
function extractAudienceFromOverview(overview) {
|
|
557
655
|
const text = normalizeSectionText(overview);
|
|
558
656
|
if (!text) {
|
|
@@ -644,161 +742,290 @@ function inferAuthBackend(value) {
|
|
|
644
742
|
}
|
|
645
743
|
return undefined;
|
|
646
744
|
}
|
|
647
|
-
function extractPlatformDecisions(value, assignValue) {
|
|
745
|
+
function extractPlatformDecisions(value, assignValue, priority = VISIBLE_SECTION_PRIORITY) {
|
|
648
746
|
const targetPlatforms = parsePlatformList(extractBulletValue(value, 'Target platforms'));
|
|
649
747
|
if (targetPlatforms.length > 0) {
|
|
650
|
-
assignValue('targetPlatforms', targetPlatforms, 'Platforms section');
|
|
748
|
+
assignValue('targetPlatforms', targetPlatforms, 'Platforms section', priority);
|
|
651
749
|
}
|
|
652
750
|
const firstTargetPlatform = normalizeChoice(extractBulletValue(value, 'First MVP platform'), PLATFORM_OPTIONS);
|
|
653
751
|
if (firstTargetPlatform) {
|
|
654
|
-
assignValue('firstTargetPlatform', firstTargetPlatform, 'Platforms section');
|
|
752
|
+
assignValue('firstTargetPlatform', firstTargetPlatform, 'Platforms section', priority);
|
|
655
753
|
}
|
|
656
754
|
const appDirectoryValue = extractBulletValue(value, 'Expo Router app directory');
|
|
657
755
|
if (appDirectoryValue?.includes('src/app')) {
|
|
658
|
-
assignValue('appDirectory', 'src', 'Platforms section');
|
|
756
|
+
assignValue('appDirectory', 'src', 'Platforms section', priority);
|
|
659
757
|
}
|
|
660
758
|
else if (appDirectoryValue?.includes('app')) {
|
|
661
|
-
assignValue('appDirectory', 'root', 'Platforms section');
|
|
759
|
+
assignValue('appDirectory', 'root', 'Platforms section', priority);
|
|
662
760
|
}
|
|
663
761
|
const organization = extractBulletValue(value, 'Platform-specific organization') ?? '';
|
|
664
762
|
if (organization.toLowerCase().includes('folder')) {
|
|
665
|
-
assignValue('platformStrategy', 'folders', 'Platforms section');
|
|
763
|
+
assignValue('platformStrategy', 'folders', 'Platforms section', priority);
|
|
666
764
|
}
|
|
667
765
|
else if (organization.toLowerCase().includes('file')) {
|
|
668
|
-
assignValue('platformStrategy', 'files-only', 'Platforms section');
|
|
766
|
+
assignValue('platformStrategy', 'files-only', 'Platforms section', priority);
|
|
669
767
|
}
|
|
670
768
|
const layoutMode = extractBulletValue(value, 'Platform layout mode');
|
|
671
769
|
if (layoutMode?.toLowerCase().includes('platform-specific')) {
|
|
672
|
-
assignValue('platformLayouts', 'platform-specific', 'Platforms section');
|
|
770
|
+
assignValue('platformLayouts', 'platform-specific', 'Platforms section', priority);
|
|
673
771
|
}
|
|
674
772
|
else if (layoutMode?.toLowerCase().includes('shared')) {
|
|
675
|
-
assignValue('platformLayouts', 'shared', 'Platforms section');
|
|
773
|
+
assignValue('platformLayouts', 'shared', 'Platforms section', priority);
|
|
676
774
|
}
|
|
677
775
|
const webOutput = normalizeChoice(extractBulletValue(value, 'Web output'), ['static', 'server', 'spa', 'none']);
|
|
678
776
|
if (webOutput) {
|
|
679
|
-
assignValue('webOutput', webOutput, 'Platforms section');
|
|
777
|
+
assignValue('webOutput', webOutput, 'Platforms section', priority);
|
|
680
778
|
}
|
|
681
779
|
const deployedServer = (extractBulletValue(value, 'Deployed server') ?? '').toLowerCase();
|
|
682
780
|
if (deployedServer.includes('no deployed server') || deployedServer === 'none') {
|
|
683
|
-
assignValue('expoServerAdapter', 'none', 'Platforms section');
|
|
684
|
-
assignValue('customBackend', false, 'Platforms section');
|
|
781
|
+
assignValue('expoServerAdapter', 'none', 'Platforms section', priority);
|
|
782
|
+
assignValue('customBackend', false, 'Platforms section', priority);
|
|
685
783
|
}
|
|
686
784
|
else if (deployedServer.includes('eas')) {
|
|
687
|
-
assignValue('expoServerAdapter', 'eas', 'Platforms section');
|
|
785
|
+
assignValue('expoServerAdapter', 'eas', 'Platforms section', priority);
|
|
688
786
|
}
|
|
689
787
|
else if (deployedServer.includes('express')) {
|
|
690
|
-
assignValue('expoServerAdapter', 'express', 'Platforms section');
|
|
788
|
+
assignValue('expoServerAdapter', 'express', 'Platforms section', priority);
|
|
691
789
|
}
|
|
692
790
|
else if (deployedServer.includes('bun')) {
|
|
693
|
-
assignValue('expoServerAdapter', 'bun', 'Platforms section');
|
|
791
|
+
assignValue('expoServerAdapter', 'bun', 'Platforms section', priority);
|
|
694
792
|
}
|
|
695
793
|
else if (deployedServer.includes('custom')) {
|
|
696
|
-
assignValue('expoServerAdapter', 'other', 'Platforms section');
|
|
697
|
-
assignValue('customBackend', true, 'Platforms section');
|
|
794
|
+
assignValue('expoServerAdapter', 'other', 'Platforms section', priority);
|
|
795
|
+
assignValue('customBackend', true, 'Platforms section', priority);
|
|
698
796
|
}
|
|
699
797
|
const expoUi = parseBooleanValue(extractBulletValue(value, 'Expo UI'));
|
|
700
798
|
if (typeof expoUi === 'boolean') {
|
|
701
|
-
assignValue('usesExpoUi', expoUi, 'Platforms section');
|
|
799
|
+
assignValue('usesExpoUi', expoUi, 'Platforms section', priority);
|
|
702
800
|
}
|
|
703
801
|
const expoUiUniversal = parseBooleanValue(extractBulletValue(value, 'Expo UI Universal components'));
|
|
704
802
|
if (typeof expoUiUniversal === 'boolean') {
|
|
705
|
-
assignValue('usesExpoUiUniversalComponents', expoUiUniversal, 'Platforms section');
|
|
803
|
+
assignValue('usesExpoUiUniversalComponents', expoUiUniversal, 'Platforms section', priority);
|
|
706
804
|
}
|
|
707
805
|
const expoNativeTabs = parseBooleanValue(extractBulletValue(value, 'Expo Native Tabs'));
|
|
708
806
|
if (typeof expoNativeTabs === 'boolean') {
|
|
709
|
-
assignValue('usesExpoNativeTabs', expoNativeTabs, 'Platforms section');
|
|
807
|
+
assignValue('usesExpoNativeTabs', expoNativeTabs, 'Platforms section', priority);
|
|
710
808
|
}
|
|
711
809
|
}
|
|
712
|
-
function extractPackageChoices(value, assignValue) {
|
|
810
|
+
function extractPackageChoices(value, assignValue, priority = VISIBLE_SECTION_PRIORITY) {
|
|
713
811
|
const entries = normalizeListSection(value)
|
|
714
812
|
?.split('\n')
|
|
715
813
|
.map((item) => item.trim().toLowerCase())
|
|
716
814
|
.filter(Boolean) ?? [];
|
|
717
815
|
for (const entry of entries) {
|
|
718
816
|
if (entry === 'uniwind') {
|
|
719
|
-
assignValue('stylingSystem', 'uniwind', 'Package Choices section');
|
|
817
|
+
assignValue('stylingSystem', 'uniwind', 'Package Choices section', priority);
|
|
720
818
|
}
|
|
721
819
|
else if (entry === 'nativewind') {
|
|
722
|
-
assignValue('stylingSystem', 'nativewind', 'Package Choices section');
|
|
820
|
+
assignValue('stylingSystem', 'nativewind', 'Package Choices section', priority);
|
|
821
|
+
}
|
|
822
|
+
else if (entry === 'nativewindui') {
|
|
823
|
+
assignValue('stylingSystem', 'nativewindui', 'Package Choices section', priority);
|
|
723
824
|
}
|
|
724
825
|
else if (entry === 'tamagui') {
|
|
725
|
-
assignValue('stylingSystem', 'tamagui', 'Package Choices section');
|
|
826
|
+
assignValue('stylingSystem', 'tamagui', 'Package Choices section', priority);
|
|
726
827
|
}
|
|
727
828
|
else if (entry === 'restyle') {
|
|
728
|
-
assignValue('stylingSystem', 'restyle', 'Package Choices section');
|
|
829
|
+
assignValue('stylingSystem', 'restyle', 'Package Choices section', priority);
|
|
729
830
|
}
|
|
730
831
|
else if (entry === 'supabase') {
|
|
731
|
-
assignValue('authBackend', 'supabase', 'Package Choices section');
|
|
832
|
+
assignValue('authBackend', 'supabase', 'Package Choices section', priority);
|
|
732
833
|
}
|
|
733
834
|
else if (entry === 'firebase') {
|
|
734
|
-
assignValue('authBackend', 'firebase', 'Package Choices section');
|
|
835
|
+
assignValue('authBackend', 'firebase', 'Package Choices section', priority);
|
|
735
836
|
}
|
|
736
837
|
}
|
|
737
838
|
}
|
|
738
|
-
function extractTechStackDecisions(value, assignValue) {
|
|
839
|
+
function extractTechStackDecisions(value, assignValue, priority = TECH_STACK_PRIORITY) {
|
|
840
|
+
const typeScriptChoice = parseBooleanValue(extractKeyValue(value, 'TypeScript'));
|
|
841
|
+
if (typeof typeScriptChoice === 'boolean') {
|
|
842
|
+
assignValue('scriptLanguage', typeScriptChoice ? 'typescript' : 'javascript', 'Tech Stack & CESS Onboarding section', priority);
|
|
843
|
+
}
|
|
844
|
+
const packageManagerChoice = normalizeChoiceLabel(extractKeyValue(value, 'Package Manager'), ['npm', 'pnpm', 'yarn', 'bun']);
|
|
845
|
+
if (packageManagerChoice) {
|
|
846
|
+
assignValue('packageManager', packageManagerChoice, 'Tech Stack & CESS Onboarding section', priority);
|
|
847
|
+
}
|
|
848
|
+
const navigationChoice = (extractKeyValue(value, 'Navigation') ?? '').toLowerCase();
|
|
849
|
+
if (isConcreteChoiceValue(navigationChoice)) {
|
|
850
|
+
if (navigationChoice.includes('react navigation')) {
|
|
851
|
+
assignValue('navigationLibrary', 'react-navigation', 'Tech Stack & CESS Onboarding section', priority);
|
|
852
|
+
}
|
|
853
|
+
else if (navigationChoice.includes('expo router')) {
|
|
854
|
+
assignValue('navigationLibrary', 'expo-router', 'Tech Stack & CESS Onboarding section', priority);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
const navigationType = (extractKeyValue(value, 'Type of Navigation') ?? '').toLowerCase();
|
|
858
|
+
if (isConcreteChoiceValue(navigationType)) {
|
|
859
|
+
if (navigationType.includes('drawer')) {
|
|
860
|
+
assignValue('reactNavigationLayout', 'drawer', 'Tech Stack & CESS Onboarding section', priority);
|
|
861
|
+
}
|
|
862
|
+
else if (navigationType.includes('tabs')) {
|
|
863
|
+
assignValue('reactNavigationLayout', 'tabs', 'Tech Stack & CESS Onboarding section', priority);
|
|
864
|
+
}
|
|
865
|
+
else if (navigationType.includes('stack')) {
|
|
866
|
+
assignValue('reactNavigationLayout', 'stack', 'Tech Stack & CESS Onboarding section', priority);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
const appDirectoryValue = extractKeyValue(value, 'Expo Router app directory');
|
|
870
|
+
if (appDirectoryValue?.includes('src/app')) {
|
|
871
|
+
assignValue('appDirectory', 'src', 'Tech Stack & CESS Onboarding section', priority);
|
|
872
|
+
}
|
|
873
|
+
else if (appDirectoryValue === 'app' || appDirectoryValue?.includes('`app`')) {
|
|
874
|
+
assignValue('appDirectory', 'root', 'Tech Stack & CESS Onboarding section', priority);
|
|
875
|
+
}
|
|
876
|
+
const organization = (extractKeyValue(value, 'Platform-specific organization (folders, files, or inline)') ?? '').toLowerCase();
|
|
877
|
+
if (isConcreteChoiceValue(organization)) {
|
|
878
|
+
if (organization.includes('folder')) {
|
|
879
|
+
assignValue('platformStrategy', 'folders', 'Tech Stack & CESS Onboarding section', priority);
|
|
880
|
+
}
|
|
881
|
+
else if (organization.includes('file')) {
|
|
882
|
+
assignValue('platformStrategy', 'files-only', 'Tech Stack & CESS Onboarding section', priority);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
const layoutMode = (extractKeyValue(value, 'Platform layout mode') ?? '').toLowerCase();
|
|
886
|
+
if (isConcreteChoiceValue(layoutMode)) {
|
|
887
|
+
if (layoutMode.includes('platform-specific')) {
|
|
888
|
+
assignValue('platformLayouts', 'platform-specific', 'Tech Stack & CESS Onboarding section', priority);
|
|
889
|
+
}
|
|
890
|
+
else if (layoutMode.includes('shared')) {
|
|
891
|
+
assignValue('platformLayouts', 'shared', 'Tech Stack & CESS Onboarding section', priority);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
const webOutput = normalizeChoiceLabel(extractKeyValue(value, 'Web output'), ['static', 'server', 'spa', 'none']);
|
|
895
|
+
if (webOutput) {
|
|
896
|
+
assignValue('webOutput', webOutput, 'Tech Stack & CESS Onboarding section', priority);
|
|
897
|
+
}
|
|
898
|
+
const styleLibrary = (extractKeyValue(value, 'Style Library') ?? '').toLowerCase();
|
|
899
|
+
if (isConcreteChoiceValue(styleLibrary)) {
|
|
900
|
+
if (styleLibrary.includes('nativewindui')) {
|
|
901
|
+
assignValue('stylingSystem', 'nativewindui', 'Tech Stack & CESS Onboarding section', priority);
|
|
902
|
+
}
|
|
903
|
+
else if (styleLibrary.includes('nativewind')) {
|
|
904
|
+
assignValue('stylingSystem', 'nativewind', 'Tech Stack & CESS Onboarding section', priority);
|
|
905
|
+
}
|
|
906
|
+
else if (styleLibrary.includes('uniwind')) {
|
|
907
|
+
assignValue('stylingSystem', 'uniwind', 'Tech Stack & CESS Onboarding section', priority);
|
|
908
|
+
}
|
|
909
|
+
else if (styleLibrary.includes('tamagui')) {
|
|
910
|
+
assignValue('stylingSystem', 'tamagui', 'Tech Stack & CESS Onboarding section', priority);
|
|
911
|
+
}
|
|
912
|
+
else if (styleLibrary.includes('restyle')) {
|
|
913
|
+
assignValue('stylingSystem', 'restyle', 'Tech Stack & CESS Onboarding section', priority);
|
|
914
|
+
}
|
|
915
|
+
else if (styleLibrary.includes('stylesheet')) {
|
|
916
|
+
assignValue('stylingSystem', 'stylesheet', 'Tech Stack & CESS Onboarding section', priority);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
assignBooleanKey(value, 'Components from create-expo-app', 'includeCreateExpoComponents', assignValue, priority);
|
|
920
|
+
assignBooleanKey(value, 'Expo UI', 'usesExpoUi', assignValue, priority);
|
|
921
|
+
assignBooleanKey(value, 'Expo UI Universal components', 'usesExpoUiUniversalComponents', assignValue, priority);
|
|
922
|
+
assignBooleanKey(value, 'Expo Native Tabs', 'usesExpoNativeTabs', assignValue, priority);
|
|
923
|
+
const stateManagementChoice = (extractKeyValue(value, 'State management library') ?? '').toLowerCase();
|
|
924
|
+
if (isConcreteChoiceValue(stateManagementChoice)) {
|
|
925
|
+
if (stateManagementChoice.includes('zustand')) {
|
|
926
|
+
assignValue('stateManagement', 'zustand', 'Tech Stack & CESS Onboarding section', priority);
|
|
927
|
+
}
|
|
928
|
+
else if (stateManagementChoice.includes('none')) {
|
|
929
|
+
assignValue('stateManagement', 'none', 'Tech Stack & CESS Onboarding section', priority);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
const authChoice = inferAuthBackend(extractKeyValue(value, 'Auth') ?? '');
|
|
933
|
+
if (authChoice) {
|
|
934
|
+
assignValue('authBackend', authChoice, 'Tech Stack & CESS Onboarding section', priority);
|
|
935
|
+
}
|
|
936
|
+
else if ((extractKeyValue(value, 'Auth') ?? '').toLowerCase().includes('none')) {
|
|
937
|
+
assignValue('authBackend', 'none', 'Tech Stack & CESS Onboarding section', priority);
|
|
938
|
+
}
|
|
939
|
+
const dataCategories = extractKeyValue(value, 'Data Categories');
|
|
940
|
+
if (dataCategories) {
|
|
941
|
+
const inferredDataNeeds = inferDataNeedSelections(dataCategories);
|
|
942
|
+
if (inferredDataNeeds.length > 0) {
|
|
943
|
+
assignValue('dataNeedSelections', inferredDataNeeds, 'Tech Stack & CESS Onboarding section', priority);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
const startingDataMode = inferDataStart(extractKeyValue(value, 'Starting Data mode') ?? '');
|
|
947
|
+
if (startingDataMode) {
|
|
948
|
+
assignValue('dataStart', startingDataMode, 'Tech Stack & CESS Onboarding section', priority);
|
|
949
|
+
}
|
|
950
|
+
const easChoice = parseBooleanValue(extractKeyValue(value, 'EAS'));
|
|
951
|
+
if (typeof easChoice === 'boolean') {
|
|
952
|
+
assignValue('easSetup', easChoice, 'Tech Stack & CESS Onboarding section', priority);
|
|
953
|
+
}
|
|
954
|
+
const newEasUses = inferEasUses(extractKeyValue(value, 'EAS Usage') ?? '');
|
|
955
|
+
if (newEasUses.length > 0) {
|
|
956
|
+
assignValue('easUses', newEasUses, 'Tech Stack & CESS Onboarding section', priority);
|
|
957
|
+
assignValue('easSetup', true, 'Tech Stack & CESS Onboarding section', priority);
|
|
958
|
+
}
|
|
959
|
+
extractPlatformDecisions(`- Deployed server: ${extractKeyValue(value, 'Deployed server') ?? ''}`, assignValue, priority);
|
|
960
|
+
const initialDeploymentPlan = extractKeyValue(value, 'Initial Deployment plan');
|
|
961
|
+
if (initialDeploymentPlan && isConcreteChoiceValue(initialDeploymentPlan)) {
|
|
962
|
+
assignValue('deploymentTarget', initialDeploymentPlan, 'Tech Stack & CESS Onboarding section', priority);
|
|
963
|
+
}
|
|
964
|
+
assignBooleanKey(value, 'Start with MDS project guidelines template', 'guidelinesTemplate', assignValue, priority);
|
|
965
|
+
assignBooleanKey(value, 'Use test-to-main safeguards', 'testToMainSafeguards', assignValue, priority);
|
|
739
966
|
const language = normalizeChoice(extractKeyValue(value, 'Language'), ['typescript', 'javascript']);
|
|
740
967
|
if (language) {
|
|
741
|
-
assignValue('scriptLanguage', language, 'Tech Stack & MDS Onboarding section');
|
|
968
|
+
assignValue('scriptLanguage', language, 'Tech Stack & MDS Onboarding section', priority);
|
|
742
969
|
}
|
|
743
970
|
const packageManager = normalizeChoice(extractKeyValue(value, 'Package manager'), ['npm', 'pnpm', 'yarn', 'bun']);
|
|
744
971
|
if (packageManager) {
|
|
745
|
-
assignValue('packageManager', packageManager, 'Tech Stack & MDS Onboarding section');
|
|
972
|
+
assignValue('packageManager', packageManager, 'Tech Stack & MDS Onboarding section', priority);
|
|
746
973
|
}
|
|
747
974
|
const routing = (extractKeyValue(value, 'Routing') ?? '').toLowerCase();
|
|
748
975
|
if (routing.includes('react navigation')) {
|
|
749
|
-
assignValue('navigationLibrary', 'react-navigation', 'Tech Stack & MDS Onboarding section');
|
|
976
|
+
assignValue('navigationLibrary', 'react-navigation', 'Tech Stack & MDS Onboarding section', priority);
|
|
750
977
|
if (routing.includes('tabs')) {
|
|
751
|
-
assignValue('reactNavigationLayout', 'tabs', 'Tech Stack & MDS Onboarding section');
|
|
978
|
+
assignValue('reactNavigationLayout', 'tabs', 'Tech Stack & MDS Onboarding section', priority);
|
|
752
979
|
}
|
|
753
980
|
else if (routing.includes('drawer')) {
|
|
754
|
-
assignValue('reactNavigationLayout', 'drawer', 'Tech Stack & MDS Onboarding section');
|
|
981
|
+
assignValue('reactNavigationLayout', 'drawer', 'Tech Stack & MDS Onboarding section', priority);
|
|
755
982
|
}
|
|
756
983
|
else {
|
|
757
|
-
assignValue('reactNavigationLayout', 'stack', 'Tech Stack & MDS Onboarding section');
|
|
984
|
+
assignValue('reactNavigationLayout', 'stack', 'Tech Stack & MDS Onboarding section', priority);
|
|
758
985
|
}
|
|
759
986
|
}
|
|
760
987
|
else if (routing.includes('expo router')) {
|
|
761
|
-
assignValue('navigationLibrary', 'expo-router', 'Tech Stack & MDS Onboarding section');
|
|
988
|
+
assignValue('navigationLibrary', 'expo-router', 'Tech Stack & MDS Onboarding section', priority);
|
|
762
989
|
}
|
|
763
990
|
const styling = (extractKeyValue(value, 'Styling') ?? '').toLowerCase();
|
|
764
991
|
if (styling.includes('uniwind')) {
|
|
765
|
-
assignValue('stylingSystem', 'uniwind', 'Tech Stack & MDS Onboarding section');
|
|
992
|
+
assignValue('stylingSystem', 'uniwind', 'Tech Stack & MDS Onboarding section', priority);
|
|
766
993
|
}
|
|
767
994
|
else if (styling.includes('nativewind')) {
|
|
768
|
-
assignValue('stylingSystem', 'nativewind', 'Tech Stack & MDS Onboarding section');
|
|
995
|
+
assignValue('stylingSystem', 'nativewind', 'Tech Stack & MDS Onboarding section', priority);
|
|
769
996
|
}
|
|
770
997
|
else if (styling.includes('tamagui')) {
|
|
771
|
-
assignValue('stylingSystem', 'tamagui', 'Tech Stack & MDS Onboarding section');
|
|
998
|
+
assignValue('stylingSystem', 'tamagui', 'Tech Stack & MDS Onboarding section', priority);
|
|
772
999
|
}
|
|
773
1000
|
else if (styling.includes('restyle')) {
|
|
774
|
-
assignValue('stylingSystem', 'restyle', 'Tech Stack & MDS Onboarding section');
|
|
1001
|
+
assignValue('stylingSystem', 'restyle', 'Tech Stack & MDS Onboarding section', priority);
|
|
775
1002
|
}
|
|
776
1003
|
else if (styling.includes('stylesheet')) {
|
|
777
|
-
assignValue('stylingSystem', 'stylesheet', 'Tech Stack & MDS Onboarding section');
|
|
1004
|
+
assignValue('stylingSystem', 'stylesheet', 'Tech Stack & MDS Onboarding section', priority);
|
|
778
1005
|
}
|
|
779
1006
|
const stateManagement = (extractKeyValue(value, 'State management') ?? '').toLowerCase();
|
|
780
1007
|
if (stateManagement.includes('zustand')) {
|
|
781
|
-
assignValue('stateManagement', 'zustand', 'Tech Stack & MDS Onboarding section');
|
|
1008
|
+
assignValue('stateManagement', 'zustand', 'Tech Stack & MDS Onboarding section', priority);
|
|
782
1009
|
}
|
|
783
1010
|
else if (stateManagement.includes('none')) {
|
|
784
|
-
assignValue('stateManagement', 'none', 'Tech Stack & MDS Onboarding section');
|
|
1011
|
+
assignValue('stateManagement', 'none', 'Tech Stack & MDS Onboarding section', priority);
|
|
785
1012
|
}
|
|
786
1013
|
const auth = inferAuthBackend(extractKeyValue(value, 'Auth') ?? '');
|
|
787
1014
|
if (auth) {
|
|
788
|
-
assignValue('authBackend', auth, 'Tech Stack & MDS Onboarding section');
|
|
1015
|
+
assignValue('authBackend', auth, 'Tech Stack & MDS Onboarding section', priority);
|
|
789
1016
|
}
|
|
790
1017
|
const distribution = extractKeyValue(value, 'Distribution');
|
|
791
1018
|
if (distribution) {
|
|
792
|
-
assignValue('deploymentTarget', distribution, 'Tech Stack & MDS Onboarding section');
|
|
1019
|
+
assignValue('deploymentTarget', distribution, 'Tech Stack & MDS Onboarding section', priority);
|
|
793
1020
|
}
|
|
794
1021
|
const easUses = inferEasUses(extractKeyValue(value, 'EAS') ?? '');
|
|
795
1022
|
if (easUses.length > 0) {
|
|
796
|
-
assignValue('easUses', easUses, 'Tech Stack & MDS Onboarding section');
|
|
797
|
-
assignValue('easSetup', true, 'Tech Stack & MDS Onboarding section');
|
|
1023
|
+
assignValue('easUses', easUses, 'Tech Stack & MDS Onboarding section', priority);
|
|
1024
|
+
assignValue('easSetup', true, 'Tech Stack & MDS Onboarding section', priority);
|
|
798
1025
|
}
|
|
799
|
-
extractOnboardingDecisionLines(value, assignValue);
|
|
1026
|
+
extractOnboardingDecisionLines(value, assignValue, priority);
|
|
800
1027
|
}
|
|
801
|
-
function extractOnboardingDecisionLines(value, assignValue) {
|
|
1028
|
+
function extractOnboardingDecisionLines(value, assignValue, priority = VISIBLE_SECTION_PRIORITY) {
|
|
802
1029
|
const lines = normalizeLineEndings(value)
|
|
803
1030
|
.split('\n')
|
|
804
1031
|
.map((line) => line.trim())
|
|
@@ -815,57 +1042,57 @@ function extractOnboardingDecisionLines(value, assignValue) {
|
|
|
815
1042
|
continue;
|
|
816
1043
|
}
|
|
817
1044
|
if (loweredKey === 'create expo starter components') {
|
|
818
|
-
assignValue('includeCreateExpoComponents', parseBooleanValue(rawValue), 'Onboarding decisions');
|
|
1045
|
+
assignValue('includeCreateExpoComponents', parseBooleanValue(rawValue), 'Onboarding decisions', priority);
|
|
819
1046
|
}
|
|
820
1047
|
else if (loweredKey === 'latest expo sdk preference') {
|
|
821
1048
|
// Captured for human context only; SDK targeting is enforced by the generator.
|
|
822
1049
|
continue;
|
|
823
1050
|
}
|
|
824
1051
|
else if (loweredKey === 'expo ui') {
|
|
825
|
-
assignValue('usesExpoUi', parseBooleanValue(rawValue), 'Onboarding decisions');
|
|
1052
|
+
assignValue('usesExpoUi', parseBooleanValue(rawValue), 'Onboarding decisions', priority);
|
|
826
1053
|
}
|
|
827
1054
|
else if (loweredKey === 'expo ui universal components') {
|
|
828
|
-
assignValue('usesExpoUiUniversalComponents', parseBooleanValue(rawValue), 'Onboarding decisions');
|
|
1055
|
+
assignValue('usesExpoUiUniversalComponents', parseBooleanValue(rawValue), 'Onboarding decisions', priority);
|
|
829
1056
|
}
|
|
830
1057
|
else if (loweredKey === 'expo native tabs') {
|
|
831
|
-
assignValue('usesExpoNativeTabs', parseBooleanValue(rawValue), 'Onboarding decisions');
|
|
1058
|
+
assignValue('usesExpoNativeTabs', parseBooleanValue(rawValue), 'Onboarding decisions', priority);
|
|
832
1059
|
}
|
|
833
1060
|
else if (loweredKey === 'target platforms') {
|
|
834
1061
|
const targetPlatforms = parsePlatformList(rawValue);
|
|
835
1062
|
if (targetPlatforms.length > 0) {
|
|
836
|
-
assignValue('targetPlatforms', targetPlatforms, 'Onboarding decisions');
|
|
1063
|
+
assignValue('targetPlatforms', targetPlatforms, 'Onboarding decisions', priority);
|
|
837
1064
|
}
|
|
838
1065
|
}
|
|
839
1066
|
else if (loweredKey === 'first mvp platform') {
|
|
840
|
-
assignValue('firstTargetPlatform', normalizeChoice(rawValue, PLATFORM_OPTIONS), 'Onboarding decisions');
|
|
1067
|
+
assignValue('firstTargetPlatform', normalizeChoice(rawValue, PLATFORM_OPTIONS), 'Onboarding decisions', priority);
|
|
841
1068
|
}
|
|
842
1069
|
else if (loweredKey === 'expo router app directory') {
|
|
843
|
-
assignValue('appDirectory', rawValue.includes('src/app') ? 'src' : 'root', 'Onboarding decisions');
|
|
1070
|
+
assignValue('appDirectory', rawValue.includes('src/app') ? 'src' : 'root', 'Onboarding decisions', priority);
|
|
844
1071
|
}
|
|
845
1072
|
else if (loweredKey === 'platform-specific organization') {
|
|
846
|
-
assignValue('platformStrategy', rawValue.toLowerCase().includes('folder') ? 'folders' : 'files-only', 'Onboarding decisions');
|
|
1073
|
+
assignValue('platformStrategy', rawValue.toLowerCase().includes('folder') ? 'folders' : 'files-only', 'Onboarding decisions', priority);
|
|
847
1074
|
}
|
|
848
1075
|
else if (loweredKey === 'platform layout mode') {
|
|
849
|
-
assignValue('platformLayouts', rawValue.toLowerCase().includes('platform-specific') ? 'platform-specific' : 'shared', 'Onboarding decisions');
|
|
1076
|
+
assignValue('platformLayouts', rawValue.toLowerCase().includes('platform-specific') ? 'platform-specific' : 'shared', 'Onboarding decisions', priority);
|
|
850
1077
|
}
|
|
851
1078
|
else if (loweredKey === 'web output') {
|
|
852
|
-
assignValue('webOutput', normalizeChoice(rawValue, ['static', 'server', 'spa', 'none']), 'Onboarding decisions');
|
|
1079
|
+
assignValue('webOutput', normalizeChoice(rawValue, ['static', 'server', 'spa', 'none']), 'Onboarding decisions', priority);
|
|
853
1080
|
}
|
|
854
1081
|
else if (loweredKey === 'deployed server') {
|
|
855
|
-
extractPlatformDecisions(`- Deployed server: ${rawValue}`, assignValue);
|
|
1082
|
+
extractPlatformDecisions(`- Deployed server: ${rawValue}`, assignValue, priority);
|
|
856
1083
|
}
|
|
857
1084
|
else if (loweredKey === 'eas usage') {
|
|
858
1085
|
const easUses = inferEasUses(rawValue);
|
|
859
1086
|
if (easUses.length > 0) {
|
|
860
|
-
assignValue('easUses', easUses, 'Onboarding decisions');
|
|
861
|
-
assignValue('easSetup', true, 'Onboarding decisions');
|
|
1087
|
+
assignValue('easUses', easUses, 'Onboarding decisions', priority);
|
|
1088
|
+
assignValue('easSetup', true, 'Onboarding decisions', priority);
|
|
862
1089
|
}
|
|
863
1090
|
}
|
|
864
1091
|
else if (loweredKey === 'data start') {
|
|
865
|
-
assignValue('dataStart', inferDataStart(rawValue), 'Onboarding decisions');
|
|
1092
|
+
assignValue('dataStart', inferDataStart(rawValue), 'Onboarding decisions', priority);
|
|
866
1093
|
}
|
|
867
1094
|
else if (loweredKey === 'test-to-main safeguards') {
|
|
868
|
-
assignValue('testToMainSafeguards', parseBooleanValue(rawValue), 'Onboarding decisions');
|
|
1095
|
+
assignValue('testToMainSafeguards', parseBooleanValue(rawValue), 'Onboarding decisions', priority);
|
|
869
1096
|
}
|
|
870
1097
|
}
|
|
871
1098
|
}
|
|
@@ -877,9 +1104,29 @@ function extractKeyValue(value, label) {
|
|
|
877
1104
|
const match = new RegExp(`^-\\s+(?:\\*\\*)?${escapeRegExp(label)}(?:\\*\\*)?:\\s+(.+)$`, 'imu').exec(value);
|
|
878
1105
|
return normalizeText(match?.[1]);
|
|
879
1106
|
}
|
|
1107
|
+
function assignBooleanKey(value, label, id, assignValue, priority) {
|
|
1108
|
+
const bool = parseBooleanValue(extractKeyValue(value, label));
|
|
1109
|
+
if (typeof bool === 'boolean') {
|
|
1110
|
+
assignValue(id, bool, 'Tech Stack & CESS Onboarding section', priority);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
function normalizeChoiceLabel(value, choices) {
|
|
1114
|
+
const normalized = normalizeText(value)?.toLowerCase().replace(/[`]/gu, '').trim();
|
|
1115
|
+
if (!normalized || !isConcreteChoiceValue(normalized)) {
|
|
1116
|
+
return undefined;
|
|
1117
|
+
}
|
|
1118
|
+
return choices.find((choice) => choice.toLowerCase() === normalized);
|
|
1119
|
+
}
|
|
1120
|
+
function isConcreteChoiceValue(value) {
|
|
1121
|
+
return !/\s\/\s/u.test(value);
|
|
1122
|
+
}
|
|
880
1123
|
function inferEasUses(value) {
|
|
881
1124
|
const normalized = value.toLowerCase();
|
|
882
|
-
|
|
1125
|
+
const selected = EAS_USE_OPTIONS.filter((item) => normalized.includes(item.toLowerCase()));
|
|
1126
|
+
if (/\bbuilding mobile apps?\b/u.test(normalized) && !selected.includes('building mobile applications')) {
|
|
1127
|
+
selected.push('building mobile applications');
|
|
1128
|
+
}
|
|
1129
|
+
return selected;
|
|
883
1130
|
}
|
|
884
1131
|
function parsePlatformList(value) {
|
|
885
1132
|
const normalized = value
|
|
@@ -934,17 +1181,17 @@ function normalizeExtractedAnswerValue(id, value) {
|
|
|
934
1181
|
case 'reactNavigationLayout':
|
|
935
1182
|
return normalizeEnum(value, ['stack', 'tabs', 'drawer']);
|
|
936
1183
|
case 'stylingSystem':
|
|
937
|
-
return normalizeEnum(value, ['uniwind', 'nativewind', 'tamagui', 'restyle', 'stylesheet']);
|
|
1184
|
+
return normalizeEnum(value, ['uniwind', 'nativewind', 'nativewindui', 'tamagui', 'restyle', 'stylesheet']);
|
|
938
1185
|
case 'stateManagement':
|
|
939
1186
|
return normalizeEnum(value, ['zustand', 'none']);
|
|
940
1187
|
case 'authBackend':
|
|
941
1188
|
return normalizeEnum(value, ['none', 'supabase', 'firebase']);
|
|
942
1189
|
case 'platformStrategy':
|
|
943
|
-
return
|
|
1190
|
+
return normalizePlatformStrategyValue(value);
|
|
944
1191
|
case 'appDirectory':
|
|
945
|
-
return
|
|
1192
|
+
return normalizeAppDirectoryValue(value);
|
|
946
1193
|
case 'platformLayouts':
|
|
947
|
-
return
|
|
1194
|
+
return normalizePlatformLayoutsValue(value);
|
|
948
1195
|
case 'webOutput':
|
|
949
1196
|
return normalizeEnum(value, ['static', 'server', 'spa', 'none']);
|
|
950
1197
|
case 'expoServerAdapter':
|
|
@@ -957,6 +1204,41 @@ function normalizeExtractedAnswerValue(id, value) {
|
|
|
957
1204
|
return normalizeText(value);
|
|
958
1205
|
}
|
|
959
1206
|
}
|
|
1207
|
+
function isGenericExtractedAnswerValue(id, value) {
|
|
1208
|
+
if (id === 'displayAppName') {
|
|
1209
|
+
return isGenericTextValue(value);
|
|
1210
|
+
}
|
|
1211
|
+
if (id === 'audience') {
|
|
1212
|
+
return normalizeText(value)?.toLowerCase() === 'expo app users';
|
|
1213
|
+
}
|
|
1214
|
+
if (id === 'coreFlows') {
|
|
1215
|
+
const normalized = normalizeText(value)?.toLowerCase();
|
|
1216
|
+
return (!normalized ||
|
|
1217
|
+
normalized === AGENT_DERIVED_CORE_FLOWS.toLowerCase() ||
|
|
1218
|
+
normalized.includes('let the agent derive') ||
|
|
1219
|
+
normalized.startsWith('# todoforcontext'));
|
|
1220
|
+
}
|
|
1221
|
+
if (id === 'screens') {
|
|
1222
|
+
const normalized = normalizeText(value)?.toLowerCase();
|
|
1223
|
+
return !normalized || normalized === 'defer' || normalized.startsWith('# todoforcontext');
|
|
1224
|
+
}
|
|
1225
|
+
if (id === 'targetPlatforms') {
|
|
1226
|
+
const platforms = normalizeStringArray(value);
|
|
1227
|
+
return (platforms?.length === PLATFORM_OPTIONS.length &&
|
|
1228
|
+
PLATFORM_OPTIONS.every((platform) => platforms.includes(platform)));
|
|
1229
|
+
}
|
|
1230
|
+
if (id === 'deploymentTarget') {
|
|
1231
|
+
return normalizeText(value)?.toLowerCase() === 'expo web/native deployment';
|
|
1232
|
+
}
|
|
1233
|
+
return false;
|
|
1234
|
+
}
|
|
1235
|
+
function isGenericTextValue(value) {
|
|
1236
|
+
const normalized = normalizeText(value)
|
|
1237
|
+
?.toLowerCase()
|
|
1238
|
+
.replace(/\s+/gu, ' ')
|
|
1239
|
+
.trim();
|
|
1240
|
+
return !normalized || normalized === 'template' || normalized === 'my expo app' || normalized === 'my-expo-app';
|
|
1241
|
+
}
|
|
960
1242
|
function areAnswerValuesEquivalent(id, left, right) {
|
|
961
1243
|
if (Array.isArray(left) || Array.isArray(right)) {
|
|
962
1244
|
return JSON.stringify(normalizeStringArray(left) ?? []) === JSON.stringify(normalizeStringArray(right) ?? []);
|
|
@@ -1146,6 +1428,7 @@ export function normalizeCessIntakeAnswers(answers) {
|
|
|
1146
1428
|
normalized.stylingSystem = normalizeEnum(answers.stylingSystem, [
|
|
1147
1429
|
'uniwind',
|
|
1148
1430
|
'nativewind',
|
|
1431
|
+
'nativewindui',
|
|
1149
1432
|
'tamagui',
|
|
1150
1433
|
'restyle',
|
|
1151
1434
|
'stylesheet',
|
|
@@ -1161,9 +1444,9 @@ export function normalizeCessIntakeAnswers(answers) {
|
|
|
1161
1444
|
normalized.dataNeedsOther = normalizeText(answers.dataNeedsOther);
|
|
1162
1445
|
normalized.targetPlatforms = normalizePlatforms(answers.targetPlatforms);
|
|
1163
1446
|
normalized.firstTargetPlatform = normalizeText(answers.firstTargetPlatform);
|
|
1164
|
-
normalized.platformStrategy =
|
|
1165
|
-
normalized.appDirectory =
|
|
1166
|
-
normalized.platformLayouts =
|
|
1447
|
+
normalized.platformStrategy = normalizePlatformStrategyValue(answers.platformStrategy);
|
|
1448
|
+
normalized.appDirectory = normalizeAppDirectoryValue(answers.appDirectory);
|
|
1449
|
+
normalized.platformLayouts = normalizePlatformLayoutsValue(answers.platformLayouts);
|
|
1167
1450
|
normalized.webOutput = normalizeEnum(answers.webOutput, ['static', 'server', 'spa', 'none']);
|
|
1168
1451
|
normalized.expoServerAdapter = normalizeEnum(answers.expoServerAdapter, [
|
|
1169
1452
|
'eas',
|
|
@@ -1206,6 +1489,9 @@ export function buildCreateExpoStackFlags(answers) {
|
|
|
1206
1489
|
case 'nativewind':
|
|
1207
1490
|
flags.push('--nativewind');
|
|
1208
1491
|
break;
|
|
1492
|
+
case 'nativewindui':
|
|
1493
|
+
flags.push('--nativewindui');
|
|
1494
|
+
break;
|
|
1209
1495
|
case 'tamagui':
|
|
1210
1496
|
flags.push('--tamagui');
|
|
1211
1497
|
break;
|
|
@@ -1421,8 +1707,40 @@ function buildOnboardArgvFromCess(parentDir, appName, answers) {
|
|
|
1421
1707
|
dataStart: answers.dataStart,
|
|
1422
1708
|
testToMain: answers.testToMainSafeguards,
|
|
1423
1709
|
saveDefaults: answers.saveDefaults,
|
|
1710
|
+
defaults: buildOnboardDefaultsFromCessAnswers(answers),
|
|
1424
1711
|
};
|
|
1425
1712
|
}
|
|
1713
|
+
function buildOnboardDefaultsFromCessAnswers(answers) {
|
|
1714
|
+
const defaults = new Set(['project-docs', 'guidelines']);
|
|
1715
|
+
switch (answers.stylingSystem) {
|
|
1716
|
+
case 'nativewindui':
|
|
1717
|
+
defaults.add('nativewindui');
|
|
1718
|
+
break;
|
|
1719
|
+
case 'nativewind':
|
|
1720
|
+
defaults.add('nativewind');
|
|
1721
|
+
break;
|
|
1722
|
+
case 'tamagui':
|
|
1723
|
+
defaults.add('tamagui');
|
|
1724
|
+
break;
|
|
1725
|
+
case 'restyle':
|
|
1726
|
+
defaults.add('restyle');
|
|
1727
|
+
break;
|
|
1728
|
+
case 'stylesheet':
|
|
1729
|
+
break;
|
|
1730
|
+
case 'uniwind':
|
|
1731
|
+
default:
|
|
1732
|
+
defaults.add('uniwind');
|
|
1733
|
+
break;
|
|
1734
|
+
}
|
|
1735
|
+
if (answers.dataStart === 'supabase' || answers.authBackend === 'supabase') {
|
|
1736
|
+
defaults.add('supabase');
|
|
1737
|
+
}
|
|
1738
|
+
defaults.add('doctor');
|
|
1739
|
+
if (answers.testToMainSafeguards ?? true) {
|
|
1740
|
+
defaults.add('test-to-main');
|
|
1741
|
+
}
|
|
1742
|
+
return [...defaults].join(',');
|
|
1743
|
+
}
|
|
1426
1744
|
function materializeQuestion(definition, context) {
|
|
1427
1745
|
return {
|
|
1428
1746
|
id: definition.id,
|
|
@@ -1476,6 +1794,45 @@ function normalizeEnum(value, choices) {
|
|
|
1476
1794
|
function normalizeChoice(value, choices) {
|
|
1477
1795
|
return normalizeEnum(value, choices);
|
|
1478
1796
|
}
|
|
1797
|
+
function normalizePlatformStrategyValue(value) {
|
|
1798
|
+
const normalized = normalizeText(value)?.toLowerCase();
|
|
1799
|
+
if (!normalized) {
|
|
1800
|
+
return undefined;
|
|
1801
|
+
}
|
|
1802
|
+
if (normalized === 'folders' || normalized.includes('folder')) {
|
|
1803
|
+
return 'folders';
|
|
1804
|
+
}
|
|
1805
|
+
if (normalized === 'files-only' || normalized.includes('file')) {
|
|
1806
|
+
return 'files-only';
|
|
1807
|
+
}
|
|
1808
|
+
return undefined;
|
|
1809
|
+
}
|
|
1810
|
+
function normalizeAppDirectoryValue(value) {
|
|
1811
|
+
const normalized = normalizeText(value)?.toLowerCase().replace(/[`]/gu, '').trim();
|
|
1812
|
+
if (!normalized) {
|
|
1813
|
+
return undefined;
|
|
1814
|
+
}
|
|
1815
|
+
if (normalized === 'src' || normalized === 'src/app') {
|
|
1816
|
+
return 'src';
|
|
1817
|
+
}
|
|
1818
|
+
if (normalized === 'root' || normalized === 'app') {
|
|
1819
|
+
return 'root';
|
|
1820
|
+
}
|
|
1821
|
+
return undefined;
|
|
1822
|
+
}
|
|
1823
|
+
function normalizePlatformLayoutsValue(value) {
|
|
1824
|
+
const normalized = normalizeText(value)?.toLowerCase();
|
|
1825
|
+
if (!normalized) {
|
|
1826
|
+
return undefined;
|
|
1827
|
+
}
|
|
1828
|
+
if (normalized === 'shared' || normalized.includes('shared')) {
|
|
1829
|
+
return 'shared';
|
|
1830
|
+
}
|
|
1831
|
+
if (normalized === 'platform-specific' || normalized.includes('platform-specific')) {
|
|
1832
|
+
return 'platform-specific';
|
|
1833
|
+
}
|
|
1834
|
+
return undefined;
|
|
1835
|
+
}
|
|
1479
1836
|
function normalizeText(value) {
|
|
1480
1837
|
if (typeof value !== 'string') {
|
|
1481
1838
|
return undefined;
|
|
@@ -1532,6 +1889,8 @@ function formatStylingLabel(value) {
|
|
|
1532
1889
|
return 'Uniwind';
|
|
1533
1890
|
case 'nativewind':
|
|
1534
1891
|
return 'NativeWind';
|
|
1892
|
+
case 'nativewindui':
|
|
1893
|
+
return 'NativeWindUI';
|
|
1535
1894
|
case 'tamagui':
|
|
1536
1895
|
return 'Tamagui';
|
|
1537
1896
|
case 'restyle':
|