agl 1.0.17 → 21.0.2

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 (277) hide show
  1. package/.smartconfig.json +55 -0
  2. package/changelog.md +1026 -0
  3. package/cli.js +14 -0
  4. package/dist_serve/bundle.js +44778 -0
  5. package/dist_serve/index.html +13 -0
  6. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  7. package/dist_ts/00_commitinfo_data.js +9 -0
  8. package/dist_ts/classes.authmodels.d.ts +126 -0
  9. package/dist_ts/classes.authmodels.js +1422 -0
  10. package/dist_ts/classes.authstore.d.ts +160 -0
  11. package/dist_ts/classes.authstore.js +2483 -0
  12. package/dist_ts/classes.browserresourcehost.d.ts +85 -0
  13. package/dist_ts/classes.browserresourcehost.js +912 -0
  14. package/dist_ts/classes.cli.d.ts +21 -0
  15. package/dist_ts/classes.cli.js +1082 -0
  16. package/dist_ts/classes.config.d.ts +23 -0
  17. package/dist_ts/classes.config.js +267 -0
  18. package/dist_ts/classes.controller.d.ts +523 -0
  19. package/dist_ts/classes.controller.js +10611 -0
  20. package/dist_ts/classes.controllermanagement.d.ts +32 -0
  21. package/dist_ts/classes.controllermanagement.js +222 -0
  22. package/dist_ts/classes.draftmanager.d.ts +30 -0
  23. package/dist_ts/classes.draftmanager.js +179 -0
  24. package/dist_ts/classes.embeddeddb.d.ts +30 -0
  25. package/dist_ts/classes.embeddeddb.js +159 -0
  26. package/dist_ts/classes.flexframedtransport.d.ts +56 -0
  27. package/dist_ts/classes.flexframedtransport.js +275 -0
  28. package/dist_ts/classes.flexmodels.private.d.ts +231 -0
  29. package/dist_ts/classes.flexmodels.private.js +985 -0
  30. package/dist_ts/classes.flexmodels.public.d.ts +207 -0
  31. package/dist_ts/classes.flexmodels.public.js +885 -0
  32. package/dist_ts/classes.flexprojectionreader.d.ts +89 -0
  33. package/dist_ts/classes.flexprojectionreader.js +580 -0
  34. package/dist_ts/classes.flexservice.d.ts +196 -0
  35. package/dist_ts/classes.flexservice.js +3704 -0
  36. package/dist_ts/classes.flexstore.d.ts +174 -0
  37. package/dist_ts/classes.flexstore.js +3400 -0
  38. package/dist_ts/classes.flexsupervisor.d.ts +105 -0
  39. package/dist_ts/classes.flexsupervisor.js +1191 -0
  40. package/dist_ts/classes.gitreversion.d.ts +431 -0
  41. package/dist_ts/classes.gitreversion.js +10592 -0
  42. package/dist_ts/classes.harnessoperationmanager.d.ts +113 -0
  43. package/dist_ts/classes.harnessoperationmanager.js +602 -0
  44. package/dist_ts/classes.opencodeclient.d.ts +146 -0
  45. package/dist_ts/classes.opencodeclient.js +3003 -0
  46. package/dist_ts/classes.opencodesupervisor.d.ts +60 -0
  47. package/dist_ts/classes.opencodesupervisor.js +1003 -0
  48. package/dist_ts/classes.passkeymanager.d.ts +34 -0
  49. package/dist_ts/classes.passkeymanager.js +456 -0
  50. package/dist_ts/classes.processinspection.d.ts +50 -0
  51. package/dist_ts/classes.processinspection.js +484 -0
  52. package/dist_ts/classes.resourcecoordinator.d.ts +64 -0
  53. package/dist_ts/classes.resourcecoordinator.js +294 -0
  54. package/dist_ts/classes.sessionintelligencereader.d.ts +13 -0
  55. package/dist_ts/classes.sessionintelligencereader.js +40 -0
  56. package/dist_ts/classes.systemmetricssampler.d.ts +53 -0
  57. package/dist_ts/classes.systemmetricssampler.js +168 -0
  58. package/dist_ts/classes.terminalmanager.d.ts +95 -0
  59. package/dist_ts/classes.terminalmanager.js +981 -0
  60. package/dist_ts/classes.terminalresourcehost.d.ts +20 -0
  61. package/dist_ts/classes.terminalresourcehost.js +84 -0
  62. package/dist_ts/classes.upgradecoordinator.d.ts +244 -0
  63. package/dist_ts/classes.upgradecoordinator.js +2155 -0
  64. package/dist_ts/classes.upgradetransaction.d.ts +92 -0
  65. package/dist_ts/classes.upgradetransaction.js +2125 -0
  66. package/dist_ts/classes.uploadmanager.d.ts +24 -0
  67. package/dist_ts/classes.uploadmanager.js +210 -0
  68. package/dist_ts/classes.validation.d.ts +91 -0
  69. package/dist_ts/classes.validation.js +1087 -0
  70. package/dist_ts/flexharness.child.d.ts +1 -0
  71. package/dist_ts/flexharness.child.js +28 -0
  72. package/dist_ts/functions.canonicaldirectory.d.ts +21 -0
  73. package/dist_ts/functions.canonicaldirectory.js +144 -0
  74. package/dist_ts/functions.controllerdataroot.d.ts +15 -0
  75. package/dist_ts/functions.controllerdataroot.js +76 -0
  76. package/dist_ts/functions.embeddeddb.d.ts +2 -0
  77. package/dist_ts/functions.embeddeddb.js +21 -0
  78. package/dist_ts/functions.flexcredentialstore.d.ts +16 -0
  79. package/dist_ts/functions.flexcredentialstore.js +93 -0
  80. package/dist_ts/functions.opencodeauth.d.ts +3 -0
  81. package/dist_ts/functions.opencodeauth.js +31 -0
  82. package/dist_ts/functions.runtimeenvironment.d.ts +2 -0
  83. package/dist_ts/functions.runtimeenvironment.js +79 -0
  84. package/dist_ts/functions.upgradefollower.d.ts +3 -0
  85. package/dist_ts/functions.upgradefollower.js +95 -0
  86. package/dist_ts/index.d.ts +24 -0
  87. package/dist_ts/index.js +25 -0
  88. package/dist_ts/interfaces.auth.d.ts +181 -0
  89. package/dist_ts/interfaces.auth.js +82 -0
  90. package/dist_ts/interfaces.config.d.ts +34 -0
  91. package/dist_ts/interfaces.config.js +2 -0
  92. package/dist_ts/interfaces.flexipc.d.ts +939 -0
  93. package/dist_ts/interfaces.flexipc.js +1492 -0
  94. package/dist_ts/interfaces.gitreversion.d.ts +246 -0
  95. package/dist_ts/interfaces.gitreversion.js +2 -0
  96. package/dist_ts/interfaces.lifecycle.d.ts +37 -0
  97. package/dist_ts/interfaces.lifecycle.js +2 -0
  98. package/dist_ts/interfaces.opencode.d.ts +101 -0
  99. package/dist_ts/interfaces.opencode.js +3 -0
  100. package/dist_ts/interfaces.projects.d.ts +156 -0
  101. package/dist_ts/interfaces.projects.js +5 -0
  102. package/dist_ts/plugins.d.ts +36 -0
  103. package/dist_ts/plugins.js +40 -0
  104. package/dist_ts_interfaces/index.d.ts +2 -0
  105. package/dist_ts_interfaces/index.js +3 -0
  106. package/dist_ts_interfaces/interfaces.d.ts +747 -0
  107. package/dist_ts_interfaces/interfaces.js +47 -0
  108. package/dist_ts_interfaces/plugins.d.ts +4 -0
  109. package/dist_ts_interfaces/plugins.js +3 -0
  110. package/dist_ts_interfaces/requests.d.ts +806 -0
  111. package/dist_ts_interfaces/requests.js +2 -0
  112. package/dist_ts_migration/classes.documentmigrationrunner.d.ts +8 -0
  113. package/dist_ts_migration/classes.documentmigrationrunner.js +24 -0
  114. package/dist_ts_migration/classes.flexmigrationrunner.d.ts +11 -0
  115. package/dist_ts_migration/classes.flexmigrationrunner.js +25 -0
  116. package/dist_ts_migration/classes.flexpostharnessmigrationrunner.d.ts +10 -0
  117. package/dist_ts_migration/classes.flexpostharnessmigrationrunner.js +15 -0
  118. package/dist_ts_migration/classes.migrationrunner.d.ts +8 -0
  119. package/dist_ts_migration/classes.migrationrunner.js +34 -0
  120. package/dist_ts_migration/index.d.ts +12 -0
  121. package/dist_ts_migration/index.js +13 -0
  122. package/dist_ts_migration/v10_flexharnessv3migration.d.ts +11 -0
  123. package/dist_ts_migration/v10_flexharnessv3migration.js +23 -0
  124. package/dist_ts_migration/v13_flexprojectionorder.d.ts +11 -0
  125. package/dist_ts_migration/v13_flexprojectionorder.js +23 -0
  126. package/dist_ts_migration/v16_flexprovidercredentials.d.ts +22 -0
  127. package/dist_ts_migration/v16_flexprovidercredentials.js +149 -0
  128. package/dist_ts_migration/v18_resourcelayout.d.ts +22 -0
  129. package/dist_ts_migration/v18_resourcelayout.js +23 -0
  130. package/dist_ts_migration/v18_resourcelayoutmigration.d.ts +6 -0
  131. package/dist_ts_migration/v18_resourcelayoutmigration.js +61 -0
  132. package/dist_ts_migration/v19_flexprojectmanagement.d.ts +11 -0
  133. package/dist_ts_migration/v19_flexprojectmanagement.js +21 -0
  134. package/dist_ts_migration/v1_embeddeddatabaselocation.d.ts +28 -0
  135. package/dist_ts_migration/v1_embeddeddatabaselocation.js +415 -0
  136. package/dist_ts_migration/v22_projectfilesystemidentitymigration.d.ts +7 -0
  137. package/dist_ts_migration/v22_projectfilesystemidentitymigration.js +105 -0
  138. package/dist_ts_migration/v2_controllerdataroot.d.ts +130 -0
  139. package/dist_ts_migration/v2_controllerdataroot.js +1887 -0
  140. package/dist_ts_migration/v6_protocoldocumentmigration.d.ts +7 -0
  141. package/dist_ts_migration/v6_protocoldocumentmigration.js +100 -0
  142. package/dist_ts_migration/v6_protocoldocuments.d.ts +7 -0
  143. package/dist_ts_migration/v6_protocoldocuments.js +138 -0
  144. package/html/index.html +13 -0
  145. package/{LICENSE → license.md} +2 -2
  146. package/package.json +86 -48
  147. package/readme.md +480 -0
  148. package/readme.plan.md +188 -0
  149. package/ts/00_commitinfo_data.ts +8 -0
  150. package/ts/classes.authmodels.ts +1245 -0
  151. package/ts/classes.authstore.ts +3274 -0
  152. package/ts/classes.browserresourcehost.ts +1205 -0
  153. package/ts/classes.cli.ts +1254 -0
  154. package/ts/classes.config.ts +351 -0
  155. package/ts/classes.controller.ts +14426 -0
  156. package/ts/classes.controllermanagement.ts +330 -0
  157. package/ts/classes.draftmanager.ts +232 -0
  158. package/ts/classes.embeddeddb.ts +166 -0
  159. package/ts/classes.flexframedtransport.ts +283 -0
  160. package/ts/classes.flexmodels.private.ts +823 -0
  161. package/ts/classes.flexmodels.public.ts +732 -0
  162. package/ts/classes.flexprojectionreader.ts +816 -0
  163. package/ts/classes.flexservice.ts +4302 -0
  164. package/ts/classes.flexstore.ts +4565 -0
  165. package/ts/classes.flexsupervisor.ts +1453 -0
  166. package/ts/classes.gitreversion.ts +13353 -0
  167. package/ts/classes.harnessoperationmanager.ts +870 -0
  168. package/ts/classes.opencodeclient.ts +4110 -0
  169. package/ts/classes.opencodesupervisor.ts +1280 -0
  170. package/ts/classes.passkeymanager.ts +570 -0
  171. package/ts/classes.processinspection.ts +623 -0
  172. package/ts/classes.resourcecoordinator.ts +436 -0
  173. package/ts/classes.sessionintelligencereader.ts +52 -0
  174. package/ts/classes.systemmetricssampler.ts +215 -0
  175. package/ts/classes.terminalmanager.ts +1207 -0
  176. package/ts/classes.terminalresourcehost.ts +122 -0
  177. package/ts/classes.upgradecoordinator.ts +2675 -0
  178. package/ts/classes.upgradetransaction.ts +2900 -0
  179. package/ts/classes.uploadmanager.ts +240 -0
  180. package/ts/classes.validation.ts +1409 -0
  181. package/ts/flexharness.child.ts +35 -0
  182. package/ts/functions.canonicaldirectory.ts +213 -0
  183. package/ts/functions.controllerdataroot.ts +107 -0
  184. package/ts/functions.embeddeddb.ts +22 -0
  185. package/ts/functions.flexcredentialstore.ts +128 -0
  186. package/ts/functions.opencodeauth.ts +34 -0
  187. package/ts/functions.runtimeenvironment.ts +90 -0
  188. package/ts/functions.upgradefollower.ts +115 -0
  189. package/ts/index.ts +36 -6
  190. package/ts/interfaces.auth.ts +316 -0
  191. package/ts/interfaces.config.ts +37 -0
  192. package/ts/interfaces.flexipc.ts +2586 -0
  193. package/ts/interfaces.gitreversion.ts +336 -0
  194. package/ts/interfaces.lifecycle.ts +46 -0
  195. package/ts/interfaces.opencode.ts +153 -0
  196. package/ts/interfaces.projects.ts +182 -0
  197. package/ts/plugins.ts +64 -0
  198. package/ts_interfaces/index.ts +2 -0
  199. package/ts_interfaces/interfaces.ts +827 -0
  200. package/ts_interfaces/plugins.ts +15 -0
  201. package/ts_interfaces/requests.ts +1186 -0
  202. package/ts_migration/classes.documentmigrationrunner.ts +32 -0
  203. package/ts_migration/classes.flexmigrationrunner.ts +33 -0
  204. package/ts_migration/classes.flexpostharnessmigrationrunner.ts +22 -0
  205. package/ts_migration/classes.migrationrunner.ts +40 -0
  206. package/ts_migration/index.ts +12 -0
  207. package/ts_migration/v10_flexharnessv3migration.ts +35 -0
  208. package/ts_migration/v13_flexprojectionorder.ts +33 -0
  209. package/ts_migration/v16_flexprovidercredentials.ts +196 -0
  210. package/ts_migration/v18_resourcelayout.ts +55 -0
  211. package/ts_migration/v18_resourcelayoutmigration.ts +68 -0
  212. package/ts_migration/v19_flexprojectmanagement.ts +28 -0
  213. package/ts_migration/v1_embeddeddatabaselocation.ts +560 -0
  214. package/ts_migration/v22_projectfilesystemidentitymigration.ts +121 -0
  215. package/ts_migration/v2_controllerdataroot.ts +2349 -0
  216. package/ts_migration/v6_protocoldocumentmigration.ts +144 -0
  217. package/ts_migration/v6_protocoldocuments.ts +198 -0
  218. package/ts_web/00_commitinfo_data.ts +8 -0
  219. package/ts_web/classes.controllersocketclient.ts +517 -0
  220. package/ts_web/classes.sessiondraftsync.ts +390 -0
  221. package/ts_web/elements.harnesscontrollerapp.ts +11494 -0
  222. package/ts_web/index.ts +2 -0
  223. package/ts_web/plugins.ts +31 -0
  224. package/.gitlab-ci.yml +0 -71
  225. package/.npmignore +0 -5
  226. package/README.md +0 -40
  227. package/dist/cli.js +0 -2
  228. package/dist/index.d.ts +0 -0
  229. package/dist/index.js +0 -9
  230. package/dist/mod_bundle/index.d.ts +0 -1
  231. package/dist/mod_bundle/index.js +0 -18
  232. package/dist/mod_bundle/mod.plugins.d.ts +0 -4
  233. package/dist/mod_bundle/mod.plugins.js +0 -11
  234. package/dist/mod_install/index.d.ts +0 -4
  235. package/dist/mod_install/index.js +0 -21
  236. package/dist/mod_install/mod.plugins.d.ts +0 -1
  237. package/dist/mod_install/mod.plugins.js +0 -7
  238. package/dist/mod_standard/index.d.ts +0 -4
  239. package/dist/mod_standard/index.js +0 -21
  240. package/dist/mod_standard/mod.browser.d.ts +0 -6
  241. package/dist/mod_standard/mod.browser.js +0 -14
  242. package/dist/mod_standard/mod.clean.d.ts +0 -4
  243. package/dist/mod_standard/mod.clean.js +0 -12
  244. package/dist/mod_standard/mod.compile.d.ts +0 -4
  245. package/dist/mod_standard/mod.compile.js +0 -21
  246. package/dist/mod_standard/mod.plugins.d.ts +0 -8
  247. package/dist/mod_standard/mod.plugins.js +0 -19
  248. package/dist/mod_standard/mod.test.d.ts +0 -4
  249. package/dist/mod_standard/mod.test.js +0 -12
  250. package/dist/plr.cli.d.ts +0 -3
  251. package/dist/plr.cli.js +0 -57
  252. package/dist/plr.config.d.ts +0 -11
  253. package/dist/plr.config.js +0 -26
  254. package/dist/plr.mods.d.ts +0 -17
  255. package/dist/plr.mods.js +0 -17
  256. package/dist/plr.paths.d.ts +0 -19
  257. package/dist/plr.paths.js +0 -26
  258. package/dist/plr.plugins.d.ts +0 -8
  259. package/dist/plr.plugins.js +0 -16
  260. package/npmextra.json +0 -10
  261. package/ts/mod_bundle/index.ts +0 -20
  262. package/ts/mod_bundle/mod.plugins.ts +0 -9
  263. package/ts/mod_install/index.ts +0 -20
  264. package/ts/mod_install/mod.plugins.ts +0 -1
  265. package/ts/mod_standard/index.ts +0 -23
  266. package/ts/mod_standard/mod.browser.ts +0 -17
  267. package/ts/mod_standard/mod.clean.ts +0 -13
  268. package/ts/mod_standard/mod.compile.ts +0 -23
  269. package/ts/mod_standard/mod.plugins.ts +0 -17
  270. package/ts/mod_standard/mod.test.ts +0 -13
  271. package/ts/plr.cli.ts +0 -60
  272. package/ts/plr.config.ts +0 -36
  273. package/ts/plr.mods.ts +0 -25
  274. package/ts/plr.paths.ts +0 -29
  275. package/ts/plr.plugins.ts +0 -17
  276. package/tslint.json +0 -3
  277. package/yarn.lock +0 -3464
