@fro.bot/systematic 3.8.0 → 3.9.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/dist/cli.js +1 -1
- package/dist/{index-hjbt4p5s.js → index-y8nc60tz.js} +297 -299
- package/dist/index.js +121 -149
- package/dist/lib/skill-catalog.d.ts +0 -13
- package/dist/lib/skill-tool.d.ts +0 -6
- package/dist/pi.js +173 -202
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -14,125 +14,18 @@ import {
|
|
|
14
14
|
loadConfig,
|
|
15
15
|
loadConfigWithSources,
|
|
16
16
|
parseFrontmatter
|
|
17
|
-
} from "./index-
|
|
17
|
+
} from "./index-y8nc60tz.js";
|
|
18
18
|
|
|
19
19
|
// src/index.ts
|
|
20
20
|
import { createHash as createHash5 } from "crypto";
|
|
21
21
|
import fs11 from "fs";
|
|
22
22
|
import path10 from "path";
|
|
23
|
-
import { fileURLToPath as fileURLToPath3, pathToFileURL as
|
|
23
|
+
import { fileURLToPath as fileURLToPath3, pathToFileURL as pathToFileURL2 } from "url";
|
|
24
24
|
|
|
25
25
|
// src/lib/bootstrap.ts
|
|
26
|
-
import fs3 from "fs";
|
|
27
|
-
import os from "os";
|
|
28
|
-
import path2 from "path";
|
|
29
|
-
|
|
30
|
-
// src/lib/skill-catalog.ts
|
|
31
|
-
import { pathToFileURL } from "url";
|
|
32
|
-
|
|
33
|
-
// src/lib/skill-loader.ts
|
|
34
26
|
import fs2 from "fs";
|
|
27
|
+
import os from "os";
|
|
35
28
|
import path from "path";
|
|
36
|
-
var SKILL_PREFIX = "systematic:";
|
|
37
|
-
var SKILL_DESCRIPTION_PREFIX = "(Systematic) ";
|
|
38
|
-
function formatSkillCommandName(name2) {
|
|
39
|
-
if (name2.includes(":")) {
|
|
40
|
-
return name2;
|
|
41
|
-
}
|
|
42
|
-
return `${SKILL_PREFIX}${name2}`;
|
|
43
|
-
}
|
|
44
|
-
function formatSkillDescription(description, fallbackName) {
|
|
45
|
-
const desc = description || `${fallbackName} skill`;
|
|
46
|
-
if (desc.startsWith(SKILL_DESCRIPTION_PREFIX)) {
|
|
47
|
-
return desc;
|
|
48
|
-
}
|
|
49
|
-
return `${SKILL_DESCRIPTION_PREFIX}${desc}`;
|
|
50
|
-
}
|
|
51
|
-
function wrapSkillTemplate(skillPath, body2) {
|
|
52
|
-
const skillDir = path.dirname(skillPath);
|
|
53
|
-
return `<skill-instruction>
|
|
54
|
-
Base directory for this skill: ${skillDir}/
|
|
55
|
-
File references (@path) in this skill are relative to this directory.
|
|
56
|
-
|
|
57
|
-
${body2.trim()}
|
|
58
|
-
</skill-instruction>
|
|
59
|
-
|
|
60
|
-
<user-request>
|
|
61
|
-
$ARGUMENTS
|
|
62
|
-
</user-request>`;
|
|
63
|
-
}
|
|
64
|
-
function extractSkillBody(wrappedTemplate) {
|
|
65
|
-
const match = wrappedTemplate.match(/<skill-instruction>([\s\S]*?)<\/skill-instruction>/);
|
|
66
|
-
return match ? match[1].trim() : wrappedTemplate;
|
|
67
|
-
}
|
|
68
|
-
function loadSkill(skillInfo) {
|
|
69
|
-
try {
|
|
70
|
-
const content = fs2.readFileSync(skillInfo.skillFile, "utf8");
|
|
71
|
-
const { body: body2 } = parseFrontmatter(content);
|
|
72
|
-
const wrappedTemplate = wrapSkillTemplate(skillInfo.skillFile, body2);
|
|
73
|
-
return {
|
|
74
|
-
name: skillInfo.name,
|
|
75
|
-
prefixedName: formatSkillCommandName(skillInfo.name),
|
|
76
|
-
description: formatSkillDescription(skillInfo.description, skillInfo.name),
|
|
77
|
-
path: skillInfo.path,
|
|
78
|
-
skillFile: skillInfo.skillFile,
|
|
79
|
-
wrappedTemplate,
|
|
80
|
-
disableModelInvocation: skillInfo.disableModelInvocation,
|
|
81
|
-
userInvocable: skillInfo.userInvocable,
|
|
82
|
-
subtask: skillInfo.subtask,
|
|
83
|
-
agent: skillInfo.agent,
|
|
84
|
-
model: skillInfo.model,
|
|
85
|
-
argumentHint: skillInfo.argumentHint
|
|
86
|
-
};
|
|
87
|
-
} catch {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// src/lib/skill-catalog.ts
|
|
93
|
-
function escapeXml(text) {
|
|
94
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
95
|
-
}
|
|
96
|
-
function buildCatalogEntries(options) {
|
|
97
|
-
const { bundledSkillsDir, disabledSkills } = options;
|
|
98
|
-
return findSkillsInDir(bundledSkillsDir).filter((s) => !disabledSkills.includes(s.name)).filter((s) => s.disableModelInvocation !== true).sort((a, b) => a.name.localeCompare(b.name)).map((s) => ({
|
|
99
|
-
name: s.name,
|
|
100
|
-
prefixedName: formatSkillCommandName(s.name),
|
|
101
|
-
description: s.description,
|
|
102
|
-
path: s.path,
|
|
103
|
-
skillFile: s.skillFile
|
|
104
|
-
}));
|
|
105
|
-
}
|
|
106
|
-
function renderCatalogVerbose(options) {
|
|
107
|
-
const entries = buildCatalogEntries(options);
|
|
108
|
-
if (entries.length === 0)
|
|
109
|
-
return "";
|
|
110
|
-
const skillLines = entries.flatMap((entry) => [
|
|
111
|
-
" <skill>",
|
|
112
|
-
` <name>${escapeXml(entry.prefixedName)}</name>`,
|
|
113
|
-
` <description>${escapeXml(entry.description)}</description>`,
|
|
114
|
-
` <location>${pathToFileURL(entry.path).href}</location>`,
|
|
115
|
-
" </skill>"
|
|
116
|
-
]);
|
|
117
|
-
return ["<available_skills>", ...skillLines, "</available_skills>"].join(`
|
|
118
|
-
`);
|
|
119
|
-
}
|
|
120
|
-
function renderCatalogCompact(options) {
|
|
121
|
-
const entries = buildCatalogEntries(options);
|
|
122
|
-
const heading = "## Available Systematic Skills";
|
|
123
|
-
if (entries.length === 0) {
|
|
124
|
-
return `${heading}
|
|
125
|
-
|
|
126
|
-
No Systematic skills are currently available.`;
|
|
127
|
-
}
|
|
128
|
-
const bullets = entries.map((entry) => `- ${entry.prefixedName}: ${entry.description}`).join(`
|
|
129
|
-
`);
|
|
130
|
-
return `${heading}
|
|
131
|
-
|
|
132
|
-
${bullets}`;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// src/lib/bootstrap.ts
|
|
136
29
|
var INTERNAL_AGENT_SIGNATURES = [
|
|
137
30
|
"You are a title generator",
|
|
138
31
|
"You are a helpful AI assistant tasked with summarizing conversations",
|
|
@@ -190,9 +83,9 @@ var applyBootstrapContent = (output, content) => {
|
|
|
190
83
|
${content}` : content;
|
|
191
84
|
};
|
|
192
85
|
function readHarnessProfile(bundledSkillsDir, name2) {
|
|
193
|
-
const profilePath =
|
|
86
|
+
const profilePath = path.join(bundledSkillsDir, "using-systematic/references", `${name2}-profile.md`);
|
|
194
87
|
try {
|
|
195
|
-
return
|
|
88
|
+
return fs2.readFileSync(profilePath, "utf8");
|
|
196
89
|
} catch (error) {
|
|
197
90
|
console.error(`Failed to read harness profile ${profilePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
198
91
|
return null;
|
|
@@ -216,25 +109,18 @@ function getBootstrapContent(config, deps) {
|
|
|
216
109
|
if (!config.bootstrap.enabled)
|
|
217
110
|
return null;
|
|
218
111
|
if (config.bootstrap.file) {
|
|
219
|
-
const customPath = config.bootstrap.file.startsWith("~/") ?
|
|
220
|
-
if (
|
|
221
|
-
return
|
|
112
|
+
const customPath = config.bootstrap.file.startsWith("~/") ? path.join(os.homedir(), config.bootstrap.file.slice(2)) : config.bootstrap.file;
|
|
113
|
+
if (fs2.existsSync(customPath)) {
|
|
114
|
+
return fs2.readFileSync(customPath, "utf8");
|
|
222
115
|
}
|
|
223
116
|
}
|
|
224
|
-
const usingSystematicPath =
|
|
225
|
-
if (!
|
|
117
|
+
const usingSystematicPath = path.join(bundledSkillsDir, "using-systematic/SKILL.md");
|
|
118
|
+
if (!fs2.existsSync(usingSystematicPath))
|
|
226
119
|
return null;
|
|
227
|
-
const fullContent =
|
|
120
|
+
const fullContent = fs2.readFileSync(usingSystematicPath, "utf8");
|
|
228
121
|
const { body: body2 } = parseFrontmatter(fullContent);
|
|
229
122
|
const content = body2.trim();
|
|
230
123
|
const skillUsage = usageTemplate ?? getSkillUsageTemplate();
|
|
231
|
-
const catalog = renderCatalogVerbose({
|
|
232
|
-
bundledSkillsDir,
|
|
233
|
-
disabledSkills: config.disabled_skills
|
|
234
|
-
});
|
|
235
|
-
const catalogSection = catalog.length > 0 ? `
|
|
236
|
-
|
|
237
|
-
${catalog}` : "";
|
|
238
124
|
const profileSection = profileBlock === undefined ? "" : `
|
|
239
125
|
|
|
240
126
|
${profileBlock}`;
|
|
@@ -245,7 +131,7 @@ You have access to structured engineering workflows via the Systematic plugin.
|
|
|
245
131
|
|
|
246
132
|
${content}
|
|
247
133
|
|
|
248
|
-
${skillUsage}${profileSection}
|
|
134
|
+
${skillUsage}${profileSection}
|
|
249
135
|
</SYSTEMATIC_WORKFLOWS>`;
|
|
250
136
|
}
|
|
251
137
|
|
|
@@ -255,16 +141,16 @@ import os3 from "os";
|
|
|
255
141
|
import path6 from "path";
|
|
256
142
|
|
|
257
143
|
// src/lib/agent-overlays.ts
|
|
258
|
-
import
|
|
259
|
-
import
|
|
144
|
+
import fs3 from "fs";
|
|
145
|
+
import path3 from "path";
|
|
260
146
|
|
|
261
147
|
// src/lib/source-model-defaults.ts
|
|
262
|
-
import * as
|
|
148
|
+
import * as path2 from "path";
|
|
263
149
|
import { fileURLToPath } from "url";
|
|
264
150
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
265
|
-
var __dirname2 =
|
|
266
|
-
var packageRoot =
|
|
267
|
-
var bundledAgentsDir =
|
|
151
|
+
var __dirname2 = path2.dirname(__filename2);
|
|
152
|
+
var packageRoot = path2.resolve(__dirname2, "..", "..");
|
|
153
|
+
var bundledAgentsDir = path2.join(packageRoot, "agents");
|
|
268
154
|
var ProviderID = exports_external.union([
|
|
269
155
|
exports_external.literal("vercel"),
|
|
270
156
|
exports_external.literal("opencode"),
|
|
@@ -453,14 +339,14 @@ function buildBundledAgentInventory(agentsDir, disabledAgents) {
|
|
|
453
339
|
const stemCategories = new Map;
|
|
454
340
|
const disabledSet = new Set(disabledAgents);
|
|
455
341
|
for (const category of categories) {
|
|
456
|
-
for (const fileName of readMarkdownFiles(
|
|
342
|
+
for (const fileName of readMarkdownFiles(path3.join(agentsDir, category))) {
|
|
457
343
|
const key = fileName.replace(/\.md$/, "");
|
|
458
344
|
const id = `${category}/${key}`;
|
|
459
345
|
agentsByQualifiedId[id] = {
|
|
460
346
|
id,
|
|
461
347
|
key,
|
|
462
348
|
category,
|
|
463
|
-
file:
|
|
349
|
+
file: path3.join(agentsDir, category, fileName),
|
|
464
350
|
disabled: disabledSet.has(key) || disabledSet.has(id)
|
|
465
351
|
};
|
|
466
352
|
const existing = stemCategories.get(key) ?? [];
|
|
@@ -585,14 +471,14 @@ function validateOverlaySkills(overlay, skills, enabledSkills) {
|
|
|
585
471
|
}
|
|
586
472
|
function readCategoryDirs(agentsDir) {
|
|
587
473
|
try {
|
|
588
|
-
return
|
|
474
|
+
return fs3.readdirSync(agentsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
589
475
|
} catch {
|
|
590
476
|
return [];
|
|
591
477
|
}
|
|
592
478
|
}
|
|
593
479
|
function readMarkdownFiles(categoryDir) {
|
|
594
480
|
try {
|
|
595
|
-
return
|
|
481
|
+
return fs3.readdirSync(categoryDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => entry.name).sort();
|
|
596
482
|
} catch {
|
|
597
483
|
return [];
|
|
598
484
|
}
|
|
@@ -606,9 +492,9 @@ function throwConfigError(sourcePath, keyPath, message) {
|
|
|
606
492
|
|
|
607
493
|
// src/lib/model-availability.ts
|
|
608
494
|
import { createHash } from "crypto";
|
|
609
|
-
import
|
|
495
|
+
import fs4 from "fs";
|
|
610
496
|
import os2 from "os";
|
|
611
|
-
import
|
|
497
|
+
import path4 from "path";
|
|
612
498
|
function emptyAvailability() {
|
|
613
499
|
return { status: "unknown", models: new Set };
|
|
614
500
|
}
|
|
@@ -618,8 +504,8 @@ var MODELS_JSON_FILENAME = "models.json";
|
|
|
618
504
|
var availabilityCache = new WeakMap;
|
|
619
505
|
function resolveCacheDir() {
|
|
620
506
|
const xdgCacheHome = process.env.XDG_CACHE_HOME?.trim();
|
|
621
|
-
const cacheBase = xdgCacheHome &&
|
|
622
|
-
return
|
|
507
|
+
const cacheBase = xdgCacheHome && path4.isAbsolute(xdgCacheHome) ? xdgCacheHome : path4.join(os2.homedir(), ".cache");
|
|
508
|
+
return path4.join(cacheBase, "opencode");
|
|
623
509
|
}
|
|
624
510
|
function fastHash(input) {
|
|
625
511
|
return createHash("sha1").update(input).digest("hex");
|
|
@@ -638,7 +524,7 @@ function isProviderRecord(value) {
|
|
|
638
524
|
function readModelsFromCache(filePath) {
|
|
639
525
|
let fd;
|
|
640
526
|
try {
|
|
641
|
-
fd =
|
|
527
|
+
fd = fs4.openSync(filePath, "r");
|
|
642
528
|
} catch {
|
|
643
529
|
return null;
|
|
644
530
|
}
|
|
@@ -646,7 +532,7 @@ function readModelsFromCache(filePath) {
|
|
|
646
532
|
try {
|
|
647
533
|
let stat;
|
|
648
534
|
try {
|
|
649
|
-
stat =
|
|
535
|
+
stat = fs4.fstatSync(fd);
|
|
650
536
|
} catch {
|
|
651
537
|
return null;
|
|
652
538
|
}
|
|
@@ -661,7 +547,7 @@ function readModelsFromCache(filePath) {
|
|
|
661
547
|
const buffer = Buffer.alloc(stat.size);
|
|
662
548
|
let bytesRead;
|
|
663
549
|
try {
|
|
664
|
-
bytesRead =
|
|
550
|
+
bytesRead = fs4.readSync(fd, buffer, 0, stat.size, 0);
|
|
665
551
|
} catch {
|
|
666
552
|
return null;
|
|
667
553
|
}
|
|
@@ -670,7 +556,7 @@ function readModelsFromCache(filePath) {
|
|
|
670
556
|
raw = buffer.toString("utf8");
|
|
671
557
|
} finally {
|
|
672
558
|
try {
|
|
673
|
-
|
|
559
|
+
fs4.closeSync(fd);
|
|
674
560
|
} catch {}
|
|
675
561
|
}
|
|
676
562
|
if (raw.trim().length === 0)
|
|
@@ -697,14 +583,14 @@ function readFallbackCache() {
|
|
|
697
583
|
const cacheDir = resolveCacheDir();
|
|
698
584
|
const openCodeModelsUrl = process.env.OPENCODE_MODELS_URL?.trim();
|
|
699
585
|
if (openCodeModelsUrl) {
|
|
700
|
-
const urlDerivedPath =
|
|
586
|
+
const urlDerivedPath = path4.join(cacheDir, `models-${fastHash(openCodeModelsUrl)}.json`);
|
|
701
587
|
const urlResult = readModelsFromCache(urlDerivedPath);
|
|
702
588
|
if (urlResult !== null && urlResult.size > 0) {
|
|
703
589
|
return { status: "cache", models: urlResult };
|
|
704
590
|
}
|
|
705
591
|
return emptyAvailability();
|
|
706
592
|
}
|
|
707
|
-
const defaultPath =
|
|
593
|
+
const defaultPath = path4.join(cacheDir, MODELS_JSON_FILENAME);
|
|
708
594
|
const defaultResult = readModelsFromCache(defaultPath);
|
|
709
595
|
if (defaultResult !== null && defaultResult.size > 0) {
|
|
710
596
|
return { status: "cache", models: defaultResult };
|
|
@@ -769,6 +655,65 @@ async function getAvailableModels(client, options = {}) {
|
|
|
769
655
|
});
|
|
770
656
|
}
|
|
771
657
|
|
|
658
|
+
// src/lib/skill-loader.ts
|
|
659
|
+
import fs5 from "fs";
|
|
660
|
+
import path5 from "path";
|
|
661
|
+
var SKILL_PREFIX = "systematic:";
|
|
662
|
+
var SKILL_DESCRIPTION_PREFIX = "(Systematic) ";
|
|
663
|
+
function formatSkillCommandName(name2) {
|
|
664
|
+
if (name2.includes(":")) {
|
|
665
|
+
return name2;
|
|
666
|
+
}
|
|
667
|
+
return `${SKILL_PREFIX}${name2}`;
|
|
668
|
+
}
|
|
669
|
+
function formatSkillDescription(description, fallbackName) {
|
|
670
|
+
const desc = description || `${fallbackName} skill`;
|
|
671
|
+
if (desc.startsWith(SKILL_DESCRIPTION_PREFIX)) {
|
|
672
|
+
return desc;
|
|
673
|
+
}
|
|
674
|
+
return `${SKILL_DESCRIPTION_PREFIX}${desc}`;
|
|
675
|
+
}
|
|
676
|
+
function wrapSkillTemplate(skillPath, body2) {
|
|
677
|
+
const skillDir = path5.dirname(skillPath);
|
|
678
|
+
return `<skill-instruction>
|
|
679
|
+
Base directory for this skill: ${skillDir}/
|
|
680
|
+
File references (@path) in this skill are relative to this directory.
|
|
681
|
+
|
|
682
|
+
${body2.trim()}
|
|
683
|
+
</skill-instruction>
|
|
684
|
+
|
|
685
|
+
<user-request>
|
|
686
|
+
$ARGUMENTS
|
|
687
|
+
</user-request>`;
|
|
688
|
+
}
|
|
689
|
+
function extractSkillBody(wrappedTemplate) {
|
|
690
|
+
const match = wrappedTemplate.match(/<skill-instruction>([\s\S]*?)<\/skill-instruction>/);
|
|
691
|
+
return match ? match[1].trim() : wrappedTemplate;
|
|
692
|
+
}
|
|
693
|
+
function loadSkill(skillInfo) {
|
|
694
|
+
try {
|
|
695
|
+
const content = fs5.readFileSync(skillInfo.skillFile, "utf8");
|
|
696
|
+
const { body: body2 } = parseFrontmatter(content);
|
|
697
|
+
const wrappedTemplate = wrapSkillTemplate(skillInfo.skillFile, body2);
|
|
698
|
+
return {
|
|
699
|
+
name: skillInfo.name,
|
|
700
|
+
prefixedName: formatSkillCommandName(skillInfo.name),
|
|
701
|
+
description: formatSkillDescription(skillInfo.description, skillInfo.name),
|
|
702
|
+
path: skillInfo.path,
|
|
703
|
+
skillFile: skillInfo.skillFile,
|
|
704
|
+
wrappedTemplate,
|
|
705
|
+
disableModelInvocation: skillInfo.disableModelInvocation,
|
|
706
|
+
userInvocable: skillInfo.userInvocable,
|
|
707
|
+
subtask: skillInfo.subtask,
|
|
708
|
+
agent: skillInfo.agent,
|
|
709
|
+
model: skillInfo.model,
|
|
710
|
+
argumentHint: skillInfo.argumentHint
|
|
711
|
+
};
|
|
712
|
+
} catch {
|
|
713
|
+
return null;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
772
717
|
// src/lib/config-handler.ts
|
|
773
718
|
function isSystematicAgentConfig(agent) {
|
|
774
719
|
const description = agent?.description;
|
|
@@ -13381,7 +13326,33 @@ function createOpencodeWorkflowGuard(options) {
|
|
|
13381
13326
|
// src/lib/skill-resolver.ts
|
|
13382
13327
|
import fs10 from "fs";
|
|
13383
13328
|
import path9 from "path";
|
|
13384
|
-
import { pathToFileURL
|
|
13329
|
+
import { pathToFileURL } from "url";
|
|
13330
|
+
|
|
13331
|
+
// src/lib/skill-catalog.ts
|
|
13332
|
+
function buildCatalogEntries(options) {
|
|
13333
|
+
const { bundledSkillsDir, disabledSkills } = options;
|
|
13334
|
+
return findSkillsInDir(bundledSkillsDir).filter((s) => !disabledSkills.includes(s.name)).filter((s) => s.disableModelInvocation !== true).sort((a, b) => a.name.localeCompare(b.name)).map((s) => ({
|
|
13335
|
+
name: s.name,
|
|
13336
|
+
prefixedName: formatSkillCommandName(s.name),
|
|
13337
|
+
description: s.description
|
|
13338
|
+
}));
|
|
13339
|
+
}
|
|
13340
|
+
function renderCatalogCompact(options) {
|
|
13341
|
+
const entries = buildCatalogEntries(options);
|
|
13342
|
+
const heading = "## Available Systematic Skills";
|
|
13343
|
+
if (entries.length === 0) {
|
|
13344
|
+
return `${heading}
|
|
13345
|
+
|
|
13346
|
+
No Systematic skills are currently available.`;
|
|
13347
|
+
}
|
|
13348
|
+
const bullets = entries.map((entry) => `- ${entry.prefixedName}: ${entry.description}`).join(`
|
|
13349
|
+
`);
|
|
13350
|
+
return `${heading}
|
|
13351
|
+
|
|
13352
|
+
${bullets}`;
|
|
13353
|
+
}
|
|
13354
|
+
|
|
13355
|
+
// src/lib/skill-resolver.ts
|
|
13385
13356
|
function getAllSkills(options) {
|
|
13386
13357
|
const { bundledSkillsDir, disabledSkills } = options;
|
|
13387
13358
|
return findSkillsInDir(bundledSkillsDir).filter((s) => !disabledSkills.includes(s.name)).map((skillInfo) => loadSkill(skillInfo)).filter((s) => s !== null).sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -13417,7 +13388,7 @@ function buildSkillToolParameterHint(options) {
|
|
|
13417
13388
|
function buildSkillContentOutput(matchedSkill) {
|
|
13418
13389
|
const body2 = extractSkillBody(matchedSkill.wrappedTemplate);
|
|
13419
13390
|
const dir = path9.dirname(matchedSkill.skillFile);
|
|
13420
|
-
const base =
|
|
13391
|
+
const base = pathToFileURL(dir).href;
|
|
13421
13392
|
const files = discoverSkillFiles(dir);
|
|
13422
13393
|
const lines = [
|
|
13423
13394
|
`<skill_content name="${matchedSkill.prefixedName}">`,
|
|
@@ -13469,6 +13440,7 @@ function discoverSkillFiles(dir, limit = 10) {
|
|
|
13469
13440
|
return files.map((file) => ` <file>${file}</file>`).join(`
|
|
13470
13441
|
`);
|
|
13471
13442
|
}
|
|
13443
|
+
|
|
13472
13444
|
// src/lib/skill-tool.ts
|
|
13473
13445
|
function createSkillTool(options) {
|
|
13474
13446
|
const { bundledSkillsDir, disabledSkills } = options;
|
|
@@ -13520,7 +13492,7 @@ var bundledSkillsDir = path10.join(packageRoot2, "skills");
|
|
|
13520
13492
|
var bundledAgentsDir2 = path10.join(packageRoot2, "agents");
|
|
13521
13493
|
var bundledCommandsDir = path10.join(packageRoot2, "commands");
|
|
13522
13494
|
var packageJsonPath = path10.join(packageRoot2, "package.json");
|
|
13523
|
-
var canonicalPackageSource =
|
|
13495
|
+
var canonicalPackageSource = pathToFileURL2(fs11.realpathSync(packageRoot2)).href;
|
|
13524
13496
|
var registrationSourceIdentity = createHash5("sha256").update(`systematic/opencode-registration-source/v1/${canonicalPackageSource}`).digest("hex");
|
|
13525
13497
|
var getPackageVersion = () => {
|
|
13526
13498
|
try {
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Escape XML special characters (&, <, >) in text content.
|
|
3
|
-
* Quotes are not escaped because catalog names and descriptions are rendered
|
|
4
|
-
* as element text, not attribute values.
|
|
5
|
-
*/
|
|
6
|
-
export declare function escapeXml(text: string): string;
|
|
7
1
|
export interface CatalogEntry {
|
|
8
2
|
name: string;
|
|
9
3
|
prefixedName: string;
|
|
10
4
|
description: string;
|
|
11
|
-
path: string;
|
|
12
|
-
skillFile: string;
|
|
13
5
|
}
|
|
14
6
|
export interface CatalogOptions {
|
|
15
7
|
bundledSkillsDir: string;
|
|
@@ -21,11 +13,6 @@ export interface CatalogOptions {
|
|
|
21
13
|
* Returns entries sorted by name.
|
|
22
14
|
*/
|
|
23
15
|
export declare function buildCatalogEntries(options: CatalogOptions): CatalogEntry[];
|
|
24
|
-
/**
|
|
25
|
-
* Renders discoverable skills as native-style verbose XML for bootstrap content.
|
|
26
|
-
* Returns empty string when no skills are available.
|
|
27
|
-
*/
|
|
28
|
-
export declare function renderCatalogVerbose(options: CatalogOptions): string;
|
|
29
16
|
/**
|
|
30
17
|
* Renders discoverable skills as a compact markdown list for tool descriptions.
|
|
31
18
|
* Always includes the heading; renders an explicit no-skills message when empty.
|
package/dist/lib/skill-tool.d.ts
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import type { ToolDefinition } from '@opencode-ai/plugin';
|
|
2
|
-
import type { SkillInfo } from './skills.js';
|
|
3
2
|
export { discoverSkillFiles } from './skill-resolver.js';
|
|
4
3
|
export interface SkillToolOptions {
|
|
5
4
|
bundledSkillsDir: string;
|
|
6
5
|
disabledSkills: string[];
|
|
7
6
|
}
|
|
8
|
-
/**
|
|
9
|
-
* Formats skills as XML for tool description.
|
|
10
|
-
* Uses indented format matching OpenCode's native skill tool.
|
|
11
|
-
*/
|
|
12
|
-
export declare function formatSkillsXml(skills: SkillInfo[]): string;
|
|
13
7
|
export declare function createSkillTool(options: SkillToolOptions): ToolDefinition;
|