@agent-link/agent 0.1.293 → 0.1.295

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 (42) hide show
  1. package/dist/adoption-lock.d.ts +14 -0
  2. package/dist/adoption-lock.js +54 -0
  3. package/dist/adoption-lock.js.map +1 -0
  4. package/dist/adoption.d.ts +21 -0
  5. package/dist/adoption.js +303 -0
  6. package/dist/adoption.js.map +1 -0
  7. package/dist/bootstrap-delegator.d.ts +7 -0
  8. package/dist/bootstrap-delegator.js +36 -0
  9. package/dist/bootstrap-delegator.js.map +1 -0
  10. package/dist/cli.js +86 -3
  11. package/dist/cli.js.map +1 -1
  12. package/dist/config.d.ts +17 -2
  13. package/dist/config.js +25 -2
  14. package/dist/config.js.map +1 -1
  15. package/dist/index.js +16 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/launcher-manager.d.ts +9 -0
  18. package/dist/launcher-manager.js +84 -0
  19. package/dist/launcher-manager.js.map +1 -0
  20. package/dist/runtime-release.d.ts +41 -0
  21. package/dist/runtime-release.js +218 -0
  22. package/dist/runtime-release.js.map +1 -0
  23. package/dist/safe-tar.d.ts +11 -0
  24. package/dist/safe-tar.js +180 -0
  25. package/dist/safe-tar.js.map +1 -0
  26. package/dist/self-check.d.ts +14 -0
  27. package/dist/self-check.js +62 -0
  28. package/dist/self-check.js.map +1 -0
  29. package/dist/service.d.ts +11 -1
  30. package/dist/service.js +32 -4
  31. package/dist/service.js.map +1 -1
  32. package/dist/start-launch-spec.d.ts +4 -0
  33. package/dist/start-launch-spec.js +25 -0
  34. package/dist/start-launch-spec.js.map +1 -1
  35. package/dist/version-stager.d.ts +6 -0
  36. package/dist/version-stager.js +88 -0
  37. package/dist/version-stager.js.map +1 -0
  38. package/dist/version-store.d.ts +51 -0
  39. package/dist/version-store.js +277 -0
  40. package/dist/version-store.js.map +1 -0
  41. package/launcher/launcher.cjs +110 -0
  42. package/package.json +3 -2
