@prestack/thread 0.1.21 → 0.1.23

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 (138) hide show
  1. package/CHANGELOG.md +227 -0
  2. package/dist/core/attach.js +21 -0
  3. package/dist/core/descend.js +6 -3
  4. package/dist/core/generators/commit.js +55 -3
  5. package/dist/core/generators/dev.d.ts +1 -0
  6. package/dist/core/generators/dev.js +69 -0
  7. package/dist/derivation/generators/build.d.ts +3 -1
  8. package/dist/derivation/generators/build.js +104 -22
  9. package/dist/derivation/generators/release.js +74 -25
  10. package/dist/derivation/release.js +3 -3
  11. package/dist/integrations/cli.d.ts +0 -1
  12. package/dist/integrations/cli.js +69 -11
  13. package/dist/integrations/declared.d.ts +2 -0
  14. package/dist/integrations/declared.js +6 -1
  15. package/dist/integrations/pglite.js +13 -3
  16. package/dist/integrations/target.d.ts +3 -0
  17. package/dist/integrity/attach.js +1 -5
  18. package/dist/integrity/slopnators/sl_stale_path.js +10 -0
  19. package/dist/operations/access.js +3 -2
  20. package/dist/operations/capabilities.d.ts +2 -0
  21. package/dist/operations/capabilities.js +2 -0
  22. package/dist/operations/generators/capability.js +237 -24
  23. package/dist/operations/generators/compile.js +150 -50
  24. package/dist/operations/generators/seed.d.ts +3 -0
  25. package/dist/operations/generators/seed.js +25 -3
  26. package/dist/operations/nodes.d.ts +2 -2
  27. package/package.json +1 -1
  28. package/dist/core/actor.ts +0 -21
  29. package/dist/core/attach.ts +0 -613
  30. package/dist/core/chain.ts +0 -145
  31. package/dist/core/condition.ts +0 -227
  32. package/dist/core/descend.ts +0 -1185
  33. package/dist/core/errors/catalogue.ts +0 -314
  34. package/dist/core/errors/classes.ts +0 -51
  35. package/dist/core/errors/error.ts +0 -152
  36. package/dist/core/errors/namespaces.ts +0 -19
  37. package/dist/core/finding.ts +0 -37
  38. package/dist/core/generators/commit.ts +0 -157
  39. package/dist/core/init.ts +0 -222
  40. package/dist/core/invoked.ts +0 -52
  41. package/dist/core/round.ts +0 -74
  42. package/dist/core/rows.ts +0 -506
  43. package/dist/core/scope.ts +0 -20
  44. package/dist/core/thread.ts +0 -29
  45. package/dist/core/tree.ts +0 -90
  46. package/dist/core/types.ts +0 -351
  47. package/dist/derivation/attach.ts +0 -57
  48. package/dist/derivation/generators/build.ts +0 -371
  49. package/dist/derivation/generators/check.ts +0 -118
  50. package/dist/derivation/generators/determinism.ts +0 -145
  51. package/dist/derivation/generators/release.ts +0 -236
  52. package/dist/derivation/release.ts +0 -43
  53. package/dist/integrations/attach.ts +0 -187
  54. package/dist/integrations/cli.ts +0 -606
  55. package/dist/integrations/declared.ts +0 -34
  56. package/dist/integrations/disk.ts +0 -466
  57. package/dist/integrations/generators/read.ts +0 -127
  58. package/dist/integrations/generators/vault.ts +0 -210
  59. package/dist/integrations/https.ts +0 -216
  60. package/dist/integrations/pglite.ts +0 -206
  61. package/dist/integrations/secret.ts +0 -54
  62. package/dist/integrations/target.ts +0 -672
  63. package/dist/integrations/vault.ts +0 -148
  64. package/dist/integrity/attach.ts +0 -150
  65. package/dist/integrity/check-threads.ts +0 -166
  66. package/dist/integrity/constraint.ts +0 -1246
  67. package/dist/integrity/generators/compiler.ts +0 -138
  68. package/dist/integrity/generators/gate.ts +0 -227
  69. package/dist/integrity/generators/issues.ts +0 -160
  70. package/dist/integrity/generators/publish.ts +0 -233
  71. package/dist/integrity/generators/trial.ts +0 -359
  72. package/dist/integrity/lint.ts +0 -214
  73. package/dist/integrity/lsp/bin.ts +0 -44
  74. package/dist/integrity/lsp/diagnostics.ts +0 -92
  75. package/dist/integrity/lsp/findings.ts +0 -63
  76. package/dist/integrity/lsp/lint.ts +0 -124
  77. package/dist/integrity/lsp/protocol.ts +0 -78
  78. package/dist/integrity/lsp/server.ts +0 -224
  79. package/dist/integrity/slopnator.ts +0 -324
  80. package/dist/integrity/slopnators/sl_broken_lineage.ts +0 -38
  81. package/dist/integrity/slopnators/sl_declared_elsewhere.ts +0 -60
  82. package/dist/integrity/slopnators/sl_derived_drift.ts +0 -101
  83. package/dist/integrity/slopnators/sl_door_in_a_node.ts +0 -250
  84. package/dist/integrity/slopnators/sl_hardcoded_style.ts +0 -55
  85. package/dist/integrity/slopnators/sl_inert_island.ts +0 -84
  86. package/dist/integrity/slopnators/sl_inert_slopnator.ts +0 -93
  87. package/dist/integrity/slopnators/sl_missing_row.ts +0 -140
  88. package/dist/integrity/slopnators/sl_no_barrel.ts +0 -48
  89. package/dist/integrity/slopnators/sl_no_child_process.ts +0 -100
  90. package/dist/integrity/slopnators/sl_no_comment.ts +0 -43
  91. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +0 -276
  92. package/dist/integrity/slopnators/sl_no_import_cycle.ts +0 -66
  93. package/dist/integrity/slopnators/sl_no_such_command.ts +0 -81
  94. package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +0 -63
  95. package/dist/integrity/slopnators/sl_outside_an_operation.ts +0 -25
  96. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +0 -70
  97. package/dist/integrity/slopnators/sl_secret_literal.ts +0 -68
  98. package/dist/integrity/slopnators/sl_stale_path.ts +0 -178
  99. package/dist/integrity/slopnators/sl_twice_meant.ts +0 -57
  100. package/dist/integrity/slopnators/sl_twice_parented.ts +0 -82
  101. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +0 -481
  102. package/dist/integrity/slopnators/sl_undeclared_destination.ts +0 -113
  103. package/dist/integrity/slopnators/sl_undeclared_element.ts +0 -44
  104. package/dist/integrity/slopnators/sl_undeclared_list.ts +0 -358
  105. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -75
  106. package/dist/integrity/slopnators/sl_undeclared_operation.ts +0 -257
  107. package/dist/integrity/slopnators/sl_undeclared_variant.ts +0 -152
  108. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +0 -108
  109. package/dist/integrity/slopnators/sl_underived_route.ts +0 -72
  110. package/dist/integrity/slopnators/sl_undescribed.ts +0 -65
  111. package/dist/integrity/slopnators/sl_ungoverned_island.ts +0 -60
  112. package/dist/integrity/slopnators/sl_unlisted_program.ts +0 -46
  113. package/dist/integrity/slopnators/sl_unnamed_island.ts +0 -41
  114. package/dist/integrity/slopnators/sl_unpaired_member.ts +0 -139
  115. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +0 -71
  116. package/dist/integrity/slopnators/sl_unprefixed_member.ts +0 -110
  117. package/dist/integrity/slopnators/sl_unthreaded.ts +0 -421
  118. package/dist/integrity/slopnators/sl_untranslated_key.ts +0 -140
  119. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +0 -132
  120. package/dist/integrity/slopnators/sl_unversioned.ts +0 -52
  121. package/dist/integrity/sweep.ts +0 -395
  122. package/dist/knowledge/attach.ts +0 -327
  123. package/dist/knowledge/generators/docsgen.ts +0 -186
  124. package/dist/knowledge/generators/glossary.ts +0 -73
  125. package/dist/knowledge/glossary.ts +0 -6
  126. package/dist/operations/access.ts +0 -131
  127. package/dist/operations/attach.ts +0 -408
  128. package/dist/operations/capabilities.ts +0 -88
  129. package/dist/operations/dispatch.ts +0 -294
  130. package/dist/operations/error-results.ts +0 -31
  131. package/dist/operations/generators/capability.ts +0 -1054
  132. package/dist/operations/generators/compile.ts +0 -701
  133. package/dist/operations/generators/permits.ts +0 -229
  134. package/dist/operations/generators/seed.ts +0 -359
  135. package/dist/operations/generators/trial.ts +0 -666
  136. package/dist/operations/nodes.ts +0 -53
  137. package/dist/operations/operations.ts +0 -91
  138. package/dist/operations/result.ts +0 -28
