@prestack/thread 0.1.21 → 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 (137) hide show
  1. package/CHANGELOG.md +109 -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 +68 -0
  7. package/dist/core/tree.d.ts +1 -0
  8. package/dist/core/tree.js +7 -1
  9. package/dist/derivation/generators/build.d.ts +3 -1
  10. package/dist/derivation/generators/build.js +103 -22
  11. package/dist/derivation/generators/release.js +74 -26
  12. package/dist/derivation/release.js +3 -3
  13. package/dist/integrations/cli.js +69 -10
  14. package/dist/integrations/pglite.js +13 -3
  15. package/dist/integrations/target.d.ts +3 -0
  16. package/dist/integrity/attach.js +1 -5
  17. package/dist/integrity/slopnators/sl_stale_path.js +10 -0
  18. package/dist/operations/access.js +3 -2
  19. package/dist/operations/capabilities.d.ts +2 -0
  20. package/dist/operations/capabilities.js +2 -0
  21. package/dist/operations/generators/capability.js +234 -24
  22. package/dist/operations/generators/compile.js +150 -50
  23. package/dist/operations/generators/seed.d.ts +3 -0
  24. package/dist/operations/generators/seed.js +25 -3
  25. package/dist/operations/nodes.d.ts +2 -2
  26. package/package.json +1 -1
  27. package/dist/core/actor.ts +0 -21
  28. package/dist/core/attach.ts +0 -613
  29. package/dist/core/chain.ts +0 -145
  30. package/dist/core/condition.ts +0 -227
  31. package/dist/core/descend.ts +0 -1185
  32. package/dist/core/errors/catalogue.ts +0 -314
  33. package/dist/core/errors/classes.ts +0 -51
  34. package/dist/core/errors/error.ts +0 -152
  35. package/dist/core/errors/namespaces.ts +0 -19
  36. package/dist/core/finding.ts +0 -37
  37. package/dist/core/generators/commit.ts +0 -157
  38. package/dist/core/init.ts +0 -222
  39. package/dist/core/invoked.ts +0 -52
  40. package/dist/core/round.ts +0 -74
  41. package/dist/core/rows.ts +0 -506
  42. package/dist/core/scope.ts +0 -20
  43. package/dist/core/thread.ts +0 -29
  44. package/dist/core/tree.ts +0 -90
  45. package/dist/core/types.ts +0 -351
  46. package/dist/derivation/attach.ts +0 -57
  47. package/dist/derivation/generators/build.ts +0 -371
  48. package/dist/derivation/generators/check.ts +0 -118
  49. package/dist/derivation/generators/determinism.ts +0 -145
  50. package/dist/derivation/generators/release.ts +0 -236
  51. package/dist/derivation/release.ts +0 -43
  52. package/dist/integrations/attach.ts +0 -187
  53. package/dist/integrations/cli.ts +0 -606
  54. package/dist/integrations/declared.ts +0 -34
  55. package/dist/integrations/disk.ts +0 -466
  56. package/dist/integrations/generators/read.ts +0 -127
  57. package/dist/integrations/generators/vault.ts +0 -210
  58. package/dist/integrations/https.ts +0 -216
  59. package/dist/integrations/pglite.ts +0 -206
  60. package/dist/integrations/secret.ts +0 -54
  61. package/dist/integrations/target.ts +0 -672
  62. package/dist/integrations/vault.ts +0 -148
  63. package/dist/integrity/attach.ts +0 -150
  64. package/dist/integrity/check-threads.ts +0 -166
  65. package/dist/integrity/constraint.ts +0 -1246
  66. package/dist/integrity/generators/compiler.ts +0 -138
  67. package/dist/integrity/generators/gate.ts +0 -227
  68. package/dist/integrity/generators/issues.ts +0 -160
  69. package/dist/integrity/generators/publish.ts +0 -233
  70. package/dist/integrity/generators/trial.ts +0 -359
  71. package/dist/integrity/lint.ts +0 -214
  72. package/dist/integrity/lsp/bin.ts +0 -44
  73. package/dist/integrity/lsp/diagnostics.ts +0 -92
  74. package/dist/integrity/lsp/findings.ts +0 -63
  75. package/dist/integrity/lsp/lint.ts +0 -124
  76. package/dist/integrity/lsp/protocol.ts +0 -78
  77. package/dist/integrity/lsp/server.ts +0 -224
  78. package/dist/integrity/slopnator.ts +0 -324
  79. package/dist/integrity/slopnators/sl_broken_lineage.ts +0 -38
  80. package/dist/integrity/slopnators/sl_declared_elsewhere.ts +0 -60
  81. package/dist/integrity/slopnators/sl_derived_drift.ts +0 -101
  82. package/dist/integrity/slopnators/sl_door_in_a_node.ts +0 -250
  83. package/dist/integrity/slopnators/sl_hardcoded_style.ts +0 -55
  84. package/dist/integrity/slopnators/sl_inert_island.ts +0 -84
  85. package/dist/integrity/slopnators/sl_inert_slopnator.ts +0 -93
  86. package/dist/integrity/slopnators/sl_missing_row.ts +0 -140
  87. package/dist/integrity/slopnators/sl_no_barrel.ts +0 -48
  88. package/dist/integrity/slopnators/sl_no_child_process.ts +0 -100
  89. package/dist/integrity/slopnators/sl_no_comment.ts +0 -43
  90. package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +0 -276
  91. package/dist/integrity/slopnators/sl_no_import_cycle.ts +0 -66
  92. package/dist/integrity/slopnators/sl_no_such_command.ts +0 -81
  93. package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +0 -63
  94. package/dist/integrity/slopnators/sl_outside_an_operation.ts +0 -25
  95. package/dist/integrity/slopnators/sl_screen_holds_only_declared.ts +0 -70
  96. package/dist/integrity/slopnators/sl_secret_literal.ts +0 -68
  97. package/dist/integrity/slopnators/sl_stale_path.ts +0 -178
  98. package/dist/integrity/slopnators/sl_twice_meant.ts +0 -57
  99. package/dist/integrity/slopnators/sl_twice_parented.ts +0 -82
  100. package/dist/integrity/slopnators/sl_undeclared_crossing.ts +0 -481
  101. package/dist/integrity/slopnators/sl_undeclared_destination.ts +0 -113
  102. package/dist/integrity/slopnators/sl_undeclared_element.ts +0 -44
  103. package/dist/integrity/slopnators/sl_undeclared_list.ts +0 -358
  104. package/dist/integrity/slopnators/sl_undeclared_node.ts +0 -75
  105. package/dist/integrity/slopnators/sl_undeclared_operation.ts +0 -257
  106. package/dist/integrity/slopnators/sl_undeclared_variant.ts +0 -152
  107. package/dist/integrity/slopnators/sl_undeclared_webhook.ts +0 -108
  108. package/dist/integrity/slopnators/sl_underived_route.ts +0 -72
  109. package/dist/integrity/slopnators/sl_undescribed.ts +0 -65
  110. package/dist/integrity/slopnators/sl_ungoverned_island.ts +0 -60
  111. package/dist/integrity/slopnators/sl_unlisted_program.ts +0 -46
  112. package/dist/integrity/slopnators/sl_unnamed_island.ts +0 -41
  113. package/dist/integrity/slopnators/sl_unpaired_member.ts +0 -139
  114. package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +0 -71
  115. package/dist/integrity/slopnators/sl_unprefixed_member.ts +0 -110
  116. package/dist/integrity/slopnators/sl_unthreaded.ts +0 -421
  117. package/dist/integrity/slopnators/sl_untranslated_key.ts +0 -140
  118. package/dist/integrity/slopnators/sl_unvaulted_secret.ts +0 -132
  119. package/dist/integrity/slopnators/sl_unversioned.ts +0 -52
  120. package/dist/integrity/sweep.ts +0 -395
  121. package/dist/knowledge/attach.ts +0 -327
  122. package/dist/knowledge/generators/docsgen.ts +0 -186
  123. package/dist/knowledge/generators/glossary.ts +0 -73
  124. package/dist/knowledge/glossary.ts +0 -6
  125. package/dist/operations/access.ts +0 -131
  126. package/dist/operations/attach.ts +0 -408
  127. package/dist/operations/capabilities.ts +0 -88
  128. package/dist/operations/dispatch.ts +0 -294
  129. package/dist/operations/error-results.ts +0 -31
  130. package/dist/operations/generators/capability.ts +0 -1054
  131. package/dist/operations/generators/compile.ts +0 -701
  132. package/dist/operations/generators/permits.ts +0 -229
  133. package/dist/operations/generators/seed.ts +0 -359
  134. package/dist/operations/generators/trial.ts +0 -666
  135. package/dist/operations/nodes.ts +0 -53
  136. package/dist/operations/operations.ts +0 -91
  137. package/dist/operations/result.ts +0 -28
