@lythos/skill-deck 0.9.16 → 0.9.18

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 CHANGED
@@ -9,7 +9,7 @@
9
9
  This package exposes a **CLI**. Invoke via:
10
10
 
11
11
  ```bash
12
- bunx @lythos/skill-deck@0.9.16 <command> [options]
12
+ bunx @lythos/skill-deck@0.9.18 <command> [options]
13
13
  ```
14
14
 
15
15
  No installation required. `bunx` auto-downloads the package.
@@ -53,14 +53,14 @@ expires = "2026-05-01" # ISO date; warns at ≤14 days
53
53
 
54
54
  | Situation | Command |
55
55
  |-----------|---------|
56
- | Sync working set with `skill-deck.toml` | `bunx @lythos/skill-deck@0.9.16 link` |
57
- | Validate `skill-deck.toml` before committing | `bunx @lythos/skill-deck@0.9.16 validate` |
58
- | Download a skill to cold pool and add to deck | `bunx @lythos/skill-deck@0.9.16 add owner/repo` |
59
- | Pull latest versions of declared skills | `bunx @lythos/skill-deck@0.9.16 refresh` |
60
- | Refresh a single skill by alias | `bunx @lythos/skill-deck@0.9.16 refresh tdd` |
61
- | Remove a skill from deck and working set | `bunx @lythos/skill-deck@0.9.16 remove tdd` |
62
- | GC unreferenced repos from cold pool | `bunx @lythos/skill-deck@0.9.16 prune` |
63
- | Use a custom deck file or working dir | `bunx @lythos/skill-deck@0.9.16 link --deck ./my-deck.toml --workdir /path/to/project` |
56
+ | Sync working set with `skill-deck.toml` | `bunx @lythos/skill-deck@0.9.18 link` |
57
+ | Validate `skill-deck.toml` before committing | `bunx @lythos/skill-deck@0.9.18 validate` |
58
+ | Download a skill to cold pool and add to deck | `bunx @lythos/skill-deck@0.9.18 add owner/repo` |
59
+ | Pull latest versions of declared skills | `bunx @lythos/skill-deck@0.9.18 refresh` |
60
+ | Refresh a single skill by alias | `bunx @lythos/skill-deck@0.9.18 refresh tdd` |
61
+ | Remove a skill from deck and working set | `bunx @lythos/skill-deck@0.9.18 remove tdd` |
62
+ | GC unreferenced repos from cold pool | `bunx @lythos/skill-deck@0.9.18 prune` |
63
+ | Use a custom deck file or working dir | `bunx @lythos/skill-deck@0.9.18 link --deck ./my-deck.toml --workdir /path/to/project` |
64
64
 
65
65
  ### Commands
66
66
 
@@ -117,7 +117,7 @@ path = "github.com/lythos-labs/lythoskill/skills/lythoskill-deck"
117
117
  EOF
118
118
 
119
119
  # 2. Link — creates symlinks in .claude/skills/