@@ -0,0 +1,218 @@
1
+ import { createHash } from 'crypto';
2
+ const RUNTIME_MANIFEST_BASE_URL = 'https://msclaude.ai/files/agent/runtime/';
3
+ const ALLOWED_ORIGIN = 'https://msclaude.ai';
4
+ const ALLOWED_PATH = '/files/agent/runtime/';
5
+ const MAX_MANIFEST_SIZE = 128 * 1024;
6
+ const MAX_BUNDLE_SIZE = 150 * 1024 * 1024;
7
+ const REQUEST_TIMEOUT_MS = 60_000;
8
+ const STABLE_SEMVER = /^\d+\.\d+\.\d+$/;
9
+ const SHA1 = /^[a-f0-9]{40}$/;
10
+ function requireString(value, field) {
11
+ if (typeof value !== 'string' || value.length === 0) {
12
+ throw new Error(`Invalid runtime manifest: ${field} must be a non-empty string`);
13
+ }
14
+ return value;
15
+ }
16
+ function validateIntegrity(value) {
17
+ const integrity = requireString(value, 'integrity');
18
+ if (!integrity.startsWith('sha512-')) {
19
+ throw new Error('Invalid runtime manifest: integrity must use SHA-512');
20
+ }
21
+ const encoded = integrity.slice('sha512-'.length);
22
+ const digest = Buffer.from(encoded, 'base64');
23
+ if (digest.length !== 64 || digest.toString('base64') !== encoded) {
24
+ throw new Error('Invalid runtime manifest: integrity is not valid SHA-512 base64');
25
+ }
26
+ return integrity;
27
+ }
28
+ function isLoopbackUrl(url) {
29
+ return (url.protocol === 'http:' || url.protocol === 'https:')
30
+ && (url.hostname === '127.0.0.1' || url.hostname === 'localhost' || url.hostname === '::1');
31
+ }
32
+ function validateArtifactUrl(value, allowLoopback) {
33
+ const artifactUrl = new URL(requireString(value, 'bundle URL'));
34
+ const production = artifactUrl.origin === ALLOWED_ORIGIN
35
+ && artifactUrl.pathname.startsWith(ALLOWED_PATH);
36
+ if ((!production && !(allowLoopback && isLoopbackUrl(artifactUrl)))
37
+ || !artifactUrl.pathname.endsWith('.tgz')
38
+ || artifactUrl.username
39
+ || artifactUrl.password
40
+ || artifactUrl.search
41
+ || artifactUrl.hash) {
42
+ throw new Error('Invalid runtime manifest: bundle URL is not allowed');
43
+ }
44
+ return artifactUrl.toString();
45
+ }
46
+ export function getRuntimeManifestUrl(version) {
47
+ if (!STABLE_SEMVER.test(version))
48
+ throw new Error('Runtime version must use major.minor.patch');
49
+ return `${RUNTIME_MANIFEST_BASE_URL}${version}/manifest.json`;
50
+ }
51
+ export function validateRuntimeManifest(value, expectedVersion, options = {}) {
52
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
53
+ throw new Error('Invalid runtime manifest: expected an object');
54
+ }
55
+ const manifest = value;
56
+ if (manifest.schemaVersion !== 1 || manifest.package !== '@agent-link/agent') {
57
+ throw new Error('Invalid runtime manifest: unsupported schema or package');
58
+ }
59
+ const version = requireString(manifest.version, 'version');
60
+ if (!STABLE_SEMVER.test(version) || version !== expectedVersion) {
61
+ throw new Error(`Invalid runtime manifest: version must equal ${expectedVersion}`);
62
+ }
63
+ const publishedAt = requireString(manifest.publishedAt, 'publishedAt');
64
+ if (!Number.isFinite(Date.parse(publishedAt))) {
65
+ throw new Error('Invalid runtime manifest: publishedAt must be an ISO timestamp');
66
+ }
67
+ if (!Array.isArray(manifest.bundles) || manifest.bundles.length === 0) {
68
+ throw new Error('Invalid runtime manifest: bundles must be a non-empty array');
69
+ }
70
+ const seen = new Set();
71
+ const bundles = manifest.bundles.map((entry, index) => {
72
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
73
+ throw new Error(`Invalid runtime manifest: bundle ${index} must be an object`);
74
+ }
75
+ const bundle = entry;
76
+ const platform = requireString(bundle.platform, `bundle ${index} platform`);
77
+ if (!['win32', 'linux', 'darwin'].includes(platform)) {
78
+ throw new Error(`Invalid runtime manifest: bundle ${index} platform is unsupported`);
79
+ }
80
+ const arch = requireString(bundle.arch, `bundle ${index} arch`);
81
+ if (!['x64', 'arm64'].includes(arch)) {
82
+ throw new Error(`Invalid runtime manifest: bundle ${index} arch is unsupported`);
83
+ }
84
+ const tuple = `${platform}-${arch}`;
85
+ if (seen.has(tuple))
86
+ throw new Error(`Invalid runtime manifest: duplicate bundle ${tuple}`);
87
+ seen.add(tuple);
88
+ const nodeRange = requireString(bundle.nodeRange, `bundle ${index} nodeRange`);
89
+ if (nodeRange !== '>=18') {
90
+ throw new Error(`Invalid runtime manifest: bundle ${index} nodeRange is unsupported`);
91
+ }
92
+ const shasum = requireString(bundle.shasum, `bundle ${index} shasum`).toLowerCase();
93
+ if (!SHA1.test(shasum)) {
94
+ throw new Error(`Invalid runtime manifest: bundle ${index} shasum must be SHA-1`);
95
+ }
96
+ if (!Number.isSafeInteger(bundle.size) || bundle.size < 1 || bundle.size > MAX_BUNDLE_SIZE) {
97
+ throw new Error(`Invalid runtime manifest: bundle ${index} size is invalid`);
98
+ }
99
+ return {
100
+ platform,
101
+ arch,
102
+ nodeRange,
103
+ url: validateArtifactUrl(bundle.url, options.allowLoopback === true),
104
+ integrity: validateIntegrity(bundle.integrity),
105
+ shasum,
106
+ size: bundle.size,
107
+ };
108
+ });
109
+ return {
110
+ schemaVersion: 1,
111
+ package: '@agent-link/agent',
112
+ version,
113
+ publishedAt,
114
+ ...(typeof manifest.sourceTag === 'string' ? { sourceTag: manifest.sourceTag } : {}),
115
+ ...(typeof manifest.sourceCommit === 'string' ? { sourceCommit: manifest.sourceCommit } : {}),
116
+ bundles,
117
+ };
118
+ }
119
+ async function fetchBuffer(url, fetchImpl, maxSize) {
120
+ const controller = new AbortController();
121
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
122
+ try {
123
+ const response = await fetchImpl(url, {
124
+ signal: controller.signal,
125
+ redirect: 'error',
126
+ headers: { 'user-agent': 'agentlink-version-store' },
127
+ });
128
+ if (!response.ok)
129
+ throw new Error(`HTTP ${response.status} ${response.statusText}`.trim());
130
+ const declaredLength = Number(response.headers.get('content-length'));
131
+ if (Number.isFinite(declaredLength) && declaredLength > maxSize) {
132
+ throw new Error(`response exceeds ${maxSize} bytes`);
133
+ }
134
+ if (!response.body)
135
+ return Buffer.alloc(0);
136
+ const chunks = [];
137
+ let total = 0;
138
+ const reader = response.body.getReader();
139
+ try {
140
+ for (;;) {
141
+ const { done, value } = await reader.read();
142
+ if (done)
143
+ break;
144
+ total += value.byteLength;
145
+ if (total > maxSize) {
146
+ await reader.cancel();
147
+ throw new Error(`response exceeds ${maxSize} bytes`);
148
+ }
149
+ chunks.push(Buffer.from(value));
150
+ }
151
+ }
152
+ finally {
153
+ reader.releaseLock();
154
+ }
155
+ return Buffer.concat(chunks, total);
156
+ }
157
+ finally {
158
+ clearTimeout(timeout);
159
+ }
160
+ }
161
+ export async function fetchRuntimeManifest(version, options = {}) {
162
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
163
+ const manifestUrl = options.manifestUrl ?? getRuntimeManifestUrl(version);
164
+ const parsedUrl = new URL(manifestUrl);
165
+ const allowLoopback = isLoopbackUrl(parsedUrl);
166
+ if (options.manifestUrl && !allowLoopback) {
167
+ throw new Error('Runtime manifest override must use a loopback URL');
168
+ }
169
+ let bytes;
170
+ try {
171
+ bytes = await fetchBuffer(manifestUrl, fetchImpl, MAX_MANIFEST_SIZE);
172
+ }
173
+ catch (error) {
174
+ throw new Error(`Failed to download runtime manifest: ${error.message}`);
175
+ }
176
+ let value;
177
+ try {
178
+ value = JSON.parse(bytes.toString('utf8'));
179
+ }
180
+ catch {
181
+ throw new Error('Invalid runtime manifest: response is not valid JSON');
182
+ }
183
+ return {
184
+ manifest: validateRuntimeManifest(value, version, { allowLoopback }),
185
+ manifestUrl: parsedUrl.toString(),
186
+ };
187
+ }
188
+ export function selectRuntimeBundle(manifest, platform = process.platform, arch = process.arch) {
189
+ const bundle = manifest.bundles.find(item => item.platform === platform && item.arch === arch);
190
+ if (!bundle) {
191
+ throw new Error(`No runtime bundle is available for ${platform}-${arch}; version-store adoption remains disabled`);
192
+ }
193
+ return bundle;
194
+ }
195
+ export function verifyRuntimeBundle(bytes, bundle) {
196
+ if (bytes.length !== bundle.size) {
197
+ throw new Error(`Runtime bundle size mismatch: expected ${bundle.size}, received ${bytes.length}`);
198
+ }
199
+ const shasum = createHash('sha1').update(bytes).digest('hex');
200
+ if (shasum !== bundle.shasum)
201
+ throw new Error('Runtime bundle SHA-1 mismatch');
202
+ const integrity = `sha512-${createHash('sha512').update(bytes).digest('base64')}`;
203
+ if (integrity !== bundle.integrity)
204
+ throw new Error('Runtime bundle SHA-512 mismatch');
205
+ }
206
+ export async function prepareRuntimeBundle(manifest, options = {}) {
207
+ const bundle = selectRuntimeBundle(manifest, options.platform, options.arch);
208
+ let bytes;
209
+ try {
210
+ bytes = await fetchBuffer(bundle.url, options.fetchImpl ?? globalThis.fetch, bundle.size);
211
+ }
212
+ catch (error) {
213
+ throw new Error(`Failed to download runtime bundle: ${error.message}`);
214
+ }
215
+ verifyRuntimeBundle(bytes, bundle);
216
+ return { manifest, bundle, bytes };
217
+ }
218
+ //# sourceMappingURL=runtime-release.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-release.js","sourceRoot":"","sources":["../src/runtime-release.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,MAAM,yBAAyB,GAAG,0CAA0C,CAAC;AAC7E,MAAM,cAAc,GAAG,qBAAqB,CAAC;AAC7C,MAAM,YAAY,GAAG,uBAAuB,CAAC;AAC7C,MAAM,iBAAiB,GAAG,GAAG,GAAG,IAAI,CAAC;AACrC,MAAM,eAAe,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AAC1C,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,aAAa,GAAG,iBAAiB,CAAC;AACxC,MAAM,IAAI,GAAG,gBAAgB,CAAC;AA4B9B,SAAS,aAAa,CAAC,KAAc,EAAE,KAAa;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,6BAA6B,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IACpD,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,OAAO,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,aAAa,CAAC,GAAQ;IAC7B,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;WACzD,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC;AAChG,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc,EAAE,aAAsB;IACjE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAChE,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,KAAK,cAAc;WACnD,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IACnD,IACE,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,aAAa,IAAI,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC;WAC5D,CAAC,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;WACtC,WAAW,CAAC,QAAQ;WACpB,WAAW,CAAC,QAAQ;WACpB,WAAW,CAAC,MAAM;WAClB,WAAW,CAAC,IAAI,EACnB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,WAAW,CAAC,QAAQ,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChG,OAAO,GAAG,yBAAyB,GAAG,OAAO,gBAAgB,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,KAAc,EACd,eAAuB,EACvB,UAAuC,EAAE;IAEzC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,MAAM,QAAQ,GAAG,KAAgC,CAAC;IAClD,IAAI,QAAQ,CAAC,aAAa,KAAK,CAAC,IAAI,QAAQ,CAAC,OAAO,KAAK,mBAAmB,EAAE,CAAC;QAC7E,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC3D,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,KAAK,eAAe,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,gDAAgD,eAAe,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,MAAM,WAAW,GAAG,aAAa,CAAC,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACvE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACpF,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAA2B,EAAE;QAC7E,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,oCAAoC,KAAK,oBAAoB,CAAC,CAAC;QACjF,CAAC;QACD,MAAM,MAAM,GAAG,KAAgC,CAAC;QAChD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,KAAK,WAAW,CAAoB,CAAC;QAC/F,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,KAAK,CAAC,oCAAoC,KAAK,0BAA0B,CAAC,CAAC;QACvF,CAAC;QACD,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC;QAChE,IAAI,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,oCAAoC,KAAK,sBAAsB,CAAC,CAAC;QACnF,CAAC;QACD,MAAM,KAAK,GAAG,GAAG,QAAQ,IAAI,IAAI,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,8CAA8C,KAAK,EAAE,CAAC,CAAC;QAC5F,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChB,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,KAAK,YAAY,CAAC,CAAC;QAC/E,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,oCAAoC,KAAK,2BAA2B,CAAC,CAAC;QACxF,CAAC;QACD,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,KAAK,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QACpF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,oCAAoC,KAAK,uBAAuB,CAAC,CAAC;QACpF,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,IAAK,MAAM,CAAC,IAAe,GAAG,CAAC,IAAK,MAAM,CAAC,IAAe,GAAG,eAAe,EAAE,CAAC;YACnH,MAAM,IAAI,KAAK,CAAC,oCAAoC,KAAK,kBAAkB,CAAC,CAAC;QAC/E,CAAC;QACD,OAAO;YACL,QAAQ;YACR,IAAI;YACJ,SAAS;YACT,GAAG,EAAE,mBAAmB,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,aAAa,KAAK,IAAI,CAAC;YACpE,SAAS,EAAE,iBAAiB,CAAC,MAAM,CAAC,SAAS,CAAC;YAC9C,MAAM;YACN,IAAI,EAAE,MAAM,CAAC,IAAc;SAC5B,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO;QACL,aAAa,EAAE,CAAC;QAChB,OAAO,EAAE,mBAAmB;QAC5B,OAAO;QACP,WAAW;QACX,GAAG,CAAC,OAAO,QAAQ,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,GAAG,CAAC,OAAO,QAAQ,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7F,OAAO;KACR,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,GAAW,EACX,SAAuB,EACvB,OAAe;IAEf,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,kBAAkB,CAAC,CAAC;IACzE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YACpC,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,EAAE,YAAY,EAAE,yBAAyB,EAAE;SACrD,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3F,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACtE,IAAI,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,cAAc,GAAG,OAAO,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,QAAQ,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI;YAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACzC,IAAI,CAAC;YACH,SAAS,CAAC;gBACR,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC5C,IAAI,IAAI;oBAAE,MAAM;gBAChB,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC;gBAC1B,IAAI,KAAK,GAAG,OAAO,EAAE,CAAC;oBACpB,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;oBACtB,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,QAAQ,CAAC,CAAC;gBACvD,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAe,EACf,UAA8D,EAAE;IAEhE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC;IACxD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC1E,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAI,OAAO,CAAC,WAAW,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,WAAW,CAAC,WAAW,EAAE,SAAS,EAAE,iBAAiB,CAAC,CAAC;IACvE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,wCAAyC,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,CAAC;QACpE,WAAW,EAAE,SAAS,CAAC,QAAQ,EAAE;KAClC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,QAAgC,EAChC,WAA4B,OAAO,CAAC,QAAQ,EAC5C,OAAe,OAAO,CAAC,IAAI;IAE3B,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC/F,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,sCAAsC,QAAQ,IAAI,IAAI,2CAA2C,CAAC,CAAC;IACrH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAa,EAAE,MAA+B;IAChF,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,0CAA0C,MAAM,CAAC,IAAI,cAAc,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACrG,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9D,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC/E,MAAM,SAAS,GAAG,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;IAClF,IAAI,SAAS,KAAK,MAAM,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,QAAgC,EAChC,UAII,EAAE;IAEN,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,sCAAuC,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACrC,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface SafeTarLimits {
2
+ maxEntries: number;
3
+ maxFileSize: number;
4
+ maxUnpackedSize: number;
5
+ }
6
+ export declare function listSafeTarGz(archive: Buffer, limits?: Partial<SafeTarLimits>): ReadonlyArray<{
7
+ path: string;
8
+ type: 'file' | 'directory';
9
+ size: number;
10
+ }>;
11
+ export declare function extractSafeTarGz(archive: Buffer, destination: string, limits?: Partial<SafeTarLimits>): void;
@@ -0,0 +1,180 @@
1
+ import { chmodSync, mkdirSync, writeFileSync, } from 'fs';
2
+ import { dirname, resolve } from 'path';
3
+ import { posix } from 'path';
4
+ import { gunzipSync } from 'zlib';
5
+ const DEFAULT_LIMITS = {
6
+ maxEntries: 100_000,
7
+ maxFileSize: 100 * 1024 * 1024,
8
+ maxUnpackedSize: 300 * 1024 * 1024,
9
+ };
10
+ function readTarString(buffer, start, length) {
11
+ const end = buffer.indexOf(0, start);
12
+ return buffer.toString('utf8', start, end >= start && end < start + length ? end : start + length);
13
+ }
14
+ function parseOctal(value, field) {
15
+ const parsed = Number.parseInt(value.trim() || '0', 8);
16
+ if (!Number.isSafeInteger(parsed) || parsed < 0) {
17
+ throw new Error(`Runtime bundle contains an invalid ${field}`);
18
+ }
19
+ return parsed;
20
+ }
21
+ function validateArchivePath(path) {
22
+ if (!path || path.includes('\\') || path.includes('\0') || path.includes(':')) {
23
+ throw new Error('Runtime bundle contains an unsupported path');
24
+ }
25
+ const normalized = posix.normalize(path).replace(/^\.\/+/, '');
26
+ if (!normalized
27
+ || posix.isAbsolute(normalized)
28
+ || normalized === '..'
29
+ || normalized.startsWith('../')) {
30
+ throw new Error('Runtime bundle contains an unsafe path');
31
+ }
32
+ return normalized.replace(/\/+$/, '');
33
+ }
34
+ function validateTarChecksum(header) {
35
+ const expected = parseOctal(readTarString(header, 148, 8), 'header checksum');
36
+ let actual = 0;
37
+ for (let index = 0; index < header.length; index++) {
38
+ actual += index >= 148 && index < 156 ? 0x20 : header[index];
39
+ }
40
+ if (actual !== expected)
41
+ throw new Error('Runtime bundle contains an invalid header checksum');
42
+ }
43
+ function parsePaxPath(content) {
44
+ let offset = 0;
45
+ let path = null;
46
+ while (offset < content.length) {
47
+ const space = content.indexOf(0x20, offset);
48
+ if (space < 0)
49
+ throw new Error('Runtime bundle contains invalid PAX metadata');
50
+ const length = Number(content.toString('ascii', offset, space));
51
+ if (!Number.isSafeInteger(length) || length <= 0 || offset + length > content.length) {
52
+ throw new Error('Runtime bundle contains invalid PAX record length');
53
+ }
54
+ const record = content.subarray(space + 1, offset + length);
55
+ if (record[record.length - 1] !== 0x0a)
56
+ throw new Error('Runtime bundle contains invalid PAX record');
57
+ const equals = record.indexOf(0x3d);
58
+ if (equals < 1)
59
+ throw new Error('Runtime bundle contains invalid PAX field');
60
+ const key = record.toString('utf8', 0, equals);
61
+ const value = record.toString('utf8', equals + 1, record.length - 1);
62
+ if (key === 'path')
63
+ path = validateArchivePath(value);
64
+ else if (!['mtime', 'atime', 'ctime'].includes(key)) {
65
+ throw new Error(`Runtime bundle contains unsupported PAX field ${key}`);
66
+ }
67
+ offset += length;
68
+ }
69
+ return path;
70
+ }
71
+ function parseTarGz(archive, limits) {
72
+ let tar;
73
+ try {
74
+ tar = gunzipSync(archive, { maxOutputLength: limits.maxUnpackedSize });
75
+ }
76
+ catch {
77
+ throw new Error('Runtime bundle is not a valid bounded gzip archive');
78
+ }
79
+ const entries = [];
80
+ const seen = new Set();
81
+ let unpackedSize = 0;
82
+ let pendingPath = null;
83
+ for (let offset = 0; offset + 512 <= tar.length;) {
84
+ const header = tar.subarray(offset, offset + 512);
85
+ if (header.every(byte => byte === 0))
86
+ break;
87
+ validateTarChecksum(header);
88
+ if (entries.length >= limits.maxEntries) {
89
+ throw new Error('Runtime bundle contains too many entries');
90
+ }
91
+ const name = readTarString(header, 0, 100);
92
+ const prefix = readTarString(header, 345, 155);
93
+ const typeFlag = String.fromCharCode(header[156] || 0);
94
+ const size = parseOctal(readTarString(header, 124, 12), 'entry size');
95
+ const mode = parseOctal(readTarString(header, 100, 8), 'entry mode') & 0o777;
96
+ if (size > limits.maxFileSize) {
97
+ throw new Error('Runtime bundle entry exceeds allowed limits');
98
+ }
99
+ const contentStart = offset + 512;
100
+ const contentEnd = contentStart + size;
101
+ if (contentEnd > tar.length) {
102
+ throw new Error('Runtime bundle contains a truncated entry');
103
+ }
104
+ const content = tar.subarray(contentStart, contentEnd);
105
+ offset = contentStart + Math.ceil(size / 512) * 512;
106
+ if (typeFlag === 'x') {
107
+ if (size > 1024 * 1024)
108
+ throw new Error('Runtime bundle PAX metadata is too large');
109
+ pendingPath = parsePaxPath(content) ?? pendingPath;
110
+ continue;
111
+ }
112
+ if (typeFlag === 'L') {
113
+ if (size > 1024 * 1024)
114
+ throw new Error('Runtime bundle long path is too large');
115
+ pendingPath = validateArchivePath(readTarString(content, 0, content.length));
116
+ continue;
117
+ }
118
+ if (typeFlag === 'g' || typeFlag === 'K') {
119
+ throw new Error(`Runtime bundle contains unsupported entry type ${typeFlag}`);
120
+ }
121
+ const type = typeFlag === '5'
122
+ ? 'directory'
123
+ : (typeFlag === '\0' || typeFlag === '0' || typeFlag === '') ? 'file' : null;
124
+ if (!type) {
125
+ throw new Error(`Runtime bundle contains unsupported entry type ${typeFlag || 'NUL'}`);
126
+ }
127
+ if (type === 'directory' && size !== 0) {
128
+ throw new Error('Runtime bundle directory contains unexpected data');
129
+ }
130
+ const archivePath = pendingPath
131
+ ?? validateArchivePath(prefix ? `${prefix}/${name}` : name);
132
+ pendingPath = null;
133
+ if (seen.has(archivePath)) {
134
+ throw new Error(`Runtime bundle contains a duplicate path: ${archivePath}`);
135
+ }
136
+ seen.add(archivePath);
137
+ unpackedSize += size;
138
+ if (unpackedSize > limits.maxUnpackedSize) {
139
+ throw new Error('Runtime bundle exceeds maximum unpacked size');
140
+ }
141
+ entries.push({
142
+ path: archivePath,
143
+ type,
144
+ mode,
145
+ content,
146
+ });
147
+ }
148
+ if (pendingPath)
149
+ throw new Error('Runtime bundle contains dangling extended path metadata');
150
+ return entries;
151
+ }
152
+ export function listSafeTarGz(archive, limits = {}) {
153
+ const resolvedLimits = { ...DEFAULT_LIMITS, ...limits };
154
+ return parseTarGz(archive, resolvedLimits).map(entry => ({
155
+ path: entry.path,
156
+ type: entry.type,
157
+ size: entry.content.length,
158
+ }));
159
+ }
160
+ export function extractSafeTarGz(archive, destination, limits = {}) {
161
+ const root = resolve(destination);
162
+ mkdirSync(root, { recursive: true, mode: 0o700 });
163
+ const resolvedLimits = { ...DEFAULT_LIMITS, ...limits };
164
+ for (const entry of parseTarGz(archive, resolvedLimits)) {
165
+ const target = resolve(root, ...entry.path.split('/'));
166
+ const rel = posix.normalize(entry.path);
167
+ if (target === root || rel.startsWith('../')) {
168
+ throw new Error('Runtime bundle extraction escaped its destination');
169
+ }
170
+ if (entry.type === 'directory') {
171
+ mkdirSync(target, { recursive: true, mode: entry.mode || 0o755 });
172
+ continue;
173
+ }
174
+ mkdirSync(dirname(target), { recursive: true, mode: 0o755 });
175
+ writeFileSync(target, entry.content, { mode: entry.mode || 0o644, flag: 'wx' });
176
+ if (process.platform !== 'win32')
177
+ chmodSync(target, entry.mode || 0o644);
178
+ }
179
+ }
180
+ //# sourceMappingURL=safe-tar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-tar.js","sourceRoot":"","sources":["../src/safe-tar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface SelfCheckResult {
2
+ ok: true;
3
+ version: string;
4
+ packageRoot: string;
5
+ launchSpecValidated: boolean;
6
+ nativeModulesValidated: boolean;
7
+ }
8
+ export declare function getCurrentPackageRoot(): string;
9
+ export declare function runSelfCheck(options?: {
10
+ packageRoot?: string;
11
+ expectedVersion?: string;
12
+ launchSpecPath?: string;
13
+ validateNativeModules?: boolean;
14
+ }): SelfCheckResult;
@@ -0,0 +1,62 @@
1
+ import { createRequire } from 'module';
2
+ import { existsSync, readFileSync, statSync } from 'fs';
3
+ import { dirname, join, resolve } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { loadLaunchSpec } from './launch-spec.js';
6
+ export function getCurrentPackageRoot() {
7
+ return resolve(dirname(fileURLToPath(import.meta.url)), '..');
8
+ }
9
+ export function runSelfCheck(options = {}) {
10
+ const packageRoot = resolve(options.packageRoot ?? getCurrentPackageRoot());
11
+ const packageJsonPath = join(packageRoot, 'package.json');
12
+ const cliPath = join(packageRoot, 'dist', 'cli.js');
13
+ const indexPath = join(packageRoot, 'dist', 'index.js');
14
+ for (const path of [packageJsonPath, cliPath, indexPath]) {
15
+ if (!existsSync(path) || !statSync(path).isFile()) {
16
+ throw new Error(`Self-check required file is missing: ${path}`);
17
+ }
18
+ }
19
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
20
+ if (packageJson.name !== '@agent-link/agent' || typeof packageJson.version !== 'string') {
21
+ throw new Error('Self-check package identity is invalid');
22
+ }
23
+ if (options.expectedVersion && packageJson.version !== options.expectedVersion) {
24
+ throw new Error(`Self-check expected version ${options.expectedVersion}, found ${packageJson.version}`);
25
+ }
26
+ let launchSpecValidated = false;
27
+ if (options.launchSpecPath) {
28
+ loadLaunchSpec(resolve(options.launchSpecPath));
29
+ launchSpecValidated = true;
30
+ }
31
+ let nativeModulesValidated = false;
32
+ if (options.validateNativeModules !== false) {
33
+ const require = createRequire(cliPath);
34
+ const nodePty = require('node-pty');
35
+ if (typeof nodePty.spawn !== 'function') {
36
+ throw new Error('Self-check failed to load node-pty native runtime');
37
+ }
38
+ const shell = process.platform === 'win32'
39
+ ? 'powershell.exe'
40
+ : (process.env.SHELL || '/bin/sh');
41
+ const args = process.platform === 'win32'
42
+ ? ['-NoProfile', '-Command', 'exit 0']
43
+ : ['-c', 'exit 0'];
44
+ const nativeProbe = nodePty.spawn(shell, args, {
45
+ name: 'xterm-256color',
46
+ cols: 20,
47
+ rows: 5,
48
+ cwd: packageRoot,
49
+ env: Object.fromEntries(Object.entries(process.env).filter((entry) => entry[1] !== undefined)),
50
+ });
51
+ nativeProbe.kill();
52
+ nativeModulesValidated = true;
53
+ }
54
+ return {
55
+ ok: true,
56
+ version: packageJson.version,
57
+ packageRoot,
58
+ launchSpecValidated,
59
+ nativeModulesValidated,
60
+ };
61
+ }
62
+ //# sourceMappingURL=self-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-check.js","sourceRoot":"","sources":["../src/self-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAUlD,MAAM,UAAU,qBAAqB;IACnC,OAAO,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,UAKzB,EAAE;IACJ,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,IAAI,qBAAqB,EAAE,CAAC,CAAC;IAC5E,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACpD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IACxD,KAAK,MAAM,IAAI,IAAI,CAAC,eAAe,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;QACzD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAGnE,CAAC;IACF,IAAI,WAAW,CAAC,IAAI,KAAK,mBAAmB,IAAI,OAAO,WAAW,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACxF,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,OAAO,CAAC,eAAe,IAAI,WAAW,CAAC,OAAO,KAAK,OAAO,CAAC,eAAe,EAAE,CAAC;QAC/E,MAAM,IAAI,KAAK,CAAC,+BAA+B,OAAO,CAAC,eAAe,WAAW,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1G,CAAC;IAED,IAAI,mBAAmB,GAAG,KAAK,CAAC;IAChC,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;QAChD,mBAAmB,GAAG,IAAI,CAAC;IAC7B,CAAC;IAED,IAAI,sBAAsB,GAAG,KAAK,CAAC;IACnC,IAAI,OAAO,CAAC,qBAAqB,KAAK,KAAK,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAYjC,CAAC;QACF,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO;YACxC,CAAC,CAAC,gBAAgB;YAClB,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,SAAS,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO;YACvC,CAAC,CAAC,CAAC,YAAY,EAAE,UAAU,EAAE,QAAQ,CAAC;YACtC,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACrB,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE;YAC7C,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,EAAE;YACR,IAAI,EAAE,CAAC;YACP,GAAG,EAAE,WAAW;YAChB,GAAG,EAAE,MAAM,CAAC,WAAW,CACrB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAA6B,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CACjG;SACF,CAAC,CAAC;QACH,WAAW,CAAC,IAAI,EAAE,CAAC;QACnB,sBAAsB,GAAG,IAAI,CAAC;IAChC,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,WAAW,CAAC,OAAO;QAC5B,WAAW;QACX,mBAAmB;QACnB,sBAAsB;KACvB,CAAC;AACJ,CAAC"}
package/dist/service.d.ts CHANGED
@@ -4,6 +4,7 @@ export interface ServiceInstallOptions {
4
4
  platform?: NodeJS.Platform;
5
5
  startIfStopped?: boolean;
6
6
  persistPolicy?: boolean;
7
+ launcherPath?: string | null;
7
8
  }
