dsh-agent-skills 0.1.0
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/LICENSE +21 -0
- package/README.md +129 -0
- package/cordis.patch.yml +13 -0
- package/lib/client.js +15235 -0
- package/lib/client.js.map +7 -0
- package/lib/discovery.d.ts +9 -0
- package/lib/discovery.js +48 -0
- package/lib/discovery.js.map +1 -0
- package/lib/index.d.ts +35 -0
- package/lib/index.js +26 -0
- package/lib/index.js.map +1 -0
- package/lib/preset.d.ts +9 -0
- package/lib/preset.js +7 -0
- package/lib/preset.js.map +1 -0
- package/lib/provider.d.ts +53 -0
- package/lib/provider.js +295 -0
- package/lib/provider.js.map +1 -0
- package/lib/registry.d.ts +85 -0
- package/lib/registry.js +122 -0
- package/lib/registry.js.map +1 -0
- package/lib/runtime.d.ts +27 -0
- package/lib/runtime.js +162 -0
- package/lib/runtime.js.map +1 -0
- package/lib/scan.d.ts +29 -0
- package/lib/scan.js +156 -0
- package/lib/scan.js.map +1 -0
- package/lib/schemas.d.ts +112 -0
- package/lib/schemas.js +82 -0
- package/lib/schemas.js.map +1 -0
- package/lib/store.d.ts +26 -0
- package/lib/store.js +88 -0
- package/lib/store.js.map +1 -0
- package/lib/typert.d.ts +195 -0
- package/lib/typert.js +153 -0
- package/lib/typert.js.map +1 -0
- package/lib/types/client/AgentSkillsSection.d.ts +9 -0
- package/lib/types/client/index.d.ts +14 -0
- package/lib/types/client/locales.d.ts +86 -0
- package/lib/types/client/styles.d.ts +4 -0
- package/lib/types/client/typert-remote.d.ts +152 -0
- package/lib/types/client/types.d.ts +13 -0
- package/lib/types/schemas.d.ts +112 -0
- package/lib/views.d.ts +27 -0
- package/lib/views.js +218 -0
- package/lib/views.js.map +1 -0
- package/package.json +130 -0
- package/scripts/install-preset.mjs +49 -0
- package/scripts/uninstall-preset.mjs +22 -0
package/lib/registry.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/** Cast a `ctx.skills` service to the structural shape. */
|
|
2
|
+
export function registryOf(skills) {
|
|
3
|
+
return skills;
|
|
4
|
+
}
|
|
5
|
+
/** Skill rank constants mirroring @deepseek-ai/dsh-skill-filesystem. */
|
|
6
|
+
export const RANK = {
|
|
7
|
+
projectDsh: 100,
|
|
8
|
+
projectAgents: 200,
|
|
9
|
+
runtime: 250,
|
|
10
|
+
custom: 300,
|
|
11
|
+
userDsh: 400,
|
|
12
|
+
userAgents: 500,
|
|
13
|
+
bundled: 600
|
|
14
|
+
};
|
|
15
|
+
/** The runtime provider name (reserved by the skill registry). */
|
|
16
|
+
export const RUNTIME_PROVIDER_NAME = "runtime";
|
|
17
|
+
/** Normalize one provider observation into candidates + completeness. */
|
|
18
|
+
export function normalizeObservation(output, providerName) {
|
|
19
|
+
if (Array.isArray(output))
|
|
20
|
+
return { candidates: output, complete: true };
|
|
21
|
+
if (output === null || typeof output !== "object")
|
|
22
|
+
return { candidates: [], complete: false };
|
|
23
|
+
const observation = output;
|
|
24
|
+
if (!Array.isArray(observation.candidates) || typeof observation.complete !== "boolean") {
|
|
25
|
+
return { candidates: [], complete: false };
|
|
26
|
+
}
|
|
27
|
+
return { candidates: observation.candidates, complete: observation.complete };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Collect candidates from one layer: runtime entries first (rank 250), then
|
|
31
|
+
* each provider in registration order. A provider that throws is skipped and
|
|
32
|
+
* marks the observation incomplete (mirrors the registry's own resilience).
|
|
33
|
+
*/
|
|
34
|
+
export async function collectLayer(layer, options, logger, excludeProvider) {
|
|
35
|
+
const entries = [];
|
|
36
|
+
let complete = true;
|
|
37
|
+
let localOrder = 0;
|
|
38
|
+
for (const [name, definition] of [...layer.runtime.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
39
|
+
entries.push({
|
|
40
|
+
candidate: {
|
|
41
|
+
name,
|
|
42
|
+
description: definition.description,
|
|
43
|
+
...(definition.whenToUse !== undefined ? { whenToUse: definition.whenToUse } : {}),
|
|
44
|
+
invocation: definition.invocation ?? { modelInvocable: true, userInvocable: true },
|
|
45
|
+
source: definition.source,
|
|
46
|
+
provider: RUNTIME_PROVIDER_NAME,
|
|
47
|
+
rank: RANK.runtime,
|
|
48
|
+
locator: definition,
|
|
49
|
+
...(definition.resourceBase !== undefined ? { resourceBase: definition.resourceBase } : {}),
|
|
50
|
+
...(definition.path !== undefined ? { path: definition.path } : {}),
|
|
51
|
+
...(definition.metadata !== undefined ? { metadata: definition.metadata } : {})
|
|
52
|
+
},
|
|
53
|
+
provider: undefined,
|
|
54
|
+
providerOrder: -1,
|
|
55
|
+
localOrder: localOrder++
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
for (const { provider, order } of layer.providers.values()) {
|
|
59
|
+
if (excludeProvider !== undefined && provider.name === excludeProvider)
|
|
60
|
+
continue;
|
|
61
|
+
let output;
|
|
62
|
+
try {
|
|
63
|
+
output = await provider.list(options);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
complete = false;
|
|
67
|
+
logger.warn(`agent-skills: provider "${provider.name}" skipped: ${String(error)}`);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const observation = normalizeObservation(output, provider.name);
|
|
71
|
+
if (!observation.complete)
|
|
72
|
+
complete = false;
|
|
73
|
+
for (const candidate of observation.candidates) {
|
|
74
|
+
entries.push({ candidate, provider, providerOrder: order, localOrder: localOrder++ });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { entries, complete };
|
|
78
|
+
}
|
|
79
|
+
/** Collect candidates from the global layer and every scoped layer. */
|
|
80
|
+
export async function collectAllLayers(registry, options, logger, excludeProvider) {
|
|
81
|
+
const entries = [];
|
|
82
|
+
let complete = true;
|
|
83
|
+
const global = await collectLayer(registry.layers.global, options, logger, excludeProvider);
|
|
84
|
+
entries.push(...global.entries);
|
|
85
|
+
if (!global.complete)
|
|
86
|
+
complete = false;
|
|
87
|
+
for (const layer of registry.layers.scoped.values()) {
|
|
88
|
+
const collected = await collectLayer(layer, options, logger, excludeProvider);
|
|
89
|
+
entries.push(...collected.entries);
|
|
90
|
+
if (!collected.complete)
|
|
91
|
+
complete = false;
|
|
92
|
+
}
|
|
93
|
+
return { entries, complete };
|
|
94
|
+
}
|
|
95
|
+
/** First-wins dedupe after rank/providerOrder/localOrder sort (registry semantics). */
|
|
96
|
+
export function dedupeWinners(entries) {
|
|
97
|
+
const sorted = [...entries].sort((a, b) => {
|
|
98
|
+
const rank = a.candidate.rank - b.candidate.rank;
|
|
99
|
+
if (rank !== 0)
|
|
100
|
+
return rank;
|
|
101
|
+
const order = a.providerOrder - b.providerOrder;
|
|
102
|
+
if (order !== 0)
|
|
103
|
+
return order;
|
|
104
|
+
return a.localOrder - b.localOrder;
|
|
105
|
+
});
|
|
106
|
+
const seen = new Set();
|
|
107
|
+
const winners = [];
|
|
108
|
+
for (const entry of sorted) {
|
|
109
|
+
if (seen.has(entry.candidate.name))
|
|
110
|
+
continue;
|
|
111
|
+
seen.add(entry.candidate.name);
|
|
112
|
+
winners.push(entry);
|
|
113
|
+
}
|
|
114
|
+
return winners;
|
|
115
|
+
}
|
|
116
|
+
/** Force the registry to re-collect on the next `list()`/snapshot. */
|
|
117
|
+
export function invalidateSkillCache(skills) {
|
|
118
|
+
const registry = registryOf(skills);
|
|
119
|
+
if (typeof registry.invalidateCache === "function")
|
|
120
|
+
registry.invalidateCache();
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/lib/runtime.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host typert service backing the Agent Skills settings page. Every mutating
|
|
3
|
+
* method persists the new state, invalidates the skill registry so the next
|
|
4
|
+
* agent step republishes the model catalog, and returns the fresh page view.
|
|
5
|
+
*
|
|
6
|
+
* @module dsh-agent-skills/runtime
|
|
7
|
+
*/
|
|
8
|
+
import { TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
9
|
+
import type { AgentSkillsView, AddDirInput, RemoveDirInput, ToggleDirInput, ToggleSkillInput } from "./schemas.js";
|
|
10
|
+
/** The host service behind the `agentSkills` typert namespace. */
|
|
11
|
+
export declare class AgentSkillsRuntime extends TypertRemoteService {
|
|
12
|
+
constructor(ctx: import("@deepseek-ai/cordis").Context);
|
|
13
|
+
/** Full page view: sources + catalog + counts. */
|
|
14
|
+
list(): Promise<AgentSkillsView>;
|
|
15
|
+
/** Enable or disable one skill by name. */
|
|
16
|
+
toggleSkill(input: ToggleSkillInput): Promise<AgentSkillsView>;
|
|
17
|
+
/** Enable or disable one scan directory (custom or builtin root). */
|
|
18
|
+
toggleDir(input: ToggleDirInput): Promise<AgentSkillsView>;
|
|
19
|
+
/** Add a custom scan directory. */
|
|
20
|
+
addDir(input: AddDirInput): Promise<AgentSkillsView>;
|
|
21
|
+
/** Remove a custom scan directory (auto-discovered ones too). */
|
|
22
|
+
removeDir(input: RemoveDirInput): Promise<AgentSkillsView>;
|
|
23
|
+
/** Re-scan everything and return the fresh view. */
|
|
24
|
+
rescan(): Promise<AgentSkillsView>;
|
|
25
|
+
/** Shared tail: auto-discover, invalidate the catalog, return the view. */
|
|
26
|
+
private refresh;
|
|
27
|
+
}
|
package/lib/runtime.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
2
|
+
var useValue = arguments.length > 2;
|
|
3
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
4
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
5
|
+
}
|
|
6
|
+
return useValue ? value : void 0;
|
|
7
|
+
};
|
|
8
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
9
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
10
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
11
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
12
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
13
|
+
var _, done = false;
|
|
14
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
15
|
+
var context = {};
|
|
16
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
17
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
18
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
19
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
20
|
+
if (kind === "accessor") {
|
|
21
|
+
if (result === void 0) continue;
|
|
22
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
23
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
24
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
25
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
26
|
+
}
|
|
27
|
+
else if (_ = accept(result)) {
|
|
28
|
+
if (kind === "field") initializers.unshift(_);
|
|
29
|
+
else descriptor[key] = _;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
33
|
+
done = true;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Host typert service backing the Agent Skills settings page. Every mutating
|
|
37
|
+
* method persists the new state, invalidates the skill registry so the next
|
|
38
|
+
* agent step republishes the model catalog, and returns the fresh page view.
|
|
39
|
+
*
|
|
40
|
+
* @module dsh-agent-skills/runtime
|
|
41
|
+
*/
|
|
42
|
+
import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
43
|
+
import { readState, writeState } from "./store.js";
|
|
44
|
+
import { buildView, ensureDiscovered, canonicalizeDir } from "./views.js";
|
|
45
|
+
import { invalidateSkillCache } from "./registry.js";
|
|
46
|
+
import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
47
|
+
/** Strip undefined recursively so the strict wire codec always passes. */
|
|
48
|
+
function jsonSafe(value) {
|
|
49
|
+
if (Array.isArray(value))
|
|
50
|
+
return value.map((entry) => jsonSafe(entry));
|
|
51
|
+
if (typeof value === "object" && value !== null) {
|
|
52
|
+
const out = {};
|
|
53
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
54
|
+
if (entry !== undefined)
|
|
55
|
+
out[key] = jsonSafe(entry);
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
/** The host service behind the `agentSkills` typert namespace. */
|
|
62
|
+
let AgentSkillsRuntime = (() => {
|
|
63
|
+
let _classSuper = TypertRemoteService;
|
|
64
|
+
let _instanceExtraInitializers = [];
|
|
65
|
+
let _list_decorators;
|
|
66
|
+
let _toggleSkill_decorators;
|
|
67
|
+
let _toggleDir_decorators;
|
|
68
|
+
let _addDir_decorators;
|
|
69
|
+
let _removeDir_decorators;
|
|
70
|
+
let _rescan_decorators;
|
|
71
|
+
return class AgentSkillsRuntime extends _classSuper {
|
|
72
|
+
static {
|
|
73
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
74
|
+
_list_decorators = [Remote];
|
|
75
|
+
_toggleSkill_decorators = [Remote];
|
|
76
|
+
_toggleDir_decorators = [Remote];
|
|
77
|
+
_addDir_decorators = [Remote];
|
|
78
|
+
_removeDir_decorators = [Remote];
|
|
79
|
+
_rescan_decorators = [Remote];
|
|
80
|
+
__esDecorate(this, null, _list_decorators, { kind: "method", name: "list", static: false, private: false, access: { has: obj => "list" in obj, get: obj => obj.list }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
81
|
+
__esDecorate(this, null, _toggleSkill_decorators, { kind: "method", name: "toggleSkill", static: false, private: false, access: { has: obj => "toggleSkill" in obj, get: obj => obj.toggleSkill }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
82
|
+
__esDecorate(this, null, _toggleDir_decorators, { kind: "method", name: "toggleDir", static: false, private: false, access: { has: obj => "toggleDir" in obj, get: obj => obj.toggleDir }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
83
|
+
__esDecorate(this, null, _addDir_decorators, { kind: "method", name: "addDir", static: false, private: false, access: { has: obj => "addDir" in obj, get: obj => obj.addDir }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
84
|
+
__esDecorate(this, null, _removeDir_decorators, { kind: "method", name: "removeDir", static: false, private: false, access: { has: obj => "removeDir" in obj, get: obj => obj.removeDir }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
85
|
+
__esDecorate(this, null, _rescan_decorators, { kind: "method", name: "rescan", static: false, private: false, access: { has: obj => "rescan" in obj, get: obj => obj.rescan }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
86
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
87
|
+
}
|
|
88
|
+
constructor(ctx) {
|
|
89
|
+
super(ctx, "agentSkills");
|
|
90
|
+
__runInitializers(this, _instanceExtraInitializers);
|
|
91
|
+
}
|
|
92
|
+
/** Full page view: sources + catalog + counts. */
|
|
93
|
+
async list() {
|
|
94
|
+
return this.refresh();
|
|
95
|
+
}
|
|
96
|
+
/** Enable or disable one skill by name. */
|
|
97
|
+
async toggleSkill(input) {
|
|
98
|
+
const state = await readState();
|
|
99
|
+
const set = new Set(state.disabledSkills);
|
|
100
|
+
if (input.enabled)
|
|
101
|
+
set.delete(input.name);
|
|
102
|
+
else
|
|
103
|
+
set.add(input.name);
|
|
104
|
+
state.disabledSkills = [...set].sort();
|
|
105
|
+
await writeState(state);
|
|
106
|
+
return this.refresh();
|
|
107
|
+
}
|
|
108
|
+
/** Enable or disable one scan directory (custom or builtin root). */
|
|
109
|
+
async toggleDir(input) {
|
|
110
|
+
const state = await readState();
|
|
111
|
+
const path = canonicalizeDir(input.path);
|
|
112
|
+
const custom = state.dirs.find((dir) => canonicalizeDir(dir.path) === path);
|
|
113
|
+
if (custom !== undefined) {
|
|
114
|
+
custom.enabled = input.enabled;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
const set = new Set(state.disabledDirs.map((entry) => canonicalizeDir(entry)));
|
|
118
|
+
if (input.enabled)
|
|
119
|
+
set.delete(path);
|
|
120
|
+
else
|
|
121
|
+
set.add(path);
|
|
122
|
+
state.disabledDirs = [...set].sort();
|
|
123
|
+
}
|
|
124
|
+
await writeState(state);
|
|
125
|
+
return this.refresh();
|
|
126
|
+
}
|
|
127
|
+
/** Add a custom scan directory. */
|
|
128
|
+
async addDir(input) {
|
|
129
|
+
const state = await readState();
|
|
130
|
+
const path = canonicalizeDir(input.path);
|
|
131
|
+
const existing = state.dirs.find((dir) => canonicalizeDir(dir.path) === path);
|
|
132
|
+
if (existing === undefined)
|
|
133
|
+
state.dirs.push({ path, enabled: true });
|
|
134
|
+
await writeState(state);
|
|
135
|
+
return this.refresh();
|
|
136
|
+
}
|
|
137
|
+
/** Remove a custom scan directory (auto-discovered ones too). */
|
|
138
|
+
async removeDir(input) {
|
|
139
|
+
const state = await readState();
|
|
140
|
+
const path = canonicalizeDir(input.path);
|
|
141
|
+
state.dirs = state.dirs.filter((dir) => canonicalizeDir(dir.path) !== path);
|
|
142
|
+
await writeState(state);
|
|
143
|
+
return this.refresh();
|
|
144
|
+
}
|
|
145
|
+
/** Re-scan everything and return the fresh view. */
|
|
146
|
+
async rescan() {
|
|
147
|
+
return this.refresh();
|
|
148
|
+
}
|
|
149
|
+
/** Shared tail: auto-discover, invalidate the catalog, return the view. */
|
|
150
|
+
async refresh() {
|
|
151
|
+
const dshHome = resolveDshHome();
|
|
152
|
+
const state = await readState(dshHome);
|
|
153
|
+
if (await ensureDiscovered(state))
|
|
154
|
+
await writeState(state, dshHome);
|
|
155
|
+
invalidateSkillCache(this.ctx.get("skills"));
|
|
156
|
+
const view = await buildView(this.ctx, state);
|
|
157
|
+
return jsonSafe(view);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
})();
|
|
161
|
+
export { AgentSkillsRuntime };
|
|
162
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
package/lib/scan.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface ParsedSkill {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
whenToUse?: string;
|
|
5
|
+
modelInvocable: boolean;
|
|
6
|
+
userInvocable: boolean;
|
|
7
|
+
metadata?: Record<string, unknown>;
|
|
8
|
+
content: string;
|
|
9
|
+
/** Absolute path of the skill file (SKILL.md or flat .md). */
|
|
10
|
+
path: string;
|
|
11
|
+
/** Absolute directory containing the skill file. */
|
|
12
|
+
directory: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ScannedRoot {
|
|
15
|
+
path: string;
|
|
16
|
+
skills: ParsedSkill[];
|
|
17
|
+
}
|
|
18
|
+
/** Parse one skill file; returns undefined when the file is not a usable skill. */
|
|
19
|
+
export declare function parseSkillFile(path: string, logger: {
|
|
20
|
+
warn(message: string): void;
|
|
21
|
+
}): Promise<ParsedSkill | undefined>;
|
|
22
|
+
/**
|
|
23
|
+
* Scan one root directory for skills (one level deep: <dir>/SKILL.md or
|
|
24
|
+
* flat *.md files). A missing root yields an empty result; a root that is
|
|
25
|
+
* not a directory is treated the same.
|
|
26
|
+
*/
|
|
27
|
+
export declare function scanRoot(root: string, logger: {
|
|
28
|
+
warn(message: string): void;
|
|
29
|
+
}): Promise<ScannedRoot>;
|
package/lib/scan.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill discovery for user-configured scan directories. Mirrors the parsing
|
|
3
|
+
* rules of @deepseek-ai/dsh-skill-filesystem so a skill authored for Claude
|
|
4
|
+
* Code / Codex / DSH looks identical from every source:
|
|
5
|
+
* - a directory carrying SKILL.md, or a flat *.md file, per root entry;
|
|
6
|
+
* - YAML frontmatter requiring name + description;
|
|
7
|
+
* - optional whenToUse, disable-model-invocation, user-invocable, metadata.
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-agent-skills/scan
|
|
10
|
+
*/
|
|
11
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
12
|
+
import { dirname, join } from "node:path";
|
|
13
|
+
import { load as parseYaml } from "js-yaml";
|
|
14
|
+
const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
15
|
+
function isRecord(value) {
|
|
16
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
function stringField(data, key) {
|
|
19
|
+
const value = data[key];
|
|
20
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
21
|
+
}
|
|
22
|
+
function frontmatterBoolean(data, key) {
|
|
23
|
+
if (!Object.hasOwn(data, key))
|
|
24
|
+
return undefined;
|
|
25
|
+
const value = data[key];
|
|
26
|
+
if (typeof value === "boolean")
|
|
27
|
+
return value;
|
|
28
|
+
if (value === 1 || value === "1")
|
|
29
|
+
return true;
|
|
30
|
+
if (value === 0 || value === "0")
|
|
31
|
+
return false;
|
|
32
|
+
if (typeof value === "string") {
|
|
33
|
+
const lowered = value.toLowerCase();
|
|
34
|
+
if (lowered === "true" || lowered === "yes" || lowered === "on")
|
|
35
|
+
return true;
|
|
36
|
+
if (lowered === "false" || lowered === "no" || lowered === "off")
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
/** Split a raw skill file into frontmatter data and body; undefined when invalid. */
|
|
42
|
+
function parseFrontmatter(raw) {
|
|
43
|
+
const firstLineEnd = raw.indexOf("\n");
|
|
44
|
+
if (firstLineEnd < 0)
|
|
45
|
+
return undefined;
|
|
46
|
+
if (raw.slice(0, firstLineEnd).replace(/\r$/, "") !== "---")
|
|
47
|
+
return undefined;
|
|
48
|
+
const start = firstLineEnd + 1;
|
|
49
|
+
let lineStart = start;
|
|
50
|
+
while (lineStart <= raw.length) {
|
|
51
|
+
const nextNewline = raw.indexOf("\n", lineStart);
|
|
52
|
+
const lineEnd = nextNewline < 0 ? raw.length : nextNewline;
|
|
53
|
+
if (raw.slice(lineStart, lineEnd).replace(/\r$/, "") === "---") {
|
|
54
|
+
const bodyStart = nextNewline < 0 ? raw.length : nextNewline + 1;
|
|
55
|
+
let parsed;
|
|
56
|
+
try {
|
|
57
|
+
parsed = parseYaml(raw.slice(start, lineStart));
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
if (!isRecord(parsed))
|
|
63
|
+
return undefined;
|
|
64
|
+
return { data: parsed, body: raw.slice(bodyStart) };
|
|
65
|
+
}
|
|
66
|
+
if (nextNewline < 0)
|
|
67
|
+
return undefined;
|
|
68
|
+
lineStart = nextNewline + 1;
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
/** Parse one skill file; returns undefined when the file is not a usable skill. */
|
|
73
|
+
export async function parseSkillFile(path, logger) {
|
|
74
|
+
let raw;
|
|
75
|
+
try {
|
|
76
|
+
raw = await readFile(path, "utf8");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
const parsed = parseFrontmatter(raw);
|
|
82
|
+
if (parsed === undefined) {
|
|
83
|
+
logger.warn(`agent-skills: skill file ${path} ignored: missing or invalid YAML frontmatter`);
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
const name = stringField(parsed.data, "name");
|
|
87
|
+
const description = stringField(parsed.data, "description");
|
|
88
|
+
if (name === undefined || description === undefined) {
|
|
89
|
+
logger.warn(`agent-skills: skill file ${path} ignored: frontmatter requires name and description`);
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
if (!SKILL_NAME.test(name)) {
|
|
93
|
+
logger.warn(`agent-skills: skill file ${path} ignored: invalid skill name "${name}"`);
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
const disableModelInvocation = frontmatterBoolean(parsed.data, "disable-model-invocation");
|
|
97
|
+
const userInvocable = frontmatterBoolean(parsed.data, "user-invocable");
|
|
98
|
+
const metadata = parsed.data.metadata;
|
|
99
|
+
return {
|
|
100
|
+
name,
|
|
101
|
+
description,
|
|
102
|
+
...(stringField(parsed.data, "whenToUse") !== undefined ? { whenToUse: stringField(parsed.data, "whenToUse") } : {}),
|
|
103
|
+
modelInvocable: disableModelInvocation !== true,
|
|
104
|
+
userInvocable: userInvocable !== false,
|
|
105
|
+
...(isRecord(metadata) ? { metadata } : {}),
|
|
106
|
+
content: parsed.body.trim(),
|
|
107
|
+
path,
|
|
108
|
+
directory: dirname(path)
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Scan one root directory for skills (one level deep: <dir>/SKILL.md or
|
|
113
|
+
* flat *.md files). A missing root yields an empty result; a root that is
|
|
114
|
+
* not a directory is treated the same.
|
|
115
|
+
*/
|
|
116
|
+
export async function scanRoot(root, logger) {
|
|
117
|
+
let entries;
|
|
118
|
+
try {
|
|
119
|
+
entries = await readdir(root, { withFileTypes: true, encoding: "utf8" });
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return { path: root, skills: [] };
|
|
123
|
+
}
|
|
124
|
+
const skills = [];
|
|
125
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
126
|
+
if (entry.name === ".system")
|
|
127
|
+
continue;
|
|
128
|
+
const path = join(root, entry.name);
|
|
129
|
+
let kind;
|
|
130
|
+
if (entry.isDirectory())
|
|
131
|
+
kind = "directory";
|
|
132
|
+
else if (entry.isFile())
|
|
133
|
+
kind = "file";
|
|
134
|
+
else if (entry.isSymbolicLink()) {
|
|
135
|
+
try {
|
|
136
|
+
const info = await stat(path);
|
|
137
|
+
kind = info.isDirectory() ? "directory" : info.isFile() ? "file" : undefined;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const locator = kind === "directory"
|
|
144
|
+
? { path: join(path, "SKILL.md"), directory: path }
|
|
145
|
+
: kind === "file" && entry.name.endsWith(".md")
|
|
146
|
+
? { path, directory: root }
|
|
147
|
+
: undefined;
|
|
148
|
+
if (locator === undefined)
|
|
149
|
+
continue;
|
|
150
|
+
const parsed = await parseSkillFile(locator.path, logger);
|
|
151
|
+
if (parsed !== undefined)
|
|
152
|
+
skills.push(parsed);
|
|
153
|
+
}
|
|
154
|
+
return { path: root, skills };
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=scan.js.map
|
package/lib/scan.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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"}
|
package/lib/schemas.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire schemas shared by the host typert face and the client remote.
|
|
3
|
+
* Zod v4 instances — the typert gateway re-checks JSON-safety after schema
|
|
4
|
+
* parsing, so optional fields must never be `undefined` on the wire.
|
|
5
|
+
*
|
|
6
|
+
* @module dsh-agent-skills/schemas
|
|
7
|
+
*/
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
/** A scan directory shown on the Agent Skills page. */
|
|
10
|
+
export declare const dirViewSchema: z.ZodObject<{
|
|
11
|
+
path: z.ZodString;
|
|
12
|
+
kind: z.ZodEnum<{
|
|
13
|
+
custom: "custom";
|
|
14
|
+
builtin: "builtin";
|
|
15
|
+
}>;
|
|
16
|
+
exists: z.ZodBoolean;
|
|
17
|
+
enabled: z.ZodBoolean;
|
|
18
|
+
skillCount: z.ZodNumber;
|
|
19
|
+
tag: z.ZodEnum<{
|
|
20
|
+
builtin: "builtin";
|
|
21
|
+
user: "user";
|
|
22
|
+
}>;
|
|
23
|
+
auto: z.ZodOptional<z.ZodBoolean>;
|
|
24
|
+
skills: z.ZodArray<z.ZodObject<{
|
|
25
|
+
name: z.ZodString;
|
|
26
|
+
description: z.ZodString;
|
|
27
|
+
}, z.core.$strip>>;
|
|
28
|
+
}, z.core.$strip>;
|
|
29
|
+
export type DirView = z.infer<typeof dirViewSchema>;
|
|
30
|
+
/** One skill shown on the Agent Skills page. */
|
|
31
|
+
export declare const skillViewSchema: z.ZodObject<{
|
|
32
|
+
name: z.ZodString;
|
|
33
|
+
description: z.ZodString;
|
|
34
|
+
whenToUse: z.ZodOptional<z.ZodString>;
|
|
35
|
+
source: z.ZodString;
|
|
36
|
+
kind: z.ZodEnum<{
|
|
37
|
+
custom: "custom";
|
|
38
|
+
builtin: "builtin";
|
|
39
|
+
global: "global";
|
|
40
|
+
}>;
|
|
41
|
+
directory: z.ZodOptional<z.ZodString>;
|
|
42
|
+
enabled: z.ZodBoolean;
|
|
43
|
+
toggleable: z.ZodBoolean;
|
|
44
|
+
}, z.core.$strip>;
|
|
45
|
+
export type SkillView = z.infer<typeof skillViewSchema>;
|
|
46
|
+
/** The full page view. */
|
|
47
|
+
export declare const agentSkillsViewSchema: z.ZodObject<{
|
|
48
|
+
dirs: z.ZodArray<z.ZodObject<{
|
|
49
|
+
path: z.ZodString;
|
|
50
|
+
kind: z.ZodEnum<{
|
|
51
|
+
custom: "custom";
|
|
52
|
+
builtin: "builtin";
|
|
53
|
+
}>;
|
|
54
|
+
exists: z.ZodBoolean;
|
|
55
|
+
enabled: z.ZodBoolean;
|
|
56
|
+
skillCount: z.ZodNumber;
|
|
57
|
+
tag: z.ZodEnum<{
|
|
58
|
+
builtin: "builtin";
|
|
59
|
+
user: "user";
|
|
60
|
+
}>;
|
|
61
|
+
auto: z.ZodOptional<z.ZodBoolean>;
|
|
62
|
+
skills: z.ZodArray<z.ZodObject<{
|
|
63
|
+
name: z.ZodString;
|
|
64
|
+
description: z.ZodString;
|
|
65
|
+
}, z.core.$strip>>;
|
|
66
|
+
}, z.core.$strip>>;
|
|
67
|
+
skills: z.ZodArray<z.ZodObject<{
|
|
68
|
+
name: z.ZodString;
|
|
69
|
+
description: z.ZodString;
|
|
70
|
+
whenToUse: z.ZodOptional<z.ZodString>;
|
|
71
|
+
source: z.ZodString;
|
|
72
|
+
kind: z.ZodEnum<{
|
|
73
|
+
custom: "custom";
|
|
74
|
+
builtin: "builtin";
|
|
75
|
+
global: "global";
|
|
76
|
+
}>;
|
|
77
|
+
directory: z.ZodOptional<z.ZodString>;
|
|
78
|
+
enabled: z.ZodBoolean;
|
|
79
|
+
toggleable: z.ZodBoolean;
|
|
80
|
+
}, z.core.$strip>>;
|
|
81
|
+
counts: z.ZodObject<{
|
|
82
|
+
total: z.ZodNumber;
|
|
83
|
+
custom: z.ZodNumber;
|
|
84
|
+
global: z.ZodNumber;
|
|
85
|
+
builtin: z.ZodNumber;
|
|
86
|
+
}, z.core.$strip>;
|
|
87
|
+
validDirs: z.ZodNumber;
|
|
88
|
+
missingDirs: z.ZodNumber;
|
|
89
|
+
}, z.core.$strip>;
|
|
90
|
+
export type AgentSkillsView = z.infer<typeof agentSkillsViewSchema>;
|
|
91
|
+
/** Input for toggling one skill. */
|
|
92
|
+
export declare const toggleSkillInputSchema: z.ZodObject<{
|
|
93
|
+
name: z.ZodString;
|
|
94
|
+
enabled: z.ZodBoolean;
|
|
95
|
+
}, z.core.$strip>;
|
|
96
|
+
export type ToggleSkillInput = z.infer<typeof toggleSkillInputSchema>;
|
|
97
|
+
/** Input for toggling one scan directory. */
|
|
98
|
+
export declare const toggleDirInputSchema: z.ZodObject<{
|
|
99
|
+
path: z.ZodString;
|
|
100
|
+
enabled: z.ZodBoolean;
|
|
101
|
+
}, z.core.$strip>;
|
|
102
|
+
export type ToggleDirInput = z.infer<typeof toggleDirInputSchema>;
|
|
103
|
+
/** Input for adding a custom scan directory. */
|
|
104
|
+
export declare const addDirInputSchema: z.ZodObject<{
|
|
105
|
+
path: z.ZodString;
|
|
106
|
+
}, z.core.$strip>;
|
|
107
|
+
export type AddDirInput = z.infer<typeof addDirInputSchema>;
|
|
108
|
+
/** Input for removing a custom scan directory. */
|
|
109
|
+
export declare const removeDirInputSchema: z.ZodObject<{
|
|
110
|
+
path: z.ZodString;
|
|
111
|
+
}, z.core.$strip>;
|
|
112
|
+
export type RemoveDirInput = z.infer<typeof removeDirInputSchema>;
|