120
- bunx @lythos/skill-deck@0.9.16 link
120
+ bunx @lythos/skill-deck@0.9.18 link
121
121
  ```
122
122
 
123
123
  ### Key Concepts
@@ -146,7 +146,7 @@ Different agents look for skills in different directories. `skill-deck.toml` con
146
146
 
147
147
  | Symptom | Cause | Fix |
148
148
  |---------|-------|-----|
149
- | `❌ Skill not found: <name>` | Skill declared in deck but not in cold pool | `bunx @lythos/skill-deck@0.9.16 add github.com/owner/repo/skill` or clone manually into cold pool |
149
+ | `❌ Skill not found: <name>` | Skill declared in deck but not in cold pool | `bunx @lythos/skill-deck@0.9.18 add github.com/owner/repo/skill` or clone manually into cold pool |
150
150
  | `link` skips entries with warnings | Real files/directories exist in working set (not symlinks) | Delete the real directories in `working_set` and re-run `link`. Never create directories manually there |
151
151
  | `refresh` reports "Not a git repository" | Skill was copied (not cloned) into cold pool | Re-clone with `git clone` or use `deck add` which clones by default |
152
152
  | `deck update` prints deprecation warning | `update` was renamed to `refresh` in v0.8+ | Use `deck refresh` instead |
@@ -255,3 +255,22 @@ Coverage is honest — no gate, no inflation. Agent BDD scenarios run locally on
255
255
  ## License
256
256
 
257
257
  MIT
258
+
259
+ <!-- test-stats -->
260
+ ![pass](https://img.shields.io/badge/71_pass-0_fail-brightgreen) ![coverage](https://img.shields.io/badge/coverage-82%25-yellow)
261
+
262
+ ```
263
+ File | % Funcs | % Lines | Uncovered Line #s
264
+ | --- | --- | --- |
265
+ All files | 74.76 | 81.66 |
266
+ src/add.ts | 83.33 | 71.17 | 43,45-49,54-58,61-70,86-88,103-105,123-124,132-134,166,170,181-187,195-200
267
+ src/link.ts | 43.75 | 61.40 | 112-120,125,128-132,140-151,155-156,171-180,189,215-216,219-220,227-234,246-248,253-254,256-270,274-277,280-287,294-296,307-309,316-319,335,343-346,348-353,355-358,360-373,375-376,379-381,416-417,463-470,488-489,497-499,501-507,533-534,546
268
+ src/parse-deck.ts | 100.00 | 92.45 | 47-50
269
+ src/prune-plan.ts | 75.00 | 97.27 | 179-181
270
+ src/prune.ts | 50.00 | 36.21 | 24-26,29-40,44-73,77-90,94-100,111-113,125-126,144,149-150
271
+ src/refresh-plan.ts | 75.00 | 97.66 | 170-172
272
+ src/refresh.ts | 85.71 | 87.30 | 43-44,56-58,73,77-78
273
+ src/remove.ts | 60.00 | 91.53 | 22-24,44
274
+ src/schema.ts | 100.00 | 100.00 |
275
+ ```
276
+ <!-- /test-stats -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lythos/skill-deck",
3
- "version": "0.9.16",
3
+ "version": "0.9.18",
4
4
  "description": "Declarative skill deck governance — cold pool, working set, deny-by-default",
5
5
  "keywords": [
6
6
  "ai-agent",
package/src/add.ts CHANGED
@@ -75,7 +75,8 @@ function resolvePath(p: string): string {
75
75
  return resolve(p)
76
76
  }
77
77
 
78
- export async function addSkill(locator: string, options: { deck?: string; workdir?: string; alias?: string; type?: string }) {
78
+ export async function addSkill(locator: string, options: { deck?: string; workdir?: string; alias?: string; type?: string; dryRun?: boolean }) {
79
+ const dryRun = options.dryRun || false
79
80
  const workdir = options.workdir ? resolvePath(options.workdir) : process.cwd()
80
81
  const deckPath = options.deck
81
82
  ? resolvePath(options.deck)
@@ -99,6 +100,37 @@ export async function addSkill(locator: string, options: { deck?: string; workdi
99
100
 
100
101
  const targetDir = join(coldPool, parsed.host, parsed.owner, parsed.repo)
101
102
 
103
+ if (dryRun) {
104
+ const skillName = parsed.skill ? basename(parsed.skill) : parsed.repo
105
+ const alias = options.alias || skillName
106
+ const skillType = (options.type || 'tool').toLowerCase()
107
+ const fqPath = parsed.skill
108
+ ? `${parsed.host}/${parsed.owner}/${parsed.repo}/${parsed.skill}`
109
+ : `${parsed.host}/${parsed.owner}/${parsed.repo}`
110
+
111
+ console.log(`🔎 Dry-run: deck add ${locator}`)
112
+ console.log(` Cold pool: ${coldPool}`)
113
+ console.log(` Deck: ${deckPath}`)
114
+ console.log()
115
+ console.log(`📂 Repo status: ${existsSync(join(targetDir, '.git')) ? 'already cloned' : existsSync(targetDir) ? 'dir exists (partial clone?)' : 'not in cold pool'}`)
116
+ if (!existsSync(join(targetDir, '.git'))) {
117
+ console.log(`📦 Would clone: https://${parsed.host}/${parsed.owner}/${parsed.repo}.git --depth 1`)
118
+ }
119
+ if (parsed.skill) {
120
+ const skillMd = join(targetDir, parsed.skill, 'SKILL.md')
121
+ if (existsSync(targetDir) && existsSync(skillMd)) {
122
+ console.log(`📄 Skill path: valid — ${skillMd}`)
123
+ } else if (existsSync(targetDir)) {
124
+ console.log(`⚠️ Skill path: NOT FOUND — check repo layout`)
125
+ }
126
+ }
127
+ console.log(`\n📝 Would add to skill-deck.toml:`)
128
+ console.log(` [${skillType}.skills.${alias}]`)
129
+ console.log(` path = "${fqPath}"`)
130
+ console.log(`\n💡 Remove --dry-run to execute.`)
131
+ return
132
+ }
133
+
102
134
  if (existsSync(targetDir)) {
103
135
  console.error(`❌ Already exists in cold pool: ${targetDir}`)
104
136
  console.error(` To update: rm -rf ${targetDir} and re-run`)
package/src/cli.ts CHANGED
@@ -23,6 +23,7 @@ const alias = aliasFlagIdx >= 0 ? args[aliasFlagIdx + 1] : undefined
23
23
  const type = typeFlagIdx >= 0 ? args[typeFlagIdx + 1] : undefined
24
24
  const noBackup = args.includes('--no-backup')
25
25
  const yes = args.includes('--yes')
26
+ const dryRun = args.includes('--dry-run')
26
27
 
27
28
  const HELP_CONFIG = {
28
29
  binName: 'lythoskill-deck',
@@ -43,6 +44,7 @@ const HELP_CONFIG = {
43
44
 
44
45
  { flag: '--alias <name>', description: 'Explicit alias for the skill (default: basename of path)' },
45
46
  { flag: '--type <type>', description: 'Target section: innate | tool | combo (default: tool)' },
47
+ { flag: '--dry-run', description: 'Show plan without executing (add, prune)' },
46
48
  { flag: '--yes', description: 'Skip interactive confirmation (for prune)' },
47
49
  ],
48
50
  }
@@ -61,7 +63,7 @@ switch (command) {
61
63
  console.error('❌ Missing locator. Usage: deck add <github.com/owner/repo[/skill]>')
62
64
  process.exit(1)
63
65
  }
64
- await addSkill(locator, { deck: deckPath, workdir, alias, type })
66
+ await addSkill(locator, { deck: deckPath, workdir, alias, type, dryRun })
65
67
  break
66
68
  }
