@prestack/thread 0.0.1

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 (248) hide show
  1. package/CHANGELOG.md +192 -0
  2. package/dist/attach.d.ts +1 -0
  3. package/dist/attach.js +1 -0
  4. package/dist/core/actor.d.ts +12 -0
  5. package/dist/core/actor.js +8 -0
  6. package/dist/core/asking.d.ts +180 -0
  7. package/dist/core/asking.js +1109 -0
  8. package/dist/core/attach.d.ts +54 -0
  9. package/dist/core/attach.js +510 -0
  10. package/dist/core/chain.d.ts +16 -0
  11. package/dist/core/chain.js +114 -0
  12. package/dist/core/cli.d.ts +2 -0
  13. package/dist/core/cli.js +1682 -0
  14. package/dist/core/condition.d.ts +52 -0
  15. package/dist/core/condition.js +198 -0
  16. package/dist/core/descend.d.ts +81 -0
  17. package/dist/core/descend.js +879 -0
  18. package/dist/core/finding.d.ts +12 -0
  19. package/dist/core/finding.js +23 -0
  20. package/dist/core/generators/meta.d.ts +2 -0
  21. package/dist/core/generators/meta.js +823 -0
  22. package/dist/core/init.d.ts +15 -0
  23. package/dist/core/init.js +134 -0
  24. package/dist/core/invoked.d.ts +9 -0
  25. package/dist/core/invoked.js +41 -0
  26. package/dist/core/round.d.ts +1 -0
  27. package/dist/core/round.js +57 -0
  28. package/dist/core/rows.d.ts +26 -0
  29. package/dist/core/rows.js +354 -0
  30. package/dist/core/scope.d.ts +6 -0
  31. package/dist/core/scope.js +12 -0
  32. package/dist/core/thread.d.ts +26 -0
  33. package/dist/core/thread.js +5 -0
  34. package/dist/core/tree.d.ts +12 -0
  35. package/dist/core/tree.js +56 -0
  36. package/dist/core/types.d.ts +49 -0
  37. package/dist/core/types.js +311 -0
  38. package/dist/derivation/attach.d.ts +2 -0
  39. package/dist/derivation/attach.js +61 -0
  40. package/dist/derivation/generators/build.d.ts +16 -0
  41. package/dist/derivation/generators/build.js +217 -0
  42. package/dist/derivation/generators/check.d.ts +18 -0
  43. package/dist/derivation/generators/check.js +78 -0
  44. package/dist/derivation/generators/derivation.d.ts +3 -0
  45. package/dist/derivation/generators/derivation.js +273 -0
  46. package/dist/derivation/generators/determinism.d.ts +20 -0
  47. package/dist/derivation/generators/determinism.js +110 -0
  48. package/dist/derivation/generators/release.d.ts +3 -0
  49. package/dist/derivation/generators/release.js +183 -0
  50. package/dist/derivation/makers/release.d.ts +1 -0
  51. package/dist/derivation/makers/release.js +107 -0
  52. package/dist/derivation/release.d.ts +10 -0
  53. package/dist/derivation/release.js +12 -0
  54. package/dist/integrations/attach.d.ts +6 -0
  55. package/dist/integrations/attach.js +177 -0
  56. package/dist/integrations/generators/read.d.ts +1 -0
  57. package/dist/integrations/generators/read.js +92 -0
  58. package/dist/integrations/generators/sdk.d.ts +1 -0
  59. package/dist/integrations/generators/sdk.js +148 -0
  60. package/dist/integrations/generators/secret.d.ts +1 -0
  61. package/dist/integrations/generators/secret.js +233 -0
  62. package/dist/integrations/generators/target.d.ts +1 -0
  63. package/dist/integrations/generators/target.js +765 -0
  64. package/dist/integrations/generators/vault.d.ts +1 -0
  65. package/dist/integrations/generators/vault.js +164 -0
  66. package/dist/integrations/sdk.d.ts +6 -0
  67. package/dist/integrations/sdk.js +151 -0
  68. package/dist/integrations/secret.d.ts +16 -0
  69. package/dist/integrations/secret.js +30 -0
  70. package/dist/integrations/target.d.ts +49 -0
  71. package/dist/integrations/target.js +225 -0
  72. package/dist/integrations/vault.d.ts +12 -0
  73. package/dist/integrations/vault.js +104 -0
  74. package/dist/integrity/attach.d.ts +2 -0
  75. package/dist/integrity/attach.js +213 -0
  76. package/dist/integrity/check-threads.d.ts +10 -0
  77. package/dist/integrity/check-threads.js +153 -0
  78. package/dist/integrity/constraint.d.ts +16 -0
  79. package/dist/integrity/constraint.js +1105 -0
  80. package/dist/integrity/generators/compiler.d.ts +1 -0
  81. package/dist/integrity/generators/compiler.js +130 -0
  82. package/dist/integrity/generators/gate.d.ts +1 -0
  83. package/dist/integrity/generators/gate.js +172 -0
  84. package/dist/integrity/generators/issues.d.ts +1 -0
  85. package/dist/integrity/generators/issues.js +100 -0
  86. package/dist/integrity/generators/publish.d.ts +1 -0
  87. package/dist/integrity/generators/publish.js +186 -0
  88. package/dist/integrity/generators/rule.d.ts +2 -0
  89. package/dist/integrity/generators/rule.js +213 -0
  90. package/dist/integrity/generators/seal.d.ts +4 -0
  91. package/dist/integrity/generators/seal.js +101 -0
  92. package/dist/integrity/generators/trial.d.ts +39 -0
  93. package/dist/integrity/generators/trial.js +254 -0
  94. package/dist/integrity/lint.d.ts +50 -0
  95. package/dist/integrity/lint.js +161 -0
  96. package/dist/integrity/lsp/bin.d.ts +2 -0
  97. package/dist/integrity/lsp/bin.js +35 -0
  98. package/dist/integrity/lsp/diagnostics.d.ts +25 -0
  99. package/dist/integrity/lsp/diagnostics.js +57 -0
  100. package/dist/integrity/lsp/findings.d.ts +20 -0
  101. package/dist/integrity/lsp/findings.js +39 -0
  102. package/dist/integrity/lsp/lint.d.ts +7 -0
  103. package/dist/integrity/lsp/lint.js +95 -0
  104. package/dist/integrity/lsp/protocol.d.ts +20 -0
  105. package/dist/integrity/lsp/protocol.js +57 -0
  106. package/dist/integrity/lsp/server.d.ts +15 -0
  107. package/dist/integrity/lsp/server.js +171 -0
  108. package/dist/integrity/sealed.d.ts +1 -0
  109. package/dist/integrity/sealed.js +56 -0
  110. package/dist/integrity/slopnator.d.ts +90 -0
  111. package/dist/integrity/slopnator.js +267 -0
  112. package/dist/integrity/slopnators/sl_broken_lineage.d.ts +2 -0
  113. package/dist/integrity/slopnators/sl_broken_lineage.js +35 -0
  114. package/dist/integrity/slopnators/sl_declared_elsewhere.d.ts +2 -0
  115. package/dist/integrity/slopnators/sl_declared_elsewhere.js +33 -0
  116. package/dist/integrity/slopnators/sl_derived_drift.d.ts +8 -0
  117. package/dist/integrity/slopnators/sl_derived_drift.js +91 -0
  118. package/dist/integrity/slopnators/sl_hardcoded_style.d.ts +2 -0
  119. package/dist/integrity/slopnators/sl_hardcoded_style.js +46 -0
  120. package/dist/integrity/slopnators/sl_inert_island.d.ts +2 -0
  121. package/dist/integrity/slopnators/sl_inert_island.js +85 -0
  122. package/dist/integrity/slopnators/sl_inert_slopnator.d.ts +2 -0
  123. package/dist/integrity/slopnators/sl_inert_slopnator.js +76 -0
  124. package/dist/integrity/slopnators/sl_missing_row.d.ts +2 -0
  125. package/dist/integrity/slopnators/sl_missing_row.js +180 -0
  126. package/dist/integrity/slopnators/sl_no_barrel.d.ts +2 -0
  127. package/dist/integrity/slopnators/sl_no_barrel.js +41 -0
  128. package/dist/integrity/slopnators/sl_no_child_process.d.ts +2 -0
  129. package/dist/integrity/slopnators/sl_no_child_process.js +61 -0
  130. package/dist/integrity/slopnators/sl_no_comment.d.ts +2 -0
  131. package/dist/integrity/slopnators/sl_no_comment.js +41 -0
  132. package/dist/integrity/slopnators/sl_no_dispatch_bypass.d.ts +2 -0
  133. package/dist/integrity/slopnators/sl_no_dispatch_bypass.js +301 -0
  134. package/dist/integrity/slopnators/sl_no_import_cycle.d.ts +2 -0
  135. package/dist/integrity/slopnators/sl_no_import_cycle.js +42 -0
  136. package/dist/integrity/slopnators/sl_no_such_command.d.ts +2 -0
  137. package/dist/integrity/slopnators/sl_no_such_command.js +55 -0
  138. package/dist/integrity/slopnators/sl_only_takes_a_literal.d.ts +2 -0
  139. package/dist/integrity/slopnators/sl_only_takes_a_literal.js +59 -0
  140. package/dist/integrity/slopnators/sl_secret_literal.d.ts +2 -0
  141. package/dist/integrity/slopnators/sl_secret_literal.js +89 -0
  142. package/dist/integrity/slopnators/sl_stale_path.d.ts +2 -0
  143. package/dist/integrity/slopnators/sl_stale_path.js +92 -0
  144. package/dist/integrity/slopnators/sl_twice_meant.d.ts +2 -0
  145. package/dist/integrity/slopnators/sl_twice_meant.js +30 -0
  146. package/dist/integrity/slopnators/sl_twice_parented.d.ts +2 -0
  147. package/dist/integrity/slopnators/sl_twice_parented.js +34 -0
  148. package/dist/integrity/slopnators/sl_undeclared_crossing.d.ts +2 -0
  149. package/dist/integrity/slopnators/sl_undeclared_crossing.js +78 -0
  150. package/dist/integrity/slopnators/sl_undeclared_destination.d.ts +2 -0
  151. package/dist/integrity/slopnators/sl_undeclared_destination.js +56 -0
  152. package/dist/integrity/slopnators/sl_undeclared_element.d.ts +2 -0
  153. package/dist/integrity/slopnators/sl_undeclared_element.js +34 -0
  154. package/dist/integrity/slopnators/sl_undeclared_node.d.ts +2 -0
  155. package/dist/integrity/slopnators/sl_undeclared_node.js +59 -0
  156. package/dist/integrity/slopnators/sl_undeclared_operation.d.ts +2 -0
  157. package/dist/integrity/slopnators/sl_undeclared_operation.js +120 -0
  158. package/dist/integrity/slopnators/sl_undeclared_variant.d.ts +2 -0
  159. package/dist/integrity/slopnators/sl_undeclared_variant.js +117 -0
  160. package/dist/integrity/slopnators/sl_undescribed.d.ts +2 -0
  161. package/dist/integrity/slopnators/sl_undescribed.js +54 -0
  162. package/dist/integrity/slopnators/sl_ungoverned_island.d.ts +2 -0
  163. package/dist/integrity/slopnators/sl_ungoverned_island.js +58 -0
  164. package/dist/integrity/slopnators/sl_unkept_rows.d.ts +2 -0
  165. package/dist/integrity/slopnators/sl_unkept_rows.js +104 -0
  166. package/dist/integrity/slopnators/sl_unnamed_island.d.ts +2 -0
  167. package/dist/integrity/slopnators/sl_unnamed_island.js +37 -0
  168. package/dist/integrity/slopnators/sl_unpaired_member.d.ts +2 -0
  169. package/dist/integrity/slopnators/sl_unpaired_member.js +114 -0
  170. package/dist/integrity/slopnators/sl_unpaired_slopnator.d.ts +2 -0
  171. package/dist/integrity/slopnators/sl_unpaired_slopnator.js +60 -0
  172. package/dist/integrity/slopnators/sl_unprefixed_member.d.ts +2 -0
  173. package/dist/integrity/slopnators/sl_unprefixed_member.js +126 -0
  174. package/dist/integrity/slopnators/sl_unseamed_reach.d.ts +2 -0
  175. package/dist/integrity/slopnators/sl_unseamed_reach.js +73 -0
  176. package/dist/integrity/slopnators/sl_unthreaded.d.ts +56 -0
  177. package/dist/integrity/slopnators/sl_unthreaded.js +352 -0
  178. package/dist/integrity/slopnators/sl_untranslated_key.d.ts +2 -0
  179. package/dist/integrity/slopnators/sl_untranslated_key.js +157 -0
  180. package/dist/integrity/slopnators/sl_unversioned.d.ts +2 -0
  181. package/dist/integrity/slopnators/sl_unversioned.js +31 -0
  182. package/dist/integrity/sweep.d.ts +24 -0
  183. package/dist/integrity/sweep.js +264 -0
  184. package/dist/knowledge/attach.d.ts +2 -0
  185. package/dist/knowledge/attach.js +339 -0
  186. package/dist/knowledge/generators/docsgen.d.ts +1 -0
  187. package/dist/knowledge/generators/docsgen.js +145 -0
  188. package/dist/knowledge/generators/glossary.d.ts +1 -0
  189. package/dist/knowledge/generators/glossary.js +56 -0
  190. package/dist/knowledge/generators/skills.d.ts +1 -0
  191. package/dist/knowledge/generators/skills.js +222 -0
  192. package/dist/knowledge/glossary.d.ts +6 -0
  193. package/dist/knowledge/glossary.js +1 -0
  194. package/dist/operations/access.d.ts +27 -0
  195. package/dist/operations/access.js +61 -0
  196. package/dist/operations/attach.d.ts +6 -0
  197. package/dist/operations/attach.js +414 -0
  198. package/dist/operations/capabilities.d.ts +37 -0
  199. package/dist/operations/capabilities.js +35 -0
  200. package/dist/operations/cost.d.ts +14 -0
  201. package/dist/operations/cost.js +37 -0
  202. package/dist/operations/dispatch.d.ts +14 -0
  203. package/dist/operations/dispatch.js +327 -0
  204. package/dist/operations/error-results.d.ts +4 -0
  205. package/dist/operations/error-results.js +25 -0
  206. package/dist/operations/errors/catalog.d.ts +58 -0
  207. package/dist/operations/errors/catalog.js +91 -0
  208. package/dist/operations/errors/classes.d.ts +73 -0
  209. package/dist/operations/errors/classes.js +22 -0
  210. package/dist/operations/errors/errors.d.ts +52 -0
  211. package/dist/operations/errors/errors.js +257 -0
  212. package/dist/operations/generators/capability.d.ts +5 -0
  213. package/dist/operations/generators/capability.js +603 -0
  214. package/dist/operations/generators/compile.d.ts +2 -0
  215. package/dist/operations/generators/compile.js +541 -0
  216. package/dist/operations/generators/grant.d.ts +1 -0
  217. package/dist/operations/generators/grant.js +267 -0
  218. package/dist/operations/generators/operation.d.ts +1 -0
  219. package/dist/operations/generators/operation.js +811 -0
  220. package/dist/operations/generators/permits.d.ts +1 -0
  221. package/dist/operations/generators/permits.js +196 -0
  222. package/dist/operations/generators/seed.d.ts +20 -0
  223. package/dist/operations/generators/seed.js +285 -0
  224. package/dist/operations/generators/trial.d.ts +53 -0
  225. package/dist/operations/generators/trial.js +376 -0
  226. package/dist/operations/http.d.ts +30 -0
  227. package/dist/operations/http.js +121 -0
  228. package/dist/operations/makers/capability.d.ts +1 -0
  229. package/dist/operations/makers/capability.js +117 -0
  230. package/dist/operations/makers/trial.d.ts +1 -0
  231. package/dist/operations/makers/trial.js +413 -0
  232. package/dist/operations/memory.d.ts +104 -0
  233. package/dist/operations/memory.js +365 -0
  234. package/dist/operations/metering.d.ts +55 -0
  235. package/dist/operations/metering.js +247 -0
  236. package/dist/operations/nodes.d.ts +35 -0
  237. package/dist/operations/nodes.js +15 -0
  238. package/dist/operations/operations.d.ts +18 -0
  239. package/dist/operations/operations.js +5 -0
  240. package/dist/operations/queue-policy.d.ts +3 -0
  241. package/dist/operations/queue-policy.js +8 -0
  242. package/dist/operations/result.d.ts +19 -0
  243. package/dist/operations/result.js +10 -0
  244. package/dist/operations/seams.d.ts +239 -0
  245. package/dist/operations/seams.js +45 -0
  246. package/dist/operations/store.d.ts +14 -0
  247. package/dist/operations/store.js +1 -0
  248. package/package.json +16 -0
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,130 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { readdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { createRequire } from 'node:module';
4
+ import { dirname, join, resolve } from 'node:path';
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";
10
+ function refuse(why) {
11
+ stderr.write(`compiler: ${why}\n`);
12
+ exit(1);
13
+ }
14
+ const SOURCE = /\.(?:ts|tsx|mts|cts)$/;
15
+ const DECLARING = /\.d\.[cm]?ts$/;
16
+ const INSTALLED = 'node_' + 'modules';
17
+ const pass = await descend();
18
+ const stopped = [...pass.broken, ...pass.findings].filter(forbids)[0];
19
+ if (stopped !== undefined) {
20
+ refuse('the descent is broken, so what this tree declares is short — and a short list of declarations ' +
21
+ `leaves out more of the app than it should, which is a compiler that agrees with anything. ${stopped.detail} (${stopped.file ?? ''})`);
22
+ }
23
+ const WORD = 'thread compiler';
24
+ const SELF = [...pass.threaded.entries()]
25
+ .flatMap(([at, held]) => held.map((one) => ({ at, row: one.row })))
26
+ .filter((one) => (one.row.by ?? '') === WORD)
27
+ .find((one) => !one.at.split('/').includes(INSTALLED));
28
+ if (SELF === undefined) {
29
+ refuse(`no row in this tree names a file of this app with \`by: '${WORD}'\`, so nothing says which config is this app's. ` +
30
+ 'Run `thread attach integrity`, which declares it.');
31
+ }
32
+ const AT = SELF.at;
33
+ const PATH = resolve(ROOT, AT);
34
+ const declared = new Set([THREAD_AT, ...pass.threaded.keys()]);
35
+ function scan(rel) {
36
+ let entries;
37
+ try {
38
+ entries = readdirSync(join(ROOT, rel === '' ? '.' : rel), { withFileTypes: true });
39
+ }
40
+ catch {
41
+ return { declares: false, holds: false, out: [] };
42
+ }
43
+ let declares = false;
44
+ let holds = false;
45
+ const out = [];
46
+ for (const entry of [...entries].sort((one, two) => one.name.localeCompare(two.name))) {
47
+ if (entry.name === '.git' || entry.name === INSTALLED)
48
+ continue;
49
+ const at = rel === '' ? entry.name : `${rel}/${entry.name}`;
50
+ if (entry.isDirectory()) {
51
+ const held = scan(at);
52
+ if (held.declares) {
53
+ declares = true;
54
+ holds = true;
55
+ out.push(...held.out);
56
+ }
57
+ else if (held.holds) {
58
+ holds = true;
59
+ out.push(at);
60
+ }
61
+ continue;
62
+ }
63
+ if (declared.has(at)) {
64
+ declares = true;
65
+ holds = true;
66
+ continue;
67
+ }
68
+ if (!SOURCE.test(entry.name) || DECLARING.test(entry.name))
69
+ continue;
70
+ holds = true;
71
+ out.push(at);
72
+ }
73
+ return { declares, holds, out };
74
+ }
75
+ const held = scan('');
76
+ if (!held.declares) {
77
+ refuse('no TypeScript file in this tree is declared by anything, so every one of them would be left out ' +
78
+ 'and the compiler would pass by reading nothing. Declare something with `thread create` first.');
79
+ }
80
+ const leave = [...held.out].sort();
81
+ let current;
82
+ try {
83
+ current = JSON.parse(readFileSync(PATH, 'utf8'));
84
+ }
85
+ catch (cause) {
86
+ refuse(`${AT} could not be read as JSON, so what it already states cannot be kept — ${String(cause)}`);
87
+ }
88
+ const wanted = JSON.stringify({ ...current, exclude: leave }, null, 2);
89
+ const has = JSON.stringify(current.exclude ?? []) === JSON.stringify(leave);
90
+ if (argv.includes('--check')) {
91
+ const findings = [];
92
+ if (!has) {
93
+ findings.push({
94
+ 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`,
98
+ 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
+ });
100
+ }
101
+ runChecker('compiler', findings, `${String(leave.length)} path(s) left out, over ${String(pass.declarations)} declaration(s)`);
102
+ if (findings.length > 0)
103
+ exit(1);
104
+ const asks = createRequire(join(ROOT, MANIFEST));
105
+ let cli;
106
+ try {
107
+ const manifest = asks.resolve(`typescript/${MANIFEST}`);
108
+ const bin = JSON.parse(readFileSync(manifest, 'utf8')).bin;
109
+ const named = typeof bin === 'string' ? bin : (bin?.tsc ?? Object.values(bin ?? {})[0]);
110
+ if (named === undefined)
111
+ refuse(`the installed \`typescript\` states no executable in its ${MANIFEST}, so there is nothing here to run.`);
112
+ cli = resolve(dirname(manifest), named);
113
+ }
114
+ catch (cause) {
115
+ refuse(`the compiler is not installed — ${String(cause)}. \`typescript\` is a dependency this app declares, so \`npm install\` is what puts it there.`);
116
+ }
117
+ const built = spawnSync(execPath, [cli, '--noEmit'], { cwd: ROOT, stdio: 'inherit' });
118
+ if (built.error !== undefined)
119
+ refuse(`the compiler could not be started — ${built.error.message}.`);
120
+ exit(built.status ?? 1);
121
+ }
122
+ if (has) {
123
+ stdout.write(`compiler: ${AT} already leaves out exactly what this tree declares nothing under.\n`);
124
+ exit(0);
125
+ }
126
+ writeFileSync(PATH, `${wanted}\n`);
127
+ stdout.write(leave.length === 0
128
+ ? `compiler: wrote ${AT} — every path here has something declared under it, so none is left out.\n`
129
+ : `compiler: wrote ${AT} — ${String(leave.length)} path(s) left out, declared by nobody: ${leave.join(', ')}.\n`);
130
+ exit(0);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,172 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { spawnSync } from 'node:child_process';
10
+ import { createHash } from 'node:crypto';
11
+ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
12
+ import { dirname, join } from 'node:path';
13
+ import { argv, execPath, stderr, stdout } from 'node:process';
14
+ import { pathToFileURL } from 'node:url';
15
+ import { descend } from "../../core/descend.js";
16
+ import { LOADER, exit } from "../../core/invoked.js";
17
+ import { ORGANISATION, ours } from "../../core/scope.js";
18
+ import { findTree, inTree } from "../../core/tree.js";
19
+ const TREE = findTree();
20
+ const ROOT = TREE.at;
21
+ const STEP_TIMEOUT = 600_000;
22
+ const { GATE } = (await import(__rewriteRelativeImportExtension(pathToFileURL(inTree(TREE, 'gate.ts')).href)));
23
+ const { GENERATORS } = (await import(__rewriteRelativeImportExtension(pathToFileURL(inTree(TREE, 'derivation.ts')).href)));
24
+ function refuse(why) {
25
+ stderr.write(`gate: ${why}\n`);
26
+ exit(1);
27
+ }
28
+ const rowsOf = (edge) => (Array.isArray(edge) ? edge : []);
29
+ const walked = await descend();
30
+ const every = [
31
+ ...rowsOf(GATE.declares),
32
+ ...rowsOf(GENERATORS),
33
+ ...[...walked.threaded.values()].flat().map((one) => one.row),
34
+ ...[...walked.stated.values()].map((one) => one),
35
+ ];
36
+ function steps() {
37
+ const found = [];
38
+ const claimed = new Set();
39
+ for (const row of every) {
40
+ const runs = (row.runs ?? '').trim();
41
+ if (runs === '' || claimed.has(runs))
42
+ continue;
43
+ claimed.add(runs);
44
+ found.push({ id: row.id ?? runs, runs });
45
+ }
46
+ if (found.length === 0) {
47
+ refuse('no row in this tree names a command to check it, so the gate would pass by running nothing');
48
+ }
49
+ return found;
50
+ }
51
+ const writers = [
52
+ ...rowsOf(GATE.declares),
53
+ ...rowsOf(GENERATORS),
54
+ ...[...walked.threaded.values()].flat().filter((one) => one.list === 'declares').map((one) => one.row),
55
+ ...[...walked.stated.values()].map((one) => one),
56
+ ];
57
+ const written = new Map();
58
+ for (const row of writers) {
59
+ const by = (row.by ?? '').trim();
60
+ const at = (row.at ?? '').trim();
61
+ if (by !== '' && at !== '' && !written.has(by))
62
+ written.set(by, at);
63
+ }
64
+ function ran(runs) {
65
+ const said = runs.trim().split(/\s+/);
66
+ const spent = { cwd: ROOT, stdio: 'inherit', timeout: STEP_TIMEOUT, killSignal: 'SIGKILL' };
67
+ if (said[0] !== 'thread') {
68
+ const shelled = spawnSync(runs, { shell: true, ...spent });
69
+ return shelled.error !== undefined ? 1 : (shelled.status ?? 1);
70
+ }
71
+ const of = `thread ${said[1] ?? ''}`;
72
+ const at = written.get(of);
73
+ if (at === undefined) {
74
+ stderr.write(`gate: nothing in this tree is written by \`${of}\`, so this step names a command that does not exist here\n`);
75
+ return 1;
76
+ }
77
+ const spun = spawnSync(execPath, [...LOADER, join(ROOT, at), ...said.slice(2)], spent);
78
+ return spun.error !== undefined ? 1 : (spun.status ?? 1);
79
+ }
80
+ function named(flag) {
81
+ const at = argv.indexOf(flag);
82
+ if (at === -1)
83
+ return undefined;
84
+ return (argv[at + 1] ?? '').split(',').map((one) => one.trim()).filter(Boolean);
85
+ }
86
+ const all = steps();
87
+ if (argv.includes('--list')) {
88
+ stdout.write(`gate: ${String(all.length)} step(s) declared\n`);
89
+ for (const step of all)
90
+ stdout.write(` ${step.id} — ${step.runs}\n`);
91
+ exit(0);
92
+ }
93
+ const only = named('--only');
94
+ const skip = named('--skip') ?? [];
95
+ const known = new Set(all.map((step) => step.id));
96
+ const unknown = [...(only ?? []), ...skip].filter((id) => !known.has(id));
97
+ if (unknown.length > 0) {
98
+ stderr.write(`gate: no declared step is called ${unknown.join(', ')} — a filter naming nothing would run a shorter gate and exit 0\n`);
99
+ stderr.write(`gate: the declared steps are ${[...known].join(', ')}\n`);
100
+ exit(1);
101
+ }
102
+ const chosen = all.filter((step) => (only === undefined || only.includes(step.id)) && !skip.includes(step.id));
103
+ const dropped = all.filter((step) => !chosen.includes(step));
104
+ if (chosen.length === 0) {
105
+ stderr.write('gate: the filter selected no steps, and a gate that runs nothing must not exit 0\n');
106
+ exit(1);
107
+ }
108
+ const failed = [];
109
+ let passed = 0;
110
+ for (const [index, step] of chosen.entries()) {
111
+ const at = `step ${String(index + 1)} of ${String(chosen.length)}`;
112
+ stdout.write(`\ngate: ${at} — ${step.runs} (${step.id})\n`);
113
+ const code = ran(step.runs);
114
+ stdout.write(`gate: ${at} — exited ${String(code)}\n`);
115
+ if (code === 0)
116
+ passed += 1;
117
+ else
118
+ failed.push(step);
119
+ }
120
+ stdout.write(`\ngate: ${String(passed)} of ${String(chosen.length)} steps passed.\n`);
121
+ if (dropped.length > 0) {
122
+ stdout.write(`gate: PARTIAL RUN — ${String(dropped.length)} of ${String(all.length)} declared step(s) did not run: ${dropped.map((step) => step.id).join(', ')}\n`);
123
+ stdout.write('gate: this is not a gate pass. `thread gate` with no filter runs every step the tree declares.\n');
124
+ }
125
+ function fingerprint() {
126
+ const of = {};
127
+ const hash = (at) => {
128
+ if (!existsSync(join(ROOT, at)))
129
+ return;
130
+ of[at] = createHash('sha256').update(readFileSync(join(ROOT, at))).digest('hex').slice(0, 16);
131
+ };
132
+ const sheets = join(ROOT, '_threads');
133
+ if (existsSync(sheets)) {
134
+ for (const name of readdirSync(sheets))
135
+ if (name.endsWith('.ts'))
136
+ hash(join('_threads', name));
137
+ }
138
+ const versions = {};
139
+ const held = join(ROOT, 'node_modules', ORGANISATION);
140
+ if (existsSync(held)) {
141
+ for (const name of readdirSync(held)) {
142
+ const pkg = `${ORGANISATION}/${name}`;
143
+ if (!ours(pkg))
144
+ continue;
145
+ const at = join(held, name, 'package.json');
146
+ if (!existsSync(at))
147
+ continue;
148
+ const read = JSON.parse(readFileSync(at, 'utf8'));
149
+ if (typeof read.version === 'string')
150
+ versions[pkg] = read.version;
151
+ }
152
+ }
153
+ return { of, versions };
154
+ }
155
+ const RECEIPT_AT = join('.thread', 'gate.json');
156
+ const RECEIPT = join(ROOT, RECEIPT_AT);
157
+ if (failed.length === 0 && dropped.length === 0) {
158
+ mkdirSync(dirname(RECEIPT), { recursive: true });
159
+ writeFileSync(RECEIPT, `${JSON.stringify({ passed: chosen.length, ...fingerprint() }, null, 2)}\n`, 'utf8');
160
+ stdout.write(`gate: wrote ${RECEIPT_AT} — what compiles is checked against this, so a tree that skipped the gate does not build.\n`);
161
+ }
162
+ else if (existsSync(RECEIPT)) {
163
+ rmSync(RECEIPT);
164
+ stdout.write(`gate: removed ${RECEIPT_AT} — the tree no longer passes, so nothing may compile against an older run.\n`);
165
+ }
166
+ if (failed.length === 0)
167
+ exit(0);
168
+ stderr.write(`gate: FAILED — ${String(failed.length)} of ${String(chosen.length)} step(s). The other ${String(passed)} ran and passed; a failing step stops nothing.\n`);
169
+ for (const step of failed)
170
+ stderr.write(` - ${step.id} — run it alone with \`${step.runs}\`\n`);
171
+ stderr.write('gate: every step above is its own command. Run the failing one on its own to work on it, and `thread issues` for everything wrong with the tree at once.\n');
172
+ exit(1);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,100 @@
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";
9
+ const WITHIN = '--in';
10
+ const CHECK = '--check';
11
+ const checking = argv.includes(CHECK);
12
+ const scoped = argv.indexOf(WITHIN);
13
+ const under = scoped === -1 ? undefined : argv[scoped + 1];
14
+ if (scoped !== -1 && (under === undefined || under.startsWith('-'))) {
15
+ stderr.write(`thread issues ${WITHIN} <path> — which directory to report on. The totals still count the whole tree.\n`);
16
+ exit(1);
17
+ }
18
+ const inside = (one) => under === undefined || one.file === undefined || one.file === under || one.file.startsWith(`${under.replace(/\/+$/, '')}/`);
19
+ const pass = await descend();
20
+ const tracked = trackedFiles();
21
+ const kept = new Set(tracked);
22
+ const found = refusals(pass, tracked);
23
+ const loose = new Set(unthreaded(pass, tracked));
24
+ const governing = [...CONSTRAINTS, ...((await rules()) ?? [])];
25
+ const named = new Map(governing.map((one) => [one.id, one]));
26
+ const ran = sweep(ROOT, governing, await load(ROOT, governing), governed(ROOT));
27
+ const refused = [
28
+ ...ran.findings.map((one) => {
29
+ const rule = named.get(one.rule);
30
+ return {
31
+ detail: `${rule === undefined ? one.rule : ruleMessage(rule)} Found: ${one.found}.`,
32
+ instead: rule?.instead ?? `read what ${one.rule} refuses and stop writing it`,
33
+ ...(one.file === '' ? {} : { file: one.file }),
34
+ };
35
+ }),
36
+ ...ran.unrun.map((one) => ({
37
+ detail: `${one} DID NOT RUN — no slopnator is on disk for it, so nothing here measured that rule and its absence from this list says nothing about it`,
38
+ instead: 'write the walk the rule names, or delete the rule and its row together — half a rule reads as a whole one from every direction',
39
+ })),
40
+ ];
41
+ const warned = found.filter((one) => one.severity === 'warning');
42
+ const firm = found.filter((one) => one.severity !== 'warning');
43
+ const cut = firm.filter((one) => one.file !== undefined && loose.has(one.file));
44
+ const rest = firm.filter((one) => !(one.file !== undefined && loose.has(one.file)));
45
+ const wrong = uncompiled().filter((one) => one.file === undefined || kept.has(one.file));
46
+ const where = (one) => {
47
+ const line = one.at?.line;
48
+ const column = one.at?.column;
49
+ return `${one.file ?? '(nowhere named)'}${line === undefined ? '' : `:${String(line)}${column === undefined ? '' : `:${String(column)}`}`}`;
50
+ };
51
+ const listed = (held) => held.flatMap((one) => [` ${where(one)}`, ` ${one.detail}`, ` fix: ${one.instead}`, '']);
52
+ const out = [];
53
+ let shown = 0;
54
+ const group = (title, taught, held) => {
55
+ if (held.length === 0)
56
+ return;
57
+ const here = held.filter(inside);
58
+ shown += here.length;
59
+ if (here.length === 0)
60
+ return;
61
+ out.push('', `${title} — ${String(held.length)}${here.length === held.length ? '' : `, ${String(here.length)} of them under ${String(under)}`}`, taught, '', ...listed(here));
62
+ };
63
+ group('files nothing declares', ' every file here is named by a row, or it is not part of this app. The descent starts at\n' +
64
+ ` ${THREAD_AT} and walks what each row declares; whatever it never arrives at is not wired,\n` +
65
+ ' however well it reads. Declare it with `thread create`, or delete it.', cut);
66
+ group('files that will not compile', ' nothing in this tree builds, serves or gates while one of its files does not typecheck.\n' +
67
+ ' Read off the same program the descent judged the declarations with.', wrong);
68
+ group('declarations this tree refuses', ' the files are reached and they compile; these are the things the descent will not accept about\n' +
69
+ ' how they are declared.', rest);
70
+ group('what the rules refuse', ' every rule this framework ships and every rule this app added, run over the files each one\n' +
71
+ ` governs — ${String(ran.rules)} rule(s) over ${String(ran.swept)} of ${String(ran.tracked)} tracked file(s).\n` +
72
+ ' This is what `thread sweep` reports, said here so one read answers the whole question.', refused);
73
+ group('derivations nothing has produced yet', ' each row here states what a generator would write, and no file is there. A generator that refuses\n' +
74
+ ' to write an empty file is doing its job, so the descent says these and does not refuse them, and\n' +
75
+ ' neither does this. Run the command the row names in `by` to produce the file.', warned);
76
+ const total = cut.length + wrong.length + rest.length + refused.length;
77
+ const saidNotCounted = () => {
78
+ if (warned.length === 0)
79
+ return;
80
+ stdout.write(`issues: ${String(warned.length)} derivation(s) nothing has produced yet — listed below, said and not counted.\n`);
81
+ };
82
+ if (total === 0) {
83
+ stdout.write(`issues: none — ${String(tracked.length)} tracked file(s), every one of them declared by a row, and all of them compile.\n` +
84
+ 'issues: that is what a threaded tree is. Nothing here is written by hand; everything here was declared.\n');
85
+ saidNotCounted();
86
+ if (out.length > 0)
87
+ stdout.write(`${out.join('\n')}\n`);
88
+ exit(0);
89
+ }
90
+ stdout.write(`issues: ${String(total)} — ${String(cut.length)} file(s) nothing declares, ${String(wrong.length)} that will not compile, ` +
91
+ `${String(rest.length)} declared in a way it refuses, ${String(refused.length)} the rules refuse, over ${String(tracked.length)} tracked file(s).\n`);
92
+ saidNotCounted();
93
+ stdout.write(under === undefined
94
+ ? `issues: listing all ${String(total)} below. \`thread issues ${WITHIN} <path>\` reports on one directory instead.\n`
95
+ : `issues: listing the ${String(shown)} of them under ${under}. The counts above are the whole tree.\n`);
96
+ stdout.write(checking
97
+ ? `issues: ${CHECK} refuses while any of these stand. Without it this reads and never refuses, so it still answers on a tree that is entirely broken.\n`
98
+ : `issues: this reads and never refuses, so it works on a tree that is entirely broken. Run it with ${CHECK}, which is what the gate runs, to have it refuse instead.\n`);
99
+ stdout.write(`${out.join('\n')}\n`);
100
+ exit(checking ? 1 : 0);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,186 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { spawnSync } from 'node:child_process';
10
+ import { existsSync, readFileSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { argv, env, execPath, stderr, stdout } from 'node:process';
13
+ import { pathToFileURL } from 'node:url';
14
+ import { CLI, exit } from "../../core/invoked.js";
15
+ import { named } from "../../core/scope.js";
16
+ import { findTree, inTree } from "../../core/tree.js";
17
+ import { opened, sealedIn } from "../../integrations/vault.js";
18
+ const TREE = findTree();
19
+ const ROOT = TREE.at;
20
+ const STEP_TIMEOUT = 900_000;
21
+ const REGISTRY = '--registry';
22
+ const DEFAULT = 'https://registry.npmjs.org';
23
+ const CHECKS = [
24
+ {
25
+ id: 'gate',
26
+ runs: 'thread gate',
27
+ because: 'every step this tree declares, in the order it declares them, which is where the descent and the sweep are',
28
+ },
29
+ {
30
+ id: 'lint',
31
+ runs: 'pnpm exec eslint .',
32
+ because: 'the rules that live on the lint surface, which is the only one carrying a fixer the sweep can report but not repair',
33
+ },
34
+ {
35
+ id: 'seal',
36
+ runs: 'pnpm seal:check',
37
+ because: 'the package must be the bytes it says it is. CHECKED and never regenerated, because a release that rewrites its own seal can never fail it',
38
+ },
39
+ ];
40
+ const MINE = /^(?:npx |pnpm )?thread /;
41
+ function run(what, extra) {
42
+ const ours = MINE.exec(what);
43
+ if (ours !== null) {
44
+ const words = what.slice(ours[0].length).split(/\s+/).filter((one) => one !== '');
45
+ const ran = spawnSync(execPath, [...CLI, ...words], {
46
+ cwd: ROOT,
47
+ stdio: 'inherit',
48
+ timeout: STEP_TIMEOUT,
49
+ killSignal: 'SIGKILL',
50
+ env: extra === undefined ? env : { ...env, ...extra },
51
+ });
52
+ return ran.error !== undefined ? 1 : (ran.status ?? 1);
53
+ }
54
+ const result = spawnSync(what, {
55
+ shell: true,
56
+ cwd: ROOT,
57
+ stdio: 'inherit',
58
+ timeout: STEP_TIMEOUT,
59
+ killSignal: 'SIGKILL',
60
+ env: extra === undefined ? env : { ...env, ...extra },
61
+ });
62
+ return result.error !== undefined ? 1 : (result.status ?? 1);
63
+ }
64
+ function refuse(id, code, because, runs) {
65
+ stderr.write(`\npublish: REFUSED — \`${id}\` exited ${String(code)}. NOTHING was published.\n`);
66
+ stderr.write(`publish: ${because}.\n`);
67
+ stderr.write(`publish: what refused is above, in that command's own words — this does not restate it, because a\n`);
68
+ stderr.write(`publish: second copy of a refusal drifts from the first. Run \`${runs}\` alone to work on it.\n`);
69
+ exit(1);
70
+ }
71
+ const flag = argv.indexOf(REGISTRY);
72
+ const registry = flag === -1 ? DEFAULT : (argv[flag + 1] ?? '');
73
+ if (registry === '' || registry.startsWith('-')) {
74
+ stderr.write(`thread publish ${REGISTRY} <url> where the packages go. Leave it off for ${DEFAULT}.\n`);
75
+ stderr.write('\nit builds, then runs every check, then publishes. A check that fails publishes nothing.\n');
76
+ exit(1);
77
+ }
78
+ const TOKEN = 'sec_registry_token';
79
+ const PRODUCTION = 'production';
80
+ const secrets = inTree(TREE, 'secrets.ts');
81
+ const declared = existsSync(secrets)
82
+ ? ((await import(__rewriteRelativeImportExtension(pathToFileURL(secrets).href))).SECRETS ?? [])
83
+ : [];
84
+ const vaulted = declared.some((one) => one.id === TOKEN);
85
+ if (vaulted && !sealedIn(ROOT, PRODUCTION).includes(TOKEN)) {
86
+ 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`);
87
+ 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`);
88
+ exit(1);
89
+ }
90
+ const setting = () => {
91
+ const at = new URL(registry);
92
+ return `npm_config_//${at.host}${at.pathname.endsWith('/') ? at.pathname : `${at.pathname}/`}:_authToken`;
93
+ };
94
+ async function tokened() {
95
+ const values = await opened(ROOT, declared.map((one) => one.id), PRODUCTION)([TOKEN]).catch((thrown) => {
96
+ stderr.write(`\npublish: ${TOKEN} is sealed here and would not open: ${thrown instanceof Error ? thrown.message : String(thrown)}. NOTHING was published.\n`);
97
+ exit(1);
98
+ });
99
+ const token = values[TOKEN];
100
+ if (token === undefined) {
101
+ stderr.write(`\npublish: the vault opened and answered nothing for ${TOKEN}. NOTHING was published.\n`);
102
+ exit(1);
103
+ }
104
+ return token;
105
+ }
106
+ stdout.write(vaulted
107
+ ? `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`
108
+ : `publish: no row declares ${TOKEN}, so this publish uses the login this machine already holds. Declare it with \`thread create secret\` to publish with a token sealed in this repository instead.\n`);
109
+ 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');
110
+ const made = run('npx thread packaged --build');
111
+ stdout.write(`publish: packaged exited ${String(made)}\n`);
112
+ if (made !== 0) {
113
+ 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', 'npx thread packaged --build');
114
+ }
115
+ stdout.write(`\npublish: ${String(CHECKS.length)} check(s) stand between this tree and ${registry}. Any one of them stops it.\n`);
116
+ for (const check of CHECKS)
117
+ stdout.write(` ${check.id} — ${check.runs}\n`);
118
+ for (const [index, check] of CHECKS.entries()) {
119
+ const at = `check ${String(index + 1)} of ${String(CHECKS.length)}`;
120
+ stdout.write(`\npublish: ${at} — ${check.runs} (${check.id})\n`);
121
+ const code = run(check.runs);
122
+ stdout.write(`publish: ${at} — exited ${String(code)}\n`);
123
+ if (code !== 0)
124
+ refuse(check.id, code, check.because, check.runs);
125
+ }
126
+ const numbered = run('npx thread packaged --release');
127
+ stdout.write(`publish: packaged --release exited ${String(numbered)}\n`);
128
+ if (numbered !== 0) {
129
+ refuse('packaged', numbered, 'the next release number and its note are written only once every check has passed, and writing them refused, so nothing here carries a number to go out under', 'npx thread packaged --release');
130
+ }
131
+ const handed = vaulted ? { [setting()]: await tokened() } : undefined;
132
+ stdout.write(`\npublish: every check passed. Publishing to ${registry} with ${vaulted ? `${TOKEN} from this repository's vault` : 'the login this machine already holds'}.\n`);
133
+ const sent = run(`pnpm -r publish --registry ${registry} --no-git-checks --access public`, handed);
134
+ if (sent !== 0) {
135
+ stderr.write(`\npublish: the checks passed and the publish itself exited ${String(sent)}.\n`);
136
+ stderr.write('publish: the third number of the release moved once for this publish, so if npm refused the version as one that already exists,\n');
137
+ stderr.write('publish: the release notes here are behind what the registry holds — read the newest entry in each CHANGELOG.md against the registry before running this again.\n');
138
+ exit(1);
139
+ }
140
+ const SHEET = 'packaging.ts';
141
+ const sheet = inTree(TREE, SHEET);
142
+ const stated = existsSync(sheet)
143
+ ? (await import(__rewriteRelativeImportExtension(pathToFileURL(sheet).href)))
144
+ : {};
145
+ const shipped = stated.PACKAGES ?? [];
146
+ function versionAt(folder) {
147
+ const at = join(ROOT, folder, 'package.json');
148
+ if (!existsSync(at))
149
+ return 'no manifest';
150
+ try {
151
+ return JSON.parse(readFileSync(at, 'utf8')).version ?? 'no version';
152
+ }
153
+ catch {
154
+ return 'no version';
155
+ }
156
+ }
157
+ function asked(what) {
158
+ return (spawnSync('git', what, { cwd: ROOT, encoding: 'utf8' }).stdout ?? '').trim();
159
+ }
160
+ if (asked(['rev-parse', '--is-inside-work-tree']) !== 'true') {
161
+ stdout.write("\npublish: it's not a repo, so nothing was committed.\n");
162
+ }
163
+ else if (shipped.length === 0) {
164
+ stdout.write('\npublish: no packaging row names a folder, so there is nothing derived here to commit.\n');
165
+ }
166
+ else {
167
+ const going = shipped.map((one) => `${named(one.id ?? '')} ${versionAt(one.folder ?? '')}`).join(', ');
168
+ const branch = asked(['rev-parse', '--abbrev-ref', 'HEAD']);
169
+ for (const one of shipped)
170
+ run(`git add ${one.folder ?? ''}`);
171
+ if (spawnSync('git', ['diff', '--cached', '--quiet'], { cwd: ROOT }).status === 0) {
172
+ stdout.write(`\npublish: ${going} — what is on disk is already what is committed, so this release added no artifact.\n`);
173
+ }
174
+ else {
175
+ const wrote = run(`git commit -m ${JSON.stringify(`thread publish — ${going}`)}`);
176
+ stdout.write(`publish: commit exited ${String(wrote)}\n`);
177
+ if (wrote !== 0) {
178
+ 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
+ stderr.write('publish: commit them by hand — everything is staged.\n');
180
+ exit(1);
181
+ }
182
+ stdout.write(`publish: committed the derived artifacts to ${branch} — ${going}.\n`);
183
+ }
184
+ }
185
+ stdout.write(`\npublish: done. What went out was derived, then built, then passed the gate, the lint and the seal, in that order. The compile inside \`thread packaged --build\` is the typecheck.\n`);
186
+ exit(0);
@@ -0,0 +1,2 @@
1
+ import { type Asked } from '../../core/asking.ts';
2
+ export declare const ASKS: readonly Asked[];