codemaxxing 1.0.0 → 1.0.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.
- package/README.md +18 -12
- package/dist/agent.d.ts +4 -0
- package/dist/agent.js +91 -16
- package/dist/commands/git.d.ts +2 -0
- package/dist/commands/git.js +50 -0
- package/dist/commands/ollama.d.ts +27 -0
- package/dist/commands/ollama.js +171 -0
- package/dist/commands/output.d.ts +2 -0
- package/dist/commands/output.js +18 -0
- package/dist/commands/registry.d.ts +2 -0
- package/dist/commands/registry.js +8 -0
- package/dist/commands/skills.d.ts +18 -0
- package/dist/commands/skills.js +121 -0
- package/dist/commands/types.d.ts +5 -0
- package/dist/commands/types.js +1 -0
- package/dist/commands/ui.d.ts +16 -0
- package/dist/commands/ui.js +79 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.js +13 -3
- package/dist/exec.js +4 -1
- package/dist/index.js +75 -401
- package/dist/tools/files.js +58 -3
- package/dist/utils/context.js +6 -0
- package/dist/utils/mcp.d.ts +7 -2
- package/dist/utils/mcp.js +34 -6
- package/package.json +8 -5
- package/src/agent.ts +0 -894
- package/src/auth-cli.ts +0 -287
- package/src/cli.ts +0 -37
- package/src/config.ts +0 -352
- package/src/exec.ts +0 -183
- package/src/index.tsx +0 -2647
- package/src/skills/registry.ts +0 -1436
- package/src/themes.ts +0 -335
- package/src/tools/files.ts +0 -374
- package/src/utils/auth.ts +0 -606
- package/src/utils/context.ts +0 -174
- package/src/utils/git.ts +0 -117
- package/src/utils/hardware.ts +0 -131
- package/src/utils/lint.ts +0 -116
- package/src/utils/mcp.ts +0 -307
- package/src/utils/models.ts +0 -218
- package/src/utils/ollama.ts +0 -352
- package/src/utils/repomap.ts +0 -220
- package/src/utils/sessions.ts +0 -254
- package/src/utils/skills.ts +0 -241
- package/tsconfig.json +0 -16
package/src/utils/sessions.ts
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import Database from "better-sqlite3";
|
|
2
|
-
import { existsSync, mkdirSync } from "fs";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
import { homedir } from "os";
|
|
5
|
-
import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";
|
|
6
|
-
|
|
7
|
-
const CONFIG_DIR = join(homedir(), ".codemaxxing");
|
|
8
|
-
const DB_PATH = join(CONFIG_DIR, "sessions.db");
|
|
9
|
-
|
|
10
|
-
let db: Database.Database | null = null;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Initialize the database and create tables if needed
|
|
14
|
-
*/
|
|
15
|
-
function getDb(): Database.Database {
|
|
16
|
-
if (db) return db;
|
|
17
|
-
|
|
18
|
-
if (!existsSync(CONFIG_DIR)) {
|
|
19
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
db = new Database(DB_PATH);
|
|
23
|
-
|
|
24
|
-
// Enable WAL mode for better concurrent performance
|
|
25
|
-
db.pragma("journal_mode = WAL");
|
|
26
|
-
|
|
27
|
-
// Create tables
|
|
28
|
-
db.exec(`
|
|
29
|
-
CREATE TABLE IF NOT EXISTS sessions (
|
|
30
|
-
id TEXT PRIMARY KEY,
|
|
31
|
-
cwd TEXT NOT NULL,
|
|
32
|
-
model TEXT NOT NULL,
|
|
33
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
34
|
-
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
35
|
-
message_count INTEGER NOT NULL DEFAULT 0,
|
|
36
|
-
token_estimate INTEGER NOT NULL DEFAULT 0,
|
|
37
|
-
summary TEXT,
|
|
38
|
-
prompt_tokens INTEGER NOT NULL DEFAULT 0,
|
|
39
|
-
completion_tokens INTEGER NOT NULL DEFAULT 0,
|
|
40
|
-
estimated_cost REAL NOT NULL DEFAULT 0
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
CREATE TABLE IF NOT EXISTS messages (
|
|
44
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
45
|
-
session_id TEXT NOT NULL,
|
|
46
|
-
role TEXT NOT NULL,
|
|
47
|
-
content TEXT,
|
|
48
|
-
tool_calls TEXT,
|
|
49
|
-
tool_call_id TEXT,
|
|
50
|
-
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
51
|
-
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
|
|
55
|
-
`);
|
|
56
|
-
|
|
57
|
-
// Migrate: add cost columns if missing (for existing DBs)
|
|
58
|
-
try {
|
|
59
|
-
db.exec(`ALTER TABLE sessions ADD COLUMN prompt_tokens INTEGER NOT NULL DEFAULT 0`);
|
|
60
|
-
} catch { /* column already exists */ }
|
|
61
|
-
try {
|
|
62
|
-
db.exec(`ALTER TABLE sessions ADD COLUMN completion_tokens INTEGER NOT NULL DEFAULT 0`);
|
|
63
|
-
} catch { /* column already exists */ }
|
|
64
|
-
try {
|
|
65
|
-
db.exec(`ALTER TABLE sessions ADD COLUMN estimated_cost REAL NOT NULL DEFAULT 0`);
|
|
66
|
-
} catch { /* column already exists */ }
|
|
67
|
-
|
|
68
|
-
return db;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Generate a short session ID (8 chars)
|
|
73
|
-
*/
|
|
74
|
-
function generateId(): string {
|
|
75
|
-
const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
76
|
-
let id = "";
|
|
77
|
-
for (let i = 0; i < 8; i++) {
|
|
78
|
-
id += chars[Math.floor(Math.random() * chars.length)];
|
|
79
|
-
}
|
|
80
|
-
return id;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Create a new session
|
|
85
|
-
*/
|
|
86
|
-
export function createSession(cwd: string, model: string): string {
|
|
87
|
-
const db = getDb();
|
|
88
|
-
const id = generateId();
|
|
89
|
-
|
|
90
|
-
db.prepare(`
|
|
91
|
-
INSERT INTO sessions (id, cwd, model) VALUES (?, ?, ?)
|
|
92
|
-
`).run(id, cwd, model);
|
|
93
|
-
|
|
94
|
-
return id;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Save a message to a session
|
|
99
|
-
*/
|
|
100
|
-
export function saveMessage(sessionId: string, message: ChatCompletionMessageParam): void {
|
|
101
|
-
const db = getDb();
|
|
102
|
-
|
|
103
|
-
const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content);
|
|
104
|
-
const toolCalls = "tool_calls" in message && message.tool_calls
|
|
105
|
-
? JSON.stringify(message.tool_calls)
|
|
106
|
-
: null;
|
|
107
|
-
const toolCallId = "tool_call_id" in message ? (message as any).tool_call_id : null;
|
|
108
|
-
|
|
109
|
-
db.prepare(`
|
|
110
|
-
INSERT INTO messages (session_id, role, content, tool_calls, tool_call_id)
|
|
111
|
-
VALUES (?, ?, ?, ?, ?)
|
|
112
|
-
`).run(sessionId, message.role, content, toolCalls, toolCallId);
|
|
113
|
-
|
|
114
|
-
// Update session metadata
|
|
115
|
-
const stats = db.prepare(`
|
|
116
|
-
SELECT COUNT(*) as count FROM messages WHERE session_id = ?
|
|
117
|
-
`).get(sessionId) as { count: number };
|
|
118
|
-
|
|
119
|
-
db.prepare(`
|
|
120
|
-
UPDATE sessions SET updated_at = datetime('now'), message_count = ? WHERE id = ?
|
|
121
|
-
`).run(stats.count, sessionId);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Update token estimate for a session
|
|
126
|
-
*/
|
|
127
|
-
export function updateTokenEstimate(sessionId: string, tokens: number): void {
|
|
128
|
-
const db = getDb();
|
|
129
|
-
db.prepare(`
|
|
130
|
-
UPDATE sessions SET token_estimate = ? WHERE id = ?
|
|
131
|
-
`).run(tokens, sessionId);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* List recent sessions
|
|
136
|
-
*/
|
|
137
|
-
export interface SessionInfo {
|
|
138
|
-
id: string;
|
|
139
|
-
cwd: string;
|
|
140
|
-
model: string;
|
|
141
|
-
created_at: string;
|
|
142
|
-
updated_at: string;
|
|
143
|
-
message_count: number;
|
|
144
|
-
token_estimate: number;
|
|
145
|
-
summary: string | null;
|
|
146
|
-
prompt_tokens: number;
|
|
147
|
-
completion_tokens: number;
|
|
148
|
-
estimated_cost: number;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export function listSessions(limit: number = 10): SessionInfo[] {
|
|
152
|
-
const db = getDb();
|
|
153
|
-
return db.prepare(`
|
|
154
|
-
SELECT * FROM sessions ORDER BY updated_at DESC LIMIT ?
|
|
155
|
-
`).all(limit) as SessionInfo[];
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Load all messages for a session
|
|
160
|
-
*/
|
|
161
|
-
export function loadMessages(sessionId: string): ChatCompletionMessageParam[] {
|
|
162
|
-
const db = getDb();
|
|
163
|
-
|
|
164
|
-
const rows = db.prepare(`
|
|
165
|
-
SELECT role, content, tool_calls, tool_call_id FROM messages
|
|
166
|
-
WHERE session_id = ? ORDER BY id ASC
|
|
167
|
-
`).all(sessionId) as Array<{
|
|
168
|
-
role: string;
|
|
169
|
-
content: string | null;
|
|
170
|
-
tool_calls: string | null;
|
|
171
|
-
tool_call_id: string | null;
|
|
172
|
-
}>;
|
|
173
|
-
|
|
174
|
-
return rows.map((row) => {
|
|
175
|
-
const msg: any = { role: row.role, content: row.content };
|
|
176
|
-
|
|
177
|
-
if (row.tool_calls) {
|
|
178
|
-
try {
|
|
179
|
-
msg.tool_calls = JSON.parse(row.tool_calls);
|
|
180
|
-
} catch { /* ignore */ }
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (row.tool_call_id) {
|
|
184
|
-
msg.tool_call_id = row.tool_call_id;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return msg as ChatCompletionMessageParam;
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Get a specific session
|
|
193
|
-
*/
|
|
194
|
-
export function getSession(sessionId: string): SessionInfo | null {
|
|
195
|
-
const db = getDb();
|
|
196
|
-
return (db.prepare(`
|
|
197
|
-
SELECT * FROM sessions WHERE id = ?
|
|
198
|
-
`).get(sessionId) as SessionInfo) || null;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Delete a session and its messages
|
|
203
|
-
*/
|
|
204
|
-
export function deleteSession(sessionId: string): boolean {
|
|
205
|
-
const db = getDb();
|
|
206
|
-
db.prepare(`DELETE FROM messages WHERE session_id = ?`).run(sessionId);
|
|
207
|
-
const result = db.prepare(`DELETE FROM sessions WHERE id = ?`).run(sessionId);
|
|
208
|
-
return result.changes > 0;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Update cost tracking for a session
|
|
213
|
-
*/
|
|
214
|
-
export function updateSessionCost(
|
|
215
|
-
sessionId: string,
|
|
216
|
-
promptTokens: number,
|
|
217
|
-
completionTokens: number,
|
|
218
|
-
estimatedCost: number
|
|
219
|
-
): void {
|
|
220
|
-
const db = getDb();
|
|
221
|
-
db.prepare(`
|
|
222
|
-
UPDATE sessions SET prompt_tokens = ?, completion_tokens = ?, estimated_cost = ? WHERE id = ?
|
|
223
|
-
`).run(promptTokens, completionTokens, estimatedCost, sessionId);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Update session summary (for context compression)
|
|
228
|
-
*/
|
|
229
|
-
export function updateSummary(sessionId: string, summary: string): void {
|
|
230
|
-
const db = getDb();
|
|
231
|
-
db.prepare(`
|
|
232
|
-
UPDATE sessions SET summary = ? WHERE id = ?
|
|
233
|
-
`).run(summary, sessionId);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Get the most recent session for a given cwd
|
|
238
|
-
*/
|
|
239
|
-
export function getLastSession(cwd: string): SessionInfo | null {
|
|
240
|
-
const db = getDb();
|
|
241
|
-
return (db.prepare(`
|
|
242
|
-
SELECT * FROM sessions WHERE cwd = ? ORDER BY updated_at DESC LIMIT 1
|
|
243
|
-
`).get(cwd) as SessionInfo) || null;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Close the database connection
|
|
248
|
-
*/
|
|
249
|
-
export function closeDb(): void {
|
|
250
|
-
if (db) {
|
|
251
|
-
db.close();
|
|
252
|
-
db = null;
|
|
253
|
-
}
|
|
254
|
-
}
|
package/src/utils/skills.ts
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, rmSync } from "fs";
|
|
2
|
-
import { join, basename } from "path";
|
|
3
|
-
import { homedir } from "os";
|
|
4
|
-
import { REGISTRY, type RegistrySkill } from "../skills/registry.js";
|
|
5
|
-
|
|
6
|
-
const SKILLS_DIR = join(homedir(), ".codemaxxing", "skills");
|
|
7
|
-
|
|
8
|
-
export interface SkillMeta {
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
version: string;
|
|
12
|
-
author: string;
|
|
13
|
-
tags: string[];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Ensure the skills directory exists
|
|
18
|
-
*/
|
|
19
|
-
function ensureSkillsDir(): void {
|
|
20
|
-
if (!existsSync(SKILLS_DIR)) {
|
|
21
|
-
mkdirSync(SKILLS_DIR, { recursive: true });
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* List all installed skills by scanning ~/.codemaxxing/skills/
|
|
27
|
-
*/
|
|
28
|
-
export function listInstalledSkills(): SkillMeta[] {
|
|
29
|
-
ensureSkillsDir();
|
|
30
|
-
const skills: SkillMeta[] = [];
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
const entries = readdirSync(SKILLS_DIR, { withFileTypes: true });
|
|
34
|
-
for (const entry of entries) {
|
|
35
|
-
if (!entry.isDirectory()) continue;
|
|
36
|
-
const metaPath = join(SKILLS_DIR, entry.name, "skill.json");
|
|
37
|
-
if (!existsSync(metaPath)) continue;
|
|
38
|
-
try {
|
|
39
|
-
const meta = JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
40
|
-
skills.push({
|
|
41
|
-
name: meta.name ?? entry.name,
|
|
42
|
-
description: meta.description ?? "",
|
|
43
|
-
version: meta.version ?? "0.0.0",
|
|
44
|
-
author: meta.author ?? "unknown",
|
|
45
|
-
tags: meta.tags ?? [],
|
|
46
|
-
});
|
|
47
|
-
} catch {
|
|
48
|
-
// skip malformed skill.json
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
} catch {
|
|
52
|
-
// directory doesn't exist or can't be read
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return skills;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Install a skill from the built-in registry
|
|
60
|
-
*/
|
|
61
|
-
export function installSkill(name: string): { ok: boolean; message: string } {
|
|
62
|
-
const skill = REGISTRY.find((s) => s.name === name);
|
|
63
|
-
if (!skill) {
|
|
64
|
-
return { ok: false, message: `Skill "${name}" not found in registry` };
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
ensureSkillsDir();
|
|
68
|
-
const skillDir = join(SKILLS_DIR, name);
|
|
69
|
-
|
|
70
|
-
if (existsSync(skillDir)) {
|
|
71
|
-
return { ok: false, message: `Skill "${name}" is already installed` };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
mkdirSync(skillDir, { recursive: true });
|
|
75
|
-
mkdirSync(join(skillDir, "examples"), { recursive: true });
|
|
76
|
-
|
|
77
|
-
// Write skill.json
|
|
78
|
-
const meta: SkillMeta = {
|
|
79
|
-
name: skill.name,
|
|
80
|
-
description: skill.description,
|
|
81
|
-
version: skill.version,
|
|
82
|
-
author: skill.author,
|
|
83
|
-
tags: skill.tags,
|
|
84
|
-
};
|
|
85
|
-
writeFileSync(join(skillDir, "skill.json"), JSON.stringify(meta, null, 2));
|
|
86
|
-
|
|
87
|
-
// Write prompt.md
|
|
88
|
-
writeFileSync(join(skillDir, "prompt.md"), skill.prompt);
|
|
89
|
-
|
|
90
|
-
return { ok: true, message: `Installed skill: ${skill.name}` };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Remove an installed skill
|
|
95
|
-
*/
|
|
96
|
-
export function removeSkill(name: string): { ok: boolean; message: string } {
|
|
97
|
-
const skillDir = join(SKILLS_DIR, name);
|
|
98
|
-
if (!existsSync(skillDir)) {
|
|
99
|
-
return { ok: false, message: `Skill "${name}" is not installed` };
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
rmSync(skillDir, { recursive: true, force: true });
|
|
103
|
-
return { ok: true, message: `Removed skill: ${name}` };
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Get the prompt.md content for an installed skill
|
|
108
|
-
*/
|
|
109
|
-
export function getSkillPrompt(name: string): string | null {
|
|
110
|
-
const promptPath = join(SKILLS_DIR, name, "prompt.md");
|
|
111
|
-
if (!existsSync(promptPath)) return null;
|
|
112
|
-
return readFileSync(promptPath, "utf-8");
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Get examples from a skill's examples/ directory
|
|
117
|
-
*/
|
|
118
|
-
function getSkillExamples(name: string): string[] {
|
|
119
|
-
const examplesDir = join(SKILLS_DIR, name, "examples");
|
|
120
|
-
if (!existsSync(examplesDir)) return [];
|
|
121
|
-
|
|
122
|
-
try {
|
|
123
|
-
return readdirSync(examplesDir)
|
|
124
|
-
.filter((f) => f.endsWith(".md"))
|
|
125
|
-
.map((f) => readFileSync(join(examplesDir, f), "utf-8"));
|
|
126
|
-
} catch {
|
|
127
|
-
return [];
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Get skills that should be active for the given project directory.
|
|
133
|
-
* If .codemaxxing/skills.json exists in the project, only those skills are active.
|
|
134
|
-
* Otherwise, all installed skills are active.
|
|
135
|
-
*/
|
|
136
|
-
export function getActiveSkills(cwd: string, sessionDisabled: Set<string> = new Set()): string[] {
|
|
137
|
-
const installed = listInstalledSkills().map((s) => s.name);
|
|
138
|
-
let active: string[];
|
|
139
|
-
|
|
140
|
-
const projectConfig = join(cwd, ".codemaxxing", "skills.json");
|
|
141
|
-
if (existsSync(projectConfig)) {
|
|
142
|
-
try {
|
|
143
|
-
const config = JSON.parse(readFileSync(projectConfig, "utf-8"));
|
|
144
|
-
const projectSkills: string[] = config.skills ?? [];
|
|
145
|
-
// Only include project skills that are actually installed
|
|
146
|
-
active = projectSkills.filter((s) => installed.includes(s));
|
|
147
|
-
} catch {
|
|
148
|
-
active = installed;
|
|
149
|
-
}
|
|
150
|
-
} else {
|
|
151
|
-
active = installed;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Filter out session-disabled skills
|
|
155
|
-
return active.filter((s) => !sessionDisabled.has(s));
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Build the skill prompt blocks to inject into the system prompt
|
|
160
|
-
*/
|
|
161
|
-
export function buildSkillPrompts(cwd: string, sessionDisabled: Set<string> = new Set()): string {
|
|
162
|
-
const activeSkills = getActiveSkills(cwd, sessionDisabled);
|
|
163
|
-
if (activeSkills.length === 0) return "";
|
|
164
|
-
|
|
165
|
-
const blocks: string[] = [];
|
|
166
|
-
for (const name of activeSkills) {
|
|
167
|
-
const prompt = getSkillPrompt(name);
|
|
168
|
-
if (!prompt) continue;
|
|
169
|
-
|
|
170
|
-
blocks.push(`\n--- Skill: ${name} ---`);
|
|
171
|
-
blocks.push(prompt.trim());
|
|
172
|
-
|
|
173
|
-
// Include examples if any
|
|
174
|
-
const examples = getSkillExamples(name);
|
|
175
|
-
for (const example of examples) {
|
|
176
|
-
blocks.push(`\n### Example:\n${example.trim()}`);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
blocks.push(`--- End Skill ---`);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return blocks.join("\n");
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Create a scaffold for a new custom skill
|
|
187
|
-
*/
|
|
188
|
-
export function createSkillScaffold(name: string): { ok: boolean; message: string; path?: string } {
|
|
189
|
-
ensureSkillsDir();
|
|
190
|
-
const skillDir = join(SKILLS_DIR, name);
|
|
191
|
-
|
|
192
|
-
if (existsSync(skillDir)) {
|
|
193
|
-
return { ok: false, message: `Skill "${name}" already exists` };
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
mkdirSync(skillDir, { recursive: true });
|
|
197
|
-
mkdirSync(join(skillDir, "examples"), { recursive: true });
|
|
198
|
-
|
|
199
|
-
const meta: SkillMeta = {
|
|
200
|
-
name,
|
|
201
|
-
description: "A custom skill",
|
|
202
|
-
version: "1.0.0",
|
|
203
|
-
author: "you",
|
|
204
|
-
tags: [],
|
|
205
|
-
};
|
|
206
|
-
writeFileSync(join(skillDir, "skill.json"), JSON.stringify(meta, null, 2));
|
|
207
|
-
|
|
208
|
-
writeFileSync(
|
|
209
|
-
join(skillDir, "prompt.md"),
|
|
210
|
-
`# ${name}\n\nAdd your skill prompt here. This content will be injected into the system prompt.\n\n## Guidelines\n- Be specific and actionable\n- Include best practices\n- List anti-patterns to avoid\n`,
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
return { ok: true, message: `Created skill scaffold: ${name}`, path: skillDir };
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Search the built-in registry by name, tags, or description
|
|
218
|
-
*/
|
|
219
|
-
export function searchRegistry(query: string): RegistrySkill[] {
|
|
220
|
-
const q = query.toLowerCase();
|
|
221
|
-
return REGISTRY.filter(
|
|
222
|
-
(s) =>
|
|
223
|
-
s.name.toLowerCase().includes(q) ||
|
|
224
|
-
s.description.toLowerCase().includes(q) ||
|
|
225
|
-
s.tags.some((t) => t.toLowerCase().includes(q)),
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Return all skills from the built-in registry
|
|
231
|
-
*/
|
|
232
|
-
export function getRegistrySkills(): RegistrySkill[] {
|
|
233
|
-
return REGISTRY;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Get the count of active skills
|
|
238
|
-
*/
|
|
239
|
-
export function getActiveSkillCount(cwd: string, sessionDisabled: Set<string> = new Set()): number {
|
|
240
|
-
return getActiveSkills(cwd, sessionDisabled).length;
|
|
241
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"outDir": "dist",
|
|
7
|
-
"rootDir": "src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"jsx": "react-jsx"
|
|
14
|
-
},
|
|
15
|
-
"include": ["src/**/*"]
|
|
16
|
-
}
|