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,351 @@
1
+ import * as plugins from './plugins.js';
2
+ import type {
3
+ IControllerDatabaseConfig,
4
+ IControllerRuntimeConfig,
5
+ IControllerRuntimeOverrides,
6
+ TControllerTlsMode,
7
+ } from './interfaces.config.js';
8
+
9
+ export const defaultControllerPort = 4097;
10
+ export const defaultOpenCodePort = 4098;
11
+ export const trustedProxySecretEnvironmentVariable = 'HARNESS_CONTROLLER_TRUSTED_PROXY_SECRET';
12
+
13
+ export interface IControllerDataDirectoryOptions {
14
+ packageRoot?: string;
15
+ homeDirectory?: string;
16
+ environment?: NodeJS.ProcessEnv;
17
+ }
18
+
19
+ export interface IControllerDataRootPaths {
20
+ legacyRoot: string;
21
+ targetRoot: string;
22
+ migrationRequired: boolean;
23
+ }
24
+
25
+ const modulePackageRoot = plugins.path.resolve(
26
+ plugins.path.dirname(plugins.url.fileURLToPath(import.meta.url)),
27
+ '..',
28
+ );
29
+
30
+ const assertPort = (valueArg: number, nameArg: string): number => {
31
+ if (!Number.isSafeInteger(valueArg) || valueArg < 1 || valueArg > 65535) {
32
+ throw new Error(`${nameArg} must be an integer between 1 and 65535.`);
33
+ }
34
+ return valueArg;
35
+ };
36
+
37
+ const effectivePort = (originArg: URL): number => {
38
+ if (originArg.port) return Number(originArg.port);
39
+ return originArg.protocol === 'https:' ? 443 : 80;
40
+ };
41
+
42
+ const normalizeOrigin = (originArg: string): URL => {
43
+ let origin: URL;
44
+ try {
45
+ origin = new URL(originArg);
46
+ } catch {
47
+ throw new Error('publicOrigin must be an absolute HTTP or HTTPS origin.');
48
+ }
49
+ if (
50
+ (origin.protocol !== 'http:' && origin.protocol !== 'https:')
51
+ || origin.username
52
+ || origin.password
53
+ || origin.pathname !== '/'
54
+ || origin.search
55
+ || origin.hash
56
+ ) {
57
+ throw new Error('publicOrigin must contain only an HTTP(S) scheme, hostname, and optional port.');
58
+ }
59
+ return origin;
60
+ };
61
+
62
+ const normalizeRpId = (rpIdArg: string, hostnameArg: string): string => {
63
+ const rpId = plugins.url.domainToASCII(
64
+ rpIdArg.trim().toLowerCase().replace(/\.$/, ''),
65
+ );
66
+ if (!rpId || rpId.includes('/') || rpId.includes(':') || /\s/.test(rpId)) {
67
+ throw new Error('rpId must be a valid hostname without a scheme, port, or path.');
68
+ }
69
+ const hostname = hostnameArg.toLowerCase().replace(/\.$/, '');
70
+ if (hostname !== rpId && !hostname.endsWith(`.${rpId}`)) {
71
+ throw new Error('rpId must equal the public-origin hostname or be its registrable parent domain.');
72
+ }
73
+ if (rpId === 'localhost' && hostname === 'localhost') return rpId;
74
+ const parsed = plugins.tldts.parse(rpId, {
75
+ allowPrivateDomains: true,
76
+ extractHostname: false,
77
+ validateHostname: true,
78
+ });
79
+ if (parsed.isIp || parsed.domain === null || parsed.publicSuffix === rpId) {
80
+ throw new Error('rpId must not be an IP address, single-label name, or public suffix.');
81
+ }
82
+ return rpId;
83
+ };
84
+
85
+ const resolveTlsMode = (
86
+ originArg: URL,
87
+ behindTlsProxyArg: boolean,
88
+ ): TControllerTlsMode => {
89
+ if (originArg.protocol === 'http:') {
90
+ if (originArg.hostname !== 'localhost') {
91
+ throw new Error('Plain HTTP is accepted only for the localhost WebAuthn development origin.');
92
+ }
93
+ if (behindTlsProxyArg) {
94
+ throw new Error('The localhost HTTP mode cannot also enable proxy termination.');
95
+ }
96
+ return 'local';
97
+ }
98
+ if (behindTlsProxyArg) return 'proxy';
99
+ throw new Error(
100
+ 'An HTTPS public origin requires --behind-tls-proxy and a trusted TLS reverse proxy.',
101
+ );
102
+ };
103
+
104
+ const resolveDirectory = async (directoryArg: string): Promise<string> => {
105
+ const resolved = await plugins.fs.promises.realpath(plugins.path.resolve(directoryArg));
106
+ const stats = await plugins.fs.promises.stat(resolved);
107
+ if (!stats.isDirectory()) {
108
+ throw new Error(`OpenCode workspace is not a directory: ${resolved}`);
109
+ }
110
+ return resolved;
111
+ };
112
+
113
+ const isDevelopmentCheckout = (packageRootArg: string): boolean => {
114
+ try {
115
+ const stats = plugins.fs.lstatSync(plugins.path.join(packageRootArg, '.git'));
116
+ return stats.isDirectory() || stats.isFile();
117
+ } catch {
118
+ return false;
119
+ }
120
+ };
121
+
122
+ const xdgRoot = (
123
+ environmentValueArg: string | undefined,
124
+ fallbackArg: string,
125
+ ): string => {
126
+ const candidate = environmentValueArg?.trim();
127
+ return candidate && plugins.path.isAbsolute(candidate) ? candidate : fallbackArg;
128
+ };
129
+
130
+ export const controllerDataRootPaths = (
131
+ optionsArg: IControllerDataDirectoryOptions = {},
132
+ ): IControllerDataRootPaths => {
133
+ const packageRoot = optionsArg.packageRoot ?? modulePackageRoot;
134
+ if (isDevelopmentCheckout(packageRoot)) {
135
+ const checkoutRoot = plugins.path.join(packageRoot, '.nogit');
136
+ return {
137
+ legacyRoot: checkoutRoot,
138
+ targetRoot: checkoutRoot,
139
+ migrationRequired: false,
140
+ };
141
+ }
142
+ const environment = optionsArg.environment ?? process.env;
143
+ const homeDirectory = optionsArg.homeDirectory ?? plugins.os.homedir();
144
+ const configHome = xdgRoot(
145
+ environment.XDG_CONFIG_HOME,
146
+ plugins.path.join(homeDirectory, '.config'),
147
+ );
148
+ return {
149
+ legacyRoot: plugins.path.join(configHome, 'harness-controller'),
150
+ targetRoot: plugins.path.join(configHome, 'hcon'),
151
+ migrationRequired: true,
152
+ };
153
+ };
154
+
155
+ /** Retained location for controller and upgrade logs across the A to B transition. */
156
+ export const controllerDataDirectory = (
157
+ optionsArg: IControllerDataDirectoryOptions = {},
158
+ ): string => controllerDataRootPaths(optionsArg).legacyRoot;
159
+
160
+ /** @deprecated Use controllerDataDirectory(). */
161
+ export const controllerStateDirectory = controllerDataDirectory;
162
+
163
+ const legacyControllerStateDirectory = (
164
+ optionsArg: IControllerDataDirectoryOptions,
165
+ ): string => {
166
+ const environment = optionsArg.environment ?? process.env;
167
+ const homeDirectory = optionsArg.homeDirectory ?? plugins.os.homedir();
168
+ const stateHome = xdgRoot(
169
+ environment.XDG_STATE_HOME,
170
+ plugins.path.join(homeDirectory, '.local', 'state'),
171
+ );
172
+ return plugins.path.join(stateHome, 'harness-controller');
173
+ };
174
+
175
+ export const readDatabaseConfig = (
176
+ optionsArg: IControllerDataDirectoryOptions = {},
177
+ ): IControllerDatabaseConfig => {
178
+ const environment = optionsArg.environment ?? process.env;
179
+ const mongoDbUrl = environment.HARNESS_CONTROLLER_MONGO_URL?.trim();
180
+ const mongoDbName = environment.HARNESS_CONTROLLER_MONGO_DB?.trim()
181
+ || 'opencode_controller';
182
+ if (!mongoDbName || !/^[A-Za-z0-9_-]{1,63}$/.test(mongoDbName)) {
183
+ throw new Error('HARNESS_CONTROLLER_MONGO_DB must use 1-63 letters, digits, underscores, or dashes.');
184
+ }
185
+ if (mongoDbUrl) {
186
+ return { mongoDbUrl, mongoDbName };
187
+ }
188
+ const embeddedDataDirectoryOverride = environment.HARNESS_CONTROLLER_DB_DIR?.trim();
189
+ const embeddedDataDirectory = embeddedDataDirectoryOverride
190
+ || plugins.path.join(controllerDataRootPaths(optionsArg).targetRoot, 'smartdb');
191
+ if (!plugins.path.isAbsolute(embeddedDataDirectory)) {
192
+ throw new Error('HARNESS_CONTROLLER_DB_DIR must be an absolute path.');
193
+ }
194
+ const packageRoot = optionsArg.packageRoot ?? modulePackageRoot;
195
+ return {
196
+ mongoDbName,
197
+ embeddedDataDirectory,
198
+ ...(!embeddedDataDirectoryOverride && !isDevelopmentCheckout(packageRoot)
199
+ ? {
200
+ legacyEmbeddedDataDirectory: plugins.path.join(
201
+ legacyControllerStateDirectory(optionsArg),
202
+ 'smartdb',
203
+ ),
204
+ }
205
+ : {}),
206
+ };
207
+ };
208
+
209
+ export const readTrustedProxySecret = (tlsModeArg: TControllerTlsMode): string | undefined => {
210
+ if (tlsModeArg === 'local') return undefined;
211
+ const secret = process.env[trustedProxySecretEnvironmentVariable]?.trim();
212
+ if (
213
+ !secret
214
+ || !/^[A-Za-z0-9_-]{43}$/u.test(secret)
215
+ || Buffer.from(secret, 'base64url').byteLength !== 32
216
+ ) {
217
+ throw new Error(
218
+ `${trustedProxySecretEnvironmentVariable} must be a 32-byte base64url secret in proxy mode.`,
219
+ );
220
+ }
221
+ return secret;
222
+ };
223
+
224
+ export const resolveInitialRuntimeConfig = async (
225
+ overridesArg: IControllerRuntimeOverrides,
226
+ ): Promise<IControllerRuntimeConfig> => {
227
+ const controllerPort = assertPort(overridesArg.controllerPort, 'controllerPort');
228
+ const opencodePort = assertPort(
229
+ overridesArg.opencodePort ?? defaultOpenCodePort,
230
+ 'opencodePort',
231
+ );
232
+ if (controllerPort === opencodePort) {
233
+ throw new Error('The controller and OpenCode ports must be different.');
234
+ }
235
+ const origin = normalizeOrigin(
236
+ overridesArg.publicOrigin ?? `http://localhost:${controllerPort}`,
237
+ );
238
+ const tlsMode = resolveTlsMode(origin, overridesArg.behindTlsProxy === true);
239
+ if (tlsMode !== 'proxy' && effectivePort(origin) !== controllerPort) {
240
+ throw new Error('Local public-origin port must match the controller listening port.');
241
+ }
242
+ const rpId = normalizeRpId(overridesArg.rpId ?? origin.hostname, origin.hostname);
243
+ const workspaceDirectory = await resolveDirectory(
244
+ overridesArg.workspaceDirectory ?? process.cwd(),
245
+ );
246
+ const projectsRoot = await resolveDirectory(
247
+ overridesArg.projectsRoot ?? workspaceDirectory,
248
+ );
249
+ return {
250
+ controllerPort,
251
+ publicOrigin: origin.origin,
252
+ rpId,
253
+ workspaceDirectory,
254
+ projectsRoot,
255
+ opencodePort,
256
+ tlsMode,
257
+ };
258
+ };
259
+
260
+ export const resolveStoredRuntimeConfig = async (
261
+ storedArg: IControllerRuntimeConfig,
262
+ overridesArg: IControllerRuntimeOverrides,
263
+ ): Promise<IControllerRuntimeConfig> => {
264
+ assertPort(storedArg.controllerPort, 'stored controllerPort');
265
+ assertPort(storedArg.opencodePort, 'stored opencodePort');
266
+ if (storedArg.controllerPort !== overridesArg.controllerPort) {
267
+ throw new Error('Stored controller port does not match the requested management port.');
268
+ }
269
+ const storedOrigin = normalizeOrigin(storedArg.publicOrigin);
270
+ if (storedOrigin.origin !== storedArg.publicOrigin) {
271
+ throw new Error('Stored publicOrigin is not canonical.');
272
+ }
273
+ const normalizedStoredRpId = normalizeRpId(storedArg.rpId, storedOrigin.hostname);
274
+ if (normalizedStoredRpId !== storedArg.rpId) {
275
+ throw new Error('Stored rpId is not canonical.');
276
+ }
277
+ if (storedArg.controllerPort === storedArg.opencodePort) {
278
+ throw new Error('Stored controller and OpenCode ports conflict.');
279
+ }
280
+ if (
281
+ storedArg.tlsMode !== 'local'
282
+ && storedArg.tlsMode !== 'proxy'
283
+ ) {
284
+ throw new Error('Stored TLS mode is invalid.');
285
+ }
286
+ const validatedTlsMode = resolveTlsMode(
287
+ storedOrigin,
288
+ storedArg.tlsMode === 'proxy',
289
+ );
290
+ if (validatedTlsMode !== storedArg.tlsMode) {
291
+ throw new Error('Stored TLS mode conflicts with the public origin or TLS material.');
292
+ }
293
+ if (storedArg.tlsMode !== 'proxy' && effectivePort(storedOrigin) !== storedArg.controllerPort) {
294
+ throw new Error('Stored local public-origin port does not match the controller port.');
295
+ }
296
+ if (overridesArg.publicOrigin !== undefined) {
297
+ const requestedOrigin = normalizeOrigin(overridesArg.publicOrigin).origin;
298
+ if (requestedOrigin !== storedArg.publicOrigin) {
299
+ throw new Error('publicOrigin is immutable after controller initialization.');
300
+ }
301
+ }
302
+ if (overridesArg.rpId !== undefined) {
303
+ const requestedRpId = normalizeRpId(overridesArg.rpId, storedOrigin.hostname);
304
+ if (requestedRpId !== storedArg.rpId) {
305
+ throw new Error('rpId is immutable after controller initialization.');
306
+ }
307
+ }
308
+ if (overridesArg.opencodePort !== undefined && overridesArg.opencodePort !== storedArg.opencodePort) {
309
+ throw new Error('opencodePort is immutable after controller initialization.');
310
+ }
311
+ if (overridesArg.workspaceDirectory !== undefined) {
312
+ const requestedDirectory = await resolveDirectory(overridesArg.workspaceDirectory);
313
+ if (requestedDirectory !== storedArg.workspaceDirectory) {
314
+ throw new Error('The OpenCode workspace is immutable after controller initialization.');
315
+ }
316
+ }
317
+ const storedDirectory = await resolveDirectory(storedArg.workspaceDirectory);
318
+ if (storedDirectory !== storedArg.workspaceDirectory) {
319
+ throw new Error('Stored OpenCode workspace is no longer its canonical real path.');
320
+ }
321
+ if (storedArg.tlsMode === 'proxy') {
322
+ if (overridesArg.behindTlsProxy === false) {
323
+ throw new Error('Stored TLS proxy mode is immutable.');
324
+ }
325
+ } else {
326
+ if (overridesArg.behindTlsProxy) {
327
+ throw new Error('Stored localhost mode cannot be changed to TLS mode.');
328
+ }
329
+ }
330
+ // Pre-v2 documents carry no projectsRoot: the first v2 start adopts one —
331
+ // from --projects-root when given, else the workspace — and it is immutable
332
+ // from then on like every other stored boundary.
333
+ let projectsRoot: string;
334
+ if (storedArg.projectsRoot === undefined) {
335
+ projectsRoot = await resolveDirectory(
336
+ overridesArg.projectsRoot ?? storedArg.workspaceDirectory,
337
+ );
338
+ } else {
339
+ projectsRoot = await resolveDirectory(storedArg.projectsRoot);
340
+ if (projectsRoot !== storedArg.projectsRoot) {
341
+ throw new Error('Stored projects root is no longer its canonical real path.');
342
+ }
343
+ if (overridesArg.projectsRoot !== undefined) {
344
+ const requestedProjectsRoot = await resolveDirectory(overridesArg.projectsRoot);
345
+ if (requestedProjectsRoot !== storedArg.projectsRoot) {
346
+ throw new Error('The projects root is immutable after it has been adopted.');
347
+ }
348
+ }
349
+ }
350
+ return { ...storedArg, projectsRoot };
351
+ };