@lythos/cold-pool 0.14.5 → 0.15.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 +11 -1
- package/package.json +2 -2
- package/src/cli.ts +2 -2
- package/src/cold-pool.ts +1 -2
- package/src/mirror.test.ts +34 -6
- package/src/mirror.ts +12 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Cold pool service layer for the lythoskill ecosystem.
|
|
4
4
|
|
|
5
|
-
> Status:
|
|
5
|
+
> Status: stable — public API
|
|
6
6
|
|
|
7
7
|
## What this is
|
|
8
8
|
|
|
@@ -11,6 +11,16 @@ skill repositories at `~/.agents/skill-repos/` (configurable). This package
|
|
|
11
11
|
is the **only** layer in the ecosystem that holds git side-effects.
|
|
12
12
|
deck / curator / arena consume it instead of running `git clone` themselves.
|
|
13
13
|
|
|
14
|
+
## CLI Commands
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Scan cold pool for unreferenced repos
|
|
18
|
+
bunx @lythos/cold-pool@0.15.0 prune [--yes] [--dry-run]
|
|
19
|
+
|
|
20
|
+
# Validate lock file against cold pool
|
|
21
|
+
bunx @lythos/cold-pool@0.15.0 validate [--lock ./skill-deck.lock]
|
|
22
|
+
```
|
|
23
|
+
|
|
14
24
|
## Architecture
|
|
15
25
|
|
|
16
26
|
Three layers, sharing the project's `intent → plan → execute` pattern
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lythos/cold-pool",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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.
|
|
45
|
+
"@lythos/infra": "^0.15.0",
|
|
46
46
|
"simple-git": "^3.36.0"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
package/src/cli.ts
CHANGED
|
@@ -51,8 +51,8 @@ async function main(): Promise<void> {
|
|
|
51
51
|
process.exit(0)
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
// Resolve cold pool path (
|
|
55
|
-
const coldPoolPath =
|
|
54
|
+
// Resolve cold pool path (default only; use --pool for override)
|
|
55
|
+
const coldPoolPath = DEFAULT_COLD_POOL_PATH
|
|
56
56
|
|
|
57
57
|
switch (command) {
|
|
58
58
|
// ── prune ─────────────────────────────────────────────────
|
package/src/cold-pool.ts
CHANGED
|
@@ -4,8 +4,7 @@ import { join, relative } from 'node:path'
|
|
|
4
4
|
import type { Locator } from './types.js'
|
|
5
5
|
import { MetadataDB } from './metadata-db.js'
|
|
6
6
|
|
|
7
|
-
export const DEFAULT_COLD_POOL_PATH =
|
|
8
|
-
?? join(homedir(), '.agents/skill-repos')
|
|
7
|
+
export const DEFAULT_COLD_POOL_PATH = join(homedir(), '.agents/skill-repos')
|
|
9
8
|
|
|
10
9
|
// ── DirEntry — pure, injectable fs entry ─────────────────────────────────────
|
|
11
10
|
|
package/src/mirror.test.ts
CHANGED
|
@@ -9,8 +9,9 @@ describe('probeConnectivity', () => {
|
|
|
9
9
|
|
|
10
10
|
beforeEach(() => {
|
|
11
11
|
originalFetch = globalThis.fetch
|
|
12
|
-
originalEnv = process.env.
|
|
12
|
+
originalEnv = process.env.LYTHOS_GH_MIRROR
|
|
13
13
|
originalSocks = process.env.LYTHOS_SOCKS_PROXY
|
|
14
|
+
delete process.env.LYTHOS_GH_MIRROR
|
|
14
15
|
delete process.env.LYTHOSKILL_GH_MIRROR
|
|
15
16
|
delete process.env.LYTHOS_SOCKS_PROXY
|
|
16
17
|
fetchCalls = []
|
|
@@ -19,10 +20,11 @@ describe('probeConnectivity', () => {
|
|
|
19
20
|
afterEach(() => {
|
|
20
21
|
globalThis.fetch = originalFetch
|
|
21
22
|
if (originalEnv !== undefined) {
|
|
22
|
-
process.env.
|
|
23
|
+
process.env.LYTHOS_GH_MIRROR = originalEnv
|
|
23
24
|
} else {
|
|
24
|
-
delete process.env.
|
|
25
|
+
delete process.env.LYTHOS_GH_MIRROR
|
|
25
26
|
}
|
|
27
|
+
delete process.env.LYTHOSKILL_GH_MIRROR
|
|
26
28
|
if (originalSocks !== undefined) {
|
|
27
29
|
process.env.LYTHOS_SOCKS_PROXY = originalSocks
|
|
28
30
|
} else {
|
|
@@ -67,7 +69,7 @@ describe('probeConnectivity', () => {
|
|
|
67
69
|
|
|
68
70
|
// ── Vertical Slice 2 ──
|
|
69
71
|
test('direct fails, user mirror ok → returns mirror path', async () => {
|
|
70
|
-
process.env.
|
|
72
|
+
process.env.LYTHOS_GH_MIRROR = 'https://my-mirror.example.com'
|
|
71
73
|
mockFetch(
|
|
72
74
|
new Map([
|
|
73
75
|
['https://example.com/skill', new Response(null, { status: 500 })],
|
|
@@ -108,7 +110,7 @@ describe('probeConnectivity', () => {
|
|
|
108
110
|
|
|
109
111
|
// ── Vertical Slice 5: Racing behavior ──
|
|
110
112
|
test('probes race concurrently, not sequentially', async () => {
|
|
111
|
-
process.env.
|
|
113
|
+
process.env.LYTHOS_GH_MIRROR = 'https://my-mirror.example.com'
|
|
112
114
|
const start = performance.now()
|
|
113
115
|
|
|
114
116
|
mockFetch(
|
|
@@ -226,7 +228,7 @@ describe('probeConnectivity', () => {
|
|
|
226
228
|
// ── Vertical Slice 11: SOCKS proxy only affects direct, mirror still works ──
|
|
227
229
|
test('SOCKS proxy fails but mirror succeeds', async () => {
|
|
228
230
|
process.env.LYTHOS_SOCKS_PROXY = '127.0.0.1:1080'
|
|
229
|
-
process.env.
|
|
231
|
+
process.env.LYTHOS_GH_MIRROR = 'https://my-mirror.example.com'
|
|
230
232
|
const execCalls: Array<{ file: string; args: string[] }> = []
|
|
231
233
|
|
|
232
234
|
const result = await probeConnectivity('https://example.com/skill', 3000, {
|
|
@@ -247,4 +249,30 @@ describe('probeConnectivity', () => {
|
|
|
247
249
|
expect(result?.path).toBe('mirror')
|
|
248
250
|
expect(execCalls.length).toBe(1) // only one curl call for direct probe
|
|
249
251
|
})
|
|
252
|
+
|
|
253
|
+
// ── Backward compat: legacy env var name still works ──
|
|
254
|
+
test('LYTHOSKILL_GH_MIRROR (legacy) still works with deprecation warning', async () => {
|
|
255
|
+
// Ensure new name is not set
|
|
256
|
+
delete process.env.LYTHOS_GH_MIRROR
|
|
257
|
+
process.env.LYTHOSKILL_GH_MIRROR = 'https://legacy-mirror.example.com'
|
|
258
|
+
const warnCalls: string[] = []
|
|
259
|
+
const originalWarn = console.warn
|
|
260
|
+
console.warn = (...args: unknown[]) => {
|
|
261
|
+
warnCalls.push(args.map(String).join(' '))
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
mockFetch(
|
|
265
|
+
new Map([
|
|
266
|
+
['https://example.com/skill', new Response(null, { status: 500 })],
|
|
267
|
+
['https://legacy-mirror.example.com/https://example.com/skill', new Response(null, { status: 200 })],
|
|
268
|
+
]),
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
const result = await probeConnectivity('https://example.com/skill')
|
|
272
|
+
|
|
273
|
+
console.warn = originalWarn
|
|
274
|
+
|
|
275
|
+
expect(result?.path).toBe('mirror')
|
|
276
|
+
expect(warnCalls.some((m) => m.includes('deprecated'))).toBe(true)
|
|
277
|
+
})
|
|
250
278
|
})
|
package/src/mirror.ts
CHANGED
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
* Mirror URL rewriting for restricted networks.
|
|
3
3
|
*
|
|
4
4
|
* Two layers only — the tool never decides which third party to trust:
|
|
5
|
-
* 1.
|
|
5
|
+
* 1. LYTHOS_GH_MIRROR env var (explicit user choice, user bears trust)
|
|
6
6
|
* 2. LYTHOS_SOCKS_PROXY / HTTPS_PROXY / HTTP_PROXY (standard, user's own infra)
|
|
7
7
|
*
|
|
8
|
+
* Backward compat: LYTHOSKILL_GH_MIRROR (legacy name) is still read with a
|
|
9
|
+
* deprecation warning. Prefer LYTHOS_GH_MIRROR for consistency with the LYTHOS_
|
|
10
|
+
*
|
|
8
11
|
* No hard-coded mirror list. Auto-fallback to "known" third-party mirrors was
|
|
9
12
|
* removed: the tool must not silently delegate trust to an external service
|
|
10
13
|
* that can return tampered skill files (see ADR-202605130...).
|
|
@@ -13,7 +16,14 @@
|
|
|
13
16
|
import { execFileSync } from 'node:child_process'
|
|
14
17
|
|
|
15
18
|
export function getMirror(): string | undefined {
|
|
16
|
-
|
|
19
|
+
let v = process.env.LYTHOS_GH_MIRROR?.trim()
|
|
20
|
+
if (!v) {
|
|
21
|
+
const legacy = process.env.LYTHOSKILL_GH_MIRROR?.trim()
|
|
22
|
+
if (legacy) {
|
|
23
|
+
console.warn('⚠️ LYTHOSKILL_GH_MIRROR is deprecated. Use LYTHOS_GH_MIRROR instead.')
|
|
24
|
+
v = legacy
|
|
25
|
+
}
|
|
26
|
+
}
|
|
17
27
|
if (!v) return undefined
|
|
18
28
|
if (v.startsWith('http://') || v.startsWith('https://')) {
|
|
19
29
|
return v.replace(/\/+$/, '')
|