@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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Cold pool service layer for the lythoskill ecosystem.
4
4
 
5
- > Status: 0.9.32 — public API. Reconciliation (reconcile plan) is functional; execute convergence WIP.
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.14.5",
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.14.5",
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 (env var > default)
55
- const coldPoolPath = process.env.LYTHOS_COLD_POOL ?? DEFAULT_COLD_POOL_PATH
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 = process.env.LYTHOS_COLD_POOL
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
 
@@ -9,8 +9,9 @@ describe('probeConnectivity', () => {
9
9
 
10
10
  beforeEach(() => {
11
11
  originalFetch = globalThis.fetch
12
- originalEnv = process.env.LYTHOSKILL_GH_MIRROR
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.LYTHOSKILL_GH_MIRROR = originalEnv
23
+ process.env.LYTHOS_GH_MIRROR = originalEnv
23
24
  } else {
24
- delete process.env.LYTHOSKILL_GH_MIRROR
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.LYTHOSKILL_GH_MIRROR = 'https://my-mirror.example.com'
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.LYTHOSKILL_GH_MIRROR = 'https://my-mirror.example.com'
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.LYTHOSKILL_GH_MIRROR = 'https://my-mirror.example.com'
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. LYTHOSKILL_GH_MIRROR env var (explicit user choice, user bears trust)
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
- const v = process.env.LYTHOSKILL_GH_MIRROR?.trim()
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(/\/+$/, '')