@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
@@ -1,12 +1,12 @@
1
- import { spawnSync } from 'node:child_process';
2
- import { attached, readdirSync, readFileSync, writeFileSync } from "../../core/files.js";
1
+ import { starts } from '../../integrations/cli.js';
2
+ import { attached, readdirSync, readFileSync, writeFileSync } from '../../integrations/disk.js';
3
3
  import { createRequire } from 'node:module';
4
4
  import { dirname, join, resolve } from 'node:path';
5
5
  import { argv, execPath, stderr, stdout } from 'node:process';
6
- import { exit } from "../../core/invoked.js";
7
- import { ROOT, THREAD_AT, descend } from "../../core/descend.js";
8
- import { MANIFEST } from "../../core/init.js";
9
- import { forbids, runChecker } from "../../core/finding.js";
6
+ import { exit } from '../../core/invoked.js';
7
+ import { ROOT, THREAD_AT, descend } from '../../core/descend.js';
8
+ import { MANIFEST } from '../../core/init.js';
9
+ import { forbids, runChecker } from '../../core/finding.js';
10
10
  function refuse(why) {
11
11
  stderr.write(`compiler: ${why}\n`);
12
12
  exit(1);
@@ -77,7 +77,8 @@ if (!held.declares) {
77
77
  refuse('no TypeScript file in this tree is declared by anything, so every one of them would be left out ' +
78
78
  'and the compiler would pass by reading nothing. Declare something with `thread create` first.');
79
79
  }
80
- const leave = [...held.out].sort();
80
+ const NEXT = '.next';
81
+ const leave = [...new Set([...held.out, NEXT])].sort();
81
82
  let current;
82
83
  try {
83
84
  current = JSON.parse(readFileSync(PATH, 'utf8'));
@@ -92,9 +93,7 @@ if (argv.includes('--check')) {
92
93
  if (!has) {
93
94
  findings.push({
94
95
  file: AT,
95
- detail: leave.length === 0
96
- ? 'leaves out paths this tree declares something under, so the compiler is not reading all of this app'
97
- : `does not leave out ${String(leave.length)} path(s) nothing in this tree declares, so the compiler is holding this app to code it never wrote`,
96
+ detail: `does not leave out ${String(leave.length)} path(s) nothing in this tree declares, so the compiler is holding this app to code it never wrote`,
98
97
  instead: 'run `thread compiler`. What the compiler reads is derived from what the tree declares — an edit here is a declaration somebody skipped, and a path put here by hand is taken back out on the next settle',
99
98
  });
100
99
  }
@@ -120,17 +119,15 @@ if (argv.includes('--check')) {
120
119
  'passed against the wrong machine says nothing about this one.\n');
121
120
  exit(1);
122
121
  }
123
- const built = spawnSync(execPath, [cli, '--noEmit'], { cwd: ROOT, stdio: 'inherit' });
124
- if (built.error !== undefined)
125
- refuse(`the compiler could not be started — ${built.error.message}.`);
126
- exit(built.status ?? 1);
122
+ const built = starts(execPath, [cli, '--noEmit'], { at: ROOT, shows: true });
123
+ if (!built.there)
124
+ refuse(`the compiler could not be started — ${built.why}.`);
125
+ exit(built.code);
127
126
  }
128
127
  if (has) {
129
128
  stdout.write(`compiler: ${AT} already leaves out exactly what this tree declares nothing under.\n`);
130
129
  exit(0);
131
130
  }
132
131
  writeFileSync(PATH, `${wanted}\n`);
133
- stdout.write(leave.length === 0
134
- ? `compiler: wrote ${AT} — every path here has something declared under it, so none is left out.\n`
135
- : `compiler: wrote ${AT} — ${String(leave.length)} path(s) left out, declared by nobody: ${leave.join(', ')}.\n`);
132
+ stdout.write(`compiler: wrote ${AT} — ${String(leave.length)} path(s) left out, declared by nobody: ${leave.join(', ')}.\n`);
136
133
  exit(0);
@@ -1,5 +1,5 @@
1
- import { spawnSync } from 'node:child_process'
2
- import { attached, readdirSync, readFileSync, writeFileSync } from '../../core/files.ts'
1
+ import { starts } from '../../integrations/cli.ts'
2
+ import { attached, readdirSync, readFileSync, writeFileSync } from '../../integrations/disk.ts'
3
3
  import { createRequire } from 'node:module'
4
4
  import { dirname, join, resolve } from 'node:path'
5
5
  import { argv, execPath, stderr, stdout } from 'node:process'
@@ -99,7 +99,9 @@ if (!held.declares) {
99
99
  )
100
100
  }
101
101
 
102
- const leave = [...held.out].sort()
102
+ const NEXT = '.next'
103
+
104
+ const leave = [...new Set([...held.out, NEXT])].sort()
103
105
 
104
106
  let current: Record<string, unknown>
