dogsbay 0.2.0-beta.6 → 0.2.0-beta.7
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/commands/agent.js +101 -12
- package/package.json +9 -9
- /package/skills/platform/{agent-readiness.md → agent-readiness/SKILL.md} +0 -0
- /package/skills/platform/{cli-commands.md → cli-commands/SKILL.md} +0 -0
- /package/skills/platform/{config-yml.md → config-yml/SKILL.md} +0 -0
- /package/skills/platform/{frontmatter-fields.md → frontmatter-fields/SKILL.md} +0 -0
- /package/skills/platform/{markdown-directives.md → markdown-directives/SKILL.md} +0 -0
- /package/skills/platform/{multi-source.md → multi-source/SKILL.md} +0 -0
- /package/skills/platform/{nav-file.md → nav-file/SKILL.md} +0 -0
- /package/skills/platform/{openapi-source.md → openapi-source/SKILL.md} +0 -0
- /package/skills/platform/{plugin-api.md → plugin-api/SKILL.md} +0 -0
- /package/skills/platform/{project-anatomy.md → project-anatomy/SKILL.md} +0 -0
- /package/skills/platform/{taxonomy-config.md → taxonomy-config/SKILL.md} +0 -0
- /package/skills/platform/{theme-tokens.md → theme-tokens/SKILL.md} +0 -0
package/dist/commands/agent.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* See plans/dogsbay-agent-skills.md for the four-tier ownership
|
|
18
18
|
* model and how this fits.
|
|
19
19
|
*/
|
|
20
|
-
import { existsSync, mkdirSync, symlinkSync, unlinkSync, writeFileSync, readlinkSync } from "node:fs";
|
|
20
|
+
import { existsSync, lstatSync, mkdirSync, readdirSync, symlinkSync, unlinkSync, writeFileSync, statSync, readlinkSync } from "node:fs";
|
|
21
21
|
import { dirname, join, relative, resolve } from "node:path";
|
|
22
22
|
import { fileURLToPath } from "node:url";
|
|
23
23
|
import pc from "picocolors";
|
|
@@ -25,15 +25,22 @@ const SUPPORTED_AGENTS = ["claude", "cursor"];
|
|
|
25
25
|
const AGENT_TARGETS = {
|
|
26
26
|
claude: {
|
|
27
27
|
name: "claude",
|
|
28
|
-
|
|
29
|
-
label: "Claude Code
|
|
28
|
+
skillsDir: ".claude/skills",
|
|
29
|
+
label: "Claude Code",
|
|
30
30
|
},
|
|
31
31
|
cursor: {
|
|
32
32
|
name: "cursor",
|
|
33
|
-
|
|
34
|
-
label: "Cursor
|
|
33
|
+
skillsDir: ".cursor/rules",
|
|
34
|
+
label: "Cursor",
|
|
35
35
|
},
|
|
36
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* Prefix every Dogsbay-shipped skill so it doesn't collide with
|
|
39
|
+
* the user's own skills under the same agent's discovery path.
|
|
40
|
+
*/
|
|
41
|
+
const PLATFORM_PREFIX = "dogsbay-";
|
|
42
|
+
const SITE_PREFIX = "dogsbay-site-";
|
|
43
|
+
const PLUGIN_PREFIX = "dogsbay-plugin-";
|
|
37
44
|
export async function agentInstall(cwd, options) {
|
|
38
45
|
const projectRoot = resolve(cwd || ".");
|
|
39
46
|
// Resolve the bundled platform-skills directory. We're running
|
|
@@ -99,13 +106,58 @@ The agent loader checks overrides first.
|
|
|
99
106
|
if (!existsSync(pluginsDir)) {
|
|
100
107
|
mkdirSync(pluginsDir, { recursive: true });
|
|
101
108
|
}
|
|
102
|
-
// 2. Per-agent discovery
|
|
109
|
+
// 2. Per-agent discovery — symlink each skill INDIVIDUALLY at
|
|
110
|
+
// the top level of the agent's skills dir. Claude Code (and
|
|
111
|
+
// similar harnesses) discover skills as direct children of
|
|
112
|
+
// .claude/skills/, each containing a SKILL.md. Nested
|
|
113
|
+
// .claude/skills/dogsbay/platform/<skill>/ doesn't get scanned.
|
|
103
114
|
for (const agent of agents) {
|
|
104
115
|
const target = AGENT_TARGETS[agent];
|
|
105
|
-
const
|
|
106
|
-
mkdirSync(
|
|
107
|
-
|
|
108
|
-
|
|
116
|
+
const agentSkillsDir = join(projectRoot, target.skillsDir);
|
|
117
|
+
mkdirSync(agentSkillsDir, { recursive: true });
|
|
118
|
+
let installed = 0;
|
|
119
|
+
let removed = 0;
|
|
120
|
+
// Platform skills: dogsbay-<name>
|
|
121
|
+
for (const entry of readSkillDirs(join(skillsDir, "platform"))) {
|
|
122
|
+
const dest = join(agentSkillsDir, `${PLATFORM_PREFIX}${entry.name}`);
|
|
123
|
+
refreshSymlink(dest, entry.path);
|
|
124
|
+
installed++;
|
|
125
|
+
}
|
|
126
|
+
// Site skills: dogsbay-site-<name> (skipping overrides/ and the README)
|
|
127
|
+
for (const entry of readSkillDirs(join(skillsDir, "site"))) {
|
|
128
|
+
if (entry.name === "overrides")
|
|
129
|
+
continue;
|
|
130
|
+
const dest = join(agentSkillsDir, `${SITE_PREFIX}${entry.name}`);
|
|
131
|
+
refreshSymlink(dest, entry.path);
|
|
132
|
+
installed++;
|
|
133
|
+
}
|
|
134
|
+
// Plugin skills: dogsbay-plugin-<name>
|
|
135
|
+
for (const entry of readSkillDirs(join(skillsDir, "plugins"))) {
|
|
136
|
+
const dest = join(agentSkillsDir, `${PLUGIN_PREFIX}${entry.name}`);
|
|
137
|
+
refreshSymlink(dest, entry.path);
|
|
138
|
+
installed++;
|
|
139
|
+
}
|
|
140
|
+
// Sweep any stale dogsbay-* symlinks whose target no longer
|
|
141
|
+
// exists (e.g. user uninstalled a plugin, or a platform skill
|
|
142
|
+
// was renamed across CLI versions).
|
|
143
|
+
if (existsSync(agentSkillsDir)) {
|
|
144
|
+
for (const name of readdirSync(agentSkillsDir)) {
|
|
145
|
+
if (!name.startsWith("dogsbay-"))
|
|
146
|
+
continue;
|
|
147
|
+
const path = join(agentSkillsDir, name);
|
|
148
|
+
if (isBrokenSymlink(path)) {
|
|
149
|
+
try {
|
|
150
|
+
unlinkSync(path);
|
|
151
|
+
removed++;
|
|
152
|
+
}
|
|
153
|
+
catch { /* ignore */ }
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
console.log(pc.green(` ✓ ${target.label}: ${installed} skills under ${target.skillsDir}/`));
|
|
158
|
+
if (removed > 0) {
|
|
159
|
+
console.log(pc.gray(` (cleaned up ${removed} stale symlink${removed === 1 ? "" : "s"})`));
|
|
160
|
+
}
|
|
109
161
|
}
|
|
110
162
|
console.log("");
|
|
111
163
|
console.log(pc.cyan("Next:"));
|
|
@@ -180,6 +232,34 @@ function printDetected(projectRoot) {
|
|
|
180
232
|
console.log("");
|
|
181
233
|
console.log(`Supported agents: ${SUPPORTED_AGENTS.join(", ")}`);
|
|
182
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* List each subdirectory of `dir` that looks like a skill — i.e.
|
|
237
|
+
* contains a SKILL.md file. Returns an empty array if `dir`
|
|
238
|
+
* doesn't exist or has no skill subdirs.
|
|
239
|
+
*/
|
|
240
|
+
function readSkillDirs(dir) {
|
|
241
|
+
if (!existsSync(dir))
|
|
242
|
+
return [];
|
|
243
|
+
const out = [];
|
|
244
|
+
for (const name of readdirSync(dir)) {
|
|
245
|
+
if (name.startsWith("."))
|
|
246
|
+
continue;
|
|
247
|
+
const path = join(dir, name);
|
|
248
|
+
let isDir = false;
|
|
249
|
+
try {
|
|
250
|
+
isDir = statSync(path).isDirectory();
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
isDir = false;
|
|
254
|
+
}
|
|
255
|
+
if (!isDir)
|
|
256
|
+
continue;
|
|
257
|
+
if (!existsSync(join(path, "SKILL.md")))
|
|
258
|
+
continue;
|
|
259
|
+
out.push({ name, path });
|
|
260
|
+
}
|
|
261
|
+
return out;
|
|
262
|
+
}
|
|
183
263
|
/**
|
|
184
264
|
* Replace any existing entry at `linkPath` with a fresh symlink
|
|
185
265
|
* pointing at `target`. Idempotent: if the link already points at
|
|
@@ -205,12 +285,21 @@ function refreshSymlink(linkPath, target) {
|
|
|
205
285
|
}
|
|
206
286
|
symlinkSync(target, linkPath, "dir");
|
|
207
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* True only when `p` IS a symlink AND its target doesn't exist.
|
|
290
|
+
* Used by the cleanup pass to remove links pointing at gone paths
|
|
291
|
+
* (e.g. an uninstalled plugin or a renamed platform skill across
|
|
292
|
+
* CLI versions).
|
|
293
|
+
*/
|
|
208
294
|
function isBrokenSymlink(p) {
|
|
209
295
|
try {
|
|
210
|
-
|
|
211
|
-
|
|
296
|
+
const lst = lstatSync(p);
|
|
297
|
+
if (!lst.isSymbolicLink())
|
|
298
|
+
return false;
|
|
212
299
|
}
|
|
213
300
|
catch {
|
|
214
301
|
return false;
|
|
215
302
|
}
|
|
303
|
+
// It's a symlink. existsSync follows the link; false → target gone.
|
|
304
|
+
return !existsSync(p);
|
|
216
305
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dogsbay",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.7",
|
|
4
4
|
"description": "CLI for Dogsbay — scaffold, build, and serve documentation sites with markdown / MkDocs / Obsidian / OpenAPI sources",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
"picocolors": "^1.1.0",
|
|
32
32
|
"prompts": "^2.4.2",
|
|
33
33
|
"yaml": "^2.8.3",
|
|
34
|
-
"@dogsbay/format-
|
|
35
|
-
"@dogsbay/format-
|
|
36
|
-
"@dogsbay/format-
|
|
37
|
-
"@dogsbay/format-
|
|
38
|
-
"@dogsbay/format-starlight": "0.2.0-beta.
|
|
39
|
-
"@dogsbay/format-dogsbay-md": "0.2.0-beta.
|
|
40
|
-
"@dogsbay/format-openapi": "0.2.0-beta.
|
|
41
|
-
"@dogsbay/types": "0.2.0-beta.
|
|
34
|
+
"@dogsbay/format-mkdocs": "0.2.0-beta.7",
|
|
35
|
+
"@dogsbay/format-astro": "0.2.0-beta.7",
|
|
36
|
+
"@dogsbay/format-mdx": "0.2.0-beta.7",
|
|
37
|
+
"@dogsbay/format-obsidian": "0.2.0-beta.7",
|
|
38
|
+
"@dogsbay/format-starlight": "0.2.0-beta.7",
|
|
39
|
+
"@dogsbay/format-dogsbay-md": "0.2.0-beta.7",
|
|
40
|
+
"@dogsbay/format-openapi": "0.2.0-beta.7",
|
|
41
|
+
"@dogsbay/types": "0.2.0-beta.7"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^22.0.0",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|