@clubmatto/ai-kit 0.0.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 (70) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +65 -0
  3. package/dist/scripts/fetch-playwright-skills.js +63 -0
  4. package/dist/src/cmd/sync.js +109 -0
  5. package/dist/src/commands/sync.js +111 -0
  6. package/dist/src/content.js +99 -0
  7. package/dist/src/index.js +19 -0
  8. package/dist/src/logger.js +2 -0
  9. package/dist/src/manifest.js +24 -0
  10. package/dist/src/output.js +46 -0
  11. package/dist/src/reader.js +99 -0
  12. package/dist/src/template.js +10 -0
  13. package/dist/tests/content.test.js +141 -0
  14. package/dist/tests/integration/cli.test.js +43 -0
  15. package/dist/tests/output.js +36 -0
  16. package/dist/tests/reader.test.js +141 -0
  17. package/dist/tests/sync.test.js +90 -0
  18. package/dist/tests/utils.js +20 -0
  19. package/dist/vitest.config.js +9 -0
  20. package/docs/roadmap.md +16 -0
  21. package/eslint.config.mjs +38 -0
  22. package/package.json +78 -0
  23. package/scripts/fetch-playwright-skills.ts +79 -0
  24. package/src/agents/monorepo.md +30 -0
  25. package/src/agents/opencode.json +31 -0
  26. package/src/cmd/sync.ts +158 -0
  27. package/src/commands/commit.md +43 -0
  28. package/src/commands/interview.md +92 -0
  29. package/src/commands/synth.md +45 -0
  30. package/src/index.ts +24 -0
  31. package/src/logger.ts +10 -0
  32. package/src/manifest.ts +29 -0
  33. package/src/output.ts +66 -0
  34. package/src/reader.ts +114 -0
  35. package/src/rules/go.md +306 -0
  36. package/src/rules/kotlin.md +177 -0
  37. package/src/rules/plan-mode.md +7 -0
  38. package/src/rules/spring-boot.md +549 -0
  39. package/src/rules/typescript.md +302 -0
  40. package/src/rules/unsure.md +9 -0
  41. package/src/skills/image-gen/SKILL.md +50 -0
  42. package/src/skills/image-gen/scripts/generate.js +166 -0
  43. package/src/skills/playwright-cli/SKILL.md +279 -0
  44. package/src/skills/playwright-cli/references/request-mocking.md +87 -0
  45. package/src/skills/playwright-cli/references/running-code.md +232 -0
  46. package/src/skills/playwright-cli/references/session-management.md +170 -0
  47. package/src/skills/playwright-cli/references/storage-state.md +275 -0
  48. package/src/skills/playwright-cli/references/test-generation.md +88 -0
  49. package/src/skills/playwright-cli/references/tracing.md +142 -0
  50. package/src/skills/playwright-cli/references/video-recording.md +43 -0
  51. package/src/template.ts +14 -0
  52. package/tests/fixtures/agents/another.json +4 -0
  53. package/tests/fixtures/agents/monorepo.md +5 -0
  54. package/tests/fixtures/agents/opencode.json +4 -0
  55. package/tests/fixtures/commands/another.md +5 -0
  56. package/tests/fixtures/commands/commit.md +7 -0
  57. package/tests/fixtures/commands/test.md +13 -0
  58. package/tests/fixtures/rules/nested/nested-rule.md +3 -0
  59. package/tests/fixtures/rules/test-rule.md +5 -0
  60. package/tests/fixtures/rules/typescript.md +5 -0
  61. package/tests/fixtures/skills/test-skill/SKILL.md +7 -0
  62. package/tests/fixtures/skills/test-skill/nested-refs/doc.md +3 -0
  63. package/tests/fixtures/skills/test-skill/skill-details.md +7 -0
  64. package/tests/integration/cli.test.ts +55 -0
  65. package/tests/output.ts +37 -0
  66. package/tests/reader.test.ts +193 -0
  67. package/tests/sync.test.ts +136 -0
  68. package/tests/utils.ts +17 -0
  69. package/tsconfig.json +23 -0
  70. package/vitest.config.ts +8 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ### Added
