opencode-plugin-hub 0.1.1 → 0.1.3
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 +18 -10
- package/dist/gui-experimental.cjs +125 -33
- package/package.json +1 -1
- package/src/contract.ts +2 -0
- package/src/gui/catalog.ts +25 -7
- package/src/gui/page.tsx +348 -202
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-plugin-hub",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Plugin manager for OpenCode Desktop: browse community plugins, search npm, inspect README and downloads, install and update without editing JSON.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/contract.ts
CHANGED
|
@@ -131,6 +131,8 @@ export const CatalogResult = Schema.Struct({
|
|
|
131
131
|
entries: Schema.Array(CatalogEntry),
|
|
132
132
|
/** `network`, `cache` or `builtin`. */
|
|
133
133
|
source: Schema.String,
|
|
134
|
+
/** The registry URL the entries came from. Optional for older cached results. */
|
|
135
|
+
registry: Schema.optional(Schema.String),
|
|
134
136
|
fetchedAt: Schema.Number,
|
|
135
137
|
error: Schema.String,
|
|
136
138
|
})
|
package/src/gui/catalog.ts
CHANGED
|
@@ -27,6 +27,8 @@ export interface CatalogResultValue {
|
|
|
27
27
|
entries: CatalogEntryValue[]
|
|
28
28
|
/** Where the list came from: `network`, `cache` or `builtin`. */
|
|
29
29
|
source: string
|
|
30
|
+
/** The registry URL the entries came from. */
|
|
31
|
+
registry: string
|
|
30
32
|
/** Epoch milliseconds of the data, 0 for the built-in snapshot. */
|
|
31
33
|
fetchedAt: number
|
|
32
34
|
error: string
|
|
@@ -129,7 +131,7 @@ function toEntries(raw: RawEntry[], installed: Set<string>): CatalogEntryValue[]
|
|
|
129
131
|
return out
|
|
130
132
|
}
|
|
131
133
|
|
|
132
|
-
async function fetchRemote(): Promise<RawEntry[]> {
|
|
134
|
+
async function fetchRemote(): Promise<{ entries: RawEntry[]; url: string }> {
|
|
133
135
|
let lastError = ""
|
|
134
136
|
for (const url of SOURCES) {
|
|
135
137
|
try {
|
|
@@ -143,7 +145,7 @@ async function fetchRemote(): Promise<RawEntry[]> {
|
|
|
143
145
|
lastError = "registry 格式不是数组"
|
|
144
146
|
continue
|
|
145
147
|
}
|
|
146
|
-
return body as RawEntry[]
|
|
148
|
+
return { entries: body as RawEntry[], url }
|
|
147
149
|
} catch (error) {
|
|
148
150
|
lastError = describe(error)
|
|
149
151
|
}
|
|
@@ -153,6 +155,8 @@ async function fetchRemote(): Promise<RawEntry[]> {
|
|
|
153
155
|
|
|
154
156
|
interface CacheFile {
|
|
155
157
|
fetchedAt: number
|
|
158
|
+
/** The source URL that produced this cache. Older caches do not have it. */
|
|
159
|
+
url?: string
|
|
156
160
|
entries: RawEntry[]
|
|
157
161
|
}
|
|
158
162
|
|
|
@@ -167,11 +171,11 @@ async function readCache(): Promise<CacheFile | undefined> {
|
|
|
167
171
|
}
|
|
168
172
|
}
|
|
169
173
|
|
|
170
|
-
async function writeCache(entries: RawEntry[]): Promise<number> {
|
|
174
|
+
async function writeCache(entries: RawEntry[], url: string): Promise<number> {
|
|
171
175
|
const fetchedAt = Date.now()
|
|
172
176
|
try {
|
|
173
177
|
await mkdir(cacheDir(), { recursive: true })
|
|
174
|
-
await writeFile(cacheFile(), JSON.stringify({ fetchedAt, entries }), "utf8")
|
|
178
|
+
await writeFile(cacheFile(), JSON.stringify({ fetchedAt, url, entries }), "utf8")
|
|
175
179
|
} catch {
|
|
176
180
|
// A failed cache write still leaves the in-memory result usable.
|
|
177
181
|
}
|
|
@@ -186,17 +190,30 @@ export async function browse(installed: Set<string>, force: boolean): Promise<Ca
|
|
|
186
190
|
const cache = await readCache()
|
|
187
191
|
const fresh = cache !== undefined && Date.now() - cache.fetchedAt < TTL
|
|
188
192
|
if (cache && fresh && !force) {
|
|
189
|
-
return {
|
|
193
|
+
return {
|
|
194
|
+
entries: toEntries(cache.entries, installed),
|
|
195
|
+
source: "cache",
|
|
196
|
+
registry: cache.url ?? SOURCES[0]!,
|
|
197
|
+
fetchedAt: cache.fetchedAt,
|
|
198
|
+
error: "",
|
|
199
|
+
}
|
|
190
200
|
}
|
|
191
201
|
try {
|
|
192
202
|
const remote = await fetchRemote()
|
|
193
|
-
const fetchedAt = await writeCache(remote)
|
|
194
|
-
return {
|
|
203
|
+
const fetchedAt = await writeCache(remote.entries, remote.url)
|
|
204
|
+
return {
|
|
205
|
+
entries: toEntries(remote.entries, installed),
|
|
206
|
+
source: "network",
|
|
207
|
+
registry: remote.url,
|
|
208
|
+
fetchedAt,
|
|
209
|
+
error: "",
|
|
210
|
+
}
|
|
195
211
|
} catch (error) {
|
|
196
212
|
if (cache) {
|
|
197
213
|
return {
|
|
198
214
|
entries: toEntries(cache.entries, installed),
|
|
199
215
|
source: "cache",
|
|
216
|
+
registry: cache.url ?? SOURCES[0]!,
|
|
200
217
|
fetchedAt: cache.fetchedAt,
|
|
201
218
|
error: describe(error),
|
|
202
219
|
}
|
|
@@ -204,6 +221,7 @@ export async function browse(installed: Set<string>, force: boolean): Promise<Ca
|
|
|
204
221
|
return {
|
|
205
222
|
entries: toEntries(SNAPSHOT.map(toRaw), installed),
|
|
206
223
|
source: "builtin",
|
|
224
|
+
registry: SOURCES[0]!,
|
|
207
225
|
fetchedAt: 0,
|
|
208
226
|
error: describe(error),
|
|
209
227
|
}
|