67
69
  case 'refresh': {
package/src/link.ts CHANGED
@@ -79,13 +79,14 @@ export function findSource(name: string, coldPool: string, projectDir: string):
79
79
  if (existsSync(join(directPath, "SKILL.md"))) return { path: directPath };
80
80
  }
81
81
 
82
- // 0.5 localhost skills: localhost/skill → cold_pool/skill
82
+ // 0.5 localhost skills: localhost/skill → cold_pool/<skill>
83
83
  if (name.startsWith('localhost/')) {
84
84
  const skill = name.slice('localhost/'.length);
85
85
  if (skill) {
86
86
  const localPath = join(coldPool, skill);
87
87
  if (existsSync(join(localPath, "SKILL.md"))) return { path: localPath };
88
88
  }
89
+ return { path: null };
89
90
  }
90
91
 
91
92
  // 1. 直接路径
@@ -216,8 +217,32 @@ for (const entry of parsedEntries) {
216
217
  continue;
217
218
  }
218
219
  if (!result.path) {
219
- errors.push(`Skill not found: ${entry.path}`);
220
- continue;
220
+ // For localhost skills, create a placeholder so the user can fill it in
221
+ if (entry.path.startsWith('localhost/')) {
222
+ const skill = entry.path.slice('localhost/'.length)
223
+ const localPath = join(COLD_POOL, skill)
224
+ if (!existsSync(join(localPath, 'SKILL.md'))) {
225
+ const now = new Date().toISOString().slice(0, 10)
226
+ const placeholder = [
227
+ '---', `name: ${skill}`, 'description: TODO — add description', 'type: standard', '---',
228
+ '', `# ${skill}`,
229
+ '', '> ⚠️ Placeholder — declared in skill-deck.toml but not yet implemented.',
230
+ '', '## TODO',
231
+ '- [ ] Define what this skill does',
232
+ '- [ ] Add usage instructions',
233
+ '- [ ] Run `deck link` to activate',
234
+ '', `Created: ${now}`, '',
235
+ ].join('\n')
236
+ mkdirSync(localPath, { recursive: true })
237
+ writeFileSync(join(localPath, 'SKILL.md'), placeholder)
238
+ console.log(`📝 Created placeholder: localhost/${skill} → ${localPath}/SKILL.md`)
239
+ result.path = localPath
240
+ }
241
+ }
242
+ if (!result.path) {
243
+ errors.push(`Skill not found: ${entry.path}`)
244
+ continue
245
+ }
221
246
  }
222
247
  declared.push({ name: entry.path, alias: entry.alias, type: entry.type, sourcePath: result.path });
223
248
  }