gestalt-mobile 0.17.1 → 0.17.2
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
|
@@ -50,7 +50,10 @@ skill paths without starting the server. Without `--skills`, a workspace
|
|
|
50
50
|
`gestalt-skills.yml` is used when present; otherwise Codex-native selection is
|
|
51
51
|
preserved. Explicit profiles take precedence over project defaults, which take
|
|
52
52
|
precedence over native configuration. Gestalt Mobile never rewrites Codex
|
|
53
|
-
configuration or skill files.
|
|
53
|
+
configuration or skill files. Exact skill paths remain authoritative, while
|
|
54
|
+
paths inside Codex's versioned plugin cache are rebound to the currently
|
|
55
|
+
discovered plugin version when their marketplace, plugin, and skill-relative
|
|
56
|
+
path still match.
|
|
54
57
|
|
|
55
58
|
## Themes
|
|
56
59
|
|
|
@@ -81,6 +81,36 @@ function canonicalSkillPath(value) {
|
|
|
81
81
|
}
|
|
82
82
|
return value;
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Return the durable identity of a skill inside Codex's versioned plugin cache.
|
|
86
|
+
* The concrete version directory is installation state, while marketplace,
|
|
87
|
+
* plugin, and skill-relative path remain stable across plugin upgrades.
|
|
88
|
+
*/
|
|
89
|
+
function versionNeutralPluginSkillPath(value) {
|
|
90
|
+
const match = value.match(/^(.*[\\/]plugins[\\/]cache[\\/][^\\/]+[\\/][^\\/]+)[\\/][^\\/]+([\\/]skills[\\/].+[\\/]SKILL\.md)$/);
|
|
91
|
+
return match ? `${match[1]}${match[2]}` : undefined;
|
|
92
|
+
}
|
|
93
|
+
function rebindVersionedPluginSkills(discovered, selection) {
|
|
94
|
+
const discoveredPaths = new Set(discovered.map((skill) => canonicalSkillPath(skill.path)));
|
|
95
|
+
const discoveredByDurablePath = new Map();
|
|
96
|
+
for (const skill of discovered) {
|
|
97
|
+
const durablePath = versionNeutralPluginSkillPath(canonicalSkillPath(skill.path));
|
|
98
|
+
if (durablePath === undefined)
|
|
99
|
+
continue;
|
|
100
|
+
const matches = discoveredByDurablePath.get(durablePath) ?? [];
|
|
101
|
+
matches.push(skill);
|
|
102
|
+
discoveredByDurablePath.set(durablePath, matches);
|
|
103
|
+
}
|
|
104
|
+
return createSkillSelection(selection.map((entry) => {
|
|
105
|
+
if (discoveredPaths.has(entry.path))
|
|
106
|
+
return entry;
|
|
107
|
+
const durablePath = versionNeutralPluginSkillPath(entry.path);
|
|
108
|
+
if (durablePath === undefined)
|
|
109
|
+
return entry;
|
|
110
|
+
const matches = discoveredByDurablePath.get(durablePath) ?? [];
|
|
111
|
+
return matches.length === 1 ? { ...entry, path: matches[0].path } : entry;
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
84
114
|
/**
|
|
85
115
|
* Validate a complete selection and return its canonical deterministic order.
|
|
86
116
|
* This is lexical only: resolving symlinks is I/O and belongs to a platform
|
|
@@ -137,11 +167,12 @@ export function compileSkillOverride(input) {
|
|
|
137
167
|
const effective = selectEffectiveSkillSelection(input);
|
|
138
168
|
if (effective.selection === undefined)
|
|
139
169
|
return { source: 'native', skillsConfig: undefined, warnings: [] };
|
|
170
|
+
const reboundSelection = rebindVersionedPluginSkills(input.discovered, effective.selection);
|
|
140
171
|
const discoveredPaths = new Set(input.discovered.map((skill) => canonicalSkillPath(skill.path)));
|
|
141
|
-
const warnings =
|
|
172
|
+
const warnings = reboundSelection
|
|
142
173
|
.filter((entry) => !discoveredPaths.has(entry.path))
|
|
143
174
|
.map((entry) => `Saved skill path is no longer discovered: ${entry.path}`);
|
|
144
|
-
const configured = applySkillSelectionSnapshot(input.discovered,
|
|
175
|
+
const configured = applySkillSelectionSnapshot(input.discovered, reboundSelection);
|
|
145
176
|
return {
|
|
146
177
|
source: effective.source,
|
|
147
178
|
skillsConfig: configured
|