@prestack/thread 0.1.20 → 0.1.22

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 (148) hide show
  1. package/CHANGELOG.md +193 -0
  2. package/dist/core/attach.js +21 -0
  3. package/dist/core/descend.d.ts +2 -0
  4. package/dist/core/descend.js +18 -3
  5. package/dist/core/generators/commit.js +55 -3
  6. package/dist/core/generators/dev.d.ts +1 -0
  7. package/dist/core/generators/dev.js +68 -0
  8. package/dist/core/rows.d.ts +5 -0
  9. package/dist/core/rows.js +45 -0
  10. package/dist/core/tree.d.ts +1 -0
  11. package/dist/core/tree.js +7 -1
  12. package/dist/derivation/generators/build.d.ts +3 -1
  13. package/dist/derivation/generators/build.js +103 -22
  14. package/dist/derivation/generators/release.js +74 -26
  15. package/dist/derivation/release.js +3 -3
  16. package/dist/integrations/cli.d.ts +3 -9
  17. package/dist/integrations/cli.js +96 -36
  18. package/dist/integrations/declared.d.ts +8 -0
  19. package/dist/integrations/declared.js +22 -0
  20. package/dist/integrations/pglite.js +13 -3
  21. package/dist/integrations/target.d.ts +4 -1
  22. package/dist/integrations/target.js +20 -6
  23. package/dist/integrity/attach.js +1 -5
  24. package/dist/integrity/generators/publish.js +2 -1
  25. package/dist/integrity/slopnators/sl_stale_path.js +10 -0
  26. package/dist/integrity/slopnators/sl_unlisted_program.js +2 -2
  27. package/dist/operations/access.js +3 -2
  28. package/dist/operations/capabilities.d.ts +2 -0
  29. package/dist/operations/capabilities.js +2 -0
  30. package/dist/operations/generators/capability.js +234 -24
  31. package/dist/operations/generators/compile.d.ts +21 -0
  32. package/dist/operations/generators/compile.js +151 -51
  33. package/dist/operations/generators/permits.d.ts +2 -1
  34. package/dist/operations/generators/permits.js +52 -47
  35. package/dist/operations/generators/seed.d.ts +3 -0
  36. package/dist/operations/generators/seed.js +25 -3
  37. package/dist/operations/nodes.d.ts +2 -2
  38. package/package.json +1 -1
  39. package/dist/core/actor.ts +0 -21
  40. package/dist/core/attach.ts +0 -613
  41. package/dist/core/chain.ts +0 -145
  42. package/dist/core/condition.ts +0 -227
  43. package/dist/core/descend.ts +0 -1173
  44. package/dist/core/errors/catalogue.ts +0 -314
  45. package/dist/core/errors/classes.ts +0 -51
  46. package/dist/core/errors/error.ts +0 -152
  47. package/dist/core/errors/namespaces.ts +0 -19
  48. package/dist/core/finding.ts +0 -37
  49. package/dist/core/generators/commit.ts +0 -157
  50. package/dist/core/init.ts +0 -222
  51. package/dist/core/invoked.ts +0 -52
  52. package/dist/core/round.ts +0 -74
  53. package/dist/core/rows.ts +0 -459
  54. package/dist/core/scope.ts +0 -20
  55. package/dist/core/thread.ts +0 -29
  56. package/dist/core/tree.ts +0 -90
  57. package/dist/core/types.ts +0 -351
  58. package/dist/derivation/attach.ts +0 -57
  59. package/dist/derivation/generators/build.ts +0 -371
  60. package/dist/derivation/generators/check.ts +0 -118
  61. package/dist/derivation/generators/determinism.ts +0 -145
  62. package/dist/derivation/generators/release.ts +0 -236
  63. package/dist/derivation/release.ts +0 -43
  64. package/dist/integrations/attach.ts +0 -187
  65. package/dist/integrations/cli.ts +0 -615
  66. package/dist/integrations/disk.ts +0 -466
  67. package/dist/integrations/generators/read.ts +0 -127
  68. package/dist/integrations/generators/vault.ts +0 -210
  69. package/dist/integrations/https.ts +0 -216
  70. package/dist/integrations/pglite.ts +0 -206
  71. package/dist/integrations/secret.ts +0 -54
  72. package/dist/integrations/target.ts +0 -656
  73. package/dist/integrations/vault.ts +0 -148
  74. package/dist/integrity/attach.ts +0 -150
  75. package/dist/integrity/check-threads.ts +0 -166
  76. package/dist/integrity/constraint.ts +0 -1246
  77. package/dist/integrity/generators/compiler.ts +0 -138
  78. package/dist/integrity/generators/gate.ts +0 -227
  79. package/dist/integrity/generators/issues.ts +0 -160
  80. package/dist/integrity/generators/publish.ts +0 -232
  81. package/dist/integrity/generators/trial.ts +0 -359
  82. package/dist/integrity/lint.ts +0 -214
  83. package/dist/integrity/lsp/bin.ts +0 -44
  84. package/dist/integrity/lsp/diagnostics.ts +0 -92
  85. package/dist/integrity/lsp/findings.ts +0 -63
  86. package/dist/integrity/lsp/lint.ts +0 -124
  87. package/dist/integrity/lsp/protocol.ts +0 -78
  88. package/dist/integrity/lsp/server.ts +0 -224
  89. package/dist/integrity/slopnator.ts +0 -324
  90. package/dist/integrity/slopnators/sl_broken_lineage.ts +0 -38
  91. package/dist/integrity/slopnators/sl_declared_elsewhere.ts +0 -60
  92. package/dist/integrity/slopnators/sl_derived_drift.ts +0 -101
  93. package/dist/integrity/slopnators/sl_door_in_a_node.ts +0 -250
  94. package/dist/integrity/slopnators/sl_hardcoded_style.ts +0 -55
  95. package/dist/integrity/slopnators/sl_inert_island.ts +0 -84
  96. package/dist/integrity/slopnators/sl_inert_slopnator.ts +0 -93
  97. package/dist/integrity/slopnators/sl_missing_row.ts +0 -140
  98. package/dist/integrity/slopnators/sl_no_barrel.ts +0 -48
  99. package/dist/integrity/slopnators/sl_no_child_process.ts +0 -100
  100. package/dist/integrity/slopnators/sl_no_comment.ts +0 -43
  101. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +0 -276
  102. package/dist/integrity/slopnators/sl_no_import_cycle.ts +0 -66
  103. package/dist/integrity/slopnators/sl_no_such_command.ts +0 -81
  104. package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +0 -63
  105. package/dist/integrity/slopnators/sl_outside_an_operation.ts +0 -25
  106. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +0 -70
  107. package/dist/integrity/slopnators/sl_secret_literal.ts +0 -68
  108. package/dist/integrity/slopnators/sl_stale_path.ts +0 -178
  109. package/dist/integrity/slopnators/sl_twice_meant.ts +0 -57
  110. package/dist/integrity/slopnators/sl_twice_parented.ts +0 -82
  111. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +0 -481
  112. package/dist/integrity/slopnators/sl_undeclared_destination.ts +0 -113
  113. package/dist/integrity/slopnators/sl_undeclared_element.ts +0 -44
  114. package/dist/integrity/slopnators/sl_undeclared_list.ts +0 -358
  115. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -75
  116. package/dist/integrity/slopnators/sl_undeclared_operation.ts +0 -257
  117. package/dist/integrity/slopnators/sl_undeclared_variant.ts +0 -152
  118. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +0 -108
  119. package/dist/integrity/slopnators/sl_underived_route.ts +0 -72
  120. package/dist/integrity/slopnators/sl_undescribed.ts +0 -65
  121. package/dist/integrity/slopnators/sl_ungoverned_island.ts +0 -60
  122. package/dist/integrity/slopnators/sl_unlisted_program.ts +0 -46
  123. package/dist/integrity/slopnators/sl_unnamed_island.ts +0 -41
  124. package/dist/integrity/slopnators/sl_unpaired_member.ts +0 -139
  125. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +0 -71
  126. package/dist/integrity/slopnators/sl_unprefixed_member.ts +0 -110
  127. package/dist/integrity/slopnators/sl_unthreaded.ts +0 -421
  128. package/dist/integrity/slopnators/sl_untranslated_key.ts +0 -140
  129. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +0 -132
  130. package/dist/integrity/slopnators/sl_unversioned.ts +0 -52
  131. package/dist/integrity/sweep.ts +0 -395
  132. package/dist/knowledge/attach.ts +0 -327
  133. package/dist/knowledge/generators/docsgen.ts +0 -186
  134. package/dist/knowledge/generators/glossary.ts +0 -73
  135. package/dist/knowledge/glossary.ts +0 -6
  136. package/dist/operations/access.ts +0 -131
  137. package/dist/operations/attach.ts +0 -408
  138. package/dist/operations/capabilities.ts +0 -88
  139. package/dist/operations/dispatch.ts +0 -294
  140. package/dist/operations/error-results.ts +0 -31
  141. package/dist/operations/generators/capability.ts +0 -1054
  142. package/dist/operations/generators/compile.ts +0 -701
  143. package/dist/operations/generators/permits.ts +0 -224
  144. package/dist/operations/generators/seed.ts +0 -359
  145. package/dist/operations/generators/trial.ts +0 -666
  146. package/dist/operations/nodes.ts +0 -53
  147. package/dist/operations/operations.ts +0 -91
  148. 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
- }