@link-assistant/hive-mind 2.8.5 → 2.8.6
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 2.8.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0140e87: Verify required Codex Agent Skills against the catalog the model actually receives instead of trusting plugin enablement, so a plugin reported as installed but whose skills are invisible is reported with an actionable diagnostic rather than passing the preflight.
|
|
8
|
+
|
|
3
9
|
## 2.8.5
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -155,6 +155,61 @@ const parseJsonCommand = (result, label) => {
|
|
|
155
155
|
|
|
156
156
|
const catalogEntries = catalog => [...(catalog?.installed || []), ...(catalog?.available || [])];
|
|
157
157
|
|
|
158
|
+
// Issue #2084: `codex plugin list` reports enablement, not model visibility.
|
|
159
|
+
//
|
|
160
|
+
// Codex renders the skills the model can actually see into a
|
|
161
|
+
// `<skills_instructions>` block in the prompt. `codex debug prompt-input`
|
|
162
|
+
// prints that prompt, so parsing the block is the only client-side signal that
|
|
163
|
+
// matches what the model receives. Entries are rendered as
|
|
164
|
+
// `- <name>: <description> (file: <path>)`, where `<name>` is bare for skills
|
|
165
|
+
// under `$CODEX_HOME/skills` and `<plugin>:<skill>` for plugin-provided ones.
|
|
166
|
+
const SKILLS_INSTRUCTIONS_BLOCK = /<skills_instructions>([\s\S]*?)<\/skills_instructions>/u;
|
|
167
|
+
const SKILL_CATALOG_ENTRY = /(?:^|\\n)\s*-\s+([a-z0-9][a-z0-9_-]*(?::[a-z0-9][a-z0-9_-]*)?)\s*:/giu;
|
|
168
|
+
|
|
169
|
+
export const parseModelVisibleSkills = (promptInput = '') => {
|
|
170
|
+
// `codex debug prompt-input` emits JSON, so newlines inside the prompt arrive
|
|
171
|
+
// as the two-character escape `\n`. Match both that and real newlines.
|
|
172
|
+
const block = SKILLS_INSTRUCTIONS_BLOCK.exec(String(promptInput).replace(/\r\n/gu, '\n').replace(/\n/gu, '\\n'));
|
|
173
|
+
if (!block) return null;
|
|
174
|
+
const skills = new Set();
|
|
175
|
+
for (const match of block[1].matchAll(SKILL_CATALOG_ENTRY)) skills.add(match[1].toLowerCase());
|
|
176
|
+
return skills;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// Verification is advisory when the probe itself cannot run: an older Codex
|
|
180
|
+
// without `debug prompt-input`, or a sandbox that blocks it, must not fail a
|
|
181
|
+
// run that the previous verification would have allowed.
|
|
182
|
+
const readModelVisibleSkills = async ({ command, env, runCommand, log }) => {
|
|
183
|
+
const result = await runCommand({ command, args: ['debug', 'prompt-input', 'hive-mind capability probe'], env });
|
|
184
|
+
if (result.code !== 0) {
|
|
185
|
+
await log(
|
|
186
|
+
` ⚠️ Could not read the model-visible skill catalog: ${String(result.stderr || result.stdout)
|
|
187
|
+
.trim()
|
|
188
|
+
.slice(0, 200)}`,
|
|
189
|
+
{ verbose: true }
|
|
190
|
+
);
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
const skills = parseModelVisibleSkills(result.stdout);
|
|
194
|
+
if (!skills) await log(' ⚠️ Codex prompt did not contain a <skills_instructions> block; skipping skill visibility verification', { verbose: true });
|
|
195
|
+
return skills;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const verifyModelVisibleSkills = async ({ command, env, runCommand, log, requiredSkills }) => {
|
|
199
|
+
if (!requiredSkills || requiredSkills.length === 0) return;
|
|
200
|
+
const visible = await readModelVisibleSkills({ command, env, runCommand, log });
|
|
201
|
+
if (!visible) return;
|
|
202
|
+
|
|
203
|
+
await log(` 🔎 Model-visible skills (${visible.size}): ${[...visible].sort().join(', ') || 'none'}`, { verbose: true });
|
|
204
|
+
const invisible = requiredSkills.filter(skill => !visible.has(skill.toLowerCase()));
|
|
205
|
+
if (invisible.length === 0) {
|
|
206
|
+
await log(` ✅ Verified ${requiredSkills.length} required skill(s) are visible to the model`);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
throw new CodexCapabilityPreflightError(`Codex reports the required plugins as installed, but the model cannot see: ${invisible.join(', ')}. ` + `Codex exposes a plugin's skills only while its payload is materialized under ` + `CODEX_HOME/plugins/cache/<marketplace>/<plugin>/<version>/skills. ` + `Visible skills were: ${[...visible].sort().join(', ') || 'none'}.`, { missing: invisible });
|
|
211
|
+
};
|
|
212
|
+
|
|
158
213
|
const skillParts = skill => {
|
|
159
214
|
const separator = skill.indexOf(':');
|
|
160
215
|
return separator === -1 ? { namespace: null, name: skill } : { namespace: skill.slice(0, separator), name: skill.slice(separator + 1) };
|
|
@@ -341,6 +396,7 @@ async function provisionCodexCapabilities({ owner, repo, issueNumber, projectDir
|
|
|
341
396
|
}
|
|
342
397
|
if (plugins.length === 0) {
|
|
343
398
|
await log(' ✅ Required Agent Skills are already available from standard skill directories');
|
|
399
|
+
await verifyModelVisibleSkills({ command, env: baseEnv, runCommand, log, requiredSkills: requirements.skills });
|
|
344
400
|
return { required: true, plugins, skills: requirements.skills, codexHome: null, baseCodexHome };
|
|
345
401
|
}
|
|
346
402
|
|
|
@@ -365,6 +421,13 @@ async function provisionCodexCapabilities({ owner, repo, issueNumber, projectDir
|
|
|
365
421
|
const unverified = plugins.filter(plugin => !verified.has(plugin));
|
|
366
422
|
if (unverified.length > 0) throw new CodexCapabilityPreflightError(`Codex capability installation did not verify successfully: ${unverified.join(', ')}`, { missing: unverified });
|
|
367
423
|
|
|
424
|
+
// Issue #2084: enablement is not exposure. The failing run reached this point
|
|
425
|
+
// with `superpowers@openai-curated` reported as "installed, enabled" while
|
|
426
|
+
// the model saw zero `superpowers:*` skills, so the run proceeded and then
|
|
427
|
+
// stalled on the repository's mandatory preflight. Confirm the requirement
|
|
428
|
+
// against the catalog the model actually receives.
|
|
429
|
+
await verifyModelVisibleSkills({ command, env: scopedEnv, runCommand, log, requiredSkills: requirements.skills });
|
|
430
|
+
|
|
368
431
|
await log(` Codex capability state: ${codexHome}`, { verbose: true });
|
|
369
432
|
return { required: true, plugins, skills: requirements.skills, codexHome, baseCodexHome };
|
|
370
433
|
}
|