@prestack/thread 0.1.3 → 0.1.5

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 (270) hide show
  1. package/CHANGELOG.md +563 -0
  2. package/dist/core/actor.d.ts +1 -1
  3. package/dist/core/actor.js +5 -4
  4. package/dist/core/actor.ts +5 -4
  5. package/dist/core/attach.d.ts +0 -7
  6. package/dist/core/attach.js +38 -67
  7. package/dist/core/attach.ts +34 -80
  8. package/dist/core/chain.js +13 -17
  9. package/dist/core/chain.ts +11 -15
  10. package/dist/core/condition.d.ts +4 -4
  11. package/dist/core/condition.js +2 -2
  12. package/dist/core/descend.d.ts +4 -2
  13. package/dist/core/descend.js +91 -23
  14. package/dist/core/descend.ts +90 -21
  15. package/dist/core/errors/catalogue.d.ts +52 -0
  16. package/dist/{operations/errors/errors.js → core/errors/catalogue.js} +1 -1
  17. package/dist/{operations/errors/errors.ts → core/errors/catalogue.ts} +1 -1
  18. package/dist/{operations/errors/catalog.d.ts → core/errors/error.d.ts} +2 -3
  19. package/dist/{operations/errors/catalog.js → core/errors/error.js} +1 -16
  20. package/dist/{operations/errors/catalog.ts → core/errors/error.ts} +3 -19
  21. package/dist/core/errors/namespaces.d.ts +3 -0
  22. package/dist/core/errors/namespaces.js +15 -0
  23. package/dist/core/errors/namespaces.ts +19 -0
  24. package/dist/core/finding.js +2 -2
  25. package/dist/core/finding.ts +1 -2
  26. package/dist/core/init.d.ts +1 -1
  27. package/dist/core/init.js +51 -5
  28. package/dist/core/init.ts +58 -5
  29. package/dist/core/invoked.d.ts +1 -1
  30. package/dist/core/invoked.js +3 -1
  31. package/dist/core/invoked.ts +5 -2
  32. package/dist/core/round.js +36 -22
  33. package/dist/core/round.ts +26 -9
  34. package/dist/core/rows.d.ts +4 -0
  35. package/dist/core/rows.js +31 -2
  36. package/dist/core/rows.ts +33 -1
  37. package/dist/core/scope.d.ts +1 -0
  38. package/dist/core/scope.js +1 -0
  39. package/dist/core/scope.ts +2 -0
  40. package/dist/core/thread.d.ts +3 -3
  41. package/dist/core/tree.d.ts +4 -1
  42. package/dist/core/tree.js +26 -6
  43. package/dist/core/tree.ts +29 -6
  44. package/dist/core/types.d.ts +3 -3
  45. package/dist/core/types.js +3 -1
  46. package/dist/core/types.ts +2 -1
  47. package/dist/derivation/attach.js +3 -2
  48. package/dist/derivation/attach.ts +2 -1
  49. package/dist/derivation/generators/build.js +6 -6
  50. package/dist/derivation/generators/build.ts +1 -1
  51. package/dist/derivation/generators/check.js +1 -1
  52. package/dist/derivation/generators/determinism.js +1 -1
  53. package/dist/derivation/generators/release.js +60 -47
  54. package/dist/derivation/generators/release.ts +66 -43
  55. package/dist/derivation/release.d.ts +7 -3
  56. package/dist/derivation/release.js +14 -1
  57. package/dist/derivation/release.ts +22 -2
  58. package/dist/integrations/attach.d.ts +4 -0
  59. package/dist/integrations/attach.js +37 -56
  60. package/dist/integrations/attach.ts +54 -60
  61. package/dist/integrations/cli.d.ts +37 -0
  62. package/dist/integrations/cli.js +440 -0
  63. package/dist/integrations/cli.ts +543 -0
  64. package/dist/{core/files.d.ts → integrations/disk.d.ts} +16 -24
  65. package/dist/integrations/disk.js +435 -0
  66. package/dist/integrations/disk.ts +465 -0
  67. package/dist/integrations/generators/read.js +6 -6
  68. package/dist/integrations/generators/read.ts +4 -4
  69. package/dist/integrations/generators/vault.js +10 -11
  70. package/dist/integrations/generators/vault.ts +4 -5
  71. package/dist/{operations/http.d.ts → integrations/https.d.ts} +10 -6
  72. package/dist/integrations/https.js +170 -0
  73. package/dist/integrations/https.ts +216 -0
  74. package/dist/integrations/pglite.d.ts +26 -0
  75. package/dist/integrations/pglite.js +143 -0
  76. package/dist/integrations/pglite.ts +206 -0
  77. package/dist/integrations/secret.d.ts +8 -2
  78. package/dist/integrations/secret.js +3 -5
  79. package/dist/integrations/secret.ts +10 -6
  80. package/dist/integrations/target.d.ts +155 -14
  81. package/dist/integrations/target.js +171 -50
  82. package/dist/integrations/target.ts +377 -61
  83. package/dist/integrations/vault.d.ts +1 -0
  84. package/dist/integrations/vault.js +20 -5
  85. package/dist/integrations/vault.ts +17 -5
  86. package/dist/integrity/attach.js +8 -77
  87. package/dist/integrity/attach.ts +7 -76
  88. package/dist/integrity/check-threads.js +5 -5
  89. package/dist/integrity/check-threads.ts +2 -2
  90. package/dist/integrity/constraint.d.ts +0 -1
  91. package/dist/integrity/constraint.js +267 -366
  92. package/dist/integrity/constraint.ts +267 -375
  93. package/dist/integrity/generators/compiler.js +14 -17
  94. package/dist/integrity/generators/compiler.ts +10 -15
  95. package/dist/integrity/generators/gate.js +15 -15
  96. package/dist/integrity/generators/gate.ts +10 -10
  97. package/dist/integrity/generators/issues.js +7 -7
  98. package/dist/integrity/generators/publish.js +39 -57
  99. package/dist/integrity/generators/publish.ts +44 -55
  100. package/dist/integrity/generators/trial.d.ts +3 -3
  101. package/dist/integrity/generators/trial.js +133 -165
  102. package/dist/integrity/generators/trial.ts +145 -169
  103. package/dist/integrity/lint.js +9 -13
  104. package/dist/integrity/lint.ts +7 -10
  105. package/dist/integrity/lsp/bin.js +5 -4
  106. package/dist/integrity/lsp/bin.ts +3 -1
  107. package/dist/integrity/lsp/diagnostics.js +3 -3
  108. package/dist/integrity/lsp/diagnostics.ts +1 -1
  109. package/dist/integrity/lsp/lint.js +19 -30
  110. package/dist/integrity/lsp/lint.ts +16 -32
  111. package/dist/integrity/lsp/server.js +3 -3
  112. package/dist/integrity/slopnator.d.ts +3 -13
  113. package/dist/integrity/slopnator.js +59 -38
  114. package/dist/integrity/slopnator.ts +54 -38
  115. package/dist/integrity/slopnators/sl_broken_lineage.js +2 -2
  116. package/dist/integrity/slopnators/sl_declared_elsewhere.js +1 -1
  117. package/dist/integrity/slopnators/sl_derived_drift.js +4 -4
  118. package/dist/integrity/slopnators/sl_derived_drift.ts +1 -1
  119. package/dist/integrity/slopnators/sl_door_in_a_node.js +220 -0
  120. package/dist/integrity/slopnators/sl_door_in_a_node.ts +250 -0
  121. package/dist/integrity/slopnators/sl_inert_island.js +10 -8
  122. package/dist/integrity/slopnators/sl_inert_island.ts +8 -6
  123. package/dist/integrity/slopnators/sl_missing_row.js +6 -51
  124. package/dist/integrity/slopnators/sl_missing_row.ts +4 -50
  125. package/dist/integrity/slopnators/sl_no_barrel.js +1 -1
  126. package/dist/integrity/slopnators/sl_no_child_process.js +36 -18
  127. package/dist/integrity/slopnators/sl_no_child_process.ts +44 -18
  128. package/dist/integrity/slopnators/sl_no_dispatch_bypass.js +80 -149
  129. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +95 -147
  130. package/dist/integrity/slopnators/sl_no_import_cycle.js +15 -4
  131. package/dist/integrity/slopnators/sl_no_import_cycle.ts +20 -4
  132. package/dist/integrity/slopnators/sl_no_such_command.js +2 -2
  133. package/dist/integrity/slopnators/sl_no_such_command.ts +1 -1
  134. package/dist/integrity/slopnators/sl_outside_an_operation.js +20 -0
  135. package/dist/integrity/slopnators/sl_outside_an_operation.ts +25 -0
  136. package/dist/integrity/slopnators/sl_screen_holds_only_declared.d.ts +2 -0
  137. package/dist/integrity/slopnators/sl_screen_holds_only_declared.js +61 -0
  138. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +70 -0
  139. package/dist/integrity/slopnators/sl_secret_literal.js +1 -33
  140. package/dist/integrity/slopnators/sl_secret_literal.ts +1 -33
  141. package/dist/integrity/slopnators/sl_stale_path.js +5 -22
  142. package/dist/integrity/slopnators/sl_stale_path.ts +4 -20
  143. package/dist/integrity/slopnators/sl_twice_meant.js +1 -1
  144. package/dist/integrity/slopnators/sl_twice_parented.js +29 -5
  145. package/dist/integrity/slopnators/sl_twice_parented.ts +28 -4
  146. package/dist/integrity/slopnators/sl_undeclared_crossing.d.ts +4 -1
  147. package/dist/integrity/slopnators/sl_undeclared_crossing.js +426 -62
  148. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +454 -70
  149. package/dist/integrity/slopnators/sl_undeclared_destination.js +59 -25
  150. package/dist/integrity/slopnators/sl_undeclared_destination.ts +69 -21
  151. package/dist/integrity/slopnators/sl_undeclared_list.d.ts +2 -0
  152. package/dist/integrity/slopnators/sl_undeclared_list.js +363 -0
  153. package/dist/integrity/slopnators/sl_undeclared_list.ts +358 -0
  154. package/dist/integrity/slopnators/sl_undeclared_node.js +1 -11
  155. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -10
  156. package/dist/integrity/slopnators/sl_undeclared_operation.js +111 -29
  157. package/dist/integrity/slopnators/sl_undeclared_operation.ts +134 -26
  158. package/dist/integrity/slopnators/sl_undeclared_variant.js +2 -2
  159. package/dist/integrity/slopnators/sl_undeclared_webhook.d.ts +2 -0
  160. package/dist/integrity/slopnators/sl_undeclared_webhook.js +90 -0
  161. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +108 -0
  162. package/dist/integrity/slopnators/sl_underived_route.d.ts +2 -0
  163. package/dist/integrity/slopnators/sl_underived_route.js +61 -0
  164. package/dist/integrity/slopnators/sl_underived_route.ts +72 -0
  165. package/dist/integrity/slopnators/sl_ungoverned_island.js +3 -3
  166. package/dist/integrity/slopnators/sl_ungoverned_island.ts +1 -1
  167. package/dist/integrity/slopnators/sl_unlisted_program.d.ts +2 -0
  168. package/dist/integrity/slopnators/sl_unlisted_program.js +39 -0
  169. package/dist/integrity/slopnators/sl_unlisted_program.ts +40 -0
  170. package/dist/integrity/slopnators/sl_unnamed_island.js +1 -1
  171. package/dist/integrity/slopnators/sl_unpaired_member.js +3 -3
  172. package/dist/integrity/slopnators/sl_unpaired_member.ts +1 -1
  173. package/dist/integrity/slopnators/sl_unpaired_slopnator.js +4 -4
  174. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +1 -1
  175. package/dist/integrity/slopnators/sl_unprefixed_member.js +5 -31
  176. package/dist/integrity/slopnators/sl_unprefixed_member.ts +2 -28
  177. package/dist/integrity/slopnators/sl_unthreaded.js +11 -7
  178. package/dist/integrity/slopnators/sl_unthreaded.ts +6 -7
  179. package/dist/integrity/slopnators/sl_untranslated_key.js +2 -25
  180. package/dist/integrity/slopnators/sl_untranslated_key.ts +1 -25
  181. package/dist/integrity/slopnators/sl_unvaulted_secret.d.ts +2 -0
  182. package/dist/integrity/slopnators/sl_unvaulted_secret.js +107 -0
  183. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +132 -0
  184. package/dist/integrity/slopnators/sl_unversioned.js +6 -4
  185. package/dist/integrity/slopnators/sl_unversioned.ts +5 -3
  186. package/dist/integrity/sweep.d.ts +1 -0
  187. package/dist/integrity/sweep.js +105 -42
  188. package/dist/integrity/sweep.ts +115 -42
  189. package/dist/knowledge/attach.js +4 -3
  190. package/dist/knowledge/attach.ts +3 -2
  191. package/dist/knowledge/generators/docsgen.js +8 -6
  192. package/dist/knowledge/generators/docsgen.ts +4 -2
  193. package/dist/knowledge/generators/glossary.js +4 -4
  194. package/dist/knowledge/generators/glossary.ts +1 -1
  195. package/dist/operations/access.d.ts +23 -0
  196. package/dist/operations/access.js +28 -1
  197. package/dist/operations/access.ts +43 -0
  198. package/dist/operations/attach.js +33 -113
  199. package/dist/operations/attach.ts +51 -117
  200. package/dist/operations/capabilities.d.ts +14 -5
  201. package/dist/operations/capabilities.js +13 -4
  202. package/dist/operations/capabilities.ts +27 -8
  203. package/dist/operations/dispatch.d.ts +8 -2
  204. package/dist/operations/dispatch.js +128 -185
  205. package/dist/operations/dispatch.ts +138 -191
  206. package/dist/operations/error-results.d.ts +1 -1
  207. package/dist/operations/error-results.js +2 -2
  208. package/dist/operations/error-results.ts +2 -2
  209. package/dist/operations/generators/capability.d.ts +11 -1
  210. package/dist/operations/generators/capability.js +481 -224
  211. package/dist/operations/generators/capability.ts +562 -233
  212. package/dist/operations/generators/compile.js +66 -39
  213. package/dist/operations/generators/compile.ts +78 -39
  214. package/dist/operations/generators/permits.js +11 -12
  215. package/dist/operations/generators/permits.ts +3 -4
  216. package/dist/operations/generators/seed.d.ts +1 -0
  217. package/dist/operations/generators/seed.js +19 -17
  218. package/dist/operations/generators/seed.ts +22 -14
  219. package/dist/operations/generators/trial.d.ts +6 -8
  220. package/dist/operations/generators/trial.js +200 -70
  221. package/dist/operations/generators/trial.ts +230 -93
  222. package/dist/operations/nodes.d.ts +15 -16
  223. package/dist/operations/nodes.ts +16 -17
  224. package/dist/operations/operations.d.ts +40 -4
  225. package/dist/operations/operations.js +1 -0
  226. package/dist/operations/operations.ts +61 -4
  227. package/dist/operations/result.d.ts +2 -2
  228. package/dist/operations/result.ts +2 -2
  229. package/package.json +1 -4
  230. package/dist/core/answers.d.ts +0 -171
  231. package/dist/core/answers.js +0 -789
  232. package/dist/core/answers.ts +0 -999
  233. package/dist/core/client.d.ts +0 -63
  234. package/dist/core/client.js +0 -249
  235. package/dist/core/client.ts +0 -289
  236. package/dist/core/files.js +0 -171
  237. package/dist/core/files.ts +0 -222
  238. package/dist/integrations/module.d.ts +0 -6
  239. package/dist/integrations/module.js +0 -153
  240. package/dist/integrations/module.ts +0 -191
  241. package/dist/integrity/slopnators/sl_unkept_rows.js +0 -104
  242. package/dist/integrity/slopnators/sl_unkept_rows.ts +0 -111
  243. package/dist/integrity/slopnators/sl_unseamed_reach.js +0 -73
  244. package/dist/integrity/slopnators/sl_unseamed_reach.ts +0 -79
  245. package/dist/operations/cost.d.ts +0 -14
  246. package/dist/operations/cost.js +0 -37
  247. package/dist/operations/cost.ts +0 -58
  248. package/dist/operations/errors/errors.d.ts +0 -52
  249. package/dist/operations/http.js +0 -124
  250. package/dist/operations/http.ts +0 -169
  251. package/dist/operations/memory.d.ts +0 -104
  252. package/dist/operations/memory.js +0 -365
  253. package/dist/operations/memory.ts +0 -470
  254. package/dist/operations/metering.d.ts +0 -55
  255. package/dist/operations/metering.js +0 -247
  256. package/dist/operations/metering.ts +0 -328
  257. package/dist/operations/queue-policy.d.ts +0 -3
  258. package/dist/operations/queue-policy.js +0 -8
  259. package/dist/operations/queue-policy.ts +0 -10
  260. package/dist/operations/seams.d.ts +0 -239
  261. package/dist/operations/seams.js +0 -45
  262. package/dist/operations/seams.ts +0 -364
  263. package/dist/operations/store.d.ts +0 -14
  264. package/dist/operations/store.js +0 -1
  265. package/dist/operations/store.ts +0 -29
  266. /package/dist/{operations → core}/errors/classes.d.ts +0 -0
  267. /package/dist/{operations → core}/errors/classes.js +0 -0
  268. /package/dist/{operations → core}/errors/classes.ts +0 -0
  269. /package/dist/integrity/slopnators/{sl_unkept_rows.d.ts → sl_door_in_a_node.d.ts} +0 -0
  270. /package/dist/integrity/slopnators/{sl_unseamed_reach.d.ts → sl_outside_an_operation.d.ts} +0 -0
