@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.
- package/CHANGELOG.md +15 -0
- package/README.md +65 -0
- package/dist/scripts/fetch-playwright-skills.js +63 -0
- package/dist/src/cmd/sync.js +109 -0
- package/dist/src/commands/sync.js +111 -0
- package/dist/src/content.js +99 -0
- package/dist/src/index.js +19 -0
- package/dist/src/logger.js +2 -0
- package/dist/src/manifest.js +24 -0
- package/dist/src/output.js +46 -0
- package/dist/src/reader.js +99 -0
- package/dist/src/template.js +10 -0
- package/dist/tests/content.test.js +141 -0
- package/dist/tests/integration/cli.test.js +43 -0
- package/dist/tests/output.js +36 -0
- package/dist/tests/reader.test.js +141 -0
- package/dist/tests/sync.test.js +90 -0
- package/dist/tests/utils.js +20 -0
- package/dist/vitest.config.js +9 -0
- package/docs/roadmap.md +16 -0
- package/eslint.config.mjs +38 -0
- package/package.json +78 -0
- package/scripts/fetch-playwright-skills.ts +79 -0
- package/src/agents/monorepo.md +30 -0
- package/src/agents/opencode.json +31 -0
- package/src/cmd/sync.ts +158 -0
- package/src/commands/commit.md +43 -0
- package/src/commands/interview.md +92 -0
- package/src/commands/synth.md +45 -0
- package/src/index.ts +24 -0
- package/src/logger.ts +10 -0
- package/src/manifest.ts +29 -0
- package/src/output.ts +66 -0
- package/src/reader.ts +114 -0
- package/src/rules/go.md +306 -0
- package/src/rules/kotlin.md +177 -0
- package/src/rules/plan-mode.md +7 -0
- package/src/rules/spring-boot.md +549 -0
- package/src/rules/typescript.md +302 -0
- package/src/rules/unsure.md +9 -0
- package/src/skills/image-gen/SKILL.md +50 -0
- package/src/skills/image-gen/scripts/generate.js +166 -0
- package/src/skills/playwright-cli/SKILL.md +279 -0
- package/src/skills/playwright-cli/references/request-mocking.md +87 -0
- package/src/skills/playwright-cli/references/running-code.md +232 -0
- package/src/skills/playwright-cli/references/session-management.md +170 -0
- package/src/skills/playwright-cli/references/storage-state.md +275 -0
- package/src/skills/playwright-cli/references/test-generation.md +88 -0
- package/src/skills/playwright-cli/references/tracing.md +142 -0
- package/src/skills/playwright-cli/references/video-recording.md +43 -0
- package/src/template.ts +14 -0
- package/tests/fixtures/agents/another.json +4 -0
- package/tests/fixtures/agents/monorepo.md +5 -0
- package/tests/fixtures/agents/opencode.json +4 -0
- package/tests/fixtures/commands/another.md +5 -0
- package/tests/fixtures/commands/commit.md +7 -0
- package/tests/fixtures/commands/test.md +13 -0
- package/tests/fixtures/rules/nested/nested-rule.md +3 -0
- package/tests/fixtures/rules/test-rule.md +5 -0
- package/tests/fixtures/rules/typescript.md +5 -0
- package/tests/fixtures/skills/test-skill/SKILL.md +7 -0
- package/tests/fixtures/skills/test-skill/nested-refs/doc.md +3 -0
- package/tests/fixtures/skills/test-skill/skill-details.md +7 -0
- package/tests/integration/cli.test.ts +55 -0
- package/tests/output.ts +37 -0
- package/tests/reader.test.ts +193 -0
- package/tests/sync.test.ts +136 -0
- package/tests/utils.ts +17 -0
- package/tsconfig.json +23 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
|
|
4
|
+
const rootDir = join(__dirname, "..");
|
|
5
|
+
const skillsDir = join(rootDir, "src", "skills", "playwright-cli");
|
|
6
|
+
|
|
7
|
+
const GITHUB_API = "https://api.github.com";
|
|
8
|
+
const REPO = "microsoft/playwright-cli";
|
|
9
|
+
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const VERSION = args[0] || "v0.1.1";
|
|
12
|
+
|
|
13
|
+
interface GitHubFile {
|
|
14
|
+
name: string;
|
|
15
|
+
path: string;
|
|
16
|
+
type: "file" | "dir";
|
|
17
|
+
download_url?: string;
|
|
18
|
+
url?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function fetchJson(url: string): Promise<GitHubFile[]> {
|
|
22
|
+
const res = await fetch(url, {
|
|
23
|
+
headers: {
|
|
24
|
+
Accept: "application/vnd.github.v3+json",
|
|
25
|
+
"User-Agent": "ai-kit",
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
|
|
30
|
+
}
|
|
31
|
+
return (await res.json()) as GitHubFile[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function fetchFile(url: string): Promise<string> {
|
|
35
|
+
const res = await fetch(url, {
|
|
36
|
+
headers: {
|
|
37
|
+
Accept: "application/vnd.github.v3.raw",
|
|
38
|
+
"User-Agent": "ai-kit",
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
if (!res.ok) {
|
|
42
|
+
throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
|
|
43
|
+
}
|
|
44
|
+
return res.text();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function main() {
|
|
48
|
+
console.log(`Fetching playwright-cli skills from ${REPO}@${VERSION}...`);
|
|
49
|
+
|
|
50
|
+
const baseUrl = `${GITHUB_API}/repos/${REPO}/contents/skills/playwright-cli?ref=${VERSION}`;
|
|
51
|
+
const files = await fetchJson(baseUrl);
|
|
52
|
+
|
|
53
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
54
|
+
mkdirSync(join(skillsDir, "references"), { recursive: true });
|
|
55
|
+
|
|
56
|
+
for (const file of files) {
|
|
57
|
+
if (file.type === "dir" && file.name === "references") {
|
|
58
|
+
const refs = await fetchJson(file.url!);
|
|
59
|
+
for (const ref of refs) {
|
|
60
|
+
const content = await fetchFile(ref.download_url!);
|
|
61
|
+
const targetPath = join(skillsDir, "references", ref.name);
|
|
62
|
+
writeFileSync(targetPath, content);
|
|
63
|
+
console.log(` - references/${ref.name}`);
|
|
64
|
+
}
|
|
65
|
+
} else if (file.type === "file") {
|
|
66
|
+
const content = await fetchFile(file.download_url!);
|
|
67
|
+
const targetPath = join(skillsDir, file.name);
|
|
68
|
+
writeFileSync(targetPath, content);
|
|
69
|
+
console.log(` - ${file.name}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log(`\nDone! Skills written to src/skills/playwright-cli/`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
main().catch((err) => {
|
|
77
|
+
console.error(err);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Agents.md
|
|
2
|
+
|
|
3
|
+
This is a monorepo containing apps in many languages.
|
|
4
|
+
|
|
5
|
+
You MUST follow the specific rules for each language. **ALWAYS** start from
|
|
6
|
+
checking out README.md.
|
|
7
|
+
|
|
8
|
+
## Build Systems
|
|
9
|
+
|
|
10
|
+
- **Kotlin/Java**: Gradle (Kotlin DSL). Use `./gradlew` commands.
|
|
11
|
+
- **Go**: Go modules. Use `go` commands.
|
|
12
|
+
- **TypeScript**: Use `npm`.
|
|
13
|
+
|
|
14
|
+
## How to Find the Right Rules
|
|
15
|
+
|
|
16
|
+
1. **Identify the primary language** of the file(s) you're working with.
|
|
17
|
+
2. **Navigate to `.agents/rules/`** and open the corresponding file:
|
|
18
|
+
- TypeScript → `typescript.md`
|
|
19
|
+
- Go → `go.md`
|
|
20
|
+
- Kotlin → `kotlin.md`
|
|
21
|
+
- etc.
|
|
22
|
+
|
|
23
|
+
CRITICAL: When you encounter a file reference (e.g., `@.ai/rules/go.md`), use the Read tool to load it on a need-to-know basis.
|
|
24
|
+
|
|
25
|
+
## Additional Guidelines
|
|
26
|
+
|
|
27
|
+
- [Plan Mode](.agents/rules/plan-mode.md)
|
|
28
|
+
- [When You're Unsure](.agents/rules/unsure.md)
|
|
29
|
+
|
|
30
|
+
_{{AGENTS_FOOTER}}_
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://opencode.ai/config.json",
|
|
3
|
+
"mcp": {
|
|
4
|
+
"context7": {
|
|
5
|
+
"type": "remote",
|
|
6
|
+
"url": "https://mcp.context7.com/mcp",
|
|
7
|
+
"headers": {
|
|
8
|
+
"CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}"
|
|
9
|
+
},
|
|
10
|
+
"enabled": false
|
|
11
|
+
},
|
|
12
|
+
"circleci": {
|
|
13
|
+
"type": "local",
|
|
14
|
+
"command": ["npx", "-y", "@circleci/mcp-server-circleci@latest"],
|
|
15
|
+
"environment": {
|
|
16
|
+
"CIRCLECI_TOKEN": "{env:CIRCLECI_TOKEN}",
|
|
17
|
+
"CIRCLECI_BASE_URL": "https://circleci.com"
|
|
18
|
+
},
|
|
19
|
+
"enabled": false
|
|
20
|
+
},
|
|
21
|
+
"MiniMax": {
|
|
22
|
+
"type": "local",
|
|
23
|
+
"command": ["uvx", "minimax-coding-plan-mcp", "-y"],
|
|
24
|
+
"environment": {
|
|
25
|
+
"MINIMAX_API_KEY": "{env:MINIMAX_API_KEY}",
|
|
26
|
+
"MINIMAX_API_HOST": "https://api.minimax.io"
|
|
27
|
+
},
|
|
28
|
+
"enabled": false
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/cmd/sync.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
2
|
+
import { dirname, join } from "path";
|
|
3
|
+
import {
|
|
4
|
+
readAgents,
|
|
5
|
+
getCommandConfig,
|
|
6
|
+
readContent,
|
|
7
|
+
readConfigs,
|
|
8
|
+
SyncItem,
|
|
9
|
+
} from "../reader";
|
|
10
|
+
import { readManifest, writeManifest } from "../manifest";
|
|
11
|
+
import { processTemplate } from "../template";
|
|
12
|
+
import { log, SyncStats } from "../output";
|
|
13
|
+
import { Logger } from "../logger";
|
|
14
|
+
|
|
15
|
+
const rootDir = join(__dirname, "..", "..", "..");
|
|
16
|
+
|
|
17
|
+
export interface SourceDirs {
|
|
18
|
+
rules: string;
|
|
19
|
+
skills: string;
|
|
20
|
+
agents: string;
|
|
21
|
+
commands: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const defaultSourceDirs: SourceDirs = {
|
|
25
|
+
rules: join(rootDir, "src", "rules"),
|
|
26
|
+
skills: join(rootDir, "src", "skills"),
|
|
27
|
+
agents: join(rootDir, "src", "agents"),
|
|
28
|
+
commands: join(rootDir, "src", "commands"),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
interface SyncOptions {
|
|
32
|
+
skipOpencode?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function sync(
|
|
36
|
+
cwd: string,
|
|
37
|
+
version: string,
|
|
38
|
+
options: SyncOptions,
|
|
39
|
+
logger: Logger = log,
|
|
40
|
+
sourceDirs: SourceDirs = defaultSourceDirs,
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
const manifest = readManifest(cwd);
|
|
43
|
+
logger.logo(version);
|
|
44
|
+
|
|
45
|
+
if (manifest && manifest.version === version) {
|
|
46
|
+
logger.success(`Already at latest version (${version})`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
logger.welcome();
|
|
51
|
+
const counts = await doSync(cwd, version, options, logger, sourceDirs);
|
|
52
|
+
logger.summary(counts);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function writeItem(aiDir: string, file: SyncItem): void {
|
|
56
|
+
const targetDir = join(aiDir, file.type);
|
|
57
|
+
if (!existsSync(targetDir)) {
|
|
58
|
+
mkdirSync(targetDir, { recursive: true });
|
|
59
|
+
}
|
|
60
|
+
const targetPath = join(targetDir, file.name);
|
|
61
|
+
const parentDir = dirname(targetPath);
|
|
62
|
+
if (!existsSync(parentDir)) {
|
|
63
|
+
mkdirSync(parentDir, { recursive: true });
|
|
64
|
+
}
|
|
65
|
+
writeFileSync(targetPath, processTemplate(file.content));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function doSync(
|
|
69
|
+
cwd: string,
|
|
70
|
+
version: string,
|
|
71
|
+
options: SyncOptions,
|
|
72
|
+
logger: Logger,
|
|
73
|
+
sourceDirs: SourceDirs,
|
|
74
|
+
): Promise<SyncStats> {
|
|
75
|
+
const aiDir = join(cwd, ".agents");
|
|
76
|
+
|
|
77
|
+
if (!existsSync(aiDir)) {
|
|
78
|
+
mkdirSync(aiDir, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const contentFiles = readContent(sourceDirs.rules, sourceDirs.skills);
|
|
82
|
+
const rootFiles = readConfigs(sourceDirs.agents);
|
|
83
|
+
const agentsFile = readAgents(sourceDirs.agents);
|
|
84
|
+
|
|
85
|
+
const rules = contentFiles.filter((f) => f.type === "rules");
|
|
86
|
+
|
|
87
|
+
const stats: SyncStats = { rules: 0, skills: 0, commands: 0 };
|
|
88
|
+
|
|
89
|
+
const installedRootFiles: string[] = [];
|
|
90
|
+
if (!options.skipOpencode) {
|
|
91
|
+
const commandConfig = getCommandConfig(sourceDirs.commands);
|
|
92
|
+
stats.commands = Object.keys(commandConfig).length;
|
|
93
|
+
|
|
94
|
+
if (Object.keys(commandConfig).length > 0) {
|
|
95
|
+
logger.section("commands");
|
|
96
|
+
for (const name of Object.keys(commandConfig)) {
|
|
97
|
+
logger.success(`${name}.md`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (rootFiles.length > 0) {
|
|
102
|
+
logger.section("configs");
|
|
103
|
+
for (const file of rootFiles) {
|
|
104
|
+
let content = file.content;
|
|
105
|
+
if (
|
|
106
|
+
file.name === "opencode.json" &&
|
|
107
|
+
Object.keys(commandConfig).length > 0
|
|
108
|
+
) {
|
|
109
|
+
const config = JSON.parse(content);
|
|
110
|
+
config.command = commandConfig;
|
|
111
|
+
content = JSON.stringify(config, null, 2) + "\n";
|
|
112
|
+
}
|
|
113
|
+
const targetPath = join(cwd, file.name);
|
|
114
|
+
writeFileSync(targetPath, content);
|
|
115
|
+
logger.success(`${file.name}`);
|
|
116
|
+
installedRootFiles.push(file.name);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (agentsFile) {
|
|
122
|
+
const targetPath = join(cwd, agentsFile.name);
|
|
123
|
+
writeFileSync(targetPath, processTemplate(agentsFile.content));
|
|
124
|
+
logger.success(`${agentsFile.name}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (rules.length > 0) {
|
|
128
|
+
logger.section("rules");
|
|
129
|
+
for (const file of rules) {
|
|
130
|
+
writeItem(aiDir, file);
|
|
131
|
+
logger.success(`${file.name}`);
|
|
132
|
+
stats.rules++;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const skills = contentFiles.filter((f) => f.type === "skills");
|
|
137
|
+
|
|
138
|
+
if (skills.length > 0) {
|
|
139
|
+
logger.section("skills");
|
|
140
|
+
const skillDirs = [...new Set(skills.map((f) => f.name.split("/")[0]))];
|
|
141
|
+
stats.skills = skillDirs.length;
|
|
142
|
+
for (const dir of skillDirs) {
|
|
143
|
+
const dirFiles = skills.filter((f) => f.name.startsWith(dir + "/"));
|
|
144
|
+
logger.success(`${dir} (${dirFiles.length} files)`);
|
|
145
|
+
for (const file of dirFiles) {
|
|
146
|
+
writeItem(aiDir, file);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
writeManifest(cwd, {
|
|
152
|
+
version,
|
|
153
|
+
installedAt: new Date().toISOString(),
|
|
154
|
+
rootFiles: installedRootFiles,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
return stats;
|
|
158
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Commit the work done in this session with a structured commit message.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Create a commit with the following format:
|
|
6
|
+
|
|
7
|
+
## Commit Message Format
|
|
8
|
+
|
|
9
|
+
**First line (one-liner):**
|
|
10
|
+
|
|
11
|
+
- Use conventional commits format: `<type>: <description>`
|
|
12
|
+
- Examples: `feat: add init command`, `fix: resolve path issue`, `docs: update README`
|
|
13
|
+
|
|
14
|
+
**Body (bullet list):**
|
|
15
|
+
|
|
16
|
+
- List the main changes made in this session
|
|
17
|
+
- Each item should be a brief description of a specific change
|
|
18
|
+
|
|
19
|
+
**Sign-off:**
|
|
20
|
+
|
|
21
|
+
- End with: `created with the help of <MODEL>`
|
|
22
|
+
- Use the current model name (e.g. "MiniMax", "GPT-4", "Claude")
|
|
23
|
+
|
|
24
|
+
## Example
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
feat: add init and update commands
|
|
28
|
+
|
|
29
|
+
- Created init command for first-time setup
|
|
30
|
+
- Added manifest tracking in .ai/.ai-kit
|
|
31
|
+
- Implemented update command for version sync
|
|
32
|
+
- Added --skip-opencode option
|
|
33
|
+
|
|
34
|
+
created with the help of MiniMax
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Process
|
|
38
|
+
|
|
39
|
+
1. First, review all changes with `git status` and `git diff`
|
|
40
|
+
2. Write a concise one-liner following conventional commits
|
|
41
|
+
3. List the key changes as bullet points
|
|
42
|
+
4. Add the sign-off line with the current model
|
|
43
|
+
5. Commit with `git commit -m "your message"`
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Interview the user to define a feature, then generate a task‑oriented implementation plan as a markdown document.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Implementation Plan Generation
|
|
6
|
+
|
|
7
|
+
You are a technical architect. Your task is to conduct a structured interview
|
|
8
|
+
with the user, then produce a \*
|
|
9
|
+
\*task‑oriented implementation plan\*\* — not a narrative PRD. The final output
|
|
10
|
+
must be a series of concrete, actionable
|
|
11
|
+
tasks, each with explicit sequential actions, and verification steps.
|
|
12
|
+
|
|
13
|
+
Follow the process below. Skip steps only if clearly irrelevant.
|
|
14
|
+
|
|
15
|
+
## Process
|
|
16
|
+
|
|
17
|
+
### 1. Problem Elicitation
|
|
18
|
+
|
|
19
|
+
Ask the user for a detailed description of the problem they want to solve. Probe
|
|
20
|
+
for:
|
|
21
|
+
|
|
22
|
+
- Current pain points or limitations
|
|
23
|
+
- User impact and severity
|
|
24
|
+
- Any initial solution ideas they have in mind
|
|
25
|
+
|
|
26
|
+
### 2. Context Verification
|
|
27
|
+
|
|
28
|
+
Explore the codebase to verify the user's assertions. Understand the current
|
|
29
|
+
state of relevant modules, existing
|
|
30
|
+
patterns, and potential constraints. **Do not ask the user for this
|
|
31
|
+
information—investigate it yourself.**
|
|
32
|
+
|
|
33
|
+
### 3. Option Exploration
|
|
34
|
+
|
|
35
|
+
Ask whether the user has considered alternative approaches. Based on your
|
|
36
|
+
understanding of the codebase, present 1-3
|
|
37
|
+
other viable options with brief trade-offs (complexity, effort,
|
|
38
|
+
maintainability).
|
|
39
|
+
|
|
40
|
+
### 4. Deep Dive Interview
|
|
41
|
+
|
|
42
|
+
Conduct a thorough interview about the proposed implementation. Your goal is to
|
|
43
|
+
gather **everything needed to write
|
|
44
|
+
concrete tasks**. Cover:
|
|
45
|
+
|
|
46
|
+
- Exact files to create/modify (capture paths **relative to project root**)
|
|
47
|
+
- Specific dependencies to add (with version research notes)
|
|
48
|
+
- Precise code changes (what, where, why)
|
|
49
|
+
- Edge cases and error states
|
|
50
|
+
- Performance expectations
|
|
51
|
+
- Compatibility requirements
|
|
52
|
+
- Security considerations
|
|
53
|
+
|
|
54
|
+
### 5. Scope Definition
|
|
55
|
+
|
|
56
|
+
Explicitly define what is **in scope** and what is **out of scope** for this
|
|
57
|
+
plan. Confirm with the user.
|
|
58
|
+
|
|
59
|
+
### 6. Task Breakdown
|
|
60
|
+
|
|
61
|
+
Decompose the implementation into **discrete, executable tasks**. Each task must
|
|
62
|
+
follow this exact structure:
|
|
63
|
+
|
|
64
|
+
## Tasks
|
|
65
|
+
|
|
66
|
+
### N. [Task Title]
|
|
67
|
+
|
|
68
|
+
**Actions:**
|
|
69
|
+
|
|
70
|
+
1. [Specific, sequential action]
|
|
71
|
+
2. [Next action, with code block if needed]
|
|
72
|
+
3. [Etc.]
|
|
73
|
+
|
|
74
|
+
**Verification:
|
|
75
|
+
** [Exact command to run or observable outcome that confirms this task is complete]
|
|
76
|
+
|
|
77
|
+
**Rules for tasks:**
|
|
78
|
+
|
|
79
|
+
- File paths must be **relative to project root** (no absolute paths, no
|
|
80
|
+
`/Users/...`)
|
|
81
|
+
- Actions must be **atomic**—one logical change per numbered step
|
|
82
|
+
- Include inline code blocks where syntax matters
|
|
83
|
+
- Verification must be **executable** (a command, a test, a visible UI state)
|
|
84
|
+
- Tasks should be **orderable**—later tasks may depend on earlier ones
|
|
85
|
+
|
|
86
|
+
### 7. Plan Generation
|
|
87
|
+
|
|
88
|
+
Once all information is gathered, generate the complete implementation plan
|
|
89
|
+
using the format above. The plan should be
|
|
90
|
+
ready to paste directly into a markdown document.
|
|
91
|
+
|
|
92
|
+
Begin the interview now.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: To consolidate the key learnings, patterns, successful code structures, and conceptual insights from the current session into a reusable, LLM-friendly reference document.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Synthesize the core work, discoveries, and decisions from this development
|
|
6
|
+
session into a structured, clear, and
|
|
7
|
+
future-oriented document. This document should enable an LLM or a future
|
|
8
|
+
developer to quickly understand and reuse the
|
|
9
|
+
outcomes of this session.
|
|
10
|
+
|
|
11
|
+
## 1. Core Task Summary
|
|
12
|
+
|
|
13
|
+
Summarize the central problem or goal of this session in 1-2 sentences.
|
|
14
|
+
|
|
15
|
+
## 2. Key Outcomes & Solutions
|
|
16
|
+
|
|
17
|
+
List the main features implemented, critical bugs fixed, or core modules
|
|
18
|
+
completed. For complex items, provide **code
|
|
19
|
+
snippets, architectural descriptions**, or key configurations.
|
|
20
|
+
|
|
21
|
+
## 3. Learnings & Discoveries
|
|
22
|
+
|
|
23
|
+
Document important insights gained during this session, such as:
|
|
24
|
+
|
|
25
|
+
- New usages or best practices for specific libraries, APIs, or tools.
|
|
26
|
+
- New understandings about system design or data flow.
|
|
27
|
+
- Pitfalls encountered and their solutions.
|
|
28
|
+
|
|
29
|
+
## 4. Reusable Patterns & Code Templates
|
|
30
|
+
|
|
31
|
+
Extract patterns, code templates, or configuration snippets that can be \*
|
|
32
|
+
\*directly applied to future projects or similar
|
|
33
|
+
tasks\*\*. Include brief context and usage instructions.
|
|
34
|
+
|
|
35
|
+
## 5. LLM Collaboration Notes (Optional)
|
|
36
|
+
|
|
37
|
+
If this session involved prompt techniques, instruction patterns, or context
|
|
38
|
+
management methods particularly useful for
|
|
39
|
+
collaborating with an LLM, document them here.
|
|
40
|
+
|
|
41
|
+
## Synthesis Process
|
|
42
|
+
|
|
43
|
+
1. First, review the entire session's conversation history and code changes.
|
|
44
|
+
2. Then, synthesize the content strictly following the section structure above.
|
|
45
|
+
3. The final output must be a complete, standalone Markdown document.
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { sync } from "./cmd/sync";
|
|
4
|
+
import { readFileSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
|
|
7
|
+
const version = JSON.parse(
|
|
8
|
+
readFileSync(join(__dirname, "..", "..", "package.json"), "utf-8"),
|
|
9
|
+
).version;
|
|
10
|
+
|
|
11
|
+
const program = new Command();
|
|
12
|
+
|
|
13
|
+
program
|
|
14
|
+
.name("@clubmatto/ai-kit")
|
|
15
|
+
.description("The AI configuration CLI from Club Matto")
|
|
16
|
+
.version(version)
|
|
17
|
+
.option("--skip-opencode", "Skip installing opencode.json to project root");
|
|
18
|
+
|
|
19
|
+
program
|
|
20
|
+
.command("sync")
|
|
21
|
+
.description("Initialize or update AI configuration")
|
|
22
|
+
.action(() => sync(process.cwd(), version, program.opts()));
|
|
23
|
+
|
|
24
|
+
program.parse();
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SyncStats } from "./output";
|
|
2
|
+
|
|
3
|
+
export interface Logger {
|
|
4
|
+
logo: (version: string) => void;
|
|
5
|
+
welcome: () => void;
|
|
6
|
+
section: (msg: string) => void;
|
|
7
|
+
success: (msg: string) => void;
|
|
8
|
+
final: (msg: string) => void;
|
|
9
|
+
summary: (counts: SyncStats) => void;
|
|
10
|
+
}
|
package/src/manifest.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
|
|
4
|
+
interface Manifest {
|
|
5
|
+
version: string;
|
|
6
|
+
installedAt: string;
|
|
7
|
+
rootFiles?: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const AI_DIR = ".agents";
|
|
11
|
+
const MANIFEST_FILE = ".ai-kit";
|
|
12
|
+
|
|
13
|
+
function getManifestPath(cwd: string): string {
|
|
14
|
+
return join(cwd, AI_DIR, MANIFEST_FILE);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function readManifest(cwd: string): Manifest | null {
|
|
18
|
+
const path = getManifestPath(cwd);
|
|
19
|
+
if (!existsSync(path)) return null;
|
|
20
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function writeManifest(cwd: string, manifest: Manifest): void {
|
|
24
|
+
const dir = join(cwd, AI_DIR);
|
|
25
|
+
if (!existsSync(dir)) {
|
|
26
|
+
mkdirSync(dir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
writeFileSync(getManifestPath(cwd), JSON.stringify(manifest, null, 2));
|
|
29
|
+
}
|
package/src/output.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import gradient from "gradient-string";
|
|
2
|
+
|
|
3
|
+
const brand = gradient(["#ff006e", "#fb5607", "#ffbe0b", "#8338ec", "#3a86ff"]);
|
|
4
|
+
|
|
5
|
+
type Color = "green" | "cyan" | "yellow" | "red" | "dim" | "white" | "reset";
|
|
6
|
+
|
|
7
|
+
const colors: Record<Color, string> = {
|
|
8
|
+
green: "\x1b[32m",
|
|
9
|
+
cyan: "\x1b[36m",
|
|
10
|
+
yellow: "\x1b[33m",
|
|
11
|
+
red: "\x1b[31m",
|
|
12
|
+
dim: "\x1b[90m",
|
|
13
|
+
white: "\x1b[37m",
|
|
14
|
+
reset: "\x1b[0m",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function colorize(text: string, color: Color): string {
|
|
18
|
+
return `${colors[color]}${text}${colors.reset}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface SyncStats {
|
|
22
|
+
rules: number;
|
|
23
|
+
skills: number;
|
|
24
|
+
commands: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const log = {
|
|
28
|
+
logo: (version: string) => {
|
|
29
|
+
console.log(
|
|
30
|
+
brand(`ai-kit v${version}`) +
|
|
31
|
+
" " +
|
|
32
|
+
colorize("The AI configuration CLI", "dim"),
|
|
33
|
+
);
|
|
34
|
+
console.log(colorize("from Club Matto\n", "dim"));
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
welcome: () => {
|
|
38
|
+
console.log(
|
|
39
|
+
colorize(
|
|
40
|
+
" Syncing AI rules, skills, and commands to your project...\n",
|
|
41
|
+
"dim",
|
|
42
|
+
),
|
|
43
|
+
);
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
section: (msg: string) => console.log(colorize(` → ${msg}`, "cyan")),
|
|
47
|
+
|
|
48
|
+
success: (msg: string) => console.log(colorize(` ✓ ${msg}`, "green")),
|
|
49
|
+
|
|
50
|
+
final: (msg: string) => console.log(colorize(` ✓ ${msg}`, "green")),
|
|
51
|
+
|
|
52
|
+
summary: (counts: SyncStats) => {
|
|
53
|
+
console.log(colorize("\n ✓ Done!", "green"));
|
|
54
|
+
console.log(
|
|
55
|
+
colorize(` → `, "dim") +
|
|
56
|
+
colorize(counts.commands.toString(), "white") +
|
|
57
|
+
colorize(` commands`, "dim") +
|
|
58
|
+
colorize(`, `, "dim") +
|
|
59
|
+
colorize(counts.rules.toString(), "white") +
|
|
60
|
+
colorize(` rules`, "dim") +
|
|
61
|
+
colorize(`, `, "dim") +
|
|
62
|
+
colorize(counts.skills.toString(), "white") +
|
|
63
|
+
colorize(` skills`, "dim"),
|
|
64
|
+
);
|
|
65
|
+
},
|
|
66
|
+
};
|