8
9
  export interface ServiceUninstallOptions {
9
10
  platform?: NodeJS.Platform;
@@ -17,9 +18,18 @@ export interface ServiceInstallResult {
17
18
  spec: LaunchSpec;
18
19
  pendingReload: boolean;
19
20
  }
21
+ export interface ServiceInstallationSnapshot {
22
+ platform: NodeJS.Platform;
23
+ artifactPath: string;
24
+ artifactContent: string | null;
25
+ specPath: string;
26
+ specContent: string | null;
27
+ }
20
28
  export declare function getServiceArtifactPath(platform?: NodeJS.Platform): string;
21
29
  export declare function getServiceEnvironment(hostType?: LaunchHostType): Record<string, string>;
22
- export declare function renderServiceArtifact(spec: LaunchSpec, specPath: string, platform?: NodeJS.Platform): string;
30
+ export declare function renderServiceArtifact(spec: LaunchSpec, specPath: string, platform?: NodeJS.Platform, launcherPath?: string | null): string;
31
+ export declare function captureServiceInstallation(platform?: NodeJS.Platform): ServiceInstallationSnapshot;
32
+ export declare function restoreServiceInstallation(snapshot: ServiceInstallationSnapshot): void;
23
33
  export declare function installServiceLaunchSpec(source: LaunchSpec, options?: ServiceInstallOptions): ServiceInstallResult;
24
34
  export declare function isServiceInstalled(platform?: NodeJS.Platform): boolean;
25
35
  export declare function serviceInstall(config: AgentConfig): void;
package/dist/service.js CHANGED
@@ -6,6 +6,7 @@ import { fileURLToPath } from 'url';
6
6
  import { CONFIG_DIR, clearRuntimeState, getLogDir, isProcessAlive, killProcess, loadRuntimeState, saveConfig, saveRuntimeState, } from './config.js';
7
7
  import { computeLaunchSpecDigest, createLaunchSpec, createServiceLaunchSpec, getServiceLaunchSpecPath, saveLaunchSpec, saveLaunchSpecSnapshot, loadLaunchSpec, } from './launch-spec.js';
8
8
  import { getCachedPathEnvVars, getResolvedExecPaths, warmExecPaths } from './sdk.js';
9
+ import { getAdoptedLauncherPath } from './launcher-manager.js';
9
10
  const SERVICE_NAME = 'agentlink';
10
11
  const LAUNCHD_LABEL = 'com.agentlink.agent';
11
12
  function getCliPath() {
@@ -78,9 +79,9 @@ function renderEnvironment(environment, format) {
78
79
  .map(([name, value]) => `set "${name}=${value.replace(/%/g, '%%')}"`)
79
80
  .join('\r\n');
80
81
  }
81
- export function renderServiceArtifact(spec, specPath, platform = process.platform) {
82
+ export function renderServiceArtifact(spec, specPath, platform = process.platform, launcherPath = getAdoptedLauncherPath()) {
82
83
  const nodePath = process.execPath;
83
- const cliPath = getCliPath();
84
+ const cliPath = launcherPath ?? getCliPath();
84
85
  const logDir = getLogDir();
85
86
  const environment = getServiceEnvironment(spec.host.type);
86
87
  if (platform === 'linux') {
@@ -161,6 +162,30 @@ function writeTextAtomic(filePath, content) {
161
162
  }
162
163
  return true;
163
164
  }
165
+ export function captureServiceInstallation(platform = process.platform) {
166
+ const artifactPath = getServiceArtifactPath(platform);
167
+ const specPath = getServiceLaunchSpecPath();
168
+ return {
169
+ platform,
170
+ artifactPath,
171
+ artifactContent: existsSync(artifactPath) ? readFileSync(artifactPath, 'utf8') : null,
172
+ specPath,
173
+ specContent: existsSync(specPath) ? readFileSync(specPath, 'utf8') : null,
174
+ };
175
+ }
176
+ export function restoreServiceInstallation(snapshot) {
177
+ if (snapshot.artifactContent === null)
178
+ rmSync(snapshot.artifactPath, { force: true });
179
+ else
180
+ writeTextAtomic(snapshot.artifactPath, snapshot.artifactContent);
181
+ if (snapshot.specContent === null)
182
+ rmSync(snapshot.specPath, { force: true });
183
+ else
184
+ writeTextAtomic(snapshot.specPath, snapshot.specContent);
185
+ if (!isSimulation() && snapshot.platform === 'linux') {
186
+ runSystemctl(['daemon-reload']);
187
+ }
188
+ }
164
189
  function runSystemctl(args) {
165
190
  execFileSync('systemctl', ['--user', ...args], { stdio: 'ignore' });
166
191
  }
@@ -193,7 +218,7 @@ function removeLegacySystemdService(stopAgent) {
193
218
  }
194
219
  }
195
220
  function startFromServiceLaunchSpec(specPath) {
196
- execFileSync(process.execPath, [getCliPath(), 'start', '--launch-spec', specPath], {
221
+ execFileSync(process.execPath, [getAdoptedLauncherPath() ?? getCliPath(), 'start', '--launch-spec', specPath], {
197
222
  stdio: 'inherit',
198
223
  windowsHide: true,
199
224
  });
@@ -227,7 +252,10 @@ export function installServiceLaunchSpec(source, options = {}) {
227
252
  const artifactPath = getServiceArtifactPath(platform);
228
253
  const previousContent = existsSync(artifactPath) ? readFileSync(artifactPath, 'utf8') : null;
229
254
  const existed = previousContent !== null;
230
- const content = renderServiceArtifact(spec, specPath, platform);
255
+ const launcherPath = options.launcherPath === undefined
256
+ ? getAdoptedLauncherPath()
257
+ : options.launcherPath;
258
+ const content = renderServiceArtifact(spec, specPath, platform, launcherPath);
231
259
  preserveRuntimeServiceSpecBeforeReplace(spec);
232
260
  const changed = writeTextAtomic(artifactPath, content);
233
261
  // Write the referenced LaunchSpec only after the host entry is safely staged.