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.
- package/README.md +61 -22
- package/README.zh.md +62 -24
- package/dist/cli.js +35 -5
- package/dist/cli.js.map +1 -1
- package/dist/domain/types.d.ts +25 -0
- package/dist/services/deployment-applier.js +6 -0
- package/dist/services/deployment-applier.js.map +1 -1
- package/dist/services/deployment-planner.d.ts +5 -0
- package/dist/services/deployment-planner.js +198 -16
- package/dist/services/deployment-planner.js.map +1 -1
- package/dist/services/doctor-service.js +1 -1
- package/dist/services/doctor-service.js.map +1 -1
- package/dist/services/skill-flow.d.ts +28 -2
- package/dist/services/skill-flow.js +354 -3
- package/dist/services/skill-flow.js.map +1 -1
- package/dist/services/source-service.d.ts +1 -1
- package/dist/services/source-service.js +15 -18
- package/dist/services/source-service.js.map +1 -1
- package/dist/state/store.d.ts +3 -0
- package/dist/state/store.js +10 -0
- package/dist/state/store.js.map +1 -1
- package/dist/tests/skill-flow.test.js +1427 -0
- package/dist/tests/skill-flow.test.js.map +1 -1
- package/dist/tui/config-app.js +53 -4
- package/dist/tui/config-app.js.map +1 -1
- package/dist/tui/find-app.d.ts +9 -0
- package/dist/tui/find-app.js +117 -0
- package/dist/tui/find-app.js.map +1 -0
- package/dist/utils/builtin-git-sources.d.ts +5 -0
- package/dist/utils/builtin-git-sources.js +23 -0
- package/dist/utils/builtin-git-sources.js.map +1 -0
- package/dist/utils/find-command.d.ts +2 -0
- package/dist/utils/find-command.js +21 -0
- package/dist/utils/find-command.js.map +1 -0
- package/dist/utils/format.d.ts +2 -1
- package/dist/utils/format.js +19 -1
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/github-catalog.d.ts +1 -0
- package/dist/utils/github-catalog.js +25 -0
- package/dist/utils/github-catalog.js.map +1 -0
- package/dist/utils/naming.d.ts +9 -1
- package/dist/utils/naming.js +33 -6
- package/dist/utils/naming.js.map +1 -1
- package/package.json +10 -1
- package/.gstack/browse-network.log +0 -1
- package/.gstack/browse.json +0 -7
- package/.gstack/qa-reports/qa-report-skill-manager-2026-03-22.md +0 -60
- package/docs/DESIGN.md +0 -407
- package/docs/PRD/PRD-1.0.0.md +0 -1862
- package/docs/PRD/renew/PRD-0.0.0.md +0 -26
- package/docs/PRD/renew/PRD-0.0.1.md +0 -408
- package/docs/PRD/renew/PRD-0.0.2.md +0 -705
- package/docs/PRD/renew/PRD-0.0.3.md +0 -740
- package/docs/PRD/renew/PRD-0.0.4.md +0 -1494
- package/docs/README.md +0 -242
- package/docs/plan/PLAN_v1.0.0.md +0 -663
- package/docs/plan/PLAN_v1.0.1.md +0 -814
- package/docs/refrences/README.md +0 -7
- package/docs/refrences/agent-skill-paths.md +0 -252
- package/docs/refrences/naming-dedupe-warning-rules.md +0 -482
- 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
|