clementine-agent 1.1.25 → 1.1.26
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/dist/cli/index.js +183 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2130,6 +2130,189 @@ configCmd
|
|
|
2130
2130
|
console.error(` Failed to open editor: ${editor}`);
|
|
2131
2131
|
}
|
|
2132
2132
|
});
|
|
2133
|
+
// ── Skills commands ─────────────────────────────────────────────────
|
|
2134
|
+
//
|
|
2135
|
+
// Procedural memory the agent extracts from successful runs lives at
|
|
2136
|
+
// vault/00-System/skills/ (global) and agents/<slug>/skills/ (per-agent).
|
|
2137
|
+
// New skills land in pending-approval until the owner OKs them. These
|
|
2138
|
+
// commands give the owner a CLI path that mirrors the dashboard UI.
|
|
2139
|
+
const skillsCmd = program
|
|
2140
|
+
.command('skills')
|
|
2141
|
+
.description('List, inspect, approve, and reject extracted skills');
|
|
2142
|
+
skillsCmd
|
|
2143
|
+
.command('list')
|
|
2144
|
+
.description('List all approved skills (global + per-agent) with use counts')
|
|
2145
|
+
.option('-a, --agent <slug>', 'Filter to a specific agent\'s skills')
|
|
2146
|
+
.option('--json', 'Emit machine-readable JSON')
|
|
2147
|
+
.action(async (opts) => {
|
|
2148
|
+
const BOLD = '\x1b[1m';
|
|
2149
|
+
const DIM = '\x1b[0;90m';
|
|
2150
|
+
const CYAN = '\x1b[0;36m';
|
|
2151
|
+
const RESET = '\x1b[0m';
|
|
2152
|
+
try {
|
|
2153
|
+
process.env.CLEMENTINE_HOME = BASE_DIR;
|
|
2154
|
+
const { listSkills } = await import('../agent/skill-extractor.js');
|
|
2155
|
+
const skills = listSkills(opts.agent);
|
|
2156
|
+
if (opts.json) {
|
|
2157
|
+
console.log(JSON.stringify(skills, null, 2));
|
|
2158
|
+
return;
|
|
2159
|
+
}
|
|
2160
|
+
if (skills.length === 0) {
|
|
2161
|
+
console.log();
|
|
2162
|
+
console.log(` ${DIM}No approved skills yet${opts.agent ? ` for "${opts.agent}"` : ''}.${RESET}`);
|
|
2163
|
+
console.log(` Skills get auto-extracted from successful cron / unleashed runs and queued for approval.`);
|
|
2164
|
+
console.log(` Pending: ${BOLD}clementine skills pending${RESET}`);
|
|
2165
|
+
console.log();
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
console.log();
|
|
2169
|
+
console.log(` ${BOLD}${'NAME'.padEnd(36)}${'AGENT'.padEnd(20)}${'USES'.padEnd(8)}${'UPDATED'}${RESET}`);
|
|
2170
|
+
console.log(` ${DIM}${'─'.repeat(80)}${RESET}`);
|
|
2171
|
+
for (const s of skills) {
|
|
2172
|
+
const agent = s.agentSlug ?? 'global';
|
|
2173
|
+
const updated = s.updatedAt.slice(0, 10);
|
|
2174
|
+
console.log(` ${s.name.slice(0, 34).padEnd(36)}${CYAN}${agent.slice(0, 18).padEnd(20)}${RESET}${String(s.useCount).padEnd(8)}${DIM}${updated}${RESET}`);
|
|
2175
|
+
}
|
|
2176
|
+
console.log();
|
|
2177
|
+
console.log(` ${DIM}Total: ${skills.length} skill${skills.length === 1 ? '' : 's'}.${RESET}`);
|
|
2178
|
+
console.log();
|
|
2179
|
+
}
|
|
2180
|
+
catch (err) {
|
|
2181
|
+
console.error(` Error listing skills: ${err}`);
|
|
2182
|
+
process.exit(1);
|
|
2183
|
+
}
|
|
2184
|
+
});
|
|
2185
|
+
skillsCmd
|
|
2186
|
+
.command('pending')
|
|
2187
|
+
.description('Show skills awaiting your approval')
|
|
2188
|
+
.option('--json', 'Emit machine-readable JSON')
|
|
2189
|
+
.action(async (opts) => {
|
|
2190
|
+
const BOLD = '\x1b[1m';
|
|
2191
|
+
const DIM = '\x1b[0;90m';
|
|
2192
|
+
const YELLOW = '\x1b[1;33m';
|
|
2193
|
+
const RESET = '\x1b[0m';
|
|
2194
|
+
try {
|
|
2195
|
+
process.env.CLEMENTINE_HOME = BASE_DIR;
|
|
2196
|
+
const { listPendingSkills } = await import('../agent/skill-extractor.js');
|
|
2197
|
+
const pending = listPendingSkills();
|
|
2198
|
+
if (opts.json) {
|
|
2199
|
+
console.log(JSON.stringify(pending, null, 2));
|
|
2200
|
+
return;
|
|
2201
|
+
}
|
|
2202
|
+
if (pending.length === 0) {
|
|
2203
|
+
console.log();
|
|
2204
|
+
console.log(` ${DIM}No skills pending approval.${RESET}`);
|
|
2205
|
+
console.log();
|
|
2206
|
+
return;
|
|
2207
|
+
}
|
|
2208
|
+
console.log();
|
|
2209
|
+
console.log(` ${YELLOW}${pending.length} skill${pending.length === 1 ? '' : 's'} pending approval${RESET}`);
|
|
2210
|
+
console.log();
|
|
2211
|
+
for (const s of pending) {
|
|
2212
|
+
const agent = s.agentSlug ? ` [agent: ${s.agentSlug}]` : '';
|
|
2213
|
+
console.log(` ${BOLD}${s.name}${RESET}${DIM}${agent}${RESET}`);
|
|
2214
|
+
console.log(` ${s.title}`);
|
|
2215
|
+
console.log(` ${DIM}${s.description}${RESET}`);
|
|
2216
|
+
console.log(` ${DIM}From ${s.source} • ${s.createdAt.slice(0, 19).replace('T', ' ')}${RESET}`);
|
|
2217
|
+
console.log();
|
|
2218
|
+
}
|
|
2219
|
+
console.log(` Approve: ${BOLD}clementine skills approve <name>${RESET}`);
|
|
2220
|
+
console.log(` Reject: ${BOLD}clementine skills reject <name>${RESET}`);
|
|
2221
|
+
console.log();
|
|
2222
|
+
}
|
|
2223
|
+
catch (err) {
|
|
2224
|
+
console.error(` Error listing pending skills: ${err}`);
|
|
2225
|
+
process.exit(1);
|
|
2226
|
+
}
|
|
2227
|
+
});
|
|
2228
|
+
skillsCmd
|
|
2229
|
+
.command('approve <name>')
|
|
2230
|
+
.description('Approve a pending skill (moves it from pending into the active library)')
|
|
2231
|
+
.action(async (name) => {
|
|
2232
|
+
const GREEN = '\x1b[0;32m';
|
|
2233
|
+
const RED = '\x1b[0;31m';
|
|
2234
|
+
const RESET = '\x1b[0m';
|
|
2235
|
+
try {
|
|
2236
|
+
process.env.CLEMENTINE_HOME = BASE_DIR;
|
|
2237
|
+
const { approvePendingSkill } = await import('../agent/skill-extractor.js');
|
|
2238
|
+
const result = approvePendingSkill(name);
|
|
2239
|
+
if (result.ok) {
|
|
2240
|
+
console.log(` ${GREEN}✓${RESET} ${result.message}`);
|
|
2241
|
+
}
|
|
2242
|
+
else {
|
|
2243
|
+
console.error(` ${RED}✗${RESET} ${result.message}`);
|
|
2244
|
+
process.exit(1);
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
catch (err) {
|
|
2248
|
+
console.error(` Error approving skill: ${err}`);
|
|
2249
|
+
process.exit(1);
|
|
2250
|
+
}
|
|
2251
|
+
});
|
|
2252
|
+
skillsCmd
|
|
2253
|
+
.command('reject <name>')
|
|
2254
|
+
.description('Reject a pending skill (deletes it from the queue)')
|
|
2255
|
+
.action(async (name) => {
|
|
2256
|
+
const GREEN = '\x1b[0;32m';
|
|
2257
|
+
const RED = '\x1b[0;31m';
|
|
2258
|
+
const RESET = '\x1b[0m';
|
|
2259
|
+
try {
|
|
2260
|
+
process.env.CLEMENTINE_HOME = BASE_DIR;
|
|
2261
|
+
const { rejectPendingSkill } = await import('../agent/skill-extractor.js');
|
|
2262
|
+
const result = rejectPendingSkill(name);
|
|
2263
|
+
if (result.ok) {
|
|
2264
|
+
console.log(` ${GREEN}✓${RESET} ${result.message}`);
|
|
2265
|
+
}
|
|
2266
|
+
else {
|
|
2267
|
+
console.error(` ${RED}✗${RESET} ${result.message}`);
|
|
2268
|
+
process.exit(1);
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
catch (err) {
|
|
2272
|
+
console.error(` Error rejecting skill: ${err}`);
|
|
2273
|
+
process.exit(1);
|
|
2274
|
+
}
|
|
2275
|
+
});
|
|
2276
|
+
skillsCmd
|
|
2277
|
+
.command('search <query>')
|
|
2278
|
+
.description('Preview which skills would be injected for a given query — useful for debugging skill matching')
|
|
2279
|
+
.option('-a, --agent <slug>', 'Search as a specific agent (skills get the agent boost)')
|
|
2280
|
+
.option('-n, --limit <n>', 'Max matches to show', '5')
|
|
2281
|
+
.action(async (query, opts) => {
|
|
2282
|
+
const BOLD = '\x1b[1m';
|
|
2283
|
+
const DIM = '\x1b[0;90m';
|
|
2284
|
+
const CYAN = '\x1b[0;36m';
|
|
2285
|
+
const GREEN = '\x1b[0;32m';
|
|
2286
|
+
const RESET = '\x1b[0m';
|
|
2287
|
+
try {
|
|
2288
|
+
process.env.CLEMENTINE_HOME = BASE_DIR;
|
|
2289
|
+
const { searchSkills } = await import('../agent/skill-extractor.js');
|
|
2290
|
+
const limit = parseInt(opts.limit ?? '5', 10);
|
|
2291
|
+
const matches = searchSkills(query, limit, opts.agent);
|
|
2292
|
+
if (matches.length === 0) {
|
|
2293
|
+
console.log();
|
|
2294
|
+
console.log(` ${DIM}No skills matched "${query}"${opts.agent ? ` for agent ${opts.agent}` : ''}.${RESET}`);
|
|
2295
|
+
console.log();
|
|
2296
|
+
return;
|
|
2297
|
+
}
|
|
2298
|
+
console.log();
|
|
2299
|
+
console.log(` ${BOLD}${matches.length} skill${matches.length === 1 ? '' : 's'} matched${RESET} ${DIM}(threshold for injection: score >= 4)${RESET}`);
|
|
2300
|
+
console.log();
|
|
2301
|
+
for (const m of matches) {
|
|
2302
|
+
const inject = m.score >= 4 ? `${GREEN}✓ would inject${RESET}` : `${DIM}below threshold${RESET}`;
|
|
2303
|
+
console.log(` ${BOLD}${m.name}${RESET} ${CYAN}score: ${m.score.toFixed(2)}${RESET} ${inject}`);
|
|
2304
|
+
console.log(` ${m.title}`);
|
|
2305
|
+
if (m.toolsUsed.length > 0) {
|
|
2306
|
+
console.log(` ${DIM}Tools: ${m.toolsUsed.join(', ')}${RESET}`);
|
|
2307
|
+
}
|
|
2308
|
+
console.log();
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
catch (err) {
|
|
2312
|
+
console.error(` Error searching skills: ${err}`);
|
|
2313
|
+
process.exit(1);
|
|
2314
|
+
}
|
|
2315
|
+
});
|
|
2133
2316
|
// ── Brain commands ──────────────────────────────────────────────────
|
|
2134
2317
|
const brainCmd = program
|
|
2135
2318
|
.command('brain')
|