@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,5 +1,5 @@
1
1
  export type Env = 'sandbox' | 'production';
2
- export declare const ENVIRONMENT: readonly [readonly ["run", "x-request-id"], readonly ["address", "x-forwarded-for"], readonly ["device", "user-agent"], readonly ["replay", "idempotency-key"]];
2
+ export declare const ENVIRONMENT: readonly [readonly ['run', 'x-request-id', 'crypto.randomUUID()'], readonly ['address', 'x-forwarded-for', null], readonly ['device', 'user-agent', null], readonly ['replay', 'idempotency-key', null], readonly ['moment', null, 'new Date().toISOString()']];
3
3
  export type Environment = {
4
4
  readonly [K in (typeof ENVIRONMENT)[number][0]]?: string;
5
5
  };
@@ -1,8 +1,9 @@
1
1
  export const ENVIRONMENT = [
2
- ['run', 'x-request-id'],
3
- ['address', 'x-forwarded-for'],
4
- ['device', 'user-agent'],
5
- ['replay', 'idempotency-key'],
2
+ ['run', 'x-request-id', 'crypto.randomUUID()'],
3
+ ['address', 'x-forwarded-for', null],
4
+ ['device', 'user-agent', null],
5
+ ['replay', 'idempotency-key', null],
6
+ ['moment', null, 'new Date().toISOString()'],
6
7
  ];
7
8
  export const PUBLIC_ROLE = 'role_public';
8
9
  export const ANONYMOUS = { id: null, roles: [PUBLIC_ROLE], entitlements: [] };
@@ -1,10 +1,11 @@
1
1
  export type Env = 'sandbox' | 'production'
2
2
 
3
3
  export const ENVIRONMENT = [
4
- ['run', 'x-request-id'],
5
- ['address', 'x-forwarded-for'],
6
- ['device', 'user-agent'],
7
- ['replay', 'idempotency-key'],
4
+ ['run', 'x-request-id', 'crypto.randomUUID()'],
5
+ ['address', 'x-forwarded-for', null],
6
+ ['device', 'user-agent', null],
7
+ ['replay', 'idempotency-key', null],
8
+ ['moment', null, 'new Date().toISOString()'],
8
9
  ] as const
9
10
 
10
11
  export type Environment = { readonly [K in (typeof ENVIRONMENT)[number][0]]?: string }
@@ -14,13 +14,6 @@ export interface Attaching {
14
14
  readonly writes: readonly Writing[];
15
15
  readonly declares: string;
16
16
  readonly rows?: readonly Appending[];
17
- readonly retires?: readonly {
18
- readonly into: string;
19
- readonly list: string;
20
- readonly id: string;
21
- readonly made?: string;
22
- readonly why: string;
23
- }[];
24
17
  readonly attaches?: readonly string[];
25
18
  readonly scripts?: Readonly<Record<string, string>>;
26
19
  readonly needs?: Readonly<Record<string, string>>;
@@ -6,14 +6,16 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
6
6
  }
7
7
  return path;
8
8
  };
9
- import { existsSync, fetching, readFileSync, rmSync, writeFileSync } from "./files.js";
9
+ import { installing, needing } from '../integrations/cli.js';
10
+ import { attached, existsSync, readFileSync, rmSync, writeFileSync } from '../integrations/disk.js';
10
11
  import { createRequire } from 'node:module';
11
12
  import { join, relative, resolve } from 'node:path';
12
13
  import { stdout } from 'node:process';
13
- import { LISTS } from "./descend.js";
14
- import { ROOT, TREE, root as rooted } from "./init.js";
15
- import { STATED, holdsRow, listBounds, quoted, reconciled, rowsIn, withRow, withoutRow } from "./rows.js";
16
- import { ours as isOurs } from "./scope.js";
14
+ import { LISTS } from './descend.js';
15
+ import { ROOT, SHAPED, TREE, root as rooted } from './init.js';
16
+ import { BESIDE } from './invoked.js';
17
+ import { STATED, holdsRow, listBounds, quoted, reconciled, rowsIn, withRow, withoutRow } from './rows.js';
18
+ import { idOf, installed, ours as isOurs } from './scope.js';
17
19
  const SHAPE = /export interface [A-Za-z0-9_]+ extends Threaded \{[\s\S]*?\n\}\n/;
18
20
  const MEMBERS = 'MEMBERS';
19
21
  const DOOR = '/attach';
@@ -64,12 +66,21 @@ export async function attaches(into, name) {
64
66
  return false;
65
67
  }
66
68
  }
