@aexol/opencode-wizard 0.1.14 → 0.1.15
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/dist/server.d.ts +43 -2
- package/dist/server.js +439 -61
- 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/tui.js +350 -185
- package/dist/tui.js.map +1 -1
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -54,6 +54,7 @@ const statusPathLoginBootstrap = {
|
|
|
54
54
|
};
|
|
55
55
|
const importOpencodePluginModule = new Function('specifier', 'return import(specifier)');
|
|
56
56
|
export const AVAILABLE_PUBLISHED_SKILL_TOOLS = ['opencode_wizard_published_skills_fetch', 'opencode_wizard_status'];
|
|
57
|
+
let publishedSkillPreferenceCacheVersion = 0;
|
|
57
58
|
export const NATIVE_SKILLS_URL_COMPATIBILITY = {
|
|
58
59
|
configKey: 'skills.urls',
|
|
59
60
|
deliveryMode: 'public_static_registry',
|
|
@@ -114,6 +115,137 @@ const PUBLISHED_SKILLS_CATALOG_QUERY = `
|
|
|
114
115
|
publishedAt
|
|
115
116
|
}
|
|
116
117
|
}
|
|
118
|
+
catalogSkills {
|
|
119
|
+
skill {
|
|
120
|
+
id
|
|
121
|
+
slug
|
|
122
|
+
name
|
|
123
|
+
summary
|
|
124
|
+
whenToUse
|
|
125
|
+
status
|
|
126
|
+
installPolicy
|
|
127
|
+
tags {
|
|
128
|
+
id
|
|
129
|
+
slug
|
|
130
|
+
label
|
|
131
|
+
description
|
|
132
|
+
facet {
|
|
133
|
+
id
|
|
134
|
+
slug
|
|
135
|
+
label
|
|
136
|
+
description
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
skillVersion {
|
|
141
|
+
id
|
|
142
|
+
version
|
|
143
|
+
title
|
|
144
|
+
summary
|
|
145
|
+
status
|
|
146
|
+
}
|
|
147
|
+
publishedArtifact {
|
|
148
|
+
id
|
|
149
|
+
frontmatterName
|
|
150
|
+
frontmatterDescription
|
|
151
|
+
checksum
|
|
152
|
+
publishedAt
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
userPreferences {
|
|
156
|
+
scopeKey
|
|
157
|
+
userKey
|
|
158
|
+
ignoredSkills {
|
|
159
|
+
assignmentSource
|
|
160
|
+
assignmentType
|
|
161
|
+
scopePath
|
|
162
|
+
includeChildren
|
|
163
|
+
skill {
|
|
164
|
+
id
|
|
165
|
+
slug
|
|
166
|
+
name
|
|
167
|
+
summary
|
|
168
|
+
whenToUse
|
|
169
|
+
status
|
|
170
|
+
installPolicy
|
|
171
|
+
tags {
|
|
172
|
+
id
|
|
173
|
+
slug
|
|
174
|
+
label
|
|
175
|
+
description
|
|
176
|
+
facet {
|
|
177
|
+
id
|
|
178
|
+
slug
|
|
179
|
+
label
|
|
180
|
+
description
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
skillVersion {
|
|
185
|
+
id
|
|
186
|
+
version
|
|
187
|
+
title
|
|
188
|
+
summary
|
|
189
|
+
status
|
|
190
|
+
}
|
|
191
|
+
publishedArtifact {
|
|
192
|
+
id
|
|
193
|
+
frontmatterName
|
|
194
|
+
frontmatterDescription
|
|
195
|
+
checksum
|
|
196
|
+
publishedAt
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
`;
|
|
203
|
+
const SET_PUBLISHED_SKILL_PREFERENCE_MUTATION = `
|
|
204
|
+
mutation SetPublishedSkillPreference($input: SetPublishedSkillPreferenceInput!) {
|
|
205
|
+
setPublishedSkillPreference(input: $input) {
|
|
206
|
+
scopeKey
|
|
207
|
+
userKey
|
|
208
|
+
ignoredSkills {
|
|
209
|
+
assignmentSource
|
|
210
|
+
assignmentType
|
|
211
|
+
scopePath
|
|
212
|
+
includeChildren
|
|
213
|
+
skill {
|
|
214
|
+
id
|
|
215
|
+
slug
|
|
216
|
+
name
|
|
217
|
+
summary
|
|
218
|
+
whenToUse
|
|
219
|
+
status
|
|
220
|
+
installPolicy
|
|
221
|
+
tags {
|
|
222
|
+
id
|
|
223
|
+
slug
|
|
224
|
+
label
|
|
225
|
+
description
|
|
226
|
+
facet {
|
|
227
|
+
id
|
|
228
|
+
slug
|
|
229
|
+
label
|
|
230
|
+
description
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
skillVersion {
|
|
235
|
+
id
|
|
236
|
+
version
|
|
237
|
+
title
|
|
238
|
+
summary
|
|
239
|
+
status
|
|
240
|
+
}
|
|
241
|
+
publishedArtifact {
|
|
242
|
+
id
|
|
243
|
+
frontmatterName
|
|
244
|
+
frontmatterDescription
|
|
245
|
+
checksum
|
|
246
|
+
publishedAt
|
|
247
|
+
}
|
|
248
|
+
}
|
|
117
249
|
}
|
|
118
250
|
}
|
|
119
251
|
`;
|
|
@@ -342,13 +474,31 @@ const readGlobalConfig = async configFile => {
|
|
|
342
474
|
const writeGlobalConfig = async (configFile, config) => {
|
|
343
475
|
await writeJsonFile(configFile, config);
|
|
344
476
|
};
|
|
477
|
+
const withoutLegacyPublishedSkillPreferences = config => {
|
|
478
|
+
const {
|
|
479
|
+
publishedSkillPreferences,
|
|
480
|
+
ignoredPublishedSkills,
|
|
481
|
+
...safeConfig
|
|
482
|
+
} = config;
|
|
483
|
+
void publishedSkillPreferences;
|
|
484
|
+
void ignoredPublishedSkills;
|
|
485
|
+
return safeConfig;
|
|
486
|
+
};
|
|
487
|
+
const hasLegacyPublishedSkillPreferences = config => {
|
|
488
|
+
return Object.prototype.hasOwnProperty.call(config, 'publishedSkillPreferences') || Object.prototype.hasOwnProperty.call(config, 'ignoredPublishedSkills');
|
|
489
|
+
};
|
|
345
490
|
const readGlobalAuthState = async configFile => {
|
|
346
491
|
const storedConfig = await readGlobalConfig(configFile);
|
|
347
492
|
const storedAuthState = storedConfig.auth;
|
|
348
493
|
if (storedAuthState === undefined || storedAuthState === null) return null;
|
|
349
|
-
if (isAuthState(storedAuthState))
|
|
494
|
+
if (isAuthState(storedAuthState)) {
|
|
495
|
+
if (hasLegacyPublishedSkillPreferences(storedConfig)) {
|
|
496
|
+
await writeGlobalConfig(configFile, withoutLegacyPublishedSkillPreferences(storedConfig));
|
|
497
|
+
}
|
|
498
|
+
return storedAuthState;
|
|
499
|
+
}
|
|
350
500
|
await writeGlobalConfig(configFile, {
|
|
351
|
-
...storedConfig,
|
|
501
|
+
...withoutLegacyPublishedSkillPreferences(storedConfig),
|
|
352
502
|
auth: null
|
|
353
503
|
});
|
|
354
504
|
return null;
|
|
@@ -363,17 +513,43 @@ const readLegacyAuthState = async authStateFile => {
|
|
|
363
513
|
const writeAuthState = async (configFile, authState) => {
|
|
364
514
|
const storedConfig = await readGlobalConfig(configFile);
|
|
365
515
|
await writeGlobalConfig(configFile, {
|
|
366
|
-
...storedConfig,
|
|
516
|
+
...withoutLegacyPublishedSkillPreferences(storedConfig),
|
|
367
517
|
auth: authState
|
|
368
518
|
});
|
|
369
519
|
};
|
|
370
520
|
const clearAuthState = async configFile => {
|
|
371
521
|
const storedConfig = await readGlobalConfig(configFile);
|
|
372
522
|
await writeGlobalConfig(configFile, {
|
|
373
|
-
...storedConfig,
|
|
523
|
+
...withoutLegacyPublishedSkillPreferences(storedConfig),
|
|
374
524
|
auth: null
|
|
375
525
|
});
|
|
376
526
|
};
|
|
527
|
+
const toIgnoredSkillSlug = value => {
|
|
528
|
+
const normalized = value.trim().toLowerCase();
|
|
529
|
+
if (!normalized) return null;
|
|
530
|
+
return normalized;
|
|
531
|
+
};
|
|
532
|
+
const getPublishedSkillIgnoreScopeKey = (resolution, payload) => {
|
|
533
|
+
const workspaceSlug = payload?.workspace?.slug ?? resolution.fallbackWorkspaceSlug;
|
|
534
|
+
if (workspaceSlug) return `workspace:${toWorkspaceSlug(workspaceSlug)}`;
|
|
535
|
+
if (resolution.repositoryUrl) return `repository:${resolution.repositoryUrl}`;
|
|
536
|
+
return `path:${toWorkspaceSlug(path.basename(resolution.repositoryRoot))}`;
|
|
537
|
+
};
|
|
538
|
+
const toStoredUserKey = authState => {
|
|
539
|
+
if (authState?.userId) return authState.userId;
|
|
540
|
+
if (authState?.email) return authState.email.toLowerCase();
|
|
541
|
+
return 'anonymous';
|
|
542
|
+
};
|
|
543
|
+
const resolvePublishedSkillPreferenceCacheContext = async config => {
|
|
544
|
+
const authState = await readGlobalAuthState(config.authStatePath);
|
|
545
|
+
return {
|
|
546
|
+
userKey: toStoredUserKey(authState),
|
|
547
|
+
preferenceVersion: publishedSkillPreferenceCacheVersion
|
|
548
|
+
};
|
|
549
|
+
};
|
|
550
|
+
const getCatalogCacheKey = (workspaceResolution, preferenceContext) => {
|
|
551
|
+
return JSON.stringify([workspaceResolution.cacheKey, preferenceContext.userKey, preferenceContext.preferenceVersion]);
|
|
552
|
+
};
|
|
377
553
|
const toAuthState = session => ({
|
|
378
554
|
pluginId: PLUGIN_ID,
|
|
379
555
|
sessionToken: session.jwtToken,
|
|
@@ -475,11 +651,12 @@ const getPublishedSkillAssignmentCounts = items => items.reduce((counts, item) =
|
|
|
475
651
|
other: 0
|
|
476
652
|
});
|
|
477
653
|
const getSkillContextKind = item => {
|
|
478
|
-
if (item.assignmentSource === 'GLOBAL') return 'global';
|
|
654
|
+
if (item.assignmentSource === 'GLOBAL' || item.assignmentSource === 'USER_GLOBAL') return 'global';
|
|
479
655
|
return 'project';
|
|
480
656
|
};
|
|
481
657
|
const getSkillPolicyLabel = (policy, contextKind) => {
|
|
482
658
|
if (policy === 'GLOBAL_CONTEXT') return 'GLOBAL_CONTEXT · active context only, not project-installable';
|
|
659
|
+
if (contextKind === 'installable') return 'PROJECT_INSTALLABLE · available to install';
|
|
483
660
|
if (contextKind === 'global') return 'PROJECT_INSTALLABLE · active global assignment';
|
|
484
661
|
return 'PROJECT_INSTALLABLE · active project/workspace assignment';
|
|
485
662
|
};
|
|
@@ -514,10 +691,35 @@ export const toPublishedSkillDetail = item => ({
|
|
|
514
691
|
markdownBody: item.publishedArtifact.markdownBody,
|
|
515
692
|
renderedContent: item.publishedArtifact.renderedContent
|
|
516
693
|
});
|
|
694
|
+
const toInstallableSkillSummary = item => ({
|
|
695
|
+
skillSlug: item.skill.slug,
|
|
696
|
+
skillName: item.skill.name,
|
|
697
|
+
artifactName: item.publishedArtifact.frontmatterName,
|
|
698
|
+
artifactDescription: item.publishedArtifact.frontmatterDescription,
|
|
699
|
+
whenToUse: item.skill.whenToUse ?? null,
|
|
700
|
+
version: item.skillVersion.version,
|
|
701
|
+
assignmentSource: 'CATALOG',
|
|
702
|
+
assignmentType: 'PATH',
|
|
703
|
+
scopePath: '',
|
|
704
|
+
includeChildren: true,
|
|
705
|
+
checksum: item.publishedArtifact.checksum,
|
|
706
|
+
publishedAt: item.publishedArtifact.publishedAt,
|
|
707
|
+
identifiers: getSkillIdentifiers({
|
|
708
|
+
...item,
|
|
709
|
+
assignmentSource: 'CATALOG',
|
|
710
|
+
assignmentType: 'PATH',
|
|
711
|
+
scopePath: '',
|
|
712
|
+
includeChildren: true
|
|
713
|
+
}),
|
|
714
|
+
tags: item.skill.tags.map(toPublishedSkillTagSummary),
|
|
715
|
+
contextKind: 'installable',
|
|
716
|
+
installPolicy: item.skill.installPolicy,
|
|
717
|
+
policyLabel: getSkillPolicyLabel(item.skill.installPolicy, 'installable')
|
|
718
|
+
});
|
|
517
719
|
export const toPublishedSkillCatalog = payload => ({
|
|
518
720
|
pluginId: PLUGIN_ID,
|
|
519
721
|
runtimeMode: 'tool_fetch_only',
|
|
520
|
-
deliveryModel: '
|
|
722
|
+
deliveryModel: 'backend_published_installed_effective_skills',
|
|
521
723
|
workspace: payload.workspace,
|
|
522
724
|
directoryPath: payload.directoryPath,
|
|
523
725
|
rootSkillSeedPath: ROOT_SKILL_SEED_PATH,
|
|
@@ -527,6 +729,36 @@ export const toPublishedSkillCatalog = payload => ({
|
|
|
527
729
|
facets: getPublishedSkillFacets(payload.skills),
|
|
528
730
|
skills: payload.skills.map(toPublishedSkillSummary)
|
|
529
731
|
});
|
|
732
|
+
const filterIgnoredPublishedSkills = async (config, result) => {
|
|
733
|
+
const authState = await readGlobalAuthState(config.authStatePath);
|
|
734
|
+
const userKey = toStoredUserKey(authState);
|
|
735
|
+
if (!result.fetchResult.ok) {
|
|
736
|
+
return {
|
|
737
|
+
...result,
|
|
738
|
+
ignoreState: {
|
|
739
|
+
scopeKey: getPublishedSkillIgnoreScopeKey(result.workspaceResolution),
|
|
740
|
+
userKey,
|
|
741
|
+
ignoredSkillSlugs: [],
|
|
742
|
+
installedGlobalSkillSlugs: [],
|
|
743
|
+
installedWorkspaceSkillSlugs: []
|
|
744
|
+
},
|
|
745
|
+
ignoredSkills: []
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
const ignoredSkills = result.fetchResult.payload.userPreferences.ignoredSkills.map(toPublishedSkillSummary);
|
|
749
|
+
const ignoredSkillSlugs = ignoredSkills.map(skill => skill.skillSlug);
|
|
750
|
+
return {
|
|
751
|
+
...result,
|
|
752
|
+
ignoreState: {
|
|
753
|
+
scopeKey: result.fetchResult.payload.userPreferences.scopeKey,
|
|
754
|
+
userKey: result.fetchResult.payload.userPreferences.userKey || userKey,
|
|
755
|
+
ignoredSkillSlugs,
|
|
756
|
+
installedGlobalSkillSlugs: [],
|
|
757
|
+
installedWorkspaceSkillSlugs: []
|
|
758
|
+
},
|
|
759
|
+
ignoredSkills
|
|
760
|
+
};
|
|
761
|
+
};
|
|
530
762
|
const getWorkspaceUnavailableMessage = payload => {
|
|
531
763
|
if (payload.workspace) return null;
|
|
532
764
|
return 'Workspace-specific skills are unavailable because the workspace was not found; global skills are still loaded.';
|
|
@@ -629,6 +861,7 @@ const toWorkspaceResolutionMetadata = resolution => ({
|
|
|
629
861
|
});
|
|
630
862
|
const formatStatusOutput = async (worktree, config, publishedSkillsResult, loginBootstrapSnapshot) => {
|
|
631
863
|
const authState = await resolveStoredAuthState(worktree, config);
|
|
864
|
+
const filteredResult = await filterIgnoredPublishedSkills(config, publishedSkillsResult);
|
|
632
865
|
const base = {
|
|
633
866
|
pluginId: PLUGIN_ID,
|
|
634
867
|
runtimeMode: 'tool_fetch_only',
|
|
@@ -657,21 +890,26 @@ const formatStatusOutput = async (worktree, config, publishedSkillsResult, login
|
|
|
657
890
|
email: loginBootstrapSnapshot.email,
|
|
658
891
|
message: loginBootstrapSnapshot.message
|
|
659
892
|
},
|
|
660
|
-
status:
|
|
661
|
-
fetchedAt:
|
|
662
|
-
source:
|
|
663
|
-
availableTools: AVAILABLE_PUBLISHED_SKILL_TOOLS
|
|
893
|
+
status: filteredResult.fetchResult.status,
|
|
894
|
+
fetchedAt: filteredResult.fetchResult.fetchedAt,
|
|
895
|
+
source: filteredResult.fetchResult.source,
|
|
896
|
+
availableTools: AVAILABLE_PUBLISHED_SKILL_TOOLS,
|
|
897
|
+
ignoredPublishedSkills: {
|
|
898
|
+
scopeKey: filteredResult.ignoreState.scopeKey,
|
|
899
|
+
userKey: filteredResult.ignoreState.userKey,
|
|
900
|
+
count: filteredResult.ignoreState.ignoredSkillSlugs.length
|
|
901
|
+
}
|
|
664
902
|
};
|
|
665
|
-
if (!
|
|
903
|
+
if (!filteredResult.fetchResult.ok) {
|
|
666
904
|
return JSON.stringify({
|
|
667
905
|
...base,
|
|
668
|
-
message:
|
|
906
|
+
message: filteredResult.fetchResult.message
|
|
669
907
|
}, null, 2);
|
|
670
908
|
}
|
|
671
909
|
return JSON.stringify({
|
|
672
910
|
...base,
|
|
673
|
-
...toPublishedSkillCatalog(
|
|
674
|
-
message: getWorkspaceUnavailableMessage(
|
|
911
|
+
...toPublishedSkillCatalog(filteredResult.fetchResult.payload),
|
|
912
|
+
message: getWorkspaceUnavailableMessage(filteredResult.fetchResult.payload)
|
|
675
913
|
}, null, 2);
|
|
676
914
|
};
|
|
677
915
|
export const toPluginAuthStateSummary = authState => {
|
|
@@ -703,6 +941,11 @@ export const resolvePluginStatusSnapshot = async ({
|
|
|
703
941
|
directory
|
|
704
942
|
});
|
|
705
943
|
const fetchResult = await fetchPublishedSkillsCatalog(worktree, config, workspaceResolution, signal);
|
|
944
|
+
const filteredResult = await filterIgnoredPublishedSkills(config, {
|
|
945
|
+
directoryPath: workspaceResolution.directoryPath,
|
|
946
|
+
workspaceResolution,
|
|
947
|
+
fetchResult
|
|
948
|
+
});
|
|
706
949
|
const authState = await resolveStoredAuthState(worktree, config);
|
|
707
950
|
return {
|
|
708
951
|
pluginId: PLUGIN_ID,
|
|
@@ -715,19 +958,43 @@ export const resolvePluginStatusSnapshot = async ({
|
|
|
715
958
|
rootSkillSeedPath: config.rootSkillSeedPath,
|
|
716
959
|
authStatePath: config.authStatePath,
|
|
717
960
|
authState: toPluginAuthStateSummary(authState),
|
|
718
|
-
status: fetchResult.status,
|
|
719
|
-
authMode: fetchResult.authMode,
|
|
720
|
-
fetchedAt: fetchResult.fetchedAt,
|
|
721
|
-
source: fetchResult.source,
|
|
961
|
+
status: filteredResult.fetchResult.status,
|
|
962
|
+
authMode: filteredResult.fetchResult.authMode,
|
|
963
|
+
fetchedAt: filteredResult.fetchResult.fetchedAt,
|
|
964
|
+
source: filteredResult.fetchResult.source,
|
|
722
965
|
availableTools: AVAILABLE_PUBLISHED_SKILL_TOOLS,
|
|
723
|
-
message: fetchResult.ok ? getWorkspaceUnavailableMessage(fetchResult.payload) : fetchResult.message,
|
|
724
|
-
catalog: fetchResult.ok ? toPublishedSkillCatalog(fetchResult.payload) : null
|
|
966
|
+
message: filteredResult.fetchResult.ok ? getWorkspaceUnavailableMessage(filteredResult.fetchResult.payload) : filteredResult.fetchResult.message,
|
|
967
|
+
catalog: filteredResult.fetchResult.ok ? toPublishedSkillCatalog(filteredResult.fetchResult.payload) : null,
|
|
968
|
+
installableCatalog: filteredResult.fetchResult.ok ? {
|
|
969
|
+
count: filteredResult.fetchResult.payload.catalogSkills.length,
|
|
970
|
+
skills: filteredResult.fetchResult.payload.catalogSkills.map(toInstallableSkillSummary)
|
|
971
|
+
} : null,
|
|
972
|
+
ignoredPublishedSkills: {
|
|
973
|
+
scopeKey: filteredResult.ignoreState.scopeKey,
|
|
974
|
+
userKey: filteredResult.ignoreState.userKey,
|
|
975
|
+
count: filteredResult.ignoreState.ignoredSkillSlugs.length,
|
|
976
|
+
skills: filteredResult.ignoredSkills
|
|
977
|
+
}
|
|
725
978
|
};
|
|
726
979
|
};
|
|
727
980
|
const withStatusMessage = (snapshot, message) => ({
|
|
728
981
|
...snapshot,
|
|
729
982
|
message
|
|
730
983
|
});
|
|
984
|
+
const toAiFacingPluginStatusSnapshot = snapshot => {
|
|
985
|
+
const {
|
|
986
|
+
ignoredPublishedSkills,
|
|
987
|
+
installableCatalog: _installableCatalog,
|
|
988
|
+
...safeSnapshot
|
|
989
|
+
} = snapshot;
|
|
990
|
+
return {
|
|
991
|
+
...safeSnapshot,
|
|
992
|
+
ignoredPublishedSkills: {
|
|
993
|
+
scopeKey: ignoredPublishedSkills.scopeKey,
|
|
994
|
+
count: ignoredPublishedSkills.count
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
};
|
|
731
998
|
const startStatusPathLoginBootstrap = (worktree, config) => {
|
|
732
999
|
if (statusPathLoginBootstrap.promise) return;
|
|
733
1000
|
if (statusPathLoginBootstrap.status === 'failed' && statusPathLoginBootstrap.failedAt && Date.now() - statusPathLoginBootstrap.failedAt < STATUS_PATH_LOGIN_RETRY_COOLDOWN_MS) {
|
|
@@ -794,6 +1061,93 @@ export const resolvePluginStatusSnapshotWithAuthBootstrap = async ({
|
|
|
794
1061
|
}
|
|
795
1062
|
return withStatusMessage(snapshot, 'Browser login is pending from the TUI/status path.');
|
|
796
1063
|
};
|
|
1064
|
+
const toBackendPreferenceScope = preferenceScope => {
|
|
1065
|
+
if (preferenceScope === 'global') return 'GLOBAL';
|
|
1066
|
+
return 'WORKSPACE';
|
|
1067
|
+
};
|
|
1068
|
+
const setPublishedSkillPreference = async ({
|
|
1069
|
+
worktree,
|
|
1070
|
+
directory,
|
|
1071
|
+
config,
|
|
1072
|
+
skillSlug,
|
|
1073
|
+
preferenceScope,
|
|
1074
|
+
installed,
|
|
1075
|
+
ignored
|
|
1076
|
+
}) => {
|
|
1077
|
+
const workspaceResolution = await resolveWorkspace({
|
|
1078
|
+
config,
|
|
1079
|
+
directory
|
|
1080
|
+
});
|
|
1081
|
+
const response = await fetchPublishedSkillsGraphQl({
|
|
1082
|
+
worktree,
|
|
1083
|
+
config,
|
|
1084
|
+
query: SET_PUBLISHED_SKILL_PREFERENCE_MUTATION,
|
|
1085
|
+
variables: {
|
|
1086
|
+
input: {
|
|
1087
|
+
...toDeliveryInput(workspaceResolution),
|
|
1088
|
+
skillSlug,
|
|
1089
|
+
preferenceScope: toBackendPreferenceScope(preferenceScope),
|
|
1090
|
+
installed,
|
|
1091
|
+
ignored
|
|
1092
|
+
}
|
|
1093
|
+
},
|
|
1094
|
+
signal: AbortSignal.timeout(PRESENCE_EVENT_TIMEOUT_MS)
|
|
1095
|
+
});
|
|
1096
|
+
if (!response.ok) {
|
|
1097
|
+
throw new Error(response.result.message);
|
|
1098
|
+
}
|
|
1099
|
+
const preferences = response.data.setPublishedSkillPreference;
|
|
1100
|
+
publishedSkillPreferenceCacheVersion += 1;
|
|
1101
|
+
return {
|
|
1102
|
+
scopeKey: preferences.scopeKey,
|
|
1103
|
+
userKey: preferences.userKey,
|
|
1104
|
+
ignoredSkillSlugs: preferences.ignoredSkills.map(item => item.skill.slug),
|
|
1105
|
+
installedGlobalSkillSlugs: [],
|
|
1106
|
+
installedWorkspaceSkillSlugs: []
|
|
1107
|
+
};
|
|
1108
|
+
};
|
|
1109
|
+
export const setPublishedSkillIgnored = async ({
|
|
1110
|
+
worktree,
|
|
1111
|
+
directory,
|
|
1112
|
+
skillSlug,
|
|
1113
|
+
ignored,
|
|
1114
|
+
preferenceScope
|
|
1115
|
+
}) => {
|
|
1116
|
+
const config = await resolveConfig(worktree);
|
|
1117
|
+
const normalizedSkillSlug = toIgnoredSkillSlug(skillSlug);
|
|
1118
|
+
if (!normalizedSkillSlug) {
|
|
1119
|
+
throw new Error('Cannot toggle an empty published skill slug.');
|
|
1120
|
+
}
|
|
1121
|
+
return setPublishedSkillPreference({
|
|
1122
|
+
worktree,
|
|
1123
|
+
directory,
|
|
1124
|
+
config,
|
|
1125
|
+
skillSlug: normalizedSkillSlug,
|
|
1126
|
+
preferenceScope: preferenceScope ?? 'project',
|
|
1127
|
+
ignored
|
|
1128
|
+
});
|
|
1129
|
+
};
|
|
1130
|
+
export const setPublishedSkillInstalled = async ({
|
|
1131
|
+
worktree,
|
|
1132
|
+
directory,
|
|
1133
|
+
skillSlug,
|
|
1134
|
+
installed,
|
|
1135
|
+
preferenceScope
|
|
1136
|
+
}) => {
|
|
1137
|
+
const config = await resolveConfig(worktree);
|
|
1138
|
+
const normalizedSkillSlug = toIgnoredSkillSlug(skillSlug);
|
|
1139
|
+
if (!normalizedSkillSlug) {
|
|
1140
|
+
throw new Error('Cannot toggle an empty published skill slug.');
|
|
1141
|
+
}
|
|
1142
|
+
return setPublishedSkillPreference({
|
|
1143
|
+
worktree,
|
|
1144
|
+
directory,
|
|
1145
|
+
config,
|
|
1146
|
+
skillSlug: normalizedSkillSlug,
|
|
1147
|
+
preferenceScope,
|
|
1148
|
+
installed
|
|
1149
|
+
});
|
|
1150
|
+
};
|
|
797
1151
|
const toPluginStatusMetadata = snapshot => ({
|
|
798
1152
|
backendOrigin: snapshot.backendOrigin,
|
|
799
1153
|
graphqlUrl: snapshot.graphqlUrl,
|
|
@@ -1503,11 +1857,11 @@ const openBrowser = async url => {
|
|
|
1503
1857
|
const normalizeDirectoryArg = (contextDirectory, directory) => {
|
|
1504
1858
|
return normalizeAbsolutePath(directory ? path.resolve(contextDirectory, directory) : contextDirectory);
|
|
1505
1859
|
};
|
|
1506
|
-
const getDetailCacheKey = (
|
|
1507
|
-
return JSON.stringify([
|
|
1860
|
+
const getDetailCacheKey = (catalogCacheKey, skillVersionId) => {
|
|
1861
|
+
return JSON.stringify([catalogCacheKey, skillVersionId]);
|
|
1508
1862
|
};
|
|
1509
|
-
const getDetailInflightKey = (
|
|
1510
|
-
return JSON.stringify([
|
|
1863
|
+
const getDetailInflightKey = (catalogCacheKey, skillVersionId, purpose) => {
|
|
1864
|
+
return JSON.stringify([catalogCacheKey, skillVersionId, purpose]);
|
|
1511
1865
|
};
|
|
1512
1866
|
const OpencodeWizardSkillsPlugin = async input => {
|
|
1513
1867
|
const {
|
|
@@ -1727,7 +2081,8 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1727
2081
|
directory
|
|
1728
2082
|
});
|
|
1729
2083
|
const directoryPath = workspaceResolution.directoryPath;
|
|
1730
|
-
const
|
|
2084
|
+
const preferenceContext = await resolvePublishedSkillPreferenceCacheContext(config);
|
|
2085
|
+
const cacheKey = getCatalogCacheKey(workspaceResolution, preferenceContext);
|
|
1731
2086
|
const cached = cache.get(cacheKey);
|
|
1732
2087
|
if (useCache && cached && cached.expiresAt > Date.now()) {
|
|
1733
2088
|
return {
|
|
@@ -1770,8 +2125,10 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1770
2125
|
purpose
|
|
1771
2126
|
}) => {
|
|
1772
2127
|
const directoryPath = workspaceResolution.directoryPath;
|
|
1773
|
-
const
|
|
1774
|
-
const
|
|
2128
|
+
const preferenceContext = await resolvePublishedSkillPreferenceCacheContext(config);
|
|
2129
|
+
const catalogCacheKey = getCatalogCacheKey(workspaceResolution, preferenceContext);
|
|
2130
|
+
const cacheKey = getDetailCacheKey(catalogCacheKey, item.skillVersion.id);
|
|
2131
|
+
const inflightKey = getDetailInflightKey(catalogCacheKey, item.skillVersion.id, purpose);
|
|
1775
2132
|
const cached = detailCache.get(cacheKey);
|
|
1776
2133
|
if (purpose === 'SYSTEM_CONTEXT' && useCache && cached && cached.expiresAt > Date.now()) {
|
|
1777
2134
|
return {
|
|
@@ -1911,18 +2268,29 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1911
2268
|
loginBootstrapSnapshot: loginBootstrap.snapshot
|
|
1912
2269
|
});
|
|
1913
2270
|
}
|
|
1914
|
-
const
|
|
2271
|
+
const filteredPublishedSkillsResult = await filterIgnoredPublishedSkills(config, publishedSkillsResult);
|
|
2272
|
+
if (!filteredPublishedSkillsResult.fetchResult.ok) {
|
|
2273
|
+
await emitFetchOutcome('FETCH_FAILED');
|
|
2274
|
+
return toFetchFailureOutput({
|
|
2275
|
+
worktree: input.worktree,
|
|
2276
|
+
config,
|
|
2277
|
+
publishedSkillsResult: filteredPublishedSkillsResult,
|
|
2278
|
+
loginBootstrapSnapshot: loginBootstrap.snapshot
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
const selection = selectPublishedSkills(filteredPublishedSkillsResult.fetchResult.payload, requestedSkills);
|
|
1915
2282
|
const isSingleRequest = requestedSkills.length === 1;
|
|
1916
2283
|
if (requestedSkills.length === 0) {
|
|
1917
|
-
const catalog = toPublishedSkillCatalog(
|
|
2284
|
+
const catalog = toPublishedSkillCatalog(filteredPublishedSkillsResult.fetchResult.payload);
|
|
1918
2285
|
context.metadata({
|
|
1919
|
-
title: `opencode-wizard published skills catalog: ${catalog.publishedSkillCount}`,
|
|
2286
|
+
title: `opencode-wizard published skills catalog: ${catalog.publishedSkillCount} active`,
|
|
1920
2287
|
metadata: {
|
|
1921
|
-
...toWorkspaceResolutionMetadata(
|
|
2288
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
1922
2289
|
status: 'ready',
|
|
1923
2290
|
publishedSkillCount: catalog.publishedSkillCount.toString(),
|
|
1924
2291
|
globalAssignmentCount: catalog.assignmentCounts.global.toString(),
|
|
1925
|
-
projectAssignmentCount: catalog.assignmentCounts.project.toString()
|
|
2292
|
+
projectAssignmentCount: catalog.assignmentCounts.project.toString(),
|
|
2293
|
+
ignoredSkillCount: filteredPublishedSkillsResult.ignoreState.ignoredSkillSlugs.length.toString()
|
|
1926
2294
|
}
|
|
1927
2295
|
});
|
|
1928
2296
|
await emitFetchOutcome('FETCH_SUCCESS');
|
|
@@ -1930,16 +2298,21 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1930
2298
|
output: JSON.stringify({
|
|
1931
2299
|
...catalog,
|
|
1932
2300
|
status: 'ready',
|
|
1933
|
-
requestedDirectoryPath:
|
|
1934
|
-
workspaceResolution: toWorkspaceResolutionOutput(
|
|
1935
|
-
|
|
1936
|
-
|
|
2301
|
+
requestedDirectoryPath: filteredPublishedSkillsResult.directoryPath,
|
|
2302
|
+
workspaceResolution: toWorkspaceResolutionOutput(filteredPublishedSkillsResult.workspaceResolution),
|
|
2303
|
+
ignoredPublishedSkills: {
|
|
2304
|
+
scopeKey: filteredPublishedSkillsResult.ignoreState.scopeKey,
|
|
2305
|
+
count: filteredPublishedSkillsResult.ignoreState.ignoredSkillSlugs.length
|
|
2306
|
+
},
|
|
2307
|
+
fetchedAt: filteredPublishedSkillsResult.fetchResult.fetchedAt,
|
|
2308
|
+
source: filteredPublishedSkillsResult.fetchResult.source,
|
|
1937
2309
|
message: 'Catalog discovery only. Provide `skill` or `skills` to fetch markdown bodies/details for selected skills.'
|
|
1938
2310
|
}, null, 2),
|
|
1939
2311
|
metadata: {
|
|
1940
2312
|
status: 'ready',
|
|
1941
|
-
...toWorkspaceResolutionMetadata(
|
|
1942
|
-
publishedSkillCount: catalog.publishedSkillCount.toString()
|
|
2313
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
2314
|
+
publishedSkillCount: catalog.publishedSkillCount.toString(),
|
|
2315
|
+
ignoredSkillCount: filteredPublishedSkillsResult.ignoreState.ignoredSkillSlugs.length.toString()
|
|
1943
2316
|
}
|
|
1944
2317
|
};
|
|
1945
2318
|
}
|
|
@@ -1950,19 +2323,23 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1950
2323
|
pluginId: PLUGIN_ID,
|
|
1951
2324
|
runtimeMode: 'tool_fetch_only',
|
|
1952
2325
|
status: 'not_found',
|
|
1953
|
-
requestedDirectoryPath:
|
|
1954
|
-
workspaceResolution: toWorkspaceResolutionOutput(
|
|
2326
|
+
requestedDirectoryPath: filteredPublishedSkillsResult.directoryPath,
|
|
2327
|
+
workspaceResolution: toWorkspaceResolutionOutput(filteredPublishedSkillsResult.workspaceResolution),
|
|
1955
2328
|
requestedSkill: requestedSkills[0],
|
|
1956
|
-
availableSkills:
|
|
2329
|
+
availableSkills: filteredPublishedSkillsResult.fetchResult.payload.skills.map(toPublishedSkillSummary),
|
|
2330
|
+
ignoredPublishedSkills: {
|
|
2331
|
+
scopeKey: filteredPublishedSkillsResult.ignoreState.scopeKey,
|
|
2332
|
+
count: filteredPublishedSkillsResult.ignoreState.ignoredSkillSlugs.length
|
|
2333
|
+
}
|
|
1957
2334
|
}, null, 2),
|
|
1958
2335
|
metadata: {
|
|
1959
2336
|
status: 'not_found',
|
|
1960
|
-
...toWorkspaceResolutionMetadata(
|
|
2337
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution)
|
|
1961
2338
|
}
|
|
1962
2339
|
};
|
|
1963
2340
|
}
|
|
1964
2341
|
let skillDetailResults = await Promise.all(selection.selectedItems.map(item => loadPublishedSkillDetail({
|
|
1965
|
-
workspaceResolution:
|
|
2342
|
+
workspaceResolution: filteredPublishedSkillsResult.workspaceResolution,
|
|
1966
2343
|
item,
|
|
1967
2344
|
signal: context.abort,
|
|
1968
2345
|
useCache: !args.refresh,
|
|
@@ -1974,7 +2351,7 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
1974
2351
|
await schedulePresenceStart(authState);
|
|
1975
2352
|
});
|
|
1976
2353
|
skillDetailResults = await Promise.all(selection.selectedItems.map(item => loadPublishedSkillDetail({
|
|
1977
|
-
workspaceResolution:
|
|
2354
|
+
workspaceResolution: filteredPublishedSkillsResult.workspaceResolution,
|
|
1978
2355
|
item,
|
|
1979
2356
|
signal: context.abort,
|
|
1980
2357
|
useCache: false,
|
|
@@ -2000,7 +2377,7 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2000
2377
|
context.metadata({
|
|
2001
2378
|
title: `opencode-wizard published skill: ${detail.artifactName || detail.skillName}`,
|
|
2002
2379
|
metadata: {
|
|
2003
|
-
...toWorkspaceResolutionMetadata(
|
|
2380
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
2004
2381
|
skillSlug: detail.skillSlug,
|
|
2005
2382
|
version: detail.version
|
|
2006
2383
|
}
|
|
@@ -2010,16 +2387,16 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2010
2387
|
output: JSON.stringify({
|
|
2011
2388
|
pluginId: PLUGIN_ID,
|
|
2012
2389
|
runtimeMode: 'tool_fetch_only',
|
|
2013
|
-
requestedDirectoryPath:
|
|
2014
|
-
workspaceResolution: toWorkspaceResolutionOutput(
|
|
2015
|
-
workspace:
|
|
2016
|
-
fetchedAt:
|
|
2017
|
-
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,
|
|
2018
2395
|
skill: detail
|
|
2019
2396
|
}, null, 2),
|
|
2020
2397
|
metadata: {
|
|
2021
2398
|
status: 'ready',
|
|
2022
|
-
...toWorkspaceResolutionMetadata(
|
|
2399
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
2023
2400
|
skillSlug: detail.skillSlug
|
|
2024
2401
|
}
|
|
2025
2402
|
};
|
|
@@ -2027,7 +2404,7 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2027
2404
|
context.metadata({
|
|
2028
2405
|
title: `opencode-wizard published skills fetch: ${skillDetails.length}`,
|
|
2029
2406
|
metadata: {
|
|
2030
|
-
...toWorkspaceResolutionMetadata(
|
|
2407
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
2031
2408
|
requestedCount: requestedSkills.length.toString(),
|
|
2032
2409
|
matchedCount: skillDetails.length.toString()
|
|
2033
2410
|
}
|
|
@@ -2037,18 +2414,18 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2037
2414
|
output: JSON.stringify({
|
|
2038
2415
|
pluginId: PLUGIN_ID,
|
|
2039
2416
|
runtimeMode: 'tool_fetch_only',
|
|
2040
|
-
requestedDirectoryPath:
|
|
2041
|
-
workspaceResolution: toWorkspaceResolutionOutput(
|
|
2042
|
-
workspace:
|
|
2043
|
-
fetchedAt:
|
|
2044
|
-
source:
|
|
2417
|
+
requestedDirectoryPath: filteredPublishedSkillsResult.directoryPath,
|
|
2418
|
+
workspaceResolution: toWorkspaceResolutionOutput(filteredPublishedSkillsResult.workspaceResolution),
|
|
2419
|
+
workspace: filteredPublishedSkillsResult.fetchResult.payload.workspace,
|
|
2420
|
+
fetchedAt: filteredPublishedSkillsResult.fetchResult.fetchedAt,
|
|
2421
|
+
source: filteredPublishedSkillsResult.fetchResult.source,
|
|
2045
2422
|
requestedSkills,
|
|
2046
2423
|
missingSkills: selection.missingIdentifiers,
|
|
2047
2424
|
skills: skillDetails
|
|
2048
2425
|
}, null, 2),
|
|
2049
2426
|
metadata: {
|
|
2050
2427
|
status: selection.missingIdentifiers.length > 0 ? 'partial' : 'ready',
|
|
2051
|
-
...toWorkspaceResolutionMetadata(
|
|
2428
|
+
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
2052
2429
|
matchedCount: skillDetails.length.toString()
|
|
2053
2430
|
}
|
|
2054
2431
|
};
|
|
@@ -2083,7 +2460,7 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2083
2460
|
metadata
|
|
2084
2461
|
});
|
|
2085
2462
|
return {
|
|
2086
|
-
output: JSON.stringify(snapshot, null, 2),
|
|
2463
|
+
output: JSON.stringify(toAiFacingPluginStatusSnapshot(snapshot), null, 2),
|
|
2087
2464
|
metadata
|
|
2088
2465
|
};
|
|
2089
2466
|
};
|
|
@@ -2143,11 +2520,12 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2143
2520
|
return;
|
|
2144
2521
|
}
|
|
2145
2522
|
}
|
|
2523
|
+
const filteredPublishedSkillsResult = await filterIgnoredPublishedSkills(config, publishedSkillsResult);
|
|
2146
2524
|
const details = await loadSystemNoteDetails({
|
|
2147
|
-
publishedSkillsResult,
|
|
2525
|
+
publishedSkillsResult: filteredPublishedSkillsResult,
|
|
2148
2526
|
signal: AbortSignal.timeout(5_000)
|
|
2149
2527
|
});
|
|
2150
|
-
const systemNote = buildSystemNote(
|
|
2528
|
+
const systemNote = buildSystemNote(filteredPublishedSkillsResult, config, details);
|
|
2151
2529
|
if (!systemNote) return;
|
|
2152
2530
|
output.system.push(systemNote);
|
|
2153
2531
|
}
|