skill-flow 1.0.1 → 1.0.3

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.
Files changed (61) hide show
  1. package/README.md +61 -22
  2. package/README.zh.md +62 -24
  3. package/dist/cli.js +35 -5
  4. package/dist/cli.js.map +1 -1
  5. package/dist/domain/types.d.ts +25 -0
  6. package/dist/services/deployment-applier.js +6 -0
  7. package/dist/services/deployment-applier.js.map +1 -1
  8. package/dist/services/deployment-planner.d.ts +5 -0
  9. package/dist/services/deployment-planner.js +198 -16
  10. package/dist/services/deployment-planner.js.map +1 -1
  11. package/dist/services/doctor-service.js +1 -1
  12. package/dist/services/doctor-service.js.map +1 -1
  13. package/dist/services/skill-flow.d.ts +28 -2
  14. package/dist/services/skill-flow.js +354 -3
  15. package/dist/services/skill-flow.js.map +1 -1
  16. package/dist/services/source-service.d.ts +1 -1
  17. package/dist/services/source-service.js +15 -18
  18. package/dist/services/source-service.js.map +1 -1
  19. package/dist/state/store.d.ts +3 -0
  20. package/dist/state/store.js +10 -0
  21. package/dist/state/store.js.map +1 -1
  22. package/dist/tests/skill-flow.test.js +1427 -0
  23. package/dist/tests/skill-flow.test.js.map +1 -1
  24. package/dist/tui/config-app.js +53 -4
  25. package/dist/tui/config-app.js.map +1 -1
  26. package/dist/tui/find-app.d.ts +9 -0
  27. package/dist/tui/find-app.js +117 -0
  28. package/dist/tui/find-app.js.map +1 -0
  29. package/dist/utils/builtin-git-sources.d.ts +5 -0
  30. package/dist/utils/builtin-git-sources.js +23 -0
  31. package/dist/utils/builtin-git-sources.js.map +1 -0
  32. package/dist/utils/find-command.d.ts +2 -0
  33. package/dist/utils/find-command.js +21 -0
  34. package/dist/utils/find-command.js.map +1 -0
  35. package/dist/utils/format.d.ts +2 -1
  36. package/dist/utils/format.js +19 -1
  37. package/dist/utils/format.js.map +1 -1
  38. package/dist/utils/github-catalog.d.ts +1 -0
  39. package/dist/utils/github-catalog.js +25 -0
  40. package/dist/utils/github-catalog.js.map +1 -0
  41. package/dist/utils/naming.d.ts +9 -1
  42. package/dist/utils/naming.js +33 -6
  43. package/dist/utils/naming.js.map +1 -1
  44. package/package.json +10 -1
  45. package/.gstack/browse-network.log +0 -1
  46. package/.gstack/browse.json +0 -7
  47. package/.gstack/qa-reports/qa-report-skill-manager-2026-03-22.md +0 -60
  48. package/docs/DESIGN.md +0 -407
  49. package/docs/PRD/PRD-1.0.0.md +0 -1862
  50. package/docs/PRD/renew/PRD-0.0.0.md +0 -26
  51. package/docs/PRD/renew/PRD-0.0.1.md +0 -408
  52. package/docs/PRD/renew/PRD-0.0.2.md +0 -705
  53. package/docs/PRD/renew/PRD-0.0.3.md +0 -740
  54. package/docs/PRD/renew/PRD-0.0.4.md +0 -1494
  55. package/docs/README.md +0 -242
  56. package/docs/plan/PLAN_v1.0.0.md +0 -663
  57. package/docs/plan/PLAN_v1.0.1.md +0 -814
  58. package/docs/refrences/README.md +0 -7
  59. package/docs/refrences/agent-skill-paths.md +0 -252
  60. package/docs/refrences/naming-dedupe-warning-rules.md +0 -482
  61. package/img/img-1.jpg +0 -0
