@ryuenn3123/agentic-senior-core 3.0.9 → 3.0.10
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/.agent-context/prompts/bootstrap-design.md +27 -12
- package/.agent-context/prompts/init-project.md +7 -0
- package/.agent-context/rules/frontend-architecture.md +1 -0
- package/.agent-context/state/memory-continuity-benchmark.json +1 -1
- package/.agent-context/state/ui-design-judge-report.json +25 -0
- package/.cursorrules +1 -1
- package/.gemini/instructions.md +1 -1
- package/.github/copilot-instructions.md +1 -1
- package/.windsurfrules +1 -1
- package/AGENTS.md +1 -1
- package/lib/cli/commands/init.mjs +4 -0
- package/lib/cli/commands/upgrade.mjs +4 -0
- package/lib/cli/compiler.mjs +15 -0
- package/lib/cli/detector.mjs +118 -2
- package/lib/cli/project-scaffolder.mjs +225 -30
- package/package.json +2 -1
- package/scripts/frontend-usability-audit.mjs +54 -0
- package/scripts/release-gate.mjs +33 -0
- package/scripts/ui-design-judge.mjs +626 -0
- package/scripts/validate.mjs +80 -0
|
@@ -306,6 +306,21 @@ function shouldBootstrapDesignDocument(discoveryAnswers, initContext) {
|
|
|
306
306
|
return false;
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
+
const DESIGN_REQUIRED_SECTIONS = [
|
|
310
|
+
'Design Intent and Product Personality',
|
|
311
|
+
'Audience and Use-Context Signals',
|
|
312
|
+
'Visual Direction and Distinctive Moves',
|
|
313
|
+
'Color Science and Semantic Roles',
|
|
314
|
+
'Typographic Engineering and Hierarchy',
|
|
315
|
+
'Spacing, Layout Rhythm, and Density Strategy',
|
|
316
|
+
'Responsive Strategy and Cross-Viewport Adaptation Matrix',
|
|
317
|
+
'Interaction, Motion, and Feedback Rules',
|
|
318
|
+
'Component Language and Shared Patterns',
|
|
319
|
+
'Accessibility Non-Negotiables',
|
|
320
|
+
'Anti-Patterns to Avoid',
|
|
321
|
+
'Implementation Notes for Future UI Tasks',
|
|
322
|
+
];
|
|
323
|
+
|
|
309
324
|
function inferDesignKeywords(discoveryAnswers) {
|
|
310
325
|
const normalizedDescription = String(discoveryAnswers.projectDescription || '').toLowerCase();
|
|
311
326
|
const normalizedDomain = String(discoveryAnswers.primaryDomain || '').toLowerCase();
|
|
@@ -316,64 +331,114 @@ function inferDesignKeywords(discoveryAnswers) {
|
|
|
316
331
|
|
|
317
332
|
if (aggregateText.includes('commerce') || aggregateText.includes('catalog') || aggregateText.includes('checkout')) {
|
|
318
333
|
return {
|
|
334
|
+
designPhilosophy: 'Conversion clarity with premium restraint.',
|
|
319
335
|
brandAdjectives: ['clear', 'desirable', 'confident'],
|
|
320
336
|
antiAdjectives: ['cluttered', 'hesitant', 'coupon-noisy'],
|
|
337
|
+
typographyScaleRatio: '1.200',
|
|
338
|
+
baseGridUnit: 8,
|
|
339
|
+
densityMode: 'conversion-focused',
|
|
340
|
+
colorIntent: 'Use a restrained neutral foundation with one controlled accent reserved for buying cues and trust moments.',
|
|
321
341
|
distinctiveMoves: [
|
|
322
342
|
'Use product hierarchy and buying cues without turning the interface into a discount template.',
|
|
323
343
|
'Keep decision-critical information prominent while secondary merchandising stays quiet.',
|
|
324
344
|
'Let imagery and spacing create premium perception before decorative effects do.',
|
|
325
345
|
],
|
|
346
|
+
mutationRules: {
|
|
347
|
+
mobile: 'Convert browsing into vertically stacked product cards, move cart and filter actions into sticky or bottom-sheet patterns, and keep thumb-reach actions persistent.',
|
|
348
|
+
tablet: 'Preserve browsing flow with a two-column rhythm, collapse tertiary filters, and keep comparison moments visible without forcing desktop density.',
|
|
349
|
+
desktop: 'Expose multi-column merchandising, comparison views, and richer product context while keeping the purchase path visually dominant.',
|
|
350
|
+
},
|
|
326
351
|
};
|
|
327
352
|
}
|
|
328
353
|
|
|
329
354
|
if (aggregateText.includes('dashboard') || aggregateText.includes('operations') || aggregateText.includes('report')) {
|
|
330
355
|
return {
|
|
356
|
+
designPhilosophy: 'Operational calm under high information density.',
|
|
331
357
|
brandAdjectives: ['calm', 'precise', 'trustworthy'],
|
|
332
358
|
antiAdjectives: ['chaotic', 'gimmicky', 'visually exhausting'],
|
|
359
|
+
typographyScaleRatio: '1.125',
|
|
360
|
+
baseGridUnit: 4,
|
|
361
|
+
densityMode: 'high-density-scanning',
|
|
362
|
+
colorIntent: 'Use neutrals for structure and reserve accent saturation for status shifts, risky actions, and alerts.',
|
|
333
363
|
distinctiveMoves: [
|
|
334
364
|
'Prioritize scanning clarity and status recognition over decorative density.',
|
|
335
365
|
'Use visual weight to separate signal from operational noise.',
|
|
336
366
|
'Reserve strong accents for alerts, decisions, and state transitions only.',
|
|
337
367
|
],
|
|
368
|
+
mutationRules: {
|
|
369
|
+
mobile: 'Collapse dense tables into prioritized cards or row groups, move filters into drawers or sheets, and pin the most critical actions to the bottom reach zone.',
|
|
370
|
+
tablet: 'Keep two-column or split-pane workflows, collapse tertiary panels, and maintain fast scan paths for operators using touch or keyboard.',
|
|
371
|
+
desktop: 'Expose the highest-density views with visible navigation, comparison surfaces, and simultaneous context panels for power users.',
|
|
372
|
+
},
|
|
338
373
|
};
|
|
339
374
|
}
|
|
340
375
|
|
|
341
376
|
if (aggregateText.includes('developer') || aggregateText.includes('api') || aggregateText.includes('platform')) {
|
|
342
377
|
return {
|
|
378
|
+
designPhilosophy: 'Technical precision with explicit structure and honest feedback.',
|
|
343
379
|
brandAdjectives: ['precise', 'technical', 'transparent'],
|
|
344
380
|
antiAdjectives: ['vague', 'marketing-heavy', 'template-polished'],
|
|
381
|
+
typographyScaleRatio: '1.125',
|
|
382
|
+
baseGridUnit: 4,
|
|
383
|
+
densityMode: 'technical-utility',
|
|
384
|
+
colorIntent: 'Anchor the interface in disciplined neutrals and use accent color only where state, feedback, or code-adjacent interaction needs emphasis.',
|
|
345
385
|
distinctiveMoves: [
|
|
346
386
|
'Make structure and feedback feel exact without becoming sterile.',
|
|
347
387
|
'Use code-adjacent rhythm and hierarchy to build trust with technical users.',
|
|
348
388
|
'Keep complexity legible through spacing, grouping, and explicit interaction states.',
|
|
349
389
|
],
|
|
390
|
+
mutationRules: {
|
|
391
|
+
mobile: 'Switch multi-pane technical layouts into stacked sections, turn secondary navigation into segmented or sheet-based controls, and keep commands near the content they affect.',
|
|
392
|
+
tablet: 'Retain split-view comprehension where possible, compress chrome, and keep documentation or diagnostics adjacent to the active task.',
|
|
393
|
+
desktop: 'Expose full navigation, dense comparison surfaces, and multi-pane workflows for expert scanning and debugging.',
|
|
394
|
+
},
|
|
350
395
|
};
|
|
351
396
|
}
|
|
352
397
|
|
|
353
398
|
if (aggregateText.includes('content') || aggregateText.includes('community') || aggregateText.includes('publish')) {
|
|
354
399
|
return {
|
|
400
|
+
designPhilosophy: 'Editorial flow with warm but controlled expression.',
|
|
355
401
|
brandAdjectives: ['editorial', 'warm', 'expressive'],
|
|
356
402
|
antiAdjectives: ['flat', 'anonymous', 'feed-generic'],
|
|
403
|
+
typographyScaleRatio: '1.200',
|
|
404
|
+
baseGridUnit: 8,
|
|
405
|
+
densityMode: 'reading-first',
|
|
406
|
+
colorIntent: 'Let typography and surface contrast lead while chroma supports hierarchy and key participation actions.',
|
|
357
407
|
distinctiveMoves: [
|
|
358
408
|
'Build a strong reading rhythm so content feels curated rather than dumped into cards.',
|
|
359
409
|
'Use contrast and spacing to guide attention between creation, moderation, and discovery.',
|
|
360
410
|
'Give key interaction moments personality without sacrificing clarity.',
|
|
361
411
|
],
|
|
412
|
+
mutationRules: {
|
|
413
|
+
mobile: 'Prioritize reading and contribution flows in a single-column narrative stack, tuck secondary discovery tools behind sheets, and keep primary creation actions within reach.',
|
|
414
|
+
tablet: 'Balance narrative reading with supporting discovery modules, using two-column compositions only where hierarchy stays obvious.',
|
|
415
|
+
desktop: 'Use wider editorial compositions, visible secondary navigation, and modular discovery surfaces without breaking reading rhythm.',
|
|
416
|
+
},
|
|
362
417
|
};
|
|
363
418
|
}
|
|
364
419
|
|
|
365
420
|
return {
|
|
421
|
+
designPhilosophy: 'Project-specific clarity with one authored tension.',
|
|
366
422
|
brandAdjectives: ['clear', 'human', 'distinct'],
|
|
367
423
|
antiAdjectives: ['generic', 'template-like', 'trend-chasing'],
|
|
424
|
+
typographyScaleRatio: '1.200',
|
|
425
|
+
baseGridUnit: 8,
|
|
426
|
+
densityMode: 'balanced-authored',
|
|
427
|
+
colorIntent: 'Use a restrained perceptual palette with one deliberate accent budget instead of interchangeable template colors.',
|
|
368
428
|
distinctiveMoves: [
|
|
369
429
|
'Create a visual direction with one memorable tension instead of stacking fashionable effects.',
|
|
370
430
|
'Use rhythm, hierarchy, and motion intentionally so the interface feels authored.',
|
|
371
431
|
'Keep the system flexible enough to evolve with product scope without losing identity.',
|
|
372
432
|
],
|
|
433
|
+
mutationRules: {
|
|
434
|
+
mobile: 'Stack primary tasks vertically, convert secondary navigation into thumb-friendly overlays or sheets, and simplify dense comparison layouts into progressive disclosure.',
|
|
435
|
+
tablet: 'Preserve hierarchy with fewer columns, condensed chrome, and adaptive navigation that maintains task continuity.',
|
|
436
|
+
desktop: 'Expose the full layout system, highest information density, and broadest navigation affordances without sacrificing clarity.',
|
|
437
|
+
},
|
|
373
438
|
};
|
|
374
439
|
}
|
|
375
440
|
|
|
376
|
-
|
|
441
|
+
function buildDesignIntentContractObject({
|
|
377
442
|
projectName,
|
|
378
443
|
projectDescription,
|
|
379
444
|
primaryDomain,
|
|
@@ -390,7 +455,7 @@ export function buildDesignIntentSeedFromSignals({
|
|
|
390
455
|
});
|
|
391
456
|
const designSignals = architectureRecommendation?.designGuidance?.normalizedSignals || null;
|
|
392
457
|
|
|
393
|
-
return
|
|
458
|
+
return {
|
|
394
459
|
mode: 'dynamic',
|
|
395
460
|
status,
|
|
396
461
|
project: {
|
|
@@ -400,6 +465,7 @@ export function buildDesignIntentSeedFromSignals({
|
|
|
400
465
|
stack: toTitleCase(initContext.stackFileName),
|
|
401
466
|
blueprint: toTitleCase(initContext.blueprintFileName),
|
|
402
467
|
},
|
|
468
|
+
designPhilosophy: inferredKeywords.designPhilosophy,
|
|
403
469
|
brandAdjectives: inferredKeywords.brandAdjectives,
|
|
404
470
|
antiAdjectives: inferredKeywords.antiAdjectives,
|
|
405
471
|
visualDirection: {
|
|
@@ -407,41 +473,162 @@ export function buildDesignIntentSeedFromSignals({
|
|
|
407
473
|
distinctiveMoves: inferredKeywords.distinctiveMoves,
|
|
408
474
|
copiedReferenceAllowed: false,
|
|
409
475
|
},
|
|
476
|
+
mathSystems: {
|
|
477
|
+
typographyScaleRatio: inferredKeywords.typographyScaleRatio,
|
|
478
|
+
baseGridUnit: inferredKeywords.baseGridUnit,
|
|
479
|
+
spacingPattern: designSignals?.spacingPattern || 'balanced-grid',
|
|
480
|
+
densityMode: inferredKeywords.densityMode,
|
|
481
|
+
},
|
|
482
|
+
colorTruth: {
|
|
483
|
+
format: 'OKLCH',
|
|
484
|
+
allowHexDerivatives: true,
|
|
485
|
+
requirePerceptualLightnessCurve: true,
|
|
486
|
+
paletteRoles: designSignals?.paletteRoles || ['base', 'surface', 'accent'],
|
|
487
|
+
intent: inferredKeywords.colorIntent,
|
|
488
|
+
},
|
|
489
|
+
crossViewportAdaptation: {
|
|
490
|
+
adaptByRecomposition: true,
|
|
491
|
+
touchTargetMinPx: 44,
|
|
492
|
+
mutationRules: inferredKeywords.mutationRules,
|
|
493
|
+
},
|
|
410
494
|
experiencePrinciples: [
|
|
411
495
|
'Design must feel project-specific, not interchangeable with generic SaaS templates.',
|
|
412
496
|
'Major interface decisions must be explainable in product and user terms.',
|
|
413
497
|
'Accessibility, responsiveness, and implementation realism are non-negotiable.',
|
|
498
|
+
'Cross-viewport behavior must reorganize tasks and navigation, not just scale the desktop layout down.',
|
|
414
499
|
],
|
|
415
500
|
forbiddenPatterns: [
|
|
416
501
|
'generic-saas-hero',
|
|
417
502
|
'copycat-brand-system',
|
|
418
503
|
'unjustified-default-gradients',
|
|
419
504
|
'placeholder-design-language',
|
|
505
|
+
'scale-only-responsive-layout',
|
|
420
506
|
],
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
'Interaction, Motion, and Feedback Rules',
|
|
429
|
-
'Component Language and Shared Patterns',
|
|
430
|
-
'Accessibility Non-Negotiables',
|
|
431
|
-
'Responsive Strategy',
|
|
432
|
-
'Anti-Patterns to Avoid',
|
|
433
|
-
'Implementation Notes for Future UI Tasks',
|
|
434
|
-
],
|
|
507
|
+
validationHints: {
|
|
508
|
+
rejectArbitraryHexOnlyPalette: true,
|
|
509
|
+
requireViewportMutationRules: true,
|
|
510
|
+
requirePerceptualColorRationale: true,
|
|
511
|
+
allowHexDerivatives: true,
|
|
512
|
+
},
|
|
513
|
+
requiredDesignSections: DESIGN_REQUIRED_SECTIONS,
|
|
435
514
|
implementation: {
|
|
436
515
|
requiredDeliverables: ['docs/DESIGN.md', 'docs/design-intent.json'],
|
|
437
516
|
requireDesignRationale: true,
|
|
438
517
|
requireDistinctVisualDirection: true,
|
|
439
518
|
requireMachineReadableContract: true,
|
|
519
|
+
requireViewportMutationRules: true,
|
|
440
520
|
bootstrapPrompt: '.agent-context/prompts/bootstrap-design.md',
|
|
521
|
+
autoLoadedRuleFiles: [
|
|
522
|
+
'.agent-context/prompts/bootstrap-design.md',
|
|
523
|
+
'.agent-context/rules/frontend-architecture.md',
|
|
524
|
+
],
|
|
525
|
+
disallowedAutoLoadedRuleFiles: [
|
|
526
|
+
'.agent-context/rules/database-design.md',
|
|
527
|
+
'.agent-context/rules/docker-runtime.md',
|
|
528
|
+
'.agent-context/rules/microservices.md',
|
|
529
|
+
],
|
|
441
530
|
},
|
|
442
531
|
architectSignals: designSignals,
|
|
443
532
|
...supplementalFields,
|
|
444
|
-
}
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
export function validateDesignIntentContract(designIntentContract) {
|
|
537
|
+
const validationErrors = [];
|
|
538
|
+
|
|
539
|
+
if (!designIntentContract || typeof designIntentContract !== 'object') {
|
|
540
|
+
return ['Design intent contract must be an object.'];
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (designIntentContract.mode !== 'dynamic') {
|
|
544
|
+
validationErrors.push('designIntent.mode must equal "dynamic".');
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (!designIntentContract.project || typeof designIntentContract.project !== 'object') {
|
|
548
|
+
validationErrors.push('designIntent.project must exist.');
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (!designIntentContract.designPhilosophy || typeof designIntentContract.designPhilosophy !== 'string') {
|
|
552
|
+
validationErrors.push('designIntent.designPhilosophy must be a non-empty string.');
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if (!designIntentContract.mathSystems || typeof designIntentContract.mathSystems !== 'object') {
|
|
556
|
+
validationErrors.push('designIntent.mathSystems must exist.');
|
|
557
|
+
} else {
|
|
558
|
+
if (!/^\d+(\.\d+)?$/.test(String(designIntentContract.mathSystems.typographyScaleRatio || '').trim())) {
|
|
559
|
+
validationErrors.push('designIntent.mathSystems.typographyScaleRatio must be numeric text.');
|
|
560
|
+
}
|
|
561
|
+
if (!Number.isInteger(designIntentContract.mathSystems.baseGridUnit) || designIntentContract.mathSystems.baseGridUnit <= 0) {
|
|
562
|
+
validationErrors.push('designIntent.mathSystems.baseGridUnit must be a positive integer.');
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (!designIntentContract.colorTruth || typeof designIntentContract.colorTruth !== 'object') {
|
|
567
|
+
validationErrors.push('designIntent.colorTruth must exist.');
|
|
568
|
+
} else {
|
|
569
|
+
if (designIntentContract.colorTruth.format !== 'OKLCH') {
|
|
570
|
+
validationErrors.push('designIntent.colorTruth.format must equal "OKLCH".');
|
|
571
|
+
}
|
|
572
|
+
if (designIntentContract.colorTruth.allowHexDerivatives !== true) {
|
|
573
|
+
validationErrors.push('designIntent.colorTruth.allowHexDerivatives must equal true.');
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
if (!designIntentContract.crossViewportAdaptation || typeof designIntentContract.crossViewportAdaptation !== 'object') {
|
|
578
|
+
validationErrors.push('designIntent.crossViewportAdaptation must exist.');
|
|
579
|
+
} else {
|
|
580
|
+
const mutationRules = designIntentContract.crossViewportAdaptation.mutationRules;
|
|
581
|
+
if (!mutationRules || typeof mutationRules !== 'object') {
|
|
582
|
+
validationErrors.push('designIntent.crossViewportAdaptation.mutationRules must exist.');
|
|
583
|
+
} else {
|
|
584
|
+
for (const viewportKey of ['mobile', 'tablet', 'desktop']) {
|
|
585
|
+
if (!String(mutationRules[viewportKey] || '').trim()) {
|
|
586
|
+
validationErrors.push(`designIntent.crossViewportAdaptation.mutationRules.${viewportKey} must be a non-empty string.`);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if (!Array.isArray(designIntentContract.requiredDesignSections) || designIntentContract.requiredDesignSections.length !== DESIGN_REQUIRED_SECTIONS.length) {
|
|
593
|
+
validationErrors.push('designIntent.requiredDesignSections must match the required design contract sections.');
|
|
594
|
+
} else {
|
|
595
|
+
for (const requiredSectionName of DESIGN_REQUIRED_SECTIONS) {
|
|
596
|
+
if (!designIntentContract.requiredDesignSections.includes(requiredSectionName)) {
|
|
597
|
+
validationErrors.push(`designIntent.requiredDesignSections is missing "${requiredSectionName}".`);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
return validationErrors;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
export function buildDesignIntentSeedFromSignals({
|
|
606
|
+
projectName,
|
|
607
|
+
projectDescription,
|
|
608
|
+
primaryDomain,
|
|
609
|
+
features = [],
|
|
610
|
+
initContext,
|
|
611
|
+
architectureRecommendation = null,
|
|
612
|
+
status = 'seed-needs-design-synthesis',
|
|
613
|
+
supplementalFields = {},
|
|
614
|
+
}) {
|
|
615
|
+
const designIntentContract = buildDesignIntentContractObject({
|
|
616
|
+
projectName,
|
|
617
|
+
projectDescription,
|
|
618
|
+
primaryDomain,
|
|
619
|
+
features,
|
|
620
|
+
initContext,
|
|
621
|
+
architectureRecommendation,
|
|
622
|
+
status,
|
|
623
|
+
supplementalFields,
|
|
624
|
+
});
|
|
625
|
+
const validationErrors = validateDesignIntentContract(designIntentContract);
|
|
626
|
+
|
|
627
|
+
if (validationErrors.length > 0) {
|
|
628
|
+
throw new Error(`Invalid design intent contract seed: ${validationErrors.join(' ')}`);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
return `${JSON.stringify(designIntentContract, null, 2)}\n`;
|
|
445
632
|
}
|
|
446
633
|
|
|
447
634
|
function buildDesignIntentSeed({
|
|
@@ -572,13 +759,13 @@ function buildDesignBootstrapPrompt({
|
|
|
572
759
|
'1. Design Vision and Product Personality',
|
|
573
760
|
'2. Audience and Use-Context Signals',
|
|
574
761
|
'3. Visual Direction and Distinctive Moves',
|
|
575
|
-
'4. Color
|
|
576
|
-
'5.
|
|
762
|
+
'4. Color Science and Semantic Roles',
|
|
763
|
+
'5. Typographic Engineering and Hierarchy',
|
|
577
764
|
'6. Spacing, Layout Rhythm, and Density Strategy',
|
|
578
|
-
'7.
|
|
579
|
-
'8.
|
|
580
|
-
'9.
|
|
581
|
-
'10.
|
|
765
|
+
'7. Responsive Strategy and Cross-Viewport Adaptation Matrix',
|
|
766
|
+
'8. Motion and Interaction Principles',
|
|
767
|
+
'9. Component Language (cards, forms, nav, states)',
|
|
768
|
+
'10. Accessibility Non-Negotiables',
|
|
582
769
|
'11. Anti-Patterns to Avoid',
|
|
583
770
|
'12. Implementation Notes for Future UI Tasks',
|
|
584
771
|
'',
|
|
@@ -586,13 +773,18 @@ function buildDesignBootstrapPrompt({
|
|
|
586
773
|
'1. mode',
|
|
587
774
|
'2. status',
|
|
588
775
|
'3. project',
|
|
589
|
-
'4.
|
|
590
|
-
'5.
|
|
591
|
-
'6.
|
|
592
|
-
'7.
|
|
593
|
-
'8.
|
|
594
|
-
'9.
|
|
595
|
-
'10.
|
|
776
|
+
'4. designPhilosophy',
|
|
777
|
+
'5. brandAdjectives',
|
|
778
|
+
'6. antiAdjectives',
|
|
779
|
+
'7. visualDirection',
|
|
780
|
+
'8. mathSystems',
|
|
781
|
+
'9. colorTruth',
|
|
782
|
+
'10. crossViewportAdaptation',
|
|
783
|
+
'11. experiencePrinciples',
|
|
784
|
+
'12. forbiddenPatterns',
|
|
785
|
+
'13. validationHints',
|
|
786
|
+
'14. requiredDesignSections',
|
|
787
|
+
'15. implementation',
|
|
596
788
|
'',
|
|
597
789
|
'## Hard Rules',
|
|
598
790
|
'1. No copy-paste from external style guides.',
|
|
@@ -601,6 +793,9 @@ function buildDesignBootstrapPrompt({
|
|
|
601
793
|
'4. Keep tone decisive like an art director, not generic AI boilerplate.',
|
|
602
794
|
'5. Do not anchor the final design language to a famous brand reference. Translate inspiration into original project-specific principles.',
|
|
603
795
|
'6. Reject interchangeable hero layouts, generic SaaS gradients, and trend-chasing decoration unless the project context explicitly justifies them.',
|
|
796
|
+
'7. Encode color intent in perceptual terms first. Hex values may exist only as implementation derivatives.',
|
|
797
|
+
'8. Responsive guidance must include layout mutation rules for mobile, tablet, and desktop. Shrinking the desktop layout is not enough.',
|
|
798
|
+
'9. Keep UI-only requests context-isolated. Load frontend design rules first and do not eagerly load backend-only rules unless the task explicitly crosses those boundaries.',
|
|
604
799
|
'',
|
|
605
800
|
'## Project Inputs',
|
|
606
801
|
`- Project name: ${discoveryAnswers.projectName}`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryuenn3123/agentic-senior-core",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Force your AI Agent to code like a Staff Engineer, not a Junior.",
|
|
6
6
|
"bin": {
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"scripts": {
|
|
44
44
|
"init": "node ./bin/agentic-senior-core.js init",
|
|
45
45
|
"audit:frontend-usability": "node ./scripts/frontend-usability-audit.mjs",
|
|
46
|
+
"audit:ui-design-judge": "node ./scripts/ui-design-judge.mjs",
|
|
46
47
|
"audit:documentation-boundary": "node ./scripts/documentation-boundary-audit.mjs",
|
|
47
48
|
"audit:context-triggered": "node ./scripts/context-triggered-audit.mjs",
|
|
48
49
|
"audit:rules-guardian": "node ./scripts/rules-guardian-audit.mjs",
|
|
@@ -20,6 +20,9 @@ const REQUIRED_FILES = [
|
|
|
20
20
|
'docs/roadmap.md',
|
|
21
21
|
'docs/v1.7-issue-breakdown.md',
|
|
22
22
|
'docs/v1.7-execution-playbook.md',
|
|
23
|
+
'.instructions.md',
|
|
24
|
+
'.agent-context/prompts/bootstrap-design.md',
|
|
25
|
+
'scripts/ui-design-judge.mjs',
|
|
23
26
|
'.agent-context/rules/frontend-architecture.md',
|
|
24
27
|
'.agent-context/review-checklists/pr-checklist.md',
|
|
25
28
|
'.agent-context/review-checklists/architecture-review.md',
|
|
@@ -53,6 +56,28 @@ const REQUIRED_FRONTEND_RULE_SNIPPETS = [
|
|
|
53
56
|
'UI Consistency Guardrails (Mandatory)',
|
|
54
57
|
'Content language must stay consistent per screen and flow unless user requests multilingual output.',
|
|
55
58
|
'Text color must remain contrast-safe against its background; no color collisions.',
|
|
59
|
+
'Responsive quality requires layout mutation and task reprioritization across breakpoints. Shrinking the desktop layout is not enough.',
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const REQUIRED_BOOTSTRAP_DESIGN_SNIPPETS = [
|
|
63
|
+
'UI Design Mode is context-isolated by default:',
|
|
64
|
+
'Responsive Strategy and Cross-Viewport Adaptation Matrix',
|
|
65
|
+
'colorTruth.format',
|
|
66
|
+
'crossViewportAdaptation.mutationRules.mobile/tablet/desktop',
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
const REQUIRED_UI_DESIGN_JUDGE_SNIPPETS = [
|
|
70
|
+
'Advisory-first UI design contract judge.',
|
|
71
|
+
'Default mode is advisory: findings never block release. Strict mode is opt-in.',
|
|
72
|
+
'Do not reward generic SaaS defaults or popular template patterns.',
|
|
73
|
+
'UI design judge only evaluates changed UI surfaces.',
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
const REQUIRED_INSTRUCTIONS_SNIPPETS = [
|
|
77
|
+
'UI Design Mode',
|
|
78
|
+
'bootstrap-design.md',
|
|
79
|
+
'frontend-architecture.md',
|
|
80
|
+
'do not eagerly load unrelated backend-only rules',
|
|
56
81
|
];
|
|
57
82
|
|
|
58
83
|
function assertFileExists(relativeFilePath, failures) {
|
|
@@ -79,6 +104,8 @@ function runAudit() {
|
|
|
79
104
|
|
|
80
105
|
const roadmapPath = 'docs/roadmap.md';
|
|
81
106
|
const frontendRulePath = '.agent-context/rules/frontend-architecture.md';
|
|
107
|
+
const bootstrapDesignPromptPath = '.agent-context/prompts/bootstrap-design.md';
|
|
108
|
+
const instructionsPath = '.instructions.md';
|
|
82
109
|
const prChecklistPath = '.agent-context/review-checklists/pr-checklist.md';
|
|
83
110
|
const architectureChecklistPath = '.agent-context/review-checklists/architecture-review.md';
|
|
84
111
|
|
|
@@ -97,6 +124,33 @@ function runAudit() {
|
|
|
97
124
|
assertContains('Frontend rule', frontendRulePath, frontendRuleContent, REQUIRED_FRONTEND_RULE_SNIPPETS, failures);
|
|
98
125
|
}
|
|
99
126
|
|
|
127
|
+
if (existsSync(resolve(REPOSITORY_ROOT, bootstrapDesignPromptPath))) {
|
|
128
|
+
const bootstrapDesignPromptContent = readFileSync(resolve(REPOSITORY_ROOT, bootstrapDesignPromptPath), 'utf8');
|
|
129
|
+
assertContains(
|
|
130
|
+
'Bootstrap design prompt',
|
|
131
|
+
bootstrapDesignPromptPath,
|
|
132
|
+
bootstrapDesignPromptContent,
|
|
133
|
+
REQUIRED_BOOTSTRAP_DESIGN_SNIPPETS,
|
|
134
|
+
failures
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (existsSync(resolve(REPOSITORY_ROOT, 'scripts/ui-design-judge.mjs'))) {
|
|
139
|
+
const uiDesignJudgeContent = readFileSync(resolve(REPOSITORY_ROOT, 'scripts/ui-design-judge.mjs'), 'utf8');
|
|
140
|
+
assertContains(
|
|
141
|
+
'UI design judge',
|
|
142
|
+
'scripts/ui-design-judge.mjs',
|
|
143
|
+
uiDesignJudgeContent,
|
|
144
|
+
REQUIRED_UI_DESIGN_JUDGE_SNIPPETS,
|
|
145
|
+
failures
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (existsSync(resolve(REPOSITORY_ROOT, instructionsPath))) {
|
|
150
|
+
const instructionsContent = readFileSync(resolve(REPOSITORY_ROOT, instructionsPath), 'utf8');
|
|
151
|
+
assertContains('Instructions', instructionsPath, instructionsContent, REQUIRED_INSTRUCTIONS_SNIPPETS, failures);
|
|
152
|
+
}
|
|
153
|
+
|
|
100
154
|
if (existsSync(resolve(REPOSITORY_ROOT, architectureChecklistPath))) {
|
|
101
155
|
const excellenceRubricContent = readFileSync(resolve(REPOSITORY_ROOT, architectureChecklistPath), 'utf8');
|
|
102
156
|
assertContains(
|
package/scripts/release-gate.mjs
CHANGED
|
@@ -18,6 +18,7 @@ const REPOSITORY_ROOT = resolve(__dirname, '..');
|
|
|
18
18
|
|
|
19
19
|
const VERSION_PATTERN = /^\d+\.\d+\.\d+$/;
|
|
20
20
|
const FRONTEND_AUDIT_SCRIPT_PATH = 'scripts/frontend-usability-audit.mjs';
|
|
21
|
+
const UI_DESIGN_JUDGE_SCRIPT_PATH = 'scripts/ui-design-judge.mjs';
|
|
21
22
|
const DOCUMENTATION_BOUNDARY_AUDIT_SCRIPT_PATH = 'scripts/documentation-boundary-audit.mjs';
|
|
22
23
|
const CONTEXT_TRIGGERED_AUDIT_SCRIPT_PATH = 'scripts/context-triggered-audit.mjs';
|
|
23
24
|
const RULES_GUARDIAN_AUDIT_SCRIPT_PATH = 'scripts/rules-guardian-audit.mjs';
|
|
@@ -716,6 +717,38 @@ function runReleaseGate() {
|
|
|
716
717
|
pushResult(results, false, 'frontend-usability-audit', `Failed to execute frontend usability audit: ${frontendAuditErrorMessage}`);
|
|
717
718
|
}
|
|
718
719
|
|
|
720
|
+
const uiDesignJudgeExecution = runMachineReadableScript(UI_DESIGN_JUDGE_SCRIPT_PATH);
|
|
721
|
+
if (!uiDesignJudgeExecution.report) {
|
|
722
|
+
const failureDetails = uiDesignJudgeExecution.executionErrorMessage
|
|
723
|
+
? `UI design judge execution failed before producing a machine-readable report: ${uiDesignJudgeExecution.executionErrorMessage}`
|
|
724
|
+
: 'UI design judge did not produce machine-readable JSON output';
|
|
725
|
+
pushResult(results, false, 'ui-design-judge-advisory', failureDetails);
|
|
726
|
+
} else {
|
|
727
|
+
diagnostics.uiDesignJudge = uiDesignJudgeExecution.report;
|
|
728
|
+
pushResult(
|
|
729
|
+
results,
|
|
730
|
+
true,
|
|
731
|
+
'ui-design-judge-advisory',
|
|
732
|
+
`ui-design-judge executed (passed=${uiDesignJudgeExecution.report.passed}, skipped=${uiDesignJudgeExecution.report.skipped}, mode=${uiDesignJudgeExecution.report.mode})`
|
|
733
|
+
);
|
|
734
|
+
|
|
735
|
+
if (uiDesignJudgeExecution.report.advisoryOnly === true) {
|
|
736
|
+
pushResult(
|
|
737
|
+
results,
|
|
738
|
+
true,
|
|
739
|
+
'ui-design-judge-non-blocking-policy',
|
|
740
|
+
'UI design judge remains advisory by default and does not hard-block release gate'
|
|
741
|
+
);
|
|
742
|
+
} else {
|
|
743
|
+
pushResult(
|
|
744
|
+
results,
|
|
745
|
+
false,
|
|
746
|
+
'ui-design-judge-non-blocking-policy',
|
|
747
|
+
'UI design judge unexpectedly ran in blocking mode during release gate'
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
719
752
|
const benchmarkGateExecution = runMachineReadableScript(BENCHMARK_GATE_SCRIPT_PATH);
|
|
720
753
|
if (!benchmarkGateExecution.report) {
|
|
721
754
|
const failureDetails = benchmarkGateExecution.executionErrorMessage
|