@@ -0,0 +1,440 @@
1
+ import { spawn, spawnSync } from 'node:child_process';
2
+ import { randomBytes } from 'node:crypto';
3
+ import { tmpdir, uptime } from 'node:os';
4
+ import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
5
+ import { allowedNodeEnvironmentFlags, env, execPath, kill, pid, stderr, stdout } from 'node:process';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { CHANNEL, FOLDER, across, attached, createFileSync, existsSync, here, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from '../integrations/disk.js';
8
+ import { VAULT_DIR } from '../integrations/vault.js';
9
+ import { CALL_PREFIX, LOCKFILES, PACKAGER, REACH, managerOf, programOf, unlisted } from '../integrations/target.js';
10
+ import { CLI } from '../core/invoked.js';
11
+ import { valuesIn } from '../core/rows.js';
12
+ import { THING } from '../core/scope.js';
13
+ import { findTree, inTree } from '../core/tree.js';
14
+ const answered = (went) => ({
15
+ there: went.error === undefined,
16
+ ok: went.status === 0,
17
+ code: went.status ?? 1,
18
+ out: String(went.stdout ?? ''),
19
+ err: String(went.stderr ?? ''),
20
+ killed: went.signal ?? null,
21
+ why: went.error === undefined ? '' : went.error.message,
22
+ });
23
+ const standing = (at) => (at === undefined || across(at) ? undefined : at);
24
+ export function starts(program, words, how = {}) {
25
+ let went;
26
+ try {
27
+ went = spawnSync(program, [...words], {
28
+ cwd: standing(how.at),
29
+ encoding: 'utf8',
30
+ shell: false,
31
+ stdio: how.shows === true
32
+ ? [how.hears === undefined ? 'inherit' : 'pipe', 'inherit', 'inherit']
33
+ : how.shows === 'errors'
34
+ ? [how.hears === undefined ? 'ignore' : 'pipe', 'pipe', 'inherit']
35
+ : 'pipe',
36
+ input: how.hears,
37
+ env: how.holds,
38
+ ...(how.within === undefined ? {} : { timeout: how.within, killSignal: 'SIGKILL' }),
39
+ });
40
+ }
41
+ catch (thrown) {
42
+ return nowhere(thrown instanceof Error ? thrown.message : String(thrown));
43
+ }
44
+ const ran = answered(went);
45
+ if (how.shows === 'tee') {
46
+ stdout.write(ran.out);
47
+ stderr.write(ran.err);
48
+ }
49
+ return ran;
50
+ }
51
+ export function started(program, words, how = {}) {
52
+ return new Promise((keep) => {
53
+ let child;
54
+ try {
55
+ child = spawn(program, [...words], { cwd: standing(how.at), shell: false, env: how.holds });
56
+ }
57
+ catch (thrown) {
58
+ keep(nowhere(thrown instanceof Error ? thrown.message : String(thrown)));
59
+ return;
60
+ }
61
+ let out = '';
62
+ let err = '';
63
+ let why = '';
64
+ const clock = how.within === undefined ? undefined : setTimeout(() => child.kill('SIGKILL'), how.within);
65
+ child.stdout.on('data', (chunk) => (out += chunk.toString()));
66
+ child.stderr.on('data', (chunk) => (err += chunk.toString()));
67
+ child.on('error', (error) => (why = error.message));
68
+ child.on('close', (code, killed) => {
69
+ if (clock !== undefined)
70
+ clearTimeout(clock);
71
+ keep({ there: why === '', ok: why === '' && code === 0, code: code ?? 1, out, err, killed, why });
72
+ });
73
+ child.stdin.end(how.hears);
74
+ });
75
+ }
76
+ export function handed(at, program, passed, shows = true, within, hears) {
77
+ return starts(program, passed, { at, shows, ...(within === undefined ? {} : { within }), ...(hears === undefined ? {} : { hears }) });
78
+ }
79
+ const HOLDING = 'THREAD_RUNNING';
80
+ const CLAIMED = 'running.';
81
+ const CLAIM = '.json';
82
+ const STARTING = 10_000;
83
+ let claimed = '';
84
+ const claimAt = (dir, one) => join(dir, CLAIMED + String(one) + CLAIM);
85
+ const generations = (dir) => existsSync(dir)
86
+ ? readdirSync(dir)
87
+ .filter((one) => one.startsWith(CLAIMED) && one.endsWith(CLAIM))
88
+ .map((one) => Number(one.slice(CLAIMED.length, one.length - CLAIM.length)))
89
+ .filter((one) => Number.isInteger(one) && one >= 0)
90
+ : [];
91
+ const living = (one) => {
92
+ try {
93
+ kill(one, 0);
94
+ return true;
95
+ }
96
+ catch (thrown) {
97
+ return thrown.code === 'EPERM';
98
+ }
99
+ };
100
+ function holding(at) {
101
+ try {
102
+ const by = JSON.parse(readFileSync(at, 'utf8'));
103
+ return by.since > Date.now() - uptime() * 1000 && living(by.pid) ? { by } : {};
104
+ }
105
+ catch {
106
+ try {
107
+ return Date.now() - statSync(at).mtimeMs < STARTING ? { by: { pid: 0, runs: '', since: Date.now() } } : {};
108
+ }
109
+ catch {
110
+ return {};
111
+ }
112
+ }
113
+ }
114
+ export function releases() {
115
+ const at = claimed === '' ? env[HOLDING] : claimed;
116
+ if (at !== undefined)
117
+ rmSync(at, { force: true });
118
+ claimed = '';
119
+ Reflect.deleteProperty(env, HOLDING);
120
+ }
121
+ export function claims(root, runs) {
122
+ if (attached())
123
+ return {};
124
+ const dir = join(root, VAULT_DIR);
125
+ for (let tries = 0; tries < 5; tries += 1) {
126
+ const taken = generations(dir);
127
+ const top = Math.max(-1, ...taken);
128
+ const held = top < 0 ? {} : holding(claimAt(dir, top));
129
+ if (held.by !== undefined)
130
+ return env[HOLDING] === claimAt(dir, top) ? {} : held;
131
+ const mine = claimAt(dir, top + 1);
132
+ if (!createFileSync(mine, JSON.stringify({ pid, runs, since: Date.now() })))
133
+ continue;
134
+ claimed = mine;
135
+ env[HOLDING] = mine;
136
+ for (const one of taken)
137
+ rmSync(claimAt(dir, one), { force: true });
138
+ process.on('exit', releases);
139
+ return {};
140
+ }
141
+ return { by: { pid: 0, runs: '', since: Date.now() } };
142
+ }
143
+ export function programFor(name, at) {
144
+ const found = programOf(name, at, existsSync);
145
+ if (found === undefined)
146
+ throw new Error(unlisted(name));
147
+ return found;
148
+ }
149
+ export const SIGNING = 'THREAD_RECEIPTS_KEY';
150
+ const SIGNED_AT = 'thread-receipts.key';
151
+ let signed = '';
152
+ export function signing() {
153
+ if (signed !== '')
154
+ return signed;
155
+ const given = env[SIGNING];
156
+ if (given !== undefined && given !== '') {
157
+ signed = given;
158
+ return signed;
159
+ }
160
+ if (attached()) {
161
+ throw new Error('this answers for a folder on another machine and was handed no key to seal receipts with, so it issues none. ' +
162
+ 'The server that started it hands one over in ' + SIGNING + '.');
163
+ }
164
+ const at = join(tmpdir(), SIGNED_AT);
165
+ if (!existsSync(at))
166
+ createFileSync(at, randomBytes(32).toString('hex'));
167
+ signed = readFileSync(at, 'utf8').trim();
168
+ return signed;
169
+ }
170
+ const OWN = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
171
+ const GUARDS = ['--permission', '--experimental-permission'];
172
+ const HUSHES = '--disable-warning';
173
+ const swapped = (path) => [...path].map((one) => (one === one.toUpperCase() ? one.toLowerCase() : one.toUpperCase())).join('');
174
+ let unguarded = false;
175
+ function guarded() {
176
+ const before = env.NODE_OPTIONS ?? '';
177
+ const on = GUARDS.find((one) => allowedNodeEnvironmentFlags.has(one));
178
+ if (on === undefined) {
179
+ if (!unguarded) {
180
+ stderr.write('thread: this node has no permission model, so a thread command started for a folder runs unguarded: nothing ' +
181
+ 'here stops it reading that folder straight off this disk, and on one machine that would go unnoticed.\n');
182
+ unguarded = true;
183
+ }
184
+ return before;
185
+ }
186
+ const kept = [...new Set([tmpdir(), realpathSync(tmpdir())])];
187
+ const allowed = (flag, paths) => paths.map((one) => flag + '="' + one + '"');
188
+ const quiet = allowedNodeEnvironmentFlags.has(HUSHES) ? [HUSHES + '=SecurityWarning'] : [];
189
+ return [before, on, ...allowed('--allow-fs-read', [OWN, swapped(OWN), ...kept]), ...allowed('--allow-fs-write', kept), '--allow-child-process', '--allow-worker', ...quiet]
190
+ .filter((one) => one !== '')
191
+ .join(' ');
192
+ }
193
+ const SERVED = 'thread-serve';
194
+ const TICK = 2;
195
+ const MARGIN = 5_000;
196
+ const SAYING = '-saying';
197
+ const ORDER = '-order';
198
+ const ANSWER = '-answer';
199
+ const serving = new Map();
200
+ const still = (one, asks) => ({ there: true, ok: false, code: -1, out: '', err: '', killed: null, why: '', of: one.of, asks });
201
+ const nowhere = (why) => ({ there: false, ok: false, code: 1, out: '', err: '', killed: null, why });
202
+ const lost = (of) => ({ there: true, ok: false, code: -1, out: '', err: '', killed: null, why: '', of, lost: of });
203
+ const told = (one) => JSON.stringify([one.order, one.at, one.said ?? null, one.mode ?? null, one.words ?? null]);
204
+ const plainly = (one) => one.order + ' ' + (one.at === '' ? '.' : one.at);
205
+ const outside = (root, at) => {
206
+ const step = relative(root, at);
207
+ return step.startsWith('..') ? true : isAbsolute(step);
208
+ };
209
+ function hand(one, held) {
210
+ const settle = one.waiting.shift();
211
+ if (settle === undefined)
212
+ one.parked.push(held);
213
+ else
214
+ settle(held);
215
+ }
216
+ function reply(dir, name, held) {
217
+ writeFileSync(join(dir, name + SAYING), JSON.stringify(held), 'utf8');
218
+ renameSync(join(dir, name + SAYING), join(dir, name + ANSWER));
219
+ }
220
+ function watching(one) {
221
+ one.watch = setInterval(() => {
222
+ let names = [];
223
+ try {
224
+ names = readdirSync(one.dir);
225
+ }
226
+ catch {
227
+ return;
228
+ }
229
+ for (const name of names) {
230
+ if (!name.endsWith(ORDER))
231
+ continue;
232
+ const file = join(one.dir, name);
233
+ let said = '';
234
+ try {
235
+ said = readFileSync(file, 'utf8');
236
+ }
237
+ catch {
238
+ continue;
239
+ }
240
+ rmSync(file, { force: true });
241
+ const order = JSON.parse(said);
242
+ const short = name.slice(0, name.length - ORDER.length);
243
+ if (outside(one.root, order.at)) {
244
+ reply(one.dir, short, {
245
+ answered: 'refused',
246
+ because: order.at + ' is outside the folder this command was pointed at, and nothing outside it is ever asked of the machine answering.',
247
+ });
248
+ continue;
249
+ }
250
+ const asked = { ...order, at: relative(one.root, order.at) };
251
+ const due = one.replaying.shift();
252
+ if (due !== undefined) {
253
+ if (told(due.order) === told(asked)) {
254
+ reply(one.dir, short, due.answered);
255
+ continue;
256
+ }
257
+ one.replaying = [];
258
+ one.err +=
259
+ 'thread: this command was carried on here by running it again and handing it the answers it was given before, ' +
260
+ 'and this time it asked for ' + plainly(asked) + ' where before it asked for ' + plainly(due.order) + '. A command ' +
261
+ 'that does not ask the same things twice cannot be carried on from its answers, so it was stopped. Run it again.\n';
262
+ one.stop?.();
263
+ continue;
264
+ }
265
+ one.pending = short;
266
+ hand(one, still(one, [asked]));
267
+ }
268
+ }, TICK);
269
+ }
270
+ function next(one, within) {
271
+ const held = one.parked.shift();
272
+ if (held !== undefined)
273
+ return Promise.resolve(held);
274
+ return new Promise((settle) => {
275
+ const done = { is: false };
276
+ const mine = (ran) => {
277
+ if (done.is)
278
+ return;
279
+ done.is = true;
280
+ settle(ran);
281
+ };
282
+ one.waiting.push(mine);
283
+ if (within === undefined)
284
+ return;
285
+ setTimeout(() => {
286
+ if (done.is)
287
+ return;
288
+ done.is = true;
289
+ one.waiting = one.waiting.filter((each) => each !== mine);
290
+ settle(still(one, []));
291
+ }, Math.max(1_000, within - MARGIN));
292
+ });
293
+ }
294
+ function begun(word, args, root, hears, called, recording = []) {
295
+ const of = called ?? randomBytes(6).toString('hex');
296
+ const dir = join(tmpdir(), SERVED, randomBytes(6).toString('hex'));
297
+ writeFileSync(join(dir, 'channel'), '', 'utf8');
298
+ const one = { of, dir, root, out: '', err: '', why: '', pending: '', waiting: [], parked: [], replaying: [...recording], handed: recording.length };
299
+ const child = spawn(execPath, [...CLI, word, ...args], {
300
+ cwd: OWN,
301
+ shell: false,
302
+ env: { ...env, [CHANNEL]: dir, [FOLDER]: root, [SIGNING]: signing(), NODE_OPTIONS: guarded() },
303
+ });
304
+ one.stop = () => child.kill();
305
+ child.stdout.on('data', (chunk) => (one.out += chunk.toString()));
306
+ child.stderr.on('data', (chunk) => (one.err += chunk.toString()));
307
+ child.on('error', (thrown) => (one.why = thrown.message));
308
+ child.on('close', (code, killed) => {
309
+ if (one.watch !== undefined)
310
+ clearInterval(one.watch);
311
+ serving.delete(of);
312
+ rmSync(dir, { recursive: true, force: true });
313
+ hand(one, { there: one.why === '', ok: one.why === '' && code === 0, code: code ?? 1, out: one.out, err: one.err, killed, why: one.why });
314
+ });
315
+ child.stdin.end(hears ?? '');
316
+ watching(one);
317
+ serving.set(of, one);
318
+ return one;
319
+ }
320
+ const UNPLACED = ' against, so it did not start. A command on this server runs against the folder the person gave and nowhere else.';
321
+ function counted(one, held) {
322
+ const asks = held.asks ?? [];
323
+ if (asks.length === 0)
324
+ return held;
325
+ one.handed += asks.length;
326
+ one.last = held;
327
+ return held;
328
+ }
329
+ async function served(word, args, within, how) {
330
+ const of = how?.of;
331
+ if (of !== undefined) {
332
+ const one = serving.get(of);
333
+ if (one === undefined) {
334
+ const recording = how?.recording;
335
+ if (recording === undefined)
336
+ return lost(of);
337
+ const root = how?.at ?? '';
338
+ if (root === '')
339
+ return nowhere('nothing said which folder to run thread ' + word + UNPLACED);
340
+ const again = begun(word, args, root, how?.hears, of, recording);
341
+ return counted(again, await next(again, within));
342
+ }
343
+ const answering = how?.answering;
344
+ if (answering !== undefined && answering < one.handed && one.last !== undefined)
345
+ return one.last;
346
+ const given = (how?.answered ?? [])[0];
347
+ if (one.pending !== '' && given !== undefined) {
348
+ reply(one.dir, one.pending, given);
349
+ one.pending = '';
350
+ }
351
+ return counted(one, await next(one, within));
352
+ }
353
+ const root = how?.at ?? '';
354
+ if (root === '')
355
+ return nowhere('nothing said which folder to run thread ' + word + UNPLACED);
356
+ const fresh = begun(word, args, root, how?.hears);
357
+ return counted(fresh, await next(fresh, within));
358
+ }
359
+ export function running(name, subcommands, at) {
360
+ const out = {};
361
+ for (const [key, word] of Object.entries(subcommands)) {
362
+ out[key] =
363
+ name === THING
364
+ ? async (args, shows, within, how) => served(word, args, within, how)
365
+ : async (args, shows, within, how) => {
366
+ const where = how?.at ?? at;
367
+ const program = programFor(name, where);
368
+ if ((shows ?? false) !== false)
369
+ return handed(where, program, [word, ...args], shows ?? false, within, how?.hears);
370
+ return await started(program, [word, ...args], { at: where, ...(within === undefined ? {} : { within }), ...(how?.hears === undefined ? {} : { hears: how.hears }) });
371
+ };
372
+ }
373
+ return out;
374
+ }
375
+ function sheet(at) {
376
+ const path = inTree(findTree(at), 'targets.ts');
377
+ return existsSync(path) ? valuesIn(readFileSync(path, 'utf8')) : {};
378
+ }
379
+ export function expansions(at) {
380
+ const held = sheet(at);
381
+ return (held.TARGETS ?? [])
382
+ .filter((one) => one.id.startsWith(REACH.cli))
383
+ .map((one) => ({ program: one.id.slice(REACH.cli.length), target: one, calls: (held.CALLS ?? []).filter((each) => each.of === one.id) }));
384
+ }
385
+ export function calls(target, at) {
386
+ const named = {};
387
+ for (const one of sheet(at).CALLS ?? [])
388
+ if (one.of === target)
389
+ named[one.id.replace(CALL_PREFIX, '')] = one.path;
390
+ return running(target.replace(REACH.cli, ''), named, at);
391
+ }
392
+ export { LOCKFILES };
393
+ export const manager = (into) => managerOf(into, existsSync);
394
+ const ADDS = { pnpm: 'add', yarn: 'add', bun: 'add', npm: 'install' };
395
+ export function adding(into) {
396
+ const tool = manager(into);
397
+ const verb = ADDS[tool];
398
+ if (verb === undefined) {
399
+ throw new Error(tool + ' is what the lockfile in ' + into + ' picks, and nothing here knows the word it adds a package with.');
400
+ }
401
+ return [tool, verb];
402
+ }
403
+ export function needing(into, needs) {
404
+ const manifest = join(into, 'package.json');
405
+ const was = readFileSync(manifest, 'utf8');
406
+ const parsed = JSON.parse(was);
407
+ const named = { ...parsed.devDependencies, ...parsed.dependencies };
408
+ const added = Object.keys(needs).filter((one) => named[one] === undefined).sort();
409
+ if (added.length === 0)
410
+ return [];
411
+ const dependencies = { ...parsed.dependencies };
412
+ for (const one of added)
413
+ dependencies[one] = needs[one] ?? 'latest';
414
+ writeFileSync(manifest, `${JSON.stringify({ ...parsed, dependencies }, null, 2)}\n`, 'utf8');
415
+ try {
416
+ installing(into);
417
+ }
418
+ catch (thrown) {
419
+ writeFileSync(manifest, was, 'utf8');
420
+ throw new Error(`${added.join(', ')} could not be fetched — ${thrown instanceof Error ? thrown.message : String(thrown)} ` +
421
+ 'package.json is as it was, so nothing here names a package that is not on disk.');
422
+ }
423
+ return added;
424
+ }
425
+ export function installing(at) {
426
+ if (attached())
427
+ return here().fetch(at);
428
+ const tool = manager(at);
429
+ const ran = starts(programFor(PACKAGER, at), ['install'], { at });
430
+ const said = (ran.out + ran.err).trim();
431
+ if (!ran.there) {
432
+ throw new Error(tool + ' is what the lockfile in ' + at + ' picks, and it is not on this machine, so nothing here can fetch ' +
433
+ 'what that tree depends on until that changes.');
434
+ }
435
+ if (!ran.ok) {
436
+ throw new Error(tool + ' could not install what ' + at + ' depends on. It said: ' +
437
+ (said === '' ? 'nothing, and exited ' + String(ran.code) : said));
438
+ }
439
+ return said;
440
+ }