@agfpd/iapeer 0.2.77 → 0.2.78
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/LICENSE +202 -0
- package/README.md +2 -2
- package/package.json +21 -2
- package/src/cli/index.ts +47 -48
- package/src/connect/index.ts +4 -4
- package/src/core/constants.ts +3 -3
- package/src/core/normalize.ts +2 -2
- package/src/create/index.ts +1 -1
- package/src/daemon/index.ts +5 -5
- package/src/daemon/main.ts +9 -9
- package/src/enable/index.ts +19 -18
- package/src/enable/provisionCommand.ts +10 -10
- package/src/identity/index.ts +2 -2
- package/src/identity/profileStandard.ts +8 -8
- package/src/init/index.ts +10 -10
- package/src/install/index.ts +2 -2
- package/src/install/signing.ts +3 -4
- package/src/launch/adapters/claude.ts +7 -7
- package/src/launch/adapters/codex.ts +5 -6
- package/src/launch/canary.ts +8 -8
- package/src/launch/cmdlog.ts +3 -3
- package/src/launch/composeSystemPrompt.ts +2 -1
- package/src/launch/index.ts +5 -6
- package/src/launch/invocation.ts +1 -1
- package/src/launch/launchd.ts +14 -15
- package/src/launch/launchdRun.ts +6 -6
- package/src/launch/nativeMemory.ts +9 -9
- package/src/launch/ptyHost.ts +1 -1
- package/src/launch/readyGateModel.ts +3 -3
- package/src/launch/types.ts +7 -7
- package/src/lifecycle/eventlog.ts +2 -2
- package/src/lifecycle/index.ts +21 -21
- package/src/lifecycle/queue.ts +1 -1
- package/src/onboard/index.ts +19 -13
- package/src/onboard/memory.ts +5 -5
- package/src/onboard/steps.ts +8 -9
- package/src/provision/index.ts +2 -3
- package/src/runtime/deploy.ts +2 -2
- package/src/runtime/index.ts +4 -4
- package/src/shadow/gate.ts +6 -6
- package/src/shadow/index.ts +2 -2
- package/src/status/index.ts +11 -11
- package/src/storage/index.ts +1 -1
- package/src/supervisor/daemon.ts +14 -8
- package/src/transport/index.ts +11 -11
- package/src/update/index.ts +4 -4
- package/src/cli/cli.test.ts +0 -603
- package/src/cli/listTui.test.ts +0 -71
- package/src/codec/codec.test.ts +0 -271
- package/src/connect/connect.test.ts +0 -163
- package/src/core/constants.test.ts +0 -32
- package/src/core/normalize.test.ts +0 -98
- package/src/create/create.test.ts +0 -143
- package/src/daemon/daemon-http.test.ts +0 -114
- package/src/daemon/daemon.test.ts +0 -267
- package/src/daemon/main.test.ts +0 -413
- package/src/enable/enable.test.ts +0 -95
- package/src/enable/provisionCommand.test.ts +0 -107
- package/src/identity/identity.test.ts +0 -279
- package/src/identity/profileStandard.test.ts +0 -204
- package/src/init/init.test.ts +0 -215
- package/src/init/runtime-resolve.test.ts +0 -49
- package/src/install/install.test.ts +0 -66
- package/src/install/signing.test.ts +0 -84
- package/src/launch/bootdeliver.test.ts +0 -108
- package/src/launch/bootstrap.test.ts +0 -56
- package/src/launch/canary.test.ts +0 -346
- package/src/launch/cmdlog.test.ts +0 -94
- package/src/launch/codexHooksTrust.test.ts +0 -248
- package/src/launch/composeSystemPrompt.layers.test.ts +0 -445
- package/src/launch/composeSystemPrompt.test.ts +0 -145
- package/src/launch/hostComposerOccupied.test.ts +0 -63
- package/src/launch/invocation.test.ts +0 -174
- package/src/launch/launch.test.ts +0 -359
- package/src/launch/launchd.test.ts +0 -499
- package/src/launch/nativeMemory.test.ts +0 -193
- package/src/launch/ptyHost.test.ts +0 -38
- package/src/launch/readyGateModel.test.ts +0 -72
- package/src/launch/sockdir.test.ts +0 -74
- package/src/lifecycle/eventlog.test.ts +0 -114
- package/src/lifecycle/lifecycle.test.ts +0 -1056
- package/src/lifecycle/queue.test.ts +0 -185
- package/src/onboard/memory.test.ts +0 -157
- package/src/onboard/onboard.test.ts +0 -39
- package/src/onboard/steps.test.ts +0 -201
- package/src/provision/provision.test.ts +0 -288
- package/src/registry/registry.test.ts +0 -432
- package/src/runtime/runtime.test.ts +0 -226
- package/src/runtime/update.test.ts +0 -192
- package/src/shadow/enumerate-skip.test.ts +0 -67
- package/src/shadow/gate.test.ts +0 -286
- package/src/shadow/install.test.ts +0 -153
- package/src/shadow/shadow.test.ts +0 -42
- package/src/status/status.test.ts +0 -208
- package/src/storage/peers-home.test.ts +0 -34
- package/src/storage/rotatelog.test.ts +0 -44
- package/src/storage/storage.test.ts +0 -65
- package/src/supervisor/attached-marker.test.ts +0 -84
- package/src/supervisor/boot.test.ts +0 -66
- package/src/supervisor/client.attach.test.ts +0 -107
- package/src/supervisor/daemon.test.ts +0 -213
- package/src/supervisor/deliver.test.ts +0 -58
- package/src/supervisor/panelog.test.ts +0 -95
- package/src/supervisor/protocol.test.ts +0 -222
- package/src/supervisor/selfargv.test.ts +0 -22
- package/src/supervisor/spinner-strip.test.ts +0 -52
- package/src/transport/compactDone.test.ts +0 -144
- package/src/transport/composerQueue.test.ts +0 -204
- package/src/transport/hostControl.test.ts +0 -87
- package/src/transport/hostDeliver.test.ts +0 -137
- package/src/transport/hostLive.test.ts +0 -50
- package/src/transport/routesend-wake.test.ts +0 -357
- package/src/update/update.test.ts +0 -208
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
// updateIapeer — the version-gated, cloud-only deploy. The three side-effects
|
|
2
|
-
// (resolve latest / install / restart) are injected, so the gate logic is tested
|
|
3
|
-
// with NO network and NO launchctl. The sandbox guard on the REAL installer is
|
|
4
|
-
// exercised too (a test must never npx-install over the prod binary).
|
|
5
|
-
|
|
6
|
-
import { describe, expect, test } from 'bun:test'
|
|
7
|
-
import { IAPEER_VERSION, recycleFoundationOwnedInfraJobs, updateIapeer, waitForDaemonHealthy } from '../index.ts'
|
|
8
|
-
import type { DaemonRestartResult } from '../launch/launchd.ts'
|
|
9
|
-
|
|
10
|
-
const restarted = (): DaemonRestartResult => ({ state: 'restarted' })
|
|
11
|
-
|
|
12
|
-
/** A deps bundle with call-tracking spies. `latest` is what the resolver returns for
|
|
13
|
-
* the spec (latest OR a pinned `target`); null simulates "not found / unreachable". */
|
|
14
|
-
function harness(opts: {
|
|
15
|
-
current: string
|
|
16
|
-
latest: string | null
|
|
17
|
-
target?: string
|
|
18
|
-
installOk?: boolean
|
|
19
|
-
restart?: DaemonRestartResult
|
|
20
|
-
recycle?: ReturnType<typeof recycleFoundationOwnedInfraJobs>
|
|
21
|
-
force?: boolean
|
|
22
|
-
}) {
|
|
23
|
-
const calls = { install: [] as string[], restart: 0, recycle: 0, resolved: [] as string[] }
|
|
24
|
-
const result = updateIapeer({
|
|
25
|
-
env: { IAPEER_TEST_SANDBOX: '1' },
|
|
26
|
-
force: opts.force,
|
|
27
|
-
currentVersion: opts.current,
|
|
28
|
-
targetVersion: opts.target,
|
|
29
|
-
resolveVersion: spec => {
|
|
30
|
-
calls.resolved.push(spec)
|
|
31
|
-
return opts.latest
|
|
32
|
-
},
|
|
33
|
-
runInstall: v => {
|
|
34
|
-
calls.install.push(v)
|
|
35
|
-
return opts.installOk ?? true
|
|
36
|
-
},
|
|
37
|
-
restartDaemon: () => {
|
|
38
|
-
calls.restart++
|
|
39
|
-
return opts.restart ?? restarted()
|
|
40
|
-
},
|
|
41
|
-
recycleInfraJobs: () => {
|
|
42
|
-
calls.recycle++
|
|
43
|
-
return opts.recycle ?? []
|
|
44
|
-
},
|
|
45
|
-
})
|
|
46
|
-
return { result, calls }
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
describe('updateIapeer — version gate', () => {
|
|
50
|
-
test('already at latest → no install, no restart', () => {
|
|
51
|
-
const { result, calls } = harness({ current: '0.2.2', latest: '0.2.2' })
|
|
52
|
-
expect(result.status).toBe('already-latest')
|
|
53
|
-
expect(result.from).toBe('0.2.2')
|
|
54
|
-
expect(result.latest).toBe('0.2.2')
|
|
55
|
-
expect(calls.install).toEqual([])
|
|
56
|
-
expect(calls.restart).toBe(0)
|
|
57
|
-
expect(calls.recycle).toBe(0)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
test('--force reinstalls + restarts even when already latest', () => {
|
|
61
|
-
const { result, calls } = harness({ current: '0.2.2', latest: '0.2.2', force: true })
|
|
62
|
-
expect(result.status).toBe('updated')
|
|
63
|
-
expect(result.to).toBe('0.2.2')
|
|
64
|
-
expect(calls.install).toEqual(['0.2.2'])
|
|
65
|
-
expect(calls.restart).toBe(1)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
test('newer published version → installs THAT version + restarts', () => {
|
|
69
|
-
const { result, calls } = harness({ current: '0.2.2', latest: '0.3.0' })
|
|
70
|
-
expect(result.status).toBe('updated')
|
|
71
|
-
expect(result.from).toBe('0.2.2')
|
|
72
|
-
expect(result.to).toBe('0.3.0')
|
|
73
|
-
expect(result.daemon).toBe('restarted')
|
|
74
|
-
expect(result.infra).toEqual([])
|
|
75
|
-
expect(calls.install).toEqual(['0.3.0']) // installs latest, not current
|
|
76
|
-
expect(calls.restart).toBe(1)
|
|
77
|
-
expect(calls.recycle).toBe(1)
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
test('after binary install, loaded foundation-owned infra jobs are recycled too', () => {
|
|
81
|
-
const recycle = [{ personality: 'timer', runtime: 'notifier', label: 'com.iapeer.timer', state: 'restarted' as const }]
|
|
82
|
-
const { result, calls } = harness({ current: '0.2.2', latest: '0.3.0', recycle })
|
|
83
|
-
expect(result.status).toBe('updated')
|
|
84
|
-
expect(result.infra).toEqual(recycle)
|
|
85
|
-
expect(calls.recycle).toBe(1)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
test('no target → resolves the "latest" spec', () => {
|
|
89
|
-
const { calls } = harness({ current: '0.2.2', latest: '0.3.0' })
|
|
90
|
-
expect(calls.resolved).toEqual(['latest'])
|
|
91
|
-
})
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
describe('updateIapeer — pinned version (one-shot target)', () => {
|
|
95
|
-
test('pin to an exact version → resolves THAT spec and installs it', () => {
|
|
96
|
-
const { result, calls } = harness({ current: '0.2.4', target: '0.2.2', latest: '0.2.2' })
|
|
97
|
-
expect(calls.resolved).toEqual(['0.2.2']) // resolves the pinned spec, not "latest"
|
|
98
|
-
expect(result.status).toBe('updated')
|
|
99
|
-
expect(result.from).toBe('0.2.4')
|
|
100
|
-
expect(result.to).toBe('0.2.2') // a DOWNGRADE — deeper recovery than the single .prev
|
|
101
|
-
expect(calls.install).toEqual(['0.2.2'])
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
test('pinned version already installed → already-at, no install', () => {
|
|
105
|
-
const { result, calls } = harness({ current: '0.2.2', target: '0.2.2', latest: '0.2.2' })
|
|
106
|
-
expect(result.status).toBe('already-latest')
|
|
107
|
-
expect(calls.install).toEqual([])
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
test('pinned version not found on npm → failed (not an npx error)', () => {
|
|
111
|
-
const { result, calls } = harness({ current: '0.2.4', target: '9.9.9', latest: null })
|
|
112
|
-
expect(result.status).toBe('failed')
|
|
113
|
-
expect(result.reason).toMatch(/"9\.9\.9" not found on npm/i)
|
|
114
|
-
expect(calls.install).toEqual([])
|
|
115
|
-
expect(calls.restart).toBe(0)
|
|
116
|
-
})
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
describe('updateIapeer — failure paths', () => {
|
|
120
|
-
test('latest unresolved (offline / registry error) → failed, no install', () => {
|
|
121
|
-
const { result, calls } = harness({ current: '0.2.2', latest: null })
|
|
122
|
-
expect(result.status).toBe('failed')
|
|
123
|
-
expect(result.reason).toMatch(/latest.*version.*npm|offline|registry/i)
|
|
124
|
-
expect(calls.install).toEqual([])
|
|
125
|
-
expect(calls.restart).toBe(0)
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
test('install fails → failed, daemon NOT restarted', () => {
|
|
129
|
-
const { result, calls } = harness({ current: '0.2.2', latest: '0.3.0', installOk: false })
|
|
130
|
-
expect(result.status).toBe('failed')
|
|
131
|
-
expect(result.latest).toBe('0.3.0')
|
|
132
|
-
expect(result.reason).toMatch(/install.*failed/i)
|
|
133
|
-
expect(calls.restart).toBe(0)
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
test('daemon not loaded → updated, daemon=not-loaded (no error)', () => {
|
|
137
|
-
const { result } = harness({ current: '0.2.2', latest: '0.3.0', restart: { state: 'not-loaded' } })
|
|
138
|
-
expect(result.status).toBe('updated')
|
|
139
|
-
expect(result.daemon).toBe('not-loaded')
|
|
140
|
-
expect(result.reason).toBeUndefined()
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
test('binary updated but restart failed → updated with a warning reason', () => {
|
|
144
|
-
const { result, calls } = harness({
|
|
145
|
-
current: '0.2.2',
|
|
146
|
-
latest: '0.3.0',
|
|
147
|
-
restart: { state: 'failed', detail: 'kickstart exit 1' },
|
|
148
|
-
})
|
|
149
|
-
expect(result.status).toBe('updated')
|
|
150
|
-
expect(result.daemon).toBe('failed')
|
|
151
|
-
expect(result.reason).toMatch(/restart failed.*kickstart exit 1/i)
|
|
152
|
-
expect(calls.recycle).toBe(0)
|
|
153
|
-
})
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
describe('updateIapeer — real-installer sandbox guard', () => {
|
|
157
|
-
test('default runInstall refuses a real install under IAPEER_TEST_SANDBOX', () => {
|
|
158
|
-
// fetchLatest injected (newer) so the gate proceeds to the DEFAULT installer,
|
|
159
|
-
// which must refuse rather than fetch+build over the prod ~/.local/bin/iapeer.
|
|
160
|
-
expect(() =>
|
|
161
|
-
updateIapeer({
|
|
162
|
-
env: { IAPEER_TEST_SANDBOX: '1' },
|
|
163
|
-
currentVersion: '0.2.2',
|
|
164
|
-
resolveVersion: () => '0.3.0',
|
|
165
|
-
// runInstall NOT injected → exercises the real defaultRunInstall guard.
|
|
166
|
-
restartDaemon: restarted,
|
|
167
|
-
}),
|
|
168
|
-
).toThrow(/IAPEER_TEST_SANDBOX/)
|
|
169
|
-
})
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
describe('IAPEER_VERSION', () => {
|
|
173
|
-
test('is a baked semver string', () => {
|
|
174
|
-
expect(IAPEER_VERSION).toMatch(/^\d+\.\d+\.\d+/)
|
|
175
|
-
})
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
/** A probe returning the given sequence (repeats the last element once exhausted). */
|
|
179
|
-
function seqProbe(seq: boolean[]): () => Promise<boolean> {
|
|
180
|
-
let i = 0
|
|
181
|
-
return () => Promise.resolve(seq[Math.min(i++, seq.length - 1)])
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
describe('waitForDaemonHealthy', () => {
|
|
185
|
-
test('two consecutive successes → healthy', async () => {
|
|
186
|
-
const h = await waitForDaemonHealthy({ probe: seqProbe([true, true]), needConsecutive: 2, timeoutMs: 1000, intervalMs: 1 })
|
|
187
|
-
expect(h.healthy).toBe(true)
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
test('a single bind-then-crash flap does NOT read as healthy (streak resets)', async () => {
|
|
191
|
-
// true, false, true, true → first success is wiped by the false; only the trailing
|
|
192
|
-
// pair (true,true) satisfies needConsecutive=2.
|
|
193
|
-
const h = await waitForDaemonHealthy({ probe: seqProbe([true, false, true, true]), needConsecutive: 2, timeoutMs: 1000, intervalMs: 1 })
|
|
194
|
-
expect(h.healthy).toBe(true)
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
test('never responds within the window → unhealthy with a detail', async () => {
|
|
198
|
-
const h = await waitForDaemonHealthy({ probe: seqProbe([false]), needConsecutive: 2, timeoutMs: 40, intervalMs: 5 })
|
|
199
|
-
expect(h.healthy).toBe(false)
|
|
200
|
-
expect(h.detail).toMatch(/did not become healthy/i)
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
test('IAPEER_TEST_SANDBOX with no injected probe → skipped healthy (never hits a real socket)', async () => {
|
|
204
|
-
const h = await waitForDaemonHealthy({ env: { IAPEER_TEST_SANDBOX: '1' } as NodeJS.ProcessEnv })
|
|
205
|
-
expect(h.healthy).toBe(true)
|
|
206
|
-
expect(h.detail).toBe('skipped-sandbox')
|
|
207
|
-
})
|
|
208
|
-
})
|