69
+ function shipped(spec, owner) {
70
+ const rest = spec.slice(owner.length + 1);
71
+ const named = idOf(owner) ?? owner;
72
+ const part = rest === DOOR.slice(1) ? named : String(rest.split('/')[0]);
73
+ return new URL('../' + part + '/' + BESIDE('attach'), import.meta.url).href;
74
+ }
67
75
  async function attaching(into, name) {
68
76
  const spec = name.endsWith(DOOR) ? name : `${name}${DOOR}`;
69
77
  const owner = packageOf(name);
70
78
  let held;
71
79
  try {
72
- held = (await import(__rewriteRelativeImportExtension(createRequire(join(into, 'package.json')).resolve(spec))));
80
+ if (attached() && isOurs(owner))
81
+ held = (await import(__rewriteRelativeImportExtension(shipped(spec, owner))));
82
+ else
83
+ held = (await import(__rewriteRelativeImportExtension(createRequire(join(into, 'package.json')).resolve(spec))));
73
84
  }
74
85
  catch {
75
86
  if (!existsSync(join(into, 'node_modules', owner, 'package.json'))) {
@@ -123,7 +134,7 @@ function acquire(into, owner) {
123
134
  stdout.write(`thread: ${owner} is not here yet, so this is fetching it. Nothing has to be typed for that.\n`);
124
135
  writeFileSync(manifest, `${JSON.stringify({ ...parsed, dependencies: { ...parsed.dependencies, [owner]: 'latest' } }, null, 2)}\n`, 'utf8');
125
136
  try {
126
- fetching(into);
137
+ installing(into);
127
138
  }
128
139
  catch (thrown) {
129
140
  writeFileSync(manifest, was, 'utf8');
@@ -160,7 +171,6 @@ export async function attach(into, name, touched = new Set(), under = []) {
160
171
  await attach(into, on, touched, [...under, name]);
161
172
  }
162
173
  const plan = new Map();
163
- const retired = [];
164
174
  const reshaped = [];
165
175
  const noticed = [];
166
176
  const held = readFileSync(root, 'utf8');
@@ -168,7 +178,6 @@ export async function attach(into, name, touched = new Set(), under = []) {
168
178
  const ours = [...one.declares.matchAll(/\bid: '([^']+)'/g)].map((found) => found[1]);
169
179
  const mine = declares !== undefined &&
170
180
  (holdsRow(held, declares, one.id) || ours.some((id) => id !== undefined && holdsRow(held, declares, id)));
171
- const installed = (at) => at.startsWith('node_modules/') && isOurs(at.split('/').slice(1, 3).join('/'));
172
181
  const pathIn = (source) => {
173
182
  const listed = `const HELD = {\n declares: [\n${source}\n ],\n}\n`;
174
183
  const span = listBounds(listed, 'declares');
@@ -305,14 +314,6 @@ export async function attach(into, name, touched = new Set(), under = []) {
305
314
  return false;
306
315
  return !text.slice(where.open, where.close).includes(each.source.trim().replace(/,$/, ''));
307
316
  }).length;
308
- const withdrawing = (one.retires ?? []).filter((gone) => {
309
- const at = join(dir, gone.into);
310
- if (!existsSync(at))
311
- return false;
312
- const text = plan.get(at) ?? readFileSync(at, 'utf8');
313
- const where = listBounds(text, gone.list);
314
- return where !== undefined && holdsRow(text, where, gone.id);
315
- }).length;
316
317
  throw new Error(`${name} brings a noun called \`${coined}\`, and this tree already declares something by that name. One ` +
317
318
  `word, one meaning: if this attached, \`thread create ${coined}\` would run the package's command and the ` +
318
319
  `thing you declared would be reachable only by its mark.\n\n` +
@@ -321,11 +322,10 @@ export async function attach(into, name, touched = new Set(), under = []) {
321
322
  `Nothing was written.\n\n` +
322
323
  `A refusal here names a command you can actually run. If the one above does not fit what you are trying ` +
323
324
  `to do, that is a gap in this framework rather than something to work around — say so.` +
324
- (waiting + withdrawing === 0
325
+ (waiting === 0
325
326
  ? ''
326
327
  : `\n\nAn attach is all or nothing, so this is also holding back everything else ${name} would have ` +
327
- `delivered: ${String(waiting)} row(s) this tree does not hold at the version installed` +
328
- `${withdrawing === 0 ? '' : ` and ${String(withdrawing)} it has withdrawn`}. None of that arrives until the ` +
328
+ `delivered: ${String(waiting)} row(s) this tree does not hold at the version installed. None of that arrives until the ` +
329
329
  `collision above is cleared, and nothing else will tell you — \`npm install\` will go on reporting this ` +
330
330
  `tree current.`));
331
331
  }
@@ -347,28 +347,6 @@ export async function attach(into, name, touched = new Set(), under = []) {
347
347
  throw new UnattachableError(name, `wants a row in \`${row.list}\`, which ${row.into} does not export`);
348
348
  plan.set(target, withRow(held, bounds, row.source));
349
349
  }
350
- for (const gone of one.retires ?? []) {
351
- const shipped = (one.rows ?? []).find((row) => row.into === gone.into && row.list === gone.list && row.id === gone.id);
352
- if (shipped !== undefined) {
353
- throw new UnattachableError(name, `both ships and retires \`${gone.id}\` in ${gone.into}, so attaching it would add and remove one row`);
354
- }
355
- if (gone.made !== undefined) {
356
- const byproduct = join(into, gone.made);
357
- if (existsSync(byproduct)) {
358
- rmSync(byproduct);
359
- retired.push(`${gone.made} — the file \`${gone.id}\` derived, which nothing writes now`);
360
- }
361
- }
362
- const target = join(dir, gone.into);
363
- if (!existsSync(target) && !plan.has(target))
364
- continue;
365
- const text = plan.get(target) ?? readFileSync(target, 'utf8');
366
- const where = listBounds(text, gone.list);
367
- if (where === undefined || !holdsRow(text, where, gone.id))
368
- continue;
369
- plan.set(target, withoutRow(text, where, gone.id));
370
- retired.push(`${gone.into}: ${gone.id} — ${gone.why}`);
371
- }
372
350
  if (one.scripts !== undefined) {
373
351
  const manifest = join(into, 'package.json');
374
352
  const held = readFileSync(manifest, 'utf8');
@@ -386,29 +364,24 @@ export async function attach(into, name, touched = new Set(), under = []) {
386
364
  }
387
365
  if (one.needs !== undefined) {
388
366
  const manifest = join(into, 'package.json');
389
- const held = plan.get(manifest) ?? readFileSync(manifest, 'utf8');
390
- const parsed = JSON.parse(held);
391
- const needs = { ...parsed.dependencies };
392
- const added = [];
393
- for (const [name, at] of Object.entries(one.needs)) {
394
- if (needs[name] !== undefined)
395
- continue;
396
- needs[name] = at;
397
- added.push(name);
367
+ const was = readFileSync(manifest, 'utf8');
368
+ const scripted = plan.get(manifest);
369
+ if (scripted !== undefined) {
370
+ writeFileSync(manifest, scripted, 'utf8');
371
+ plan.delete(manifest);
372
+ touched.add(relative(into, manifest));
373
+ }
374
+ let added;
375
+ try {
376
+ added = needing(into, one.needs);
377
+ }
378
+ catch (thrown) {
379
+ writeFileSync(manifest, was, 'utf8');
380
+ throw new Error(`${thrown instanceof Error ? thrown.message : String(thrown)} Nothing was attached.`);
398
381
  }
399
382
  if (added.length > 0) {
400
- const next = `${JSON.stringify({ ...parsed, dependencies: needs }, null, 2)}\n`;
401
- const was = readFileSync(manifest, 'utf8');
402
- writeFileSync(manifest, next, 'utf8');
403
383
  touched.add(relative(into, manifest));
404
- stdout.write(`thread: ${name} needs ${added.join(', ')}, so this is fetching ${added.length === 1 ? 'it' : 'them'}. Nothing has to be typed for that.\n`);
405
- try {
406
- fetching(into);
407
- }
408
- catch (thrown) {
409
- writeFileSync(manifest, was, 'utf8');
410
- throw new Error(`${added.join(', ')} could not be fetched — ${thrown instanceof Error ? thrown.message : String(thrown)} Nothing was attached and package.json is as it was.`);
411
- }
384
+ stdout.write(`thread: ${name} needs ${added.join(', ')}, so ${added.length === 1 ? 'it is' : 'they are'} in package.json now and fetched. Nothing has to be typed for that.\n`);
412
385
  }
413
386
  }
414
387
  if (one.ignores !== undefined && one.ignores.length > 0) {
@@ -425,8 +398,6 @@ export async function attach(into, name, touched = new Set(), under = []) {
425
398
  writeFileSync(path, text, 'utf8');
426
399
  touched.add(relative(into, path));
427
400
  }
428
- for (const line of retired)
429
- stdout.write(`thread: retired ${line}\n`);
430
401
  for (const file of reshaped)
431
402
  stdout.write(`thread: reshaped ${file} — what a row may state has changed\n`);
432
403
  for (const id of noticed)
@@ -512,8 +483,8 @@ export async function detach(into, name) {
512
483
  }
513
484
  return [...touched].sort();
514
485
  }
515
- const DESCRIBES = 'The package every tree installs first: the descent, the CLI, and the makers and generators that used to be separate packages.';
516
- const CORE_SOURCE = `import type { Threaded } from '../core/thread.ts'
486
+ const DESCRIBES = 'The package every tree installs first: the descent that reads a tree, the gate that checks it, and the generators every tree runs.';
487
+ const CORE_SOURCE = `import type { Threaded } from '${SHAPED}'
517
488
 
518
489
  export const CORE: Threaded = {
519
490
  id: 'core',
@@ -532,7 +503,7 @@ const SEEDED = {
532
503
  ' {',
533
504
  ' id: \'core\',',
534
505
  ' at: \'_threads/core.ts\',',
535
- ' describes: \'The package every tree installs first: the descent, the CLI, and the makers and generators that used to be separate packages.\',',
506
+ ' describes: \'The package every tree installs first: the descent that reads a tree, the gate that checks it, and the generators every tree runs.\',',
536
507
  ' version: 1,',
537
508
  ' },',
538
509
  ].join('\n'),
@@ -1,12 +1,14 @@
1
- import { existsSync, fetching, readFileSync, rmSync, writeFileSync } from './files.ts'
1
+ import { installing, needing } from '../integrations/cli.ts'
2
+ import { attached, existsSync, readFileSync, rmSync, writeFileSync } from '../integrations/disk.ts'
2
3
  import { createRequire } from 'node:module'
3
4
  import { join, relative, resolve } from 'node:path'
4
5
  import { stdout } from 'node:process'
5
6
 
6
7
  import { LISTS } from './descend.ts'
7
- import { ROOT, TREE, root as rooted } from './init.ts'
8
+ import { ROOT, SHAPED, TREE, root as rooted } from './init.ts'
9
+ import { BESIDE } from './invoked.ts'
8
10
  import { STATED, holdsRow, listBounds, quoted, reconciled, rowsIn, withRow, withoutRow } from './rows.ts'
9
- import { ours as isOurs } from './scope.ts'
11
+ import { idOf, installed, ours as isOurs } from './scope.ts'
10
12
 
11
13
  const SHAPE = /export interface [A-Za-z0-9_]+ extends Threaded \{[\s\S]*?\n\}\n/
12
14
 
@@ -35,16 +37,6 @@ export interface Attaching {
35
37
  readonly declares: string
36
38
  readonly rows?: readonly Appending[]
37
39
 
38
- readonly retires?: readonly {
39
- readonly into: string
40
- readonly list: string
41
- readonly id: string
42
-
43
- readonly made?: string
44
-
45
- readonly why: string
46
- }[]
47
-
48
40
  readonly attaches?: readonly string[]
49
41
 
50
42
  readonly scripts?: Readonly<Record<string, string>>
@@ -108,11 +100,20 @@ export async function attaches(into: string, name: string): Promise<boolean> {
108
100
  }
109
101
  }
110
102
 
103
+ function shipped(spec: string, owner: string): string {
104
+ const rest = spec.slice(owner.length + 1)
105
+ const named = idOf(owner) ?? owner
106
+ const part = rest === DOOR.slice(1) ? named : String(rest.split('/')[0])
107
+ return new URL('../' + part + '/' + BESIDE('attach'), import.meta.url).href
108
+ }
109
+
111
110
  async function attaching(into: string, name: string): Promise<Attaching> {
112
111
  const spec = name.endsWith(DOOR) ? name : `${name}${DOOR}`
113
112
  const owner = packageOf(name)
114
113
  let held: { ATTACH?: Attaching }
115
114
  try {
115
+ if (attached() && isOurs(owner)) held = (await import(shipped(spec, owner))) as { ATTACH?: Attaching }
116
+ else
116
117
  held = (await import(createRequire(join(into, 'package.json')).resolve(spec))) as { ATTACH?: Attaching }
117
118
  } catch {
118
119
  if (!existsSync(join(into, 'node_modules', owner, 'package.json'))) {
@@ -170,7 +171,7 @@ function acquire(into: string, owner: string): void {
170
171
  stdout.write(`thread: ${owner} is not here yet, so this is fetching it. Nothing has to be typed for that.\n`)
171
172
  writeFileSync(manifest, `${JSON.stringify({ ...parsed, dependencies: { ...parsed.dependencies, [owner]: 'latest' } }, null, 2)}\n`, 'utf8')
172
173
  try {
173
- fetching(into)
174
+ installing(into)
174
175
  } catch (thrown) {
175
176
  writeFileSync(manifest, was, 'utf8')
176
177
  throw new Error(
@@ -216,7 +217,6 @@ export async function attach(
216
217
 
217
218
  const plan = new Map<string, string>()
218
219
 
219
- const retired: string[] = []
220
220
 
221
221
  const reshaped: string[] = []
222
222
 
@@ -230,8 +230,6 @@ export async function attach(
230
230
  declares !== undefined &&
231
231
  (holdsRow(held, declares, one.id) || ours.some((id) => id !== undefined && holdsRow(held, declares, id)))
232
232
 
233
- const installed = (at: string): boolean => at.startsWith('node_modules/') && isOurs(at.split('/').slice(1, 3).join('/'))
234
-
235
233
  const pathIn = (source: string): string | undefined => {
236
234
  const listed = `const HELD = {\n declares: [\n${source}\n ],\n}\n`
237
235
  const span = listBounds(listed, 'declares')
@@ -362,13 +360,6 @@ export async function attach(
362
360
  if (where === undefined) return false
363
361
  return !text.slice(where.open, where.close).includes(each.source.trim().replace(/,$/, ''))
364
362
  }).length
365
- const withdrawing = (one.retires ?? []).filter((gone) => {
366
- const at = join(dir, gone.into)
367
- if (!existsSync(at)) return false
368
- const text = plan.get(at) ?? readFileSync(at, 'utf8')
369
- const where = listBounds(text, gone.list)
370
- return where !== undefined && holdsRow(text, where, gone.id)
371
- }).length
372
363
 
373
364
  throw new Error(
374
365
  `${name} brings a noun called \`${coined}\`, and this tree already declares something by that name. One ` +
@@ -380,11 +371,10 @@ export async function attach(
380
371
 
381
372
  `A refusal here names a command you can actually run. If the one above does not fit what you are trying ` +
382
373
  `to do, that is a gap in this framework rather than something to work around — say so.` +
383
- (waiting + withdrawing === 0
374
+ (waiting === 0
384
375
  ? ''
385
376
  : `\n\nAn attach is all or nothing, so this is also holding back everything else ${name} would have ` +
386
- `delivered: ${String(waiting)} row(s) this tree does not hold at the version installed` +
387
- `${withdrawing === 0 ? '' : ` and ${String(withdrawing)} it has withdrawn`}. None of that arrives until the ` +
377
+ `delivered: ${String(waiting)} row(s) this tree does not hold at the version installed. None of that arrives until the ` +
388
378
  `collision above is cleared, and nothing else will tell you — \`npm install\` will go on reporting this ` +
389
379
  `tree current.`),
390
380
  )
@@ -409,34 +399,6 @@ export async function attach(
409
399
  plan.set(target, withRow(held, bounds, row.source))
410
400
  }
411
401
 
412
- for (const gone of one.retires ?? []) {
413
- const shipped = (one.rows ?? []).find(
414
- (row) => row.into === gone.into && row.list === gone.list && row.id === gone.id,
415
- )
416
- if (shipped !== undefined) {
417
- throw new UnattachableError(
418
- name,
419
- `both ships and retires \`${gone.id}\` in ${gone.into}, so attaching it would add and remove one row`,
420
- )
421
- }
422
-
423
- if (gone.made !== undefined) {
424
- const byproduct = join(into, gone.made)
425
- if (existsSync(byproduct)) {
426
- rmSync(byproduct)
427
- retired.push(`${gone.made} — the file \`${gone.id}\` derived, which nothing writes now`)
428
- }
429
- }
430
-
431
- const target = join(dir, gone.into)
432
- if (!existsSync(target) && !plan.has(target)) continue
433
- const text = plan.get(target) ?? readFileSync(target, 'utf8')
434
- const where = listBounds(text, gone.list)
435
- if (where === undefined || !holdsRow(text, where, gone.id)) continue
436
- plan.set(target, withoutRow(text, where, gone.id))
437
- retired.push(`${gone.into}: ${gone.id} — ${gone.why}`)
438
- }
439
-
440
402
  if (one.scripts !== undefined) {
441
403
  const manifest = join(into, 'package.json')
442
404
  const held = readFileSync(manifest, 'utf8')
@@ -453,30 +415,23 @@ export async function attach(
453
415
 
454
416
  if (one.needs !== undefined) {
455
417
  const manifest = join(into, 'package.json')
456
-
457
- const held = plan.get(manifest) ?? readFileSync(manifest, 'utf8')
458
- const parsed = JSON.parse(held) as Record<string, unknown> & { dependencies?: Record<string, string> }
459
- const needs = { ...parsed.dependencies }
460
- const added: string[] = []
461
- for (const [name, at] of Object.entries(one.needs)) {
462
- if (needs[name] !== undefined) continue
463
- needs[name] = at
464
- added.push(name)
418
+ const was = readFileSync(manifest, 'utf8')
419
+ const scripted = plan.get(manifest)
420
+ if (scripted !== undefined) {
421
+ writeFileSync(manifest, scripted, 'utf8')
422
+ plan.delete(manifest)
423
+ touched.add(relative(into, manifest))
424
+ }
425
+ let added: readonly string[]
426
+ try {
427
+ added = needing(into, one.needs)
428
+ } catch (thrown) {
429
+ writeFileSync(manifest, was, 'utf8')
430
+ throw new Error(`${thrown instanceof Error ? thrown.message : String(thrown)} Nothing was attached.`)
465
431
  }
466
432
  if (added.length > 0) {
467
- const next = `${JSON.stringify({ ...parsed, dependencies: needs }, null, 2)}\n`
468
- const was = readFileSync(manifest, 'utf8')
469
- writeFileSync(manifest, next, 'utf8')
470
433
  touched.add(relative(into, manifest))
471
- stdout.write(`thread: ${name} needs ${added.join(', ')}, so this is fetching ${added.length === 1 ? 'it' : 'them'}. Nothing has to be typed for that.\n`)
472
- try {
473
- fetching(into)
474
- } catch (thrown) {
475
- writeFileSync(manifest, was, 'utf8')
476
- throw new Error(
477
- `${added.join(', ')} could not be fetched — ${thrown instanceof Error ? thrown.message : String(thrown)} Nothing was attached and package.json is as it was.`,
478
- )
479
- }
434
+ stdout.write(`thread: ${name} needs ${added.join(', ')}, so ${added.length === 1 ? 'it is' : 'they are'} in package.json now and fetched. Nothing has to be typed for that.\n`)
480
435
  }
481
436
  }
482
437
 
@@ -496,7 +451,6 @@ export async function attach(
496
451
  touched.add(relative(into, path))
497
452
  }
498
453
 
499
- for (const line of retired) stdout.write(`thread: retired ${line}\n`)
500
454
  for (const file of reshaped) stdout.write(`thread: reshaped ${file} — what a row may state has changed\n`)
501
455
  for (const id of noticed) stdout.write(`thread: declared ${id} — a file this app grew after \`thread init\` ran\n`)
502
456
 
@@ -582,9 +536,9 @@ export async function detach(into: string, name: string): Promise<readonly strin
582
536
  }
583
537
 
584
538
  const DESCRIBES =
585
- 'The package every tree installs first: the descent, the CLI, and the makers and generators that used to be separate packages.'
539
+ 'The package every tree installs first: the descent that reads a tree, the gate that checks it, and the generators every tree runs.'
586
540
 
587
- const CORE_SOURCE = `import type { Threaded } from '../core/thread.ts'
541
+ const CORE_SOURCE = `import type { Threaded } from '${SHAPED}'
588
542
 
589
543
  export const CORE: Threaded = {
590
544
  id: 'core',
@@ -604,7 +558,7 @@ const SEEDED = {
604
558
  ' {',
605
559
  ' id: \'core\',',
606
560
  ' at: \'_threads/core.ts\',',
607
- ' describes: \'The package every tree installs first: the descent, the CLI, and the makers and generators that used to be separate packages.\',',
561
+ ' describes: \'The package every tree installs first: the descent that reads a tree, the gate that checks it, and the generators every tree runs.\',',
608
562
  ' version: 1,',
609
563
  ' },',
610
564
  ].join('\n'),
@@ -1,10 +1,10 @@
1
- import { spawnSync } from 'node:child_process';
1
+ import { starts } from '../integrations/cli.js';
2
2
  import { join } from 'node:path';
3
3
  import { execPath } from 'node:process';
4
4
  import { fileURLToPath } from 'node:url';
5
- import { existsSync, readFileSync, readdirSync } from "./files.js";
6
- import { valuesIn } from "./rows.js";
7
- import { findTree } from "./tree.js";
5
+ import { existsSync, readFileSync, readdirSync } from '../integrations/disk.js';
6
+ import { valuesIn } from './rows.js';
7
+ import { findTree } from './tree.js';
8
8
  const STATING = 'derivation.ts';
9
9
  export async function generators(tree = findTree()) {
10
10
  if (!existsSync(tree.dir))
@@ -39,12 +39,8 @@ export const REFUSED_BY = 'round: refused';
39
39
  export function batched(at, commands, within) {
40
40
  if (commands.length === 0)
41
41
  return [];
42
- const out = spawnSync(execPath, [...LOADER, RUNNER, ...new Set(commands)], {
43
- cwd: at,
44
- encoding: 'utf8',
45
- ...(within === undefined ? {} : { timeout: within, killSignal: 'SIGKILL' }),
46
- });
47
- const lines = `${out.stdout ?? ''}${out.stderr ?? ''}`.split('\n');
42
+ const out = starts(execPath, [...LOADER, RUNNER, ...new Set(commands)], { at, shows: 'errors', within });
43
+ const lines = out.out.split('\n');
48
44
  const found = new Map();
49
45
  let held = [];
50
46
  for (const line of lines) {
@@ -58,12 +54,12 @@ export function batched(at, commands, within) {
58
54
  held = [];
59
55
  }
60
56
  const orphaned = held.join('\n').trim();
61
- const died = out.error !== undefined
62
- ? ` The runner itself failed to start or was stopped: ${out.error.message}.`
63
- : out.signal !== null && out.signal !== undefined
64
- ? ` The runner was killed by ${out.signal}, so everything after the command it was running is unreported rather than refused.`
65
- : found.size === 0 && out.status !== 0
66
- ? ` The runner exited ${String(out.status)} having reported nothing, so it died before the first command finished.`
57
+ const died = out.why !== ''
58
+ ? ` The runner itself failed to start or was stopped: ${out.why}.`
59
+ : out.killed !== null
60
+ ? ` The runner was killed by ${out.killed} after ${String(within ?? 0)} ms. The last "settle: running" line above names the command it was inside, and everything after that one is unreported rather than refused.`
61
+ : found.size === 0 && !out.ok
62
+ ? ` The runner exited ${String(out.code)} having reported nothing, so it died before the first command finished.`
67
63
  : '';
68
64
  let firstUnreached = true;
69
65
  return commands.map((one) => {
@@ -93,7 +89,7 @@ export function settling(at, all, skip = []) {
93
89
  let before;
94
90
  while (round < ROUNDS) {
95
91
  round += 1;
96
- const asking = round === 1 ? mine.map((one) => word(one.runs)) : batch(at, mine.map((one) => word(one.runs))).refused;
92
+ const asking = batch(at, mine.map((one) => word(one.runs))).refused;
97
93
  const unhappy = mine.filter((one) => asking.includes(word(one.runs)));
98
94
  if (unhappy.length === 0)
99
95
  return { ran, unsettled: [], rounds: round };
@@ -1,10 +1,10 @@
1
- import { spawnSync } from 'node:child_process'
1
+ import { starts } from '../integrations/cli.ts'
2
2
  import { join } from 'node:path'
3
3
  import { execPath } from 'node:process'
4
4
  import { fileURLToPath } from 'node:url'
5
5
 
6
6
  import type { Row } from './descend.ts'
7
- import { existsSync, readFileSync, readdirSync } from './files.ts'
7
+ import { existsSync, readFileSync, readdirSync } from '../integrations/disk.ts'
8
8
  import { valuesIn } from './rows.ts'
9
9
  import { findTree, type Tree } from './tree.ts'
10
10
 
@@ -58,12 +58,8 @@ export function batched(
58
58
  ): readonly { readonly command: string; readonly ok: boolean; readonly said: string }[] {
59
59
  if (commands.length === 0) return []
60
60
 
61
- const out = spawnSync(execPath, [...LOADER, RUNNER, ...new Set(commands)], {
62
- cwd: at,
63
- encoding: 'utf8',
64
- ...(within === undefined ? {} : { timeout: within, killSignal: 'SIGKILL' as const }),
65
- })
66
- const lines = `${out.stdout ?? ''}${out.stderr ?? ''}`.split('\n')
61
+ const out = starts(execPath, [...LOADER, RUNNER, ...new Set(commands)], { at, shows: 'errors', within })
62
+ const lines = out.out.split('\n')
67
63
 
68
64
  const found = new Map<string, { readonly command: string; readonly ok: boolean; readonly said: string }>()
69
65
  let held: string[] = []
@@ -80,12 +76,12 @@ export function batched(
80
76
 
81
77
  const orphaned = held.join('\n').trim()
82
78
  const died =
83
- out.error !== undefined
84
- ? ` The runner itself failed to start or was stopped: ${out.error.message}.`
85
- : out.signal !== null && out.signal !== undefined
86
- ? ` The runner was killed by ${out.signal}, so everything after the command it was running is unreported rather than refused.`
87
- : found.size === 0 && out.status !== 0
88
- ? ` The runner exited ${String(out.status)} having reported nothing, so it died before the first command finished.`
79
+ out.why !== ''
80
+ ? ` The runner itself failed to start or was stopped: ${out.why}.`
81
+ : out.killed !== null
82
+ ? ` The runner was killed by ${out.killed} after ${String(within ?? 0)} ms. The last "settle: running" line above names the command it was inside, and everything after that one is unreported rather than refused.`
83
+ : found.size === 0 && !out.ok
84
+ ? ` The runner exited ${String(out.code)} having reported nothing, so it died before the first command finished.`
89
85
  : ''
90
86
  let firstUnreached = true
91
87
  return commands.map((one) => {
@@ -127,7 +123,7 @@ export function settling(
127
123
  while (round < ROUNDS) {
128
124
  round += 1
129
125
 
130
- const asking = round === 1 ? mine.map((one) => word(one.runs)) : batch(at, mine.map((one) => word(one.runs))).refused
126
+ const asking = batch(at, mine.map((one) => word(one.runs))).refused
131
127
  const unhappy = mine.filter((one) => asking.includes(word(one.runs)))
132
128
  if (unhappy.length === 0) return { ran, unsettled: [], rounds: round }
133
129
 
@@ -1,8 +1,8 @@
1
1
  import { type Actor } from './actor.ts';
2
- export declare const COMPARE_OPS: readonly ["eq", "neq", "lt", "lte", "gt", "gte", "in", "has"];
2
+ export declare const COMPARE_OPS: readonly ['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'in', 'has'];
3
3
  export type CompareOp = (typeof COMPARE_OPS)[number];
4
- export declare const AGGREGATIONS: readonly ["count", "sum", "min", "max", "avg"];
5
- export declare const ACTOR_FACTS: readonly ["id", "roles", "entitlements", ...("run" | "address" | "device" | "replay")[]];
4
+ export declare const AGGREGATIONS: readonly ['count', 'sum', 'min', 'max', 'avg'];
5
+ export declare const ACTOR_FACTS: readonly ["id", "roles", "entitlements", ...("address" | "device" | "moment" | "replay" | "run")[]];
6
6
  export declare const AGO: RegExp;
7
7
  export type Operand = {
8
8
  readonly value: string | number | boolean | null;
@@ -41,7 +41,7 @@ export declare function walkOperands(condition: Condition, take: (one: Operand)
41
41
  export declare function mentionsActor(condition: Condition): boolean;
42
42
  export declare function agoSeconds(ago: string): number | undefined;
43
43
  export declare function satisfies(condition: Condition, actor: Actor): boolean;
44
- export declare const CONDITION_ANSWERS: readonly ["is", "than", "field", "value", "actor", "ago", "of", "how", "over", "op", "when", "joins"];
44
+ export declare const CONDITION_ANSWERS: readonly ['is', 'than', 'field', 'value', 'actor', 'ago', 'of', 'how', 'over', 'op', 'when', 'joins'];
45
45
  export declare function conditioned(ask: (key: string, question: string) => Promise<string>, say: (line: string) => void, subject: {
46
46
  readonly id: string;
47
47
  readonly fields: readonly string[];
@@ -1,4 +1,4 @@
1
- import { ENVIRONMENT } from "./actor.js";
1
+ import { ENVIRONMENT } from './actor.js';
2
2
  export const COMPARE_OPS = ['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'in', 'has'];
3
3
  export const AGGREGATIONS = ['count', 'sum', 'min', 'max', 'avg'];
4
4
  export const ACTOR_FACTS = ['id', 'roles', 'entitlements', ...ENVIRONMENT.map(([fact]) => fact)];
@@ -182,7 +182,7 @@ export async function conditioned(ask, say, subject, all) {
182
182
  const first = held[0];
183
183
  return held.length === 1 ? first : joiner === 'all' ? { all: held } : { any: held };
184
184
  }
185
- import { quoted } from "./rows.js";
185
+ import { quoted } from './rows.js';
186
186
  export function said(one) {
187
187
  if (typeof one === 'string')
188
188
  return quoted(one);