@lythos/cold-pool 0.11.1 → 0.12.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lythos/cold-pool",
3
- "version": "0.11.1",
3
+ "version": "0.12.0",
4
4
  "description": "Cold pool service layer — dedicated resource holder for skill repositories with intent/plan/execute primitives. Single owner of git side-effects; consumed by deck/curator/arena.",
5
5
  "keywords": [
6
6
  "ai-agent",
@@ -42,7 +42,7 @@
42
42
  },
43
43
  "homepage": "https://github.com/lythos-labs/lythoskill/tree/main/packages/lythoskill-cold-pool#readme",
44
44
  "dependencies": {
45
- "@lythos/infra": "^0.11.1",
45
+ "@lythos/infra": "^0.12.0",
46
46
  "simple-git": "^3.36.0"
47
47
  },
48
48
  "engines": {
@@ -3,15 +3,23 @@ import { probeConnectivity } from './mirror.js'
3
3
 
4
4
  describe('probeConnectivity', () => {
5
5
  let originalFetch: typeof fetch
6
+ let originalEnv: string | undefined
6
7
  let fetchCalls: Array<{ url: string; options: RequestInit }>
7
8
 
8
9
  beforeEach(() => {
9
10
  originalFetch = globalThis.fetch
11
+ originalEnv = process.env.LYTHOSKILL_GH_MIRROR
12
+ delete process.env.LYTHOSKILL_GH_MIRROR
10
13
  fetchCalls = []
11
14
  })
12
15
 
13
16
  afterEach(() => {
14
17
  globalThis.fetch = originalFetch
18
+ if (originalEnv !== undefined) {
19
+ process.env.LYTHOSKILL_GH_MIRROR = originalEnv
20
+ } else {
21
+ delete process.env.LYTHOSKILL_GH_MIRROR
22
+ }
15
23
  })
16
24
 
17
25
  function mockFetch(
@@ -50,11 +58,12 @@ describe('probeConnectivity', () => {
50
58
  })
51
59
 
52
60
  // ── Vertical Slice 2 ──
53
- test('direct fails, mirror ok → returns mirror path', async () => {
61
+ test('direct fails, user mirror ok → returns mirror path', async () => {
62
+ process.env.LYTHOSKILL_GH_MIRROR = 'https://my-mirror.example.com'
54
63
  mockFetch(
55
64
  new Map([
56
65
  ['https://example.com/skill', new Response(null, { status: 500 })],
57
- ['https://ghfast.top/https://example.com/skill', new Response(null, { status: 200 })],
66
+ ['https://my-mirror.example.com/https://example.com/skill', new Response(null, { status: 200 })],
58
67
  ]),
59
68
  )
60
69
 
@@ -62,7 +71,7 @@ describe('probeConnectivity', () => {
62
71
 
63
72
  expect(result).toMatchObject({
64
73
  path: 'mirror',
65
- url: 'https://ghfast.top/https://example.com/skill',
74
+ url: 'https://my-mirror.example.com/https://example.com/skill',
66
75
  latencyMs: expect.any(Number),
67
76
  })
68
77
  })
@@ -91,14 +100,13 @@ describe('probeConnectivity', () => {
91
100
 
92
101
  // ── Vertical Slice 5: Racing behavior ──
93
102
  test('probes race concurrently, not sequentially', async () => {
103
+ process.env.LYTHOSKILL_GH_MIRROR = 'https://my-mirror.example.com'
94
104
  const start = performance.now()
95
105
 
96
106
  mockFetch(
97
107
  new Map([
98
108
  ['https://example.com/skill', new Response(null, { status: 500 })],
99
- ['https://ghfast.top/https://example.com/skill', new Response(null, { status: 200 })],
100
- ['https://ghproxy.com/https://example.com/skill', new Response(null, { status: 200 })],
101
- ['https://mirror.ghproxy.com/https://example.com/skill', new Response(null, { status: 200 })],
109
+ ['https://my-mirror.example.com/https://example.com/skill', new Response(null, { status: 200 })],
102
110
  ]),
103
111
  50, // each mock fetch takes 50ms
104
112
  )
@@ -108,11 +116,26 @@ describe('probeConnectivity', () => {
108
116
  const elapsed = performance.now() - start
109
117
 
110
118
  expect(result?.path).toBe('mirror')
111
- // Sequential would take ~200ms (4 × 50ms). Racing should be ~50-100ms.
119
+ // Sequential would take ~100ms (2 × 50ms). Racing should be ~50-100ms.
112
120
  expect(elapsed).toBeLessThan(150)
113
121
  })
114
122
 
115
- // ── Vertical Slice 6: Timeout honored ──
123
+ // ── Vertical Slice 6: No user mirror set → only probes direct ──
124
+ test('without user mirror, only probes direct', async () => {
125
+ mockFetch(
126
+ new Map([
127
+ ['https://example.com/skill', new Response(null, { status: 200 })],
128
+ ]),
129
+ )
130
+
131
+ const result = await probeConnectivity('https://example.com/skill')
132
+
133
+ expect(result?.path).toBe('direct')
134
+ expect(fetchCalls.length).toBe(1)
135
+ expect(fetchCalls[0].url).toBe('https://example.com/skill')
136
+ })
137
+
138
+ // ── Vertical Slice 7: Timeout honored ──
116
139
  test('timeout aborts slow probes', async () => {
117
140
  globalThis.fetch = async (_input, init?) => {
118
141
  return new Promise((_, reject) => {
package/src/mirror.ts CHANGED
@@ -1,24 +1,15 @@
1
1
  /**
2
2
  * Mirror URL rewriting for restricted networks.
3
3
  *
4
- * Three layers, checked in order:
5
- * 1. LYTHOSKILL_GH_MIRROR env var (explicit user choice)
6
- * 2. HTTPS_PROXY / HTTP_PROXY (standard Bun fetch and git respect these natively)
7
- * 3. Known public mirrors (auto-fallback when GitHub is unreachable)
4
+ * Two layers only the tool never decides which third party to trust:
5
+ * 1. LYTHOSKILL_GH_MIRROR env var (explicit user choice, user bears trust)
6
+ * 2. LYTHOS_SOCKS_PROXY / HTTPS_PROXY / HTTP_PROXY (standard, user's own infra)
8
7
  *
9
- * Per ADR-20260512191438745.
8
+ * No hard-coded mirror list. Auto-fallback to "known" third-party mirrors was
9
+ * removed: the tool must not silently delegate trust to an external service
10
+ * that can return tampered skill files (see ADR-202605130...).
10
11
  */
11
12
 
12
- // ── Known public mirrors (tried in order when GitHub is unreachable) ──
13
-
14
- const KNOWN_MIRRORS = [
15
- 'https://ghfast.top', // commonly used in CN
16
- 'https://ghproxy.com', // commonly used in CN
17
- 'https://mirror.ghproxy.com', // ghproxy alternative domain
18
- ]
19
-
20
- // ── Explicit user mirror ──────────────────────────────────────────────
21
-
22
13
  export function getMirror(): string | undefined {
23
14
  const v = process.env.LYTHOSKILL_GH_MIRROR?.trim()
24
15
  if (!v) return undefined
@@ -28,18 +19,14 @@ export function getMirror(): string | undefined {
28
19
  return `https://${v.replace(/\/+$/, '')}`
29
20
  }
30
21
 
31
- // ── URL rewriting ─────────────────────────────────────────────────────
32
-
33
22
  export function rewriteUrl(url: string, mirror?: string): string {
34
23
  if (!mirror) return url
35
24
  return `${mirror}/${url}`
36
25
  }
37
26
 
38
27
  export function mirrorUrls(url: string): string[] {
39
- const mirrors = [...KNOWN_MIRRORS]
40
28
  const explicit = getMirror()
41
- if (explicit) mirrors.unshift(explicit)
42
- return mirrors.map(m => rewriteUrl(url, m))
29
+ return explicit ? [rewriteUrl(url, explicit)] : []
43
30
  }
44
31
 
45
32
  export function isLikelyGitHubBlock(err: unknown): boolean {
@@ -61,7 +48,7 @@ export interface ProbeFailure {
61
48
  }
62
49
 
63
50
  /**
64
- * Quick connectivity probe: race direct + all mirrors concurrently.
51
+ * Quick connectivity probe: race direct + user mirror (if set) concurrently.
65
52
  * Uses short timeout (default 3s) to fail fast instead of waiting for
66
53
  * the full git clone / fetch timeout.
67
54
  *