@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.
Files changed (113) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +2 -2
  3. package/package.json +21 -2
  4. package/src/cli/index.ts +47 -48
  5. package/src/connect/index.ts +4 -4
  6. package/src/core/constants.ts +3 -3
  7. package/src/core/normalize.ts +2 -2
  8. package/src/create/index.ts +1 -1
  9. package/src/daemon/index.ts +5 -5
  10. package/src/daemon/main.ts +9 -9
  11. package/src/enable/index.ts +19 -18
  12. package/src/enable/provisionCommand.ts +10 -10
  13. package/src/identity/index.ts +2 -2
  14. package/src/identity/profileStandard.ts +8 -8
  15. package/src/init/index.ts +10 -10
  16. package/src/install/index.ts +2 -2
  17. package/src/install/signing.ts +3 -4
  18. package/src/launch/adapters/claude.ts +7 -7
  19. package/src/launch/adapters/codex.ts +5 -6
  20. package/src/launch/canary.ts +8 -8
  21. package/src/launch/cmdlog.ts +3 -3
  22. package/src/launch/composeSystemPrompt.ts +2 -1
  23. package/src/launch/index.ts +5 -6
  24. package/src/launch/invocation.ts +1 -1
  25. package/src/launch/launchd.ts +14 -15
  26. package/src/launch/launchdRun.ts +6 -6
  27. package/src/launch/nativeMemory.ts +9 -9
  28. package/src/launch/ptyHost.ts +1 -1
  29. package/src/launch/readyGateModel.ts +3 -3
  30. package/src/launch/types.ts +7 -7
  31. package/src/lifecycle/eventlog.ts +2 -2
  32. package/src/lifecycle/index.ts +21 -21
  33. package/src/lifecycle/queue.ts +1 -1
  34. package/src/onboard/index.ts +19 -13
  35. package/src/onboard/memory.ts +5 -5
  36. package/src/onboard/steps.ts +8 -9
  37. package/src/provision/index.ts +2 -3
  38. package/src/runtime/deploy.ts +2 -2
  39. package/src/runtime/index.ts +4 -4
  40. package/src/shadow/gate.ts +6 -6
  41. package/src/shadow/index.ts +2 -2
  42. package/src/status/index.ts +11 -11
  43. package/src/storage/index.ts +1 -1
  44. package/src/supervisor/daemon.ts +14 -8
  45. package/src/transport/index.ts +11 -11
  46. package/src/update/index.ts +4 -4
  47. package/src/cli/cli.test.ts +0 -603
  48. package/src/cli/listTui.test.ts +0 -71
  49. package/src/codec/codec.test.ts +0 -271
  50. package/src/connect/connect.test.ts +0 -163
  51. package/src/core/constants.test.ts +0 -32
  52. package/src/core/normalize.test.ts +0 -98
  53. package/src/create/create.test.ts +0 -143
  54. package/src/daemon/daemon-http.test.ts +0 -114
  55. package/src/daemon/daemon.test.ts +0 -267
  56. package/src/daemon/main.test.ts +0 -413
  57. package/src/enable/enable.test.ts +0 -95
  58. package/src/enable/provisionCommand.test.ts +0 -107
  59. package/src/identity/identity.test.ts +0 -279
  60. package/src/identity/profileStandard.test.ts +0 -204
  61. package/src/init/init.test.ts +0 -215
  62. package/src/init/runtime-resolve.test.ts +0 -49
  63. package/src/install/install.test.ts +0 -66
  64. package/src/install/signing.test.ts +0 -84
  65. package/src/launch/bootdeliver.test.ts +0 -108
  66. package/src/launch/bootstrap.test.ts +0 -56
  67. package/src/launch/canary.test.ts +0 -346
  68. package/src/launch/cmdlog.test.ts +0 -94
  69. package/src/launch/codexHooksTrust.test.ts +0 -248
  70. package/src/launch/composeSystemPrompt.layers.test.ts +0 -445
  71. package/src/launch/composeSystemPrompt.test.ts +0 -145
  72. package/src/launch/hostComposerOccupied.test.ts +0 -63
  73. package/src/launch/invocation.test.ts +0 -174
  74. package/src/launch/launch.test.ts +0 -359
  75. package/src/launch/launchd.test.ts +0 -499
  76. package/src/launch/nativeMemory.test.ts +0 -193
  77. package/src/launch/ptyHost.test.ts +0 -38
  78. package/src/launch/readyGateModel.test.ts +0 -72
  79. package/src/launch/sockdir.test.ts +0 -74
  80. package/src/lifecycle/eventlog.test.ts +0 -114
  81. package/src/lifecycle/lifecycle.test.ts +0 -1056
  82. package/src/lifecycle/queue.test.ts +0 -185
  83. package/src/onboard/memory.test.ts +0 -157
  84. package/src/onboard/onboard.test.ts +0 -39
  85. package/src/onboard/steps.test.ts +0 -201
  86. package/src/provision/provision.test.ts +0 -288
  87. package/src/registry/registry.test.ts +0 -432
  88. package/src/runtime/runtime.test.ts +0 -226
  89. package/src/runtime/update.test.ts +0 -192
  90. package/src/shadow/enumerate-skip.test.ts +0 -67
  91. package/src/shadow/gate.test.ts +0 -286
  92. package/src/shadow/install.test.ts +0 -153
  93. package/src/shadow/shadow.test.ts +0 -42
  94. package/src/status/status.test.ts +0 -208
  95. package/src/storage/peers-home.test.ts +0 -34
  96. package/src/storage/rotatelog.test.ts +0 -44
  97. package/src/storage/storage.test.ts +0 -65
  98. package/src/supervisor/attached-marker.test.ts +0 -84
  99. package/src/supervisor/boot.test.ts +0 -66
  100. package/src/supervisor/client.attach.test.ts +0 -107
  101. package/src/supervisor/daemon.test.ts +0 -213
  102. package/src/supervisor/deliver.test.ts +0 -58
  103. package/src/supervisor/panelog.test.ts +0 -95
  104. package/src/supervisor/protocol.test.ts +0 -222
  105. package/src/supervisor/selfargv.test.ts +0 -22
  106. package/src/supervisor/spinner-strip.test.ts +0 -52
  107. package/src/transport/compactDone.test.ts +0 -144
  108. package/src/transport/composerQueue.test.ts +0 -204
  109. package/src/transport/hostControl.test.ts +0 -87
  110. package/src/transport/hostDeliver.test.ts +0 -137
  111. package/src/transport/hostLive.test.ts +0 -50
  112. package/src/transport/routesend-wake.test.ts +0 -357
  113. 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
- })