@@ -1,327 +0,0 @@
1
- import type { Attaching } from '../core/attach.ts'
2
-
3
- import { SHAPED } from '../core/init.ts'
4
- import { quoted } from '../core/rows.ts'
5
-
6
- const DESCRIBES =
7
- 'The system that compiles what this repository holds into forms a reader can understand — the glossary first, and every later view of the tree computed rather than written.'
8
-
9
- const CONCEPTS =
10
- 'Every word this framework means something specific by that no declaration coins — its own verbs and the fields they sit in, written by a person because nothing in the tree can state them, and read into the glossary with everything else.'
11
-
12
- const CONCEPTS_SOURCE = `import type { Member } from '${SHAPED}'
13
-
14
- export interface Concept extends Member {
15
- readonly avoid?: readonly string[]
16
- }
17
-
18
- export const CONCEPTS: readonly Concept[] = [
19
- {
20
- id: 'id',
21
- at: '_threads/concepts.ts',
22
- describes: 'The word a declaration coins. Every id enters the glossary and the \`describes\` beside it becomes the meaning there, so naming a thing is how this framework acquires vocabulary, and one word carrying two meanings is a contradiction the tree can see.',
23
- version: 1,
24
- cites: [
25
- { on: '2026-08-19', said: 'we need it to start with the threads concepts first, coin the ids and describe what it means.' },
26
- ],
27
- },
28
- {
29
- id: 'wearing',
30
- at: '_threads/concepts.ts',
31
- describes: 'The relation an app declares between one of its own variants and the elements that may put it on. The framework ships an empty one and an app widens it, so a member named for a variant the app declared compiles and is offered wherever that variant says the element wears it — autocomplete reaching the variants an app added, without the package ever holding a list of them.',
32
- version: 1,
33
- cites: [
34
- { on: '2026-08-25', said: 'Autocomplete should be a framework feature for sure.' },
35
- { on: '2026-08-25', said: 'Wearing' },
36
- ],
37
- },
38
- {
39
- id: 'dispatching',
40
- at: '_threads/concepts.ts',
41
- describes: 'The operations this app declares, named wherever something reaches one. The framework ships an empty list and each app widens it, so a name written at a call site is accepted only when this app declared an operation by it.',
42
- version: 1,
43
- cites: [
44
- { on: '2026-08-25', said: 'And make sure the composition can only dispatch existing operations.' },
45
- { on: '2026-08-25', said: 'Type only for both.' },
46
- ],
47
- },
48
- {
49
- id: 'holds',
50
- at: '_threads/concepts.ts',
51
- describes: 'What a sheet contains rather than what it authored. A row here is a named value — a token, a style guide entry, a signal, a mode, a theme — and it carries no address, because a value is not a file and nothing wrote it anywhere. That is what tells it from declares, which is the verb of authorship and admits exactly one owner per address: a hundred values written into one sheet would otherwise read as a hundred authors of it.',
52
- version: 1,
53
- cites: [
54
- { on: '2026-08-26', said: 'No there\\'s just something completely wrong about how you did this, that\\'s why you got this error. The law is not wrong' },
55
- { on: '2026-08-26', said: 'holds' },
56
- ],
57
- },
58
- {
59
- id: 'at',
60
- at: '_threads/concepts.ts',
61
- describes: 'Where a declared thing lives, written as a path from the root. It is a string and never an import, which is the whole trick that lets a parent name a child without depending on it: the descent resolves the string when it runs and slopnators in. A path naming a directory threads nothing beneath it.',
62
- version: 1,
63
- cites: [
64
- { on: '2026-08-19', said: 'we need it to start with the threads concepts first, coin the ids and describe what it means.' },
65
- ],
66
- },
67
- {
68
- id: 'describes',
69
- at: '_threads/concepts.ts',
70
- describes: 'What a thing is and what it solves, to somebody who has not seen it. It is the one piece of prose the tree requires, and the glossary takes each word’s meaning from here, so a sentence that restates the id leaves the word defined by nothing.',
71
- version: 1,
72
- cites: [
73
- { on: '2026-08-19', said: 'we need it to start with the threads concepts first, coin the ids and describe what it means.' },
74
- ],
75
- },
76
- {
77
- id: 'version',
78
- at: '_threads/concepts.ts',
79
- describes: 'Which one of itself a governing declaration is, so a change to it is a difference a consumer can see rather than a move underneath things already built against it.',
80
- version: 1,
81
- cites: [
82
- { on: '2026-08-19', said: 'we need it to start with the threads concepts first, coin the ids and describe what it means.' },
83
- ],
84
- },
85
- {
86
- id: 'cites',
87
- at: '_threads/concepts.ts',
88
- describes: 'Whose words permitted a thing to exist, quoted as they were said and dated. It records who decided rather than what was decided, which is \`describes\`, so a declaration nobody asked for is visible as one.',
89
- version: 1,
90
- cites: [
91
- { on: '2026-08-19', said: 'we need it to start with the threads concepts first, coin the ids and describe what it means.' },
92
- ],
93
- },
94
- {
95
- id: 'by',
96
- at: '_threads/concepts.ts',
97
- describes: 'The command that writes a byproduct. Somewhere across the declarations naming one derived address, one of them owes this, because a generated file whose generator is unnamed cannot be checked against what it should be.',
98
- version: 1,
99
- cites: [
100
- { on: '2026-08-19', said: 'we need it to start with the threads concepts first, coin the ids and describe what it means.' },
101
- ],
102
- },
103
- {
104
- id: 'runs',
105
- at: '_threads/concepts.ts',
106
- describes: 'The command that proves a byproduct is still the bytes its generator writes. It is the other half of \`by\`: one names what made the file, the other names what catches it drifting.',
107
- version: 1,
108
- cites: [
109
- { on: '2026-08-19', said: 'we need it to start with the threads concepts first, coin the ids and describe what it means.' },
110
- ],
111
- },
112
- {
113
- id: 'declares',
114
- at: '_threads/concepts.ts',
115
- describes: 'The verb of authorship: a person wrote this file and the declaration is the truth about it. Exactly one may ever declare a given address, because a child with two owners has two answers for where it came from and the tree can give neither.',
116
- version: 1,
117
- cites: [
118
- { on: '2026-08-19', said: 'we need it to start with the threads concepts first, coin the ids and describe what it means.' },
119
- ],
120
- },
121
- {
122
- id: 'derives',
123
- at: '_threads/concepts.ts',
124
- describes: 'The verb of byproduct: delete the file, run the command again, and identical bytes come back. Many may derive the same kind, because a derivation owns nothing — it owes a \`by\` that writes it and a \`runs\` that proves it.',
125
- version: 1,
126
- cites: [
127
- { on: '2026-08-19', said: 'we need it to start with the threads concepts first, coin the ids and describe what it means.' },
128
- ],
129
- },
130
- {
131
- id: 'seeds',
132
- at: '_threads/concepts.ts',
133
- describes: 'The verb of scaffold: a machine writes the file out of the tree and a person fills the one field a machine cannot supply. Many may seed the same kind, and it is proved by shape rather than by bytes, because half of what is on disk is somebody’s own writing.',
134
- version: 1,
135
- cites: [
136
- { on: '2026-08-19', said: 'we need it to start with the threads concepts first, coin the ids and describe what it means.' },
137
- ],
138
- },
139
- {
140
- id: 'requires',
141
- at: '_threads/concepts.ts',
142
- describes: 'Demand that must be met: the thing named has to be there. Demand is not lineage and confers no ownership — needing a thing has never been the same as having been declared by it, which is why it is a word of its own and not a fourth verb.',
143
- version: 1,
144
- avoid: ['needs'],
145
- cites: [
146
- { on: '2026-08-19', said: 'Do add to it requires and takes cause these will also be part of it.' },
147
- { on: '2026-08-19', said: 'I see no reason to not have this, it\\'s useful.' },
148
- ],
149
- },
150
- {
151
- id: 'pass',
152
- at: '_threads/concepts.ts',
153
- describes: 'One traversal of something, and what it found. The descent from the root is a pass; so is a slopnator over a syntax tree, or over the text of a file. The word names the act and its result together, which is why descending returns a \`Pass\` rather than a report about one.',
154
- version: 1,
155
- avoid: ['walk'],
156
- cites: [
157
- { on: '2026-08-20', said: 'Walk is pass.' },
158
- { on: '2026-08-20', said: 'walk is pass. fix it.' },
159
- ],
160
- },
161
- {
162
- id: 'slopnator',
163
- at: '_threads/concepts.ts',
164
- describes: 'The code that finds what a rule refuses — one per rule, resolved from the rule\\'s id, in one of three kinds: a pass over a syntax tree, a pass over a file\\'s text, or a command whose output is read.',
165
- version: 1,
166
- avoid: ['walk'],
167
- cites: [
168
- { on: '2026-08-19', said: 'I still don\\'t get why it\\'s called walk. Seems bizarre. Smells like slop' },
169
- { on: '2026-08-19', said: 'Then put walk in the concepts (not the repo\\'s, just the package, fuck the repo).' },
170
- ],
171
- },
172
- {
173
- id: 'takes',
174
- at: '_threads/concepts.ts',
175
- describes: 'Demand that may go unmet: the thing named is used when it is there. It is \`requires\` without the refusal, so something optional is stated rather than discovered by reading what happens when it is missing.',
176
- version: 1,
177
- cites: [
178
- { on: '2026-08-19', said: 'Do add to it requires and takes cause these will also be part of it.' },
179
- { on: '2026-08-19', said: 'I see no reason to not have this, it\\'s useful.' },
180
- ],
181
- },
182
- {
183
- id: 'threaded',
184
- at: '_threads/concepts.ts',
185
- describes: 'What a file is once some parent names it in \`declares\`, \`derives\` or \`seeds\`. A file is threaded or it is not, and the record of which parent did it and by which verb is a \`Threading\`. The framework is named for this, so nothing here claims, owns or registers anything — whatever the descent never reaches is unthreaded, and that absence is the finding.',
186
- version: 1,
187
- avoid: ['claim', 'claims', 'claimed'],
188
- cites: [
189
- { on: '2026-08-20', said: 'Claim I don\\'t fukcing know what is. We have threads, threaded, these are the fucking names. The framework is named for this damn it.' },
190
- { on: '2026-08-20', said: 'add whatever you need to add to put it in your head that it\\'s threaded not claimed.' },
191
- ],
192
- },
193
- {
194
- id: 'attribute',
195
- at: '_threads/concepts.ts',
196
- describes: 'One typed thing an entity holds: which kind of value it is, which refinement of that kind, and the bounds on it. It is the smallest thing a provider can be told to keep, and an attribute nothing declares is one nobody can account for.',
197
- version: 1,
198
- cites: [
199
- { on: '2026-08-21', said: 'Value and Invariant' },
200
- { on: '2026-08-28', said: 'The concept takes a different word' },
201
- ],
202
- },
203
- {
204
- id: 'invariant',
205
- at: '_threads/concepts.ts',
206
- describes: 'What is true of a thing no matter who is asking. It is written in the same condition language a grant uses and told apart from one mechanically rather than by taste: an invariant that reaches for the actor is true for some callers and false for others, so it is a grant somebody filed in the wrong place.',
207
- version: 1,
208
- cites: [
209
- { on: '2026-08-21', said: 'Value and Invariant' },
210
- ],
211
- },
212
- {
213
- id: 'grant',
214
- at: '_threads/concepts.ts',
215
- describes: 'One statement of who may do which verbs to which entity, narrowed to some of its values, under a condition the row must meet. A grant is a way in and nothing else: absence is refusal, and two standing together admit more than either alone.',
216
- version: 1,
217
- cites: [
218
- { on: '2026-08-21', said: 'Invariant + Grant' },
219
- { on: '2026-08-21', said: 'who can, when, where, how much' },
220
- ],
221
- },
222
- {
223
- id: 'target',
224
- at: '_threads/concepts.ts',
225
- describes: 'A declared destination — somewhere this app sends something or keeps something — named so that nothing ever reaches one it did not declare. It is one word across the framework and not two: an operation calls out to a target over the network, an entity is kept in a target, and both are the same idea of a place named before it is reached. What each package needs beyond that differs, and neither borrows the other\\'s shape: a target data keeps things in carries what it is on the prefix of its id, because what it can be made to enforce decides what may be written for it, and a declaration it cannot hold is refused where it was written rather than emitted as something that reads like enforcement and is not.',
226
- version: 1,
227
- cites: [
228
- { on: '2026-08-29', said: 'Target is not two things. Target is a destination, either in operations or in data.' },
229
- { on: '2026-08-29', said: 'it seems like this is the thing that decides what\\'s going to server and whats local, that it?' },
230
- ],
231
- },
232
- {
233
- id: 'setting',
234
- at: '_threads/concepts.ts',
235
- describes: 'One property a material or a variant sets, and where its value comes from: a value the style guide holds, named outright, or a token asked for one, arguments and all — never both together. It is the row both compose from, so a material’s resting look, its states, and a variant’s states are one shape instead of three that only resemble each other.',
236
- version: 1,
237
- cites: [],
238
- },
239
- {
240
- id: 'token',
241
- at: '_threads/concepts.ts',
242
- describes: 'A sort of variable an app may have, named and never valued — colour, space, shadow. It says such a variable can exist; the style guide says which ones there are and what each holds. Where the thing is better stated as a rule than as a list, the token carries that rule and a style guide row hands it arguments instead of a value. An app adds one to bring a new sort of variable into being, and may not remove what the framework put there.',
243
- version: 1,
244
- cites: [],
245
- },
246
- ]
247
- `
248
-
249
- const SEEDED = {
250
- attaches: ['@prestack/thread/derivation/attach'] as const,
251
- id: 'knowledge',
252
- declares: [
253
- ' {',
254
- ' id: \'knowledge\',',
255
- ' at: \'_threads/knowledge.ts\',',
256
- ' describes: \'The system that compiles what this repository holds into forms a reader can understand — the glossary first, and every later view of the tree computed rather than written.\',',
257
- ' version: 1,',
258
- ' },',
259
- ].join('\n'),
260
- }
261
-
262
- const SHIPPED: readonly { readonly into: string; readonly list: string; readonly id: string; readonly source: string }[] = [
263
- {
264
- into: 'derivation.ts',
265
- list: 'GENERATORS',
266
- id: 'glossary-generator',
267
- source: " {\n id: 'glossary-generator',\n at: 'node_modules/@prestack/thread/dist/knowledge/generators/glossary.js',\n describes: 'The generator of the glossary — it descends the tree, takes the `describes` from the row that coins each word, and writes them in the order the descent reaches them.',\n version: 1,\n by: 'thread glossary',\n runs: 'thread glossary --check',\n },",
268
- },
269
- {
270
- into: 'derivation.ts',
271
- list: 'GENERATORS',
272
- id: 'docs-generator',
273
- source: " {\n id: 'docs-generator',\n at: 'node_modules/@prestack/thread/dist/knowledge/generators/docsgen.js',\n describes: 'The writer of the page stating what this app declares — it descends the tree once and writes every node, everything each one declares and derives, and the command that writes each of those, with the sentence the row itself states. It moved here from the package that had operations in it, where it could only ever have documented operations: a package stating what another package declares would be one package authoring another\\'s. Where an operation has been run, the count of recorded runs is taken from the trials file by path if that file is there, so what proves an operation survives without anything here depending on the package that produces it.',\n version: 1,\n by: 'thread docs',\n runs: 'thread docs --check',\n },",
274
- },
275
- ]
276
- export const ATTACH: Attaching = {
277
- attaches: SEEDED.attaches,
278
- id: SEEDED.id,
279
- declares: SEEDED.declares,
280
- writes: [
281
- {
282
- file: 'knowledge.ts',
283
- source: [
284
- `import type { Threaded } from '${SHAPED}'`,
285
- '',
286
- 'export const KNOWLEDGE: Threaded = {',
287
- " id: 'knowledge',",
288
- " at: '_threads/knowledge.ts',",
289
- ` describes: ${quoted(DESCRIBES)},`,
290
- ' version: 1,',
291
- ' declares: [',
292
- ' {',
293
- " id: 'concepts',",
294
- " at: '_threads/concepts.ts',",
295
- ` describes: ${quoted(CONCEPTS)},`,
296
- ' },',
297
- ' ],',
298
- ' derives: [',
299
- ' {',
300
- " id: 'glossary',",
301
- " at: '_threads/glossary.ts',",
302
- " describes: 'Every word this repository coins and what it means — one row per word, taken from the `describes` on the row that declares it, ordered by the descent, so the file is the tree read as vocabulary rather than a list kept beside it.',",
303
- ' version: 1,',
304
- " by: 'thread glossary',",
305
- " runs: 'thread glossary --check',",
306
- ' },',
307
-
308
- ' {',
309
- " id: 'docs',",
310
- " at: 'docs.md',",
311
- " describes: 'What this app declares, as a page: every node, what it declares, what it derives and what writes each of those, with the sentence each row states about itself. It is the glossary\\'s other half — that one says what every coined word means, this one says what every row is — and both are the same descent read twice, so a section going out of date is a bug rather than a chore.',",
312
- ' version: 1,',
313
- " by: 'thread docs',",
314
- " runs: 'thread docs --check',",
315
- ' },',
316
- ' ],',
317
- '}',
318
- '',
319
- ].join('\n'),
320
- },
321
- {
322
- file: 'concepts.ts',
323
- source: CONCEPTS_SOURCE,
324
- },
325
- ],
326
- rows: SHIPPED,
327
- }
@@ -1,186 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync } from '../../integrations/disk.ts'
2
- import { resolve } from 'node:path'
3
- import { argv, stderr, stdout } from 'node:process'
4
-
5
- import { exit } from '../../core/invoked.ts'
6
- import { ROOT, descend, type Pass, type Row } from '../../core/descend.ts'
7
- import { forbids, runChecker, type Finding } from '../../core/finding.ts'
8
- import { agentInstructions } from '../../integrity/lint.ts'
9
-
10
- const AT = 'docs.md'
11
-
12
- const CHECKING = argv.includes('--check')
13
-
14
- const SHOWING = argv.includes('--show')
15
-
16
- const TRIALS_AT = 'operations/_trials.json'
17
-
18
- function refuse(why: string): never {
19
- stderr.write(`docs: ${why}\n`)
20
- exit(1)
21
- }
22
-
23
- const text = (value: unknown): string | undefined => (typeof value === 'string' && value !== '' ? value : undefined)
24
-
25
- const said = (one: Row): string => text(one.describes) ?? '_no `describes` — this row says nothing about itself._'
26
-
27
- const pass = await descend()
28
-
29
- const stopped = [...pass.broken, ...pass.findings].filter(forbids)[0]
30
- if (stopped !== undefined) {
31
- refuse(
32
- 'the descent is broken, so this would state a tree that is only partly known and read afterwards as the whole of it — ' +
33
- `${stopped.detail} (${stopped.file ?? ''})`,
34
- )
35
- }
36
-
37
- const PATH = resolve(ROOT, AT)
38
-
39
- interface Ran {
40
- readonly operation?: string
41
- readonly scenario?: string
42
- readonly ok?: boolean
43
- }
44
-
45
- const proven = (): ReadonlyMap<string, number> => {
46
- const found = new Map<string, number>()
47
- const at = resolve(ROOT, TRIALS_AT)
48
- if (!existsSync(at)) return found
49
- try {
50
- const held = JSON.parse(readFileSync(at, 'utf8')) as readonly Ran[]
51
- for (const one of held) {
52
- const which = text(one.operation)
53
- if (which === undefined) continue
54
- found.set(which, (found.get(which) ?? 0) + 1)
55
- }
56
- } catch {
57
- return found
58
- }
59
- return found
60
- }
61
-
62
- function grouped(held: Pass): ReadonlyMap<string, readonly { readonly list: string; readonly row: Row }[]> {
63
- const found = new Map<string, { readonly list: string; readonly row: Row }[]>()
64
- for (const threadings of held.threaded.values()) {
65
- for (const one of threadings) {
66
- const kept = found.get(one.by) ?? []
67
- kept.push({ list: one.list, row: one.row })
68
- found.set(one.by, kept)
69
- }
70
- }
71
- return found
72
- }
73
-
74
- const under = grouped(pass)
75
- const trials = proven()
76
-
77
- const named = (one: Row): string => text(one.id) ?? text(one.at) ?? '(unnamed)'
78
-
79
- const line = (one: { readonly list: string; readonly row: Row }): string => {
80
- const row = one.row
81
- const where = text(row.at)
82
- const by = text(row.by)
83
- const runs = text(row.runs)
84
- const ran = trials.get(named(row))
85
-
86
- return [
87
- `- **${named(row)}**${where === undefined ? '' : ` — \`${where}\``}`,
88
- ` ${said(row)}`,
89
- ...(by === undefined ? [] : [` Written by \`${by}\`${runs === undefined ? '' : `, checked by \`${runs}\``}.`]),
90
- ...((row.requires ?? []).length === 0 ? [] : [` Requires ${(row.requires ?? []).map((each) => `\`${each}\``).join(', ')}.`]),
91
- ...((row.takes ?? []).length === 0 ? [] : [` Takes ${(row.takes ?? []).map((each) => `\`${each}\``).join(', ')}.`]),
92
-
93
- ...(ran === undefined ? [] : [` Proved by ${String(ran)} recorded run(s).`]),
94
- ].join('\n')
95
- }
96
-
97
- const words = [...pass.coined].sort(([one], [two]) => (one < two ? -1 : 1))
98
-
99
- const threadedRows = new Set([...pass.threaded.values()].flat().map((one) => one.row))
100
- const loose = [...pass.stated.values()].filter((one) => !threadedRows.has(one))
101
- const commands = [...pass.derived.values(), ...[...under.values()].flat().map((one) => one.row), ...loose]
102
- .filter((one) => text(one.by)?.startsWith('thread ') === true)
103
- .reduce((found, one) => found.set(text(one.by) as string, one), new Map<string, Row>())
104
-
105
- const sections = [...under.keys()].sort()
106
-
107
- const refused = agentInstructions()
108
-
109
- const page = [
110
- '<!-- GENERATED by `thread docs` from what this app declares — do not edit by hand.',
111
- ' Every sentence here is the `describes` on a row. To change one, change the row. -->',
112
- '',
113
- '# What this app declares',
114
- '',
115
- `${String(pass.declarations)} declaration(s) over ${String(pass.rows)} row(s), read from the tree by the same descent`,
116
- 'every generator here reads. This page is rewritten whenever a package is attached and whenever a',
117
- 'command writes a row, so a section that is out of date is a bug rather than a chore.',
118
- '',
119
- '## Commands',
120
- '',
121
- ...(commands.size === 0
122
- ? ['_nothing here declares a command yet._']
123
- : [...commands.entries()]
124
- .sort(([one], [two]) => (one < two ? -1 : 1))
125
- .map(([word, one]) => `- \`${word}\` — ${said(one)}`)),
126
- '',
127
- '## What the build refuses',
128
- '',
129
- 'Every rule below stops a build outright. Each line pairs the code it rejects with the code it requires instead.',
130
- '',
131
- ...(refused.length === 0
132
- ? ['_nothing here refuses anything yet._']
133
- : refused.map((rule) => `- ${rule}`)),
134
- '',
135
- ...sections.flatMap((node) => {
136
- const own = pass.stated.get(node) ?? pass.derived.get(node)
137
- const kept = under.get(node) ?? []
138
- const declares = kept.filter((one) => one.list === 'declares')
139
- const derives = kept.filter((one) => one.list === 'derives')
140
- const seeds = kept.filter((one) => one.list === 'seeds')
141
- return [
142
- `## ${node}`,
143
- '',
144
- ...(own === undefined ? [] : [said(own), '']),
145
- ...(declares.length === 0 ? [] : ['### What it declares', '', ...declares.map(line), '']),
146
- ...(derives.length === 0 ? [] : ['### What it derives', '', ...derives.map(line), '']),
147
- ...(seeds.length === 0 ? [] : ['### What it seeds', '', ...seeds.map(line), '']),
148
- ]
149
- }),
150
- '## Every word this app coins',
151
- '',
152
- ...(words.length === 0
153
- ? ['_nothing here coins a word yet._']
154
- : words.map(([word, held]) => `- **${word}** — ${held.said[0] ?? '_no meaning stated_'}`)),
155
- '',
156
- ].join('\n')
157
-
158
- if (SHOWING) {
159
- stdout.write(page)
160
- exit(0)
161
- }
162
-
163
- if (CHECKING) {
164
- const findings: Finding[] = []
165
- const held = existsSync(PATH) ? readFileSync(PATH, 'utf8') : undefined
166
- if (held === undefined) {
167
- findings.push({
168
- detail: `${AT} is not there, and this app declares it`,
169
- instead: `Run \`thread docs\`. Nothing writes this page by hand — it is what the tree says, read back.`,
170
- file: AT,
171
- severity: 'forbidden',
172
- })
173
- } else if (held !== page) {
174
- findings.push({
175
- detail: `${AT} states something other than what this tree declares`,
176
- instead: `Run \`thread docs\`. A sentence here is the \`describes\` on a row — to change one, change the row.`,
177
- file: AT,
178
- severity: 'forbidden',
179
- })
180
- }
181
- runChecker('docs', findings, `${AT} states every row this app declares, ${String(pass.rows)} of them`)
182
- exit(findings.length === 0 ? 0 : 1)
183
- }
184
-
185
- writeFileSync(PATH, page, 'utf8')
186
- stdout.write(`docs: wrote ${AT} — ${String(sections.length)} node(s), ${String(commands.size)} command(s), ${String(words.length)} word(s).\n`)
@@ -1,73 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync } from '../../integrations/disk.ts'
2
- import { dirname, relative, resolve } from 'node:path'
3
- import { argv, stderr, stdout } from 'node:process'
4
- import { fileURLToPath } from 'node:url'
5
-
6
- import { exit } from '../../core/invoked.ts'
7
- import { ROOT, descend } from '../../core/descend.ts'
8
- import { forbids, runChecker, type Finding } from '../../core/finding.ts'
9
-
10
- function refuse(why: string): never {
11
- stderr.write(`glossary: ${why}\n`)
12
- exit(1)
13
- }
14
-
15
- function text(value: unknown): string | undefined {
16
- return typeof value === 'string' && value !== '' ? value : undefined
17
- }
18
-
19
- function quote(value: string): string {
20
- return `'${value.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/\n/g, '\\n')}'`
21
- }
22
-
23
- const pass = await descend()
24
-
25
- const stopped = [...pass.broken, ...pass.findings].filter(forbids)[0]
26
- if (stopped !== undefined) {
27
- refuse(`the descent is broken, so the harvest is short and writing it would delete words that exist — ${stopped.detail} (${stopped.file ?? ''})`)
28
- }
29
-
30
- const SELF = pass.derived.get('glossary')
31
- if (SELF === undefined) {
32
- refuse('nothing in the tree derives `glossary`, so this script has no declaration saying what it writes or where')
33
- }
34
-
35
- const AT = text(SELF.at) ?? refuse('the `glossary` row names no `at`, so where the glossary lands is unstated')
36
- const PATH = resolve(ROOT, AT)
37
-
38
- const toward = relative(dirname(PATH), fileURLToPath(new URL('../glossary.ts', import.meta.url))).split('\\').join('/')
39
-
40
- const shape = toward.startsWith('.') ? toward : `./${toward}`
41
-
42
- const words = [...pass.coined]
43
-
44
- function row([word, held]: (typeof words)[number]): string {
45
- const from = held.from.map(quote).join(', ')
46
- return ` { id: ${quote(word)}, under: ${quote(held.under)}, from: [${from}], means: ${quote(held.said[0] ?? '')} },`
47
- }
48
-
49
- const content = `import type { Glossary } from '${shape}'
50
-
51
- export const GLOSSARY: Glossary[] = [
52
- ${words.map(row).join('\n')}
53
- ]
54
- `
55
-
56
- if (argv.includes('--check')) {
57
- const findings: Finding[] = []
58
- const current = existsSync(PATH) ? readFileSync(PATH, 'utf8') : ''
59
-
60
- if (current !== content) {
61
- findings.push({
62
- file: AT,
63
- detail: 'is not what the slopnator from the root derives',
64
- instead: `run \`${text(SELF.by) ?? 'thread glossary'}\` and commit what it writes. Never edit this file — a meaning lives on the row that coins the word, and an edit here is a change to that row somebody skipped`,
65
- })
66
- }
67
-
68
- runChecker('glossary', findings, `${String(words.length)} word(s) coined over ${String(pass.declarations)} declaration(s)`)
69
- exit(findings.length === 0 ? 0 : 1)
70
- }
71
-
72
- writeFileSync(PATH, content)
73
- stdout.write(`glossary: wrote ${AT} — ${String(words.length)} word(s).\n`)
@@ -1,6 +0,0 @@
1
- export interface Glossary {
2
- readonly id: string
3
- readonly under: string
4
- readonly from: readonly string[]
5
- readonly means: string
6
- }