@@ -0,0 +1,240 @@
1
+ import * as plugins from './plugins.js';
2
+ import {
3
+ controllerMaxAttachmentPromptSuffixBytes,
4
+ controllerMaxDraftAttachmentBytes,
5
+ controllerMaxDraftAttachmentTotalBytes,
6
+ controllerMaxDraftAttachments,
7
+ type IControllerDraftAttachment,
8
+ } from '../ts_interfaces/interfaces.js';
9
+
10
+ const maximumActiveUploads = 64;
11
+ const maximumActiveUploadBytes = 64 * 1024 * 1024;
12
+
13
+ export interface IControllerUploadHandle {
14
+ id: string;
15
+ directory: string;
16
+ paths: string[];
17
+ promptSuffix: string;
18
+ bytes: number;
19
+ cleanup(): Promise<void>;
20
+ }
21
+
22
+ interface IActiveUpload {
23
+ handle: IControllerUploadHandle;
24
+ cleanupPromise?: Promise<void>;
25
+ }
26
+
27
+ export class ControllerUploadManager {
28
+ private rootPromise?: Promise<string>;
29
+ private readonly activeUploads = new Map<string, IActiveUpload>();
30
+ private readonly pendingCreates = new Set<Promise<IControllerUploadHandle>>();
31
+ private activeUploadCount = 0;
32
+ private activeBytes = 0;
33
+ private closed = false;
34
+ private closePromise?: Promise<void>;
35
+
36
+ public create(
37
+ attachmentsArg: readonly IControllerDraftAttachment[],
38
+ ): Promise<IControllerUploadHandle | undefined> {
39
+ if (attachmentsArg.length === 0) return Promise.resolve(undefined);
40
+ if (this.closed) throw new Error('The controller upload manager is closed.');
41
+ if (attachmentsArg.length > controllerMaxDraftAttachments) {
42
+ throw new Error('The attachment count exceeds the controller limit.');
43
+ }
44
+ if (this.activeUploadCount >= maximumActiveUploads) {
45
+ throw new Error('The controller has too many active uploads.');
46
+ }
47
+
48
+ const decoded = attachmentsArg.map((attachment, index) => {
49
+ if (
50
+ attachment.name.length === 0
51
+ || attachment.name !== plugins.path.basename(attachment.name)
52
+ || Buffer.byteLength(attachment.name, 'utf8') > 255
53
+ // eslint-disable-next-line no-control-regex
54
+ || /[\x00-\x1f\x7f/\\]/.test(attachment.name)
55
+ ) {
56
+ throw new Error(`Attachment ${index + 1} has an unsafe file name.`);
57
+ }
58
+ if (
59
+ attachment.mediaType.length === 0
60
+ || Buffer.byteLength(attachment.mediaType, 'utf8') > 129
61
+ // eslint-disable-next-line no-control-regex
62
+ || /[\x00-\x20\x7f]/.test(attachment.mediaType)
63
+ ) throw new Error(`Attachment ${index + 1} has an unsafe media type.`);
64
+ const data = Buffer.from(attachment.dataBase64, 'base64');
65
+ if (data.toString('base64') !== attachment.dataBase64) {
66
+ throw new Error(`Attachment ${index + 1} is not canonical base64.`);
67
+ }
68
+ if (data.byteLength !== attachment.size) {
69
+ throw new Error(`Attachment ${index + 1} size does not match its content.`);
70
+ }
71
+ if (data.byteLength > controllerMaxDraftAttachmentBytes) {
72
+ throw new Error(`Attachment ${index + 1} exceeds the controller byte limit.`);
73
+ }
74
+ return { attachment, data };
75
+ });
76
+ const bytes = decoded.reduce((sum, entry) => sum + entry.data.byteLength, 0);
77
+ if (bytes > controllerMaxDraftAttachmentTotalBytes) {
78
+ throw new Error('The attachments exceed the controller total byte limit.');
79
+ }
80
+ if (this.activeBytes + bytes > maximumActiveUploadBytes) {
81
+ throw new Error('The controller active upload byte limit is exhausted.');
82
+ }
83
+
84
+ this.activeUploadCount += 1;
85
+ this.activeBytes += bytes;
86
+ const createPromise = this.createReserved(decoded, bytes);
87
+ this.pendingCreates.add(createPromise);
88
+ void createPromise.finally(() => this.pendingCreates.delete(createPromise)).catch(() => undefined);
89
+ return createPromise;
90
+ }
91
+
92
+ public async close(): Promise<void> {
93
+ if (this.closePromise) return this.closePromise;
94
+ this.closed = true;
95
+ const closePromise = this.closeInternal();
96
+ this.closePromise = closePromise;
97
+ try {
98
+ await closePromise;
99
+ } catch (errorArg) {
100
+ if (this.closePromise === closePromise) this.closePromise = undefined;
101
+ throw errorArg;
102
+ }
103
+ }
104
+
105
+ private async createReserved(
106
+ decodedArg: Array<{
107
+ attachment: IControllerDraftAttachment;
108
+ data: Buffer;
109
+ }>,
110
+ bytesArg: number,
111
+ ): Promise<IControllerUploadHandle> {
112
+ const id = plugins.crypto.randomBytes(16).toString('base64url');
113
+ let directory: string | undefined;
114
+ let admitted = false;
115
+ try {
116
+ const root = await this.ensureRoot();
117
+ directory = await plugins.fs.promises.mkdtemp(plugins.path.join(root, 'message-'));
118
+ await plugins.fs.promises.chmod(directory, 0o700);
119
+ const paths: string[] = [];
120
+ for (const [index, entry] of decodedArg.entries()) {
121
+ const filePath = plugins.path.join(directory, `${index + 1}-${entry.attachment.name}`);
122
+ const relative = plugins.path.relative(directory, filePath);
123
+ if (
124
+ relative === '..'
125
+ || relative.startsWith(`..${plugins.path.sep}`)
126
+ || plugins.path.isAbsolute(relative)
127
+ ) throw new Error('An attachment path escaped its upload directory.');
128
+ const flags = plugins.fs.constants.O_WRONLY
129
+ | plugins.fs.constants.O_CREAT
130
+ | plugins.fs.constants.O_EXCL
131
+ | (plugins.fs.constants.O_NOFOLLOW ?? 0);
132
+ const file = await plugins.fs.promises.open(filePath, flags, 0o600);
133
+ try {
134
+ await file.writeFile(entry.data);
135
+ } finally {
136
+ await file.close();
137
+ }
138
+ paths.push(filePath);
139
+ }
140
+ const promptSuffix = `\n\n[Attached files - stored on disk; read them with filesystem tools]\n${decodedArg
141
+ .map((entry, index) => `- ${paths[index]} (${entry.attachment.mediaType}, ${entry.data.byteLength} bytes)`)
142
+ .join('\n')}`;
143
+ if (Buffer.byteLength(promptSuffix, 'utf8') > controllerMaxAttachmentPromptSuffixBytes) {
144
+ throw new Error('The generated attachment prompt suffix exceeds its byte limit.');
145
+ }
146
+ const handle: IControllerUploadHandle = {
147
+ id,
148
+ directory,
149
+ paths,
150
+ promptSuffix,
151
+ bytes: bytesArg,
152
+ cleanup: () => this.cleanup(id),
153
+ };
154
+ this.activeUploads.set(id, { handle });
155
+ admitted = true;
156
+ return handle;
157
+ } finally {
158
+ if (!admitted) {
159
+ if (directory) {
160
+ await plugins.fs.promises.rm(directory, { recursive: true, force: true }).catch(() => undefined);
161
+ }
162
+ this.activeUploadCount -= 1;
163
+ this.activeBytes -= bytesArg;
164
+ }
165
+ }
166
+ }
167
+
168
+ private async closeInternal(): Promise<void> {
169
+ await Promise.allSettled([...this.pendingCreates]);
170
+ const results = await Promise.allSettled(
171
+ [...this.activeUploads.values()].map((entry) => entry.handle.cleanup()),
172
+ );
173
+ const errors = results
174
+ .filter((result): result is PromiseRejectedResult => result.status === 'rejected')
175
+ .map((result) => result.reason);
176
+ if (this.rootPromise) {
177
+ try {
178
+ const root = await this.rootPromise;
179
+ await plugins.fs.promises.rm(root, { recursive: true, force: true });
180
+ this.activeUploads.clear();
181
+ this.activeUploadCount = 0;
182
+ this.activeBytes = 0;
183
+ errors.length = 0;
184
+ } catch (errorArg) {
185
+ errors.push(errorArg);
186
+ }
187
+ }
188
+ if (errors.length > 0) throw new AggregateError(errors, 'Controller upload cleanup failed.');
189
+ }
190
+
191
+ private async ensureRoot(): Promise<string> {
192
+ if (!this.rootPromise) {
193
+ this.rootPromise = (async () => {
194
+ let root: string | undefined;
195
+ try {
196
+ root = await plugins.fs.promises.mkdtemp(
197
+ plugins.path.join(plugins.os.tmpdir(), 'harness-controller-uploads-'),
198
+ );
199
+ await plugins.fs.promises.chmod(root, 0o700);
200
+ return await plugins.fs.promises.realpath(root);
201
+ } catch (errorArg) {
202
+ if (root) {
203
+ await plugins.fs.promises.rm(root, { recursive: true, force: true })
204
+ .catch(() => undefined);
205
+ }
206
+ throw errorArg;
207
+ }
208
+ })();
209
+ }
210
+ const rootPromise = this.rootPromise;
211
+ try {
212
+ return await rootPromise;
213
+ } catch (errorArg) {
214
+ if (this.rootPromise === rootPromise) this.rootPromise = undefined;
215
+ throw errorArg;
216
+ }
217
+ }
218
+
219
+ private async cleanup(idArg: string): Promise<void> {
220
+ const active = this.activeUploads.get(idArg);
221
+ if (!active) return;
222
+ if (active.cleanupPromise) return active.cleanupPromise;
223
+ const cleanupPromise = (async () => {
224
+ await plugins.fs.promises.rm(active.handle.directory, { recursive: true, force: true });
225
+ if (this.activeUploads.get(idArg) === active) {
226
+ this.activeUploads.delete(idArg);
227
+ this.activeUploadCount -= 1;
228
+ this.activeBytes -= active.handle.bytes;
229
+ }
230
+ })();
231
+ active.cleanupPromise = cleanupPromise;
232
+ try {
233
+ await cleanupPromise;
234
+ } finally {
235
+ if (this.activeUploads.get(idArg) === active && active.cleanupPromise === cleanupPromise) {
236
+ active.cleanupPromise = undefined;
237
+ }
238
+ }
239
+ }
240
+ }