@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,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