@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,139 @@
1
+ import { createHash, createPrivateKey, createPublicKey, generateKeyPairSync, randomUUID } from 'node:crypto';
2
+ import { lstat, mkdir, readdir, realpath, rm } from 'node:fs/promises';
3
+ import { isAbsolute, join, resolve } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { isDeepStrictEqual } from 'node:util';
6
+ import { rsiBuildResources as io } from './rsi-build.js';
7
+ export const rsiAuthorityRoles = ['approval', 'release', 'adoption', 'observation', 'qualification', 'host',
8
+ 'pr', 'review', 'merge', 'build', 'sign', 'publish', 'registry-verify', 'catalog-admission'];
9
+ const uuid = /^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u;
10
+ const hash = (value) => createHash('sha256').update(value).digest('hex');
11
+ function fail(message) { throw new Error(`rsi authority resources: ${message}`); }
12
+ async function readPrivate(path, maximum) {
13
+ const item = await lstat(path);
14
+ if (!item.isFile() || item.nlink !== 1 || await realpath(path) !== path)
15
+ fail(`unsafe file: ${path}`);
16
+ return io.readStable(path, maximum, true);
17
+ }
18
+ function locations(home, profile) {
19
+ const root = join(home, 'rsi-authorities', profile);
20
+ return { root, keys: join(root, 'identities'), stateRoot: join(root, 'state'), configRoot: join(root, 'config'),
21
+ registryRoot: join(root, 'registry'), catalogPath: join(root, 'catalog.json'), receiptPath: join(root, 'bootstrap.json') };
22
+ }
23
+ async function inspect(home, profile, signal) {
24
+ const paths = locations(home, profile);
25
+ await io.directory(paths.root);
26
+ if (!isDeepStrictEqual((await readdir(paths.root)).sort(), ['bootstrap.json', 'catalog.json', 'config', 'identities', 'registry', 'state']))
27
+ fail('existing resources are incomplete');
28
+ const receipt = JSON.parse((await readPrivate(paths.receiptPath, 65_536)).toString('utf8'));
29
+ const { receiptDigest, ...content } = receipt;
30
+ const resources = receipt.resources;
31
+ if (receipt.schemaVersion !== 1 || receipt.dshHome !== home || receipt.profile !== profile
32
+ || hash(JSON.stringify(content)) !== receiptDigest || resources?.schemaVersion !== 1
33
+ || resources.root !== paths.root || !uuid.test(resources.installationId) || !uuid.test(resources.ledgerId)
34
+ || resources.installationId === resources.ledgerId || resources.registry?.id !== `registry-${resources.installationId}`
35
+ || resources.registry.root !== paths.registryRoot || resources.registry.locator !== pathToFileURL(paths.registryRoot).href
36
+ || resources.catalog?.id !== `catalog-${resources.installationId}` || resources.catalog.path !== paths.catalogPath
37
+ || resources.stateRoot !== paths.stateRoot || resources.configRoot !== paths.configRoot
38
+ || !resources.identities || !receipt.keyDigests
39
+ || !isDeepStrictEqual(Object.keys(resources.identities).sort(), [...rsiAuthorityRoles].sort())
40
+ || !isDeepStrictEqual(Object.keys(receipt.keyDigests).sort(), [...rsiAuthorityRoles].sort()))
41
+ fail('resource receipt differs from the installation');
42
+ for (const directory of [paths.keys, paths.stateRoot, paths.configRoot, paths.registryRoot])
43
+ await io.directory(directory);
44
+ if (!isDeepStrictEqual((await readdir(paths.keys)).sort(), rsiAuthorityRoles.map(role => `${role}.pem`).sort()))
45
+ fail('signing identities changed');
46
+ const publicKeys = new Set();
47
+ for (const role of rsiAuthorityRoles) {
48
+ signal.throwIfAborted();
49
+ const identity = resources.identities[role], expectedAuthority = `${role}-${resources.installationId}`;
50
+ if (!isDeepStrictEqual(Object.keys(identity).sort(), ['authority', 'keyId', 'keyPath', 'publicKeyPem'])
51
+ || identity.authority !== expectedAuthority || identity.keyId !== `${expectedAuthority}-key`
52
+ || identity.keyPath !== join(paths.keys, `${role}.pem`))
53
+ fail('signing identity binding changed');
54
+ const bytes = await readPrivate(identity.keyPath, 16_384);
55
+ const key = createPrivateKey(bytes), publicKey = createPublicKey(key).export({ format: 'pem', type: 'spki' }).toString();
56
+ if (key.asymmetricKeyType !== 'ed25519' || hash(bytes) !== receipt.keyDigests[role]
57
+ || publicKey !== identity.publicKeyPem || publicKeys.has(publicKey))
58
+ fail('signing identity key changed');
59
+ publicKeys.add(publicKey);
60
+ }
61
+ // These are live release resources: validate them, never reset their contents
62
+ // or compare them with the initial empty catalog/registry/state snapshots.
63
+ const { parseCatalog } = await import('@dsh-enhanced/plugin-control-plane');
64
+ parseCatalog(JSON.parse((await readPrivate(paths.catalogPath, 2_097_152)).toString('utf8')));
65
+ signal.throwIfAborted();
66
+ return resources;
67
+ }
68
+ /** Caller holds the DSH_HOME lifecycle lock. This creates identities and local
69
+ * storage, not grants; owner-bound authorization is configured separately. */
70
+ export async function prepareRsiAuthorityResources(input) {
71
+ const { dshHome: home, profile } = input;
72
+ if (!isAbsolute(home) || resolve(home) !== home || home.includes('\0') || /[\r\n]/u.test(home)
73
+ || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u.test(profile))
74
+ fail('invalid installation binding');
75
+ const signal = AbortSignal.any([input.signal ?? new AbortController().signal, AbortSignal.timeout(30_000)]);
76
+ signal.throwIfAborted();
77
+ await io.directory(home, false);
78
+ const parent = join(home, 'rsi-authorities'), paths = locations(home, profile);
79
+ if (input.existingOnly) {
80
+ await io.directory(parent);
81
+ return inspect(home, profile, signal);
82
+ }
83
+ try {
84
+ await mkdir(parent, { mode: 0o700 });
85
+ }
86
+ catch (error) {
87
+ if (error.code !== 'EEXIST')
88
+ throw error;
89
+ }
90
+ await io.directory(parent);
91
+ let existing = false;
92
+ try {
93
+ await lstat(paths.root);
94
+ existing = true;
95
+ }
96
+ catch (error) {
97
+ if (error.code !== 'ENOENT')
98
+ throw error;
99
+ }
100
+ if (existing)
101
+ return inspect(home, profile, signal);
102
+ // An exclusive claim prevents overwriting another installation. Failed work
103
+ // removes only this exact directory; incomplete crash residue is never reset.
104
+ await mkdir(paths.root, { mode: 0o700 });
105
+ const claimed = await lstat(paths.root);
106
+ try {
107
+ for (const directory of [paths.keys, paths.stateRoot, paths.configRoot, paths.registryRoot])
108
+ await mkdir(directory, { mode: 0o700 });
109
+ const installationId = randomUUID(), ledgerId = randomUUID();
110
+ const identities = {}, keyDigests = {};
111
+ for (const role of rsiAuthorityRoles) {
112
+ signal.throwIfAborted();
113
+ const pair = generateKeyPairSync('ed25519'), keyPath = join(paths.keys, `${role}.pem`);
114
+ const privateKey = pair.privateKey.export({ type: 'pkcs8', format: 'pem' }).toString();
115
+ await io.writeExclusive(keyPath, privateKey);
116
+ const authority = `${role}-${installationId}`;
117
+ identities[role] = { authority, keyId: `${authority}-key`, keyPath,
118
+ publicKeyPem: pair.publicKey.export({ type: 'spki', format: 'pem' }).toString() };
119
+ keyDigests[role] = hash(privateKey);
120
+ }
121
+ const resources = { schemaVersion: 1, root: paths.root, installationId, ledgerId, identities,
122
+ registry: { id: `registry-${installationId}`, root: paths.registryRoot, locator: pathToFileURL(paths.registryRoot).href },
123
+ catalog: { id: `catalog-${installationId}`, path: paths.catalogPath }, stateRoot: paths.stateRoot, configRoot: paths.configRoot };
124
+ await io.writeExclusive(paths.catalogPath, '{"schemaVersion":1,"entries":[]}\n');
125
+ const content = { schemaVersion: 1, dshHome: home, profile, resources, keyDigests };
126
+ await io.writeExclusive(paths.receiptPath, JSON.stringify({ ...content, receiptDigest: hash(JSON.stringify(content)) }));
127
+ for (const directory of [paths.keys, paths.stateRoot, paths.configRoot, paths.registryRoot, paths.root, parent])
128
+ await io.syncDirectory(directory);
129
+ return await inspect(home, profile, signal);
130
+ }
131
+ catch (error) {
132
+ const current = await lstat(paths.root).catch(() => undefined);
133
+ if (current?.isDirectory() && current.dev === claimed.dev && current.ino === claimed.ino)
134
+ await rm(paths.root, { recursive: true, force: true });
135
+ await io.syncDirectory(parent);
136
+ throw error;
137
+ }
138
+ }
139
+ //# sourceMappingURL=rsi-authority-resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rsi-authority-resources.js","sourceRoot":"","sources":["../src/rsi-authority-resources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ export interface Pin {
2
+ path: string;
3
+ sha256: string;
4
+ }
5
+ declare const PHASES: readonly ["pr", "review", "merge", "build", "sign", "publish", "registry-verify", "catalog-admission"];
6
+ type Phase = typeof PHASES[number];
7
+ type Executable = 'approval' | 'release' | 'adoption' | 'observation' | 'qualification' | 'hostAuthority' | 'hostAttestor';
8
+ export interface RsiAuthorityRuntime {
9
+ schemaVersion: 1;
10
+ packageVersion: string;
11
+ root: string;
12
+ node: Pin;
13
+ executables: Record<Executable, Pin>;
14
+ releaseAdapters: Record<Phase, Pin>;
15
+ processHelper: Pin;
16
+ observerClient: Pin;
17
+ catalogValidator: Pin;
18
+ catalogInterpreter: Pin;
19
+ }
20
+ interface Options {
21
+ packageRoot?: string;
22
+ nodePath?: string;
23
+ }
24
+ /** Read a copied runtime receipt through its physical stage path, retaining
25
+ * the logical paths embedded in the original installation. */
26
+ export declare function readRsiAuthorityRuntimeReceipt(input: {
27
+ logicalHome: string;
28
+ physicalHome: string;
29
+ profile: string;
30
+ signal?: AbortSignal;
31
+ }): Promise<{
32
+ runtime: RsiAuthorityRuntime;
33
+ receiptDigest: string;
34
+ }>;
35
+ /** Replace only the copied runtime under a stopped Home stage. The receipt and
36
+ * shebangs keep their logical Home paths, so the transaction can rename Home. */
37
+ export declare function replaceRsiAuthorityRuntimeInStage(input: {
38
+ logicalHome: string;
39
+ physicalHome: string;
40
+ profile: string;
41
+ signal?: AbortSignal;
42
+ }, options?: Options): Promise<RsiAuthorityRuntime>;
43
+ /** Caller holds the home lifecycle lock. Only this function's stage/final claim is removed on failure. */
44
+ export declare function prepareRsiAuthorityRuntime(input: {
45
+ dshHome: string;
46
+ profile: string;
47
+ signal?: AbortSignal;
48
+ }, options?: Options): Promise<RsiAuthorityRuntime>;
49
+ export {};
50
+ //# sourceMappingURL=rsi-authority-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rsi-authority-runtime.d.ts","sourceRoot":"","sources":["../src/rsi-authority-runtime.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,GAAG;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACrD,QAAA,MAAM,MAAM,wGAAyG,CAAA;AACrH,KAAK,KAAK,GAAG,OAAO,MAAM,CAAC,MAAM,CAAC,CAAA;AAClC,KAAK,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,GAAG,eAAe,GAAG,eAAe,GAAG,cAAc,CAAA;AAC1H,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,CAAC,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,GAAG,CAAA;IACT,WAAW,EAAE,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;IACpC,eAAe,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACnC,aAAa,EAAE,GAAG,CAAA;IAClB,cAAc,EAAE,GAAG,CAAA;IACnB,gBAAgB,EAAE,GAAG,CAAA;IACrB,kBAAkB,EAAE,GAAG,CAAA;CACxB;AAID,UAAU,OAAO;IAAG,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE;AA8J7D;8DAC8D;AAC9D,wBAAsB,8BAA8B,CAAC,KAAK,EAAE;IAC1D,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CACjF,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,mBAAmB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAcnE;AAED;iFACiF;AACjF,wBAAsB,iCAAiC,CAAC,KAAK,EAAE;IAC7D,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CACjF,EAAE,OAAO,GAAE,OAAY,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA4DtD;AAED,0GAA0G;AAC1G,wBAAsB,0BAA0B,CAAC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,EAChH,OAAO,GAAE,OAAY,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAiErD"}
@@ -0,0 +1,393 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { constants } from 'node:fs';
3
+ import { chmod, lstat, mkdir, mkdtemp, open, readdir, realpath, rename, rm } from 'node:fs/promises';
4
+ import { createRequire } from 'node:module';
5
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
6
+ import { pathToFileURL } from 'node:url';
7
+ import { isDeepStrictEqual } from 'node:util';
8
+ import { rsiBuildResources as io } from './rsi-build.js';
9
+ import { version } from './version.js';
10
+ const PHASES = ['pr', 'review', 'merge', 'build', 'sign', 'publish', 'registry-verify', 'catalog-admission'];
11
+ const EXECUTABLES = {
12
+ approval: 'dsh-source-approval-authority.js', release: 'dsh-source-release-authority.js',
13
+ adoption: 'dsh-source-adoption-authority.js', observation: 'dsh-task-observation-authority.js',
14
+ qualification: 'dsh-live-qualification-authority.js', hostAuthority: 'dsh-systemd-host-authority.js',
15
+ hostAttestor: 'dsh-systemd-host-attestor.js',
16
+ };
17
+ const MAX_ENTRIES = 512, MAX_FILE = 160_000_000, MAX_TOTAL = 256_000_000;
18
+ const CONTRACT_PACKAGE = '@dsh-enhanced/assistant-growth-contract';
19
+ const CONTRACT_ROOT = `node_modules/${CONTRACT_PACKAGE}`;
20
+ const RUNTIME_DIRECTORIES = ['bin', 'lib', 'node_modules', 'node_modules/@dsh-enhanced', CONTRACT_ROOT, `${CONTRACT_ROOT}/lib`];
21
+ function fail(message) { throw new Error(`rsi authority runtime: ${message}`); }
22
+ function hash(bytes) { return createHash('sha256').update(bytes).digest('hex'); }
23
+ function exactPath(path) {
24
+ return isAbsolute(path) && resolve(path) === path
25
+ && !path.includes('\0') && !path.includes('\r') && !path.includes('\n');
26
+ }
27
+ function environment(home) { return { PATH: '/usr/bin:/bin', LANG: 'C', LC_ALL: 'C', HOME: home }; }
28
+ function pin(root, path, sha256) { return { path: join(root, path), sha256 }; }
29
+ function result(root, entries) {
30
+ const found = (path) => {
31
+ const item = entries.find(entry => entry.path === path);
32
+ if (!item)
33
+ fail(`missing asset: ${path}`);
34
+ return pin(root, path, item.sha256);
35
+ };
36
+ const executables = {};
37
+ for (const [key, filename] of Object.entries(EXECUTABLES))
38
+ executables[key] = found(`bin/${filename}`);
39
+ const releaseAdapters = {};
40
+ for (const phase of PHASES)
41
+ releaseAdapters[phase] = found(`bin/dsh-local-release-${phase}.js`);
42
+ return { schemaVersion: 1, packageVersion: version, root, node: found('node'), executables, releaseAdapters,
43
+ processHelper: found('lib/adapter-process.js'), observerClient: found('lib/runtime-observer-protocol.js'),
44
+ catalogValidator: found('lib/catalog.js'), catalogInterpreter: found('lib/catalog-interpreter.js') };
45
+ }
46
+ async function asset(path, maximum, signal) {
47
+ signal.throwIfAborted();
48
+ const bytes = await io.readStable(path, maximum, false, true);
49
+ signal.throwIfAborted();
50
+ return bytes;
51
+ }
52
+ async function sourceAssets(packageRoot, nodePath, signal) {
53
+ await io.directory(packageRoot, false);
54
+ await io.directory(join(packageRoot, 'bin'), false);
55
+ await io.directory(join(packageRoot, 'lib'), false);
56
+ const packageBytes = await asset(join(packageRoot, 'package.json'), 65_536, signal);
57
+ const manifest = JSON.parse(packageBytes.toString('utf8'));
58
+ if (manifest.name !== '@dsh-enhanced/plugin-control-plane' || manifest.version !== version || manifest.type !== 'module')
59
+ fail('installed package identity differs');
60
+ if (typeof manifest.dependencies?.[CONTRACT_PACKAGE] !== 'string')
61
+ fail('installed shared contract is not declared');
62
+ const libraries = (await readdir(join(packageRoot, 'lib'))).filter(name => name.endsWith('.js')).sort();
63
+ if (!libraries.length || libraries.length + 19 > MAX_ENTRIES)
64
+ fail('library entry bound exceeded');
65
+ const names = new Map([['package.json', join(packageRoot, 'package.json')], ['node', nodePath]]);
66
+ for (const name of libraries)
67
+ names.set(`lib/${name}`, join(packageRoot, 'lib', name));
68
+ for (const name of Object.values(EXECUTABLES))
69
+ names.set(`bin/${name}`, join(packageRoot, 'bin', name));
70
+ for (const phase of PHASES)
71
+ names.set(`bin/dsh-local-release-${phase}.js`, join(packageRoot, 'bin', 'dsh-local-release-adapter.js'));
72
+ // Resolve through this package's manifest, but accept only its own dependency
73
+ // edge or the adjacent edge in the same pnpm virtual-store node_modules.
74
+ const resolvedContract = createRequire(join(packageRoot, 'package.json')).resolve(`${CONTRACT_PACKAGE}/package.json`);
75
+ const contractRoot = dirname(await realpath(resolvedContract));
76
+ const edges = [join(packageRoot, 'node_modules', CONTRACT_PACKAGE)];
77
+ if (basename(dirname(packageRoot)) === '@dsh-enhanced' && basename(dirname(dirname(packageRoot))) === 'node_modules'
78
+ && basename(dirname(dirname(dirname(dirname(packageRoot))))) === '.pnpm') {
79
+ edges.push(join(dirname(packageRoot), 'assistant-growth-contract'));
80
+ }
81
+ const edgeRoots = await Promise.all(edges.map(async (edge) => realpath(edge).catch(() => undefined)));
82
+ if (!edgeRoots.includes(contractRoot))
83
+ fail('installed shared contract resolved outside its dependency edge');
84
+ await io.directory(contractRoot, false);
85
+ await io.directory(join(contractRoot, 'lib'), false);
86
+ const contractPackageBytes = await asset(join(contractRoot, 'package.json'), 65_536, signal);
87
+ const contractManifest = JSON.parse(contractPackageBytes.toString('utf8'));
88
+ if (contractManifest.name !== CONTRACT_PACKAGE || contractManifest.version !== version || contractManifest.type !== 'module'
89
+ || Object.keys(contractManifest.dependencies ?? {}).length || Object.keys(contractManifest.optionalDependencies ?? {}).length) {
90
+ fail('installed shared contract identity or dependency boundary differs');
91
+ }
92
+ names.set(`${CONTRACT_ROOT}/package.json`, join(contractRoot, 'package.json'));
93
+ const contractLibraries = (await readdir(join(contractRoot, 'lib'))).filter(name => name.endsWith('.js')).sort();
94
+ if (!contractLibraries.includes('index.js') || names.size + contractLibraries.length > MAX_ENTRIES)
95
+ fail('shared contract entry bound exceeded');
96
+ for (const name of contractLibraries)
97
+ names.set(`${CONTRACT_ROOT}/lib/${name}`, join(contractRoot, 'lib', name));
98
+ const files = [];
99
+ let total = 0;
100
+ for (const [path, sourcePath] of names) {
101
+ const bytes = path === 'package.json' ? packageBytes : path === `${CONTRACT_ROOT}/package.json`
102
+ ? contractPackageBytes : await asset(sourcePath, MAX_FILE, signal);
103
+ total += bytes.length;
104
+ if (total > MAX_TOTAL)
105
+ fail('asset byte bound exceeded');
106
+ const sourceMode = (await lstat(sourcePath)).mode & 0o777;
107
+ files.push({ path, sourcePath, bytes, sourceSha256: hash(bytes), sourceMode });
108
+ }
109
+ const node = files.find(file => file.path === 'node').bytes;
110
+ if (!node.subarray(0, 4).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46])))
111
+ fail('Node interpreter is not native ELF');
112
+ const nodeVersion = await io.command(nodePath, ['--version'], environment(packageRoot), signal, 10_000, 1024);
113
+ const match = /^v(\d+)\.(\d+)\.(\d+)$/u.exec(nodeVersion);
114
+ if (!match || !(Number(match[1]) === 22 && Number(match[2]) >= 19 || Number(match[1]) >= 24))
115
+ fail('Node version is outside package engines');
116
+ return files;
117
+ }
118
+ async function verifySources(files, signal) {
119
+ const seen = new Set();
120
+ for (const file of files) {
121
+ if (seen.has(file.sourcePath))
122
+ continue;
123
+ seen.add(file.sourcePath);
124
+ if (hash(await asset(file.sourcePath, MAX_FILE, signal)) !== file.sourceSha256
125
+ || ((await lstat(file.sourcePath)).mode & 0o777) !== file.sourceMode)
126
+ fail('installed source changed');
127
+ }
128
+ }
129
+ function deployedBytes(file, root) {
130
+ if (file.path === 'package.json')
131
+ return Buffer.from('{"type":"module"}\n');
132
+ if (!file.path.startsWith('bin/'))
133
+ return file.bytes;
134
+ const first = file.bytes.toString('utf8', 0, 128).split('\n', 1)[0] ?? '';
135
+ if (!first.startsWith('#!'))
136
+ fail('CLI has no shebang');
137
+ return Buffer.concat([Buffer.from(`#!${join(root, 'node')}\n`), file.bytes.subarray(Buffer.byteLength(first) + 1)]);
138
+ }
139
+ async function writeFile(path, bytes, mode) {
140
+ const fd = await open(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, mode);
141
+ try {
142
+ await fd.writeFile(bytes);
143
+ await fd.chmod(mode);
144
+ await fd.sync();
145
+ }
146
+ finally {
147
+ await fd.close();
148
+ }
149
+ }
150
+ async function verifyTree(root, entries, signal) {
151
+ await io.directory(root);
152
+ const expected = new Map(entries.map(item => [item.path, item]));
153
+ const visit = async (folder, relative = '') => {
154
+ signal.throwIfAborted();
155
+ const names = await readdir(folder);
156
+ for (const name of names) {
157
+ const path = relative ? `${relative}/${name}` : name;
158
+ const full = join(root, path), item = await lstat(full);
159
+ if (item.isSymbolicLink() || item.nlink !== 1 && item.isFile() || process.getuid && item.uid !== process.getuid())
160
+ fail('deployed asset is linked or unowned');
161
+ if (item.isDirectory()) {
162
+ if (!RUNTIME_DIRECTORIES.includes(path) || !entries.some(entry => entry.path.startsWith(`${path}/`))
163
+ || (item.mode & 0o777) !== 0o700)
164
+ fail('unexpected runtime directory');
165
+ await visit(full, path);
166
+ }
167
+ else if (item.isFile()) {
168
+ if (path === 'receipt.json')
169
+ continue;
170
+ const entry = expected.get(path);
171
+ if (!entry || item.size !== entry.size || (item.mode & 0o777) !== entry.mode
172
+ || hash(await asset(full, MAX_FILE, signal)) !== entry.sha256)
173
+ fail(`deployed asset changed: ${path}`);
174
+ expected.delete(path);
175
+ }
176
+ else
177
+ fail('nonregular runtime entry');
178
+ }
179
+ };
180
+ await visit(root);
181
+ if (expected.size)
182
+ fail('deployed asset missing');
183
+ const receipt = await lstat(join(root, 'receipt.json'));
184
+ if (!receipt.isFile() || receipt.nlink !== 1 || (receipt.mode & 0o777) !== 0o600)
185
+ fail('unsafe receipt');
186
+ }
187
+ async function verifyRuntime(runtime, signal) {
188
+ const env = environment(runtime.root);
189
+ const modules = ['source-approval-authority', 'source-release-authority', 'source-adoption-authority',
190
+ 'task-observation-authority', 'live-qualification-authority', 'systemd-host-authority',
191
+ 'runtime-observer-protocol', 'adapter-process'];
192
+ const urls = modules.map(name => pathToFileURL(join(runtime.root, 'lib', `${name}.js`)).href);
193
+ const script = `await Promise.all(${JSON.stringify(urls)}.map(url => import(url)))`;
194
+ await io.command(runtime.node.path, ['--input-type=module', '--eval', script], env, signal, 10_000, 4096);
195
+ for (const [key, spec] of [['hostAttestor', runtime.executables.hostAttestor], ...Object.entries(runtime.releaseAdapters)]) {
196
+ const expected = key === 'hostAttestor' ? 'dsh-systemd-host-attestor-8' : 'dsh-local-release-adapter-1';
197
+ const output = await io.command(runtime.node.path, [spec.path, '--version'], env, signal, 10_000, 4096);
198
+ if (output !== expected)
199
+ fail(`CLI version check failed: ${key}`);
200
+ }
201
+ }
202
+ /** Read a copied runtime receipt through its physical stage path, retaining
203
+ * the logical paths embedded in the original installation. */
204
+ export async function readRsiAuthorityRuntimeReceipt(input) {
205
+ const { logicalHome, physicalHome, profile } = input;
206
+ if (!exactPath(logicalHome) || !exactPath(physicalHome) || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u.test(profile))
207
+ fail('invalid copied runtime binding');
208
+ const root = join(physicalHome, 'rsi-authority-runtimes', profile);
209
+ const source = await io.readStable(join(root, 'receipt.json'), 65_536, true);
210
+ const receipt = JSON.parse(source.toString('utf8'));
211
+ const { digest, ...body } = receipt;
212
+ if (receipt.schemaVersion !== 1 || receipt.root !== join(logicalHome, 'rsi-authority-runtimes', profile)
213
+ || !Array.isArray(receipt.entries) || receipt.entries.length > MAX_ENTRIES
214
+ || !/^[a-f0-9]{64}$/u.test(digest) || hash(JSON.stringify(body)) !== digest)
215
+ fail('copied runtime receipt differs');
216
+ const signal = input.signal ?? new AbortController().signal;
217
+ await verifyTree(root, receipt.entries, signal);
218
+ const { entries: _entries, ...runtime } = body;
219
+ return { runtime, receiptDigest: hash(source) };
220
+ }
221
+ /** Replace only the copied runtime under a stopped Home stage. The receipt and
222
+ * shebangs keep their logical Home paths, so the transaction can rename Home. */
223
+ export async function replaceRsiAuthorityRuntimeInStage(input, options = {}) {
224
+ const previous = await readRsiAuthorityRuntimeReceipt(input);
225
+ const signal = AbortSignal.any([input.signal ?? new AbortController().signal, AbortSignal.timeout(120_000)]);
226
+ const parent = join(input.physicalHome, 'rsi-authority-runtimes');
227
+ await io.directory(parent);
228
+ const final = join(input.logicalHome, 'rsi-authority-runtimes', input.profile);
229
+ if (previous.runtime.root !== final)
230
+ fail('previous runtime root changed');
231
+ const physical = join(parent, input.profile);
232
+ const packageRoot = options.packageRoot ?? dirname(createRequire(import.meta.url).resolve('@dsh-enhanced/plugin-control-plane/package.json'));
233
+ const nodePath = await realpath(options.nodePath ?? process.execPath);
234
+ if (!exactPath(packageRoot) || !exactPath(nodePath))
235
+ fail('source paths must be canonical');
236
+ const files = await sourceAssets(packageRoot, nodePath, signal);
237
+ const logicalSourcePath = (path) => path === input.physicalHome ? input.logicalHome
238
+ : path.startsWith(`${input.physicalHome}${sep}`)
239
+ ? join(input.logicalHome, relative(input.physicalHome, path)) : path;
240
+ const entries = files.map(file => {
241
+ const bytes = deployedBytes(file, final);
242
+ return { path: file.path, sha256: hash(bytes), size: bytes.length,
243
+ mode: file.path === 'node' || file.path.startsWith('bin/') ? 0o700 : 0o600,
244
+ sourcePath: logicalSourcePath(file.sourcePath), sourceSha256: file.sourceSha256,
245
+ sourceSize: file.bytes.length, sourceMode: file.sourceMode };
246
+ }).sort((a, b) => a.path.localeCompare(b.path));
247
+ const runtime = result(final, entries);
248
+ const stage = await mkdtemp(join(parent, `.${input.profile}-update-`));
249
+ const backup = await mkdtemp(join(parent, `.${input.profile}-previous-`));
250
+ await rm(backup, { recursive: true });
251
+ let moved = false;
252
+ try {
253
+ await chmod(stage, 0o700);
254
+ for (const directory of RUNTIME_DIRECTORIES)
255
+ await mkdir(join(stage, directory), { mode: 0o700 });
256
+ for (const file of files) {
257
+ const entry = entries.find(item => item.path === file.path);
258
+ await writeFile(join(stage, file.path), deployedBytes(file, final), entry.mode);
259
+ }
260
+ await verifySources(files, signal);
261
+ const body = { ...runtime, entries };
262
+ await writeFile(join(stage, 'receipt.json'), Buffer.from(JSON.stringify({ ...body, digest: hash(JSON.stringify(body)) })), 0o600);
263
+ await verifyTree(stage, entries, signal);
264
+ for (const directory of [...RUNTIME_DIRECTORIES].reverse())
265
+ await io.syncDirectory(join(stage, directory));
266
+ await io.syncDirectory(stage);
267
+ await rename(physical, backup);
268
+ moved = true;
269
+ try {
270
+ await rename(stage, physical);
271
+ }
272
+ catch (error) {
273
+ await rename(backup, physical);
274
+ moved = false;
275
+ throw error;
276
+ }
277
+ const actual = await readRsiAuthorityRuntimeReceipt(input);
278
+ if (!isDeepStrictEqual(actual.runtime, runtime))
279
+ fail('replacement runtime differs');
280
+ await verifyRuntime({ ...runtime, root: physical, node: { ...runtime.node, path: join(physical, 'node') },
281
+ executables: Object.fromEntries(Object.entries(runtime.executables).map(([key, pin]) => [key, { ...pin, path: join(physical, 'bin', EXECUTABLES[key]) }])),
282
+ releaseAdapters: Object.fromEntries(Object.entries(runtime.releaseAdapters).map(([key, pin]) => [key, { ...pin, path: join(physical, 'bin', `dsh-local-release-${key}.js`) }])) }, signal);
283
+ await rm(backup, { recursive: true });
284
+ return runtime;
285
+ }
286
+ catch (error) {
287
+ if (moved) {
288
+ await rm(physical, { recursive: true, force: true });
289
+ await rename(backup, physical);
290
+ }
291
+ throw error;
292
+ }
293
+ finally {
294
+ await rm(stage, { recursive: true, force: true });
295
+ if (!moved)
296
+ await rm(backup, { recursive: true, force: true });
297
+ }
298
+ }
299
+ /** Caller holds the home lifecycle lock. Only this function's stage/final claim is removed on failure. */
300
+ export async function prepareRsiAuthorityRuntime(input, options = {}) {
301
+ if (!exactPath(input.dshHome) || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u.test(input.profile))
302
+ fail('invalid home or profile');
303
+ if (process.platform !== 'linux')
304
+ fail('Linux is required');
305
+ await io.directory(input.dshHome, false);
306
+ const packageRoot = options.packageRoot ?? dirname(createRequire(import.meta.url).resolve('@dsh-enhanced/plugin-control-plane/package.json'));
307
+ const nodePath = await realpath(options.nodePath ?? process.execPath);
308
+ if (!exactPath(packageRoot) || !exactPath(nodePath))
309
+ fail('source paths must be canonical');
310
+ const parent = join(input.dshHome, 'rsi-authority-runtimes');
311
+ try {
312
+ await mkdir(parent, { mode: 0o700 });
313
+ }
314
+ catch (error) {
315
+ if (error.code !== 'EEXIST')
316
+ throw error;
317
+ }
318
+ await io.directory(parent);
319
+ const final = join(parent, input.profile);
320
+ const signal = AbortSignal.any([input.signal ?? new AbortController().signal, AbortSignal.timeout(120_000)]);
321
+ const files = await sourceAssets(packageRoot, nodePath, signal);
322
+ const entries = files.map(file => {
323
+ const bytes = deployedBytes(file, final);
324
+ return { path: file.path, sha256: hash(bytes), size: bytes.length,
325
+ mode: file.path === 'node' || file.path.startsWith('bin/') ? 0o700 : 0o600,
326
+ sourcePath: file.sourcePath, sourceSha256: file.sourceSha256, sourceSize: file.bytes.length, sourceMode: file.sourceMode };
327
+ }).sort((a, b) => a.path.localeCompare(b.path));
328
+ const runtime = result(final, entries);
329
+ try {
330
+ await lstat(final);
331
+ const receipt = JSON.parse((await io.readStable(join(final, 'receipt.json'), 65_536, true)).toString('utf8'));
332
+ const { digest, ...body } = receipt;
333
+ if (hash(JSON.stringify(body)) !== digest || !isDeepStrictEqual(body, { ...runtime, entries }))
334
+ fail('runtime differs from receipt');
335
+ await verifyTree(final, entries, signal);
336
+ await verifySources(files, signal);
337
+ await verifyRuntime(runtime, signal);
338
+ return runtime;
339
+ }
340
+ catch (error) {
341
+ if (error.code !== 'ENOENT')
342
+ throw error;
343
+ try {
344
+ await lstat(final);
345
+ fail('existing runtime is incomplete');
346
+ }
347
+ catch (found) {
348
+ if (found.code !== 'ENOENT')
349
+ throw found;
350
+ }
351
+ }
352
+ const stage = await mkdtemp(join(parent, `.${input.profile}-stage-`));
353
+ let claimed;
354
+ try {
355
+ await chmod(stage, 0o700);
356
+ for (const directory of RUNTIME_DIRECTORIES)
357
+ await mkdir(join(stage, directory), { mode: 0o700 });
358
+ for (const file of files) {
359
+ signal.throwIfAborted();
360
+ const entry = entries.find(item => item.path === file.path);
361
+ await writeFile(join(stage, file.path), deployedBytes(file, final), entry.mode);
362
+ }
363
+ await verifySources(files, signal);
364
+ const body = { ...runtime, entries };
365
+ await writeFile(join(stage, 'receipt.json'), Buffer.from(JSON.stringify({ ...body, digest: hash(JSON.stringify(body)) })), 0o600);
366
+ for (const directory of [...RUNTIME_DIRECTORIES].reverse())
367
+ await io.syncDirectory(join(stage, directory));
368
+ await io.syncDirectory(stage);
369
+ signal.throwIfAborted();
370
+ await mkdir(final, { mode: 0o700 });
371
+ const identity = await lstat(final);
372
+ claimed = { dev: identity.dev, ino: identity.ino };
373
+ for (const name of ['bin', 'lib', 'node_modules', 'node', 'package.json', 'receipt.json'])
374
+ await rename(join(stage, name), join(final, name));
375
+ await verifyTree(final, entries, signal);
376
+ await verifyRuntime(runtime, signal);
377
+ await io.syncDirectory(parent);
378
+ return runtime;
379
+ }
380
+ catch (error) {
381
+ if (claimed) {
382
+ const current = await lstat(final).catch(() => undefined);
383
+ if (current?.isDirectory() && current.dev === claimed.dev && current.ino === claimed.ino)
384
+ await rm(final, { recursive: true, force: true });
385
+ }
386
+ throw error;
387
+ }
388
+ finally {
389
+ await rm(stage, { recursive: true, force: true });
390
+ await io.syncDirectory(parent);
391
+ }
392
+ }
393
+ //# sourceMappingURL=rsi-authority-runtime.js.map