@@ -1,157 +0,0 @@
1
- import { createHash } from 'node:crypto'
2
- import { deflateSync, inflateSync } from 'node:zlib'
3
- import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs'
4
- import { join, relative, sep } from 'node:path'
5
- import { argv, cwd, stdout, stderr } from 'node:process'
6
-
7
- const dir = cwd()
8
- const message = (argv[2] ?? 'thread').slice(0, 400)
9
- const NL = String.fromCharCode(10)
10
- const NUL = String.fromCharCode(0)
11
- const SLASH = String.fromCharCode(47)
12
- const matches = (pat: string, name: string): boolean => {
13
- const parts = pat.split('*')
14
- if (parts.length === 1) return name === pat
15
- const first = parts[0]
16
- if (!name.startsWith(first)) return false
17
- let at = first.length
18
- for (let k = 1; k < parts.length - 1; k += 1) {
19
- const found = name.indexOf(parts[k], at)
20
- if (found === -1) return false
21
- at = found + parts[k].length
22
- }
23
- const last = parts[parts.length - 1]
24
- return name.length - last.length >= at && name.endsWith(last)
25
- }
26
-
27
- interface Ignore {
28
- readonly negate: boolean
29
- readonly dirOnly: boolean
30
- readonly anchored: boolean
31
- readonly pat: string
32
- }
33
-
34
- let text = ''
35
- try {
36
- text = readFileSync(join(dir, '.gitignore'), 'utf8')
37
- } catch {
38
- text = ''
39
- }
40
- const patterns: Ignore[] = []
41
- for (const raw of text.split(NL)) {
42
- let line = raw.trim()
43
- if (line === '' || line.startsWith('#')) continue
44
- const negate = line.startsWith('!')
45
- if (negate) line = line.slice(1)
46
- const dirOnly = line.endsWith(SLASH)
47
- if (dirOnly) line = line.slice(0, -1)
48
- let anchored = line.startsWith(SLASH)
49
- if (anchored) line = line.slice(1)
50
- if (line.includes(SLASH)) anchored = true
51
- if (line !== '') patterns.push({ negate, dirOnly, anchored, pat: line })
52
- }
53
-
54
- const ignored = (rel: string, name: string, isDir: boolean): boolean => {
55
- if (name === '.git') return true
56
- let hit = false
57
- for (const one of patterns) {
58
- if (one.dirOnly && !isDir) continue
59
- if (matches(one.pat, one.anchored ? rel : name)) hit = !one.negate
60
- }
61
- return hit
62
- }
63
- const BRANCH = ['refs', 'heads', 'main'].join(SLASH)
64
-
65
- interface Entry {
66
- readonly mode: string
67
- readonly name: string
68
- readonly sha: string
69
- }
70
-
71
- const store = (kind: string, body: Buffer): string => {
72
- const whole = Buffer.concat([Buffer.from(kind + ' ' + String(body.length) + NUL), body])
73
- const sha = createHash('sha1').update(whole).digest('hex')
74
- const at = join(dir, '.git', 'objects', sha.slice(0, 2), sha.slice(2))
75
- if (!existsSync(at)) {
76
- mkdirSync(join(dir, '.git', 'objects', sha.slice(0, 2)), { recursive: true })
77
- writeFileSync(at, deflateSync(whole))
78
- }
79
- return sha
80
- }
81
-
82
- const tree = (at: string): string => {
83
- const entries: Entry[] = []
84
- for (const name of readdirSync(at)) {
85
- const full = join(at, name)
86
- const stat = statSync(full)
87
- const rel = relative(dir, full).split(sep).join(SLASH)
88
- if (ignored(rel, name, stat.isDirectory())) continue
89
- if (stat.isDirectory()) {
90
- const sub = tree(full)
91
- if (sub !== '') entries.push({ mode: '40000', name, sha: sub })
92
- } else if (stat.isFile()) {
93
- const sha = store('blob', readFileSync(full))
94
- entries.push({ mode: (stat.mode & 0o111) !== 0 ? '100755' : '100644', name, sha })
95
- }
96
- }
97
- if (entries.length === 0) return ''
98
- const key = (one: Entry): string => one.name + (one.mode === '40000' ? SLASH : '')
99
- entries.sort((one, two) => (key(one) < key(two) ? -1 : key(one) > key(two) ? 1 : 0))
100
- const body = Buffer.concat(
101
- entries.map((one) => Buffer.concat([Buffer.from(one.mode + ' ' + one.name + NUL), Buffer.from(one.sha, 'hex')])),
102
- )
103
- return store('tree', body)
104
- }
105
-
106
- const treeOf = (sha: string): string => {
107
- const at = join(dir, '.git', 'objects', sha.slice(0, 2), sha.slice(2))
108
- const raw = inflateSync(readFileSync(at))
109
- const body = raw.slice(raw.indexOf(0) + 1).toString('utf8')
110
- const first = body.split(NL)[0] ?? ''
111
- return first.startsWith('tree ') ? first.slice(5) : ''
112
- }
113
-
114
- const record = (): void => {
115
- const gitDir = join(dir, '.git')
116
- if (!existsSync(join(gitDir, 'HEAD'))) {
117
- mkdirSync(join(gitDir, 'objects'), { recursive: true })
118
- mkdirSync(join(gitDir, 'refs', 'heads'), { recursive: true })
119
- writeFileSync(join(gitDir, 'HEAD'), 'ref: ' + BRANCH + NL)
120
- }
121
- const head = readFileSync(join(gitDir, 'HEAD'), 'utf8').trim()
122
- const ref = head.startsWith('ref: ') ? head.slice(5) : BRANCH
123
- const refAt = join(gitDir, ref)
124
- const parent = existsSync(refAt) ? readFileSync(refAt, 'utf8').trim() : ''
125
-
126
- const root = tree(dir)
127
- if (root === '') {
128
- stdout.write('commit: nothing to commit' + NL)
129
- return
130
- }
131
- if (parent !== '' && treeOf(parent) === root) {
132
- stdout.write('commit: nothing changed' + NL)
133
- return
134
- }
135
-
136
- const when = String(Math.floor(Date.now() / 1000)) + ' +0000'
137
- const who = 'thread <thread@prestack> ' + when
138
- const body = [
139
- 'tree ' + root,
140
- ...(parent === '' ? [] : ['parent ' + parent]),
141
- 'author ' + who,
142
- 'committer ' + who,
143
- '',
144
- message,
145
- '',
146
- ].join(NL)
147
- const sha = store('commit', Buffer.from(body))
148
- writeFileSync(refAt, sha + NL)
149
- stdout.write('commit: ' + sha.slice(0, 8) + ' on ' + (ref.split(SLASH).pop() ?? 'main') + NL)
150
- }
151
-
152
- try {
153
- record()
154
- } catch (thrown) {
155
- stderr.write('commit: ' + (thrown instanceof Error ? thrown.message : String(thrown)) + NL)
156
- process.exit(1)
157
- }
package/dist/core/init.ts DELETED
@@ -1,222 +0,0 @@
1
- import { LOCKFILES, installing, manager } from '../integrations/cli.ts'
2
- import { existsSync, readFileSync, writeFileSync } from '../integrations/disk.ts'
3
- import { createRequire } from 'node:module'
4
- import { join, relative, resolve } from 'node:path'
5
- import { fileURLToPath } from 'node:url'
6
-
7
- import { quoted } from './rows.ts'
8
- import { NAMED } from './scope.ts'
9
-
10
-
11
- export const TREE = '_threads'
12
- export const ROOT = 'thread.ts'
13
-
14
- export const SHAPED = `${NAMED}/core/thread`
15
-
16
- export class AlreadyThreadedError extends Error {
17
- readonly at: string
18
- constructor(at: string) {
19
- super(
20
-
21
- `${at} already exists, so this repository already has a root. A tree has one root and it is written once. ` +
22
- 'Declare something under it with `thread create` — run it bare to see what this tree makes — or take on ' +
23
- 'a package with `thread attach`, which brings its rows with it. Neither is written by hand.',
24
- )
25
- this.name = 'AlreadyThreadedError'
26
- this.at = at
27
- }
28
- }
29
-
30
- export const COMPILER = 'tsconfig.json'
31
-
32
- export const MANIFEST = 'package.json'
33
-
34
- const BUILT = '_gener' + 'ated/packages/core'
35
-
36
- const MODULE = 'module'
37
-
38
- const NPM = 'npm'
39
-
40
- const LATEST = 'latest'
41
-
42
- export const REGISTRY = '.npm' + 'rc'
43
-
44
- export const IGNORED = '.git' + 'ignore'
45
-
46
- export function ignored(): string {
47
- return [
48
- 'node_' + 'modules/',
49
- '.next/',
50
- 'dist/',
51
-
52
- '*.tsbuildinfo',
53
-
54
- 'next-env.d.ts',
55
- '.DS_Store',
56
- '',
57
- ].join('\n')
58
- }
59
-
60
- export function compiler(): string {
61
- return `${JSON.stringify(
62
- {
63
- compilerOptions: {
64
- target: 'ES2022',
65
- module: 'ESNext',
66
- moduleResolution: 'bundler',
67
- strict: true,
68
-
69
- allowImportingTsExtensions: true,
70
-
71
- skipLibCheck: true,
72
-
73
- types: ['node'],
74
- jsx: 'react-jsx',
75
- noEmit: true,
76
- },
77
- },
78
- null,
79
- 2,
80
- )}\n`
81
- }
82
-
83
- function owned(into: string): readonly { readonly id: string; readonly at: string; readonly describes: string; readonly runs?: string }[] {
84
- const held = Object.keys(LOCKFILES).filter((one) => existsSync(join(into, one)))
85
- return [
86
- {
87
- id: 'manifest',
88
- at: 'package.json',
89
- describes:
90
- 'What this app is made of and what may be run against it — the packages it installs and the commands that build it, serve it and refuse it.',
91
- },
92
-
93
- ...(existsSync(join(into, REGISTRY))
94
- ? [
95
- {
96
- id: 'registry',
97
- at: REGISTRY,
98
- describes:
99
- 'Which registry this app’s packages come from, and any credential scoped to it. Declared beside the lockfile because an install is not reproducible without it: the lockfile says which versions answered, and this says who answered.',
100
- },
101
- ]
102
- : []),
103
- {
104
- id: 'ignored',
105
- at: IGNORED,
106
- describes:
107
- 'What is built rather than written, so the checks that read this repository can tell the two apart. Every surface here asks which files are tracked, and without it an app that has been served once answers with its whole build cache.',
108
- },
109
- ...held.map((one) => ({
110
- id: 'lockfile',
111
- at: one,
112
- describes:
113
- 'The exact version of every package this app resolved to, so an install here and an install anywhere else are the same install.',
114
- })),
115
- ]
116
- }
117
-
118
- export function root(into: string): string {
119
- const rows = owned(into).flatMap((one) => [
120
- ' {',
121
- ` id: ${quoted(one.id)},`,
122
- ` at: ${quoted(one.at)},`,
123
- ` describes: ${quoted(one.describes)},`,
124
- ' version: 1,',
125
- ...(one.runs === undefined ? [] : [` runs: ${quoted(one.runs)},`]),
126
- ' },',
127
- ])
128
- return [
129
- `import type { Threaded } from '${SHAPED}'`,
130
- '',
131
- 'export const THREAD: Threaded = {',
132
- " id: 'thread',",
133
- ` at: '${TREE}/${ROOT}',`,
134
- " describes: 'The framework that declares what must exist, forbids what is not declared, and derives what can be derived.',",
135
- ' version: 1,',
136
- ' declares: [',
137
- ...rows,
138
- ' ],',
139
- '}',
140
- '',
141
- ].join('\n')
142
- }
143
-
144
- const own = createRequire(import.meta.url)
145
-
146
- function manifested(at: string): { readonly name?: string; readonly version?: string } | undefined {
147
- try {
148
- return own(at) as { readonly name?: string; readonly version?: string }
149
- } catch {
150
- return undefined
151
- }
152
- }
153
-
154
- function shipped(): readonly [string, string] {
155
- let at = fileURLToPath(new URL('.', import.meta.url))
156
- for (;;) {
157
- const read = manifested(join(at, MANIFEST))
158
- if (read !== undefined) {
159
- if (read.name !== undefined && read.version !== undefined) return [read.name, read.version]
160
- const core = manifested(join(at, BUILT, MANIFEST))
161
- if (core?.name !== undefined && core.version !== undefined) return [core.name, core.version]
162
- }
163
- const up = resolve(at, '..')
164
- if (up === at) {
165
- throw new Error(
166
- 'this framework cannot find the package it is running from, so it has no name to install into your project. ' +
167
- 'That name is read off the manifest beside this code rather than written down anywhere, which is what keeps it ' +
168
- 'right when the package is renamed.',
169
- )
170
- }
171
- at = up
172
- }
173
- }
174
-
175
- export function init(into: string): readonly string[] {
176
- const dir = resolve(into, TREE)
177
- const at = join(dir, ROOT)
178
- if (existsSync(at)) throw new AlreadyThreadedError(relative(into, at))
179
- const written: string[] = []
180
-
181
- const held = join(into, COMPILER)
182
- if (!existsSync(held)) {
183
- writeFileSync(held, compiler(), 'utf8')
184
- written.push(COMPILER)
185
- }
186
-
187
- const manifest = join(into, MANIFEST)
188
- if (!existsSync(manifest)) {
189
- const called = (into.split('/').filter(Boolean).pop() ?? 'app').toLowerCase().replace(/[^a-z0-9-]+/g, '-')
190
- writeFileSync(manifest, JSON.stringify({ name: called, version: '0.0.0', type: MODULE }, null, 2) + '\n', 'utf8')
191
- written.push(MANIFEST)
192
- }
193
- const stated = JSON.parse(readFileSync(manifest, 'utf8')) as { type?: string }
194
- if (stated.type !== MODULE) {
195
- writeFileSync(manifest, `${JSON.stringify({ ...stated, type: MODULE }, null, 2)}\n`, 'utf8')
196
- written.push(MANIFEST)
197
- }
198
-
199
- const [from, version] = shipped()
200
- const holds = JSON.parse(readFileSync(manifest, 'utf8')) as { devDependencies?: Record<string, string> }
201
- const dev = holds.devDependencies ?? {}
202
- const wanted: Readonly<Record<string, string>> = { [from]: '^' + version, ...(manager(into) === NPM ? { [NPM]: LATEST } : {}) }
203
- const missing = Object.entries(wanted).filter(([name]) => dev[name] === undefined)
204
- if (missing.length > 0) {
205
- writeFileSync(manifest, JSON.stringify({ ...holds, devDependencies: { ...dev, ...Object.fromEntries(missing) } }, null, 2) + '\n', 'utf8')
206
- written.push(MANIFEST)
207
- }
208
-
209
- const ignore = join(into, IGNORED)
210
- if (!existsSync(ignore)) {
211
- writeFileSync(ignore, ignored(), 'utf8')
212
- written.push(IGNORED)
213
- }
214
-
215
- installing(into)
216
-
217
- for (const [name, text] of [[ROOT, root(into)]] as const) {
218
- writeFileSync(join(dir, name), text, 'utf8')
219
- written.push(relative(into, join(dir, name)))
220
- }
221
- return written
222
- }
@@ -1,52 +0,0 @@
1
- import { dirname, join } from 'node:path'
2
- import { argv, exit as ending } from 'node:process'
3
- import { fileURLToPath } from 'node:url'
4
-
5
- import { realpathSync } from '../integrations/disk.ts'
6
-
7
- export function invoked(url: string): boolean {
8
- const named = argv[1]
9
- if (named === undefined) return false
10
- try {
11
- const held = new URL(url)
12
- held.search = ''
13
- held.hash = ''
14
- return realpathSync(named) === realpathSync(fileURLToPath(held))
15
- } catch {
16
- return false
17
- }
18
- }
19
-
20
- export const SOURCE = import.meta.url.endsWith('.ts')
21
-
22
- export const BESIDE = (name: string): string => `${name}${SOURCE ? '.ts' : '.js'}`
23
-
24
- export const BUILT = (at: string): string => (SOURCE ? at : at.replace(/\.tsx?$/, '.js'))
25
-
26
- export const LOADER: readonly string[] = SOURCE ? ['--import', 'tsx'] : []
27
-
28
- export const CLI: readonly string[] = [
29
- ...LOADER,
30
- join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'cli', BESIDE('cli')),
31
- ]
32
-
33
- export const REFUSED = Symbol.for('thread.refused')
34
-
35
- let sharing = false
36
-
37
- export const shared = (on: boolean): boolean => {
38
- const was = sharing
39
- sharing = on
40
- return was
41
- }
42
-
43
- export function exit(code?: number): never {
44
- if (!sharing) ending(code)
45
- throw Object.assign(new Error(`refused with ${String(code ?? 0)}`), { [REFUSED]: code ?? 0 })
46
- }
47
-
48
- export const refusal = (thrown: unknown): number | undefined => {
49
- if (typeof thrown !== 'object' || thrown === null) return undefined
50
- const held = (thrown as Record<symbol, unknown>)[REFUSED]
51
- return typeof held === 'number' ? held : undefined
52
- }
@@ -1,74 +0,0 @@
1
- import { resolve } from 'node:path'
2
- import { argv, exitCode, stderr, stdout } from 'node:process'
3
- import { pathToFileURL } from 'node:url'
4
-
5
- import { generators, RAN, REFUSED_BY } from './chain.ts'
6
- import { attached, here } from '../integrations/disk.ts'
7
- import { forget } from './descend.ts'
8
- import { refusal, shared } from './invoked.ts'
9
- import { findTree } from './tree.ts'
10
-
11
- let spun = 0
12
-
13
- const words = (command: string): readonly string[] => command.trim().split(/\s+/).slice(1)
14
-
15
- shared(true)
16
-
17
- const tree = findTree()
18
- const rows = await generators(tree)
19
-
20
- let stale = true
21
-
22
- for (const command of argv.slice(2).filter((one) => one !== '')) {
23
- const said = words(command)
24
- const name = said[0]
25
- if (name === undefined) continue
26
-
27
- const held = rows.find((one) => one.by === `thread ${name}`)
28
- if (held?.at === undefined) {
29
- stdout.write(`round: no command named "${name}", so \`${command}\` was not run\n`)
30
- stdout.write(`${REFUSED_BY} ${command}\n`)
31
- continue
32
- }
33
-
34
- const found = resolve(tree.at, held.at)
35
-
36
- if (stale) forget()
37
-
38
- argv.length = 1
39
- argv.push(found, ...said.slice(1))
40
-
41
- spun += 1
42
-
43
- process.exitCode = 0
44
-
45
- const began = Date.now()
46
- stderr.write(`settle: running ${command}\n`)
47
-
48
- let ok = true
49
- const ran = attached() ? here().run(found, said.slice(1)) : undefined
50
- if (ran !== undefined) {
51
- stdout.write(ran.out)
52
- stderr.write(ran.err)
53
- ok = ran.there && ran.ok
54
- if (!ran.there) stdout.write('round: ' + command + ' could not be started where the tree is: ' + ran.why + '\n')
55
- } else {
56
- try {
57
- await import(`${pathToFileURL(found).href}?round=${String(spun)}`)
58
- ok = exitCode === undefined || exitCode === 0
59
- } catch (thrown) {
60
- const code = refusal(thrown)
61
- if (code === undefined) {
62
- ok = false
63
- stdout.write(`round: \`${command}\` threw: ${thrown instanceof Error ? thrown.message : String(thrown)}\n`)
64
- } else ok = code === 0
65
- }
66
- }
67
-
68
- stdout.write(`${ok ? RAN : REFUSED_BY} ${command}\n`)
69
- stderr.write(`settle: ${command} — ${String(Date.now() - began)} ms, ${ok ? 'ran' : 'refused'}\n`)
70
-
71
- stale = !command.trim().endsWith('--check')
72
- }
73
-
74
- process.exitCode = 0