@chatcode/cco-market 1.45.1

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.
Files changed (177) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/README.zh.md +143 -0
  4. package/UPDATE-API-V1.md +132 -0
  5. package/client/client.js +11534 -0
  6. package/cordis.patch.yml +5 -0
  7. package/lib/accelerate.js +184 -0
  8. package/lib/agents.js +36 -0
  9. package/lib/backup.js +572 -0
  10. package/lib/catalog-local-match.js +126 -0
  11. package/lib/catalog-npm.js +111 -0
  12. package/lib/changelog.js +242 -0
  13. package/lib/channels.js +64 -0
  14. package/lib/check.js +1067 -0
  15. package/lib/compatibility.js +198 -0
  16. package/lib/diagnostics.js +49 -0
  17. package/lib/discovery-compatibility.js +260 -0
  18. package/lib/dsh-cli.js +949 -0
  19. package/lib/dsh-install.js +108 -0
  20. package/lib/gist.js +352 -0
  21. package/lib/groups.js +97 -0
  22. package/lib/home-paths.js +42 -0
  23. package/lib/hot.js +519 -0
  24. package/lib/http.js +39 -0
  25. package/lib/index.js +97 -0
  26. package/lib/install.js +387 -0
  27. package/lib/log.js +197 -0
  28. package/lib/ndjson.js +154 -0
  29. package/lib/net.js +98 -0
  30. package/lib/order.js +284 -0
  31. package/lib/patch.js +521 -0
  32. package/lib/pnpm-compat.js +490 -0
  33. package/lib/presets.js +278 -0
  34. package/lib/profile.js +911 -0
  35. package/lib/region-probe.js +93 -0
  36. package/lib/regions.js +253 -0
  37. package/lib/registry.js +204 -0
  38. package/lib/restart.js +373 -0
  39. package/lib/routes.js +4372 -0
  40. package/lib/settings.js +109 -0
  41. package/lib/skill-market/api.js +119 -0
  42. package/lib/skill-market/config.js +29 -0
  43. package/lib/skill-market/installer.js +352 -0
  44. package/lib/skill-market/runtime.js +13 -0
  45. package/lib/skill-market/tui.js +119 -0
  46. package/lib/skill-market/types.js +1 -0
  47. package/lib/skill-market/web-routes.js +123 -0
  48. package/lib/snapshot.js +500 -0
  49. package/lib/source-migration.js +54 -0
  50. package/lib/sources.js +596 -0
  51. package/lib/store.js +91 -0
  52. package/lib/themes.js +102 -0
  53. package/lib/trial.js +116 -0
  54. package/lib/types/accelerate.d.ts +85 -0
  55. package/lib/types/agents.d.ts +22 -0
  56. package/lib/types/backup.d.ts +131 -0
  57. package/lib/types/catalog-local-match.d.ts +50 -0
  58. package/lib/types/catalog-npm.d.ts +47 -0
  59. package/lib/types/changelog.d.ts +102 -0
  60. package/lib/types/channels.d.ts +56 -0
  61. package/lib/types/check.d.ts +266 -0
  62. package/lib/types/compatibility.d.ts +64 -0
  63. package/lib/types/diagnostics.d.ts +29 -0
  64. package/lib/types/discovery-compatibility.d.ts +80 -0
  65. package/lib/types/dsh-cli.d.ts +324 -0
  66. package/lib/types/dsh-install.d.ts +46 -0
  67. package/lib/types/gist.d.ts +53 -0
  68. package/lib/types/groups.d.ts +34 -0
  69. package/lib/types/home-paths.d.ts +16 -0
  70. package/lib/types/hot.d.ts +221 -0
  71. package/lib/types/http.d.ts +12 -0
  72. package/lib/types/index.d.ts +14 -0
  73. package/lib/types/install.d.ts +172 -0
  74. package/lib/types/log.d.ts +43 -0
  75. package/lib/types/ndjson.d.ts +52 -0
  76. package/lib/types/net.d.ts +58 -0
  77. package/lib/types/order.d.ts +100 -0
  78. package/lib/types/patch.d.ts +129 -0
  79. package/lib/types/pnpm-compat.d.ts +93 -0
  80. package/lib/types/presets.d.ts +90 -0
  81. package/lib/types/profile.d.ts +253 -0
  82. package/lib/types/region-probe.d.ts +50 -0
  83. package/lib/types/regions.d.ts +122 -0
  84. package/lib/types/registry.d.ts +86 -0
  85. package/lib/types/restart.d.ts +194 -0
  86. package/lib/types/routes.d.ts +67 -0
  87. package/lib/types/settings.d.ts +78 -0
  88. package/lib/types/skill-market/api.d.ts +10 -0
  89. package/lib/types/skill-market/config.d.ts +3 -0
  90. package/lib/types/skill-market/installer.d.ts +23 -0
  91. package/lib/types/skill-market/runtime.d.ts +10 -0
  92. package/lib/types/skill-market/tui.d.ts +4 -0
  93. package/lib/types/skill-market/types.d.ts +71 -0
  94. package/lib/types/skill-market/web-routes.d.ts +19 -0
  95. package/lib/types/snapshot.d.ts +93 -0
  96. package/lib/types/source-migration.d.ts +11 -0
  97. package/lib/types/sources.d.ts +216 -0
  98. package/lib/types/store.d.ts +30 -0
  99. package/lib/types/themes.d.ts +40 -0
  100. package/lib/types/trial.d.ts +61 -0
  101. package/lib/types/update-api-v1.d.ts +66 -0
  102. package/lib/types/updates.d.ts +123 -0
  103. package/lib/types/verify.d.ts +139 -0
  104. package/lib/update-api-v1.js +215 -0
  105. package/lib/updates.js +361 -0
  106. package/lib/verify.js +453 -0
  107. package/package.json +121 -0
  108. package/src/accelerate.ts +213 -0
  109. package/src/agents.ts +43 -0
  110. package/src/backup.ts +583 -0
  111. package/src/catalog-local-match.ts +144 -0
  112. package/src/catalog-npm.ts +120 -0
  113. package/src/changelog.ts +282 -0
  114. package/src/channels.ts +70 -0
  115. package/src/check.ts +1239 -0
  116. package/src/client/CommentsModal.tsx +119 -0
  117. package/src/client/Diagnostics.tsx +907 -0
  118. package/src/client/ErrorBoundary.tsx +111 -0
  119. package/src/client/InstallToast.tsx +31 -0
  120. package/src/client/Market.module.css +830 -0
  121. package/src/client/MarketSection.tsx +5301 -0
  122. package/src/client/OperationsPanel.tsx +365 -0
  123. package/src/client/SettingsCard.tsx +621 -0
  124. package/src/client/SkillMarket.module.css +21 -0
  125. package/src/client/SkillMarketSection.tsx +162 -0
  126. package/src/client/comments.ts +54 -0
  127. package/src/client/globals.d.ts +13 -0
  128. package/src/client/index.ts +180 -0
  129. package/src/client/locales.ts +1112 -0
  130. package/src/client/market-data.ts +1321 -0
  131. package/src/client/operations.ts +201 -0
  132. package/src/client/preset-panel.tsx +263 -0
  133. package/src/client/primitives.d.ts +140 -0
  134. package/src/client/self-check.ts +147 -0
  135. package/src/client/snapshot-panel.tsx +244 -0
  136. package/src/compatibility.ts +237 -0
  137. package/src/diagnostics.ts +84 -0
  138. package/src/discovery-compatibility.ts +315 -0
  139. package/src/dsh-cli.ts +1126 -0
  140. package/src/dsh-install.ts +118 -0
  141. package/src/gist.ts +362 -0
  142. package/src/groups.ts +111 -0
  143. package/src/home-paths.ts +53 -0
  144. package/src/hot.ts +628 -0
  145. package/src/http.ts +41 -0
  146. package/src/index.ts +128 -0
  147. package/src/install.ts +420 -0
  148. package/src/log.ts +206 -0
  149. package/src/ndjson.ts +185 -0
  150. package/src/net.ts +106 -0
  151. package/src/order.ts +303 -0
  152. package/src/patch.ts +522 -0
  153. package/src/pnpm-compat.ts +527 -0
  154. package/src/presets.ts +344 -0
  155. package/src/profile.ts +940 -0
  156. package/src/region-probe.ts +97 -0
  157. package/src/regions.ts +310 -0
  158. package/src/registry.ts +250 -0
  159. package/src/restart.ts +396 -0
  160. package/src/routes.ts +4506 -0
  161. package/src/settings.ts +141 -0
  162. package/src/skill-market/api.ts +130 -0
  163. package/src/skill-market/config.ts +32 -0
  164. package/src/skill-market/installer.ts +337 -0
  165. package/src/skill-market/runtime.ts +14 -0
  166. package/src/skill-market/tui.ts +157 -0
  167. package/src/skill-market/types.ts +80 -0
  168. package/src/skill-market/web-routes.ts +132 -0
  169. package/src/snapshot.ts +532 -0
  170. package/src/source-migration.ts +61 -0
  171. package/src/sources.ts +565 -0
  172. package/src/store.ts +89 -0
  173. package/src/themes.ts +125 -0
  174. package/src/trial.ts +156 -0
  175. package/src/update-api-v1.ts +277 -0
  176. package/src/updates.ts +400 -0
  177. package/src/verify.ts +492 -0
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Resolving a GitHub install through a region's proxy without proxying the
3
+ * tarball pnpm records.
4
+ *
5
+ * pnpm does not fetch `github:owner/repo` with `git clone`; it resolves the
6
+ * shortcut and downloads a tarball from codeload.github.com. That rules out
7
+ * the usual `git config insteadOf` trick — there is no git command to
8
+ * redirect.
9
+ *
10
+ * Prefix-proxying that tarball used to save substantial time, but pnpm 11's
11
+ * fail-closed lockfile checks changed the safety boundary. A URL shaped like
12
+ * `https://proxy/https://codeload.github.com/.../<commit>` no longer has the
13
+ * codeload hostname, so pnpm treats it as an ordinary remote tarball and
14
+ * requires an integrity hash that its GitHub resolver does not write. The
15
+ * result is ERR_PNPM_MISSING_TARBALL_INTEGRITY on the install itself (#385).
16
+ * Disabling that check or minting a checksum from whatever the proxy served
17
+ * would weaken pnpm's supply-chain protection, so neither is acceptable.
18
+ *
19
+ * The safe middle ground is to resolve HEAD through the regional proxy, then
20
+ * hand pnpm a commit-pinned `github:owner/repo#<sha>` target. The ref lookup
21
+ * still avoids a slow or unreachable GitHub metadata request; pnpm itself
22
+ * fetches the canonical codeload URL, records it as `gitHosted: true`, and
23
+ * keeps its integrity policy intact.
24
+ *
25
+ * - **The commit has to be pinned.** The profile reads each plugin's
26
+ * installed commit back out of the lockfile by matching a codeload URL
27
+ * ending in a 40-character SHA (src/profile.ts). A `HEAD` tarball installs
28
+ * perfectly and then reports no version forever. So this resolves the SHA
29
+ * first, and a rewrite that cannot get one does not happen.
30
+ * - **Build-script approval has to keep matching.** `gitAllowBuildsKey`
31
+ * (src/sources.ts) derives its stable key from the repo, and the pinned
32
+ * GitHub form preserves that identity.
33
+ *
34
+ * Catalog subpath entries are left alone: `#path:` identifies a different
35
+ * package inside the repo, so the acceleration step never rewrites that
36
+ * fragment. Collection roots discovered after install preserve the resolved
37
+ * commit and add their subpath as pnpm's second `&path:` selector.
38
+ *
39
+ * Every SHA-lookup failure falls back to the original target. Acceleration
40
+ * is an optimisation, and an optimisation that can fail an install is a bug.
41
+ */
42
+
43
+ import { logEvent } from './log.ts'
44
+ import { marketFetch } from './net.ts'
45
+ import {
46
+ githubRoutesFor, rememberGithubRoute, routesFor, throughProxy, type GithubRoute, type Region,
47
+ } from './regions.ts'
48
+
49
+ /** A bare repo shortcut whose HEAD can be replaced by one immutable ref. */
50
+ const BARE_GITHUB_RE = /^github:([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)$/
51
+
52
+ /**
53
+ * How long to wait for the SHA before giving up and installing directly.
54
+ *
55
+ * Short on purpose: this is spent BEFORE the download starts, and the whole
56
+ * point is to avoid a slow or unreachable direct metadata lookup. A proxy
57
+ * that cannot answer promptly should not delay pnpm's ordinary direct path.
58
+ */
59
+ const RESOLVE_TIMEOUT_MS = 6000
60
+
61
+ /**
62
+ * The commit `HEAD` points at, from git's own ref advertisement.
63
+ *
64
+ * This is the endpoint `git clone` reads before it fetches anything, and it
65
+ * is the right one here for two measured reasons. It is not the REST API, so
66
+ * it does not consume the 60-requests-per-hour unauthenticated quota that a
67
+ * user installing a handful of plugins could plausibly exhaust. And it
68
+ * survives the proxy: over five consecutive tries from an unproxied mainland
69
+ * connection it answered 200 in ~1.2s every time, while the REST API through
70
+ * the same proxy returned 200, 200, then 403 — a proxy that rate-limits the
71
+ * API path would silently drop every install back to the slow route.
72
+ *
73
+ * The response is git's pkt-line format, whose first ref line carries
74
+ * `<sha> HEAD\0<capabilities>`. Read with a pattern rather than a parser:
75
+ * one 40-character hex string followed by `HEAD` is unambiguous in this
76
+ * payload, and a length-prefix reader would be more code to get wrong.
77
+ *
78
+ * The same advertisement lists every branch and tag, which is what `ref`
79
+ * uses. A plugin installed from `github:owner/repo#publish` is not asking
80
+ * about the default branch at all, and answering with it made the market
81
+ * report an update forever (#446) — the two SHAs simply never match. Both
82
+ * namespaces are searched because pnpm accepts a tag there too, branches
83
+ * first since that is what the reports are about.
84
+ * @param ref - branch or tag to resolve, or undefined for the default branch.
85
+ */
86
+ export async function headCommit(
87
+ repo: string,
88
+ proxy: string | null,
89
+ signal?: AbortSignal,
90
+ ref?: string,
91
+ ): Promise<string | null> {
92
+ const result = await tryHeadCommit(repo, proxy, signal, ref)
93
+ return result.kind === 'valid' ? result.sha : null
94
+ }
95
+
96
+ type HeadAttempt =
97
+ | { kind: 'valid'; sha: string | null }
98
+ | { kind: 'failed' }
99
+
100
+ /** One route attempt, preserving valid "ref is absent" from invalid payloads. */
101
+ async function tryHeadCommit(
102
+ repo: string,
103
+ proxy: GithubRoute,
104
+ signal?: AbortSignal,
105
+ ref?: string,
106
+ ): Promise<HeadAttempt> {
107
+ const base = `https://github.com/${repo}/info/refs?service=git-upload-pack`
108
+ try {
109
+ const res = await marketFetch(throughProxy(proxy, base), {
110
+ signal,
111
+ headers: { 'user-agent': 'git/2.40.0' },
112
+ })
113
+ if (!res.ok) return { kind: 'failed' }
114
+ const body = await res.text()
115
+ const contentType = (res as Response & { headers?: { get?(name: string): string | null } })
116
+ .headers?.get?.('content-type')?.toLowerCase() ?? ''
117
+ // Public mirrors often answer a failed upstream request with their own
118
+ // branded HTML and status 200. A git advertisement has both its service
119
+ // prelude and at least one advertised ref; accepting anything else would
120
+ // cache a route that never returned Git data in the first place.
121
+ if (contentType.includes('text/html')
122
+ || !body.includes('# service=git-upload-pack')
123
+ || !/[0-9a-f]{40} (?:HEAD|refs\/(?:heads|tags)\/)/u.test(body)) {
124
+ return { kind: 'failed' }
125
+ }
126
+ if (ref === undefined) {
127
+ const found = /([0-9a-f]{40}) HEAD/.exec(body)
128
+ return { kind: 'valid', sha: found === null ? null : found[1]! }
129
+ }
130
+ // Anchored to the ref's full name so `publish` cannot match a branch
131
+ // called `publish-old`, and escaped because a ref may contain regex
132
+ // metacharacters (`.` is legal in a branch name).
133
+ const quoted = ref.replace(/[.*+?^${}()|[\]\\]/gu, String.raw`\$&`)
134
+ for (const namespace of ['heads', 'tags']) {
135
+ const found = new RegExp(String.raw`([0-9a-f]{40}) refs/${namespace}/${quoted}(?![^\s])`, 'u').exec(body)
136
+ if (found !== null) return { kind: 'valid', sha: found[1]! }
137
+ }
138
+ // The advertisement is authoritative for this repository. Asking another
139
+ // mirror cannot make a branch that is absent here appear.
140
+ return { kind: 'valid', sha: null }
141
+ } catch {
142
+ return { kind: 'failed' }
143
+ }
144
+ }
145
+
146
+ /** Run one candidate under its own budget, optionally linked to a caller signal. */
147
+ async function timedHeadCommit(
148
+ repo: string,
149
+ route: GithubRoute,
150
+ ref?: string,
151
+ signal?: AbortSignal,
152
+ ): Promise<HeadAttempt> {
153
+ const controller = new AbortController()
154
+ const abort = (): void => { controller.abort() }
155
+ if (signal?.aborted === true) controller.abort()
156
+ else signal?.addEventListener('abort', abort, { once: true })
157
+ const timer = setTimeout(abort, RESOLVE_TIMEOUT_MS)
158
+ try {
159
+ return await tryHeadCommit(repo, route, controller.signal, ref)
160
+ } finally {
161
+ clearTimeout(timer)
162
+ signal?.removeEventListener('abort', abort)
163
+ }
164
+ }
165
+
166
+ /**
167
+ * The current `HEAD` commit for a repo, on whichever route the region uses.
168
+ *
169
+ * Wraps the timeout so callers outside the install path — the build-script
170
+ * approval below, which needs a commit-pinned key — do not each reinvent it.
171
+ */
172
+ export async function resolveHeadCommit(
173
+ repo: string,
174
+ region: Region,
175
+ env: NodeJS.ProcessEnv = process.env,
176
+ ref?: string,
177
+ ): Promise<string | null> {
178
+ for (const route of githubRoutesFor('git', region, env)) {
179
+ const result = await timedHeadCommit(repo, route, ref)
180
+ if (result.kind === 'failed') continue
181
+ rememberGithubRoute('git', route)
182
+ return result.sha
183
+ }
184
+ return null
185
+ }
186
+
187
+ /**
188
+ * The install target to actually hand pnpm, given the region in force.
189
+ *
190
+ * @param target - what `installTargetFor` produced.
191
+ * @param region - the download region.
192
+ * @param env - environment, for the proxy override.
193
+ * @returns a commit-pinned GitHub shortcut when one route resolves HEAD,
194
+ * otherwise `target` unchanged.
195
+ */
196
+ export async function acceleratedTarget(
197
+ target: string,
198
+ region: Region,
199
+ env: NodeJS.ProcessEnv = process.env,
200
+ ): Promise<string> {
201
+ // A plain global install lets pnpm do its ordinary GitHub resolution. A
202
+ // custom prefix makes even that region an accelerated one.
203
+ if (routesFor(region, env).githubProxy === null) return target
204
+ const bare = BARE_GITHUB_RE.exec(target)
205
+ if (bare === null) return target
206
+ const repo = bare[1]!
207
+ const sha = await resolveHeadCommit(repo, region, env)
208
+ if (sha === null) {
209
+ logEvent('info', 'region', `${repo}: could not resolve a commit through the available routes; installing directly`)
210
+ return target
211
+ }
212
+ return `github:${repo}#${sha}`
213
+ }
package/src/agents.ts ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Optional host-provided agent inventory: lets the market refuse plugin
3
+ * mutations while a live agent is mid-turn. Mutating `node_modules` under a
4
+ * running agent replaces files the running plugin modules may still read or
5
+ * lazily import — the update "succeeds" while old code and new files mix.
6
+ */
7
+
8
+ export interface RunningAgentLike {
9
+ id?: unknown
10
+ status?: unknown
11
+ }
12
+
13
+ export interface AgentsServiceLike {
14
+ list(): RunningAgentLike[]
15
+ }
16
+
17
+ export type AgentsLookup = () => AgentsServiceLike | undefined
18
+
19
+ /**
20
+ * Ids of the host's currently running agents, or [] when the host has no
21
+ * agents service. Only a positive `status === 'running'` blocks an update —
22
+ * unknown statuses are treated as not running, so a future agent
23
+ * implementation with different wording fails open (the market stays
24
+ * usable) instead of wedging the plugin page.
25
+ */
26
+ export function runningAgentIds(agents: AgentsServiceLike | undefined): string[] {
27
+ if (agents === undefined) return []
28
+ let listed: RunningAgentLike[]
29
+ try {
30
+ listed = agents.list()
31
+ } catch {
32
+ // A half-disposed registry must never take the market's routes down.
33
+ return []
34
+ }
35
+ if (!Array.isArray(listed)) return []
36
+ const ids: string[] = []
37
+ for (const agent of listed) {
38
+ if (agent === null || typeof agent !== 'object' || agent.status !== 'running') continue
39
+ const id = typeof agent.id === 'string' && agent.id !== '' ? agent.id : 'agent'
40
+ if (!ids.includes(id)) ids.push(id)
41
+ }
42
+ return ids
43
+ }