@appsforgood/next-supabase-kit 0.4.2 → 0.4.3
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/CHANGELOG.md +10 -0
- package/README.md +2 -1
- package/UPGRADE.md +12 -0
- package/USER_GUIDE.html +9 -2
- package/USER_GUIDE.md +1 -0
- package/dist/index.js +319 -242
- package/dist/index.js.map +1 -1
- package/examples/next-supabase-installed/.antigravity/runtime-skills/deslop/SKILL.md +7 -1
- package/examples/next-supabase-installed/.antigravity/runtime-skills/frontend-design/SKILL.md +3 -1
- package/examples/next-supabase-installed/.antigravity/runtime-skills/planning/SKILL.md +1 -1
- package/examples/next-supabase-installed/.antigravity/runtime-skills/testing-qa/SKILL.md +2 -0
- package/examples/next-supabase-installed/.cursor/skills/deslop/SKILL.md +7 -1
- package/examples/next-supabase-installed/.cursor/skills/frontend-design/SKILL.md +3 -1
- package/examples/next-supabase-installed/.cursor/skills/planning/SKILL.md +1 -1
- package/examples/next-supabase-installed/.cursor/skills/testing-qa/SKILL.md +2 -0
- package/examples/next-supabase-installed/USER_GUIDE.html +9 -2
- package/examples/next-supabase-installed/USER_GUIDE.md +1 -0
- package/examples/next-supabase-installed/skills/deslop/SKILL.md +7 -1
- package/examples/next-supabase-installed/skills/frontend-design/SKILL.md +3 -1
- package/examples/next-supabase-installed/skills/planning/SKILL.md +1 -1
- package/examples/next-supabase-installed/skills/testing-qa/SKILL.md +2 -0
- package/package.json +1 -1
- package/skills/deslop/SKILL.md +7 -1
- package/skills/frontend-design/SKILL.md +3 -1
- package/skills/planning/SKILL.md +1 -1
- package/skills/testing-qa/SKILL.md +2 -0
package/dist/index.js
CHANGED
|
@@ -25,11 +25,12 @@ function findPackageRoot(start = dirname(fileURLToPath(import.meta.url))) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// src/catalog.ts
|
|
28
|
-
var
|
|
28
|
+
var catalogByRoot = /* @__PURE__ */ new Map();
|
|
29
29
|
function loadCatalog(packageRoot = findPackageRoot()) {
|
|
30
|
-
|
|
30
|
+
const existing = catalogByRoot.get(packageRoot);
|
|
31
|
+
if (existing) return existing;
|
|
31
32
|
const parsed = JSON.parse(readFileSync(join2(packageRoot, "catalog.json"), "utf8"));
|
|
32
|
-
|
|
33
|
+
catalogByRoot.set(packageRoot, parsed);
|
|
33
34
|
return parsed;
|
|
34
35
|
}
|
|
35
36
|
function agentSourcePath(packageRoot, id) {
|
|
@@ -423,8 +424,222 @@ function addSkill(cwd, skillName, options = {}) {
|
|
|
423
424
|
}
|
|
424
425
|
|
|
425
426
|
// src/install/adapter-validate.ts
|
|
427
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
428
|
+
import { join as join7 } from "path";
|
|
429
|
+
|
|
430
|
+
// src/config/defaults.ts
|
|
431
|
+
var PACKAGE_NAME = "@appsforgood/next-supabase-kit";
|
|
432
|
+
var PACKAGE_VERSION = "0.4.3";
|
|
433
|
+
var ROOT_DOCS = ["AGENTS.md", "USER_GUIDE.md", "USER_GUIDE.html"];
|
|
434
|
+
var CURSOR_RULE_FILE = {
|
|
435
|
+
source: "assistant-adapters/cursor-agent-kit.mdc",
|
|
436
|
+
target: ".cursor/rules/cursor-agent-kit.mdc"
|
|
437
|
+
};
|
|
438
|
+
var CLAUDE_TEMPLATE = "templates/next-supabase/CLAUDE.md";
|
|
439
|
+
var USER_GUIDE_SOURCE = "USER_GUIDE.md";
|
|
440
|
+
var USER_GUIDE_HTML_SOURCE = "USER_GUIDE.html";
|
|
441
|
+
var AGENTS_DOC_SOURCE = "templates/next-supabase/AGENTS.md";
|
|
442
|
+
|
|
443
|
+
// src/install/ide-activate.ts
|
|
444
|
+
var IDE_TARGETS = ["cursor", "claude", "codex", "copilot", "antigravity"];
|
|
445
|
+
var ALLOWED = new Set(IDE_TARGETS);
|
|
446
|
+
function isIdeTarget(value) {
|
|
447
|
+
return ALLOWED.has(value);
|
|
448
|
+
}
|
|
449
|
+
var InvalidActivateTargetError = class extends Error {
|
|
450
|
+
constructor(invalid) {
|
|
451
|
+
super(`Unknown --activate target(s): ${invalid.join(", ")}. Allowed: cursor, claude, codex, copilot, antigravity, all.`);
|
|
452
|
+
this.invalid = invalid;
|
|
453
|
+
this.name = "InvalidActivateTargetError";
|
|
454
|
+
}
|
|
455
|
+
invalid;
|
|
456
|
+
};
|
|
457
|
+
function parseActivateTargets(raw) {
|
|
458
|
+
if (!raw || raw.length === 0) return [];
|
|
459
|
+
return normalizeTargets(raw.flatMap((value) => value.split(",")));
|
|
460
|
+
}
|
|
461
|
+
function normalizeTargets(targets) {
|
|
462
|
+
const normalized = /* @__PURE__ */ new Set();
|
|
463
|
+
const invalid = [];
|
|
464
|
+
for (const target of targets) {
|
|
465
|
+
const value = target.trim().toLowerCase();
|
|
466
|
+
if (!value) continue;
|
|
467
|
+
if (value === "all") {
|
|
468
|
+
for (const item of ALLOWED) normalized.add(item);
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
if (isIdeTarget(value)) {
|
|
472
|
+
normalized.add(value);
|
|
473
|
+
} else {
|
|
474
|
+
invalid.push(target.trim());
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (invalid.length > 0) throw new InvalidActivateTargetError(invalid);
|
|
478
|
+
return [...normalized];
|
|
479
|
+
}
|
|
480
|
+
function activateIdeTargets(options) {
|
|
481
|
+
const cwd = options.cwd;
|
|
482
|
+
const packageRoot = findPackageRoot();
|
|
483
|
+
const targets = normalizeTargets(options.targets);
|
|
484
|
+
const force = Boolean(options.force);
|
|
485
|
+
const collector = emptyCollector();
|
|
486
|
+
const result = { activated: targets, ...collector };
|
|
487
|
+
if (targets.length === 0) return result;
|
|
488
|
+
if (targets.includes("cursor")) {
|
|
489
|
+
copyFromPackage(cwd, packageRoot, CURSOR_RULE_FILE.source, CURSOR_RULE_FILE.target, force, result);
|
|
490
|
+
generateCursorAgents(cwd, force, result);
|
|
491
|
+
generateCursorSkills(cwd, force, result);
|
|
492
|
+
}
|
|
493
|
+
if (targets.includes("claude")) {
|
|
494
|
+
copyFromPackage(cwd, packageRoot, CLAUDE_TEMPLATE, "CLAUDE.md", force, result);
|
|
495
|
+
generateClaudeAgents(cwd, force, result);
|
|
496
|
+
}
|
|
497
|
+
if (targets.includes("codex")) {
|
|
498
|
+
generateCodexAgents(cwd, force, result);
|
|
499
|
+
}
|
|
500
|
+
if (targets.includes("copilot")) {
|
|
501
|
+
generateCopilotInstructions(cwd, force, result);
|
|
502
|
+
}
|
|
503
|
+
if (targets.includes("antigravity")) {
|
|
504
|
+
generateAntigravityCommands(cwd, force, result);
|
|
505
|
+
}
|
|
506
|
+
return result;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// src/install/install.ts
|
|
426
510
|
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
|
|
511
|
+
import { join as join6 } from "path";
|
|
512
|
+
|
|
513
|
+
// src/install/managed-assets.ts
|
|
427
514
|
import { join as join5 } from "path";
|
|
515
|
+
function listManagedAssets(packageRoot, options = {}) {
|
|
516
|
+
const assets = [
|
|
517
|
+
{ target: "AGENTS.md", sourcePath: join5(packageRoot, AGENTS_DOC_SOURCE), category: "root-doc" },
|
|
518
|
+
{ target: "USER_GUIDE.md", sourcePath: join5(packageRoot, USER_GUIDE_SOURCE), category: "root-doc" },
|
|
519
|
+
{ target: "USER_GUIDE.html", sourcePath: join5(packageRoot, USER_GUIDE_HTML_SOURCE), category: "root-doc" },
|
|
520
|
+
{ target: CURSOR_RULE_FILE.target, sourcePath: join5(packageRoot, CURSOR_RULE_FILE.source), category: "adapter" }
|
|
521
|
+
];
|
|
522
|
+
const activated = new Set(options.activated ?? ["cursor"]);
|
|
523
|
+
if (activated.has("claude")) {
|
|
524
|
+
assets.push({
|
|
525
|
+
target: "CLAUDE.md",
|
|
526
|
+
sourcePath: join5(packageRoot, "templates/next-supabase/CLAUDE.md"),
|
|
527
|
+
category: "adapter"
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
return assets;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/install/install.ts
|
|
534
|
+
function initProject(options) {
|
|
535
|
+
const cwd = options.cwd;
|
|
536
|
+
const stack = options.stack ?? "next-supabase";
|
|
537
|
+
const packageRoot = findPackageRoot();
|
|
538
|
+
const force = Boolean(options.force);
|
|
539
|
+
ensureDir(join6(cwd, ".agent-kit", "conflicts"));
|
|
540
|
+
const result = {
|
|
541
|
+
...emptyCollector(),
|
|
542
|
+
manifestPath: ".agent-kit/manifest.json"
|
|
543
|
+
};
|
|
544
|
+
const templateHashes = {};
|
|
545
|
+
const agentsDoc = readFileSync6(join6(packageRoot, AGENTS_DOC_SOURCE), "utf8");
|
|
546
|
+
const userGuide = readFileSync6(join6(packageRoot, USER_GUIDE_SOURCE), "utf8");
|
|
547
|
+
const userGuideHtml = readFileSync6(join6(packageRoot, USER_GUIDE_HTML_SOURCE), "utf8");
|
|
548
|
+
templateHashes["AGENTS.md"] = sha256(agentsDoc);
|
|
549
|
+
templateHashes["USER_GUIDE.md"] = sha256(userGuide);
|
|
550
|
+
templateHashes["USER_GUIDE.html"] = sha256(userGuideHtml);
|
|
551
|
+
recordCopy(
|
|
552
|
+
result,
|
|
553
|
+
copyTextWithConflict(join6(packageRoot, AGENTS_DOC_SOURCE), cwd, "AGENTS.md", {
|
|
554
|
+
force,
|
|
555
|
+
conflictRoot: join6(cwd, ".agent-kit", "conflicts")
|
|
556
|
+
})
|
|
557
|
+
);
|
|
558
|
+
recordCopy(
|
|
559
|
+
result,
|
|
560
|
+
copyTextWithConflict(join6(packageRoot, USER_GUIDE_SOURCE), cwd, "USER_GUIDE.md", {
|
|
561
|
+
force,
|
|
562
|
+
conflictRoot: join6(cwd, ".agent-kit", "conflicts")
|
|
563
|
+
})
|
|
564
|
+
);
|
|
565
|
+
recordCopy(
|
|
566
|
+
result,
|
|
567
|
+
copyTextWithConflict(join6(packageRoot, USER_GUIDE_HTML_SOURCE), cwd, "USER_GUIDE.html", {
|
|
568
|
+
force,
|
|
569
|
+
conflictRoot: join6(cwd, ".agent-kit", "conflicts")
|
|
570
|
+
})
|
|
571
|
+
);
|
|
572
|
+
if (options.legacyDocs) {
|
|
573
|
+
const legacyRoot = join6(packageRoot, "templates", stack);
|
|
574
|
+
const legacyDocs = ["SPEC.md", "DECISIONS.md", "DESIGN.md", "SECURITY.md", "TESTING.md", "QUALITY_GATES.md"];
|
|
575
|
+
for (const doc of legacyDocs) {
|
|
576
|
+
const source = join6(legacyRoot, doc);
|
|
577
|
+
if (!existsSync6(source)) continue;
|
|
578
|
+
recordCopy(
|
|
579
|
+
result,
|
|
580
|
+
copyTextWithConflict(source, cwd, doc, {
|
|
581
|
+
force,
|
|
582
|
+
conflictRoot: join6(cwd, ".agent-kit", "conflicts")
|
|
583
|
+
})
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
const activateTargets = parseActivateTargets(options.activate);
|
|
588
|
+
const targets = activateTargets.length > 0 ? activateTargets : ["cursor"];
|
|
589
|
+
result.activation = activateIdeTargets({ cwd, targets, force });
|
|
590
|
+
generatePortableSkills(cwd, force, result.activation);
|
|
591
|
+
result.copied.push(...result.activation.copied.filter((path) => !result.copied.includes(path)));
|
|
592
|
+
result.unchanged.push(...result.activation.unchanged.filter((path) => !result.unchanged.includes(path)));
|
|
593
|
+
result.conflicts.push(...result.activation.conflicts.filter((path) => !result.conflicts.includes(path)));
|
|
594
|
+
result.overwritten.push(...result.activation.overwritten.filter((path) => !result.overwritten.includes(path)));
|
|
595
|
+
const assets = listManagedAssets(packageRoot, { activated: targets });
|
|
596
|
+
const assetHashes = {};
|
|
597
|
+
for (const asset of assets) {
|
|
598
|
+
if (existsSync6(asset.sourcePath)) assetHashes[asset.target] = sha256(readFileSync6(asset.sourcePath, "utf8"));
|
|
599
|
+
}
|
|
600
|
+
for (const relative2 of [...result.copied, ...result.unchanged, ...result.overwritten]) {
|
|
601
|
+
const path = join6(cwd, relative2);
|
|
602
|
+
if (existsSync6(path) && !assetHashes[relative2]) {
|
|
603
|
+
assetHashes[relative2] = sha256(readFileSync6(path, "utf8"));
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
const catalog = loadCatalog(packageRoot);
|
|
607
|
+
const manifest = {
|
|
608
|
+
schemaVersion: 3,
|
|
609
|
+
packageName: PACKAGE_NAME,
|
|
610
|
+
packageVersion: PACKAGE_VERSION,
|
|
611
|
+
stack,
|
|
612
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
613
|
+
docs: [...ROOT_DOCS],
|
|
614
|
+
activated: targets,
|
|
615
|
+
templateHashes,
|
|
616
|
+
assetHashes
|
|
617
|
+
};
|
|
618
|
+
writeText(join6(cwd, ".agent-kit", "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
619
|
+
`);
|
|
620
|
+
writeText(
|
|
621
|
+
join6(cwd, ".agent-kit", "config.json"),
|
|
622
|
+
`${JSON.stringify({ stack, catalog: { defaultAgents: catalog.defaultAgents, defaultSkills: catalog.defaultSkills } }, null, 2)}
|
|
623
|
+
`
|
|
624
|
+
);
|
|
625
|
+
if (!targets.includes("cursor")) {
|
|
626
|
+
recordCopy(
|
|
627
|
+
result,
|
|
628
|
+
copyTextWithConflict(join6(packageRoot, CURSOR_RULE_FILE.source), cwd, CURSOR_RULE_FILE.target, {
|
|
629
|
+
force,
|
|
630
|
+
conflictRoot: join6(cwd, ".agent-kit", "conflicts")
|
|
631
|
+
})
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
return result;
|
|
635
|
+
}
|
|
636
|
+
function readManifest(cwd) {
|
|
637
|
+
const manifestPath = join6(cwd, ".agent-kit", "manifest.json");
|
|
638
|
+
if (!existsSync6(manifestPath)) return null;
|
|
639
|
+
return JSON.parse(readFileSync6(manifestPath, "utf8"));
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// src/install/adapter-validate.ts
|
|
428
643
|
function summary(findings) {
|
|
429
644
|
return {
|
|
430
645
|
pass: findings.filter((finding) => finding.level === "pass").length,
|
|
@@ -432,14 +647,14 @@ function summary(findings) {
|
|
|
432
647
|
fail: findings.filter((finding) => finding.level === "fail").length
|
|
433
648
|
};
|
|
434
649
|
}
|
|
435
|
-
function report(target, findings) {
|
|
436
|
-
return { target, summary: summary(findings), findings };
|
|
650
|
+
function report(target, findings, validated) {
|
|
651
|
+
return { target, validated, summary: summary(findings), findings };
|
|
437
652
|
}
|
|
438
653
|
function has(cwd, relative2) {
|
|
439
|
-
return
|
|
654
|
+
return existsSync7(join7(cwd, relative2));
|
|
440
655
|
}
|
|
441
656
|
function text(cwd, relative2) {
|
|
442
|
-
return
|
|
657
|
+
return readFileSync7(join7(cwd, relative2), "utf8");
|
|
443
658
|
}
|
|
444
659
|
function validateCursor(cwd) {
|
|
445
660
|
const catalog = loadCatalog();
|
|
@@ -527,45 +742,55 @@ function validateAntigravity(cwd) {
|
|
|
527
742
|
}
|
|
528
743
|
return findings;
|
|
529
744
|
}
|
|
745
|
+
var validators = {
|
|
746
|
+
cursor: validateCursor,
|
|
747
|
+
claude: validateClaude,
|
|
748
|
+
codex: validateCodex,
|
|
749
|
+
copilot: validateCopilot,
|
|
750
|
+
antigravity: validateAntigravity
|
|
751
|
+
};
|
|
752
|
+
function resolveAdapterTargets(cwd, target) {
|
|
753
|
+
if (target !== "all") return [target];
|
|
754
|
+
const activated = (readManifest(cwd)?.activated ?? []).filter(isIdeTarget);
|
|
755
|
+
return activated.length > 0 ? activated : [...IDE_TARGETS];
|
|
756
|
+
}
|
|
530
757
|
function validateAdapter(cwd, target) {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
if (target === "antigravity") return report("antigravity", validateAntigravity(cwd));
|
|
536
|
-
return report("all", [...validateCursor(cwd), ...validateClaude(cwd), ...validateCodex(cwd), ...validateCopilot(cwd), ...validateAntigravity(cwd)]);
|
|
758
|
+
const validated = resolveAdapterTargets(cwd, target);
|
|
759
|
+
const findings = validated.flatMap((ide) => validators[ide](cwd));
|
|
760
|
+
const label = target === "all" && validated.length < IDE_TARGETS.length ? `all (${validated.join(", ")})` : target;
|
|
761
|
+
return report(label, findings, validated);
|
|
537
762
|
}
|
|
538
763
|
function validatePackage() {
|
|
539
764
|
const cwd = process.cwd();
|
|
540
765
|
const findings = [];
|
|
541
|
-
if (!
|
|
766
|
+
if (!existsSync7(join7(cwd, "catalog.json"))) {
|
|
542
767
|
findings.push({ level: "fail", area: "package", message: "catalog.json is missing." });
|
|
543
768
|
} else {
|
|
544
769
|
findings.push({ level: "pass", area: "package", message: "catalog.json is present." });
|
|
545
770
|
}
|
|
546
|
-
if (!
|
|
771
|
+
if (!existsSync7(join7(cwd, "USER_GUIDE.md"))) {
|
|
547
772
|
findings.push({ level: "fail", area: "package", message: "USER_GUIDE.md is missing." });
|
|
548
|
-
} else if (!
|
|
773
|
+
} else if (!readFileSync7(join7(cwd, "USER_GUIDE.md"), "utf8").includes("Do not review code alone")) {
|
|
549
774
|
findings.push({ level: "fail", area: "package", message: "USER_GUIDE.md dropped the screenshot fail-closed sentence." });
|
|
550
775
|
} else {
|
|
551
776
|
findings.push({ level: "pass", area: "package", message: "USER_GUIDE.md includes the screenshot rule." });
|
|
552
777
|
}
|
|
553
|
-
if (!
|
|
778
|
+
if (!existsSync7(join7(cwd, "USER_GUIDE.html"))) {
|
|
554
779
|
findings.push({ level: "fail", area: "package", message: "USER_GUIDE.html is missing." });
|
|
555
|
-
} else if (!
|
|
780
|
+
} else if (!readFileSync7(join7(cwd, "USER_GUIDE.html"), "utf8").includes("Do not review code alone")) {
|
|
556
781
|
findings.push({ level: "fail", area: "package", message: "USER_GUIDE.html dropped the screenshot fail-closed sentence." });
|
|
557
782
|
} else {
|
|
558
783
|
findings.push({ level: "pass", area: "package", message: "USER_GUIDE.html includes the screenshot rule." });
|
|
559
784
|
}
|
|
560
|
-
if (!
|
|
785
|
+
if (!existsSync7(join7(cwd, "skills/browser-qa/SKILL.md"))) {
|
|
561
786
|
findings.push({ level: "fail", area: "package", message: "skills/browser-qa/SKILL.md is missing." });
|
|
562
787
|
}
|
|
563
|
-
return report("package", findings);
|
|
788
|
+
return report("package", findings, []);
|
|
564
789
|
}
|
|
565
790
|
|
|
566
791
|
// src/install/doctor.ts
|
|
567
|
-
import { existsSync as
|
|
568
|
-
import { join as
|
|
792
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8 } from "fs";
|
|
793
|
+
import { join as join8 } from "path";
|
|
569
794
|
var LEGACY_LEFTOVER_PATHS = [
|
|
570
795
|
"AGENT_ROSTER.md",
|
|
571
796
|
"COUNCIL.md",
|
|
@@ -583,11 +808,11 @@ function summarize(findings) {
|
|
|
583
808
|
};
|
|
584
809
|
}
|
|
585
810
|
function read(cwd, relative2) {
|
|
586
|
-
const path =
|
|
587
|
-
return
|
|
811
|
+
const path = join8(cwd, relative2);
|
|
812
|
+
return existsSync8(path) ? readFileSync8(path, "utf8") : null;
|
|
588
813
|
}
|
|
589
814
|
function listLegacyLeftovers(cwd) {
|
|
590
|
-
return LEGACY_LEFTOVER_PATHS.filter((relative2) =>
|
|
815
|
+
return LEGACY_LEFTOVER_PATHS.filter((relative2) => existsSync8(join8(cwd, relative2)));
|
|
591
816
|
}
|
|
592
817
|
function createDoctorReport(cwd) {
|
|
593
818
|
const catalog = loadCatalog();
|
|
@@ -637,9 +862,33 @@ function createDoctorReport(cwd) {
|
|
|
637
862
|
const meta = parseFrontmatter(content);
|
|
638
863
|
if (!meta.tools || meta.tools.length === 0) {
|
|
639
864
|
findings.push({ level: "fail", area: "agents", message: `${id} is missing a tools list.` });
|
|
640
|
-
|
|
641
|
-
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
867
|
+
const expectedRequired = packagedRequiredTools(id);
|
|
868
|
+
const actualRequired = meta.requiredTools ?? [];
|
|
869
|
+
const missingRequired = expectedRequired.filter((tool) => !actualRequired.includes(tool));
|
|
870
|
+
if (missingRequired.length > 0) {
|
|
871
|
+
findings.push({
|
|
872
|
+
level: "fail",
|
|
873
|
+
area: "agents",
|
|
874
|
+
message: `${id} dropped requiredTools: ${missingRequired.join(", ")}.`
|
|
875
|
+
});
|
|
876
|
+
continue;
|
|
642
877
|
}
|
|
878
|
+
const requiredNotAllowed = actualRequired.filter((tool) => !meta.tools?.includes(tool));
|
|
879
|
+
if (requiredNotAllowed.length > 0) {
|
|
880
|
+
findings.push({
|
|
881
|
+
level: "fail",
|
|
882
|
+
area: "agents",
|
|
883
|
+
message: `${id} lists required tools that are not in tools: ${requiredNotAllowed.join(", ")}.`
|
|
884
|
+
});
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
findings.push({
|
|
888
|
+
level: "pass",
|
|
889
|
+
area: "agents",
|
|
890
|
+
message: expectedRequired.length > 0 ? `${id} keeps required tools.` : `${id} declares tools.`
|
|
891
|
+
});
|
|
643
892
|
}
|
|
644
893
|
const leftovers = listLegacyLeftovers(cwd);
|
|
645
894
|
if (leftovers.length > 0) {
|
|
@@ -663,225 +912,41 @@ function createDoctorReport(cwd) {
|
|
|
663
912
|
ok: findings.every((item) => item.level !== "fail")
|
|
664
913
|
};
|
|
665
914
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
var PACKAGE_NAME = "@appsforgood/next-supabase-kit";
|
|
673
|
-
var PACKAGE_VERSION = "0.4.2";
|
|
674
|
-
var ROOT_DOCS = ["AGENTS.md", "USER_GUIDE.md", "USER_GUIDE.html"];
|
|
675
|
-
var CURSOR_RULE_FILE = {
|
|
676
|
-
source: "assistant-adapters/cursor-agent-kit.mdc",
|
|
677
|
-
target: ".cursor/rules/cursor-agent-kit.mdc"
|
|
678
|
-
};
|
|
679
|
-
var CLAUDE_TEMPLATE = "templates/next-supabase/CLAUDE.md";
|
|
680
|
-
var USER_GUIDE_SOURCE = "USER_GUIDE.md";
|
|
681
|
-
var USER_GUIDE_HTML_SOURCE = "USER_GUIDE.html";
|
|
682
|
-
var AGENTS_DOC_SOURCE = "templates/next-supabase/AGENTS.md";
|
|
683
|
-
|
|
684
|
-
// src/install/ide-activate.ts
|
|
685
|
-
var ALLOWED = /* @__PURE__ */ new Set(["cursor", "claude", "codex", "copilot", "antigravity"]);
|
|
686
|
-
var InvalidActivateTargetError = class extends Error {
|
|
687
|
-
constructor(invalid) {
|
|
688
|
-
super(`Unknown --activate target(s): ${invalid.join(", ")}. Allowed: cursor, claude, codex, copilot, antigravity, all.`);
|
|
689
|
-
this.invalid = invalid;
|
|
690
|
-
this.name = "InvalidActivateTargetError";
|
|
691
|
-
}
|
|
692
|
-
invalid;
|
|
693
|
-
};
|
|
694
|
-
function parseActivateTargets(raw) {
|
|
695
|
-
if (!raw || raw.length === 0) return [];
|
|
696
|
-
return normalizeTargets(raw.flatMap((value) => value.split(",")));
|
|
697
|
-
}
|
|
698
|
-
function normalizeTargets(targets) {
|
|
699
|
-
const normalized = /* @__PURE__ */ new Set();
|
|
700
|
-
const invalid = [];
|
|
701
|
-
for (const target of targets) {
|
|
702
|
-
const value = target.trim().toLowerCase();
|
|
703
|
-
if (!value) continue;
|
|
704
|
-
if (value === "all") {
|
|
705
|
-
for (const item of ALLOWED) normalized.add(item);
|
|
706
|
-
continue;
|
|
707
|
-
}
|
|
708
|
-
if (ALLOWED.has(value)) {
|
|
709
|
-
normalized.add(value);
|
|
710
|
-
} else {
|
|
711
|
-
invalid.push(target.trim());
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
if (invalid.length > 0) throw new InvalidActivateTargetError(invalid);
|
|
715
|
-
return [...normalized];
|
|
716
|
-
}
|
|
717
|
-
function activateIdeTargets(options) {
|
|
718
|
-
const cwd = options.cwd;
|
|
719
|
-
const packageRoot = findPackageRoot();
|
|
720
|
-
const targets = normalizeTargets(options.targets);
|
|
721
|
-
const force = Boolean(options.force);
|
|
722
|
-
const collector = emptyCollector();
|
|
723
|
-
const result = { activated: targets, ...collector };
|
|
724
|
-
if (targets.length === 0) return result;
|
|
725
|
-
if (targets.includes("cursor")) {
|
|
726
|
-
copyFromPackage(cwd, packageRoot, CURSOR_RULE_FILE.source, CURSOR_RULE_FILE.target, force, result);
|
|
727
|
-
generateCursorAgents(cwd, force, result);
|
|
728
|
-
generateCursorSkills(cwd, force, result);
|
|
729
|
-
}
|
|
730
|
-
if (targets.includes("claude")) {
|
|
731
|
-
copyFromPackage(cwd, packageRoot, CLAUDE_TEMPLATE, "CLAUDE.md", force, result);
|
|
732
|
-
generateClaudeAgents(cwd, force, result);
|
|
733
|
-
}
|
|
734
|
-
if (targets.includes("codex")) {
|
|
735
|
-
generateCodexAgents(cwd, force, result);
|
|
736
|
-
}
|
|
737
|
-
if (targets.includes("copilot")) {
|
|
738
|
-
generateCopilotInstructions(cwd, force, result);
|
|
739
|
-
}
|
|
740
|
-
if (targets.includes("antigravity")) {
|
|
741
|
-
generateAntigravityCommands(cwd, force, result);
|
|
742
|
-
}
|
|
743
|
-
return result;
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
// src/install/managed-assets.ts
|
|
747
|
-
import { join as join7 } from "path";
|
|
748
|
-
function listManagedAssets(packageRoot, options = {}) {
|
|
749
|
-
const assets = [
|
|
750
|
-
{ target: "AGENTS.md", sourcePath: join7(packageRoot, AGENTS_DOC_SOURCE), category: "root-doc" },
|
|
751
|
-
{ target: "USER_GUIDE.md", sourcePath: join7(packageRoot, USER_GUIDE_SOURCE), category: "root-doc" },
|
|
752
|
-
{ target: "USER_GUIDE.html", sourcePath: join7(packageRoot, USER_GUIDE_HTML_SOURCE), category: "root-doc" },
|
|
753
|
-
{ target: CURSOR_RULE_FILE.target, sourcePath: join7(packageRoot, CURSOR_RULE_FILE.source), category: "adapter" }
|
|
754
|
-
];
|
|
755
|
-
const activated = new Set(options.activated ?? ["cursor"]);
|
|
756
|
-
if (activated.has("claude")) {
|
|
757
|
-
assets.push({
|
|
758
|
-
target: "CLAUDE.md",
|
|
759
|
-
sourcePath: join7(packageRoot, "templates/next-supabase/CLAUDE.md"),
|
|
760
|
-
category: "adapter"
|
|
761
|
-
});
|
|
915
|
+
function packagedRequiredTools(id) {
|
|
916
|
+
try {
|
|
917
|
+
const source = readFileSync8(agentSourcePath(findPackageRoot(), id), "utf8");
|
|
918
|
+
return parseFrontmatter(source).requiredTools ?? [];
|
|
919
|
+
} catch {
|
|
920
|
+
return [];
|
|
762
921
|
}
|
|
763
|
-
return assets;
|
|
764
922
|
}
|
|
765
923
|
|
|
766
|
-
// src/install/
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
const
|
|
772
|
-
|
|
773
|
-
const
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
const
|
|
779
|
-
|
|
780
|
-
const userGuideHtml = readFileSync8(join8(packageRoot, USER_GUIDE_HTML_SOURCE), "utf8");
|
|
781
|
-
templateHashes["AGENTS.md"] = sha256(agentsDoc);
|
|
782
|
-
templateHashes["USER_GUIDE.md"] = sha256(userGuide);
|
|
783
|
-
templateHashes["USER_GUIDE.html"] = sha256(userGuideHtml);
|
|
784
|
-
recordCopy(
|
|
785
|
-
result,
|
|
786
|
-
copyTextWithConflict(join8(packageRoot, AGENTS_DOC_SOURCE), cwd, "AGENTS.md", {
|
|
787
|
-
force,
|
|
788
|
-
conflictRoot: join8(cwd, ".agent-kit", "conflicts")
|
|
789
|
-
})
|
|
790
|
-
);
|
|
791
|
-
recordCopy(
|
|
792
|
-
result,
|
|
793
|
-
copyTextWithConflict(join8(packageRoot, USER_GUIDE_SOURCE), cwd, "USER_GUIDE.md", {
|
|
794
|
-
force,
|
|
795
|
-
conflictRoot: join8(cwd, ".agent-kit", "conflicts")
|
|
796
|
-
})
|
|
797
|
-
);
|
|
798
|
-
recordCopy(
|
|
799
|
-
result,
|
|
800
|
-
copyTextWithConflict(join8(packageRoot, USER_GUIDE_HTML_SOURCE), cwd, "USER_GUIDE.html", {
|
|
801
|
-
force,
|
|
802
|
-
conflictRoot: join8(cwd, ".agent-kit", "conflicts")
|
|
803
|
-
})
|
|
804
|
-
);
|
|
805
|
-
if (options.legacyDocs) {
|
|
806
|
-
const legacyRoot = join8(packageRoot, "templates", stack);
|
|
807
|
-
const legacyDocs = ["SPEC.md", "DECISIONS.md", "DESIGN.md", "SECURITY.md", "TESTING.md", "QUALITY_GATES.md"];
|
|
808
|
-
for (const doc of legacyDocs) {
|
|
809
|
-
const source = join8(legacyRoot, doc);
|
|
810
|
-
if (!existsSync8(source)) continue;
|
|
811
|
-
recordCopy(
|
|
812
|
-
result,
|
|
813
|
-
copyTextWithConflict(source, cwd, doc, {
|
|
814
|
-
force,
|
|
815
|
-
conflictRoot: join8(cwd, ".agent-kit", "conflicts")
|
|
816
|
-
})
|
|
817
|
-
);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
const activateTargets = parseActivateTargets(options.activate);
|
|
821
|
-
const targets = activateTargets.length > 0 ? activateTargets : ["cursor"];
|
|
822
|
-
result.activation = activateIdeTargets({ cwd, targets, force });
|
|
823
|
-
generatePortableSkills(cwd, force, result.activation);
|
|
824
|
-
result.copied.push(...result.activation.copied.filter((path) => !result.copied.includes(path)));
|
|
825
|
-
result.unchanged.push(...result.activation.unchanged.filter((path) => !result.unchanged.includes(path)));
|
|
826
|
-
result.conflicts.push(...result.activation.conflicts.filter((path) => !result.conflicts.includes(path)));
|
|
827
|
-
result.overwritten.push(...result.activation.overwritten.filter((path) => !result.overwritten.includes(path)));
|
|
828
|
-
const assets = listManagedAssets(packageRoot, { activated: targets });
|
|
829
|
-
const assetHashes = {};
|
|
830
|
-
for (const asset of assets) {
|
|
831
|
-
if (existsSync8(asset.sourcePath)) assetHashes[asset.target] = sha256(readFileSync8(asset.sourcePath, "utf8"));
|
|
832
|
-
}
|
|
833
|
-
for (const relative2 of [...result.copied, ...result.unchanged, ...result.overwritten]) {
|
|
834
|
-
const path = join8(cwd, relative2);
|
|
835
|
-
if (existsSync8(path) && !assetHashes[relative2]) {
|
|
836
|
-
assetHashes[relative2] = sha256(readFileSync8(path, "utf8"));
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
const catalog = loadCatalog(packageRoot);
|
|
840
|
-
const manifest = {
|
|
841
|
-
schemaVersion: 3,
|
|
842
|
-
packageName: PACKAGE_NAME,
|
|
843
|
-
packageVersion: PACKAGE_VERSION,
|
|
844
|
-
stack,
|
|
845
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
846
|
-
docs: [...ROOT_DOCS],
|
|
847
|
-
activated: targets,
|
|
848
|
-
templateHashes,
|
|
849
|
-
assetHashes
|
|
850
|
-
};
|
|
851
|
-
writeText(join8(cwd, ".agent-kit", "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
852
|
-
`);
|
|
853
|
-
writeText(
|
|
854
|
-
join8(cwd, ".agent-kit", "config.json"),
|
|
855
|
-
`${JSON.stringify({ stack, catalog: { defaultAgents: catalog.defaultAgents, defaultSkills: catalog.defaultSkills } }, null, 2)}
|
|
856
|
-
`
|
|
857
|
-
);
|
|
858
|
-
if (!targets.includes("cursor")) {
|
|
859
|
-
recordCopy(
|
|
860
|
-
result,
|
|
861
|
-
copyTextWithConflict(join8(packageRoot, CURSOR_RULE_FILE.source), cwd, CURSOR_RULE_FILE.target, {
|
|
862
|
-
force,
|
|
863
|
-
conflictRoot: join8(cwd, ".agent-kit", "conflicts")
|
|
864
|
-
})
|
|
865
|
-
);
|
|
866
|
-
}
|
|
867
|
-
return result;
|
|
868
|
-
}
|
|
869
|
-
function readManifest(cwd) {
|
|
870
|
-
const manifestPath = join8(cwd, ".agent-kit", "manifest.json");
|
|
871
|
-
if (!existsSync8(manifestPath)) return null;
|
|
872
|
-
return JSON.parse(readFileSync8(manifestPath, "utf8"));
|
|
924
|
+
// src/install/guide.ts
|
|
925
|
+
import { existsSync as existsSync9 } from "fs";
|
|
926
|
+
import { join as join9, resolve as resolve3 } from "path";
|
|
927
|
+
import { pathToFileURL } from "url";
|
|
928
|
+
function resolveUserGuideHtml(cwd) {
|
|
929
|
+
const local = join9(cwd, "USER_GUIDE.html");
|
|
930
|
+
if (existsSync9(local)) return locate(local, "cwd");
|
|
931
|
+
const packaged = join9(findPackageRoot(), "USER_GUIDE.html");
|
|
932
|
+
if (existsSync9(packaged)) return locate(packaged, "package");
|
|
933
|
+
throw new Error("USER_GUIDE.html is missing. Run agent-kit init, then open the file in a browser.");
|
|
934
|
+
}
|
|
935
|
+
function locate(path, source) {
|
|
936
|
+
const absolute = resolve3(path);
|
|
937
|
+
return { path: absolute, source, fileUrl: pathToFileURL(absolute).href };
|
|
873
938
|
}
|
|
874
939
|
|
|
875
940
|
// src/install/update.ts
|
|
876
|
-
import { existsSync as
|
|
877
|
-
import { join as
|
|
941
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
|
|
942
|
+
import { join as join10 } from "path";
|
|
878
943
|
|
|
879
944
|
// src/install/file-update-plan.ts
|
|
880
|
-
import { existsSync as
|
|
945
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
|
|
881
946
|
function planFileUpdate(input) {
|
|
882
947
|
const sourceContent = readFileSync9(input.sourcePath, "utf8");
|
|
883
948
|
const sourceHash = sha256(sourceContent);
|
|
884
|
-
if (!
|
|
949
|
+
if (!existsSync10(input.targetPath)) {
|
|
885
950
|
return { target: input.target, action: "created", reason: "File is missing locally.", sourceContent, sourceHash };
|
|
886
951
|
}
|
|
887
952
|
const localContent = readFileSync9(input.targetPath, "utf8");
|
|
@@ -1007,7 +1072,7 @@ function updateProject(options) {
|
|
|
1007
1072
|
const assets = listManagedAssets(packageRoot, { activated });
|
|
1008
1073
|
const files = [];
|
|
1009
1074
|
for (const asset of assets) {
|
|
1010
|
-
if (!
|
|
1075
|
+
if (!existsSync11(asset.sourcePath)) continue;
|
|
1011
1076
|
const plan = planFileUpdate({
|
|
1012
1077
|
target: asset.target,
|
|
1013
1078
|
sourcePath: asset.sourcePath,
|
|
@@ -1041,11 +1106,11 @@ function updateProject(options) {
|
|
|
1041
1106
|
files.push(...activationToUpdateFiles(activation));
|
|
1042
1107
|
const nextHashes = { ...manifest.assetHashes };
|
|
1043
1108
|
for (const asset of assets) {
|
|
1044
|
-
if (
|
|
1109
|
+
if (existsSync11(asset.sourcePath)) nextHashes[asset.target] = sha256(readFileSync10(asset.sourcePath, "utf8"));
|
|
1045
1110
|
}
|
|
1046
1111
|
for (const relative2 of [...activation.copied, ...activation.unchanged, ...activation.overwritten]) {
|
|
1047
|
-
const path =
|
|
1048
|
-
if (
|
|
1112
|
+
const path = join10(cwd, relative2);
|
|
1113
|
+
if (existsSync11(path)) nextHashes[relative2] = sha256(readFileSync10(path, "utf8"));
|
|
1049
1114
|
}
|
|
1050
1115
|
const next = {
|
|
1051
1116
|
...manifest,
|
|
@@ -1055,7 +1120,7 @@ function updateProject(options) {
|
|
|
1055
1120
|
docs: ["AGENTS.md", "USER_GUIDE.md", "USER_GUIDE.html"],
|
|
1056
1121
|
assetHashes: nextHashes
|
|
1057
1122
|
};
|
|
1058
|
-
writeText(
|
|
1123
|
+
writeText(join10(cwd, ".agent-kit", "manifest.json"), `${JSON.stringify(next, null, 2)}
|
|
1059
1124
|
`);
|
|
1060
1125
|
} else {
|
|
1061
1126
|
files.push({
|
|
@@ -1173,7 +1238,7 @@ add.command("agent <name>").description("Install one agent into .cursor/agents a
|
|
|
1173
1238
|
line(`${result.action} ${result.target}`);
|
|
1174
1239
|
if (!options.dryRun) detail(`Available agents: ${listAgents().join(", ")}`);
|
|
1175
1240
|
});
|
|
1176
|
-
program.command("doctor").description("Check agents,
|
|
1241
|
+
program.command("doctor").description("Check agents, required tools, the screenshot QA rule, and leftover 0.3 council files.").option("--json", "Machine-readable output").action((options) => {
|
|
1177
1242
|
const report2 = createDoctorReport(process.cwd());
|
|
1178
1243
|
if (options.json) {
|
|
1179
1244
|
printJson(report2);
|
|
@@ -1187,10 +1252,22 @@ program.command("doctor").description("Check agents, skills, the screenshot QA r
|
|
|
1187
1252
|
if (!report2.ok) {
|
|
1188
1253
|
fail("doctor found failures");
|
|
1189
1254
|
process.exitCode = 1;
|
|
1255
|
+
} else {
|
|
1256
|
+
detail("Open USER_GUIDE.html in a browser. GitHub shows source, not the layout. Run agent-kit guide for the path.");
|
|
1257
|
+
}
|
|
1258
|
+
});
|
|
1259
|
+
program.command("guide").description("Print the path to USER_GUIDE.html. Open it in a browser; GitHub shows source.").option("--json", "Machine-readable output").action((options) => {
|
|
1260
|
+
const location = resolveUserGuideHtml(process.cwd());
|
|
1261
|
+
if (options.json) {
|
|
1262
|
+
printJson(location);
|
|
1263
|
+
return;
|
|
1190
1264
|
}
|
|
1265
|
+
heading("user guide");
|
|
1266
|
+
line(location.path);
|
|
1267
|
+
detail("Open that file in a browser. GitHub shows HTML as source, not the layout.");
|
|
1191
1268
|
});
|
|
1192
1269
|
var adapter = program.command("adapter").description("Validate IDE adapter files.");
|
|
1193
|
-
adapter.command("validate [target]").description("Validate cursor, claude, codex, copilot, antigravity
|
|
1270
|
+
adapter.command("validate [target]").description("Validate activated IDEs, or one of cursor, claude, codex, copilot, antigravity").option("--json", "Machine-readable output").action((rawTarget, options) => {
|
|
1194
1271
|
const target = rawTarget ?? "all";
|
|
1195
1272
|
const allowed = ["cursor", "claude", "codex", "copilot", "antigravity", "all"];
|
|
1196
1273
|
if (!allowed.includes(target)) {
|