8
+
9
+ - Initial setup for release-it
10
+
11
+ ## [0.0.1] - 2026-02-21
12
+
13
+ ### Added
14
+
15
+ - Initial release
package/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # ai-kit
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@clubmatto/ai-kit)](https://www.npmjs.com/package/@clubmatto/ai-kit)
4
+ [![License: MIT](https://img.shields.io/npm/l/@clubmatto/ai-kit)](/LICENSE)
5
+
6
+ The AI configuration CLI from Club Matto. Sync rules, skills, and commands to power up your AI coding workflow.
7
+
8
+ ## Features
9
+
10
+ - **Language Rules** — TypeScript, Go, Kotlin, and more
11
+ - **Skills** — Reusable AI capabilities like Playwright automation
12
+ - **Commands** — Pre-built prompts for common tasks (commit messages, PR reviews)
13
+
14
+ ## Quick Start
15
+
16
+ ```bash
17
+ # Install globally
18
+ npm install -g @clubmatto/ai-kit
19
+
20
+ # Sync AI configuration to your project
21
+ ai-kit sync
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```bash
27
+ # Initialize or update AI configuration
28
+ ai-kit sync
29
+
30
+ # Skip installing opencode.json to project root
31
+ ai-kit sync --skip-opencode
32
+ ```
33
+
34
+ ## What's Installed
35
+
36
+ | Location | Description |
37
+ | --------------- | --------------------------------- |
38
+ | `.ai/commands/` | Command prompts |
39
+ | `.ai/rules/` | Language/framework rules |
40
+ | `.ai/skills/` | Reusable AI capabilities |
41
+ | `opencode.json` | Opencode configuration (optional) |
42
+ | `AGENTS.md` | Agent instructions |
43
+
44
+ ## Commands
45
+
46
+ | Command | Description |
47
+ | ------------- | ---------------------------------- |
48
+ | `ai-kit sync` | Initialize or update configuration |
49
+
50
+ ## Local Development
51
+
52
+ ```bash
53
+ # Build the CLI
54
+ npm run build
55
+
56
+ # Link for local testing
57
+ npm link
58
+
59
+ # Test in any directory
60
+ ai-kit sync
61
+ ```
62
+
63
+ ## License
64
+
65
+ MIT — see [LICENSE](/LICENSE) for details.
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs_1 = require("fs");
4
+ const path_1 = require("path");
5
+ const rootDir = (0, path_1.join)(__dirname, "..");
6
+ const skillsDir = (0, path_1.join)(rootDir, "src", "skills", "playwright-cli");
7
+ const GITHUB_API = "https://api.github.com";
8
+ const REPO = "microsoft/playwright-cli";
9
+ const args = process.argv.slice(2);
10
+ const VERSION = args[0] || "v0.1.1";
11
+ async function fetchJson(url) {
12
+ const res = await fetch(url, {
13
+ headers: {
14
+ Accept: "application/vnd.github.v3+json",
15
+ "User-Agent": "ai-kit",
16
+ },
17
+ });
18
+ if (!res.ok) {
19
+ throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
20
+ }
21
+ return (await res.json());
22
+ }
23
+ async function fetchFile(url) {
24
+ const res = await fetch(url, {
25
+ headers: {
26
+ Accept: "application/vnd.github.v3.raw",
27
+ "User-Agent": "ai-kit",
28
+ },
29
+ });
30
+ if (!res.ok) {
31
+ throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
32
+ }
33
+ return res.text();
34
+ }
35
+ async function main() {
36
+ console.log(`Fetching playwright-cli skills from ${REPO}@${VERSION}...`);
37
+ const baseUrl = `${GITHUB_API}/repos/${REPO}/contents/skills/playwright-cli?ref=${VERSION}`;
38
+ const files = await fetchJson(baseUrl);
39
+ (0, fs_1.mkdirSync)(skillsDir, { recursive: true });
40
+ (0, fs_1.mkdirSync)((0, path_1.join)(skillsDir, "references"), { recursive: true });
41
+ for (const file of files) {
42
+ if (file.type === "dir" && file.name === "references") {
43
+ const refs = await fetchJson(file.url);
44
+ for (const ref of refs) {
45
+ const content = await fetchFile(ref.download_url);
46
+ const targetPath = (0, path_1.join)(skillsDir, "references", ref.name);
47
+ (0, fs_1.writeFileSync)(targetPath, content);
48
+ console.log(` - references/${ref.name}`);
49
+ }
50
+ }
51
+ else if (file.type === "file") {
52
+ const content = await fetchFile(file.download_url);
53
+ const targetPath = (0, path_1.join)(skillsDir, file.name);
54
+ (0, fs_1.writeFileSync)(targetPath, content);
55
+ console.log(` - ${file.name}`);
56
+ }
57
+ }
58
+ console.log(`\nDone! Skills written to src/skills/playwright-cli/`);
59
+ }
60
+ main().catch((err) => {
61
+ console.error(err);
62
+ process.exit(1);
63
+ });
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sync = sync;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const reader_1 = require("../reader");
7
+ const manifest_1 = require("../manifest");
8
+ const template_1 = require("../template");
9
+ const output_1 = require("../output");
10
+ const rootDir = (0, path_1.join)(__dirname, "..", "..", "..");
11
+ const defaultSourceDirs = {
12
+ rules: (0, path_1.join)(rootDir, "src", "rules"),
13
+ skills: (0, path_1.join)(rootDir, "src", "skills"),
14
+ agents: (0, path_1.join)(rootDir, "src", "agents"),
15
+ commands: (0, path_1.join)(rootDir, "src", "commands"),
16
+ };
17
+ async function sync(cwd, version, options, logger = output_1.log, sourceDirs = defaultSourceDirs) {
18
+ const manifest = (0, manifest_1.readManifest)(cwd);
19
+ logger.logo(version);
20
+ if (manifest && manifest.version === version) {
21
+ logger.success(`Already at latest version (${version})`);
22
+ return;
23
+ }
24
+ logger.welcome();
25
+ const counts = await doSync(cwd, version, options, logger, sourceDirs);
26
+ logger.summary(counts);
27
+ }
28
+ function writeItem(aiDir, file) {
29
+ const targetDir = (0, path_1.join)(aiDir, file.type);
30
+ if (!(0, fs_1.existsSync)(targetDir)) {
31
+ (0, fs_1.mkdirSync)(targetDir, { recursive: true });
32
+ }
33
+ const targetPath = (0, path_1.join)(targetDir, file.name);
34
+ const parentDir = (0, path_1.dirname)(targetPath);
35
+ if (!(0, fs_1.existsSync)(parentDir)) {
36
+ (0, fs_1.mkdirSync)(parentDir, { recursive: true });
37
+ }
38
+ (0, fs_1.writeFileSync)(targetPath, (0, template_1.processTemplate)(file.content));
39
+ }
40
+ async function doSync(cwd, version, options, logger, sourceDirs) {
41
+ const aiDir = (0, path_1.join)(cwd, ".agents");
42
+ if (!(0, fs_1.existsSync)(aiDir)) {
43
+ (0, fs_1.mkdirSync)(aiDir, { recursive: true });
44
+ }
45
+ const contentFiles = (0, reader_1.readContent)(sourceDirs.rules, sourceDirs.skills);
46
+ const rootFiles = (0, reader_1.readConfigs)(sourceDirs.agents);
47
+ const agentsFile = (0, reader_1.readAgents)(sourceDirs.agents);
48
+ const rules = contentFiles.filter((f) => f.type === "rules");
49
+ const stats = { rules: 0, skills: 0, commands: 0 };
50
+ const installedRootFiles = [];
51
+ if (!options.skipOpencode) {
52
+ const commandConfig = (0, reader_1.getCommandConfig)(sourceDirs.commands);
53
+ stats.commands = Object.keys(commandConfig).length;
54
+ if (Object.keys(commandConfig).length > 0) {
55
+ logger.section("commands");
56
+ for (const name of Object.keys(commandConfig)) {
57
+ logger.success(`${name}.md`);
58
+ }
59
+ }
60
+ if (rootFiles.length > 0) {
61
+ logger.section("configs");
62
+ for (const file of rootFiles) {
63
+ let content = file.content;
64
+ if (file.name === "opencode.json" &&
65
+ Object.keys(commandConfig).length > 0) {
66
+ const config = JSON.parse(content);
67
+ config.command = commandConfig;
68
+ content = JSON.stringify(config, null, 2) + "\n";
69
+ }
70
+ const targetPath = (0, path_1.join)(cwd, file.name);
71
+ (0, fs_1.writeFileSync)(targetPath, content);
72
+ logger.success(`${file.name}`);
73
+ installedRootFiles.push(file.name);
74
+ }
75
+ }
76
+ }
77
+ if (agentsFile) {
78
+ const targetPath = (0, path_1.join)(cwd, agentsFile.name);
79
+ (0, fs_1.writeFileSync)(targetPath, (0, template_1.processTemplate)(agentsFile.content));
80
+ logger.success(`${agentsFile.name}`);
81
+ }
82
+ if (rules.length > 0) {
83
+ logger.section("rules");
84
+ for (const file of rules) {
85
+ writeItem(aiDir, file);
86
+ logger.success(`${file.name}`);
87
+ stats.rules++;
88
+ }
89
+ }
90
+ const skills = contentFiles.filter((f) => f.type === "skills");
91
+ if (skills.length > 0) {
92
+ logger.section("skills");
93
+ const skillDirs = [...new Set(skills.map((f) => f.name.split("/")[0]))];
94
+ stats.skills = skillDirs.length;
95
+ for (const dir of skillDirs) {
96
+ const dirFiles = skills.filter((f) => f.name.startsWith(dir + "/"));
97
+ logger.success(`${dir} (${dirFiles.length} files)`);
98
+ for (const file of dirFiles) {
99
+ writeItem(aiDir, file);
100
+ }
101
+ }
102
+ }
103
+ (0, manifest_1.writeManifest)(cwd, {
104
+ version,
105
+ installedAt: new Date().toISOString(),
106
+ rootFiles: installedRootFiles,
107
+ });
108
+ return stats;
109
+ }
@@ -0,0 +1,111 @@
1
+ import { mkdirSync, existsSync, writeFileSync } from "fs";
2
+ import { join, dirname } from "path";
3
+ import { fileURLToPath } from "url";
4
+ import { getContentFiles, getRootFiles, getAgentsFile, getCommandConfig, } from "../content.js";
5
+ import { readManifest, writeManifest } from "../manifest.js";
6
+ import { processTemplate } from "../template.js";
7
+ import { log } from "../output.js";
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const rootDir = join(__dirname, "..", "..", "..");
10
+ const defaultSourceDirs = {
11
+ rules: join(rootDir, "src", "rules"),
12
+ skills: join(rootDir, "src", "skills"),
13
+ agents: join(rootDir, "src", "agents"),
14
+ commands: join(rootDir, "src", "commands"),
15
+ };
16
+ export async function sync(cwd, version, options, logger = log, sourceDirs = defaultSourceDirs) {
17
+ const manifest = readManifest(cwd);
18
+ logger.logo(version);
19
+ if (!manifest) {
20
+ logger.action("Initializing ai-kit...");
21
+ const count = await doSync(cwd, version, options, logger, sourceDirs);
22
+ logger.final(`ai-kit initialized (${count} files)`);
23
+ return;
24
+ }
25
+ if (manifest.version === version) {
26
+ logger.success(`Already at latest version (${version})`);
27
+ return;
28
+ }
29
+ logger.action(`Updating from ${manifest.version} to ${version}...`);
30
+ const count = await doSync(cwd, version, options, logger, sourceDirs);
31
+ logger.final(`Updated to ${version} (${count} files)`);
32
+ }
33
+ async function doSync(cwd, version, options, logger, sourceDirs) {
34
+ const aiDir = join(cwd, ".agents");
35
+ if (!existsSync(aiDir)) {
36
+ mkdirSync(aiDir, { recursive: true });
37
+ }
38
+ const contentFiles = getContentFiles(sourceDirs.rules, sourceDirs.skills);
39
+ const rootFiles = getRootFiles(sourceDirs.agents);
40
+ const agentsFile = getAgentsFile(sourceDirs.agents);
41
+ const rules = contentFiles.filter((f) => f.type === "rules");
42
+ const skills = contentFiles.filter((f) => f.type === "skills");
43
+ let count = 0;
44
+ if (rules.length > 0) {
45
+ logger.section("rules");
46
+ for (const file of rules) {
47
+ const targetDir = join(aiDir, file.type);
48
+ if (!existsSync(targetDir)) {
49
+ mkdirSync(targetDir, { recursive: true });
50
+ }
51
+ const targetPath = join(targetDir, file.name);
52
+ const parentDir = dirname(targetPath);
53
+ if (!existsSync(parentDir)) {
54
+ mkdirSync(parentDir, { recursive: true });
55
+ }
56
+ writeFileSync(targetPath, processTemplate(file.content));
57
+ logger.success(`${file.type}/${file.name}`);
58
+ count++;
59
+ }
60
+ }
61
+ if (skills.length > 0) {
62
+ logger.section("skills");
63
+ for (const file of skills) {
64
+ const targetDir = join(aiDir, file.type);
65
+ if (!existsSync(targetDir)) {
66
+ mkdirSync(targetDir, { recursive: true });
67
+ }
68
+ const targetPath = join(targetDir, file.name);
69
+ const parentDir = dirname(targetPath);
70
+ if (!existsSync(parentDir)) {
71
+ mkdirSync(parentDir, { recursive: true });
72
+ }
73
+ writeFileSync(targetPath, processTemplate(file.content));
74
+ logger.success(`${file.type}/${file.name}`);
75
+ count++;
76
+ }
77
+ }
78
+ const installedRootFiles = [];
79
+ if (!options.skipOpencode) {
80
+ const commandConfig = getCommandConfig(sourceDirs.commands);
81
+ if (rootFiles.length > 0) {
82
+ logger.section("root files");
83
+ for (const file of rootFiles) {
84
+ let content = file.content;
85
+ if (file.name === "opencode.json" &&
86
+ Object.keys(commandConfig).length > 0) {
87
+ const config = JSON.parse(content);
88
+ config.command = commandConfig;
89
+ content = JSON.stringify(config, null, 2) + "\n";
90
+ }
91
+ const targetPath = join(cwd, file.name);
92
+ writeFileSync(targetPath, content);
93
+ logger.success(`${file.name}`);
94
+ installedRootFiles.push(file.name);
95
+ count++;
96
+ }
97
+ }
98
+ }
99
+ if (agentsFile) {
100
+ const targetPath = join(cwd, agentsFile.name);
101
+ writeFileSync(targetPath, processTemplate(agentsFile.content));
102
+ logger.success(`${agentsFile.name}`);
103
+ count++;
104
+ }
105
+ writeManifest(cwd, {
106
+ version,
107
+ installedAt: new Date().toISOString(),
108
+ rootFiles: installedRootFiles,
109
+ });
110
+ return count;
111
+ }
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCommandConfig = getCommandConfig;
4
+ exports.getContentFiles = getContentFiles;
5
+ exports.getRootFiles = getRootFiles;
6
+ exports.getAgentsFile = getAgentsFile;
7
+ const fs_1 = require("fs");
8
+ const path_1 = require("path");
9
+ function parseFrontmatter(content) {
10
+ const result = {};
11
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
12
+ if (!match)
13
+ return result;
14
+ const frontmatter = match[1];
15
+ for (const line of frontmatter.split("\n")) {
16
+ const colonIndex = line.indexOf(":");
17
+ if (colonIndex === -1)
18
+ continue;
19
+ const key = line.slice(0, colonIndex).trim();
20
+ result[key] = line.slice(colonIndex + 1).trim();
21
+ }
22
+ return result;
23
+ }
24
+ function getCommandConfig(commandsDir) {
25
+ const config = {};
26
+ try {
27
+ const files = (0, fs_1.readdirSync)(commandsDir);
28
+ for (const file of files) {
29
+ if (!file.endsWith(".md"))
30
+ continue;
31
+ const filePath = (0, path_1.join)(commandsDir, file);
32
+ const content = (0, fs_1.readFileSync)(filePath, "utf-8");
33
+ const frontmatter = parseFrontmatter(content);
34
+ const name = file.replace(/\.md$/, "");
35
+ const body = content.replace(/^---[\s\S]*?---\n/, "").trim();
36
+ config[name] = {
37
+ description: frontmatter.description || "",
38
+ template: body,
39
+ };
40
+ }
41
+ }
42
+ catch {
43
+ return config;
44
+ }
45
+ return config;
46
+ }
47
+ function getFiles(dir, type, baseDir) {
48
+ if (!(0, fs_1.readdirSync)(dir, { withFileTypes: true }).length) {
49
+ return [];
50
+ }
51
+ const base = baseDir || dir;
52
+ return (0, fs_1.readdirSync)(dir, { withFileTypes: true }).flatMap((entry) => {
53
+ const path = (0, path_1.join)(dir, entry.name);
54
+ const relativePath = path.slice(base.length + 1);
55
+ if (entry.isDirectory()) {
56
+ return getFiles(path, type, base);
57
+ }
58
+ if (entry.name.endsWith(".md")) {
59
+ return [
60
+ {
61
+ type,
62
+ name: relativePath,
63
+ content: (0, fs_1.readFileSync)(path, "utf-8"),
64
+ },
65
+ ];
66
+ }
67
+ return [];
68
+ });
69
+ }
70
+ function getContentFiles(rulesDir, skillsDir) {
71
+ return [...getFiles(rulesDir, "rules"), ...getFiles(skillsDir, "skills")];
72
+ }
73
+ function getRootFiles(agentsDir) {
74
+ try {
75
+ return (0, fs_1.readdirSync)(agentsDir, { withFileTypes: true })
76
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
77
+ .map((entry) => ({
78
+ type: "config",
79
+ name: entry.name,
80
+ content: (0, fs_1.readFileSync)((0, path_1.join)(agentsDir, entry.name), "utf-8"),
81
+ }));
82
+ }
83
+ catch {
84
+ return [];
85
+ }
86
+ }
87
+ function getAgentsFile(agentsDir) {
88
+ const sourcePath = (0, path_1.join)(agentsDir, "monorepo.md");
89
+ try {
90
+ return {
91
+ type: "config",
92
+ name: "AGENTS.md",
93
+ content: (0, fs_1.readFileSync)(sourcePath, "utf-8"),
94
+ };
95
+ }
96
+ catch {
97
+ return null;
98
+ }
99
+ }
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const sync_1 = require("./cmd/sync");
6
+ const fs_1 = require("fs");
7
+ const path_1 = require("path");
8
+ const version = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, "..", "..", "package.json"), "utf-8")).version;
9
+ const program = new commander_1.Command();
10
+ program
11
+ .name("@clubmatto/ai-kit")
12
+ .description("The AI configuration CLI from Club Matto")
13
+ .version(version)
14
+ .option("--skip-opencode", "Skip installing opencode.json to project root");
15
+ program
16
+ .command("sync")
17
+ .description("Initialize or update AI configuration")
18
+ .action(() => (0, sync_1.sync)(process.cwd(), version, program.opts()));
19
+ program.parse();
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readManifest = readManifest;
4
+ exports.writeManifest = writeManifest;
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ const AI_DIR = ".agents";
8
+ const MANIFEST_FILE = ".ai-kit";
9
+ function getManifestPath(cwd) {
10
+ return (0, path_1.join)(cwd, AI_DIR, MANIFEST_FILE);
11
+ }
12
+ function readManifest(cwd) {
13
+ const path = getManifestPath(cwd);
14
+ if (!(0, fs_1.existsSync)(path))
15
+ return null;
16
+ return JSON.parse((0, fs_1.readFileSync)(path, "utf-8"));
17
+ }
18
+ function writeManifest(cwd, manifest) {
19
+ const dir = (0, path_1.join)(cwd, AI_DIR);
20
+ if (!(0, fs_1.existsSync)(dir)) {
21
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
22
+ }
23
+ (0, fs_1.writeFileSync)(getManifestPath(cwd), JSON.stringify(manifest, null, 2));
24
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.log = void 0;
7
+ const gradient_string_1 = __importDefault(require("gradient-string"));
8
+ const brand = (0, gradient_string_1.default)(["#ff006e", "#fb5607", "#ffbe0b", "#8338ec", "#3a86ff"]);
9
+ const colors = {
10
+ green: "\x1b[32m",
11
+ cyan: "\x1b[36m",
12
+ yellow: "\x1b[33m",
13
+ red: "\x1b[31m",
14
+ dim: "\x1b[90m",
15
+ white: "\x1b[37m",
16
+ reset: "\x1b[0m",
17
+ };
18
+ function colorize(text, color) {
19
+ return `${colors[color]}${text}${colors.reset}`;
20
+ }
21
+ exports.log = {
22
+ logo: (version) => {
23
+ console.log(brand(`ai-kit v${version}`) +
24
+ " " +
25
+ colorize("The AI configuration CLI", "dim"));
26
+ console.log(colorize("from Club Matto\n", "dim"));
27
+ },
28
+ welcome: () => {
29
+ console.log(colorize(" Syncing AI rules, skills, and commands to your project...\n", "dim"));
30
+ },
31
+ section: (msg) => console.log(colorize(` → ${msg}`, "cyan")),
32
+ success: (msg) => console.log(colorize(` ✓ ${msg}`, "green")),
33
+ final: (msg) => console.log(colorize(` ✓ ${msg}`, "green")),
34
+ summary: (counts) => {
35
+ console.log(colorize("\n ✓ Done!", "green"));
36
+ console.log(colorize(` → `, "dim") +
37
+ colorize(counts.commands.toString(), "white") +
38
+ colorize(` commands`, "dim") +
39
+ colorize(`, `, "dim") +
40
+ colorize(counts.rules.toString(), "white") +
41
+ colorize(` rules`, "dim") +
42
+ colorize(`, `, "dim") +
43
+ colorize(counts.skills.toString(), "white") +
44
+ colorize(` skills`, "dim"));
45
+ },
46
+ };
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCommandConfig = getCommandConfig;
4
+ exports.readContent = readContent;
5
+ exports.readConfigs = readConfigs;
6
+ exports.readAgents = readAgents;
7
+ const fs_1 = require("fs");
8
+ const path_1 = require("path");
9
+ function parseFrontmatter(content) {
10
+ const result = {};
11
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
12
+ if (!match)
13
+ return result;
14
+ const frontmatter = match[1];
15
+ for (const line of frontmatter.split("\n")) {
16
+ const colonIndex = line.indexOf(":");
17
+ if (colonIndex === -1)
18
+ continue;
19
+ const key = line.slice(0, colonIndex).trim();
20
+ result[key] = line.slice(colonIndex + 1).trim();
21
+ }
22
+ return result;
23
+ }
24
+ function getCommandConfig(commandsDir) {
25
+ const config = {};
26
+ try {
27
+ const files = (0, fs_1.readdirSync)(commandsDir);
28
+ for (const file of files) {
29
+ if (!file.endsWith(".md"))
30
+ continue;
31
+ const filePath = (0, path_1.join)(commandsDir, file);
32
+ const content = (0, fs_1.readFileSync)(filePath, "utf-8");
33
+ const frontmatter = parseFrontmatter(content);
34
+ const name = file.replace(/\.md$/, "");
35
+ const body = content.replace(/^---[\s\S]*?---\n/, "").trim();
36
+ config[name] = {
37
+ description: frontmatter.description || "",
38
+ template: body,
39
+ };
40
+ }
41
+ }
42
+ catch {
43
+ return config;
44
+ }
45
+ return config;
46
+ }
47
+ function readFiles(dir, type, baseDir) {
48
+ if (!(0, fs_1.readdirSync)(dir, { withFileTypes: true }).length) {
49
+ return [];
50
+ }
51
+ const base = baseDir || dir;
52
+ return (0, fs_1.readdirSync)(dir, { withFileTypes: true }).flatMap((entry) => {
53
+ const path = (0, path_1.join)(dir, entry.name);
54
+ const relativePath = path.slice(base.length + 1);
55
+ if (entry.isDirectory()) {
56
+ return readFiles(path, type, base);
57
+ }
58
+ if (entry.name.endsWith(".md")) {
59
+ return [
60
+ {
61
+ type,
62
+ name: relativePath,
63
+ content: (0, fs_1.readFileSync)(path, "utf-8"),
64
+ },
65
+ ];
66
+ }
67
+ return [];
68
+ });
69
+ }
70
+ function readContent(rulesDir, skillsDir) {
71
+ return [...readFiles(rulesDir, "rules"), ...readFiles(skillsDir, "skills")];
72
+ }
73
+ function readConfigs(agentsDir) {
74
+ try {
75
+ return (0, fs_1.readdirSync)(agentsDir, { withFileTypes: true })
76
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
77
+ .map((entry) => ({
78
+ type: "config",
79
+ name: entry.name,
80
+ content: (0, fs_1.readFileSync)((0, path_1.join)(agentsDir, entry.name), "utf-8"),
81
+ }));
82
+ }
83
+ catch {
84
+ return [];
85
+ }
86
+ }
87
+ function readAgents(agentsDir) {
88
+ const sourcePath = (0, path_1.join)(agentsDir, "monorepo.md");
89
+ try {
90
+ return {
91
+ type: "config",
92
+ name: "AGENTS.md",
93
+ content: (0, fs_1.readFileSync)(sourcePath, "utf-8"),
94
+ };
95
+ }
96
+ catch {
97
+ return null;
98
+ }
99
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processTemplate = processTemplate;
4
+ function processTemplate(content) {
5
+ const now = new Date();
6
+ const isoDate = now.toISOString().split("T")[0];
7
+ return content
8
+ .replace(/\{\{FOOTER}}/g, `Last updated: ${isoDate}. This file extends the global rules in @AGENTS.md. Always check both files.`)
9
+ .replace(/\{\{AGENTS_FOOTER}}/g, `This file was last updated: ${isoDate}. Always check the \`.ai/rules/\` directory for the most current language-specific guidelines.`);
10
+ }