105
107
  try {
@@ -116,10 +118,7 @@ if (argv.includes('--check')) {
116
118
  if (!has) {
117
119
  findings.push({
118
120
  file: AT,
119
- detail:
120
- leave.length === 0
121
- ? 'leaves out paths this tree declares something under, so the compiler is not reading all of this app'
122
- : `does not leave out ${String(leave.length)} path(s) nothing in this tree declares, so the compiler is holding this app to code it never wrote`,
121
+ detail: `does not leave out ${String(leave.length)} path(s) nothing in this tree declares, so the compiler is holding this app to code it never wrote`,
123
122
  instead:
124
123
  'run `thread compiler`. What the compiler reads is derived from what the tree declares — an edit here is a declaration somebody skipped, and a path put here by hand is taken back out on the next settle',
125
124
  })
@@ -151,9 +150,9 @@ if (argv.includes('--check')) {
151
150
  exit(1)
152
151
  }
153
152
 
154
- const built = spawnSync(execPath, [cli, '--noEmit'], { cwd: ROOT, stdio: 'inherit' })
155
- if (built.error !== undefined) refuse(`the compiler could not be started — ${built.error.message}.`)
156
- exit(built.status ?? 1)
153
+ const built = starts(execPath, [cli, '--noEmit'], { at: ROOT, shows: true })
154
+ if (!built.there) refuse(`the compiler could not be started — ${built.why}.`)
155
+ exit(built.code)
157
156
  }
158
157
 
159
158
  if (has) {
@@ -162,9 +161,5 @@ if (has) {
162
161
  }
163
162
 
164
163
  writeFileSync(PATH, `${wanted}\n`)
165
- stdout.write(
166
- leave.length === 0
167
- ? `compiler: wrote ${AT} — every path here has something declared under it, so none is left out.\n`
168
- : `compiler: wrote ${AT} — ${String(leave.length)} path(s) left out, declared by nobody: ${leave.join(', ')}.\n`,
169
- )
164
+ stdout.write(`compiler: wrote ${AT} — ${String(leave.length)} path(s) left out, declared by nobody: ${leave.join(', ')}.\n`)
170
165
  exit(0)
@@ -1,14 +1,13 @@
1
- import { spawnSync } from 'node:child_process';
1
+ import { starts } from '../../integrations/cli.js';
2
2
  import { createHash } from 'node:crypto';
3
- import { readFileSync as bytesAt } from 'node:fs';
4
3
  import { join } from 'node:path';
5
4
  import { argv, execPath, stderr, stdout } from 'node:process';
6
- import { descend } from "../../core/descend.js";
7
- import { attached, existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from "../../core/files.js";
8
- import { LOADER, exit } from "../../core/invoked.js";
9
- import { valuesIn } from "../../core/rows.js";
10
- import { ORGANISATION, ours } from "../../core/scope.js";
11
- import { findTree, inTree } from "../../core/tree.js";
5
+ import { descend } from '../../core/descend.js';
6
+ import { attached, existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from '../../integrations/disk.js';
7
+ import { LOADER, exit } from '../../core/invoked.js';
8
+ import { valuesIn } from '../../core/rows.js';
9
+ import { ORGANISATION, ours } from '../../core/scope.js';
10
+ import { findTree, inTree } from '../../core/tree.js';
12
11
  const TREE = findTree();
13
12
  const ROOT = TREE.at;
14
13
  const STEP_TIMEOUT = 600_000;
@@ -56,10 +55,10 @@ for (const row of writers) {
56
55
  }
57
56
  function ran(runs) {
58
57
  const said = runs.trim().split(/\s+/);
59
- const spent = { cwd: ROOT, stdio: 'inherit', timeout: STEP_TIMEOUT, killSignal: 'SIGKILL' };
58
+ const spent = { at: ROOT, shows: true, within: STEP_TIMEOUT };
60
59
  if (said[0] !== 'thread') {
61
- const shelled = spawnSync(runs, { shell: true, ...spent });
62
- return shelled.error !== undefined ? 1 : (shelled.status ?? 1);
60
+ const other = starts(said[0] ?? '', said.slice(1), spent);
61
+ return other.there ? other.code : 1;
63
62
  }
64
63
  const of = `thread ${said[1] ?? ''}`;
65
64
  const at = written.get(of);
@@ -67,8 +66,8 @@ function ran(runs) {
67
66
  stderr.write(`gate: nothing in this tree is written by \`${of}\`, so this step names a command that does not exist here\n`);
68
67
  return 1;
69
68
  }
70
- const spun = spawnSync(execPath, [...LOADER, join(ROOT, at), ...said.slice(2)], spent);
71
- return spun.error !== undefined ? 1 : (spun.status ?? 1);
69
+ const spun = starts(execPath, [...LOADER, join(ROOT, at), ...said.slice(2)], spent);
70
+ return spun.there ? spun.code : 1;
72
71
  }
73
72
  function named(flag) {
74
73
  const at = argv.indexOf(flag);
@@ -111,8 +110,9 @@ for (const [index, step] of chosen.entries()) {
111
110
  `passed against the wrong machine says nothing about this one.\n`);
112
111
  continue;
113
112
  }
113
+ const began = Date.now();
114
114
  const code = ran(step.runs);
115
- stdout.write(`gate: ${at} — exited ${String(code)}\n`);
115
+ stdout.write(`gate: ${at} — exited ${String(code)} in ${String(Date.now() - began)} ms\n`);
116
116
  if (code === 0)
117
117
  passed += 1;
118
118
  else
@@ -128,7 +128,7 @@ function fingerprint() {
128
128
  const hash = (at) => {
129
129
  if (!existsSync(join(ROOT, at)))
130
130
  return;
131
- of[at] = createHash('sha256').update(bytesAt(join(ROOT, at))).digest('hex').slice(0, 16);
131
+ of[at] = createHash('sha256').update(readFileSync(join(ROOT, at))).digest('hex').slice(0, 16);
132
132
  };
133
133
  const sheets = join(ROOT, '_threads');
134
134
  if (existsSync(sheets)) {
@@ -1,11 +1,10 @@
1
- import { spawnSync } from 'node:child_process'
1
+ import { starts } from '../../integrations/cli.ts'
2
2
  import { createHash } from 'node:crypto'
3
- import { readFileSync as bytesAt } from 'node:fs'
4
3
  import { dirname, join } from 'node:path'
5
4
  import { argv, execPath, stderr, stdout } from 'node:process'
6
5
  import { fileURLToPath } from 'node:url'
7
6
  import { descend } from '../../core/descend.ts'
8
- import { attached, existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from '../../core/files.ts'
7
+ import { attached, existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from '../../integrations/disk.ts'
9
8
  import { LOADER, exit } from '../../core/invoked.ts'
10
9
  import { valuesIn } from '../../core/rows.ts'
11
10
  import { ORGANISATION, ours } from '../../core/scope.ts'
@@ -82,11 +81,11 @@ for (const row of writers) {
82
81
 
83
82
  function ran(runs: string): number {
84
83
  const said = runs.trim().split(/\s+/)
85
- const spent = { cwd: ROOT, stdio: 'inherit', timeout: STEP_TIMEOUT, killSignal: 'SIGKILL' } as const
84
+ const spent = { at: ROOT, shows: true, within: STEP_TIMEOUT } as const
86
85
 
87
86
  if (said[0] !== 'thread') {
88
- const shelled = spawnSync(runs, { shell: true, ...spent })
89
- return shelled.error !== undefined ? 1 : (shelled.status ?? 1)
87
+ const other = starts(said[0] ?? '', said.slice(1), spent)
88
+ return other.there ? other.code : 1
90
89
  }
91
90
 
92
91
  const of = `thread ${said[1] ?? ''}`
@@ -96,8 +95,8 @@ function ran(runs: string): number {
96
95
  return 1
97
96
  }
98
97
 
99
- const spun = spawnSync(execPath, [...LOADER, join(ROOT, at), ...said.slice(2)], spent)
100
- return spun.error !== undefined ? 1 : (spun.status ?? 1)
98
+ const spun = starts(execPath, [...LOADER, join(ROOT, at), ...said.slice(2)], spent)
99
+ return spun.there ? spun.code : 1
101
100
  }
102
101
 
103
102
  function named(flag: string): readonly string[] | undefined {
@@ -151,9 +150,10 @@ for (const [index, step] of chosen.entries()) {
151
150
  continue
152
151
  }
153
152
 
153
+ const began = Date.now()
154
154
  const code = ran(step.runs)
155
155
 
156
- stdout.write(`gate: ${at} — exited ${String(code)}\n`)
156
+ stdout.write(`gate: ${at} — exited ${String(code)} in ${String(Date.now() - began)} ms\n`)
157
157
  if (code === 0) passed += 1
158
158
  else failed.push(step)
159
159
  }
@@ -169,7 +169,7 @@ function fingerprint(): { readonly of: Record<string, string>; readonly versions
169
169
  const of: Record<string, string> = {}
170
170
  const hash = (at: string): void => {
171
171
  if (!existsSync(join(ROOT, at))) return
172
- of[at] = createHash('sha256').update(bytesAt(join(ROOT, at))).digest('hex').slice(0, 16)
172
+ of[at] = createHash('sha256').update(readFileSync(join(ROOT, at))).digest('hex').slice(0, 16)
173
173
  }
174
174
  const sheets = join(ROOT, '_threads')
175
175
  if (existsSync(sheets)) {
@@ -1,11 +1,11 @@
1
1
  import { argv, stderr, stdout } from 'node:process';
2
- import { exit } from "../../core/invoked.js";
3
- import { uncompiled } from "../../core/descend.js";
4
- import { THREAD_AT, descend, refusals, trackedFiles, unthreaded } from "../check-threads.js";
5
- import { CONSTRAINTS } from "../constraint.js";
6
- import { ruleMessage } from "../lint.js";
7
- import { ROOT, load, rules } from "../slopnator.js";
8
- import { sweep, tracked as governed } from "../sweep.js";
2
+ import { exit } from '../../core/invoked.js';
3
+ import { uncompiled } from '../../core/descend.js';
4
+ import { THREAD_AT, descend, refusals, trackedFiles, unthreaded } from '../check-threads.js';
5
+ import { CONSTRAINTS } from '../constraint.js';
6
+ import { ruleMessage } from '../lint.js';
7
+ import { ROOT, load, rules } from '../slopnator.js';
8
+ import { sweep, tracked as governed } from '../sweep.js';
9
9
  const WITHIN = '--in';
10
10
  const CHECK = '--check';
11
11
  const checking = argv.includes(CHECK);
@@ -1,53 +1,31 @@
1
- import { spawnSync } from 'node:child_process';
2
- import { existsSync, readFileSync } from "../../core/files.js";
3
- import { valuesIn } from "../../core/rows.js";
1
+ import { calls, starts } from '../../integrations/cli.js';
2
+ import { existsSync, readFileSync } from '../../integrations/disk.js';
3
+ import { valuesIn } from '../../core/rows.js';
4
4
  import { join } from 'node:path';
5
5
  import { argv, env, execPath, stderr, stdout } from 'node:process';
6
- import { TYPED } from "../../core/answers.js";
7
- import { CLI, exit } from "../../core/invoked.js";
8
- import { named } from "../../core/scope.js";
9
- import { findTree, inTree } from "../../core/tree.js";
10
- import { opened, sealedIn } from "../../integrations/vault.js";
6
+ import { CLI, exit } from '../../core/invoked.js';
7
+ import { THING as TYPED, named } from '../../core/scope.js';
8
+ import { findTree, inTree } from '../../core/tree.js';
9
+ import { placedAt } from '../../integrations/target.js';
10
+ import { opened, sealedIn } from '../../integrations/vault.js';
11
11
  const TREE = findTree();
12
12
  const ROOT = TREE.at;
13
13
  const STEP_TIMEOUT = 900_000;
14
- const REGISTRY = '--registry';
15
- const DEFAULT = 'https://registry.npmjs.org';
14
+ const REGISTRY = 'ht_registry';
16
15
  const CHECKS = [
17
16
  {
18
17
  id: 'gate',
19
18
  runs: 'thread gate',
20
19
  because: 'every step this tree declares, in the order it declares them, which is where the descent and the sweep are',
21
20
  },
22
- {
23
- id: 'lint',
24
- runs: 'pnpm exec eslint .',
25
- because: 'the rules that live on the lint surface, which is the only one carrying a fixer the sweep can report but not repair',
26
- },
27
21
  ];
28
- const MINE = /^(?:npx |pnpm )?thread /;
29
- function run(what, extra) {
30
- const ours = MINE.exec(what);
31
- if (ours !== null) {
32
- const words = what.slice(ours[0].length).split(/\s+/).filter((one) => one !== '');
33
- const ran = spawnSync(execPath, [...CLI, ...words], {
34
- cwd: ROOT,
35
- stdio: 'inherit',
36
- timeout: STEP_TIMEOUT,
37
- killSignal: 'SIGKILL',
38
- env: extra === undefined ? env : { ...env, ...extra },
39
- });
40
- return ran.error !== undefined ? 1 : (ran.status ?? 1);
41
- }
42
- const result = spawnSync(what, {
43
- shell: true,
44
- cwd: ROOT,
45
- stdio: 'inherit',
46
- timeout: STEP_TIMEOUT,
47
- killSignal: 'SIGKILL',
48
- env: extra === undefined ? env : { ...env, ...extra },
49
- });
50
- return result.error !== undefined ? 1 : (result.status ?? 1);
22
+ const PREFIX = /^(?:npx|pnpm)$/;
23
+ const words = (said) => said.split(/\s+/).filter((one) => one !== '');
24
+ function run(given, extra) {
25
+ const mine = given[0] === 'thread' ? 1 : PREFIX.test(given[0] ?? '') && given[1] === 'thread' ? 2 : 0;
26
+ const how = { at: ROOT, shows: true, within: STEP_TIMEOUT, holds: extra === undefined ? env : { ...env, ...extra } };
27
+ const went = mine === 0 ? starts(given[0] ?? '', given.slice(1), how) : starts(execPath, [...CLI, ...given.slice(mine)], how);
28
+ return went.there ? went.code : 1;
51
29
  }
52
30
  function refuse(id, code, because, runs) {
53
31
  stderr.write(`\npublish: REFUSED — \`${id}\` exited ${String(code)}. NOTHING was published.\n`);
@@ -56,10 +34,9 @@ function refuse(id, code, because, runs) {
56
34
  stderr.write(`publish: second copy of a refusal drifts from the first. Run \`${runs}\` alone to work on it.\n`);
57
35
  exit(1);
58
36
  }
59
- const flag = argv.indexOf(REGISTRY);
60
- const registry = flag === -1 ? DEFAULT : (argv[flag + 1] ?? '');
61
- if (registry === '' || registry.startsWith('-')) {
62
- stderr.write(`thread publish ${REGISTRY} <url> where the packages go. Leave it off for ${DEFAULT}.\n`);
37
+ const given = argv.indexOf('--registry');
38
+ if (given !== -1) {
39
+ stderr.write('thread publish takes no url. Where the packages go is the address on the ht_registry row in _threads/targets.ts.\n');
63
40
  stderr.write('\nit builds, then runs every check, then publishes. A check that fails publishes nothing.\n');
64
41
  exit(1);
65
42
  }
@@ -70,6 +47,12 @@ const declared = existsSync(secrets)
70
47
  ? (valuesIn(readFileSync(secrets)).SECRETS ?? [])
71
48
  : [];
72
49
  const vaulted = declared.some((one) => one.id === TOKEN);
50
+ const targets = inTree(TREE, 'targets.ts');
51
+ const registry = placedAt(existsSync(targets) ? (valuesIn(readFileSync(targets)).TARGETS ?? []) : [], REGISTRY).replace(/[/]$/, '');
52
+ if (registry === '') {
53
+ stderr.write('\npublish: no target row says where the registry is, so there is nowhere for these packages to go. Give ' + REGISTRY + ' an address in _threads/targets.ts, the absolute url of the registry. NOTHING was published.\n');
54
+ exit(1);
55
+ }
73
56
  if (vaulted && !sealedIn(ROOT, PRODUCTION).includes(TOKEN)) {
74
57
  stderr.write(`\npublish: ${TOKEN} is declared in _threads/secrets.ts and has no value sealed for ${PRODUCTION}, so nothing was checked and NOTHING was published.\n`);
75
58
  stderr.write(`publish: run \`thread create secret set ${TOKEN}\` at a terminal and paste the registry token, or take the row out to publish with the login this machine holds.\n`);
@@ -96,7 +79,7 @@ stdout.write(vaulted
96
79
  ? `publish: ${TOKEN} is declared and sealed for ${PRODUCTION}. It is opened only after every check passes, and handed to pnpm as its auth setting for ${registry}.\n`
97
80
  : `publish: no row declares ${TOKEN}, so this publish uses ${signedAs}. Declare it with \`thread create secret\` to publish with a token sealed in this repository instead.\n`);
98
81
  stdout.write('publish: deriving and building what the packaging rows state first, so every check below reads the files this release ships rather than the source they were written from.\n');
99
- const made = run(`${TYPED} packaged --build`);
82
+ const made = run(words(`${TYPED} packaged --build`));
100
83
  stdout.write(`publish: packaged exited ${String(made)}\n`);
101
84
  if (made !== 0) {
102
85
  refuse('packaged', made, 'a package whose manifest and release note are not what its rows state would go out describing itself as something nobody declared, and one that did not compile would go out promising files it does not have', `${TYPED} packaged --build`);
@@ -107,28 +90,28 @@ for (const check of CHECKS)
107
90
  for (const [index, check] of CHECKS.entries()) {
108
91
  const at = `check ${String(index + 1)} of ${String(CHECKS.length)}`;
109
92
  stdout.write(`\npublish: ${at} — ${check.runs} (${check.id})\n`);
110
- const code = run(check.runs);
93
+ const code = run(words(check.runs));
111
94
  stdout.write(`publish: ${at} — exited ${String(code)}\n`);
112
95
  if (code !== 0)
113
96
  refuse(check.id, code, check.because, check.runs);
114
97
  }
115
- const numbered = run(`${TYPED} packaged --release`);
98
+ const numbered = run(words(`${TYPED} packaged --release`));
116
99
  stdout.write(`publish: packaged --release exited ${String(numbered)}\n`);
117
100
  if (numbered !== 0) {
118
101
  refuse('packaged', numbered, 'the next release number is written onto the manifests only once every check has passed, and writing it refused, so nothing here carries a number to go out under', `${TYPED} packaged --release`);
119
102
  }
120
103
  const handed = vaulted ? { [setting()]: await tokened() } : undefined;
121
104
  stdout.write(`\npublish: every check passed. Publishing to ${registry} with ${vaulted ? `${TOKEN} from this repository's vault` : signedAs}.\n`);
122
- const sent = run(`pnpm -r publish --registry ${registry} --no-git-checks --access public`, handed);
105
+ const sent = run(words(`pnpm -r publish --registry ${registry} --no-git-checks --access public`), handed);
123
106
  if (sent !== 0) {
124
107
  stderr.write(`\npublish: the checks passed and the publish itself exited ${String(sent)}.\n`);
125
- const back = run(`${TYPED} packaged`);
108
+ const back = run(words(`${TYPED} packaged`));
126
109
  stderr.write(back === 0
127
110
  ? 'publish: the manifests carry the last recorded release again and no note was written, so the next `thread publish` numbers this release once more.\n'
128
111
  : `publish: the manifests still carry the number that did not go out. Run \`${TYPED} packaged\` to put the last recorded release back.\n`);
129
112
  exit(1);
130
113
  }
131
- const recorded = run(`${TYPED} packaged --record`);
114
+ const recorded = run(words(`${TYPED} packaged --record`));
132
115
  stdout.write(`publish: packaged --record exited ${String(recorded)}\n`);
133
116
  if (recorded !== 0) {
134
117
  stderr.write(`\npublish: the packages went out and the note recording them refused to be written, so the next publish would number this release again. Run \`${TYPED} packaged --record\` and read what it says.\n`);
@@ -151,10 +134,9 @@ function versionAt(folder) {
151
134
  return 'no version';
152
135
  }
153
136
  }
154
- function asked(what) {
155
- return (spawnSync('git', what, { cwd: ROOT, encoding: 'utf8' }).stdout ?? '').trim();
156
- }
157
- if (asked(['rev-parse', '--is-inside-work-tree']) !== 'true') {
137
+ const git = calls('cli_git', ROOT);
138
+ const asked = async (what) => (await git.rev_parse(what)).out.trim();
139
+ if ((await asked(['--is-inside-work-tree'])) !== 'true') {
158
140
  stdout.write("\npublish: it's not a repo, so nothing was committed.\n");
159
141
  }
160
142
  else if (shipped.length === 0) {
@@ -162,14 +144,14 @@ else if (shipped.length === 0) {
162
144
  }
163
145
  else {
164
146
  const going = shipped.map((one) => `${named(one.id ?? '')} ${versionAt(one.folder ?? '')}`).join(', ');
165
- const branch = asked(['rev-parse', '--abbrev-ref', 'HEAD']);
147
+ const branch = await asked(['--abbrev-ref', 'HEAD']);
166
148
  for (const one of shipped)
167
- run(`git add ${one.folder ?? ''}`);
168
- if (spawnSync('git', ['diff', '--cached', '--quiet'], { cwd: ROOT }).status === 0) {
149
+ await git.stage([one.folder ?? ''], true, STEP_TIMEOUT);
150
+ if ((await git.diff(['--cached', '--quiet'])).ok) {
169
151
  stdout.write(`\npublish: ${going} — what is on disk is already what is committed, so this release added no artifact.\n`);
170
152
  }
171
153
  else {
172
- const wrote = run(`git commit -m ${JSON.stringify(`thread publish — ${going}`)}`);
154
+ const wrote = (await git.commit(['-m', `thread publish — ${going}`], true, STEP_TIMEOUT)).code;
173
155
  stdout.write(`publish: commit exited ${String(wrote)}\n`);
174
156
  if (wrote !== 0) {
175
157
  stderr.write('\npublish: the packages went out and the files that describe them are not committed, so this release has no record in git.\n');
@@ -179,5 +161,5 @@ else {
179
161
  stdout.write(`publish: committed the derived artifacts to ${branch} — ${going}.\n`);
180
162
  }
181
163
  }
182
- stdout.write(`\npublish: done. What went out was derived, then built, then passed the gate and the lint, in that order. The compile inside \`thread packaged --build\` is the typecheck.\n`);
164
+ stdout.write(`\npublish: done. What went out was derived, then built, then passed the gate, in that order. The compile inside \`thread packaged --build\` is the typecheck.\n`);
183
165
  exit(0);
@@ -1,15 +1,15 @@
1
- import { spawnSync } from 'node:child_process'
2
- import { existsSync, readFileSync } from '../../core/files.ts'
1
+ import { calls, starts } from '../../integrations/cli.ts'
2
+ import { existsSync, readFileSync } from '../../integrations/disk.ts'
3
3
  import { valuesIn } from '../../core/rows.ts'
4
4
  import { join } from 'node:path'
5
5
  import { argv, env, execPath, stderr, stdout } from 'node:process'
6
6
  import { pathToFileURL } from 'node:url'
7
- import { TYPED } from '../../core/answers.ts'
8
7
  import { CLI, exit } from '../../core/invoked.ts'
9
- import { named } from '../../core/scope.ts'
8
+ import { THING as TYPED, named } from '../../core/scope.ts'
10
9
  import { findTree, inTree } from '../../core/tree.ts'
11
10
 
12
11
  import type { Secret } from '../../integrations/secret.ts'
12
+ import { placedAt, type Target } from '../../integrations/target.ts'
13
13
  import { opened, sealedIn } from '../../integrations/vault.ts'
14
14
 
15
15
  const TREE = findTree()
@@ -17,9 +17,7 @@ const ROOT = TREE.at
17
17
 
18
18
  const STEP_TIMEOUT = 900_000
19
19
 
20
- const REGISTRY = '--registry'
21
-
22
- const DEFAULT = 'https://registry.npmjs.org'
20
+ const REGISTRY = 'ht_registry'
23
21
 
24
22
  interface Check {
25
23
  readonly id: string
@@ -33,37 +31,17 @@ const CHECKS: readonly Check[] = [
33
31
  runs: 'thread gate',
34
32
  because: 'every step this tree declares, in the order it declares them, which is where the descent and the sweep are',
35
33
  },
36
- {
37
- id: 'lint',
38
- runs: 'pnpm exec eslint .',
39
- because: 'the rules that live on the lint surface, which is the only one carrying a fixer the sweep can report but not repair',
40
- },
41
34
  ]
42
35
 
43
- const MINE = /^(?:npx |pnpm )?thread /
44
-
45
- function run(what: string, extra?: Record<string, string>): number {
46
- const ours = MINE.exec(what)
47
- if (ours !== null) {
48
- const words = what.slice(ours[0].length).split(/\s+/).filter((one) => one !== '')
49
- const ran = spawnSync(execPath, [...CLI, ...words], {
50
- cwd: ROOT,
51
- stdio: 'inherit',
52
- timeout: STEP_TIMEOUT,
53
- killSignal: 'SIGKILL',
54
- env: extra === undefined ? env : { ...env, ...extra },
55
- })
56
- return ran.error !== undefined ? 1 : (ran.status ?? 1)
57
- }
58
- const result = spawnSync(what, {
59
- shell: true,
60
- cwd: ROOT,
61
- stdio: 'inherit',
62
- timeout: STEP_TIMEOUT,
63
- killSignal: 'SIGKILL',
64
- env: extra === undefined ? env : { ...env, ...extra },
65
- })
66
- return result.error !== undefined ? 1 : (result.status ?? 1)
36
+ const PREFIX = /^(?:npx|pnpm)$/
37
+
38
+ const words = (said: string): readonly string[] => said.split(/\s+/).filter((one) => one !== '')
39
+
40
+ function run(given: readonly string[], extra?: Record<string, string>): number {
41
+ const mine = given[0] === 'thread' ? 1 : PREFIX.test(given[0] ?? '') && given[1] === 'thread' ? 2 : 0
42
+ const how = { at: ROOT, shows: true, within: STEP_TIMEOUT, holds: extra === undefined ? env : { ...env, ...extra } }
43
+ const went = mine === 0 ? starts(given[0] ?? '', given.slice(1), how) : starts(execPath, [...CLI, ...given.slice(mine)], how)
44
+ return went.there ? went.code : 1
67
45
  }
68
46
 
69
47
  function refuse(id: string, code: number, because: string, runs: string): never {
@@ -74,11 +52,10 @@ function refuse(id: string, code: number, because: string, runs: string): never
74
52
  exit(1)
75
53
  }
76
54
 
77
- const flag = argv.indexOf(REGISTRY)
78
- const registry = flag === -1 ? DEFAULT : (argv[flag + 1] ?? '')
55
+ const given = argv.indexOf('--registry')
79
56
 
80
- if (registry === '' || registry.startsWith('-')) {
81
- stderr.write(`thread publish ${REGISTRY} <url> where the packages go. Leave it off for ${DEFAULT}.\n`)
57
+ if (given !== -1) {
58
+ stderr.write('thread publish takes no url. Where the packages go is the address on the ht_registry row in _threads/targets.ts.\n')
82
59
  stderr.write('\nit builds, then runs every check, then publishes. A check that fails publishes nothing.\n')
83
60
  exit(1)
84
61
  }
@@ -95,6 +72,18 @@ const declared = existsSync(secrets)
95
72
 
96
73
  const vaulted = declared.some((one) => one.id === TOKEN)
97
74
 
75
+ const targets = inTree(TREE, 'targets.ts')
76
+
77
+ const registry = placedAt(
78
+ existsSync(targets) ? ((valuesIn(readFileSync(targets)) as { TARGETS?: readonly Target[] }).TARGETS ?? []) : [],
79
+ REGISTRY,
80
+ ).replace(/[/]$/, '')
81
+
82
+ if (registry === '') {
83
+ stderr.write('\npublish: no target row says where the registry is, so there is nowhere for these packages to go. Give ' + REGISTRY + ' an address in _threads/targets.ts, the absolute url of the registry. NOTHING was published.\n')
84
+ exit(1)
85
+ }
86
+
98
87
  if (vaulted && !sealedIn(ROOT, PRODUCTION).includes(TOKEN)) {
99
88
  stderr.write(`\npublish: ${TOKEN} is declared in _threads/secrets.ts and has no value sealed for ${PRODUCTION}, so nothing was checked and NOTHING was published.\n`)
100
89
  stderr.write(`publish: run \`thread create secret set ${TOKEN}\` at a terminal and paste the registry token, or take the row out to publish with the login this machine holds.\n`)
@@ -129,7 +118,7 @@ stdout.write(
129
118
 
130
119
  stdout.write('publish: deriving and building what the packaging rows state first, so every check below reads the files this release ships rather than the source they were written from.\n')
131
120
 
132
- const made = run(`${TYPED} packaged --build`)
121
+ const made = run(words(`${TYPED} packaged --build`))
133
122
  stdout.write(`publish: packaged exited ${String(made)}\n`)
134
123
  if (made !== 0) {
135
124
  refuse(
@@ -147,12 +136,12 @@ for (const [index, check] of CHECKS.entries()) {
147
136
  const at = `check ${String(index + 1)} of ${String(CHECKS.length)}`
148
137
  stdout.write(`\npublish: ${at} — ${check.runs} (${check.id})\n`)
149
138
 
150
- const code = run(check.runs)
139
+ const code = run(words(check.runs))
151
140
  stdout.write(`publish: ${at} — exited ${String(code)}\n`)
152
141
  if (code !== 0) refuse(check.id, code, check.because, check.runs)
153
142
  }
154
143
 
155
- const numbered = run(`${TYPED} packaged --release`)
144
+ const numbered = run(words(`${TYPED} packaged --release`))
156
145
  stdout.write(`publish: packaged --release exited ${String(numbered)}\n`)
157
146
  if (numbered !== 0) {
158
147
  refuse(
@@ -167,11 +156,11 @@ const handed = vaulted ? { [setting()]: await tokened() } : undefined
167
156
 
168
157
  stdout.write(`\npublish: every check passed. Publishing to ${registry} with ${vaulted ? `${TOKEN} from this repository's vault` : signedAs}.\n`)
169
158
 
170
- const sent = run(`pnpm -r publish --registry ${registry} --no-git-checks --access public`, handed)
159
+ const sent = run(words(`pnpm -r publish --registry ${registry} --no-git-checks --access public`), handed)
171
160
 
172
161
  if (sent !== 0) {
173
162
  stderr.write(`\npublish: the checks passed and the publish itself exited ${String(sent)}.\n`)
174
- const back = run(`${TYPED} packaged`)
163
+ const back = run(words(`${TYPED} packaged`))
175
164
  stderr.write(
176
165
  back === 0
177
166
  ? 'publish: the manifests carry the last recorded release again and no note was written, so the next `thread publish` numbers this release once more.\n'
@@ -180,7 +169,7 @@ if (sent !== 0) {
180
169
  exit(1)
181
170
  }
182
171
 
183
- const recorded = run(`${TYPED} packaged --record`)
172
+ const recorded = run(words(`${TYPED} packaged --record`))
184
173
  stdout.write(`publish: packaged --record exited ${String(recorded)}\n`)
185
174
  if (recorded !== 0) {
186
175
  stderr.write(`\npublish: the packages went out and the note recording them refused to be written, so the next publish would number this release again. Run \`${TYPED} packaged --record\` and read what it says.\n`)
@@ -212,24 +201,24 @@ function versionAt(folder: string): string {
212
201
  }
213
202
  }
214
203
 
215
- function asked(what: readonly string[]): string {
216
- return (spawnSync('git', what, { cwd: ROOT, encoding: 'utf8' }).stdout ?? '').trim()
217
- }
204
+ const git = calls('cli_git', ROOT)
205
+
206
+ const asked = async (what: readonly string[]): Promise<string> => (await git.rev_parse(what)).out.trim()
218
207
 
219
- if (asked(['rev-parse', '--is-inside-work-tree']) !== 'true') {
208
+ if ((await asked(['--is-inside-work-tree'])) !== 'true') {
220
209
  stdout.write("\npublish: it's not a repo, so nothing was committed.\n")
221
210
  } else if (shipped.length === 0) {
222
211
  stdout.write('\npublish: no packaging row names a folder, so there is nothing derived here to commit.\n')
223
212
  } else {
224
213
  const going = shipped.map((one) => `${named(one.id ?? '')} ${versionAt(one.folder ?? '')}`).join(', ')
225
- const branch = asked(['rev-parse', '--abbrev-ref', 'HEAD'])
214
+ const branch = await asked(['--abbrev-ref', 'HEAD'])
226
215
 
227
- for (const one of shipped) run(`git add ${one.folder ?? ''}`)
216
+ for (const one of shipped) await git.stage([one.folder ?? ''], true, STEP_TIMEOUT)
228
217
 
229
- if (spawnSync('git', ['diff', '--cached', '--quiet'], { cwd: ROOT }).status === 0) {
218
+ if ((await git.diff(['--cached', '--quiet'])).ok) {
230
219
  stdout.write(`\npublish: ${going} — what is on disk is already what is committed, so this release added no artifact.\n`)
231
220
  } else {
232
- const wrote = run(`git commit -m ${JSON.stringify(`thread publish — ${going}`)}`)
221
+ const wrote = (await git.commit(['-m', `thread publish — ${going}`], true, STEP_TIMEOUT)).code
233
222
  stdout.write(`publish: commit exited ${String(wrote)}\n`)
234
223
  if (wrote !== 0) {
235
224
  stderr.write('\npublish: the packages went out and the files that describe them are not committed, so this release has no record in git.\n')
@@ -240,5 +229,5 @@ if (asked(['rev-parse', '--is-inside-work-tree']) !== 'true') {
240
229
  }
241
230
  }
242
231
 
243
- stdout.write(`\npublish: done. What went out was derived, then built, then passed the gate and the lint, in that order. The compile inside \`thread packaged --build\` is the typecheck.\n`)
232
+ stdout.write(`\npublish: done. What went out was derived, then built, then passed the gate, in that order. The compile inside \`thread packaged --build\` is the typecheck.\n`)
244
233
  exit(0)