@archships/dim-plugin-skills 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/README.md +76 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +319 -0
- package/dist/index.js.map +1 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# @archships/dim-plugin-skills
|
|
2
|
+
|
|
3
|
+
Official file-backed skills plugin for `dim-agent-sdk`.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
- discovers `SKILL.md` bundles from `${cwd}/.agents/skills` and any extra `roots`
|
|
8
|
+
- activates skills from explicit `$skill-name` mentions or a session controller
|
|
9
|
+
- injects active skill bodies into the runtime system prompt
|
|
10
|
+
- exposes bundled `references/`, `scripts/`, and `assets/` as absolute paths for existing tools
|
|
11
|
+
|
|
12
|
+
## Skill layout
|
|
13
|
+
|
|
14
|
+
Each skill is a directory with a required `SKILL.md` file and optional bundled resources:
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
demo-skill/
|
|
18
|
+
├── SKILL.md
|
|
19
|
+
├── references/
|
|
20
|
+
├── scripts/
|
|
21
|
+
├── assets/
|
|
22
|
+
└── agents/openai.yaml
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`SKILL.md` must start with YAML frontmatter containing at least:
|
|
26
|
+
|
|
27
|
+
```md
|
|
28
|
+
---
|
|
29
|
+
name: "demo-skill"
|
|
30
|
+
description: "Short description"
|
|
31
|
+
---
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { createAgent, createModel } from '@archships/dim-agent-sdk'
|
|
38
|
+
import { createSkillsPlugin } from '@archships/dim-plugin-skills'
|
|
39
|
+
|
|
40
|
+
const agent = createAgent({
|
|
41
|
+
model: createModel(adapter),
|
|
42
|
+
cwd: process.cwd(),
|
|
43
|
+
plugins: [
|
|
44
|
+
createSkillsPlugin({
|
|
45
|
+
roots: ['/absolute/path/to/shared-skills'],
|
|
46
|
+
}),
|
|
47
|
+
],
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const session = await agent.createSession()
|
|
51
|
+
session.send('Please use $demo-skill for this task.')
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Dynamic enable / disable
|
|
55
|
+
|
|
56
|
+
The plugin exposes a session controller through `session.getPlugin('skills')`:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const controller = session.getPlugin('skills')
|
|
60
|
+
await controller?.enable('demo-skill')
|
|
61
|
+
await controller?.disable('demo-skill')
|
|
62
|
+
await controller?.disableAll()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Behavior notes:
|
|
66
|
+
|
|
67
|
+
- `$skill-name` mentions only activate the skill for the current run
|
|
68
|
+
- controller-enabled skills stay active for the session until disabled
|
|
69
|
+
- changes made while a run is in progress take effect on the next run
|
|
70
|
+
- enabled skills are persisted through `save()` / `restoreSession()`
|
|
71
|
+
|
|
72
|
+
## Notes
|
|
73
|
+
|
|
74
|
+
- skill content is injected into the runtime `system` message
|
|
75
|
+
- `references/` files are indexed by path, not eagerly inlined into the prompt
|
|
76
|
+
- bundled scripts are not auto-executed; the model must call existing tools such as `read` or `exec`
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DimPlugin } from "@archships/dim-plugin-api";
|
|
2
|
+
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
interface SkillsPluginOptions {
|
|
5
|
+
roots?: string[];
|
|
6
|
+
}
|
|
7
|
+
interface SkillSummary {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
rootPath: string;
|
|
11
|
+
skillFilePath: string;
|
|
12
|
+
references: string[];
|
|
13
|
+
scripts: string[];
|
|
14
|
+
assets: string[];
|
|
15
|
+
openaiMetadataPath?: string;
|
|
16
|
+
}
|
|
17
|
+
interface SkillsStatus {
|
|
18
|
+
availableSkills: SkillSummary[];
|
|
19
|
+
enabledSkills: string[];
|
|
20
|
+
pendingEnabledSkills?: string[];
|
|
21
|
+
}
|
|
22
|
+
interface SkillsSessionController {
|
|
23
|
+
getState(): Promise<SkillsStatus>;
|
|
24
|
+
enable(skillName: string): Promise<SkillsStatus>;
|
|
25
|
+
disable(skillName: string): Promise<SkillsStatus>;
|
|
26
|
+
disableAll(): Promise<SkillsStatus>;
|
|
27
|
+
}
|
|
28
|
+
declare function createSkillsPlugin(options?: SkillsPluginOptions): DimPlugin;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { SkillSummary, SkillsPluginOptions, SkillsSessionController, SkillsStatus, createSkillsPlugin };
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
//#region src/index.ts
|
|
4
|
+
const DEFAULT_PLUGIN_ID = "skills";
|
|
5
|
+
const DEFAULT_DISCOVERY_LIMIT = 256;
|
|
6
|
+
const DEFAULT_RESOURCE_LIMIT = 256;
|
|
7
|
+
function createSkillsPlugin(options = {}) {
|
|
8
|
+
return {
|
|
9
|
+
manifest: {
|
|
10
|
+
id: DEFAULT_PLUGIN_ID,
|
|
11
|
+
version: "0.1.0",
|
|
12
|
+
apiVersion: 1,
|
|
13
|
+
permissions: { fs: "read" },
|
|
14
|
+
capabilities: ["skills"]
|
|
15
|
+
},
|
|
16
|
+
setup(context) {
|
|
17
|
+
const catalog = createCatalogLoader(context, options);
|
|
18
|
+
return {
|
|
19
|
+
promptContributors: [async (input) => {
|
|
20
|
+
const activeSkillNames = await resolveActiveSkillNames(context, catalog, input);
|
|
21
|
+
if (activeSkillNames.length === 0) return void 0;
|
|
22
|
+
const loadedCatalog = await catalog.load();
|
|
23
|
+
const activeSkills = activeSkillNames.map((name) => loadedCatalog.byName.get(name)).filter((skill) => skill !== void 0);
|
|
24
|
+
if (activeSkills.length === 0) return void 0;
|
|
25
|
+
return [formatSkillsPrompt(activeSkills)];
|
|
26
|
+
}],
|
|
27
|
+
createSessionController: (controllerContext) => new DefaultSkillsSessionController({
|
|
28
|
+
context: controllerContext,
|
|
29
|
+
catalog
|
|
30
|
+
}),
|
|
31
|
+
hooks: [{
|
|
32
|
+
descriptor: { name: "run.start" },
|
|
33
|
+
middleware: [async ({ payload, context: runtimeContext }) => {
|
|
34
|
+
await reconcilePendingEnabledSkills(runtimeContext);
|
|
35
|
+
return payload;
|
|
36
|
+
}]
|
|
37
|
+
}]
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
var DefaultSkillsSessionController = class {
|
|
43
|
+
context;
|
|
44
|
+
catalog;
|
|
45
|
+
constructor(dependencies) {
|
|
46
|
+
this.context = dependencies.context;
|
|
47
|
+
this.catalog = dependencies.catalog;
|
|
48
|
+
}
|
|
49
|
+
async getState() {
|
|
50
|
+
const loadedCatalog = await this.catalog.load();
|
|
51
|
+
const state = await this.readState();
|
|
52
|
+
return {
|
|
53
|
+
availableSkills: loadedCatalog.summaries,
|
|
54
|
+
enabledSkills: state.enabledSkills ?? [],
|
|
55
|
+
pendingEnabledSkills: state.pendingEnabledSkills
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async enable(skillName) {
|
|
59
|
+
const catalog = await this.catalog.load();
|
|
60
|
+
const normalized = skillName.trim();
|
|
61
|
+
if (!catalog.byName.has(normalized)) throw new Error(`Unknown skill: ${skillName}`);
|
|
62
|
+
return this.updateState((state) => {
|
|
63
|
+
const next = sortNames([...state.pendingEnabledSkills ?? state.enabledSkills ?? [], normalized]);
|
|
64
|
+
return this.context.isRunning() ? {
|
|
65
|
+
...state,
|
|
66
|
+
pendingEnabledSkills: next
|
|
67
|
+
} : {
|
|
68
|
+
enabledSkills: next,
|
|
69
|
+
pendingEnabledSkills: void 0
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
async disable(skillName) {
|
|
74
|
+
const normalized = skillName.trim();
|
|
75
|
+
return this.updateState((state) => {
|
|
76
|
+
const next = (state.pendingEnabledSkills ?? state.enabledSkills ?? []).filter((name) => name !== normalized);
|
|
77
|
+
return this.context.isRunning() ? {
|
|
78
|
+
...state,
|
|
79
|
+
pendingEnabledSkills: next
|
|
80
|
+
} : {
|
|
81
|
+
enabledSkills: next,
|
|
82
|
+
pendingEnabledSkills: void 0
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
async disableAll() {
|
|
87
|
+
return this.updateState((state) => this.context.isRunning() ? {
|
|
88
|
+
...state,
|
|
89
|
+
pendingEnabledSkills: []
|
|
90
|
+
} : {
|
|
91
|
+
enabledSkills: [],
|
|
92
|
+
pendingEnabledSkills: void 0
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
async updateState(updater) {
|
|
96
|
+
const next = normalizeState(updater(await this.readState()));
|
|
97
|
+
await this.context.pluginState.replace(this.context.sessionId, createStateEntry(next));
|
|
98
|
+
await this.context.save();
|
|
99
|
+
return {
|
|
100
|
+
availableSkills: (await this.catalog.load()).summaries,
|
|
101
|
+
enabledSkills: next.enabledSkills ?? [],
|
|
102
|
+
pendingEnabledSkills: next.pendingEnabledSkills
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
async readState() {
|
|
106
|
+
return readStateEntry(await this.context.pluginState.get(this.context.sessionId));
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
function createCatalogLoader(context, options) {
|
|
110
|
+
const resolvedRoots = resolveRoots(context.cwd, options.roots);
|
|
111
|
+
let cachedCatalog;
|
|
112
|
+
return { load() {
|
|
113
|
+
cachedCatalog ??= scanCatalog(context, resolvedRoots);
|
|
114
|
+
return cachedCatalog;
|
|
115
|
+
} };
|
|
116
|
+
}
|
|
117
|
+
async function scanCatalog(context, roots) {
|
|
118
|
+
const byName = /* @__PURE__ */ new Map();
|
|
119
|
+
for (const root of roots) {
|
|
120
|
+
if (!await context.services.fileSystem.exists(root)) continue;
|
|
121
|
+
const skillFiles = sortPaths(await context.services.fileSystem.glob("**/SKILL.md", {
|
|
122
|
+
cwd: root,
|
|
123
|
+
limit: DEFAULT_DISCOVERY_LIMIT
|
|
124
|
+
}));
|
|
125
|
+
for (const skillFilePath of skillFiles) {
|
|
126
|
+
let source;
|
|
127
|
+
try {
|
|
128
|
+
source = await readFile(skillFilePath, "utf8");
|
|
129
|
+
} catch {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const parsed = parseSkillFile(source);
|
|
133
|
+
if (!parsed) {
|
|
134
|
+
warn(`Skipping invalid skill file: ${skillFilePath}`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (byName.has(parsed.name)) {
|
|
138
|
+
warn(`Skipping duplicate skill "${parsed.name}" from ${skillFilePath}`);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const rootPath = path.dirname(skillFilePath);
|
|
142
|
+
const references = await listResourcePaths(context, path.join(rootPath, "references"));
|
|
143
|
+
const scripts = await listResourcePaths(context, path.join(rootPath, "scripts"));
|
|
144
|
+
const assets = await listResourcePaths(context, path.join(rootPath, "assets"));
|
|
145
|
+
const openaiMetadataPath = await context.services.fileSystem.exists(path.join(rootPath, "agents/openai.yaml")) ? path.join(rootPath, "agents/openai.yaml") : void 0;
|
|
146
|
+
byName.set(parsed.name, {
|
|
147
|
+
name: parsed.name,
|
|
148
|
+
description: parsed.description,
|
|
149
|
+
body: parsed.body,
|
|
150
|
+
rootPath,
|
|
151
|
+
skillFilePath,
|
|
152
|
+
references,
|
|
153
|
+
scripts,
|
|
154
|
+
assets,
|
|
155
|
+
openaiMetadataPath
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
byName,
|
|
161
|
+
summaries: [...byName.values()].map(({ body: _body, ...summary }) => summary).sort((left, right) => left.name.localeCompare(right.name))
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
async function listResourcePaths(context, directory) {
|
|
165
|
+
if (!await context.services.fileSystem.exists(directory)) return [];
|
|
166
|
+
try {
|
|
167
|
+
return sortPaths(await context.services.fileSystem.glob("**/*", {
|
|
168
|
+
cwd: directory,
|
|
169
|
+
limit: DEFAULT_RESOURCE_LIMIT
|
|
170
|
+
}));
|
|
171
|
+
} catch {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function parseSkillFile(source) {
|
|
176
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/u.exec(source);
|
|
177
|
+
if (!match) return null;
|
|
178
|
+
const frontmatter = parseFrontmatter(match[1]);
|
|
179
|
+
const name = frontmatter.name?.trim();
|
|
180
|
+
const description = frontmatter.description?.trim();
|
|
181
|
+
const body = match[2].trim();
|
|
182
|
+
if (!name || !description || !body) return null;
|
|
183
|
+
return {
|
|
184
|
+
name,
|
|
185
|
+
description,
|
|
186
|
+
body
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function parseFrontmatter(source) {
|
|
190
|
+
const result = {};
|
|
191
|
+
for (const rawLine of source.split(/\r?\n/u)) {
|
|
192
|
+
const line = rawLine.trimEnd();
|
|
193
|
+
if (line.trim().length === 0 || line.trimStart().startsWith("#")) continue;
|
|
194
|
+
if (/^\s/u.test(rawLine)) continue;
|
|
195
|
+
const match = /^([A-Za-z0-9_-]+):\s*(.*)$/u.exec(line);
|
|
196
|
+
if (!match) continue;
|
|
197
|
+
const [, key, value] = match;
|
|
198
|
+
if (!value) continue;
|
|
199
|
+
result[key] = stripQuotes(value.trim());
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
function stripQuotes(value) {
|
|
204
|
+
if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) return value.slice(1, -1);
|
|
205
|
+
return value;
|
|
206
|
+
}
|
|
207
|
+
async function resolveActiveSkillNames(context, catalog, input) {
|
|
208
|
+
const loadedCatalog = await catalog.load();
|
|
209
|
+
const state = readStateEntry(await context.services.pluginState.get(input.sessionId));
|
|
210
|
+
const mentioned = extractMentionedSkillNames(input.input);
|
|
211
|
+
const merged = /* @__PURE__ */ new Set();
|
|
212
|
+
for (const name of state.enabledSkills ?? []) if (loadedCatalog.byName.has(name)) merged.add(name);
|
|
213
|
+
for (const name of mentioned) if (loadedCatalog.byName.has(name)) merged.add(name);
|
|
214
|
+
return sortNames([...merged]);
|
|
215
|
+
}
|
|
216
|
+
function extractMentionedSkillNames(input) {
|
|
217
|
+
const text = extractText(input);
|
|
218
|
+
if (!text) return [];
|
|
219
|
+
const names = /* @__PURE__ */ new Set();
|
|
220
|
+
for (const match of text.matchAll(/(?:^|[^\w.-])\$([A-Za-z0-9._-]+)/gu)) if (match[1]) names.add(match[1]);
|
|
221
|
+
return [...names];
|
|
222
|
+
}
|
|
223
|
+
function extractText(input) {
|
|
224
|
+
if (typeof input === "string") return input;
|
|
225
|
+
if (Array.isArray(input)) return input.filter((block) => block.type === "text").map((block) => block.text).join("\n");
|
|
226
|
+
if (input.type === "text") return input.text;
|
|
227
|
+
return "";
|
|
228
|
+
}
|
|
229
|
+
function formatSkillsPrompt(skills) {
|
|
230
|
+
return [
|
|
231
|
+
"SKILLS ACTIVE",
|
|
232
|
+
"",
|
|
233
|
+
"The following skills are active for this run. Treat their instruction bodies as system-level guidance. Bundled references are not preloaded into context; use the listed absolute paths with the existing tools when you need them.",
|
|
234
|
+
"",
|
|
235
|
+
...skills.map(formatSkillBlock)
|
|
236
|
+
].join("\n");
|
|
237
|
+
}
|
|
238
|
+
function formatSkillBlock(skill) {
|
|
239
|
+
const sections = [
|
|
240
|
+
`Skill: ${skill.name}`,
|
|
241
|
+
`Description: ${skill.description}`,
|
|
242
|
+
`Root Path: ${skill.rootPath}`,
|
|
243
|
+
`SKILL.md: ${skill.skillFilePath}`,
|
|
244
|
+
"Instructions:",
|
|
245
|
+
skill.body
|
|
246
|
+
];
|
|
247
|
+
if (skill.references.length > 0) sections.push(formatResourceSection("References", skill.references));
|
|
248
|
+
if (skill.scripts.length > 0) sections.push(formatResourceSection("Scripts", skill.scripts));
|
|
249
|
+
if (skill.assets.length > 0) sections.push(formatResourceSection("Assets", skill.assets));
|
|
250
|
+
if (skill.openaiMetadataPath) sections.push(`OpenAI Metadata: ${skill.openaiMetadataPath}`);
|
|
251
|
+
return sections.join("\n");
|
|
252
|
+
}
|
|
253
|
+
function formatResourceSection(title, entries) {
|
|
254
|
+
return [title + ":", ...entries.map((entry) => `- ${entry}`)].join("\n");
|
|
255
|
+
}
|
|
256
|
+
function resolveRoots(cwd, roots) {
|
|
257
|
+
const baseCwd = cwd ?? process.cwd();
|
|
258
|
+
const resolved = [path.resolve(baseCwd, ".agents/skills"), ...(roots ?? []).map((root) => path.resolve(baseCwd, root))];
|
|
259
|
+
const seen = /* @__PURE__ */ new Set();
|
|
260
|
+
const uniqueRoots = [];
|
|
261
|
+
for (const root of resolved) {
|
|
262
|
+
const normalized = path.normalize(root);
|
|
263
|
+
if (seen.has(normalized)) continue;
|
|
264
|
+
seen.add(normalized);
|
|
265
|
+
uniqueRoots.push(normalized);
|
|
266
|
+
}
|
|
267
|
+
return uniqueRoots;
|
|
268
|
+
}
|
|
269
|
+
async function reconcilePendingEnabledSkills(context) {
|
|
270
|
+
if (!context.sessionId) return;
|
|
271
|
+
const current = readStateEntry(await context.services.pluginState.get(context.sessionId));
|
|
272
|
+
if (current.pendingEnabledSkills === void 0) return;
|
|
273
|
+
await context.services.pluginState.replace(context.sessionId, createStateEntry({
|
|
274
|
+
enabledSkills: current.pendingEnabledSkills,
|
|
275
|
+
pendingEnabledSkills: void 0
|
|
276
|
+
}));
|
|
277
|
+
}
|
|
278
|
+
function readStateEntry(entry) {
|
|
279
|
+
if (!entry || typeof entry.data !== "object" || entry.data === null) return {};
|
|
280
|
+
const data = entry.data;
|
|
281
|
+
return normalizeState({
|
|
282
|
+
enabledSkills: readStringArray(data.enabledSkills),
|
|
283
|
+
pendingEnabledSkills: readStringArray(data.pendingEnabledSkills)
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
function createStateEntry(state) {
|
|
287
|
+
const normalized = normalizeState(state);
|
|
288
|
+
const data = {};
|
|
289
|
+
data.enabledSkills = normalized.enabledSkills ?? [];
|
|
290
|
+
if (normalized.pendingEnabledSkills !== void 0) data.pendingEnabledSkills = normalized.pendingEnabledSkills;
|
|
291
|
+
return {
|
|
292
|
+
version: 1,
|
|
293
|
+
updatedAt: Date.now(),
|
|
294
|
+
data
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function readStringArray(value) {
|
|
298
|
+
if (!Array.isArray(value)) return void 0;
|
|
299
|
+
return sortNames(value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean));
|
|
300
|
+
}
|
|
301
|
+
function normalizeState(state) {
|
|
302
|
+
return {
|
|
303
|
+
enabledSkills: sortNames(state.enabledSkills ?? []),
|
|
304
|
+
pendingEnabledSkills: state.pendingEnabledSkills === void 0 ? void 0 : sortNames(state.pendingEnabledSkills)
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
function sortNames(names) {
|
|
308
|
+
return [...new Set(names)].sort((left, right) => left.localeCompare(right));
|
|
309
|
+
}
|
|
310
|
+
function sortPaths(paths) {
|
|
311
|
+
return [...paths].sort((left, right) => left.localeCompare(right));
|
|
312
|
+
}
|
|
313
|
+
function warn(message) {
|
|
314
|
+
console.warn(`[skills] ${message}`);
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
export { createSkillsPlugin };
|
|
318
|
+
|
|
319
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport type {\n DimPlugin,\n HookHandlerInput,\n MessageContentInput,\n PluginContext,\n PluginRuntimeContext,\n PluginSessionControllerContext,\n PluginSessionStateEntry,\n RunStartPayload,\n} from '@archships/dim-plugin-api'\n\nconst DEFAULT_PLUGIN_ID = 'skills'\nconst DEFAULT_DISCOVERY_LIMIT = 256\nconst DEFAULT_RESOURCE_LIMIT = 256\n\nexport interface SkillsPluginOptions {\n roots?: string[]\n}\n\nexport interface SkillSummary {\n name: string\n description: string\n rootPath: string\n skillFilePath: string\n references: string[]\n scripts: string[]\n assets: string[]\n openaiMetadataPath?: string\n}\n\nexport interface SkillsStatus {\n availableSkills: SkillSummary[]\n enabledSkills: string[]\n pendingEnabledSkills?: string[]\n}\n\nexport interface SkillsSessionController {\n getState(): Promise<SkillsStatus>\n enable(skillName: string): Promise<SkillsStatus>\n disable(skillName: string): Promise<SkillsStatus>\n disableAll(): Promise<SkillsStatus>\n}\n\ninterface SkillsPluginStateData {\n enabledSkills?: string[]\n pendingEnabledSkills?: string[]\n}\n\ninterface SkillBundle extends SkillSummary {\n body: string\n}\n\ninterface SkillsCatalog {\n byName: Map<string, SkillBundle>\n summaries: SkillSummary[]\n}\n\ninterface SkillsControllerDependencies {\n context: PluginSessionControllerContext\n catalog: CatalogLoader\n}\n\ninterface CatalogLoader {\n load(): Promise<SkillsCatalog>\n}\n\nexport function createSkillsPlugin(options: SkillsPluginOptions = {}): DimPlugin {\n return {\n manifest: {\n id: DEFAULT_PLUGIN_ID,\n version: '0.1.0',\n apiVersion: 1,\n permissions: {\n fs: 'read',\n },\n capabilities: ['skills'],\n },\n setup(context) {\n const catalog = createCatalogLoader(context, options)\n\n return {\n promptContributors: [\n async (input) => {\n const activeSkillNames = await resolveActiveSkillNames(context, catalog, input)\n if (activeSkillNames.length === 0) return undefined\n\n const loadedCatalog = await catalog.load()\n const activeSkills = activeSkillNames\n .map((name) => loadedCatalog.byName.get(name))\n .filter((skill): skill is SkillBundle => skill !== undefined)\n\n if (activeSkills.length === 0) return undefined\n return [formatSkillsPrompt(activeSkills)]\n },\n ],\n createSessionController: (controllerContext) =>\n new DefaultSkillsSessionController({\n context: controllerContext,\n catalog,\n }),\n hooks: [\n {\n descriptor: { name: 'run.start' },\n middleware: [\n async ({\n payload,\n context: runtimeContext,\n }: HookHandlerInput<RunStartPayload>) => {\n await reconcilePendingEnabledSkills(runtimeContext)\n return payload\n },\n ],\n },\n ],\n }\n },\n }\n}\n\nclass DefaultSkillsSessionController implements SkillsSessionController {\n private readonly context: PluginSessionControllerContext\n private readonly catalog: CatalogLoader\n\n constructor(dependencies: SkillsControllerDependencies) {\n this.context = dependencies.context\n this.catalog = dependencies.catalog\n }\n\n async getState(): Promise<SkillsStatus> {\n const loadedCatalog = await this.catalog.load()\n const state = await this.readState()\n return {\n availableSkills: loadedCatalog.summaries,\n enabledSkills: state.enabledSkills ?? [],\n pendingEnabledSkills: state.pendingEnabledSkills,\n }\n }\n\n async enable(skillName: string): Promise<SkillsStatus> {\n const catalog = await this.catalog.load()\n const normalized = skillName.trim()\n if (!catalog.byName.has(normalized)) throw new Error(`Unknown skill: ${skillName}`)\n\n return this.updateState((state) => {\n const base = state.pendingEnabledSkills ?? state.enabledSkills ?? []\n const next = sortNames([...base, normalized])\n return this.context.isRunning()\n ? {\n ...state,\n pendingEnabledSkills: next,\n }\n : {\n enabledSkills: next,\n pendingEnabledSkills: undefined,\n }\n })\n }\n\n async disable(skillName: string): Promise<SkillsStatus> {\n const normalized = skillName.trim()\n return this.updateState((state) => {\n const base = state.pendingEnabledSkills ?? state.enabledSkills ?? []\n const next = base.filter((name) => name !== normalized)\n return this.context.isRunning()\n ? {\n ...state,\n pendingEnabledSkills: next,\n }\n : {\n enabledSkills: next,\n pendingEnabledSkills: undefined,\n }\n })\n }\n\n async disableAll(): Promise<SkillsStatus> {\n return this.updateState((state) =>\n this.context.isRunning()\n ? {\n ...state,\n pendingEnabledSkills: [],\n }\n : {\n enabledSkills: [],\n pendingEnabledSkills: undefined,\n },\n )\n }\n\n private async updateState(\n updater: (state: SkillsPluginStateData) => SkillsPluginStateData,\n ): Promise<SkillsStatus> {\n const current = await this.readState()\n const next = normalizeState(updater(current))\n await this.context.pluginState.replace(this.context.sessionId, createStateEntry(next))\n await this.context.save()\n const loadedCatalog = await this.catalog.load()\n return {\n availableSkills: loadedCatalog.summaries,\n enabledSkills: next.enabledSkills ?? [],\n pendingEnabledSkills: next.pendingEnabledSkills,\n }\n }\n\n private async readState(): Promise<SkillsPluginStateData> {\n return readStateEntry(await this.context.pluginState.get(this.context.sessionId))\n }\n}\n\nfunction createCatalogLoader(context: PluginContext, options: SkillsPluginOptions): CatalogLoader {\n const resolvedRoots = resolveRoots(context.cwd, options.roots)\n let cachedCatalog: Promise<SkillsCatalog> | undefined\n\n return {\n load() {\n cachedCatalog ??= scanCatalog(context, resolvedRoots)\n return cachedCatalog\n },\n }\n}\n\nasync function scanCatalog(context: PluginContext, roots: string[]): Promise<SkillsCatalog> {\n const byName = new Map<string, SkillBundle>()\n\n for (const root of roots) {\n if (!(await context.services.fileSystem.exists(root))) continue\n\n const skillFiles = sortPaths(\n await context.services.fileSystem.glob('**/SKILL.md', {\n cwd: root,\n limit: DEFAULT_DISCOVERY_LIMIT,\n }),\n )\n\n for (const skillFilePath of skillFiles) {\n let source: string\n try {\n source = await readFile(skillFilePath, 'utf8')\n } catch {\n continue\n }\n\n const parsed = parseSkillFile(source)\n if (!parsed) {\n warn(`Skipping invalid skill file: ${skillFilePath}`)\n continue\n }\n if (byName.has(parsed.name)) {\n warn(`Skipping duplicate skill \"${parsed.name}\" from ${skillFilePath}`)\n continue\n }\n\n const rootPath = path.dirname(skillFilePath)\n const references = await listResourcePaths(context, path.join(rootPath, 'references'))\n const scripts = await listResourcePaths(context, path.join(rootPath, 'scripts'))\n const assets = await listResourcePaths(context, path.join(rootPath, 'assets'))\n const openaiMetadataPath = (await context.services.fileSystem.exists(\n path.join(rootPath, 'agents/openai.yaml'),\n ))\n ? path.join(rootPath, 'agents/openai.yaml')\n : undefined\n\n byName.set(parsed.name, {\n name: parsed.name,\n description: parsed.description,\n body: parsed.body,\n rootPath,\n skillFilePath,\n references,\n scripts,\n assets,\n openaiMetadataPath,\n })\n }\n }\n\n const summaries = [...byName.values()]\n .map(({ body: _body, ...summary }) => summary)\n .sort((left, right) => left.name.localeCompare(right.name))\n\n return {\n byName,\n summaries,\n }\n}\n\nasync function listResourcePaths(context: PluginContext, directory: string): Promise<string[]> {\n if (!(await context.services.fileSystem.exists(directory))) return []\n\n try {\n return sortPaths(\n await context.services.fileSystem.glob('**/*', {\n cwd: directory,\n limit: DEFAULT_RESOURCE_LIMIT,\n }),\n )\n } catch {\n return []\n }\n}\n\nfunction parseSkillFile(source: string): { name: string; description: string; body: string } | null {\n const match = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/u.exec(source)\n if (!match) return null\n\n const frontmatter = parseFrontmatter(match[1])\n const name = frontmatter.name?.trim()\n const description = frontmatter.description?.trim()\n const body = match[2].trim()\n\n if (!name || !description || !body) return null\n return {\n name,\n description,\n body,\n }\n}\n\nfunction parseFrontmatter(source: string): Record<string, string> {\n const result: Record<string, string> = {}\n\n for (const rawLine of source.split(/\\r?\\n/u)) {\n const line = rawLine.trimEnd()\n if (line.trim().length === 0 || line.trimStart().startsWith('#')) continue\n if (/^\\s/u.test(rawLine)) continue\n\n const match = /^([A-Za-z0-9_-]+):\\s*(.*)$/u.exec(line)\n if (!match) continue\n\n const [, key, value] = match\n if (!value) continue\n result[key] = stripQuotes(value.trim())\n }\n\n return result\n}\n\nfunction stripQuotes(value: string): string {\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n )\n return value.slice(1, -1)\n return value\n}\n\nasync function resolveActiveSkillNames(\n context: PluginContext,\n catalog: CatalogLoader,\n input: { sessionId: string; input: MessageContentInput },\n): Promise<string[]> {\n const loadedCatalog = await catalog.load()\n const state = readStateEntry(await context.services.pluginState.get(input.sessionId))\n const mentioned = extractMentionedSkillNames(input.input)\n const merged = new Set<string>()\n\n for (const name of state.enabledSkills ?? []) {\n if (loadedCatalog.byName.has(name)) merged.add(name)\n }\n for (const name of mentioned) {\n if (loadedCatalog.byName.has(name)) merged.add(name)\n }\n\n return sortNames([...merged])\n}\n\nfunction extractMentionedSkillNames(input: MessageContentInput): string[] {\n const text = extractText(input)\n if (!text) return []\n\n const names = new Set<string>()\n for (const match of text.matchAll(/(?:^|[^\\w.-])\\$([A-Za-z0-9._-]+)/gu)) {\n if (match[1]) names.add(match[1])\n }\n return [...names]\n}\n\nfunction extractText(input: MessageContentInput): string {\n if (typeof input === 'string') return input\n if (Array.isArray(input))\n return input\n .filter((block): block is { type: 'text'; text: string } => block.type === 'text')\n .map((block) => block.text)\n .join('\\n')\n if (input.type === 'text') return input.text\n return ''\n}\n\nfunction formatSkillsPrompt(skills: SkillBundle[]): string {\n return [\n 'SKILLS ACTIVE',\n '',\n 'The following skills are active for this run. Treat their instruction bodies as system-level guidance. Bundled references are not preloaded into context; use the listed absolute paths with the existing tools when you need them.',\n '',\n ...skills.map(formatSkillBlock),\n ].join('\\n')\n}\n\nfunction formatSkillBlock(skill: SkillBundle): string {\n const sections = [\n `Skill: ${skill.name}`,\n `Description: ${skill.description}`,\n `Root Path: ${skill.rootPath}`,\n `SKILL.md: ${skill.skillFilePath}`,\n 'Instructions:',\n skill.body,\n ]\n\n if (skill.references.length > 0)\n sections.push(formatResourceSection('References', skill.references))\n if (skill.scripts.length > 0) sections.push(formatResourceSection('Scripts', skill.scripts))\n if (skill.assets.length > 0) sections.push(formatResourceSection('Assets', skill.assets))\n if (skill.openaiMetadataPath) sections.push(`OpenAI Metadata: ${skill.openaiMetadataPath}`)\n\n return sections.join('\\n')\n}\n\nfunction formatResourceSection(title: string, entries: string[]): string {\n return [title + ':', ...entries.map((entry) => `- ${entry}`)].join('\\n')\n}\n\nfunction resolveRoots(cwd: string | undefined, roots: string[] | undefined): string[] {\n const baseCwd = cwd ?? process.cwd()\n const defaultRoot = path.resolve(baseCwd, '.agents/skills')\n const resolved = [defaultRoot, ...(roots ?? []).map((root) => path.resolve(baseCwd, root))]\n const seen = new Set<string>()\n const uniqueRoots: string[] = []\n\n for (const root of resolved) {\n const normalized = path.normalize(root)\n if (seen.has(normalized)) continue\n seen.add(normalized)\n uniqueRoots.push(normalized)\n }\n\n return uniqueRoots\n}\n\nasync function reconcilePendingEnabledSkills(context: PluginRuntimeContext): Promise<void> {\n if (!context.sessionId) return\n\n const current = readStateEntry(await context.services.pluginState.get(context.sessionId))\n if (current.pendingEnabledSkills === undefined) return\n\n await context.services.pluginState.replace(\n context.sessionId,\n createStateEntry({\n enabledSkills: current.pendingEnabledSkills,\n pendingEnabledSkills: undefined,\n }),\n )\n}\n\nfunction readStateEntry(entry: PluginSessionStateEntry | null): SkillsPluginStateData {\n if (!entry || typeof entry.data !== 'object' || entry.data === null) return {}\n\n const data = entry.data as Record<string, unknown>\n return normalizeState({\n enabledSkills: readStringArray(data.enabledSkills),\n pendingEnabledSkills: readStringArray(data.pendingEnabledSkills),\n })\n}\n\nfunction createStateEntry(state: SkillsPluginStateData): PluginSessionStateEntry {\n const normalized = normalizeState(state)\n const data: Record<string, string[]> = {}\n\n data.enabledSkills = normalized.enabledSkills ?? []\n if (normalized.pendingEnabledSkills !== undefined)\n data.pendingEnabledSkills = normalized.pendingEnabledSkills\n\n return {\n version: 1,\n updatedAt: Date.now(),\n data,\n }\n}\n\nfunction readStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) return undefined\n\n const strings = value\n .filter((entry): entry is string => typeof entry === 'string')\n .map((entry) => entry.trim())\n .filter(Boolean)\n\n return sortNames(strings)\n}\n\nfunction normalizeState(state: SkillsPluginStateData): SkillsPluginStateData {\n return {\n enabledSkills: sortNames(state.enabledSkills ?? []),\n pendingEnabledSkills:\n state.pendingEnabledSkills === undefined ? undefined : sortNames(state.pendingEnabledSkills),\n }\n}\n\nfunction sortNames(names: string[]): string[] {\n return [...new Set(names)].sort((left, right) => left.localeCompare(right))\n}\n\nfunction sortPaths(paths: string[]): string[] {\n return [...paths].sort((left, right) => left.localeCompare(right))\n}\n\nfunction warn(message: string): void {\n console.warn(`[skills] ${message}`)\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@archships/dim-plugin-skills",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Official skills plugin for dim-agent-sdk.",
|
|
5
|
+
"homepage": "https://dimcode.dev/",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist/**/*"
|
|
9
|
+
],
|
|
10
|
+
"type": "module",
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"@archships/dim-agent-sdk": ">=0.0.11 <0.1.0",
|
|
24
|
+
"@archships/dim-plugin-api": ">=0.0.3 <0.1.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@archships/dim-agent-sdk": "0.0.12",
|
|
28
|
+
"@archships/dim-plugin-api": "0.0.3"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsdown",
|
|
32
|
+
"typecheck": "tsc --noEmit",
|
|
33
|
+
"bump": "bumpp --commit --no-verify --no-tag --no-push",
|
|
34
|
+
"release": "pnpm run bump && pnpm run build && pnpm publish",
|
|
35
|
+
"release:check": "pnpm run build && npm pack --dry-run"
|
|
36
|
+
}
|
|
37
|
+
}
|