@aexol/opencode-wizard 0.1.14 → 0.1.16
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 +2 -1
- package/dist/config.d.ts +6 -0
- package/dist/config.js +19 -0
- package/dist/config.js.map +1 -0
- package/dist/server.d.ts +49 -2
- package/dist/server.js +448 -97
- package/dist/server.js.map +1 -1
- package/dist/smoke-published-skills.js +7 -1
- package/dist/smoke-published-skills.js.map +1 -1
- package/dist/storage.d.ts +5 -0
- package/dist/storage.js +43 -0
- package/dist/storage.js.map +1 -0
- package/dist/tui.js +414 -186
- package/dist/tui.js.map +1 -1
- package/package.json +3 -2
package/dist/server.js
CHANGED
|
@@ -6,6 +6,8 @@ import crypto from 'node:crypto';
|
|
|
6
6
|
import { execFile } from 'node:child_process';
|
|
7
7
|
import { promisify } from 'node:util';
|
|
8
8
|
import { URL, fileURLToPath } from 'node:url';
|
|
9
|
+
import { resolveBackendOriginFromValues } from './config.js';
|
|
10
|
+
import { deleteFileIfExists, readJsonFile, writePrivateJsonFile } from './storage.js';
|
|
9
11
|
const execFileAsync = promisify(execFile);
|
|
10
12
|
const MODULE_FILE_PATH = fileURLToPath(import.meta.url);
|
|
11
13
|
const PACKAGE_ROOT_PATH = path.resolve(path.dirname(MODULE_FILE_PATH), '..');
|
|
@@ -14,7 +16,6 @@ const CACHE_TTL_MS = 30_000;
|
|
|
14
16
|
const ROOT_SKILL_SEED_PATH = '.opencode/skills';
|
|
15
17
|
const GLOBAL_CONFIG_PATH = path.join(os.homedir(), '.config', 'opencode', 'opencode-wizard.json');
|
|
16
18
|
const LEGACY_AUTH_STATE_PATH = 'plugin/opencode-wizard/.generated/auth-state.json';
|
|
17
|
-
const PUBLISHED_BACKEND_ORIGIN = 'https://opencode-wizard.aexol.work';
|
|
18
19
|
const OIDC_ISSUER = 'https://login.microsoftonline.com/86f4caf4-0d6f-4682-9a06-ea57f3e4e76c/v2.0';
|
|
19
20
|
const OIDC_CLIENT_ID = 'da963901-2375-442b-9e99-14e59f43eda2';
|
|
20
21
|
const OIDC_CALLBACK_ORIGIN = 'http://localhost:24953';
|
|
@@ -54,6 +55,7 @@ const statusPathLoginBootstrap = {
|
|
|
54
55
|
};
|
|
55
56
|
const importOpencodePluginModule = new Function('specifier', 'return import(specifier)');
|
|
56
57
|
export const AVAILABLE_PUBLISHED_SKILL_TOOLS = ['opencode_wizard_published_skills_fetch', 'opencode_wizard_status'];
|
|
58
|
+
let publishedSkillPreferenceCacheVersion = 0;
|
|
57
59
|
export const NATIVE_SKILLS_URL_COMPATIBILITY = {
|
|
58
60
|
configKey: 'skills.urls',
|
|
59
61
|
deliveryMode: 'public_static_registry',
|
|
@@ -114,6 +116,137 @@ const PUBLISHED_SKILLS_CATALOG_QUERY = `
|
|
|
114
116
|
publishedAt
|
|
115
117
|
}
|
|
116
118
|
}
|
|
119
|
+
catalogSkills {
|
|
120
|
+
skill {
|
|
121
|
+
id
|
|
122
|
+
slug
|
|
123
|
+
name
|
|
124
|
+
summary
|
|
125
|
+
whenToUse
|
|
126
|
+
status
|
|
127
|
+
installPolicy
|
|
128
|
+
tags {
|
|
129
|
+
id
|
|
130
|
+
slug
|
|
131
|
+
label
|
|
132
|
+
description
|
|
133
|
+
facet {
|
|
134
|
+
id
|
|
135
|
+
slug
|
|
136
|
+
label
|
|
137
|
+
description
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
skillVersion {
|
|
142
|
+
id
|
|
143
|
+
version
|
|
144
|
+
title
|
|
145
|
+
summary
|
|
146
|
+
status
|
|
147
|
+
}
|
|
148
|
+
publishedArtifact {
|
|
149
|
+
id
|
|
150
|
+
frontmatterName
|
|
151
|
+
frontmatterDescription
|
|
152
|
+
checksum
|
|
153
|
+
publishedAt
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
userPreferences {
|
|
157
|
+
scopeKey
|
|
158
|
+
userKey
|
|
159
|
+
ignoredSkills {
|
|
160
|
+
assignmentSource
|
|
161
|
+
assignmentType
|
|
162
|
+
scopePath
|
|
163
|
+
includeChildren
|
|
164
|
+
skill {
|
|
165
|
+
id
|
|
166
|
+
slug
|
|
167
|
+
name
|
|
168
|
+
summary
|
|
169
|
+
whenToUse
|
|
170
|
+
status
|
|
171
|
+
installPolicy
|
|
172
|
+
tags {
|
|
173
|
+
id
|
|
174
|
+
slug
|
|
175
|
+
label
|
|
176
|
+
description
|
|
177
|
+
facet {
|
|
178
|
+
id
|
|
179
|
+
slug
|
|
180
|
+
label
|
|
181
|
+
description
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
skillVersion {
|
|
186
|
+
id
|
|
187
|
+
version
|
|
188
|
+
title
|
|
189
|
+
summary
|
|
190
|
+
status
|
|
191
|
+
}
|
|
192
|
+
publishedArtifact {
|
|
193
|
+
id
|
|
194
|
+
frontmatterName
|
|
195
|
+
frontmatterDescription
|
|
196
|
+
checksum
|
|
197
|
+
publishedAt
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
`;
|
|
204
|
+
const SET_PUBLISHED_SKILL_PREFERENCE_MUTATION = `
|
|
205
|
+
mutation SetPublishedSkillPreference($input: SetPublishedSkillPreferenceInput!) {
|
|
206
|
+
setPublishedSkillPreference(input: $input) {
|
|
207
|
+
scopeKey
|
|
208
|
+
userKey
|
|
209
|
+
ignoredSkills {
|
|
210
|
+
assignmentSource
|
|
211
|
+
assignmentType
|
|
212
|
+
scopePath
|
|
213
|
+
includeChildren
|
|
214
|
+
skill {
|
|
215
|
+
id
|
|
216
|
+
slug
|
|
217
|
+
name
|
|
218
|
+
summary
|
|
219
|
+
whenToUse
|
|
220
|
+
status
|
|
221
|
+
installPolicy
|
|
222
|
+
tags {
|
|
223
|
+
id
|
|
224
|
+
slug
|
|
225
|
+
label
|
|
226
|
+
description
|
|
227
|
+
facet {
|
|
228
|
+
id
|
|
229
|
+
slug
|
|
230
|
+
label
|
|
231
|
+
description
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
skillVersion {
|
|
236
|
+
id
|
|
237
|
+
version
|
|
238
|
+
title
|
|
239
|
+
summary
|
|
240
|
+
status
|
|
241
|
+
}
|
|
242
|
+
publishedArtifact {
|
|
243
|
+
id
|
|
244
|
+
frontmatterName
|
|
245
|
+
frontmatterDescription
|
|
246
|
+
checksum
|
|
247
|
+
publishedAt
|
|
248
|
+
}
|
|
249
|
+
}
|
|
117
250
|
}
|
|
118
251
|
}
|
|
119
252
|
`;
|
|
@@ -175,20 +308,12 @@ const readLocalEnvValues = async startDirectory => {
|
|
|
175
308
|
return new Map();
|
|
176
309
|
}
|
|
177
310
|
};
|
|
178
|
-
const normalizeBackendOrigin = value => {
|
|
179
|
-
if (!value) return null;
|
|
180
|
-
try {
|
|
181
|
-
const normalizedUrl = new URL(value);
|
|
182
|
-
return normalizedUrl.origin;
|
|
183
|
-
} catch {
|
|
184
|
-
return null;
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
311
|
const resolveBackendOrigin = async worktree => {
|
|
188
312
|
const envValues = await readLocalEnvValues(worktree);
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
313
|
+
return resolveBackendOriginFromValues({
|
|
314
|
+
environmentBackendOrigin: process.env.OPENCODE_WIZARD_BACKEND_ORIGIN,
|
|
315
|
+
localBackendOrigin: envValues.get('OPENCODE_WIZARD_BACKEND_ORIGIN')
|
|
316
|
+
});
|
|
192
317
|
};
|
|
193
318
|
const toWorkspaceSlug = value => {
|
|
194
319
|
const normalized = value.trim().toLowerCase().replace(/[^a-z0-9-]+/gu, '-').replace(/^-+|-+$/gu, '');
|
|
@@ -304,26 +429,6 @@ const formatSkillLabel = item => {
|
|
|
304
429
|
return item.skill.name;
|
|
305
430
|
};
|
|
306
431
|
const toFrontmatterString = value => JSON.stringify(value);
|
|
307
|
-
const readJsonFile = async filePath => {
|
|
308
|
-
try {
|
|
309
|
-
const raw = await fs.readFile(filePath, 'utf8');
|
|
310
|
-
const parsed = JSON.parse(raw);
|
|
311
|
-
return parsed;
|
|
312
|
-
} catch {
|
|
313
|
-
return null;
|
|
314
|
-
}
|
|
315
|
-
};
|
|
316
|
-
const writeJsonFile = async (filePath, value) => {
|
|
317
|
-
await fs.mkdir(path.dirname(filePath), {
|
|
318
|
-
recursive: true
|
|
319
|
-
});
|
|
320
|
-
await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
321
|
-
};
|
|
322
|
-
const deleteFileIfExists = async filePath => {
|
|
323
|
-
await fs.rm(filePath, {
|
|
324
|
-
force: true
|
|
325
|
-
});
|
|
326
|
-
};
|
|
327
432
|
const isRecord = value => {
|
|
328
433
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
329
434
|
};
|
|
@@ -340,15 +445,33 @@ const readGlobalConfig = async configFile => {
|
|
|
340
445
|
return {};
|
|
341
446
|
};
|
|
342
447
|
const writeGlobalConfig = async (configFile, config) => {
|
|
343
|
-
await
|
|
448
|
+
await writePrivateJsonFile(configFile, config);
|
|
449
|
+
};
|
|
450
|
+
const withoutLegacyPublishedSkillPreferences = config => {
|
|
451
|
+
const {
|
|
452
|
+
publishedSkillPreferences,
|
|
453
|
+
ignoredPublishedSkills,
|
|
454
|
+
...safeConfig
|
|
455
|
+
} = config;
|
|
456
|
+
void publishedSkillPreferences;
|
|
457
|
+
void ignoredPublishedSkills;
|
|
458
|
+
return safeConfig;
|
|
459
|
+
};
|
|
460
|
+
const hasLegacyPublishedSkillPreferences = config => {
|
|
461
|
+
return Object.prototype.hasOwnProperty.call(config, 'publishedSkillPreferences') || Object.prototype.hasOwnProperty.call(config, 'ignoredPublishedSkills');
|
|
344
462
|
};
|
|
345
463
|
const readGlobalAuthState = async configFile => {
|
|
346
464
|
const storedConfig = await readGlobalConfig(configFile);
|
|
347
465
|
const storedAuthState = storedConfig.auth;
|
|
348
466
|
if (storedAuthState === undefined || storedAuthState === null) return null;
|
|
349
|
-
if (isAuthState(storedAuthState))
|
|
467
|
+
if (isAuthState(storedAuthState)) {
|
|
468
|
+
if (hasLegacyPublishedSkillPreferences(storedConfig)) {
|
|
469
|
+
await writeGlobalConfig(configFile, withoutLegacyPublishedSkillPreferences(storedConfig));
|
|
470
|
+
}
|
|
471
|
+
return storedAuthState;
|
|
472
|
+
}
|
|
350
473
|
await writeGlobalConfig(configFile, {
|
|
351
|
-
...storedConfig,
|
|
474
|
+
...withoutLegacyPublishedSkillPreferences(storedConfig),
|
|
352
475
|
auth: null
|
|
353
476
|
});
|
|
354
477
|
return null;
|
|
@@ -363,17 +486,43 @@ const readLegacyAuthState = async authStateFile => {
|
|
|
363
486
|
const writeAuthState = async (configFile, authState) => {
|
|
364
487
|
const storedConfig = await readGlobalConfig(configFile);
|
|
365
488
|
await writeGlobalConfig(configFile, {
|
|
366
|
-
...storedConfig,
|
|
489
|
+
...withoutLegacyPublishedSkillPreferences(storedConfig),
|
|
367
490
|
auth: authState
|
|
368
491
|
});
|
|
369
492
|
};
|
|
370
493
|
const clearAuthState = async configFile => {
|
|
371
494
|
const storedConfig = await readGlobalConfig(configFile);
|
|
372
495
|
await writeGlobalConfig(configFile, {
|
|
373
|
-
...storedConfig,
|
|
496
|
+
...withoutLegacyPublishedSkillPreferences(storedConfig),
|
|
374
497
|
auth: null
|
|
375
498
|
});
|
|
376
499
|
};
|
|
500
|
+
const toIgnoredSkillSlug = value => {
|
|
501
|
+
const normalized = value.trim().toLowerCase();
|
|
502
|
+
if (!normalized) return null;
|
|
503
|
+
return normalized;
|
|
504
|
+
};
|
|
505
|
+
const getPublishedSkillIgnoreScopeKey = (resolution, payload) => {
|
|
506
|
+
const workspaceSlug = payload?.workspace?.slug ?? resolution.fallbackWorkspaceSlug;
|
|
507
|
+
if (workspaceSlug) return `workspace:${toWorkspaceSlug(workspaceSlug)}`;
|
|
508
|
+
if (resolution.repositoryUrl) return `repository:${resolution.repositoryUrl}`;
|
|
509
|
+
return `path:${toWorkspaceSlug(path.basename(resolution.repositoryRoot))}`;
|
|
510
|
+
};
|
|
511
|
+
const toStoredUserKey = authState => {
|
|
512
|
+
if (authState?.userId) return authState.userId;
|
|
513
|
+
if (authState?.email) return authState.email.toLowerCase();
|
|
514
|
+
return 'anonymous';
|
|
515
|
+
};
|
|
516
|
+
const resolvePublishedSkillPreferenceCacheContext = async config => {
|
|
517
|
+
const authState = await readGlobalAuthState(config.authStatePath);
|
|
518
|
+
return {
|
|
519
|
+
userKey: toStoredUserKey(authState),
|
|
520
|
+
preferenceVersion: publishedSkillPreferenceCacheVersion
|
|
521
|
+
};
|
|
522
|
+
};
|
|
523
|
+
const getCatalogCacheKey = (workspaceResolution, preferenceContext) => {
|
|
524
|
+
return JSON.stringify([workspaceResolution.cacheKey, preferenceContext.userKey, preferenceContext.preferenceVersion]);
|
|
525
|
+
};
|
|
377
526
|
const toAuthState = session => ({
|
|
378
527
|
pluginId: PLUGIN_ID,
|
|
379
528
|
sessionToken: session.jwtToken,
|
|
@@ -475,11 +624,12 @@ const getPublishedSkillAssignmentCounts = items => items.reduce((counts, item) =
|
|
|
475
624
|
other: 0
|
|
476
625
|
});
|
|
477
626
|
const getSkillContextKind = item => {
|
|
478
|
-
if (item.assignmentSource === 'GLOBAL') return 'global';
|
|
627
|
+
if (item.assignmentSource === 'GLOBAL' || item.assignmentSource === 'USER_GLOBAL') return 'global';
|
|
479
628
|
return 'project';
|
|
480
629
|
};
|
|
481
630
|
const getSkillPolicyLabel = (policy, contextKind) => {
|
|
482
631
|
if (policy === 'GLOBAL_CONTEXT') return 'GLOBAL_CONTEXT · active context only, not project-installable';
|
|
632
|
+
if (contextKind === 'installable') return 'PROJECT_INSTALLABLE · available to install';
|
|
483
633
|
if (contextKind === 'global') return 'PROJECT_INSTALLABLE · active global assignment';
|
|
484
634
|
return 'PROJECT_INSTALLABLE · active project/workspace assignment';
|
|
485
635
|
};
|
|
@@ -514,10 +664,35 @@ export const toPublishedSkillDetail = item => ({
|
|
|
514
664
|
markdownBody: item.publishedArtifact.markdownBody,
|
|
515
665
|
renderedContent: item.publishedArtifact.renderedContent
|
|
516
666
|
});
|
|
667
|
+
const toInstallableSkillSummary = item => ({
|
|
668
|
+
skillSlug: item.skill.slug,
|
|
669
|
+
skillName: item.skill.name,
|
|
670
|
+
artifactName: item.publishedArtifact.frontmatterName,
|
|
671
|
+
artifactDescription: item.publishedArtifact.frontmatterDescription,
|
|
672
|
+
whenToUse: item.skill.whenToUse ?? null,
|
|
673
|
+
version: item.skillVersion.version,
|
|
674
|
+
assignmentSource: 'CATALOG',
|
|
675
|
+
assignmentType: 'PATH',
|
|
676
|
+
scopePath: '',
|
|
677
|
+
includeChildren: true,
|
|
678
|
+
checksum: item.publishedArtifact.checksum,
|
|
679
|
+
publishedAt: item.publishedArtifact.publishedAt,
|
|
680
|
+
identifiers: getSkillIdentifiers({
|
|
681
|
+
...item,
|
|
682
|
+
assignmentSource: 'CATALOG',
|
|
683
|
+
assignmentType: 'PATH',
|
|
684
|
+
scopePath: '',
|
|
685
|
+
includeChildren: true
|
|
686
|
+
}),
|
|
687
|
+
tags: item.skill.tags.map(toPublishedSkillTagSummary),
|
|
688
|
+
contextKind: 'installable',
|
|
689
|
+
installPolicy: item.skill.installPolicy,
|
|
690
|
+
policyLabel: getSkillPolicyLabel(item.skill.installPolicy, 'installable')
|
|
691
|
+
});
|
|
517
692
|
export const toPublishedSkillCatalog = payload => ({
|
|
518
693
|
pluginId: PLUGIN_ID,
|
|
519
694
|
runtimeMode: 'tool_fetch_only',
|
|
520
|
-
deliveryModel: '
|
|
695
|
+
deliveryModel: 'backend_published_installed_effective_skills',
|
|
521
696
|
workspace: payload.workspace,
|
|
522
697
|
directoryPath: payload.directoryPath,
|
|
523
698
|
rootSkillSeedPath: ROOT_SKILL_SEED_PATH,
|
|
@@ -527,6 +702,36 @@ export const toPublishedSkillCatalog = payload => ({
|
|
|
527
702
|
facets: getPublishedSkillFacets(payload.skills),
|
|
528
703
|
skills: payload.skills.map(toPublishedSkillSummary)
|
|
529
704
|
});
|
|
705
|
+
const filterIgnoredPublishedSkills = async (config, result) => {
|
|
706
|
+
const authState = await readGlobalAuthState(config.authStatePath);
|
|
707
|
+
const userKey = toStoredUserKey(authState);
|
|
708
|
+
if (!result.fetchResult.ok) {
|
|
709
|
+
return {
|
|
710
|
+
...result,
|
|
711
|
+
ignoreState: {
|
|
712
|
+
scopeKey: getPublishedSkillIgnoreScopeKey(result.workspaceResolution),
|
|
713
|
+
userKey,
|
|
714
|
+
ignoredSkillSlugs: [],
|
|
715
|
+
installedGlobalSkillSlugs: [],
|
|
716
|
+
installedWorkspaceSkillSlugs: []
|
|
717
|
+
},
|
|
718
|
+
ignoredSkills: []
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
const ignoredSkills = result.fetchResult.payload.userPreferences.ignoredSkills.map(toPublishedSkillSummary);
|
|
722
|
+
const ignoredSkillSlugs = ignoredSkills.map(skill => skill.skillSlug);
|
|
723
|
+
return {
|
|
724
|
+
...result,
|
|
725
|
+
ignoreState: {
|
|
726
|
+
scopeKey: result.fetchResult.payload.userPreferences.scopeKey,
|
|
727
|
+
userKey: result.fetchResult.payload.userPreferences.userKey || userKey,
|
|
728
|
+
ignoredSkillSlugs,
|
|
729
|
+
installedGlobalSkillSlugs: [],
|
|
730
|
+
installedWorkspaceSkillSlugs: []
|
|
731
|
+
},
|
|
732
|
+
ignoredSkills
|
|
733
|
+
};
|
|
734
|
+
};
|
|
530
735
|
const getWorkspaceUnavailableMessage = payload => {
|
|
531
736
|
if (payload.workspace) return null;
|
|
532
737
|
return 'Workspace-specific skills are unavailable because the workspace was not found; global skills are still loaded.';
|
|
@@ -601,7 +806,7 @@ const buildSkillDetailSnippetLine = detail => {
|
|
|
601
806
|
const body = detail.markdownBody || detail.renderedContent || detail.markdownDocument;
|
|
602
807
|
return `- ${detail.artifactName || detail.skillName}: ${truncateText(body, 700)}`;
|
|
603
808
|
};
|
|
604
|
-
const buildSystemNote = (result, config, details) => {
|
|
809
|
+
export const buildSystemNote = (result, config, details) => {
|
|
605
810
|
if (!result.fetchResult.ok) return null;
|
|
606
811
|
const catalog = toPublishedSkillCatalog(result.fetchResult.payload);
|
|
607
812
|
const skillNames = catalog.skills.map(skill => skill.artifactName || skill.skillName || skill.skillSlug);
|
|
@@ -612,7 +817,7 @@ const buildSystemNote = (result, config, details) => {
|
|
|
612
817
|
const projectSkills = catalog.skills.filter(skill => skill.contextKind === 'project').slice(0, 5).map(buildSkillCatalogLine);
|
|
613
818
|
const detailLines = details.slice(0, SYSTEM_NOTE_DETAIL_LIMIT).map(buildSkillDetailSnippetLine);
|
|
614
819
|
const detailBlock = detailLines.length > 0 ? ` Loaded body snippets (capped):\n${truncateText(detailLines.join('\n'), SYSTEM_NOTE_DETAIL_CHAR_LIMIT)}` : '';
|
|
615
|
-
return [result.fetchResult.payload.workspace ? `opencode-wizard published
|
|
820
|
+
return [result.fetchResult.payload.workspace ? `Prefer opencode-wizard backend-published fetched skill bodies for scoped/private wizard skills in workspace ${result.fetchResult.payload.workspace.slug}.` : 'Prefer opencode-wizard backend-published global fetched skill bodies; workspace-specific skills are unavailable because the workspace was not found.', `Current directory: ${result.directoryPath}.`, `Published skills for this scope: ${renderedSkillNames}${renderedCountSuffix}; counts: ${catalog.assignmentCounts.global} global, ${catalog.assignmentCounts.project} project, ${catalog.assignmentCounts.other} other.`, 'Use catalog whenToUse guidance to decide applicability; when it matches the task, fetch full bodies with opencode_wizard_published_skills_fetch and prefer those fetched bodies for current scoped/private wizard guidance.', 'GLOBAL_CONTEXT skills are active context skills and are not project-installable; PROJECT_INSTALLABLE skills can be assigned globally or to project/workspace scopes; assignment rows decide which skills are active here.', globalSkills.length > 0 ? `Global context skills:\n${globalSkills.join('\n')}` : 'Global context skills: none.', projectSkills.length > 0 ? `Project-scoped active skills:\n${projectSkills.join('\n')}` : 'Project-scoped active skills: none.', detailBlock, 'Local/native sources can still complement wizard skills: .opencode/skills is source seed content, skills.urls is a public/static complement, and backend-published fetched bodies are preferred for private/scoped wizard guidance.', `Root source seed path remains seed/source content: ${config.rootSkillSeedPath}/**.`].filter(line => line.length > 0).join(' ');
|
|
616
821
|
};
|
|
617
822
|
const toWorkspaceResolutionOutput = resolution => ({
|
|
618
823
|
requestedDirectory: resolution.requestedDirectory,
|
|
@@ -629,6 +834,7 @@ const toWorkspaceResolutionMetadata = resolution => ({
|
|
|
629
834
|
});
|
|
630
835
|
const formatStatusOutput = async (worktree, config, publishedSkillsResult, loginBootstrapSnapshot) => {
|
|
631
836
|
const authState = await resolveStoredAuthState(worktree, config);
|
|
837
|
+
const filteredResult = await filterIgnoredPublishedSkills(config, publishedSkillsResult);
|
|
632
838
|
const base = {
|
|
633
839
|
pluginId: PLUGIN_ID,
|
|
634
840
|
runtimeMode: 'tool_fetch_only',
|
|
@@ -657,21 +863,26 @@ const formatStatusOutput = async (worktree, config, publishedSkillsResult, login
|
|
|
657
863
|
email: loginBootstrapSnapshot.email,
|
|
658
864
|
message: loginBootstrapSnapshot.message
|
|
659
865
|
},
|
|
660
|
-
status:
|
|
661
|
-
fetchedAt:
|
|
662
|
-
source:
|
|
663
|
-
availableTools: AVAILABLE_PUBLISHED_SKILL_TOOLS
|
|
866
|
+
status: filteredResult.fetchResult.status,
|
|
867
|
+
fetchedAt: filteredResult.fetchResult.fetchedAt,
|
|
868
|
+
source: filteredResult.fetchResult.source,
|
|
869
|
+
availableTools: AVAILABLE_PUBLISHED_SKILL_TOOLS,
|
|
870
|
+
ignoredPublishedSkills: {
|
|
871
|
+
scopeKey: filteredResult.ignoreState.scopeKey,
|
|
872
|
+
userKey: filteredResult.ignoreState.userKey,
|
|
873
|
+
count: filteredResult.ignoreState.ignoredSkillSlugs.length
|
|
874
|
+
}
|
|
664
875
|
};
|
|
665
|
-
if (!
|
|
876
|
+
if (!filteredResult.fetchResult.ok) {
|
|
666
877
|
return JSON.stringify({
|
|
667
878
|
...base,
|
|
668
|
-
message:
|
|
879
|
+
message: filteredResult.fetchResult.message
|
|
669
880
|
}, null, 2);
|
|
670
881
|
}
|
|
671
882
|
return JSON.stringify({
|
|
672
883
|
...base,
|
|
673
|
-
...toPublishedSkillCatalog(
|
|
674
|
-
message: getWorkspaceUnavailableMessage(
|
|
884
|
+
...toPublishedSkillCatalog(filteredResult.fetchResult.payload),
|
|
885
|
+
message: getWorkspaceUnavailableMessage(filteredResult.fetchResult.payload)
|
|
675
886
|
}, null, 2);
|
|
676
887
|
};
|
|
677
888
|
export const toPluginAuthStateSummary = authState => {
|
|
@@ -703,6 +914,11 @@ export const resolvePluginStatusSnapshot = async ({
|
|
|
703
914
|
directory
|
|
704
915
|
});
|
|
705
916
|
const fetchResult = await fetchPublishedSkillsCatalog(worktree, config, workspaceResolution, signal);
|
|
917
|
+
const filteredResult = await filterIgnoredPublishedSkills(config, {
|
|
918
|
+
directoryPath: workspaceResolution.directoryPath,
|
|
919
|
+
workspaceResolution,
|
|
920
|
+
fetchResult
|
|
921
|
+
});
|
|
706
922
|
const authState = await resolveStoredAuthState(worktree, config);
|
|
707
923
|
return {
|
|
708
924
|
pluginId: PLUGIN_ID,
|
|
@@ -715,19 +931,43 @@ export const resolvePluginStatusSnapshot = async ({
|
|
|
715
931
|
rootSkillSeedPath: config.rootSkillSeedPath,
|
|
716
932
|
authStatePath: config.authStatePath,
|
|
717
933
|
authState: toPluginAuthStateSummary(authState),
|
|
718
|
-
status: fetchResult.status,
|
|
719
|
-
authMode: fetchResult.authMode,
|
|
720
|
-
fetchedAt: fetchResult.fetchedAt,
|
|
721
|
-
source: fetchResult.source,
|
|
934
|
+
status: filteredResult.fetchResult.status,
|
|
935
|
+
authMode: filteredResult.fetchResult.authMode,
|
|
936
|
+
fetchedAt: filteredResult.fetchResult.fetchedAt,
|
|
937
|
+
source: filteredResult.fetchResult.source,
|
|
722
938
|
availableTools: AVAILABLE_PUBLISHED_SKILL_TOOLS,
|
|
723
|
-
message: fetchResult.ok ? getWorkspaceUnavailableMessage(fetchResult.payload) : fetchResult.message,
|
|
724
|
-
catalog: fetchResult.ok ? toPublishedSkillCatalog(fetchResult.payload) : null
|
|
939
|
+
message: filteredResult.fetchResult.ok ? getWorkspaceUnavailableMessage(filteredResult.fetchResult.payload) : filteredResult.fetchResult.message,
|
|
940
|
+
catalog: filteredResult.fetchResult.ok ? toPublishedSkillCatalog(filteredResult.fetchResult.payload) : null,
|
|
941
|
+
installableCatalog: filteredResult.fetchResult.ok ? {
|
|
942
|
+
count: filteredResult.fetchResult.payload.catalogSkills.length,
|
|
943
|
+
skills: filteredResult.fetchResult.payload.catalogSkills.map(toInstallableSkillSummary)
|
|
944
|
+
} : null,
|
|
945
|
+
ignoredPublishedSkills: {
|
|
946
|
+
scopeKey: filteredResult.ignoreState.scopeKey,
|
|
947
|
+
userKey: filteredResult.ignoreState.userKey,
|
|
948
|
+
count: filteredResult.ignoreState.ignoredSkillSlugs.length,
|
|
949
|
+
skills: filteredResult.ignoredSkills
|
|
950
|
+
}
|
|
725
951
|
};
|
|
726
952
|
};
|
|
727
953
|
const withStatusMessage = (snapshot, message) => ({
|
|
728
954
|
...snapshot,
|
|
729
955
|
message
|
|
730
956
|
});
|
|
957
|
+
const toAiFacingPluginStatusSnapshot = snapshot => {
|
|
958
|
+
const {
|
|
959
|
+
ignoredPublishedSkills,
|
|
960
|
+
installableCatalog: _installableCatalog,
|
|
961
|
+
...safeSnapshot
|
|
962
|
+
} = snapshot;
|
|
963
|
+
return {
|
|
964
|
+
...safeSnapshot,
|
|
965
|
+
ignoredPublishedSkills: {
|
|
966
|
+
scopeKey: ignoredPublishedSkills.scopeKey,
|
|
967
|
+
count: ignoredPublishedSkills.count
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
};
|
|
731
971
|
const startStatusPathLoginBootstrap = (worktree, config) => {
|
|
732
972
|
if (statusPathLoginBootstrap.promise) return;
|
|
733
973
|
if (statusPathLoginBootstrap.status === 'failed' && statusPathLoginBootstrap.failedAt && Date.now() - statusPathLoginBootstrap.failedAt < STATUS_PATH_LOGIN_RETRY_COOLDOWN_MS) {
|
|
@@ -794,6 +1034,93 @@ export const resolvePluginStatusSnapshotWithAuthBootstrap = async ({
|
|
|
794
1034
|
}
|
|
795
1035
|
return withStatusMessage(snapshot, 'Browser login is pending from the TUI/status path.');
|
|
796
1036
|
};
|
|
1037
|
+
const toBackendPreferenceScope = preferenceScope => {
|
|
1038
|
+
if (preferenceScope === 'global') return 'GLOBAL';
|
|
1039
|
+
return 'WORKSPACE';
|
|
1040
|
+
};
|
|
1041
|
+
const setPublishedSkillPreference = async ({
|
|
1042
|
+
worktree,
|
|
1043
|
+
directory,
|
|
1044
|
+
config,
|
|
1045
|
+
skillSlug,
|
|
1046
|
+
preferenceScope,
|
|
1047
|
+
installed,
|
|
1048
|
+
ignored
|
|
1049
|
+
}) => {
|
|
1050
|
+
const workspaceResolution = await resolveWorkspace({
|
|
1051
|
+
config,
|
|
1052
|
+
directory
|
|
1053
|
+
});
|
|
1054
|
+
const response = await fetchPublishedSkillsGraphQl({
|
|
1055
|
+
worktree,
|
|
1056
|
+
config,
|
|
1057
|
+
query: SET_PUBLISHED_SKILL_PREFERENCE_MUTATION,
|
|
1058
|
+
variables: {
|
|
1059
|
+
input: {
|
|
1060
|
+
...toDeliveryInput(workspaceResolution),
|
|
1061
|
+
skillSlug,
|
|
1062
|
+
preferenceScope: toBackendPreferenceScope(preferenceScope),
|
|
1063
|
+
installed,
|
|
1064
|
+
ignored
|
|
1065
|
+
}
|
|
1066
|
+
},
|
|
1067
|
+
signal: AbortSignal.timeout(PRESENCE_EVENT_TIMEOUT_MS)
|
|
1068
|
+
});
|
|
1069
|
+
if (!response.ok) {
|
|
1070
|
+
throw new Error(response.result.message);
|
|
1071
|
+
}
|
|
1072
|
+
const preferences = response.data.setPublishedSkillPreference;
|
|
1073
|
+
publishedSkillPreferenceCacheVersion += 1;
|
|
1074
|
+
return {
|
|
1075
|
+
scopeKey: preferences.scopeKey,
|
|
1076
|
+
userKey: preferences.userKey,
|
|
1077
|
+
ignoredSkillSlugs: preferences.ignoredSkills.map(item => item.skill.slug),
|
|
1078
|
+
installedGlobalSkillSlugs: [],
|
|
1079
|
+
installedWorkspaceSkillSlugs: []
|
|
1080
|
+
};
|
|
1081
|
+
};
|
|
1082
|
+
export const setPublishedSkillIgnored = async ({
|
|
1083
|
+
worktree,
|
|
1084
|
+
directory,
|
|
1085
|
+
skillSlug,
|
|
1086
|
+
ignored,
|
|
1087
|
+
preferenceScope
|
|
1088
|
+
}) => {
|
|
1089
|
+
const config = await resolveConfig(worktree);
|
|
1090
|
+
const normalizedSkillSlug = toIgnoredSkillSlug(skillSlug);
|
|
1091
|
+
if (!normalizedSkillSlug) {
|
|
1092
|
+
throw new Error('Cannot toggle an empty published skill slug.');
|
|
1093
|
+
}
|
|
1094
|
+
return setPublishedSkillPreference({
|
|
1095
|
+
worktree,
|
|
1096
|
+
directory,
|
|
1097
|
+
config,
|
|
1098
|
+
skillSlug: normalizedSkillSlug,
|
|
1099
|
+
preferenceScope: preferenceScope ?? 'project',
|
|
1100
|
+
ignored
|
|
1101
|
+
});
|
|
1102
|
+
};
|
|
1103
|
+
export const setPublishedSkillInstalled = async ({
|
|
1104
|
+
worktree,
|
|
1105
|
+
directory,
|
|
1106
|
+
skillSlug,
|
|
1107
|
+
installed,
|
|
1108
|
+
preferenceScope
|
|
1109
|
+
}) => {
|
|
1110
|
+
const config = await resolveConfig(worktree);
|
|
1111
|
+
const normalizedSkillSlug = toIgnoredSkillSlug(skillSlug);
|
|
1112
|
+
if (!normalizedSkillSlug) {
|
|
1113
|
+
throw new Error('Cannot toggle an empty published skill slug.');
|
|
1114
|
+
}
|
|
1115
|
+
return setPublishedSkillPreference({
|
|
1116
|
+
worktree,
|
|
1117
|
+
directory,
|
|
1118
|
+
config,
|
|
1119
|
+
skillSlug: normalizedSkillSlug,
|
|
1120
|
+
preferenceScope,
|
|
1121
|
+
installed
|
|
1122
|
+
});
|
|
1123
|
+
};
|
|
797
1124
|
const toPluginStatusMetadata = snapshot => ({
|
|
798
1125
|
backendOrigin: snapshot.backendOrigin,
|
|
799
1126
|
graphqlUrl: snapshot.graphqlUrl,
|
|
@@ -1503,11 +1830,11 @@ const openBrowser = async url => {
|
|
|
1503
1830
|
const normalizeDirectoryArg = (contextDirectory, directory) => {
|
|
1504
1831
|
return normalizeAbsolutePath(directory ? path.resolve(contextDirectory, directory) : contextDirectory);
|
|
1505
1832
|
};
|
|
1506
|
-
const getDetailCacheKey = (
|
|
1507
|
-
return JSON.stringify([
|
|
1833
|
+
const getDetailCacheKey = (catalogCacheKey, skillVersionId) => {
|
|
1834
|
+
return JSON.stringify([catalogCacheKey, skillVersionId]);
|
|
1508
1835
|
};
|
|
1509
|
-
const getDetailInflightKey = (
|
|
1510
|
-
return JSON.stringify([
|
|
1836
|
+
const getDetailInflightKey = (catalogCacheKey, skillVersionId, purpose) => {
|
|
1837
|
+
return JSON.stringify([catalogCacheKey, skillVersionId, purpose]);
|
|
1511
1838
|
};
|
|
1512
1839
|
const OpencodeWizardSkillsPlugin = async input => {
|
|
1513
1840
|
const {
|
|
@@ -1727,7 +2054,8 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1727
2054
|
directory
|
|
1728
2055
|
});
|
|
1729
2056
|
const directoryPath = workspaceResolution.directoryPath;
|
|
1730
|
-
const
|
|
2057
|
+
const preferenceContext = await resolvePublishedSkillPreferenceCacheContext(config);
|
|
2058
|
+
const cacheKey = getCatalogCacheKey(workspaceResolution, preferenceContext);
|
|
1731
2059
|
const cached = cache.get(cacheKey);
|
|
1732
2060
|
if (useCache && cached && cached.expiresAt > Date.now()) {
|
|
1733
2061
|
return {
|
|
@@ -1770,8 +2098,10 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1770
2098
|
purpose
|
|
1771
2099
|
}) => {
|
|
1772
2100
|
const directoryPath = workspaceResolution.directoryPath;
|
|
1773
|
-
const
|
|
1774
|
-
const
|
|
2101
|
+
const preferenceContext = await resolvePublishedSkillPreferenceCacheContext(config);
|
|
2102
|
+
const catalogCacheKey = getCatalogCacheKey(workspaceResolution, preferenceContext);
|
|
2103
|
+
const cacheKey = getDetailCacheKey(catalogCacheKey, item.skillVersion.id);
|
|
2104
|
+
const inflightKey = getDetailInflightKey(catalogCacheKey, item.skillVersion.id, purpose);
|
|
1775
2105
|
const cached = detailCache.get(cacheKey);
|
|
1776
2106
|
if (purpose === 'SYSTEM_CONTEXT' && useCache && cached && cached.expiresAt > Date.now()) {
|
|
1777
2107
|
return {
|
|
@@ -1911,18 +2241,29 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1911
2241
|
loginBootstrapSnapshot: loginBootstrap.snapshot
|
|
1912
2242
|
});
|
|
1913
2243
|
}
|
|
1914
|
-
const
|
|
2244
|
+
const filteredPublishedSkillsResult = await filterIgnoredPublishedSkills(config, publishedSkillsResult);
|
|
2245
|
+
if (!filteredPublishedSkillsResult.fetchResult.ok) {
|
|
2246
|
+
await emitFetchOutcome('FETCH_FAILED');
|
|
2247
|
+
return toFetchFailureOutput({
|
|
2248
|
+
worktree: input.worktree,
|
|
2249
|
+
config,
|
|
2250
|
+
publishedSkillsResult: filteredPublishedSkillsResult,
|
|
2251
|
+
loginBootstrapSnapshot: loginBootstrap.snapshot
|
|
2252
|
+
});
|
|
2253
|
+
}
|
|
2254
|
+
const selection = selectPublishedSkills(filteredPublishedSkillsResult.fetchResult.payload, requestedSkills);
|
|
1915
2255
|
const isSingleRequest = requestedSkills.length === 1;
|
|
1916
2256
|
if (requestedSkills.length === 0) {
|
|
1917
|
-
const catalog = toPublishedSkillCatalog(
|
|
2257
|
+
const catalog = toPublishedSkillCatalog(filteredPublishedSkillsResult.fetchResult.payload);
|
|
1918
2258
|
context.metadata({
|
|
1919
|
-
title: `opencode-wizard published skills catalog: ${catalog.publishedSkillCount}`,
|
|
2259
|
+
title: `opencode-wizard published skills catalog: ${catalog.publishedSkillCount} active`,
|
|
1920
2260
|
metadata: {
|
|
1921
|
-
...toWorkspaceResolutionMetadata(
|
|
2261
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
1922
2262
|
status: 'ready',
|
|
1923
2263
|
publishedSkillCount: catalog.publishedSkillCount.toString(),
|
|
1924
2264
|
globalAssignmentCount: catalog.assignmentCounts.global.toString(),
|
|
1925
|
-
projectAssignmentCount: catalog.assignmentCounts.project.toString()
|
|
2265
|
+
projectAssignmentCount: catalog.assignmentCounts.project.toString(),
|
|
2266
|
+
ignoredSkillCount: filteredPublishedSkillsResult.ignoreState.ignoredSkillSlugs.length.toString()
|
|
1926
2267
|
}
|
|
1927
2268
|
});
|
|
1928
2269
|
await emitFetchOutcome('FETCH_SUCCESS');
|
|
@@ -1930,16 +2271,21 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1930
2271
|
output: JSON.stringify({
|
|
1931
2272
|
...catalog,
|
|
1932
2273
|
status: 'ready',
|
|
1933
|
-
requestedDirectoryPath:
|
|
1934
|
-
workspaceResolution: toWorkspaceResolutionOutput(
|
|
1935
|
-
|
|
1936
|
-
|
|
2274
|
+
requestedDirectoryPath: filteredPublishedSkillsResult.directoryPath,
|
|
2275
|
+
workspaceResolution: toWorkspaceResolutionOutput(filteredPublishedSkillsResult.workspaceResolution),
|
|
2276
|
+
ignoredPublishedSkills: {
|
|
2277
|
+
scopeKey: filteredPublishedSkillsResult.ignoreState.scopeKey,
|
|
2278
|
+
count: filteredPublishedSkillsResult.ignoreState.ignoredSkillSlugs.length
|
|
2279
|
+
},
|
|
2280
|
+
fetchedAt: filteredPublishedSkillsResult.fetchResult.fetchedAt,
|
|
2281
|
+
source: filteredPublishedSkillsResult.fetchResult.source,
|
|
1937
2282
|
message: 'Catalog discovery only. Provide `skill` or `skills` to fetch markdown bodies/details for selected skills.'
|
|
1938
2283
|
}, null, 2),
|
|
1939
2284
|
metadata: {
|
|
1940
2285
|
status: 'ready',
|
|
1941
|
-
...toWorkspaceResolutionMetadata(
|
|
1942
|
-
publishedSkillCount: catalog.publishedSkillCount.toString()
|
|
2286
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
2287
|
+
publishedSkillCount: catalog.publishedSkillCount.toString(),
|
|
2288
|
+
ignoredSkillCount: filteredPublishedSkillsResult.ignoreState.ignoredSkillSlugs.length.toString()
|
|
1943
2289
|
}
|
|
1944
2290
|
};
|
|
1945
2291
|
}
|
|
@@ -1950,19 +2296,23 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1950
2296
|
pluginId: PLUGIN_ID,
|
|
1951
2297
|
runtimeMode: 'tool_fetch_only',
|
|
1952
2298
|
status: 'not_found',
|
|
1953
|
-
requestedDirectoryPath:
|
|
1954
|
-
workspaceResolution: toWorkspaceResolutionOutput(
|
|
2299
|
+
requestedDirectoryPath: filteredPublishedSkillsResult.directoryPath,
|
|
2300
|
+
workspaceResolution: toWorkspaceResolutionOutput(filteredPublishedSkillsResult.workspaceResolution),
|
|
1955
2301
|
requestedSkill: requestedSkills[0],
|
|
1956
|
-
availableSkills:
|
|
2302
|
+
availableSkills: filteredPublishedSkillsResult.fetchResult.payload.skills.map(toPublishedSkillSummary),
|
|
2303
|
+
ignoredPublishedSkills: {
|
|
2304
|
+
scopeKey: filteredPublishedSkillsResult.ignoreState.scopeKey,
|
|
2305
|
+
count: filteredPublishedSkillsResult.ignoreState.ignoredSkillSlugs.length
|
|
2306
|
+
}
|
|
1957
2307
|
}, null, 2),
|
|
1958
2308
|
metadata: {
|
|
1959
2309
|
status: 'not_found',
|
|
1960
|
-
...toWorkspaceResolutionMetadata(
|
|
2310
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution)
|
|
1961
2311
|
}
|
|
1962
2312
|
};
|
|
1963
2313
|
}
|
|
1964
2314
|
let skillDetailResults = await Promise.all(selection.selectedItems.map(item => loadPublishedSkillDetail({
|
|
1965
|
-
workspaceResolution:
|
|
2315
|
+
workspaceResolution: filteredPublishedSkillsResult.workspaceResolution,
|
|
1966
2316
|
item,
|
|
1967
2317
|
signal: context.abort,
|
|
1968
2318
|
useCache: !args.refresh,
|
|
@@ -1974,7 +2324,7 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1974
2324
|
await schedulePresenceStart(authState);
|
|
1975
2325
|
});
|
|
1976
2326
|
skillDetailResults = await Promise.all(selection.selectedItems.map(item => loadPublishedSkillDetail({
|
|
1977
|
-
workspaceResolution:
|
|
2327
|
+
workspaceResolution: filteredPublishedSkillsResult.workspaceResolution,
|
|
1978
2328
|
item,
|
|
1979
2329
|
signal: context.abort,
|
|
1980
2330
|
useCache: false,
|
|
@@ -2000,7 +2350,7 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2000
2350
|
context.metadata({
|
|
2001
2351
|
title: `opencode-wizard published skill: ${detail.artifactName || detail.skillName}`,
|
|
2002
2352
|
metadata: {
|
|
2003
|
-
...toWorkspaceResolutionMetadata(
|
|
2353
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
2004
2354
|
skillSlug: detail.skillSlug,
|
|
2005
2355
|
version: detail.version
|
|
2006
2356
|
}
|
|
@@ -2010,16 +2360,16 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2010
2360
|
output: JSON.stringify({
|
|
2011
2361
|
pluginId: PLUGIN_ID,
|
|
2012
2362
|
runtimeMode: 'tool_fetch_only',
|
|
2013
|
-
requestedDirectoryPath:
|
|
2014
|
-
workspaceResolution: toWorkspaceResolutionOutput(
|
|
2015
|
-
workspace:
|
|
2016
|
-
fetchedAt:
|
|
2017
|
-
source:
|
|
2363
|
+
requestedDirectoryPath: filteredPublishedSkillsResult.directoryPath,
|
|
2364
|
+
workspaceResolution: toWorkspaceResolutionOutput(filteredPublishedSkillsResult.workspaceResolution),
|
|
2365
|
+
workspace: filteredPublishedSkillsResult.fetchResult.payload.workspace,
|
|
2366
|
+
fetchedAt: filteredPublishedSkillsResult.fetchResult.fetchedAt,
|
|
2367
|
+
source: filteredPublishedSkillsResult.fetchResult.source,
|
|
2018
2368
|
skill: detail
|
|
2019
2369
|
}, null, 2),
|
|
2020
2370
|
metadata: {
|
|
2021
2371
|
status: 'ready',
|
|
2022
|
-
...toWorkspaceResolutionMetadata(
|
|
2372
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
2023
2373
|
skillSlug: detail.skillSlug
|
|
2024
2374
|
}
|
|
2025
2375
|
};
|
|
@@ -2027,7 +2377,7 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2027
2377
|
context.metadata({
|
|
2028
2378
|
title: `opencode-wizard published skills fetch: ${skillDetails.length}`,
|
|
2029
2379
|
metadata: {
|
|
2030
|
-
...toWorkspaceResolutionMetadata(
|
|
2380
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
2031
2381
|
requestedCount: requestedSkills.length.toString(),
|
|
2032
2382
|
matchedCount: skillDetails.length.toString()
|
|
2033
2383
|
}
|
|
@@ -2037,18 +2387,18 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2037
2387
|
output: JSON.stringify({
|
|
2038
2388
|
pluginId: PLUGIN_ID,
|
|
2039
2389
|
runtimeMode: 'tool_fetch_only',
|
|
2040
|
-
requestedDirectoryPath:
|
|
2041
|
-
workspaceResolution: toWorkspaceResolutionOutput(
|
|
2042
|
-
workspace:
|
|
2043
|
-
fetchedAt:
|
|
2044
|
-
source:
|
|
2390
|
+
requestedDirectoryPath: filteredPublishedSkillsResult.directoryPath,
|
|
2391
|
+
workspaceResolution: toWorkspaceResolutionOutput(filteredPublishedSkillsResult.workspaceResolution),
|
|
2392
|
+
workspace: filteredPublishedSkillsResult.fetchResult.payload.workspace,
|
|
2393
|
+
fetchedAt: filteredPublishedSkillsResult.fetchResult.fetchedAt,
|
|
2394
|
+
source: filteredPublishedSkillsResult.fetchResult.source,
|
|
2045
2395
|
requestedSkills,
|
|
2046
2396
|
missingSkills: selection.missingIdentifiers,
|
|
2047
2397
|
skills: skillDetails
|
|
2048
2398
|
}, null, 2),
|
|
2049
2399
|
metadata: {
|
|
2050
2400
|
status: selection.missingIdentifiers.length > 0 ? 'partial' : 'ready',
|
|
2051
|
-
...toWorkspaceResolutionMetadata(
|
|
2401
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
2052
2402
|
matchedCount: skillDetails.length.toString()
|
|
2053
2403
|
}
|
|
2054
2404
|
};
|
|
@@ -2083,7 +2433,7 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2083
2433
|
metadata
|
|
2084
2434
|
});
|
|
2085
2435
|
return {
|
|
2086
|
-
output: JSON.stringify(snapshot, null, 2),
|
|
2436
|
+
output: JSON.stringify(toAiFacingPluginStatusSnapshot(snapshot), null, 2),
|
|
2087
2437
|
metadata
|
|
2088
2438
|
};
|
|
2089
2439
|
};
|
|
@@ -2143,11 +2493,12 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2143
2493
|
return;
|
|
2144
2494
|
}
|
|
2145
2495
|
}
|
|
2496
|
+
const filteredPublishedSkillsResult = await filterIgnoredPublishedSkills(config, publishedSkillsResult);
|
|
2146
2497
|
const details = await loadSystemNoteDetails({
|
|
2147
|
-
publishedSkillsResult,
|
|
2498
|
+
publishedSkillsResult: filteredPublishedSkillsResult,
|
|
2148
2499
|
signal: AbortSignal.timeout(5_000)
|
|
2149
2500
|
});
|
|
2150
|
-
const systemNote = buildSystemNote(
|
|
2501
|
+
const systemNote = buildSystemNote(filteredPublishedSkillsResult, config, details);
|
|
2151
2502
|
if (!systemNote) return;
|
|
2152
2503
|
output.system.push(systemNote);
|
|
2153
2504
|
}
|