@aexol/opencode-wizard 0.1.15 → 0.2.0
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 +22 -0
- package/dist/server.js +65 -45
- package/dist/server.js.map +1 -1
- package/dist/smoke-published-skills.js +21 -2
- 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 +219 -126
- package/dist/tui.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ Useful commands:
|
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
npm run typecheck
|
|
24
|
+
npm run test
|
|
24
25
|
npm run build
|
|
25
26
|
npm run release:check
|
|
26
27
|
```
|
|
@@ -45,7 +46,7 @@ Use `skills.urls` only for public registries that are intentionally cacheable by
|
|
|
45
46
|
|
|
46
47
|
## Catalog discovery and auth bootstrap
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
Catalog discovery uses the backend-issued plugin session token stored at `~/.config/opencode/opencode-wizard.json` (`auth` field); the plugin does not persist or send Microsoft/Entra tokens to GraphQL. If no valid plugin session exists, no-arg `opencode_wizard_published_skills_fetch`, explicit `opencode_wizard_status`, TUI status, and chat/system-context startup may start the browser Entra PKCE flow and exchange the callback for a fresh backend-issued plugin session.
|
|
49
50
|
|
|
50
51
|
Call `opencode_wizard_published_skills_fetch` without `skill` or `skills` to manually bootstrap plugin login if needed and return catalog-only discovery output for the current directory scope.
|
|
51
52
|
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const PUBLISHED_BACKEND_ORIGIN = "https://opencode-wizard.aexol.work";
|
|
2
|
+
export declare const normalizeBackendOrigin: (value: string | undefined) => string | null;
|
|
3
|
+
export declare const resolveBackendOriginFromValues: ({ environmentBackendOrigin, localBackendOrigin, }: {
|
|
4
|
+
environmentBackendOrigin?: string;
|
|
5
|
+
localBackendOrigin?: string;
|
|
6
|
+
}) => string;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const PUBLISHED_BACKEND_ORIGIN = 'https://opencode-wizard.aexol.work';
|
|
2
|
+
export const normalizeBackendOrigin = value => {
|
|
3
|
+
if (!value) return null;
|
|
4
|
+
try {
|
|
5
|
+
const normalizedUrl = new URL(value);
|
|
6
|
+
return normalizedUrl.origin;
|
|
7
|
+
} catch {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
export const resolveBackendOriginFromValues = ({
|
|
12
|
+
environmentBackendOrigin,
|
|
13
|
+
localBackendOrigin
|
|
14
|
+
}) => {
|
|
15
|
+
const configuredBackendOrigin = normalizeBackendOrigin(environmentBackendOrigin) ?? normalizeBackendOrigin(localBackendOrigin);
|
|
16
|
+
if (configuredBackendOrigin) return configuredBackendOrigin;
|
|
17
|
+
return PUBLISHED_BACKEND_ORIGIN;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["PUBLISHED_BACKEND_ORIGIN","normalizeBackendOrigin","value","normalizedUrl","URL","origin","resolveBackendOriginFromValues","environmentBackendOrigin","localBackendOrigin","configuredBackendOrigin"],"sources":["../src/config.ts"],"sourcesContent":["export const PUBLISHED_BACKEND_ORIGIN = 'https://opencode-wizard.aexol.work';\n\nexport const normalizeBackendOrigin = (value: string | undefined): string | null => {\n if (!value) return null;\n\n try {\n const normalizedUrl = new URL(value);\n return normalizedUrl.origin;\n } catch {\n return null;\n }\n};\n\nexport const resolveBackendOriginFromValues = ({\n environmentBackendOrigin,\n localBackendOrigin,\n}: {\n environmentBackendOrigin?: string;\n localBackendOrigin?: string;\n}): string => {\n const configuredBackendOrigin =\n normalizeBackendOrigin(environmentBackendOrigin) ?? normalizeBackendOrigin(localBackendOrigin);\n\n if (configuredBackendOrigin) return configuredBackendOrigin;\n\n return PUBLISHED_BACKEND_ORIGIN;\n};\n"],"mappings":"AAAA,OAAO,MAAMA,wBAAwB,GAAG,oCAAoC;AAE5E,OAAO,MAAMC,sBAAsB,GAAIC,KAAyB,IAAoB;EAClF,IAAI,CAACA,KAAK,EAAE,OAAO,IAAI;EAEvB,IAAI;IACF,MAAMC,aAAa,GAAG,IAAIC,GAAG,CAACF,KAAK,CAAC;IACpC,OAAOC,aAAa,CAACE,MAAM;EAC7B,CAAC,CAAC,MAAM;IACN,OAAO,IAAI;EACb;AACF,CAAC;AAED,OAAO,MAAMC,8BAA8B,GAAGA,CAAC;EAC7CC,wBAAwB;EACxBC;AAIF,CAAC,KAAa;EACZ,MAAMC,uBAAuB,GAC3BR,sBAAsB,CAACM,wBAAwB,CAAC,IAAIN,sBAAsB,CAACO,kBAAkB,CAAC;EAEhG,IAAIC,uBAAuB,EAAE,OAAOA,uBAAuB;EAE3D,OAAOT,wBAAwB;AACjC,CAAC","ignoreList":[]}
|
package/dist/server.d.ts
CHANGED
|
@@ -65,8 +65,18 @@ export type PublishedSkillCatalogItem = {
|
|
|
65
65
|
frontmatterDescription: string;
|
|
66
66
|
checksum: string;
|
|
67
67
|
publishedAt: string;
|
|
68
|
+
fileCount: number;
|
|
68
69
|
};
|
|
69
70
|
};
|
|
71
|
+
type PublishedSkillArtifactFilePayload = {
|
|
72
|
+
id: string;
|
|
73
|
+
relativePath: string;
|
|
74
|
+
contentType: string;
|
|
75
|
+
content: string;
|
|
76
|
+
checksum: string;
|
|
77
|
+
size: number;
|
|
78
|
+
sortOrder: number;
|
|
79
|
+
};
|
|
70
80
|
type PublishedSkillFacet = {
|
|
71
81
|
id: string;
|
|
72
82
|
slug: string;
|
|
@@ -96,6 +106,7 @@ export type PublishedSkillDetailItem = PublishedSkillCatalogItem & {
|
|
|
96
106
|
publishedArtifact: PublishedSkillCatalogItem['publishedArtifact'] & {
|
|
97
107
|
markdownBody: string;
|
|
98
108
|
renderedContent: string;
|
|
109
|
+
files: PublishedSkillArtifactFilePayload[];
|
|
99
110
|
};
|
|
100
111
|
};
|
|
101
112
|
type AuthState = {
|
|
@@ -134,10 +145,12 @@ type PublishedSkillSummary = {
|
|
|
134
145
|
includeChildren: boolean | null;
|
|
135
146
|
checksum: string;
|
|
136
147
|
publishedAt: string;
|
|
148
|
+
fileCount: number;
|
|
137
149
|
identifiers: string[];
|
|
138
150
|
tags: PublishedSkillTagSummary[];
|
|
139
151
|
contextKind: 'global' | 'project' | 'installable';
|
|
140
152
|
installPolicy: PublishedSkillInstallPolicy;
|
|
153
|
+
assignmentLabel: string;
|
|
141
154
|
policyLabel: string;
|
|
142
155
|
};
|
|
143
156
|
type PublishedSkillDetail = PublishedSkillSummary & {
|
|
@@ -147,6 +160,8 @@ type PublishedSkillDetail = PublishedSkillSummary & {
|
|
|
147
160
|
markdownDocument: string;
|
|
148
161
|
markdownBody: string;
|
|
149
162
|
renderedContent: string;
|
|
163
|
+
files: PublishedSkillArtifactFilePayload[];
|
|
164
|
+
resources: PublishedSkillArtifactFilePayload[];
|
|
150
165
|
};
|
|
151
166
|
type OpencodePluginServerInput = {
|
|
152
167
|
worktree: string;
|
|
@@ -171,6 +186,7 @@ type PublishedSkillsSuccessState = {
|
|
|
171
186
|
assignmentCounts: {
|
|
172
187
|
global: number;
|
|
173
188
|
project: number;
|
|
189
|
+
user: number;
|
|
174
190
|
other: number;
|
|
175
191
|
};
|
|
176
192
|
facets: PublishedSkillFacetSummary[];
|
|
@@ -185,6 +201,11 @@ export type NativeSkillsUrlCompatibility = {
|
|
|
185
201
|
guidance: string;
|
|
186
202
|
};
|
|
187
203
|
export declare const NATIVE_SKILLS_URL_COMPATIBILITY: NativeSkillsUrlCompatibility;
|
|
204
|
+
type PublishedSkillsResult = {
|
|
205
|
+
directoryPath: string;
|
|
206
|
+
workspaceResolution: WorkspaceResolution;
|
|
207
|
+
fetchResult: FetchResult;
|
|
208
|
+
};
|
|
188
209
|
type PublishedSkillsIgnoreState = {
|
|
189
210
|
scopeKey: string;
|
|
190
211
|
userKey: string;
|
|
@@ -238,6 +259,7 @@ export declare const selectPublishedSkills: <TItem extends PublishedSkillCatalog
|
|
|
238
259
|
selectedItems: TItem[];
|
|
239
260
|
missingIdentifiers: string[];
|
|
240
261
|
};
|
|
262
|
+
export declare const buildSystemNote: (result: PublishedSkillsResult, config: ResolvedConfig, details: PublishedSkillDetail[]) => string | null;
|
|
241
263
|
declare const toWorkspaceResolutionOutput: (resolution: WorkspaceResolution) => {
|
|
242
264
|
requestedDirectory: string;
|
|
243
265
|
repositoryRoot: string;
|
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';
|
|
@@ -113,6 +114,7 @@ const PUBLISHED_SKILLS_CATALOG_QUERY = `
|
|
|
113
114
|
frontmatterDescription
|
|
114
115
|
checksum
|
|
115
116
|
publishedAt
|
|
117
|
+
fileCount
|
|
116
118
|
}
|
|
117
119
|
}
|
|
118
120
|
catalogSkills {
|
|
@@ -150,6 +152,7 @@ const PUBLISHED_SKILLS_CATALOG_QUERY = `
|
|
|
150
152
|
frontmatterDescription
|
|
151
153
|
checksum
|
|
152
154
|
publishedAt
|
|
155
|
+
fileCount
|
|
153
156
|
}
|
|
154
157
|
}
|
|
155
158
|
userPreferences {
|
|
@@ -194,6 +197,7 @@ const PUBLISHED_SKILLS_CATALOG_QUERY = `
|
|
|
194
197
|
frontmatterDescription
|
|
195
198
|
checksum
|
|
196
199
|
publishedAt
|
|
200
|
+
fileCount
|
|
197
201
|
}
|
|
198
202
|
}
|
|
199
203
|
}
|
|
@@ -244,6 +248,7 @@ const SET_PUBLISHED_SKILL_PREFERENCE_MUTATION = `
|
|
|
244
248
|
frontmatterDescription
|
|
245
249
|
checksum
|
|
246
250
|
publishedAt
|
|
251
|
+
fileCount
|
|
247
252
|
}
|
|
248
253
|
}
|
|
249
254
|
}
|
|
@@ -259,6 +264,16 @@ const PUBLISHED_SKILL_DETAIL_QUERY = `
|
|
|
259
264
|
renderedContent
|
|
260
265
|
checksum
|
|
261
266
|
publishedAt
|
|
267
|
+
fileCount
|
|
268
|
+
files {
|
|
269
|
+
id
|
|
270
|
+
relativePath
|
|
271
|
+
contentType
|
|
272
|
+
content
|
|
273
|
+
checksum
|
|
274
|
+
size
|
|
275
|
+
sortOrder
|
|
276
|
+
}
|
|
262
277
|
}
|
|
263
278
|
}
|
|
264
279
|
`;
|
|
@@ -307,20 +322,12 @@ const readLocalEnvValues = async startDirectory => {
|
|
|
307
322
|
return new Map();
|
|
308
323
|
}
|
|
309
324
|
};
|
|
310
|
-
const normalizeBackendOrigin = value => {
|
|
311
|
-
if (!value) return null;
|
|
312
|
-
try {
|
|
313
|
-
const normalizedUrl = new URL(value);
|
|
314
|
-
return normalizedUrl.origin;
|
|
315
|
-
} catch {
|
|
316
|
-
return null;
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
325
|
const resolveBackendOrigin = async worktree => {
|
|
320
326
|
const envValues = await readLocalEnvValues(worktree);
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
327
|
+
return resolveBackendOriginFromValues({
|
|
328
|
+
environmentBackendOrigin: process.env.OPENCODE_WIZARD_BACKEND_ORIGIN,
|
|
329
|
+
localBackendOrigin: envValues.get('OPENCODE_WIZARD_BACKEND_ORIGIN')
|
|
330
|
+
});
|
|
324
331
|
};
|
|
325
332
|
const toWorkspaceSlug = value => {
|
|
326
333
|
const normalized = value.trim().toLowerCase().replace(/[^a-z0-9-]+/gu, '-').replace(/^-+|-+$/gu, '');
|
|
@@ -436,26 +443,6 @@ const formatSkillLabel = item => {
|
|
|
436
443
|
return item.skill.name;
|
|
437
444
|
};
|
|
438
445
|
const toFrontmatterString = value => JSON.stringify(value);
|
|
439
|
-
const readJsonFile = async filePath => {
|
|
440
|
-
try {
|
|
441
|
-
const raw = await fs.readFile(filePath, 'utf8');
|
|
442
|
-
const parsed = JSON.parse(raw);
|
|
443
|
-
return parsed;
|
|
444
|
-
} catch {
|
|
445
|
-
return null;
|
|
446
|
-
}
|
|
447
|
-
};
|
|
448
|
-
const writeJsonFile = async (filePath, value) => {
|
|
449
|
-
await fs.mkdir(path.dirname(filePath), {
|
|
450
|
-
recursive: true
|
|
451
|
-
});
|
|
452
|
-
await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
453
|
-
};
|
|
454
|
-
const deleteFileIfExists = async filePath => {
|
|
455
|
-
await fs.rm(filePath, {
|
|
456
|
-
force: true
|
|
457
|
-
});
|
|
458
|
-
};
|
|
459
446
|
const isRecord = value => {
|
|
460
447
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
461
448
|
};
|
|
@@ -472,7 +459,7 @@ const readGlobalConfig = async configFile => {
|
|
|
472
459
|
return {};
|
|
473
460
|
};
|
|
474
461
|
const writeGlobalConfig = async (configFile, config) => {
|
|
475
|
-
await
|
|
462
|
+
await writePrivateJsonFile(configFile, config);
|
|
476
463
|
};
|
|
477
464
|
const withoutLegacyPublishedSkillPreferences = config => {
|
|
478
465
|
const {
|
|
@@ -628,7 +615,22 @@ const getPublishedSkillFacets = items => {
|
|
|
628
615
|
}
|
|
629
616
|
return [...facetsBySlug.values()].sort((left, right) => left.slug.localeCompare(right.slug));
|
|
630
617
|
};
|
|
618
|
+
const isUserPublishedSkillAssignment = assignmentSource => assignmentSource === 'USER' || assignmentSource === 'USER_GLOBAL' || assignmentSource === 'USER_WORKSPACE';
|
|
619
|
+
const getPublishedSkillAssignmentLabel = assignmentSource => {
|
|
620
|
+
if (assignmentSource === 'GLOBAL') return 'GLOBAL SCOPE assignment';
|
|
621
|
+
if (assignmentSource === 'WORKSPACE') return 'PROJECT SCOPE assignment';
|
|
622
|
+
if (assignmentSource === 'USER_GLOBAL') return 'USER SCOPE preference (global target)';
|
|
623
|
+
if (assignmentSource === 'USER_WORKSPACE') return 'USER SCOPE preference (project target)';
|
|
624
|
+
if (assignmentSource === 'USER') return 'USER SCOPE assignment';
|
|
625
|
+
return `${assignmentSource.toUpperCase().replace(/_/gu, ' ')} assignment`;
|
|
626
|
+
};
|
|
631
627
|
const getPublishedSkillAssignmentCounts = items => items.reduce((counts, item) => {
|
|
628
|
+
if (isUserPublishedSkillAssignment(item.assignmentSource)) {
|
|
629
|
+
return {
|
|
630
|
+
...counts,
|
|
631
|
+
user: counts.user + 1
|
|
632
|
+
};
|
|
633
|
+
}
|
|
632
634
|
if (item.assignmentSource === 'GLOBAL') {
|
|
633
635
|
return {
|
|
634
636
|
...counts,
|
|
@@ -648,17 +650,22 @@ const getPublishedSkillAssignmentCounts = items => items.reduce((counts, item) =
|
|
|
648
650
|
}, {
|
|
649
651
|
global: 0,
|
|
650
652
|
project: 0,
|
|
653
|
+
user: 0,
|
|
651
654
|
other: 0
|
|
652
655
|
});
|
|
653
656
|
const getSkillContextKind = item => {
|
|
654
657
|
if (item.assignmentSource === 'GLOBAL' || item.assignmentSource === 'USER_GLOBAL') return 'global';
|
|
655
658
|
return 'project';
|
|
656
659
|
};
|
|
657
|
-
const getSkillPolicyLabel = (policy, contextKind) => {
|
|
660
|
+
const getSkillPolicyLabel = (policy, contextKind, assignmentSource) => {
|
|
661
|
+
if (isUserPublishedSkillAssignment(assignmentSource) && policy === 'GLOBAL_CONTEXT') {
|
|
662
|
+
return 'GLOBAL_CONTEXT · active USER SCOPE context';
|
|
663
|
+
}
|
|
664
|
+
if (isUserPublishedSkillAssignment(assignmentSource)) return 'PROJECT_INSTALLABLE · active USER SCOPE preference';
|
|
658
665
|
if (policy === 'GLOBAL_CONTEXT') return 'GLOBAL_CONTEXT · active context only, not project-installable';
|
|
659
666
|
if (contextKind === 'installable') return 'PROJECT_INSTALLABLE · available to install';
|
|
660
|
-
if (contextKind === 'global') return 'PROJECT_INSTALLABLE · active
|
|
661
|
-
return 'PROJECT_INSTALLABLE · active
|
|
667
|
+
if (contextKind === 'global') return 'PROJECT_INSTALLABLE · active GLOBAL SCOPE assignment';
|
|
668
|
+
return 'PROJECT_INSTALLABLE · active PROJECT SCOPE assignment';
|
|
662
669
|
};
|
|
663
670
|
const toPublishedSkillSummary = item => {
|
|
664
671
|
const contextKind = getSkillContextKind(item);
|
|
@@ -675,11 +682,13 @@ const toPublishedSkillSummary = item => {
|
|
|
675
682
|
includeChildren: item.includeChildren ?? null,
|
|
676
683
|
checksum: item.publishedArtifact.checksum,
|
|
677
684
|
publishedAt: item.publishedArtifact.publishedAt,
|
|
685
|
+
fileCount: item.publishedArtifact.fileCount,
|
|
678
686
|
identifiers: getSkillIdentifiers(item),
|
|
679
687
|
tags: item.skill.tags.map(toPublishedSkillTagSummary),
|
|
680
688
|
contextKind,
|
|
681
689
|
installPolicy: item.skill.installPolicy,
|
|
682
|
-
|
|
690
|
+
assignmentLabel: getPublishedSkillAssignmentLabel(item.assignmentSource),
|
|
691
|
+
policyLabel: getSkillPolicyLabel(item.skill.installPolicy, contextKind, item.assignmentSource)
|
|
683
692
|
};
|
|
684
693
|
};
|
|
685
694
|
export const toPublishedSkillDetail = item => ({
|
|
@@ -689,7 +698,9 @@ export const toPublishedSkillDetail = item => ({
|
|
|
689
698
|
artifactId: item.publishedArtifact.id,
|
|
690
699
|
markdownDocument: buildSkillMarkdown(item),
|
|
691
700
|
markdownBody: item.publishedArtifact.markdownBody,
|
|
692
|
-
renderedContent: item.publishedArtifact.renderedContent
|
|
701
|
+
renderedContent: item.publishedArtifact.renderedContent,
|
|
702
|
+
files: item.publishedArtifact.files,
|
|
703
|
+
resources: item.publishedArtifact.files.filter(file => file.relativePath !== 'SKILL.md')
|
|
693
704
|
});
|
|
694
705
|
const toInstallableSkillSummary = item => ({
|
|
695
706
|
skillSlug: item.skill.slug,
|
|
@@ -704,6 +715,7 @@ const toInstallableSkillSummary = item => ({
|
|
|
704
715
|
includeChildren: true,
|
|
705
716
|
checksum: item.publishedArtifact.checksum,
|
|
706
717
|
publishedAt: item.publishedArtifact.publishedAt,
|
|
718
|
+
fileCount: item.publishedArtifact.fileCount,
|
|
707
719
|
identifiers: getSkillIdentifiers({
|
|
708
720
|
...item,
|
|
709
721
|
assignmentSource: 'CATALOG',
|
|
@@ -714,7 +726,8 @@ const toInstallableSkillSummary = item => ({
|
|
|
714
726
|
tags: item.skill.tags.map(toPublishedSkillTagSummary),
|
|
715
727
|
contextKind: 'installable',
|
|
716
728
|
installPolicy: item.skill.installPolicy,
|
|
717
|
-
|
|
729
|
+
assignmentLabel: 'catalog skill',
|
|
730
|
+
policyLabel: getSkillPolicyLabel(item.skill.installPolicy, 'installable', 'CATALOG')
|
|
718
731
|
});
|
|
719
732
|
export const toPublishedSkillCatalog = payload => ({
|
|
720
733
|
pluginId: PLUGIN_ID,
|
|
@@ -827,24 +840,27 @@ const truncateText = (value, maxLength) => {
|
|
|
827
840
|
};
|
|
828
841
|
const buildSkillCatalogLine = skill => {
|
|
829
842
|
const description = truncateText(skill.whenToUse || skill.artifactDescription || skill.skillName || skill.skillSlug, SYSTEM_NOTE_SKILL_DESCRIPTION_LIMIT);
|
|
830
|
-
|
|
843
|
+
const scopeLabel = isUserPublishedSkillAssignment(skill.assignmentSource) ? 'USER SCOPE' : skill.contextKind === 'global' ? 'GLOBAL SCOPE' : 'PROJECT SCOPE';
|
|
844
|
+
const assignmentLabel = skill.assignmentSource.toLowerCase().replace(/_/gu, ' ');
|
|
845
|
+
return `- ${skill.artifactName || skill.skillName} (${skill.skillSlug}, ${assignmentLabel} assignment) [${scopeLabel}]: ${description}`;
|
|
831
846
|
};
|
|
832
847
|
const buildSkillDetailSnippetLine = detail => {
|
|
833
848
|
const body = detail.markdownBody || detail.renderedContent || detail.markdownDocument;
|
|
834
849
|
return `- ${detail.artifactName || detail.skillName}: ${truncateText(body, 700)}`;
|
|
835
850
|
};
|
|
836
|
-
const buildSystemNote = (result, config, details) => {
|
|
851
|
+
export const buildSystemNote = (result, config, details) => {
|
|
837
852
|
if (!result.fetchResult.ok) return null;
|
|
838
853
|
const catalog = toPublishedSkillCatalog(result.fetchResult.payload);
|
|
839
854
|
const skillNames = catalog.skills.map(skill => skill.artifactName || skill.skillName || skill.skillSlug);
|
|
840
855
|
const renderedSkillNames = skillNames.length > 0 ? skillNames.slice(0, SYSTEM_NOTE_SKILL_NAME_LIMIT).join(', ') : 'none';
|
|
841
856
|
const remainingCount = Math.max(skillNames.length - SYSTEM_NOTE_SKILL_NAME_LIMIT, 0);
|
|
842
857
|
const renderedCountSuffix = remainingCount > 0 ? ` (+${remainingCount} more)` : '';
|
|
843
|
-
const globalSkills = catalog.skills.filter(skill => skill.contextKind === 'global').slice(0, 8).map(buildSkillCatalogLine);
|
|
844
|
-
const projectSkills = catalog.skills.filter(skill => skill.contextKind === 'project').slice(0, 5).map(buildSkillCatalogLine);
|
|
858
|
+
const globalSkills = catalog.skills.filter(skill => skill.contextKind === 'global' && !isUserPublishedSkillAssignment(skill.assignmentSource)).slice(0, 8).map(buildSkillCatalogLine);
|
|
859
|
+
const projectSkills = catalog.skills.filter(skill => skill.contextKind === 'project' && !isUserPublishedSkillAssignment(skill.assignmentSource)).slice(0, 5).map(buildSkillCatalogLine);
|
|
860
|
+
const userSkills = catalog.skills.filter(skill => isUserPublishedSkillAssignment(skill.assignmentSource)).slice(0, 5).map(buildSkillCatalogLine);
|
|
845
861
|
const detailLines = details.slice(0, SYSTEM_NOTE_DETAIL_LIMIT).map(buildSkillDetailSnippetLine);
|
|
846
862
|
const detailBlock = detailLines.length > 0 ? ` Loaded body snippets (capped):\n${truncateText(detailLines.join('\n'), SYSTEM_NOTE_DETAIL_CHAR_LIMIT)}` : '';
|
|
847
|
-
return [result.fetchResult.payload.workspace ? `opencode-wizard published
|
|
863
|
+
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} workspace, ${catalog.assignmentCounts.user} user, ${catalog.assignmentCounts.other} other (GLOBAL SCOPE: ${catalog.assignmentCounts.global}, PROJECT SCOPE: ${catalog.assignmentCounts.project}, USER SCOPE: ${catalog.assignmentCounts.user}).`, '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 to GLOBAL SCOPE, PROJECT SCOPE, or USER SCOPE; assignment rows decide which scope is active here.', globalSkills.length > 0 ? `GLOBAL SCOPE / Global context skills:\n${globalSkills.join('\n')}` : 'GLOBAL SCOPE / Global context skills: none.', projectSkills.length > 0 ? `PROJECT SCOPE / Project-scoped active skills:\n${projectSkills.join('\n')}` : 'PROJECT SCOPE / Project-scoped active skills: none.', userSkills.length > 0 ? `USER SCOPE / User-scoped active skills:\n${userSkills.join('\n')}` : 'USER SCOPE / User-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(' ');
|
|
848
864
|
};
|
|
849
865
|
const toWorkspaceResolutionOutput = resolution => ({
|
|
850
866
|
requestedDirectory: resolution.requestedDirectory,
|
|
@@ -2290,6 +2306,7 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2290
2306
|
publishedSkillCount: catalog.publishedSkillCount.toString(),
|
|
2291
2307
|
globalAssignmentCount: catalog.assignmentCounts.global.toString(),
|
|
2292
2308
|
projectAssignmentCount: catalog.assignmentCounts.project.toString(),
|
|
2309
|
+
userAssignmentCount: catalog.assignmentCounts.user.toString(),
|
|
2293
2310
|
ignoredSkillCount: filteredPublishedSkillsResult.ignoreState.ignoredSkillSlugs.length.toString()
|
|
2294
2311
|
}
|
|
2295
2312
|
});
|
|
@@ -2312,6 +2329,9 @@ const OpencodeWizardSkillsPlugin = async input => {
|
|
|
2312
2329
|
status: 'ready',
|
|
2313
2330
|
...toWorkspaceResolutionMetadata(filteredPublishedSkillsResult.workspaceResolution),
|
|
2314
2331
|
publishedSkillCount: catalog.publishedSkillCount.toString(),
|
|
2332
|
+
globalAssignmentCount: catalog.assignmentCounts.global.toString(),
|
|
2333
|
+
projectAssignmentCount: catalog.assignmentCounts.project.toString(),
|
|
2334
|
+
userAssignmentCount: catalog.assignmentCounts.user.toString(),
|
|
2315
2335
|
ignoredSkillCount: filteredPublishedSkillsResult.ignoreState.ignoredSkillSlugs.length.toString()
|
|
2316
2336
|
}
|
|
2317
2337
|
};
|