@dsh-enhanced/lark-channel 0.1.47 → 0.1.49

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 (173) hide show
  1. package/README.md +19 -8
  2. package/docs/rsi-setup.md +123 -11
  3. package/docs/setup.md +27 -14
  4. package/docs/supervised-growth.md +2 -0
  5. package/lib/adapter.d.ts +6 -0
  6. package/lib/adapter.d.ts.map +1 -1
  7. package/lib/adapter.js +79 -8
  8. package/lib/adapter.js.map +1 -1
  9. package/lib/business-cli-install.d.ts +9 -0
  10. package/lib/business-cli-install.d.ts.map +1 -0
  11. package/lib/business-cli-install.js +367 -0
  12. package/lib/business-cli-install.js.map +1 -0
  13. package/lib/business-environment.d.ts +2 -0
  14. package/lib/business-environment.d.ts.map +1 -0
  15. package/lib/business-environment.js +16 -0
  16. package/lib/business-environment.js.map +1 -0
  17. package/lib/business-skill.d.ts +32 -0
  18. package/lib/business-skill.d.ts.map +1 -0
  19. package/lib/business-skill.js +202 -0
  20. package/lib/business-skill.js.map +1 -0
  21. package/lib/rsi-authority-config.d.ts +29 -0
  22. package/lib/rsi-authority-config.d.ts.map +1 -0
  23. package/lib/rsi-authority-config.js +233 -0
  24. package/lib/rsi-authority-config.js.map +1 -0
  25. package/lib/rsi-authority-resources.d.ts +36 -0
  26. package/lib/rsi-authority-resources.d.ts.map +1 -0
  27. package/lib/rsi-authority-resources.js +139 -0
  28. package/lib/rsi-authority-resources.js.map +1 -0
  29. package/lib/rsi-authority-runtime.d.ts +50 -0
  30. package/lib/rsi-authority-runtime.d.ts.map +1 -0
  31. package/lib/rsi-authority-runtime.js +393 -0
  32. package/lib/rsi-authority-runtime.js.map +1 -0
  33. package/lib/rsi-bootstrap-manifest.d.ts +39 -0
  34. package/lib/rsi-bootstrap-manifest.d.ts.map +1 -0
  35. package/lib/rsi-bootstrap-manifest.js +366 -0
  36. package/lib/rsi-bootstrap-manifest.js.map +1 -0
  37. package/lib/rsi-bootstrap.d.ts +30 -0
  38. package/lib/rsi-bootstrap.d.ts.map +1 -0
  39. package/lib/rsi-bootstrap.js +363 -0
  40. package/lib/rsi-bootstrap.js.map +1 -0
  41. package/lib/rsi-build.d.ts +45 -0
  42. package/lib/rsi-build.d.ts.map +1 -0
  43. package/lib/rsi-build.js +404 -0
  44. package/lib/rsi-build.js.map +1 -0
  45. package/lib/rsi-creation-build.d.ts +47 -0
  46. package/lib/rsi-creation-build.d.ts.map +1 -0
  47. package/lib/rsi-creation-build.js +333 -0
  48. package/lib/rsi-creation-build.js.map +1 -0
  49. package/lib/rsi-host-authorities.d.ts +18 -0
  50. package/lib/rsi-host-authorities.d.ts.map +1 -0
  51. package/lib/rsi-host-authorities.js +129 -0
  52. package/lib/rsi-host-authorities.js.map +1 -0
  53. package/lib/rsi-host-update.d.ts +113 -0
  54. package/lib/rsi-host-update.d.ts.map +1 -0
  55. package/lib/rsi-host-update.js +316 -0
  56. package/lib/rsi-host-update.js.map +1 -0
  57. package/lib/rsi-install-inputs.d.ts +43 -0
  58. package/lib/rsi-install-inputs.d.ts.map +1 -0
  59. package/lib/rsi-install-inputs.js +342 -0
  60. package/lib/rsi-install-inputs.js.map +1 -0
  61. package/lib/rsi-install.d.ts +54 -0
  62. package/lib/rsi-install.d.ts.map +1 -0
  63. package/lib/rsi-install.js +404 -0
  64. package/lib/rsi-install.js.map +1 -0
  65. package/lib/rsi-local-activation.d.ts +78 -0
  66. package/lib/rsi-local-activation.d.ts.map +1 -0
  67. package/lib/rsi-local-activation.js +485 -0
  68. package/lib/rsi-local-activation.js.map +1 -0
  69. package/lib/rsi-local-cohort.d.ts +70 -0
  70. package/lib/rsi-local-cohort.d.ts.map +1 -0
  71. package/lib/rsi-local-cohort.js +781 -0
  72. package/lib/rsi-local-cohort.js.map +1 -0
  73. package/lib/rsi-local-install.d.ts +40 -0
  74. package/lib/rsi-local-install.d.ts.map +1 -0
  75. package/lib/rsi-local-install.js +221 -0
  76. package/lib/rsi-local-install.js.map +1 -0
  77. package/lib/rsi-local-pair-install.d.ts +38 -0
  78. package/lib/rsi-local-pair-install.d.ts.map +1 -0
  79. package/lib/rsi-local-pair-install.js +200 -0
  80. package/lib/rsi-local-pair-install.js.map +1 -0
  81. package/lib/rsi-local-profile-update.d.ts +25 -0
  82. package/lib/rsi-local-profile-update.d.ts.map +1 -0
  83. package/lib/rsi-local-profile-update.js +226 -0
  84. package/lib/rsi-local-profile-update.js.map +1 -0
  85. package/lib/rsi-local-resources.d.ts +37 -0
  86. package/lib/rsi-local-resources.d.ts.map +1 -0
  87. package/lib/rsi-local-resources.js +184 -0
  88. package/lib/rsi-local-resources.js.map +1 -0
  89. package/lib/rsi-local-roots-extension.d.ts +11 -0
  90. package/lib/rsi-local-roots-extension.d.ts.map +1 -0
  91. package/lib/rsi-local-roots-extension.js +31 -0
  92. package/lib/rsi-local-roots-extension.js.map +1 -0
  93. package/lib/rsi-local-update-build.d.ts +18 -0
  94. package/lib/rsi-local-update-build.d.ts.map +1 -0
  95. package/lib/rsi-local-update-build.js +37 -0
  96. package/lib/rsi-local-update-build.js.map +1 -0
  97. package/lib/rsi-local-update.d.ts +39 -0
  98. package/lib/rsi-local-update.d.ts.map +1 -0
  99. package/lib/rsi-local-update.js +205 -0
  100. package/lib/rsi-local-update.js.map +1 -0
  101. package/lib/rsi-memory-learning.d.ts +22 -0
  102. package/lib/rsi-memory-learning.d.ts.map +1 -0
  103. package/lib/rsi-memory-learning.js +76 -0
  104. package/lib/rsi-memory-learning.js.map +1 -0
  105. package/lib/rsi-owner-profile.d.ts +37 -0
  106. package/lib/rsi-owner-profile.d.ts.map +1 -0
  107. package/lib/rsi-owner-profile.js +178 -0
  108. package/lib/rsi-owner-profile.js.map +1 -0
  109. package/lib/rsi-plugin-creation.d.ts +31 -0
  110. package/lib/rsi-plugin-creation.d.ts.map +1 -0
  111. package/lib/rsi-plugin-creation.js +179 -0
  112. package/lib/rsi-plugin-creation.js.map +1 -0
  113. package/lib/rsi-profile.d.ts +23 -0
  114. package/lib/rsi-profile.d.ts.map +1 -1
  115. package/lib/rsi-profile.js +154 -43
  116. package/lib/rsi-profile.js.map +1 -1
  117. package/lib/rsi-release-build.d.ts +41 -0
  118. package/lib/rsi-release-build.d.ts.map +1 -0
  119. package/lib/rsi-release-build.js +223 -0
  120. package/lib/rsi-release-build.js.map +1 -0
  121. package/lib/rsi-service-environment.d.ts +6 -0
  122. package/lib/rsi-service-environment.d.ts.map +1 -0
  123. package/lib/rsi-service-environment.js +113 -0
  124. package/lib/rsi-service-environment.js.map +1 -0
  125. package/lib/rsi-service-setup.d.ts +10 -0
  126. package/lib/rsi-service-setup.d.ts.map +1 -0
  127. package/lib/rsi-service-setup.js +34 -0
  128. package/lib/rsi-service-setup.js.map +1 -0
  129. package/lib/rsi-setup.d.ts +35 -2
  130. package/lib/rsi-setup.d.ts.map +1 -1
  131. package/lib/rsi-setup.js +459 -32
  132. package/lib/rsi-setup.js.map +1 -1
  133. package/lib/rsi-source-maintenance.d.ts +25 -0
  134. package/lib/rsi-source-maintenance.d.ts.map +1 -0
  135. package/lib/rsi-source-maintenance.js +348 -0
  136. package/lib/rsi-source-maintenance.js.map +1 -0
  137. package/lib/rsi-source-update.d.ts +26 -0
  138. package/lib/rsi-source-update.d.ts.map +1 -0
  139. package/lib/rsi-source-update.js +276 -0
  140. package/lib/rsi-source-update.js.map +1 -0
  141. package/lib/rsi-source.d.ts +34 -0
  142. package/lib/rsi-source.d.ts.map +1 -0
  143. package/lib/rsi-source.js +375 -0
  144. package/lib/rsi-source.js.map +1 -0
  145. package/lib/rsi-systemd-bootstrap.d.ts +46 -0
  146. package/lib/rsi-systemd-bootstrap.d.ts.map +1 -0
  147. package/lib/rsi-systemd-bootstrap.js +271 -0
  148. package/lib/rsi-systemd-bootstrap.js.map +1 -0
  149. package/lib/sdk.d.ts.map +1 -1
  150. package/lib/sdk.js +26 -1
  151. package/lib/sdk.js.map +1 -1
  152. package/lib/setup-business.d.ts +49 -0
  153. package/lib/setup-business.d.ts.map +1 -0
  154. package/lib/setup-business.js +335 -0
  155. package/lib/setup-business.js.map +1 -0
  156. package/lib/setup-profile.d.ts +1 -1
  157. package/lib/setup-profile.d.ts.map +1 -1
  158. package/lib/setup-profile.js +25 -2
  159. package/lib/setup-profile.js.map +1 -1
  160. package/lib/setup.d.ts +12 -1
  161. package/lib/setup.d.ts.map +1 -1
  162. package/lib/setup.js +138 -34
  163. package/lib/setup.js.map +1 -1
  164. package/lib/systemd.d.ts +10 -0
  165. package/lib/systemd.d.ts.map +1 -1
  166. package/lib/systemd.js +23 -6
  167. package/lib/systemd.js.map +1 -1
  168. package/lib/types.d.ts +7 -0
  169. package/lib/types.d.ts.map +1 -1
  170. package/lib/types.js.map +1 -1
  171. package/lib/version.d.ts +1 -1
  172. package/lib/version.js +1 -1
  173. package/package.json +32 -20
