skill-tree 0.1.2 → 0.1.4
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 +188 -140
- package/dist/chunk-7QIQJVNP.mjs +14206 -0
- package/dist/chunk-FKJJ4RJG.mjs +13874 -0
- package/dist/chunk-OYHYXKXO.mjs +7297 -0
- package/dist/chunk-PDPN7FW7.mjs +1045 -0
- package/dist/chunk-Y54UK2J3.mjs +13071 -0
- package/dist/cli/index.js +6257 -10937
- package/dist/cli/index.mjs +388 -107
- package/dist/index.d.mts +2197 -5682
- package/dist/index.d.ts +2197 -5682
- package/dist/index.js +7196 -14794
- package/dist/index.mjs +22 -140
- package/dist/sqlite-OLU72GHB.mjs +6 -0
- package/package.json +2 -3
package/dist/cli/index.mjs
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
CachedStorageAdapter,
|
|
4
4
|
GitSyncAdapter,
|
|
5
5
|
SkillBank,
|
|
6
6
|
SkillGraphServer,
|
|
7
|
-
SkillTreeMcpServer,
|
|
8
7
|
VERSION,
|
|
9
8
|
createDefaultSyncConfig
|
|
10
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-OYHYXKXO.mjs";
|
|
10
|
+
import "../chunk-PDPN7FW7.mjs";
|
|
11
11
|
|
|
12
12
|
// src/cli/index.ts
|
|
13
|
-
import { Command as
|
|
13
|
+
import { Command as Command36 } from "commander";
|
|
14
14
|
|
|
15
15
|
// src/config/types.ts
|
|
16
16
|
var DEFAULT_CONFIG = {
|
|
17
17
|
storage: {
|
|
18
|
-
|
|
19
|
-
path: "~/.skill-tree/skills.db"
|
|
18
|
+
path: "~/.skill-tree"
|
|
20
19
|
},
|
|
21
20
|
indexer: {
|
|
22
21
|
sources: [],
|
|
@@ -46,7 +45,6 @@ import * as os from "os";
|
|
|
46
45
|
var ENV_MAPPINGS = {
|
|
47
46
|
GITHUB_TOKEN: "indexer.github_token",
|
|
48
47
|
ANTHROPIC_API_KEY: "indexer.anthropic_key",
|
|
49
|
-
SKILL_TREE_STORAGE_TYPE: "storage.type",
|
|
50
48
|
SKILL_TREE_STORAGE_PATH: "storage.path",
|
|
51
49
|
SKILL_TREE_OUTPUT_FORMAT: "cli.output_format",
|
|
52
50
|
SKILL_TREE_QUIET: "cli.quiet",
|
|
@@ -92,8 +90,8 @@ function substituteEnvVarsInObject(obj) {
|
|
|
92
90
|
}
|
|
93
91
|
return obj;
|
|
94
92
|
}
|
|
95
|
-
function setNestedProperty(obj,
|
|
96
|
-
const parts =
|
|
93
|
+
function setNestedProperty(obj, path7, value) {
|
|
94
|
+
const parts = path7.split(".");
|
|
97
95
|
let current = obj;
|
|
98
96
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
99
97
|
const part = parts[i];
|
|
@@ -252,8 +250,8 @@ var ConfigLoader = class {
|
|
|
252
250
|
/**
|
|
253
251
|
* Get a specific config value by path
|
|
254
252
|
*/
|
|
255
|
-
get(
|
|
256
|
-
const parts =
|
|
253
|
+
get(path7) {
|
|
254
|
+
const parts = path7.split(".");
|
|
257
255
|
let current = this.getConfig();
|
|
258
256
|
for (const part of parts) {
|
|
259
257
|
if (current === null || typeof current !== "object") {
|
|
@@ -281,8 +279,8 @@ var ConfigLoader = class {
|
|
|
281
279
|
# Generated by skill-tree
|
|
282
280
|
|
|
283
281
|
storage:
|
|
284
|
-
|
|
285
|
-
path: ~/.skill-tree
|
|
282
|
+
# Path to .skilltree directory (skills stored as files, SQLite cache auto-generated)
|
|
283
|
+
path: ~/.skill-tree
|
|
286
284
|
|
|
287
285
|
indexer:
|
|
288
286
|
# GitHub token for API access (or use GITHUB_TOKEN env var)
|
|
@@ -380,7 +378,6 @@ async function createSkillBankFromOptions(options) {
|
|
|
380
378
|
ensureDir(skillPath);
|
|
381
379
|
const skillBank = new SkillBank({
|
|
382
380
|
storage: {
|
|
383
|
-
type: "filesystem",
|
|
384
381
|
basePath: skillPath,
|
|
385
382
|
openSkillsCompatible: true
|
|
386
383
|
}
|
|
@@ -1889,7 +1886,7 @@ var IndexerService = class {
|
|
|
1889
1886
|
if (skill.status !== "indexed" && !options?.force) continue;
|
|
1890
1887
|
try {
|
|
1891
1888
|
const converted = convertIndexerSkill(skill);
|
|
1892
|
-
await this.skillBank.
|
|
1889
|
+
await this.skillBank.saveSkill(converted.skill);
|
|
1893
1890
|
skillsAdded.push(converted.skill.id);
|
|
1894
1891
|
} catch (err) {
|
|
1895
1892
|
indexed.errors.push(`Failed to import ${skill.slug}: ${err.message}`);
|
|
@@ -1934,7 +1931,7 @@ var IndexerService = class {
|
|
|
1934
1931
|
for (const skill of skills) {
|
|
1935
1932
|
try {
|
|
1936
1933
|
const converted = convertIndexerSkill(skill);
|
|
1937
|
-
await this.skillBank.
|
|
1934
|
+
await this.skillBank.saveSkill(converted.skill);
|
|
1938
1935
|
result.imported++;
|
|
1939
1936
|
result.skills.push(converted.skill);
|
|
1940
1937
|
} catch (err) {
|
|
@@ -2972,7 +2969,7 @@ var indexerCommand = new Command20("index").description("Skill indexer - discove
|
|
|
2972
2969
|
import { Command as Command21 } from "commander";
|
|
2973
2970
|
import * as fs7 from "fs";
|
|
2974
2971
|
var configCommand = new Command21("config").description("View and manage configuration");
|
|
2975
|
-
configCommand.command("show").description("Show current configuration").option("--path <path>", "Path to specific config value (e.g., storage.
|
|
2972
|
+
configCommand.command("show").description("Show current configuration").option("--path <path>", "Path to specific config value (e.g., storage.path)").action((options) => {
|
|
2976
2973
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
2977
2974
|
const configPath = globalOpts.config;
|
|
2978
2975
|
const loader = new ConfigLoader(configPath);
|
|
@@ -3061,15 +3058,9 @@ configCommand.command("validate").description("Validate configuration file").act
|
|
|
3061
3058
|
const loader = new ConfigLoader(configPath);
|
|
3062
3059
|
const config2 = loader.load();
|
|
3063
3060
|
const errors = [];
|
|
3064
|
-
if (!config2.storage.type) {
|
|
3065
|
-
errors.push("storage.type is required");
|
|
3066
|
-
}
|
|
3067
3061
|
if (!config2.storage.path) {
|
|
3068
3062
|
errors.push("storage.path is required");
|
|
3069
3063
|
}
|
|
3070
|
-
if (!["sqlite", "filesystem", "memory"].includes(config2.storage.type)) {
|
|
3071
|
-
errors.push(`storage.type must be one of: sqlite, filesystem, memory`);
|
|
3072
|
-
}
|
|
3073
3064
|
if (config2.indexer.min_confidence < 0 || config2.indexer.min_confidence > 1) {
|
|
3074
3065
|
errors.push("indexer.min_confidence must be between 0 and 1");
|
|
3075
3066
|
}
|
|
@@ -3448,105 +3439,395 @@ function resolveCommand() {
|
|
|
3448
3439
|
});
|
|
3449
3440
|
}
|
|
3450
3441
|
|
|
3451
|
-
// src/cli/commands/
|
|
3442
|
+
// src/cli/commands/loadout/index.ts
|
|
3443
|
+
import { Command as Command35 } from "commander";
|
|
3444
|
+
|
|
3445
|
+
// src/cli/commands/loadout/list.ts
|
|
3452
3446
|
import { Command as Command23 } from "commander";
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3447
|
+
|
|
3448
|
+
// src/serving/state-persistence.ts
|
|
3449
|
+
import * as fs9 from "fs";
|
|
3450
|
+
import * as path6 from "path";
|
|
3451
|
+
var STATE_FILENAME = ".loadout-state.json";
|
|
3452
|
+
function loadState(skillPath) {
|
|
3453
|
+
const filePath = path6.join(skillPath, STATE_FILENAME);
|
|
3454
|
+
try {
|
|
3455
|
+
const raw = fs9.readFileSync(filePath, "utf-8");
|
|
3456
|
+
const data = JSON.parse(raw);
|
|
3457
|
+
return {
|
|
3458
|
+
available: new Map(data.available),
|
|
3459
|
+
expanded: new Set(data.expanded),
|
|
3460
|
+
pending: new Set(data.pending),
|
|
3461
|
+
source: data.source,
|
|
3462
|
+
updatedAt: new Date(data.updatedAt)
|
|
3463
|
+
};
|
|
3464
|
+
} catch {
|
|
3465
|
+
return null;
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
function saveState(skillPath, state) {
|
|
3469
|
+
const filePath = path6.join(skillPath, STATE_FILENAME);
|
|
3470
|
+
const data = {
|
|
3471
|
+
available: Array.from(state.available.entries()),
|
|
3472
|
+
expanded: Array.from(state.expanded),
|
|
3473
|
+
pending: Array.from(state.pending),
|
|
3474
|
+
source: state.source,
|
|
3475
|
+
updatedAt: state.updatedAt.toISOString()
|
|
3476
|
+
};
|
|
3477
|
+
fs9.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
3478
|
+
}
|
|
3479
|
+
function clearState(skillPath) {
|
|
3480
|
+
const filePath = path6.join(skillPath, STATE_FILENAME);
|
|
3481
|
+
try {
|
|
3482
|
+
fs9.unlinkSync(filePath);
|
|
3483
|
+
return true;
|
|
3484
|
+
} catch {
|
|
3485
|
+
return false;
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
|
|
3489
|
+
// src/cli/utils/loadout-server.ts
|
|
3490
|
+
async function createLoadoutServer(options) {
|
|
3491
|
+
const skillPath = resolveSkillPath(options.path);
|
|
3457
3492
|
ensureDir(skillPath);
|
|
3458
|
-
const storage = new
|
|
3493
|
+
const storage = new CachedStorageAdapter({ basePath: skillPath });
|
|
3459
3494
|
await storage.initialize();
|
|
3460
|
-
const
|
|
3461
|
-
agentCanModify: true,
|
|
3462
|
-
agentCanSetLoadout: globalOpts.agentCanSetLoadout ?? false,
|
|
3463
|
-
agentCanSwitchProfile: true,
|
|
3464
|
-
requireApproval: false,
|
|
3465
|
-
autoExpandOnUse: true,
|
|
3495
|
+
const server = new SkillGraphServer(storage, {
|
|
3466
3496
|
autoExpandRelated: false,
|
|
3467
|
-
maxExpanded:
|
|
3468
|
-
});
|
|
3469
|
-
await graphServer.initialize();
|
|
3470
|
-
const mcpServer = new SkillTreeMcpServer(graphServer, {
|
|
3471
|
-
dynamicTools: false
|
|
3497
|
+
maxExpanded: 10
|
|
3472
3498
|
});
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3499
|
+
await server.initialize();
|
|
3500
|
+
const persisted = loadState(skillPath);
|
|
3501
|
+
if (persisted) {
|
|
3502
|
+
server.restoreState(persisted);
|
|
3503
|
+
}
|
|
3504
|
+
return {
|
|
3505
|
+
server,
|
|
3506
|
+
skillPath,
|
|
3507
|
+
save: () => saveState(skillPath, server.getState())
|
|
3508
|
+
};
|
|
3509
|
+
}
|
|
3510
|
+
|
|
3511
|
+
// src/cli/commands/loadout/list.ts
|
|
3512
|
+
var listSubcommand = new Command23("list").description("List skills in the current loadout").option("-f, --filter <filter>", "Filter: all, expanded, available, pending", "all").action(async (options, command) => {
|
|
3513
|
+
const globalOpts = command.optsWithGlobals();
|
|
3514
|
+
try {
|
|
3515
|
+
const { server } = await createLoadoutServer(globalOpts);
|
|
3516
|
+
const view = server.agentListLoadout();
|
|
3517
|
+
const filter = options.filter || "all";
|
|
3518
|
+
if (globalOpts.json) {
|
|
3519
|
+
const output = filter === "pending" ? { pending: view.pending } : filter === "expanded" ? { available: view.available.filter((s) => s.expanded), profiles: view.profiles } : filter === "available" ? { available: view.available.filter((s) => !s.expanded), profiles: view.profiles } : view;
|
|
3520
|
+
console.log(JSON.stringify(output, null, 2));
|
|
3482
3521
|
return;
|
|
3483
3522
|
}
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
};
|
|
3494
|
-
break;
|
|
3495
|
-
case "notifications/initialized":
|
|
3496
|
-
return;
|
|
3497
|
-
case "tools/list":
|
|
3498
|
-
result = {
|
|
3499
|
-
tools: mcpServer.getTools().map((t) => ({
|
|
3500
|
-
name: t.name,
|
|
3501
|
-
description: t.description,
|
|
3502
|
-
inputSchema: t.inputSchema
|
|
3503
|
-
}))
|
|
3504
|
-
};
|
|
3505
|
-
break;
|
|
3506
|
-
case "tools/call": {
|
|
3507
|
-
const { name, arguments: args } = params;
|
|
3508
|
-
const toolResult = await mcpServer.executeTool(name, args || {});
|
|
3509
|
-
result = {
|
|
3510
|
-
content: [
|
|
3511
|
-
{
|
|
3512
|
-
type: "text",
|
|
3513
|
-
text: JSON.stringify(toolResult, null, 2)
|
|
3514
|
-
}
|
|
3515
|
-
],
|
|
3516
|
-
isError: !toolResult.success
|
|
3517
|
-
};
|
|
3518
|
-
break;
|
|
3523
|
+
let skills = view.available;
|
|
3524
|
+
if (filter === "expanded") skills = skills.filter((s) => s.expanded);
|
|
3525
|
+
if (filter === "available") skills = skills.filter((s) => !s.expanded);
|
|
3526
|
+
if (filter === "pending") {
|
|
3527
|
+
if (view.pending.length === 0) {
|
|
3528
|
+
printInfo("No pending skill requests");
|
|
3529
|
+
} else {
|
|
3530
|
+
for (const id of view.pending) {
|
|
3531
|
+
console.log(` \u25CB ${id}`);
|
|
3519
3532
|
}
|
|
3520
|
-
case "ping":
|
|
3521
|
-
result = {};
|
|
3522
|
-
break;
|
|
3523
|
-
default:
|
|
3524
|
-
respond(id, null, { code: -32601, message: `Method not found: ${method}` });
|
|
3525
|
-
return;
|
|
3526
3533
|
}
|
|
3527
|
-
|
|
3528
|
-
} catch (err) {
|
|
3529
|
-
respond(id, null, { code: -32603, message: String(err) });
|
|
3534
|
+
return;
|
|
3530
3535
|
}
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3536
|
+
if (skills.length === 0) {
|
|
3537
|
+
printInfo('Loadout is empty. Use "skill-tree loadout add" or "skill-tree loadout profile" to add skills.');
|
|
3538
|
+
return;
|
|
3539
|
+
}
|
|
3540
|
+
for (const skill of skills) {
|
|
3541
|
+
const state = skill.expanded ? "\u25B8" : "\xB7";
|
|
3542
|
+
const tags = skill.tags.length > 0 ? ` [${skill.tags.join(", ")}]` : "";
|
|
3543
|
+
console.log(` ${state} ${skill.id} - ${skill.name}${tags}`);
|
|
3544
|
+
}
|
|
3545
|
+
if (!globalOpts.quiet) {
|
|
3546
|
+
console.log();
|
|
3547
|
+
printInfo(`${skills.length} skill(s) in loadout`);
|
|
3548
|
+
}
|
|
3549
|
+
} catch (error) {
|
|
3550
|
+
printError(error.message);
|
|
3551
|
+
process.exit(1);
|
|
3552
|
+
}
|
|
3553
|
+
});
|
|
3554
|
+
|
|
3555
|
+
// src/cli/commands/loadout/search.ts
|
|
3556
|
+
import { Command as Command24 } from "commander";
|
|
3557
|
+
var searchSubcommand = new Command24("search").description("Search for skills to add to the loadout").argument("<query>", "Search query").option("-l, --limit <n>", "Maximum results", "10").action(async (query, options, command) => {
|
|
3558
|
+
const globalOpts = command.optsWithGlobals();
|
|
3559
|
+
try {
|
|
3560
|
+
const { server } = await createLoadoutServer(globalOpts);
|
|
3561
|
+
const limit = parseInt(options.limit || "10", 10);
|
|
3562
|
+
const results = await server.agentSearchSkills(query, limit);
|
|
3563
|
+
if (globalOpts.json) {
|
|
3564
|
+
console.log(JSON.stringify(results, null, 2));
|
|
3565
|
+
return;
|
|
3566
|
+
}
|
|
3567
|
+
if (results.length === 0) {
|
|
3568
|
+
printInfo(`No skills found matching "${query}"`);
|
|
3569
|
+
return;
|
|
3570
|
+
}
|
|
3571
|
+
for (const skill of results) {
|
|
3572
|
+
const tags = skill.tags.length > 0 ? ` [${skill.tags.join(", ")}]` : "";
|
|
3573
|
+
console.log(` ${skill.id} - ${skill.name}${tags}`);
|
|
3574
|
+
console.log(` ${skill.description}`);
|
|
3575
|
+
}
|
|
3576
|
+
if (!globalOpts.quiet) {
|
|
3577
|
+
console.log();
|
|
3578
|
+
printInfo(`${results.length} result(s)`);
|
|
3579
|
+
}
|
|
3580
|
+
} catch (error) {
|
|
3581
|
+
printError(error.message);
|
|
3582
|
+
process.exit(1);
|
|
3583
|
+
}
|
|
3584
|
+
});
|
|
3585
|
+
|
|
3586
|
+
// src/cli/commands/loadout/add.ts
|
|
3587
|
+
import { Command as Command25 } from "commander";
|
|
3588
|
+
var addSubcommand = new Command25("add").description("Add skills to the loadout").argument("<ids...>", "Skill IDs to add").action(async (ids, _options, command) => {
|
|
3589
|
+
const globalOpts = command.optsWithGlobals();
|
|
3590
|
+
try {
|
|
3591
|
+
const { server, save } = await createLoadoutServer(globalOpts);
|
|
3592
|
+
await server.addSkills(ids);
|
|
3593
|
+
save();
|
|
3594
|
+
if (globalOpts.json) {
|
|
3595
|
+
console.log(JSON.stringify({ added: ids }));
|
|
3596
|
+
return;
|
|
3597
|
+
}
|
|
3598
|
+
printSuccess(`Added ${ids.length} skill(s) to loadout`);
|
|
3599
|
+
} catch (error) {
|
|
3600
|
+
printError(error.message);
|
|
3601
|
+
process.exit(1);
|
|
3602
|
+
}
|
|
3603
|
+
});
|
|
3604
|
+
|
|
3605
|
+
// src/cli/commands/loadout/remove.ts
|
|
3606
|
+
import { Command as Command26 } from "commander";
|
|
3607
|
+
var removeSubcommand = new Command26("remove").description("Remove skills from the loadout").argument("<ids...>", "Skill IDs to remove").action(async (ids, _options, command) => {
|
|
3608
|
+
const globalOpts = command.optsWithGlobals();
|
|
3609
|
+
try {
|
|
3610
|
+
const { server, save } = await createLoadoutServer(globalOpts);
|
|
3611
|
+
server.removeSkills(ids);
|
|
3612
|
+
save();
|
|
3613
|
+
if (globalOpts.json) {
|
|
3614
|
+
console.log(JSON.stringify({ removed: ids }));
|
|
3615
|
+
return;
|
|
3616
|
+
}
|
|
3617
|
+
printSuccess(`Removed ${ids.length} skill(s) from loadout`);
|
|
3618
|
+
} catch (error) {
|
|
3619
|
+
printError(error.message);
|
|
3620
|
+
process.exit(1);
|
|
3621
|
+
}
|
|
3622
|
+
});
|
|
3623
|
+
|
|
3624
|
+
// src/cli/commands/loadout/profile.ts
|
|
3625
|
+
import { Command as Command27 } from "commander";
|
|
3626
|
+
var profileSubcommand = new Command27("profile").description("Switch to a named skill profile").argument("[name]", "Profile name (e.g. debugging, security, code-review)").option("--list", "List available profiles").action(async (name, options, command) => {
|
|
3627
|
+
const globalOpts = command.optsWithGlobals();
|
|
3628
|
+
try {
|
|
3629
|
+
const { server, save } = await createLoadoutServer(globalOpts);
|
|
3630
|
+
if (options.list || !name) {
|
|
3631
|
+
const profiles = server.getProfiles();
|
|
3632
|
+
if (globalOpts.json) {
|
|
3633
|
+
console.log(JSON.stringify({ profiles }));
|
|
3634
|
+
return;
|
|
3635
|
+
}
|
|
3636
|
+
printInfo("Available profiles:");
|
|
3637
|
+
for (const p of profiles) {
|
|
3638
|
+
console.log(` ${p}`);
|
|
3639
|
+
}
|
|
3640
|
+
return;
|
|
3641
|
+
}
|
|
3642
|
+
await server.setLoadoutFromProfile(name);
|
|
3643
|
+
save();
|
|
3644
|
+
if (globalOpts.json) {
|
|
3645
|
+
console.log(JSON.stringify(server.agentListLoadout()));
|
|
3646
|
+
return;
|
|
3647
|
+
}
|
|
3648
|
+
const state = server.getState();
|
|
3649
|
+
printSuccess(`Switched to "${name}" profile (${state.available.size} skills)`);
|
|
3650
|
+
} catch (error) {
|
|
3651
|
+
printError(error.message);
|
|
3652
|
+
process.exit(1);
|
|
3653
|
+
}
|
|
3654
|
+
});
|
|
3655
|
+
|
|
3656
|
+
// src/cli/commands/loadout/set.ts
|
|
3657
|
+
import { Command as Command28 } from "commander";
|
|
3658
|
+
var setSubcommand = new Command28("set").description("Set loadout from criteria (tags, task description, etc.)").option("--tags <tags>", "Comma-separated tags to match").option("--task <description>", "Task description for semantic matching").option("--max-skills <n>", "Maximum number of skills").action(async (options, command) => {
|
|
3659
|
+
const globalOpts = command.optsWithGlobals();
|
|
3660
|
+
try {
|
|
3661
|
+
const { server, save } = await createLoadoutServer(globalOpts);
|
|
3662
|
+
const criteria = {};
|
|
3663
|
+
if (options.tags) {
|
|
3664
|
+
criteria.tags = options.tags.split(",").map((t) => t.trim());
|
|
3665
|
+
}
|
|
3666
|
+
if (options.task) {
|
|
3667
|
+
criteria.taskDescription = options.task;
|
|
3668
|
+
}
|
|
3669
|
+
if (options.maxSkills) {
|
|
3670
|
+
criteria.maxSkills = parseInt(options.maxSkills, 10);
|
|
3671
|
+
}
|
|
3672
|
+
await server.setLoadout(criteria);
|
|
3673
|
+
save();
|
|
3674
|
+
const state = server.getState();
|
|
3675
|
+
if (globalOpts.json) {
|
|
3676
|
+
console.log(JSON.stringify(server.agentListLoadout()));
|
|
3677
|
+
return;
|
|
3678
|
+
}
|
|
3679
|
+
printSuccess(`Loadout set (${state.available.size} skills)`);
|
|
3680
|
+
} catch (error) {
|
|
3681
|
+
printError(error.message);
|
|
3682
|
+
process.exit(1);
|
|
3683
|
+
}
|
|
3684
|
+
});
|
|
3685
|
+
|
|
3686
|
+
// src/cli/commands/loadout/expand.ts
|
|
3687
|
+
import { Command as Command29 } from "commander";
|
|
3688
|
+
var expandSubcommand = new Command29("expand").description("Expand a skill to see its full content").argument("<id>", "Skill ID to expand").action(async (id, _options, command) => {
|
|
3689
|
+
const globalOpts = command.optsWithGlobals();
|
|
3690
|
+
try {
|
|
3691
|
+
const { server, save } = await createLoadoutServer(globalOpts);
|
|
3692
|
+
const expanded = server.expandSkill(id);
|
|
3693
|
+
if (!expanded) {
|
|
3694
|
+
printError(`Skill "${id}" not found in loadout`);
|
|
3695
|
+
process.exit(1);
|
|
3696
|
+
}
|
|
3697
|
+
save();
|
|
3698
|
+
const skill = server.getState().available.get(id);
|
|
3699
|
+
if (globalOpts.json) {
|
|
3700
|
+
console.log(JSON.stringify(skill, null, 2));
|
|
3701
|
+
return;
|
|
3702
|
+
}
|
|
3703
|
+
printSuccess(`Expanded "${id}"`);
|
|
3704
|
+
console.log();
|
|
3705
|
+
console.log(formatSkillDetail(skill));
|
|
3706
|
+
} catch (error) {
|
|
3707
|
+
printError(error.message);
|
|
3708
|
+
process.exit(1);
|
|
3709
|
+
}
|
|
3710
|
+
});
|
|
3711
|
+
|
|
3712
|
+
// src/cli/commands/loadout/collapse.ts
|
|
3713
|
+
import { Command as Command30 } from "commander";
|
|
3714
|
+
var collapseSubcommand = new Command30("collapse").description("Collapse an expanded skill back to summary").argument("<id>", "Skill ID to collapse").action(async (id, _options, command) => {
|
|
3715
|
+
const globalOpts = command.optsWithGlobals();
|
|
3716
|
+
try {
|
|
3717
|
+
const { server, save } = await createLoadoutServer(globalOpts);
|
|
3718
|
+
const collapsed = server.collapseSkill(id);
|
|
3719
|
+
if (!collapsed) {
|
|
3720
|
+
printError(`Skill "${id}" is not expanded`);
|
|
3721
|
+
process.exit(1);
|
|
3722
|
+
}
|
|
3723
|
+
save();
|
|
3724
|
+
if (globalOpts.json) {
|
|
3725
|
+
console.log(JSON.stringify({ collapsed: true }));
|
|
3726
|
+
return;
|
|
3727
|
+
}
|
|
3728
|
+
printSuccess(`Collapsed "${id}"`);
|
|
3729
|
+
} catch (error) {
|
|
3730
|
+
printError(error.message);
|
|
3731
|
+
process.exit(1);
|
|
3732
|
+
}
|
|
3733
|
+
});
|
|
3734
|
+
|
|
3735
|
+
// src/cli/commands/loadout/use.ts
|
|
3736
|
+
import { Command as Command31 } from "commander";
|
|
3737
|
+
var useSubcommand = new Command31("use").description("Mark a skill as being used (auto-expands and records usage)").argument("<id>", "Skill ID to use").action(async (id, _options, command) => {
|
|
3738
|
+
const globalOpts = command.optsWithGlobals();
|
|
3739
|
+
try {
|
|
3740
|
+
const { server, save } = await createLoadoutServer(globalOpts);
|
|
3741
|
+
server.recordUsage(id);
|
|
3742
|
+
const expanded = server.expandSkill(id);
|
|
3743
|
+
if (!expanded) {
|
|
3744
|
+
printError(`Skill "${id}" not found in loadout`);
|
|
3745
|
+
process.exit(1);
|
|
3746
|
+
}
|
|
3747
|
+
save();
|
|
3748
|
+
const skill = server.getState().available.get(id);
|
|
3749
|
+
if (globalOpts.json) {
|
|
3750
|
+
console.log(JSON.stringify(skill, null, 2));
|
|
3751
|
+
return;
|
|
3752
|
+
}
|
|
3753
|
+
printSuccess(`Using "${id}"`);
|
|
3754
|
+
console.log();
|
|
3755
|
+
console.log(formatSkillDetail(skill));
|
|
3756
|
+
} catch (error) {
|
|
3757
|
+
printError(error.message);
|
|
3758
|
+
process.exit(1);
|
|
3759
|
+
}
|
|
3760
|
+
});
|
|
3761
|
+
|
|
3762
|
+
// src/cli/commands/loadout/get.ts
|
|
3763
|
+
import { Command as Command32 } from "commander";
|
|
3764
|
+
var getSubcommand = new Command32("get").description("Get details about a skill in the loadout").argument("<id>", "Skill ID").action(async (id, _options, command) => {
|
|
3765
|
+
const globalOpts = command.optsWithGlobals();
|
|
3766
|
+
try {
|
|
3767
|
+
const { server } = await createLoadoutServer(globalOpts);
|
|
3768
|
+
const state = server.getState();
|
|
3769
|
+
const skill = state.available.get(id);
|
|
3770
|
+
if (!skill) {
|
|
3771
|
+
printError(`Skill "${id}" not found in loadout`);
|
|
3772
|
+
process.exit(1);
|
|
3773
|
+
}
|
|
3774
|
+
if (globalOpts.json) {
|
|
3775
|
+
console.log(JSON.stringify(skill, null, 2));
|
|
3776
|
+
return;
|
|
3777
|
+
}
|
|
3778
|
+
console.log(formatSkillDetail(skill));
|
|
3779
|
+
} catch (error) {
|
|
3780
|
+
printError(error.message);
|
|
3781
|
+
process.exit(1);
|
|
3782
|
+
}
|
|
3783
|
+
});
|
|
3784
|
+
|
|
3785
|
+
// src/cli/commands/loadout/render.ts
|
|
3786
|
+
import { Command as Command33 } from "commander";
|
|
3787
|
+
var renderSubcommand = new Command33("render").description("Render the current loadout as a system prompt (XML or Markdown)").option("--format <format>", "Output format: xml or markdown", "xml").action(async (options, command) => {
|
|
3788
|
+
const globalOpts = command.optsWithGlobals();
|
|
3789
|
+
try {
|
|
3790
|
+
const { server } = await createLoadoutServer(globalOpts);
|
|
3791
|
+
const state = server.getState();
|
|
3792
|
+
if (state.available.size === 0) {
|
|
3793
|
+
printInfo("Loadout is empty. Nothing to render.");
|
|
3794
|
+
return;
|
|
3795
|
+
}
|
|
3796
|
+
const output = server.renderSystemPrompt();
|
|
3797
|
+
console.log(output);
|
|
3798
|
+
} catch (error) {
|
|
3799
|
+
printError(error.message);
|
|
3800
|
+
process.exit(1);
|
|
3801
|
+
}
|
|
3802
|
+
});
|
|
3803
|
+
|
|
3804
|
+
// src/cli/commands/loadout/clear.ts
|
|
3805
|
+
import { Command as Command34 } from "commander";
|
|
3806
|
+
var clearSubcommand = new Command34("clear").description("Clear the current loadout state").action(async (_options, command) => {
|
|
3807
|
+
const globalOpts = command.optsWithGlobals();
|
|
3808
|
+
try {
|
|
3809
|
+
const skillPath = resolveSkillPath(globalOpts.path);
|
|
3810
|
+
const cleared = clearState(skillPath);
|
|
3811
|
+
if (globalOpts.json) {
|
|
3812
|
+
console.log(JSON.stringify({ cleared }));
|
|
3813
|
+
return;
|
|
3814
|
+
}
|
|
3815
|
+
if (cleared) {
|
|
3816
|
+
printSuccess("Loadout state cleared");
|
|
3537
3817
|
} else {
|
|
3538
|
-
|
|
3818
|
+
printInfo("No loadout state to clear");
|
|
3539
3819
|
}
|
|
3540
|
-
|
|
3820
|
+
} catch (error) {
|
|
3821
|
+
printError(error.message);
|
|
3822
|
+
process.exit(1);
|
|
3541
3823
|
}
|
|
3542
|
-
process.on("SIGTERM", () => {
|
|
3543
|
-
mcpServer.dispose();
|
|
3544
|
-
process.exit(0);
|
|
3545
|
-
});
|
|
3546
3824
|
});
|
|
3547
3825
|
|
|
3826
|
+
// src/cli/commands/loadout/index.ts
|
|
3827
|
+
var loadoutCommand = new Command35("loadout").description("Manage skill loadouts for agent sessions").addCommand(listSubcommand).addCommand(searchSubcommand).addCommand(addSubcommand).addCommand(removeSubcommand).addCommand(profileSubcommand).addCommand(setSubcommand).addCommand(expandSubcommand).addCommand(collapseSubcommand).addCommand(useSubcommand).addCommand(getSubcommand).addCommand(renderSubcommand).addCommand(clearSubcommand);
|
|
3828
|
+
|
|
3548
3829
|
// src/cli/index.ts
|
|
3549
|
-
var program = new
|
|
3830
|
+
var program = new Command36();
|
|
3550
3831
|
var config = loadConfig();
|
|
3551
3832
|
program.name("skill-tree").description("Management CLI for agent skills").version(VERSION).option("-p, --path <dir>", "Skills directory path", config.storage.path).option("-c, --config <file>", "Config file path", getConfigPath()).option("--json", "Output as JSON", config.cli.output_format === "json").option("-q, --quiet", "Suppress non-essential output", config.cli.quiet).option("--no-color", "Disable colored output", !config.cli.color);
|
|
3552
3833
|
program.addCommand(listCommand);
|
|
@@ -3565,5 +3846,5 @@ program.addCommand(importCommand);
|
|
|
3565
3846
|
program.addCommand(indexerCommand);
|
|
3566
3847
|
program.addCommand(configCommand);
|
|
3567
3848
|
program.addCommand(syncCommand2);
|
|
3568
|
-
program.addCommand(
|
|
3849
|
+
program.addCommand(loadoutCommand);
|
|
3569
3850
|
program.parse();
|