aioengine 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +137 -130
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aioengine",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "AI change control for developers using AI coding tools.",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -438,34 +438,96 @@ function getChangedFiles(root) {
438
438
  }
439
439
 
440
440
  function inferTaskProfile(task) {
441
- const lower = task.toLowerCase();
441
+ const cleanTask = task.toLowerCase();
442
442
 
443
443
  const profiles = [
444
- {
444
+ {
445
+ id: "ui",
446
+ label: "UI / frontend task",
447
+ strongKeywords: [
448
+ "landing page",
449
+ "home page",
450
+ "hero",
451
+ "headline",
452
+ "cta",
453
+ "navbar",
454
+ "footer",
455
+ "layout",
456
+ "mobile",
457
+ "responsive",
458
+ "pricing page",
459
+ "dashboard header",
460
+ ],
461
+ keywords: [
462
+ "ui",
463
+ "frontend",
464
+ "front end",
465
+ "page",
466
+ "component",
467
+ "style",
468
+ "css",
469
+ "tailwind",
470
+ "design",
471
+ "copy",
472
+ "button",
473
+ "card",
474
+ "section",
475
+ ],
476
+ allowed: [
477
+ "src/app/",
478
+ "src/components/",
479
+ "src/siteconfig.ts",
480
+ "public/",
481
+ "next-env.d.ts",
482
+ ],
483
+ sensitive: [
484
+ ".env",
485
+ "auth",
486
+ "stripe",
487
+ "billing",
488
+ "payment",
489
+ "supabase",
490
+ "migration",
491
+ "middleware",
492
+ "package.json",
493
+ ".github/workflows",
494
+ ],
495
+ },
496
+ {
445
497
  id: "cli",
446
498
  label: "CLI / tooling task",
447
- keywords: [
499
+ strongKeywords: [
448
500
  "cli",
449
501
  "command",
502
+ "terminal command",
503
+ "npm package",
504
+ "package executable",
505
+ "bin",
506
+ "commander",
507
+ "aioengine init",
508
+ "aioengine check",
509
+ "aioengine review",
510
+ "aioengine scope",
511
+ "aioengine rules",
512
+ ],
513
+ keywords: [
450
514
  "terminal",
451
515
  "init",
452
516
  "check",
453
517
  "review",
454
518
  "scope",
455
519
  "rules",
456
- "package",
457
520
  "script",
458
521
  "npm",
459
- "bin",
460
- "commander",
461
- "aioengine",
522
+ "package",
523
+ "developer tool",
524
+ "tooling",
525
+ "publish",
462
526
  ],
463
527
  allowed: [
464
528
  "packages/cli/",
465
529
  "package.json",
466
530
  "package-lock.json",
467
- "src/index.js",
468
- "readme",
469
531
  ".aioengine/",
470
532
  "CLAUDE.md",
471
533
  ".cursor/",
@@ -482,179 +544,124 @@ function inferTaskProfile(task) {
482
544
  ".github/workflows",
483
545
  ],
484
546
  },
485
- {
486
- id: "ui",
487
- label: "UI / frontend task",
488
- keywords: [
489
- "ui",
490
- "layout",
491
- "style",
492
- "design",
493
- "button",
494
- "card",
495
- "page",
496
- "copy",
497
- "text",
498
- "color",
499
- "colour",
500
- "spacing",
501
- "responsive",
502
- "navbar",
503
- "footer",
504
- "hero",
505
- "landing",
506
- "pricing",
507
- "headline",
508
- ],
509
- allowed: [
510
- "app/",
511
- "pages/",
512
- "components/",
513
- "styles/",
514
- "public/",
515
- "src/app/",
516
- "src/components/",
517
- "src/styles/",
518
- ".css",
519
- ".tsx",
520
- ".jsx",
521
- ],
522
- sensitive: [
523
- "api/",
524
- "auth",
525
- "session",
526
- "stripe",
527
- "billing",
528
- "payment",
529
- "supabase",
530
- "migration",
531
- "schema",
532
- "rls",
533
- ".env",
534
- "package.json",
535
- "package-lock.json",
536
- "middleware",
537
- ".github/workflows",
538
- "next.config",
539
- "vercel",
540
- ],
541
- },
542
547
  {
543
548
  id: "docs",
544
549
  label: "Docs / copy task",
545
- keywords: [
546
- "docs",
547
- "readme",
548
- "copy",
549
- "text",
550
- "wording",
551
- "content",
552
- "landing page copy",
553
- "headline",
554
- "description",
555
- ],
556
- allowed: [
557
- ".md",
558
- "readme",
559
- "app/",
560
- "src/app/",
561
- "components/",
562
- "src/components/",
563
- ],
550
+ strongKeywords: ["readme", "documentation", "docs"],
551
+ keywords: ["copy", "text", "wording", "content", "instructions"],
552
+ allowed: ["README", "readme", "docs/", ".md", "CLAUDE.md"],
564
553
  sensitive: [
565
- "api/",
554
+ ".env",
566
555
  "auth",
567
556
  "stripe",
568
557
  "billing",
569
558
  "payment",
570
559
  "supabase",
571
560
  "migration",
572
- ".env",
573
- "package.json",
574
561
  "middleware",
562
+ "package.json",
575
563
  ],
576
564
  },
577
565
  {
578
566
  id: "backend",
579
567
  label: "Backend / API task",
568
+ strongKeywords: ["api route", "route handler", "database", "server action"],
580
569
  keywords: [
581
570
  "api",
582
- "route",
583
- "server",
584
571
  "backend",
572
+ "server",
585
573
  "database",
586
574
  "supabase",
575
+ "schema",
576
+ "auth",
587
577
  "webhook",
588
578
  "stripe",
589
- "auth",
590
- "login",
591
- "billing",
592
579
  ],
593
580
  allowed: [
594
- "api/",
595
- "server",
596
- "lib/",
581
+ "src/app/api/",
597
582
  "src/lib/",
598
- "supabase",
599
- "schema",
600
- "migration",
601
- "middleware",
583
+ "supabase/",
584
+ "prisma/",
602
585
  "package.json",
603
586
  ],
604
- sensitive: [".env", "billing", "payment", "stripe", "auth", "rls", "migration"],
605
- },
606
- ];
607
-
608
- const matched = profiles.find((profile) =>
609
- profile.keywords.some((keyword) => lower.includes(keyword))
610
- );
611
-
612
- return (
613
- matched ?? {
614
- id: "unknown",
615
- label: "Unknown / general task",
616
- keywords: [],
617
- allowed: [],
618
587
  sensitive: [
619
588
  ".env",
620
- "auth",
621
- "session",
622
589
  "stripe",
623
590
  "billing",
624
591
  "payment",
625
- "supabase",
592
+ "auth",
626
593
  "migration",
627
594
  "schema",
628
595
  "rls",
629
596
  "middleware",
630
- "package.json",
631
- "package-lock.json",
632
- ".github/workflows",
633
597
  ],
598
+ },
599
+ ];
600
+
601
+ const scoredProfiles = profiles
602
+ .map((profile) => {
603
+ const strongScore = profile.strongKeywords.filter((keyword) =>
604
+ cleanTask.includes(keyword)
605
+ ).length;
606
+
607
+ const normalScore = profile.keywords.filter((keyword) =>
608
+ cleanTask.includes(keyword)
609
+ ).length;
610
+
611
+ return {
612
+ ...profile,
613
+ score: strongScore * 3 + normalScore,
614
+ };
615
+ })
616
+ .filter((profile) => profile.score > 0)
617
+ .sort((a, b) => b.score - a.score);
618
+
619
+ return (
620
+ scoredProfiles[0] ?? {
621
+ id: "unknown",
622
+ label: "Unknown / general task",
623
+ allowed: [],
624
+ sensitive: [],
634
625
  }
635
626
  );
636
627
  }
637
628
 
638
629
  function isProbablyOutOfScope(file, profile) {
639
- const lower = file.toLowerCase();
640
-
641
- if (profile.id === "unknown") {
630
+ if (!profile || profile.id === "unknown") {
642
631
  return false;
643
632
  }
644
633
 
645
- const touchesSensitiveArea = profile.sensitive.some((pattern) =>
646
- lower.includes(pattern)
647
- );
634
+ const normalizedFile = file.replaceAll("\\", "/").toLowerCase();
635
+
636
+ const allowedPatterns = profile.allowed ?? [];
637
+ const sensitivePatterns = profile.sensitive ?? [];
648
638
 
649
- if (!touchesSensitiveArea) {
639
+ const isAllowed = allowedPatterns.some((pattern) => {
640
+ const normalizedPattern = pattern.replaceAll("\\", "/").toLowerCase();
641
+
642
+ if (normalizedPattern.endsWith("/")) {
643
+ return normalizedFile.startsWith(normalizedPattern);
644
+ }
645
+
646
+ return (
647
+ normalizedFile === normalizedPattern ||
648
+ normalizedFile.includes(normalizedPattern)
649
+ );
650
+ });
651
+
652
+ if (isAllowed) {
650
653
  return false;
651
654
  }
652
655
 
653
- const explicitlyAllowed = profile.allowed.some((pattern) =>
654
- lower.includes(pattern)
656
+ const isSensitive = sensitivePatterns.some((pattern) =>
657
+ normalizedFile.includes(pattern.toLowerCase())
655
658
  );
656
659
 
657
- return !explicitlyAllowed;
660
+ if (isSensitive) {
661
+ return true;
662
+ }
663
+
664
+ return allowedPatterns.length > 0;
658
665
  }
659
666
 
660
667
  function isRiskyFile(file) {