@@ -0,0 +1,781 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { createHash } from 'node:crypto';
10
+ import { spawn } from 'node:child_process';
11
+ import { constants } from 'node:fs';
12
+ import { chmod, lstat, mkdir, mkdtemp, open, readdir, realpath, rename, rm, stat } from 'node:fs/promises';
13
+ import { createRequire } from 'node:module';
14
+ import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
15
+ import { fileURLToPath, pathToFileURL } from 'node:url';
16
+ import { gunzipSync } from 'node:zlib';
17
+ import { isMap, isScalar, parseDocument } from 'yaml';
18
+ import { rsiBuildResources as io } from './rsi-build.js';
19
+ const PROFILE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u;
20
+ const SLUG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
21
+ const HASH = /^[a-f0-9]{64}$/u;
22
+ const COMMIT = /^[a-f0-9]{40}$/u;
23
+ const INTERNAL = '@dsh-enhanced/';
24
+ const COORDINATOR = ['assistant-policy', 'assistant-automations', 'plugin-control-plane'];
25
+ const MAX_ARCHIVE = 268_435_456;
26
+ const MAX_PACKAGE_FILES = 10_000;
27
+ const MAX_PACKAGES = 128;
28
+ function fail(message) { throw new Error(`rsi local cohort: ${message}`); }
29
+ function digest(bytes) { return createHash('sha256').update(bytes).digest('hex'); }
30
+ function exact(path) { return isAbsolute(path) && resolve(path) === path && !path.includes('\0'); }
31
+ function inside(root, path) { const rel = relative(root, path); return rel !== '' && rel !== '..' && !rel.startsWith(`..${sep}`) && !isAbsolute(rel); }
32
+ function same(left, right) { return JSON.stringify(left) === JSON.stringify(right); }
33
+ function slugOf(name) {
34
+ if (!name.startsWith(INTERNAL) || !SLUG.test(name.slice(INTERNAL.length)))
35
+ fail(`invalid internal package name: ${name}`);
36
+ return name.slice(INTERNAL.length);
37
+ }
38
+ function validateInput(home, profile) {
39
+ if (!exact(home) || !PROFILE.test(profile))
40
+ fail('invalid home or profile');
41
+ }
42
+ async function exists(path) {
43
+ try {
44
+ await lstat(path);
45
+ return true;
46
+ }
47
+ catch (error) {
48
+ if (error.code === 'ENOENT')
49
+ return false;
50
+ throw error;
51
+ }
52
+ }
53
+ async function stableFile(path, limit, ownerPrivate = false) {
54
+ const fd = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
55
+ try {
56
+ const before = await fd.stat();
57
+ if (!before.isFile() || before.nlink !== 1 || before.size > limit || before.size < 0
58
+ || ownerPrivate && (before.mode & 0o077) !== 0
59
+ || process.getuid && before.uid !== process.getuid())
60
+ fail(`unsafe file: ${path}`);
61
+ const bytes = await fd.readFile(), after = await fd.stat(), entry = await lstat(path);
62
+ if (before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size
63
+ || before.mtimeMs !== after.mtimeMs || bytes.length !== before.size
64
+ || entry.dev !== before.dev || entry.ino !== before.ino || entry.isSymbolicLink())
65
+ fail(`file changed during read: ${path}`);
66
+ return bytes;
67
+ }
68
+ finally {
69
+ await fd.close();
70
+ }
71
+ }
72
+ async function privateDirectory(path) { await io.directory(path); }
73
+ async function sourceManifest(root, path, version) {
74
+ const manifest = JSON.parse((await stableFile(join(root, path, 'package.json'), 1_048_576)).toString('utf8'));
75
+ if (manifest.name !== `${INTERNAL}${path.split('/')[1]}` || manifest.version !== version)
76
+ fail(`package identity differs: ${path}`);
77
+ return manifest;
78
+ }
79
+ function runtimeDependencies(manifest) {
80
+ const names = new Set();
81
+ for (const field of ['dependencies', 'optionalDependencies']) {
82
+ const map = manifest[field];
83
+ if (map === undefined)
84
+ continue;
85
+ if (!map || typeof map !== 'object' || Array.isArray(map))
86
+ fail(`invalid ${field}`);
87
+ for (const [name, value] of Object.entries(map)) {
88
+ if (typeof value !== 'string')
89
+ fail(`invalid ${field} entry`);
90
+ if (name.startsWith(INTERNAL)) {
91
+ slugOf(name);
92
+ names.add(name);
93
+ }
94
+ }
95
+ }
96
+ return [...names].sort();
97
+ }
98
+ async function approvedBuilds(workspace) {
99
+ const document = parseDocument((await stableFile(join(workspace, 'pnpm-workspace.yaml'), 1_048_576)).toString('utf8'), { uniqueKeys: true });
100
+ if (document.errors.length || document.warnings.length || !isMap(document.contents))
101
+ fail('source workspace configuration is invalid');
102
+ const mapping = document.get('allowBuilds', true);
103
+ if (!isMap(mapping) || mapping.items.length > 128)
104
+ fail('source allowBuilds must be a bounded mapping');
105
+ const entries = [];
106
+ for (const item of mapping.items) {
107
+ if (!isScalar(item.key) || typeof item.key.value !== 'string'
108
+ || !/^(@[a-z0-9._-]+\/)?[a-z0-9._-]+$/u.test(item.key.value)
109
+ || !isScalar(item.value) || typeof item.value.value !== 'boolean')
110
+ fail('source allowBuilds must contain package names and booleans');
111
+ entries.push([item.key.value, item.value.value]);
112
+ }
113
+ return Object.fromEntries(entries.sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0));
114
+ }
115
+ async function closure(workspace, version, bundles) {
116
+ const selected = new Set(bundles.map(slug => `${INTERNAL}${slug}`));
117
+ const pending = [...new Set([...bundles, ...COORDINATOR].map(slug => `${INTERNAL}${slug}`))];
118
+ const visited = new Map();
119
+ while (pending.length) {
120
+ if (visited.size >= MAX_PACKAGES)
121
+ fail('package closure exceeds bound');
122
+ const name = pending.shift();
123
+ if (visited.has(name))
124
+ continue;
125
+ const slug = slugOf(name);
126
+ let path;
127
+ for (const base of ['plugins', 'packages']) {
128
+ const candidate = `${base}/${slug}`;
129
+ if (await exists(join(workspace, candidate, 'package.json'))) {
130
+ if (path)
131
+ fail(`ambiguous package path: ${name}`);
132
+ path = candidate;
133
+ }
134
+ }
135
+ if (!path)
136
+ fail(`internal runtime dependency unavailable: ${name}`);
137
+ const packageRoot = join(workspace, path);
138
+ if (await realpath(packageRoot) !== packageRoot)
139
+ fail(`package path escapes clean workspace: ${name}`);
140
+ const manifest = await sourceManifest(workspace, path, version);
141
+ const dependencies = runtimeDependencies(manifest);
142
+ const bundle = path.startsWith('plugins/');
143
+ if (selected.has(name) && !bundle)
144
+ fail(`selected bundle is a library: ${name}`);
145
+ visited.set(name, { path, name, bundle, runtimeDependencies: dependencies });
146
+ pending.push(...dependencies);
147
+ }
148
+ return [...visited.values()].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
149
+ }
150
+ function tarNumber(header, start, length) {
151
+ const bytes = header.subarray(start, start + length);
152
+ if (bytes.some(byte => byte !== 0 && byte !== 32 && (byte < 48 || byte > 55)))
153
+ fail('unsupported tar number');
154
+ const value = bytes.toString('ascii').replaceAll('\0', ' ').trim();
155
+ if (!/^[0-7]+$/u.test(value))
156
+ fail('invalid tar number');
157
+ const number = Number.parseInt(value, 8);
158
+ if (!Number.isSafeInteger(number))
159
+ fail('tar number exceeds bound');
160
+ return number;
161
+ }
162
+ function tarString(header, start, length) {
163
+ const bytes = header.subarray(start, start + length), end = bytes.indexOf(0);
164
+ if (end !== -1 && bytes.subarray(end).some(byte => byte !== 0))
165
+ fail('invalid tar string padding');
166
+ return bytes.subarray(0, end === -1 ? bytes.length : end).toString('utf8');
167
+ }
168
+ function archiveEntries(packed, onManifest) {
169
+ let tar;
170
+ try {
171
+ tar = gunzipSync(packed, { maxOutputLength: MAX_ARCHIVE });
172
+ }
173
+ catch {
174
+ fail('invalid or oversized gzip tarball');
175
+ }
176
+ if (tar.length < 1536 || tar.length % 512)
177
+ fail('invalid tar layout');
178
+ const files = [], seen = new Set();
179
+ let offset = 0, ended = false;
180
+ while (offset < tar.length) {
181
+ const header = tar.subarray(offset, offset + 512);
182
+ if (header.every(byte => byte === 0)) {
183
+ if (tar.length - offset < 1024 || tar.subarray(offset).some(byte => byte !== 0))
184
+ fail('invalid tar terminator');
185
+ ended = true;
186
+ break;
187
+ }
188
+ let checksum = 0;
189
+ for (let i = 0; i < 512; i++)
190
+ checksum += i >= 148 && i < 156 ? 32 : header[i];
191
+ if (checksum !== tarNumber(header, 148, 8))
192
+ fail('tar checksum differs');
193
+ const type = header[156], size = tarNumber(header, 124, 12), mode = tarNumber(header, 100, 8) & 0o777;
194
+ if (type !== 0 && type !== 48 && type !== 53 || type === 53 && size !== 0)
195
+ fail('tar links or special entries are forbidden');
196
+ const name = tarString(header, 0, 100), prefix = tarString(header, 345, 155);
197
+ const archivePath = prefix ? `${prefix}/${name}` : name;
198
+ const canonical = type === 53 && archivePath.endsWith('/') ? archivePath.slice(0, -1) : archivePath;
199
+ if (canonical !== 'package' && !canonical.startsWith('package/') || canonical.includes('//')
200
+ || canonical.split('/').some(part => part === '' || part === '.' || part === '..'))
201
+ fail('unsafe tar path');
202
+ if (seen.has(canonical))
203
+ fail('duplicate tar path');
204
+ seen.add(canonical);
205
+ const next = offset + 512 + Math.ceil(size / 512) * 512;
206
+ if (next > tar.length)
207
+ fail('truncated tar entry');
208
+ if (type !== 53) {
209
+ if (canonical === 'package')
210
+ fail('package root is a file');
211
+ const bytes = tar.subarray(offset + 512, offset + 512 + size);
212
+ files.push({ path: canonical.slice('package/'.length), sha256: digest(bytes), mode });
213
+ if (canonical === 'package/package.json')
214
+ onManifest?.(bytes);
215
+ if (files.length > MAX_PACKAGE_FILES)
216
+ fail('package file count exceeds bound');
217
+ }
218
+ offset = next;
219
+ }
220
+ if (!ended || !files.some(item => item.path === 'package.json'))
221
+ fail('archive has no package manifest');
222
+ const filePaths = new Set(files.map(file => file.path));
223
+ for (const file of files) {
224
+ const parts = file.path.split('/');
225
+ for (let i = 1; i < parts.length; i++)
226
+ if (filePaths.has(parts.slice(0, i).join('/')))
227
+ fail('tar file is an ancestor');
228
+ }
229
+ return files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
230
+ }
231
+ async function adapterNormalize(bytes) {
232
+ const require = createRequire(import.meta.url);
233
+ const root = dirname(require.resolve('@dsh-enhanced/plugin-control-plane/package.json'));
234
+ const adapter = await import(__rewriteRelativeImportExtension(pathToFileURL(join(root, 'bin', 'dsh-local-release-adapter.js')).href));
235
+ if (typeof adapter.normalizePackedDependencyOrder !== 'function')
236
+ fail('installed Control Plane lacks archive validation');
237
+ return adapter.normalizePackedDependencyOrder(bytes);
238
+ }
239
+ async function unpackAndCheck(tarball, files, stage, signal) {
240
+ const unpack = await mkdtemp(join(stage, 'unpack-'));
241
+ try {
242
+ await io.command('/usr/bin/tar', ['--no-same-owner', '--no-same-permissions', '-xzf', tarball, '-C', unpack], { PATH: '/usr/bin:/bin', LANG: 'C', LC_ALL: 'C', HOME: stage }, signal, 60_000);
243
+ const root = join(unpack, 'package');
244
+ const actual = [];
245
+ const walk = async (directory) => {
246
+ for (const name of await readdir(directory)) {
247
+ const path = join(directory, name), metadata = await lstat(path);
248
+ if (metadata.isSymbolicLink() || !inside(root, path) || await realpath(path) !== path)
249
+ fail('unsafe extracted file');
250
+ if (metadata.isDirectory())
251
+ await walk(path);
252
+ else if (metadata.isFile())
253
+ actual.push({ path: relative(root, path).split(sep).join('/'),
254
+ sha256: digest(await stableFile(path, MAX_ARCHIVE)), mode: metadata.mode & 0o777 });
255
+ else
256
+ fail('nonregular extracted entry');
257
+ }
258
+ };
259
+ await walk(root);
260
+ actual.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
261
+ if (actual.length !== files.length || actual.some((item, index) => item.path !== files[index]?.path
262
+ || item.sha256 !== files[index]?.sha256 || (item.mode & 0o100) !== (files[index].mode & 0o100)
263
+ || (item.mode & 0o022) !== 0))
264
+ fail('extracted inventory differs from tar headers');
265
+ return JSON.parse((await stableFile(join(root, 'package.json'), 1_048_576)).toString('utf8'));
266
+ }
267
+ finally {
268
+ await rm(unpack, { recursive: true, force: true });
269
+ }
270
+ }
271
+ function validatePackedManifest(manifest, source, item, version) {
272
+ if (manifest.name !== item.name || manifest.version !== version || manifest.main !== source.main
273
+ || !same(manifest.exports, source.exports) || !same(manifest.dsh, source.dsh)
274
+ || item.bundle !== Boolean(manifest.dsh?.bundle)
275
+ || !same(runtimeDependencies(manifest), item.runtimeDependencies))
276
+ fail(`packed package manifest differs: ${item.name}`);
277
+ for (const dependency of item.runtimeDependencies) {
278
+ const value = manifest.dependencies?.[dependency]
279
+ ?? manifest.optionalDependencies?.[dependency];
280
+ if (typeof value !== 'string' || value.startsWith('workspace:') || value.startsWith('catalog:'))
281
+ fail(`packed runtime dependency is unresolved: ${item.name} -> ${dependency}`);
282
+ }
283
+ }
284
+ function expectedRoot(home, profile) { return join(home, 'rsi-local-cohorts', profile); }
285
+ function validateReceipt(value, home, profile) {
286
+ if (!value || value.schemaVersion !== 1 || value.root !== expectedRoot(home, profile)
287
+ || !COMMIT.test(value.sourceCommit) || typeof value.version !== 'string'
288
+ || typeof value.sourceRepository !== 'string'
289
+ || !exact(value.sourceRepository) && value.sourceRepository !== 'https://github.com/22-ai-00/dsh-enhanced.git'
290
+ || !value.allowBuilds || typeof value.allowBuilds !== 'object' || Array.isArray(value.allowBuilds)
291
+ || !Array.isArray(value.bundles) || !Array.isArray(value.packages) || !HASH.test(value.receiptDigest))
292
+ fail('invalid cohort receipt');
293
+ const { receiptDigest, ...content } = value;
294
+ if (digest(JSON.stringify(content)) !== receiptDigest)
295
+ fail('cohort receipt digest differs');
296
+ const approved = Object.entries(value.allowBuilds);
297
+ if (approved.length > 128 || !same(approved.map(([name]) => name), approved.map(([name]) => name).sort())
298
+ || approved.some(([name, enabled]) => !/^(@[a-z0-9._-]+\/)?[a-z0-9._-]+$/u.test(name) || typeof enabled !== 'boolean'))
299
+ fail('invalid approved build scripts');
300
+ if (!same(value.bundles, [...new Set(value.bundles)].sort()) || value.bundles.some(slug => !SLUG.test(slug)))
301
+ fail('invalid selected bundles');
302
+ if (!same(value.packages.map(item => item.name), [...new Set(value.packages.map(item => item.name))].sort()))
303
+ fail('invalid package order');
304
+ for (const item of value.packages) {
305
+ const slug = slugOf(item.name);
306
+ if (item.path !== `plugins/${slug}` && item.path !== `packages/${slug}`
307
+ || item.bundle !== item.path.startsWith('plugins/')
308
+ || item.tarball !== join(value.root, 'artifacts', `${slug}.tgz`) || !HASH.test(item.sha256)
309
+ || !Array.isArray(item.runtimeDependencies) || !same(item.runtimeDependencies, [...new Set(item.runtimeDependencies)].sort())
310
+ || item.runtimeDependencies.some(name => !name.startsWith(INTERNAL)) || !Array.isArray(item.files)
311
+ || !same(item.files.map(file => file.path), [...new Set(item.files.map(file => file.path))].sort()))
312
+ fail('invalid package receipt');
313
+ for (const file of item.files)
314
+ if (typeof file.path !== 'string' || file.path.startsWith('/')
315
+ || file.path.split('/').some(part => !part || part === '.' || part === '..') || !HASH.test(file.sha256)
316
+ || !Number.isInteger(file.mode) || file.mode < 0 || file.mode > 0o777)
317
+ fail('invalid inventory receipt');
318
+ }
319
+ if (value.packages.length > MAX_PACKAGES || value.packages.some(item => item.runtimeDependencies.some(name => !value.packages.some(other => other.name === name))))
320
+ fail('incomplete runtime closure');
321
+ if (value.bundles.some(slug => !value.packages.some(item => item.name === `${INTERNAL}${slug}` && item.bundle)))
322
+ fail('selected bundle missing');
323
+ if (COORDINATOR.some(slug => !value.packages.some(item => item.name === `${INTERNAL}${slug}` && item.bundle)))
324
+ fail('coordinator bundle missing');
325
+ }
326
+ async function readExisting(home, profile, source) {
327
+ const root = expectedRoot(home, profile);
328
+ await privateDirectory(join(home, 'rsi-local-cohorts'));
329
+ await privateDirectory(root);
330
+ if (!same((await readdir(root)).sort(), ['artifacts', 'receipt.json']))
331
+ fail('cohort directory is incomplete');
332
+ await privateDirectory(join(root, 'artifacts'));
333
+ const value = JSON.parse((await stableFile(join(root, 'receipt.json'), 16_777_216, true)).toString('utf8'));
334
+ validateReceipt(value, home, profile);
335
+ if (source && (source.sourceCommit !== value.sourceCommit || source.version !== value.version
336
+ || source.origin.locator !== value.sourceRepository))
337
+ fail('cohort source differs');
338
+ const expectedNames = value.packages.map(item => `${slugOf(item.name)}.tgz`).sort();
339
+ if (!same((await readdir(join(root, 'artifacts'))).sort(), expectedNames))
340
+ fail('cohort artifacts differ');
341
+ for (const item of value.packages) {
342
+ const packed = await stableFile(item.tarball, MAX_ARCHIVE, true);
343
+ if (digest(packed) !== item.sha256 || !same(archiveEntries(packed), item.files))
344
+ fail(`cohort tarball differs: ${item.name}`);
345
+ }
346
+ return value;
347
+ }
348
+ export async function readRsiLocalCohort(input) {
349
+ validateInput(input.dshHome, input.profile);
350
+ await io.directory(input.dshHome, false);
351
+ return readExisting(input.dshHome, input.profile, input.source);
352
+ }
353
+ async function defaultBuild(workspace, output, paths, signal) {
354
+ const pnpm = process.env.COREPACK_PNPM_PATH ?? 'pnpm';
355
+ const environment = { ...process.env, COREPACK_ENABLE_AUTO_PIN: '0', npm_config_ignore_scripts: 'true' };
356
+ const version = await io.command(pnpm, ['--version'], environment, signal, 15_000);
357
+ if (version !== '11.7.0')
358
+ fail('pnpm 11.7.0 is required');
359
+ // This is owner-authorized bootstrap, not a candidate release build. Reuse
360
+ // pnpm's normal cache while the frozen lock verifies downloaded packages.
361
+ const configuredStore = await io.command(pnpm, ['store', 'path'], environment, signal, 15_000);
362
+ if (!exact(configuredStore))
363
+ fail('pnpm store path is invalid');
364
+ const store = await realpath(configuredStore).catch(error => {
365
+ if (error.code === 'ENOENT')
366
+ return configuredStore;
367
+ throw error;
368
+ });
369
+ await io.command(pnpm, ['--dir', workspace, 'install', '--frozen-lockfile', '--ignore-scripts', '--package-import-method=copy', `--store-dir=${store}`], environment, signal, 600_000, 2_097_152);
370
+ await io.command(pnpm, ['--dir', workspace, '--workspace-root', '--if-present', 'run', 'build'], environment, signal, 600_000, 2_097_152);
371
+ for (const path of paths) {
372
+ signal.throwIfAborted();
373
+ const destination = join(output, path.split('/')[1]);
374
+ await mkdir(destination, { mode: 0o700 });
375
+ await io.command(pnpm, ['--dir', join(workspace, path), 'pack', '--pack-destination', destination], environment, signal, 180_000, 2_097_152);
376
+ }
377
+ }
378
+ export const rsiLocalCohortPorts = { build: defaultBuild };
379
+ /** The caller holds the DSH_HOME lifecycle lock. A claimed receipt is immutable. */
380
+ export async function prepareRsiLocalCohort(input, ports = rsiLocalCohortPorts) {
381
+ validateInput(input.dshHome, input.profile);
382
+ await io.directory(input.dshHome, false);
383
+ if (input.source.schemaVersion !== 1 || !COMMIT.test(input.source.sourceCommit)
384
+ || !exact(input.source.repository)
385
+ || input.source.repository !== join(input.dshHome, 'rsi-sources', input.profile, 'checkout')
386
+ || !exact(input.source.origin.locator) && input.source.origin.locator !== 'https://github.com/22-ai-00/dsh-enhanced.git'
387
+ || !Array.isArray(input.bundles) || input.bundles.some(slug => !SLUG.test(slug)))
388
+ fail('invalid source or bundle selection');
389
+ const bundles = [...new Set(input.bundles)].sort();
390
+ const parent = join(input.dshHome, 'rsi-local-cohorts');
391
+ try {
392
+ await mkdir(parent, { mode: 0o700 });
393
+ }
394
+ catch (error) {
395
+ if (error.code !== 'EEXIST')
396
+ throw error;
397
+ }
398
+ await privateDirectory(parent);
399
+ const final = expectedRoot(input.dshHome, input.profile);
400
+ if (await exists(final)) {
401
+ const value = await readExisting(input.dshHome, input.profile, input.source);
402
+ if (!same(value.bundles, bundles))
403
+ fail('cohort bundle selection differs');
404
+ return value;
405
+ }
406
+ const signal = AbortSignal.any([input.signal ?? new AbortController().signal, AbortSignal.timeout(1_800_000)]);
407
+ const stage = await mkdtemp(join(parent, `.${input.profile}-stage-`));
408
+ await chmod(stage, 0o700);
409
+ let claimed;
410
+ try {
411
+ const workspace = join(stage, 'workspace'), output = join(stage, 'output');
412
+ await mkdir(workspace, { mode: 0o700 });
413
+ await mkdir(output, { mode: 0o700 });
414
+ const env = { PATH: '/usr/bin:/bin', LANG: 'C', LC_ALL: 'C', HOME: stage,
415
+ GIT_CONFIG_NOSYSTEM: '1', GIT_CONFIG_GLOBAL: '/dev/null', GIT_TERMINAL_PROMPT: '0', GIT_NO_LAZY_FETCH: '1' };
416
+ const git = (args) => io.command('/usr/bin/git', args, env, signal, 60_000);
417
+ await git(['-C', workspace, 'init', '--object-format=sha1', '.']);
418
+ await git(['-C', workspace, 'fetch', '--no-tags', '--no-recurse-submodules', input.source.repository,
419
+ `+${input.source.sourceCommit}:refs/dsh-local-cohort/source`]);
420
+ await git(['-C', workspace, 'checkout', '--detach', input.source.sourceCommit]);
421
+ if (await git(['-C', workspace, 'rev-parse', 'HEAD']) !== input.source.sourceCommit
422
+ || await git(['-C', workspace, 'status', '--porcelain=v1', '--untracked-files=all']) !== '')
423
+ fail('build workspace is not exact clean commit');
424
+ const rootManifest = JSON.parse((await stableFile(join(workspace, 'package.json'), 1_048_576)).toString('utf8'));
425
+ if (rootManifest.name !== 'dsh-enhanced' || rootManifest.version !== input.source.version)
426
+ fail('source root version differs');
427
+ const allowBuilds = await approvedBuilds(workspace);
428
+ const packages = await closure(workspace, input.source.version, bundles);
429
+ const sourceManifests = new Map();
430
+ for (const item of packages)
431
+ sourceManifests.set(item.name, await sourceManifest(workspace, item.path, input.source.version));
432
+ await ports.build(workspace, output, packages.map(item => item.path), signal);
433
+ signal.throwIfAborted();
434
+ if (await git(['-C', workspace, 'rev-parse', 'HEAD']) !== input.source.sourceCommit
435
+ || await git(['-C', workspace, 'diff', '--name-only']) !== ''
436
+ || await git(['-C', workspace, 'diff', '--cached', '--name-only']) !== '')
437
+ fail('tracked build input changed');
438
+ await mkdir(final, { mode: 0o700 });
439
+ const identity = await stat(final);
440
+ claimed = { dev: identity.dev, ino: identity.ino };
441
+ const artifacts = join(final, 'artifacts');
442
+ await mkdir(artifacts, { mode: 0o700 });
443
+ const entries = [];
444
+ for (const item of packages) {
445
+ const slug = slugOf(item.name), directory = join(output, slug), names = await readdir(directory);
446
+ if (names.length !== 1 || !names[0].endsWith('.tgz'))
447
+ fail(`pack output is ambiguous: ${item.name}`);
448
+ const inputTar = join(directory, names[0]);
449
+ const bytes = await adapterNormalize(await stableFile(inputTar, MAX_ARCHIVE));
450
+ const files = archiveEntries(bytes);
451
+ const normalized = join(stage, `${slug}.tgz`);
452
+ await io.writeExclusive(normalized, bytes);
453
+ const packedManifest = await unpackAndCheck(normalized, files, stage, signal);
454
+ validatePackedManifest(packedManifest, sourceManifests.get(item.name), item, input.source.version);
455
+ const tarball = join(artifacts, `${slug}.tgz`);
456
+ await rename(normalized, tarball);
457
+ entries.push({ ...item, tarball, sha256: digest(bytes), files });
458
+ }
459
+ const content = { schemaVersion: 1, root: final, sourceCommit: input.source.sourceCommit,
460
+ version: input.source.version, sourceRepository: input.source.origin.locator, allowBuilds, bundles, packages: entries };
461
+ const value = { ...content, receiptDigest: digest(JSON.stringify(content)) };
462
+ validateReceipt(value, input.dshHome, input.profile);
463
+ await io.syncDirectory(artifacts);
464
+ await io.writeExclusive(join(final, 'receipt.json'), JSON.stringify(value));
465
+ await io.syncDirectory(final);
466
+ await io.syncDirectory(parent);
467
+ return value;
468
+ }
469
+ catch (error) {
470
+ if (claimed) {
471
+ const current = await lstat(final).catch(() => undefined);
472
+ if (current?.isDirectory() && current.dev === claimed.dev && current.ino === claimed.ino
473
+ && !await exists(join(final, 'receipt.json')))
474
+ await rm(final, { recursive: true, force: true });
475
+ }
476
+ throw error;
477
+ }
478
+ finally {
479
+ await rm(stage, { recursive: true, force: true });
480
+ await io.syncDirectory(parent);
481
+ }
482
+ }
483
+ /** A profile's roots and runtime closure define the only eligible peer providers.
484
+ * Peers never expand that closure, including optional peers. Receipt schema 1
485
+ * stays immutable; the peer edges are derived from its exact manifest bytes. */
486
+ export function rsiLocalRuntimeClosure(cohort, bundles) {
487
+ const packages = new Map(cohort.packages.map(item => [item.name, item]));
488
+ if (!bundles.length || new Set(bundles).size !== bundles.length
489
+ || bundles.some(slug => !SLUG.test(slug) || !packages.get(`${INTERNAL}${slug}`)?.bundle))
490
+ fail('bundle is outside cohort');
491
+ const pending = bundles.map(slug => `${INTERNAL}${slug}`), result = new Map();
492
+ while (pending.length) {
493
+ const name = pending.shift();
494
+ if (result.has(name))
495
+ continue;
496
+ const item = packages.get(name);
497
+ if (!item)
498
+ fail(`installed closure missing: ${name}`);
499
+ result.set(name, item);
500
+ pending.push(...item.runtimeDependencies);
501
+ }
502
+ return [...result.values()];
503
+ }
504
+ export async function readRsiLocalArtifactManifest(item) {
505
+ slugOf(item.name);
506
+ let bytes;
507
+ const packed = await stableFile(item.tarball, MAX_ARCHIVE);
508
+ const files = archiveEntries(packed, manifest => { bytes = manifest; });
509
+ if (digest(packed) !== item.sha256 || !same(files, item.files))
510
+ fail(`cohort tarball differs: ${item.name}`);
511
+ if (!bytes || bytes.length > 1_048_576 || digest(bytes) !== item.files.find(file => file.path === 'package.json')?.sha256) {
512
+ fail(`installed package file differs: ${item.name}/package.json`);
513
+ }
514
+ const manifest = JSON.parse(bytes.toString('utf8'));
515
+ if (manifest.name !== item.name || manifest.version !== item.version
516
+ || !same(runtimeDependencies(manifest), item.runtimeDependencies))
517
+ fail(`installed package identity differs: ${item.name}`);
518
+ const peers = manifest.peerDependencies;
519
+ if (peers === undefined)
520
+ return { peerDependencies: {} };
521
+ if (!peers || typeof peers !== 'object' || Array.isArray(peers))
522
+ fail(`invalid peerDependencies: ${item.name}`);
523
+ const result = {};
524
+ for (const [name, range] of Object.entries(peers)) {
525
+ if (typeof range !== 'string' || !range)
526
+ fail(`invalid peerDependencies entry: ${item.name}`);
527
+ if (name.startsWith(INTERNAL))
528
+ slugOf(name);
529
+ result[name] = range;
530
+ }
531
+ return { peerDependencies: result };
532
+ }
533
+ export async function rsiLocalPeerOverrides(input) {
534
+ const { cohort } = input;
535
+ validateReceipt(cohort, dirname(dirname(cohort.root)), cohort.root.split(sep).at(-1));
536
+ const closure = rsiLocalRuntimeClosure(cohort, input.bundles);
537
+ const providers = new Map(closure.map(item => [item.name, item])), result = {};
538
+ const manifestPaths = new Map();
539
+ if (input.profilePath) {
540
+ const root = await realpath(input.profilePath);
541
+ if (root !== input.profilePath)
542
+ fail('profile path is a link');
543
+ const pending = input.bundles.map(slug => ({ name: `${INTERNAL}${slug}`, from: join(root, 'package.json') }));
544
+ while (pending.length) {
545
+ const { name, from } = pending.shift();
546
+ const path = await realpath(createRequire(from).resolve(`${name}/package.json`));
547
+ if (!inside(root, path))
548
+ fail(`installed package escapes profile: ${name}`);
549
+ const previous = manifestPaths.get(name);
550
+ if (previous && previous !== path)
551
+ fail(`installed package identity split: ${name}`);
552
+ if (previous)
553
+ continue;
554
+ manifestPaths.set(name, path);
555
+ pending.push(...providers.get(name).runtimeDependencies.map(dependency => ({ name: dependency, from: path })));
556
+ }
557
+ }
558
+ for (const parent of closure) {
559
+ let bytes;
560
+ if (input.profilePath) {
561
+ bytes = await stableFile(manifestPaths.get(parent.name), 1_048_576);
562
+ }
563
+ else {
564
+ const manifest = await readRsiLocalArtifactManifest({ ...parent, version: cohort.version });
565
+ for (const name of Object.keys(manifest.peerDependencies)) {
566
+ const provider = providers.get(name);
567
+ if (provider)
568
+ result[`${parent.name}@${cohort.version}>${name}`] = `file:${provider.tarball}`;
569
+ }
570
+ continue;
571
+ }
572
+ if (!bytes || bytes.length > 1_048_576 || digest(bytes) !== parent.files.find(file => file.path === 'package.json')?.sha256)
573
+ fail(`installed package file differs: ${parent.name}/package.json`);
574
+ const manifest = JSON.parse(bytes.toString('utf8'));
575
+ if (manifest.name !== parent.name || manifest.version !== cohort.version
576
+ || !same(runtimeDependencies(manifest), parent.runtimeDependencies))
577
+ fail(`installed package identity differs: ${parent.name}`);
578
+ const peers = manifest.peerDependencies;
579
+ if (peers === undefined)
580
+ continue;
581
+ if (!peers || typeof peers !== 'object' || Array.isArray(peers))
582
+ fail(`invalid peerDependencies: ${parent.name}`);
583
+ for (const [name, range] of Object.entries(peers)) {
584
+ if (typeof range !== 'string' || !range)
585
+ fail(`invalid peerDependencies entry: ${parent.name}`);
586
+ if (!name.startsWith(INTERNAL))
587
+ continue;
588
+ slugOf(name);
589
+ const provider = providers.get(name);
590
+ if (provider)
591
+ result[`${parent.name}@${cohort.version}>${name}`] = `file:${provider.tarball}`;
592
+ }
593
+ }
594
+ return result;
595
+ }
596
+ /** Validate the exact installed files for selected bundles and their own runtime closure. */
597
+ export async function verifyRsiLocalInstalledPackages(input) {
598
+ const { cohort } = input;
599
+ if (!exact(input.profilePath) || !exact(cohort.root))
600
+ fail('invalid installed profile path');
601
+ const home = dirname(dirname(cohort.root));
602
+ validateReceipt(cohort, home, cohort.root.split(sep).at(-1));
603
+ await readExisting(home, cohort.root.split(sep).at(-1));
604
+ const root = await realpath(input.profilePath);
605
+ if (root !== input.profilePath)
606
+ fail('profile path is a link');
607
+ const selected = input.bundles ?? cohort.bundles;
608
+ const packages = new Map(cohort.packages.map(item => [item.name, item]));
609
+ if (!Array.isArray(selected) || selected.some(slug => !SLUG.test(slug)
610
+ || !packages.get(`${INTERNAL}${slug}`)?.bundle))
611
+ fail('bundle is outside cohort');
612
+ const eligible = new Set(rsiLocalRuntimeClosure(cohort, selected).map(item => item.name));
613
+ const physicalPackages = new Map();
614
+ const pending = [...new Set(selected.map(slug => `${INTERNAL}${slug}`))]
615
+ .map(name => ({ name, from: join(root, 'package.json') }));
616
+ const visited = new Set();
617
+ while (pending.length) {
618
+ const { name, from } = pending.shift();
619
+ const item = packages.get(name);
620
+ if (!item)
621
+ fail(`installed closure missing: ${name}`);
622
+ const manifestPath = createRequire(from).resolve(`${name}/package.json`);
623
+ const packageRoot = dirname(manifestPath), physical = await realpath(packageRoot);
624
+ if (!inside(root, physical))
625
+ fail(`installed package escapes profile: ${name}`);
626
+ const existingPhysical = physicalPackages.get(name);
627
+ if (existingPhysical && existingPhysical !== physical)
628
+ fail(`installed package identity split: ${name}`);
629
+ physicalPackages.set(name, physical);
630
+ const visitKey = `${name}\0${physical}`;
631
+ if (visited.has(visitKey))
632
+ continue;
633
+ visited.add(visitKey);
634
+ const manifest = JSON.parse((await stableFile(manifestPath, 1_048_576)).toString('utf8'));
635
+ if (manifest.name !== name || manifest.version !== cohort.version || !same(runtimeDependencies(manifest), item.runtimeDependencies))
636
+ fail(`installed package identity differs: ${name}`);
637
+ for (const file of item.files) {
638
+ const path = join(packageRoot, file.path), physicalFile = await realpath(path);
639
+ if (!inside(physical, physicalFile))
640
+ fail(`installed package file escapes: ${name}/${file.path}`);
641
+ const metadata = await lstat(path);
642
+ if (!metadata.isFile() || metadata.isSymbolicLink() || (metadata.mode & 0o100) !== (file.mode & 0o100)
643
+ || (metadata.mode & 0o022) !== 0
644
+ || digest(await stableFile(path, MAX_ARCHIVE)) !== file.sha256)
645
+ fail(`installed package file differs: ${name}/${file.path}`);
646
+ }
647
+ const actualFiles = [];
648
+ const walk = async (directory) => {
649
+ for (const child of await readdir(directory)) {
650
+ if (directory === packageRoot && child === 'node_modules')
651
+ continue;
652
+ const path = join(directory, child), metadata = await lstat(path);
653
+ if (metadata.isDirectory())
654
+ await walk(path);
655
+ else if (metadata.isFile())
656
+ actualFiles.push(relative(packageRoot, path).split(sep).join('/'));
657
+ else
658
+ fail(`installed package has unsafe entry: ${name}`);
659
+ }
660
+ };
661
+ await walk(packageRoot);
662
+ if (!same(actualFiles.sort(), item.files.map(file => file.path)))
663
+ fail(`installed package inventory differs: ${name}`);
664
+ const peers = manifest.peerDependencies;
665
+ if (peers !== undefined && (!peers || typeof peers !== 'object' || Array.isArray(peers)))
666
+ fail(`invalid peerDependencies: ${name}`);
667
+ const localPeers = Object.entries(peers ?? {}).filter(([peer, range]) => {
668
+ if (typeof range !== 'string' || !range)
669
+ fail(`invalid peerDependencies entry: ${name}`);
670
+ return eligible.has(peer);
671
+ }).map(([peer]) => peer);
672
+ for (const dependency of new Set([...item.runtimeDependencies, ...localPeers])) {
673
+ // Resolve relative to this package so pnpm's nested layout cannot silently
674
+ // route a runtime edge to a global or otherwise unrelated installation.
675
+ const localRequire = createRequire(manifestPath);
676
+ const dependencyPath = localRequire.resolve(`${dependency}/package.json`);
677
+ if (!inside(root, await realpath(dependencyPath)))
678
+ fail(`runtime dependency escapes profile: ${name} -> ${dependency}`);
679
+ pending.push({ name: dependency, from: manifestPath });
680
+ }
681
+ }
682
+ }
683
+ /** A native package add replaces pnpm links while the caller is running.
684
+ * Node caches their old physical targets in that process. Resolve the final
685
+ * installed closure in a new process using this pinned verifier's same checks. */
686
+ export async function verifyRsiLocalInstalledPackagesFresh(input, signal) {
687
+ const modulePath = fileURLToPath(import.meta.url);
688
+ const source = await io.readStable(modulePath, 2_097_152);
689
+ const payload = JSON.stringify({ input, modulePath, moduleUrl: pathToFileURL(modulePath).href, sourceHash: digest(source) });
690
+ if (Buffer.byteLength(payload) > 20_971_520)
691
+ fail('fresh installed verification input exceeds bound');
692
+ const script = `
693
+ import { createHash } from 'node:crypto'
694
+ import { readFile } from 'node:fs/promises'
695
+ let size = 0
696
+ const chunks = []
697
+ try {
698
+ for await (const chunk of process.stdin) {
699
+ size += chunk.length
700
+ if (size > 20_971_520) throw new Error('verification input exceeds bound')
701
+ chunks.push(chunk)
702
+ }
703
+ const payload = JSON.parse(Buffer.concat(chunks).toString('utf8'))
704
+ const source = await readFile(payload.modulePath)
705
+ if (createHash('sha256').update(source).digest('hex') !== payload.sourceHash) throw new Error('pinned verifier source changed')
706
+ const { verifyRsiLocalInstalledPackages } = await import(payload.moduleUrl)
707
+ await verifyRsiLocalInstalledPackages(payload.input)
708
+ process.stdout.write(JSON.stringify({ ok: true }))
709
+ } catch (error) {
710
+ process.stdout.write(JSON.stringify({ ok: false, message: String(error?.message ?? error).slice(0, 4096) }))
711
+ }
712
+ `;
713
+ const environment = { ...process.env, NODE_OPTIONS: undefined, NODE_PATH: undefined };
714
+ const deadline = AbortSignal.any([signal ?? new AbortController().signal, AbortSignal.timeout(120_000)]);
715
+ deadline.throwIfAborted();
716
+ const result = await new Promise((resolvePromise, reject) => {
717
+ const child = spawn(process.execPath, ['--input-type=module', '--eval', script], {
718
+ env: environment, stdio: ['pipe', 'pipe', 'pipe'], detached: process.platform !== 'win32', windowsHide: true,
719
+ });
720
+ const output = [];
721
+ let outputBytes = 0, stderrBytes = 0, exceeded = false, spawnError = false;
722
+ const group = () => {
723
+ if (!child.pid)
724
+ return;
725
+ try {
726
+ if (process.platform === 'win32')
727
+ child.kill('SIGKILL');
728
+ else
729
+ process.kill(-child.pid, 'SIGKILL');
730
+ }
731
+ catch (error) {
732
+ if (error.code !== 'ESRCH')
733
+ child.kill('SIGKILL');
734
+ }
735
+ };
736
+ const abort = () => group();
737
+ deadline.addEventListener('abort', abort, { once: true });
738
+ if (deadline.aborted)
739
+ group();
740
+ child.stdout.on('data', (chunk) => {
741
+ outputBytes += chunk.length;
742
+ if (outputBytes > 8_192) {
743
+ exceeded = true;
744
+ group();
745
+ }
746
+ else
747
+ output.push(chunk);
748
+ });
749
+ child.stderr.on('data', (chunk) => {
750
+ stderrBytes += chunk.length;
751
+ if (stderrBytes > 8_192) {
752
+ exceeded = true;
753
+ group();
754
+ }
755
+ });
756
+ child.stdin.on('error', () => { spawnError = true; group(); });
757
+ child.once('error', () => { spawnError = true; group(); });
758
+ child.once('close', (code, killed) => {
759
+ deadline.removeEventListener('abort', abort);
760
+ if (spawnError || exceeded || deadline.aborted || code !== 0 || killed !== null) {
761
+ reject(new Error('rsi local cohort: fresh installed verification process failed or exceeded its bound'));
762
+ }
763
+ else
764
+ resolvePromise(Buffer.concat(output).toString('utf8'));
765
+ });
766
+ child.stdin.end(payload);
767
+ });
768
+ let parsed;
769
+ try {
770
+ parsed = JSON.parse(result);
771
+ }
772
+ catch {
773
+ fail('fresh installed verification returned invalid result');
774
+ }
775
+ if (parsed.ok === true && Object.keys(parsed).length === 1)
776
+ return;
777
+ if (parsed.ok === false && typeof parsed.message === 'string' && Object.keys(parsed).length === 2)
778
+ throw new Error(parsed.message);
779
+ fail('fresh installed verification returned invalid result');
780
+ }
781
+ //# sourceMappingURL=rsi-local-cohort.js.map