aioengine 0.1.0 → 0.1.2

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 +152 -131
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aioengine",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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
@@ -5,13 +5,14 @@ import pc from "picocolors";
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";
7
7
  import { execSync } from "node:child_process";
8
+ import { fileURLToPath } from "node:url";
8
9
 
9
10
  const program = new Command();
10
11
 
11
12
  program
12
13
  .name("aioengine")
13
14
  .description("AI change control for developers using AI coding tools.")
14
- .version("0.1.0");
15
+ .version(getCliVersion());
15
16
 
16
17
  program
17
18
  .command("init")
@@ -438,34 +439,96 @@ function getChangedFiles(root) {
438
439
  }
439
440
 
440
441
  function inferTaskProfile(task) {
441
- const lower = task.toLowerCase();
442
+ const cleanTask = task.toLowerCase();
442
443
 
443
444
  const profiles = [
444
- {
445
+ {
446
+ id: "ui",
447
+ label: "UI / frontend task",
448
+ strongKeywords: [
449
+ "landing page",
450
+ "home page",
451
+ "hero",
452
+ "headline",
453
+ "cta",
454
+ "navbar",
455
+ "footer",
456
+ "layout",
457
+ "mobile",
458
+ "responsive",
459
+ "pricing page",
460
+ "dashboard header",
461
+ ],
462
+ keywords: [
463
+ "ui",
464
+ "frontend",
465
+ "front end",
466
+ "page",
467
+ "component",
468
+ "style",
469
+ "css",
470
+ "tailwind",
471
+ "design",
472
+ "copy",
473
+ "button",
474
+ "card",
475
+ "section",
476
+ ],
477
+ allowed: [
478
+ "src/app/",
479
+ "src/components/",
480
+ "src/siteconfig.ts",
481
+ "public/",
482
+ "next-env.d.ts",
483
+ ],
484
+ sensitive: [
485
+ ".env",
486
+ "auth",
487
+ "stripe",
488
+ "billing",
489
+ "payment",
490
+ "supabase",
491
+ "migration",
492
+ "middleware",
493
+ "package.json",
494
+ ".github/workflows",
495
+ ],
496
+ },
497
+ {
445
498
  id: "cli",
446
499
  label: "CLI / tooling task",
447
- keywords: [
500
+ strongKeywords: [
448
501
  "cli",
449
502
  "command",
503
+ "terminal command",
504
+ "npm package",
505
+ "package executable",
506
+ "bin",
507
+ "commander",
508
+ "aioengine init",
509
+ "aioengine check",
510
+ "aioengine review",
511
+ "aioengine scope",
512
+ "aioengine rules",
513
+ ],
514
+ keywords: [
450
515
  "terminal",
451
516
  "init",
452
517
  "check",
453
518
  "review",
454
519
  "scope",
455
520
  "rules",
456
- "package",
457
521
  "script",
458
522
  "npm",
459
- "bin",
460
- "commander",
461
- "aioengine",
523
+ "package",
524
+ "developer tool",
525
+ "tooling",
526
+ "publish",
462
527
  ],
463
528
  allowed: [
464
529
  "packages/cli/",
465
530
  "package.json",
466
531
  "package-lock.json",
467
- "src/index.js",
468
- "readme",
469
532
  ".aioengine/",
470
533
  "CLAUDE.md",
471
534
  ".cursor/",
@@ -482,179 +545,124 @@ function inferTaskProfile(task) {
482
545
  ".github/workflows",
483
546
  ],
484
547
  },
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
548
  {
543
549
  id: "docs",
544
550
  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
- ],
551
+ strongKeywords: ["readme", "documentation", "docs"],
552
+ keywords: ["copy", "text", "wording", "content", "instructions"],
553
+ allowed: ["README", "readme", "docs/", ".md", "CLAUDE.md"],
564
554
  sensitive: [
565
- "api/",
555
+ ".env",
566
556
  "auth",
567
557
  "stripe",
568
558
  "billing",
569
559
  "payment",
570
560
  "supabase",
571
561
  "migration",
572
- ".env",
573
- "package.json",
574
562
  "middleware",
563
+ "package.json",
575
564
  ],
576
565
  },
577
566
  {
578
567
  id: "backend",
579
568
  label: "Backend / API task",
569
+ strongKeywords: ["api route", "route handler", "database", "server action"],
580
570
  keywords: [
581
571
  "api",
582
- "route",
583
- "server",
584
572
  "backend",
573
+ "server",
585
574
  "database",
586
575
  "supabase",
576
+ "schema",
577
+ "auth",
587
578
  "webhook",
588
579
  "stripe",
589
- "auth",
590
- "login",
591
- "billing",
592
580
  ],
593
581
  allowed: [
594
- "api/",
595
- "server",
596
- "lib/",
582
+ "src/app/api/",
597
583
  "src/lib/",
598
- "supabase",
599
- "schema",
600
- "migration",
601
- "middleware",
584
+ "supabase/",
585
+ "prisma/",
602
586
  "package.json",
603
587
  ],
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
588
  sensitive: [
619
589
  ".env",
620
- "auth",
621
- "session",
622
590
  "stripe",
623
591
  "billing",
624
592
  "payment",
625
- "supabase",
593
+ "auth",
626
594
  "migration",
627
595
  "schema",
628
596
  "rls",
629
597
  "middleware",
630
- "package.json",
631
- "package-lock.json",
632
- ".github/workflows",
633
598
  ],
599
+ },
600
+ ];
601
+
602
+ const scoredProfiles = profiles
603
+ .map((profile) => {
604
+ const strongScore = profile.strongKeywords.filter((keyword) =>
605
+ cleanTask.includes(keyword)
606
+ ).length;
607
+
608
+ const normalScore = profile.keywords.filter((keyword) =>
609
+ cleanTask.includes(keyword)
610
+ ).length;
611
+
612
+ return {
613
+ ...profile,
614
+ score: strongScore * 3 + normalScore,
615
+ };
616
+ })
617
+ .filter((profile) => profile.score > 0)
618
+ .sort((a, b) => b.score - a.score);
619
+
620
+ return (
621
+ scoredProfiles[0] ?? {
622
+ id: "unknown",
623
+ label: "Unknown / general task",
624
+ allowed: [],
625
+ sensitive: [],
634
626
  }
635
627
  );
636
628
  }
637
629
 
638
630
  function isProbablyOutOfScope(file, profile) {
639
- const lower = file.toLowerCase();
640
-
641
- if (profile.id === "unknown") {
631
+ if (!profile || profile.id === "unknown") {
642
632
  return false;
643
633
  }
644
634
 
645
- const touchesSensitiveArea = profile.sensitive.some((pattern) =>
646
- lower.includes(pattern)
647
- );
635
+ const normalizedFile = file.replaceAll("\\", "/").toLowerCase();
636
+
637
+ const allowedPatterns = profile.allowed ?? [];
638
+ const sensitivePatterns = profile.sensitive ?? [];
639
+
640
+ const isAllowed = allowedPatterns.some((pattern) => {
641
+ const normalizedPattern = pattern.replaceAll("\\", "/").toLowerCase();
642
+
643
+ if (normalizedPattern.endsWith("/")) {
644
+ return normalizedFile.startsWith(normalizedPattern);
645
+ }
646
+
647
+ return (
648
+ normalizedFile === normalizedPattern ||
649
+ normalizedFile.includes(normalizedPattern)
650
+ );
651
+ });
648
652
 
649
- if (!touchesSensitiveArea) {
653
+ if (isAllowed) {
650
654
  return false;
651
655
  }
652
656
 
653
- const explicitlyAllowed = profile.allowed.some((pattern) =>
654
- lower.includes(pattern)
657
+ const isSensitive = sensitivePatterns.some((pattern) =>
658
+ normalizedFile.includes(pattern.toLowerCase())
655
659
  );
656
660
 
657
- return !explicitlyAllowed;
661
+ if (isSensitive) {
662
+ return true;
663
+ }
664
+
665
+ return allowedPatterns.length > 0;
658
666
  }
659
667
 
660
668
  function isRiskyFile(file) {
@@ -887,4 +895,17 @@ Do not add dependencies without a clear reason.
887
895
 
888
896
  For UI-only tasks, avoid backend, API, database, and config changes.
889
897
  `;
898
+ }
899
+
900
+ function getCliVersion() {
901
+ try {
902
+ const currentFile = fileURLToPath(import.meta.url);
903
+ const currentDir = path.dirname(currentFile);
904
+ const packagePath = path.join(currentDir, "..", "package.json");
905
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
906
+
907
+ return packageJson.version ?? "0.0.0";
908
+ } catch {
909
+ return "0.0.0";
910
+ }
890
911
  }