@@ -1,482 +0,0 @@
1
- # Naming, Dedupe, and Warning Rules
2
-
3
- This document explains the naming rules used by `skill-flow`, especially for workflow groups and skills, and clarifies the current dedupe and warning behavior.
4
-
5
- ## Overview
6
-
7
- The project intentionally separates:
8
-
9
- - stable internal identifiers
10
- - user-facing display names
11
- - final projected names on target agents
12
-
13
- These are related, but they are not the same field.
14
-
15
- ## Core Terms
16
-
17
- ### Group
18
-
19
- A group is one registered Git source. In code, this is the source/workflow group stored in `manifest.json` and `lock.json`.
20
-
21
- Relevant fields:
22
-
23
- - `source.locator`: the user-provided source locator
24
- - `source.displayName`: the readable group name
25
- - `source.id`: the stable internal identifier
26
-
27
- ### Skill
28
-
29
- A skill is one discovered `SKILL.md` leaf inside a group.
30
-
31
- Relevant fields:
32
-
33
- - `leaf.id`: the stable internal identifier
34
- - `leaf.name`: normalized value from `SKILL.md` frontmatter `name`
35
- - `leaf.linkName`: the readable skill name and default projection name
36
- - `leaf.title`: display title derived from the first markdown heading or the raw name
37
-
38
- ### Projected Name
39
-
40
- When a skill is deployed to an agent target, the actual directory/link name may differ from `leaf.linkName` if there is a collision. The final deployed name is the projected name.
41
-
42
- Current rule:
43
-
44
- - no collision: use `leaf.linkName`
45
- - collision: prefer `groupName-skillName`
46
- - if that still collides, fall back to `groupId-skillName`
47
-
48
- ## Group Naming Rules
49
-
50
- ### `source.locator`
51
-
52
- This is the original source reference the user added, for example:
53
-
54
- - `garrytan/gstack`
55
- - `https://github.com/garrytan/gstack`
56
- - `https://github.com/garrytan/gstack.git`
57
- - `git@github.com:garrytan/gstack.git`
58
- - `/local/path/to/repo`
59
-
60
- ### `source.displayName`
61
-
62
- This is the readable group name.
63
-
64
- Rules:
65
-
66
- - GitHub source: use the repo name
67
- - `.git` URL: use the basename without `.git`
68
- - local path: use the final path segment
69
-
70
- Examples:
71
-
72
- - `garrytan/gstack` -> `gstack`
73
- - `https://github.com/garrytan/gstack.git` -> `gstack`
74
- - `/Users/me/my-skills` -> `my-skills`
75
-
76
- ### `source.id`
77
-
78
- This is the stable internal group identifier.
79
-
80
- Rules:
81
-
82
- - GitHub source: `slugify("${owner}-${repo}")`
83
- - non-GitHub source: `slugify(displayName)`
84
-
85
- Examples:
86
-
87
- - `garrytan/gstack` -> `garrytan-gstack`
88
- - `https://github.com/garrytan/gstack.git` -> `garrytan-gstack`
89
- - `git@github.com:garrytan/gstack.git` -> `garrytan-gstack`
90
- - `/Users/me/my-skills` -> `my-skills`
91
-
92
- Why this exists:
93
-
94
- - `displayName` is for readability
95
- - `source.id` is for stability and uniqueness
96
-
97
- This is why two GitHub repos with the same repo name but different owners do not collide:
98
-
99
- - `alice/gstack` -> `alice-gstack`
100
- - `garrytan/gstack` -> `garrytan-gstack`
101
-
102
- ## Group Display Rules
103
-
104
- In `config`, group labels are displayed as:
105
-
106
- - `group_name(@user_name)`
107
-
108
- Example:
109
-
110
- - `gstack(@garrytan)`
111
-
112
- This is display-only. It does not change `source.id`, `displayName`, bindings, or lock data.
113
-
114
- The same group label is now also used in user-facing list and doctor output where the source is known.
115
-
116
- ## Skill Naming Rules
117
-
118
- ### Discovery
119
-
120
- The scanner finds every `SKILL.md` under the source checkout, excluding:
121
-
122
- - `.git`
123
- - `node_modules`
124
-
125
- Each discovered `SKILL.md` becomes a skill candidate.
126
-
127
- ### `leaf.id`
128
-
129
- This is the stable skill identifier.
130
-
131
- Rule:
132
-
133
- - `leaf.id = "${sourceId}:${relativePath}"`
134
-
135
- Examples:
136
-
137
- - `garrytan-gstack:browse`
138
- - `garrytan-gstack:catalog/review`
139
- - `garrytan-gstack:.` for a root-level skill
140
-
141
- This ID is based on source identity plus path identity, not on frontmatter `name`.
142
-
143
- ### `leaf.name`
144
-
145
- This comes from frontmatter `name`, normalized with `slugify`.
146
-
147
- Example:
148
-
149
- ```yaml
150
- ---
151
- name: browse
152
- description: ...
153
- ---
154
- ```
155
-
156
- becomes:
157
-
158
- - `leaf.name = "browse"`
159
-
160
- This field is the skill's declared canonical name, but it is not the main config display label.
161
-
162
- ### `leaf.linkName`
163
-
164
- This is the human-facing skill name used in `config`, and the default projected name for deployment.
165
-
166
- Rules:
167
-
168
- - if the skill is inside a subdirectory, use that directory name
169
- - if the skill is at the repo root, use the group's `displayName`
170
-
171
- Examples:
172
-
173
- Repository:
174
-
175
- ```text
176
- repo/
177
- browse/SKILL.md
178
- review/SKILL.md
179
- ```
180
-
181
- Results:
182
-
183
- - `browse` -> `leaf.linkName = "browse"`
184
- - `review` -> `leaf.linkName = "review"`
185
-
186
- Repository:
187
-
188
- ```text
189
- repo/
190
- SKILL.md
191
- ```
192
-
193
- If the group display name is `gstack`, then:
194
-
195
- - root skill -> `leaf.linkName = "gstack"`
196
-
197
- Important:
198
-
199
- - skill labels do not inherit the GitHub owner in normal display
200
- - the owner is shown at the group level, not the skill level
201
-
202
- ### `leaf.title`
203
-
204
- This is derived from:
205
-
206
- - the first `# ` heading in the markdown body, or
207
- - the raw frontmatter `name`, or
208
- - `"Untitled skill"`
209
-
210
- This is descriptive metadata, not the deployment name.
211
-
212
- ## Dedupe Logic
213
-
214
- There are two different dedupe layers in the project.
215
-
216
- ### 1. Source dedupe
217
-
218
- This prevents the same source from being added twice.
219
-
220
- The add flow checks whether a source with the same `source.id` already exists.
221
-
222
- For GitHub, these forms all normalize to the same source identity:
223
-
224
- - `https://github.com/garrytan/gstack`
225
- - `https://github.com/garrytan/gstack.git`
226
- - `git@github.com:garrytan/gstack.git`
227
- - `garrytan/gstack`
228
-
229
- All four produce:
230
-
231
- - `source.displayName = "gstack"`
232
- - `source.id = "garrytan-gstack"`
233
-
234
- So they are treated as the same group and cannot be added twice.
235
-
236
- This dedupe is identity-based.
237
-
238
- It does not depend on:
239
-
240
- - how the user typed the locator
241
- - whether the source used https, ssh, or `owner/repo`
242
-
243
- ### 2. Skill content dedupe inside one source
244
-
245
- After scanning a source, the inventory builder dedupes skills inside that source.
246
-
247
- The dedupe key is:
248
-
249
- - `parsed.name + "\n" + parsed.description`
250
-
251
- This means two skills in the same source are considered duplicates if both:
252
-
253
- - their frontmatter `name` is the same
254
- - their frontmatter `description` is the same
255
-
256
- When duplicates are found:
257
-
258
- - the first discovered candidate is kept
259
- - later duplicates are moved to `invalidLeafs`
260
- - an invalid reason is recorded explaining which earlier path won
261
-
262
- Current discovery order:
263
-
264
- - files and directories are walked in sorted order
265
- - visible directories are scanned before hidden directories
266
-
267
- So "first discovered" is deterministic.
268
-
269
- Important limitations of the current dedupe behavior:
270
-
271
- - dedupe happens only within one source scan
272
- - it does not merge or eliminate duplicates across different groups
273
- - cross-group duplication is handled later at projection time, not inventory time
274
-
275
- ### 3. Cross-group name collision handling during deployment
276
-
277
- This is not inventory dedupe. It is deployment conflict resolution.
278
-
279
- When multiple selected skills for the same target have the same `leaf.linkName`:
280
-
281
- - if there is no collision, projected name = `leaf.linkName`
282
- - if there is a collision, projected name prefers `${groupName}-${leaf.linkName}`
283
- - if that projected name still collides, projected name falls back to `${sourceId}-${leaf.linkName}`
284
-
285
- Example:
286
-
287
- - group `gstack(@garrytan)` has `browse`
288
- - group `toolkit(@alice)` has `browse`
289
-
290
- If both are selected for the same target:
291
-
292
- - `browse` becomes `gstack-browse`
293
- - `browse` becomes `toolkit-browse`
294
-
295
- This keeps both deployable without overwriting each other.
296
-
297
- Fallback example:
298
-
299
- - `gstack(@alice)` has `browse`
300
- - `gstack(@garrytan)` has `browse`
301
-
302
- Preferred projected names would both be `gstack-browse`, so the system falls back to:
303
-
304
- - `alice-gstack-browse`
305
- - `garrytan-gstack-browse`
306
-
307
- ## Warning Logic
308
-
309
- Warnings in the current system come from multiple places.
310
-
311
- ### 1. Metadata warnings on valid skills
312
-
313
- A skill can still be valid while carrying metadata warnings.
314
-
315
- Current metadata warning rules include:
316
-
317
- - `name` is not 1-64 characters
318
- - `name` contains invalid characters
319
- - `name` does not match the parent directory name
320
- - `description` is empty
321
- - `description` is longer than 1024 characters
322
-
323
- These warnings do not block the skill from being included if the required structure is still valid.
324
-
325
- Examples:
326
-
327
- - frontmatter exists
328
- - `name` exists
329
- - `description` exists
330
- - but `name` does not match the directory
331
-
332
- That skill is still accepted, but it carries a warning.
333
-
334
- ### 2. Invalid leaf records
335
-
336
- Some issues are hard failures for a specific skill candidate.
337
-
338
- Examples:
339
-
340
- - `SKILL.md` does not start with YAML frontmatter
341
- - frontmatter is missing `name`
342
- - frontmatter is missing `description`
343
- - the skill was dropped as a duplicate within the same source
344
-
345
- These are recorded as `invalidLeafs`.
346
-
347
- Invalid leafs are not added to the active leaf inventory.
348
-
349
- When a source is added or updated:
350
-
351
- - valid leafs are kept
352
- - invalid leafs are reported as warnings in the operation result
353
-
354
- So from the user's perspective, "skipped" items often surface as warnings, even though internally they are tracked as invalid leafs.
355
-
356
- ### 3. Projection warnings
357
-
358
- During config/deployment preview, additional warnings can appear.
359
-
360
- Examples:
361
-
362
- - another selected skill in a different group has identical content
363
- - selected leaf no longer exists in source inventory
364
- - a target path is blocked by foreign content
365
-
366
- These warnings are deployment-related, not metadata-related.
367
-
368
- They describe what will happen when the current selection is projected.
369
-
370
- ### 4. UI display behavior
371
-
372
- In `config`:
373
-
374
- - a skill row is tinted warning/yellow if it has metadata warnings
375
- - a skill row is also tinted warning/yellow if it has projection warnings
376
-
377
- This means the same yellow state can be caused by different warning categories:
378
-
379
- - metadata shape problem
380
- - projection conflict
381
- - duplicate-selection side effect
382
-
383
- ## Valid vs Warning vs Invalid
384
-
385
- The easiest way to reason about the current system is:
386
-
387
- - valid: accepted into inventory and deployable in principle
388
- - warning: accepted, but something about it is questionable or conflicting
389
- - invalid: not accepted into inventory as an active skill
390
-
391
- Examples:
392
-
393
- - `name` mismatches parent directory -> valid + warning
394
- - missing `description` -> invalid
395
- - duplicate content inside one source -> invalid
396
- - same skill name in two groups -> valid, but may need renamed projection on a target
397
-
398
- ## Practical Examples
399
-
400
- ### Example 1: same GitHub repo added with different locator formats
401
-
402
- Commands:
403
-
404
- ```bash
405
- skill-flow add https://github.com/garrytan/gstack
406
- skill-flow add git@github.com:garrytan/gstack.git
407
- ```
408
-
409
- Result:
410
-
411
- - second add is rejected as already existing
412
- - because both normalize to `source.id = garrytan-gstack`
413
-
414
- ### Example 2: root-level skill GitHub repo
415
-
416
- Repo:
417
-
418
- ```text
419
- gstack/
420
- SKILL.md
421
- ```
422
-
423
- Result:
424
-
425
- - group display in config: `gstack(@garrytan)`
426
- - root skill display in config: `gstack`
427
-
428
- Not:
429
-
430
- - `garrytan-gstack`
431
-
432
- ### Example 3: duplicate skill content inside one repo
433
-
434
- Repo:
435
-
436
- ```text
437
- repo/
438
- browse/SKILL.md
439
- browse-copy/SKILL.md
440
- ```
441
-
442
- If both files declare the same frontmatter `name` and `description`:
443
-
444
- - first one discovered is kept
445
- - second one is marked invalid
446
- - the source add/update returns a warning for the skipped duplicate
447
-
448
- ### Example 4: same link name across different groups
449
-
450
- Groups:
451
-
452
- - `gstack(@garrytan)` with skill `browse`
453
- - `toolkit(@alice)` with skill `browse`
454
-
455
- Config display:
456
-
457
- - both still show as `browse`
458
-
459
- Projection to the same target:
460
-
461
- - `gstack-browse`
462
- - `toolkit-browse`
463
-
464
- This is conflict resolution, not inventory dedupe.
465
-
466
- ## Current Design Intent
467
-
468
- The naming model is intentionally split this way:
469
-
470
- - group identity should be globally stable
471
- - group display should be human-readable
472
- - skill display should follow repo structure
473
- - deployment naming should stay clean by default
474
- - only collisions should force prefixes
475
-
476
- In short:
477
-
478
- - group uniqueness uses `source.id`
479
- - group display uses `displayName` plus owner context in UI
480
- - skill display uses `leaf.linkName`
481
- - target conflict resolution prefers `${displayName}-${linkName}`
482
- - if that still collides, target conflict resolution falls back to `${sourceId}-${linkName}`
package/img/img-1.jpg DELETED
Binary file