@prestack/thread 0.0.1 → 0.0.2
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.
- package/dist/core/actor.ts +20 -0
- package/dist/core/asking.d.ts +0 -1
- package/dist/core/asking.js +0 -1
- package/dist/core/asking.ts +1342 -0
- package/dist/core/attach.js +2 -2
- package/dist/core/attach.ts +585 -0
- package/dist/core/chain.js +8 -1
- package/dist/core/chain.ts +148 -0
- package/dist/core/cli.js +97 -18
- package/dist/core/cli.ts +2004 -0
- package/dist/core/condition.ts +227 -0
- package/dist/core/descend.d.ts +1 -0
- package/dist/core/descend.js +36 -0
- package/dist/core/descend.ts +1001 -0
- package/dist/core/finding.ts +38 -0
- package/dist/core/generators/meta.js +6 -0
- package/dist/core/generators/meta.ts +1006 -0
- package/dist/core/init.ts +170 -0
- package/dist/core/invoked.ts +47 -0
- package/dist/core/round.ts +57 -0
- package/dist/core/rows.ts +369 -0
- package/dist/core/scope.ts +18 -0
- package/dist/core/thread.ts +29 -0
- package/dist/core/tree.ts +67 -0
- package/dist/core/types.ts +350 -0
- package/dist/derivation/attach.js +1 -1
- package/dist/derivation/attach.ts +68 -0
- package/dist/derivation/generators/build.ts +232 -0
- package/dist/derivation/generators/check.ts +118 -0
- package/dist/derivation/generators/derivation.ts +347 -0
- package/dist/derivation/generators/determinism.ts +145 -0
- package/dist/derivation/generators/release.js +19 -9
- package/dist/derivation/generators/release.ts +213 -0
- package/dist/derivation/makers/release.ts +135 -0
- package/dist/derivation/release.ts +23 -0
- package/dist/integrations/attach.js +2 -2
- package/dist/integrations/attach.ts +207 -0
- package/dist/integrations/generators/read.ts +127 -0
- package/dist/integrations/generators/secret.ts +289 -0
- package/dist/integrations/generators/target.js +16 -6
- package/dist/integrations/generators/target.ts +944 -0
- package/dist/integrations/generators/vault.js +46 -14
- package/dist/integrations/generators/vault.ts +212 -0
- package/dist/integrations/{sdk.js → module.js} +4 -4
- package/dist/integrations/module.ts +189 -0
- package/dist/integrations/secret.ts +50 -0
- package/dist/integrations/target.d.ts +3 -1
- package/dist/integrations/target.js +14 -11
- package/dist/integrations/target.ts +340 -0
- package/dist/integrations/vault.d.ts +2 -0
- package/dist/integrations/vault.js +4 -2
- package/dist/integrations/vault.ts +136 -0
- package/dist/integrity/attach.ts +234 -0
- package/dist/integrity/check-threads.js +2 -26
- package/dist/integrity/check-threads.ts +166 -0
- package/dist/integrity/constraint.ts +1202 -0
- package/dist/integrity/generators/compiler.ts +161 -0
- package/dist/integrity/generators/gate.ts +201 -0
- package/dist/integrity/generators/issues.ts +160 -0
- package/dist/integrity/generators/publish.js +14 -5
- package/dist/integrity/generators/publish.ts +247 -0
- package/dist/integrity/generators/rule.ts +271 -0
- package/dist/integrity/generators/seal.ts +117 -0
- package/dist/integrity/generators/trial.ts +320 -0
- package/dist/integrity/lint.ts +227 -0
- package/dist/integrity/lsp/bin.ts +42 -0
- package/dist/integrity/lsp/diagnostics.ts +92 -0
- package/dist/integrity/lsp/findings.ts +63 -0
- package/dist/integrity/lsp/lint.ts +140 -0
- package/dist/integrity/lsp/protocol.ts +78 -0
- package/dist/integrity/lsp/server.ts +224 -0
- package/dist/integrity/sealed.js +2 -2
- package/dist/integrity/sealed.ts +56 -0
- package/dist/integrity/slopnator.ts +350 -0
- package/dist/integrity/slopnators/sl_broken_lineage.ts +36 -0
- package/dist/integrity/slopnators/sl_declared_elsewhere.ts +39 -0
- package/dist/integrity/slopnators/sl_derived_drift.ts +98 -0
- package/dist/integrity/slopnators/sl_hardcoded_style.ts +55 -0
- package/dist/integrity/slopnators/sl_inert_island.ts +91 -0
- package/dist/integrity/slopnators/sl_inert_slopnator.ts +93 -0
- package/dist/integrity/slopnators/sl_missing_row.ts +182 -0
- package/dist/integrity/slopnators/sl_no_barrel.ts +48 -0
- package/dist/integrity/slopnators/sl_no_child_process.ts +74 -0
- package/dist/integrity/slopnators/sl_no_comment.ts +43 -0
- package/dist/integrity/slopnators/sl_no_dispatch_bypass.ts +328 -0
- package/dist/integrity/slopnators/sl_no_import_cycle.ts +50 -0
- package/dist/integrity/slopnators/sl_no_such_command.ts +64 -0
- package/dist/integrity/slopnators/sl_only_takes_a_literal.ts +63 -0
- package/dist/integrity/slopnators/sl_secret_literal.ts +100 -0
- package/dist/integrity/slopnators/sl_stale_path.ts +94 -0
- package/dist/integrity/slopnators/sl_twice_meant.ts +31 -0
- package/dist/integrity/slopnators/sl_twice_parented.ts +37 -0
- package/dist/integrity/slopnators/sl_undeclared_crossing.ts +87 -0
- package/dist/integrity/slopnators/sl_undeclared_destination.ts +65 -0
- package/dist/integrity/slopnators/sl_undeclared_element.ts +44 -0
- package/dist/integrity/slopnators/sl_undeclared_node.ts +69 -0
- package/dist/integrity/slopnators/sl_undeclared_operation.ts +147 -0
- package/dist/integrity/slopnators/sl_undeclared_variant.ts +148 -0
- package/dist/integrity/slopnators/sl_undescribed.ts +65 -0
- package/dist/integrity/slopnators/sl_ungoverned_island.ts +61 -0
- package/dist/integrity/slopnators/sl_unkept_rows.ts +111 -0
- package/dist/integrity/slopnators/sl_unnamed_island.ts +41 -0
- package/dist/integrity/slopnators/sl_unpaired_member.ts +131 -0
- package/dist/integrity/slopnators/sl_unpaired_slopnator.ts +58 -0
- package/dist/integrity/slopnators/sl_unprefixed_member.ts +136 -0
- package/dist/integrity/slopnators/sl_unseamed_reach.ts +79 -0
- package/dist/integrity/slopnators/sl_unthreaded.ts +419 -0
- package/dist/integrity/slopnators/sl_untranslated_key.ts +164 -0
- package/dist/integrity/slopnators/sl_unversioned.ts +36 -0
- package/dist/integrity/sweep.ts +307 -0
- package/dist/knowledge/attach.ts +350 -0
- package/dist/knowledge/generators/docsgen.ts +174 -0
- package/dist/knowledge/generators/glossary.ts +73 -0
- package/dist/knowledge/generators/skills.ts +263 -0
- package/dist/knowledge/glossary.ts +6 -0
- package/dist/operations/access.ts +88 -0
- package/dist/operations/attach.ts +475 -0
- package/dist/operations/capabilities.ts +65 -0
- package/dist/operations/cost.ts +58 -0
- package/dist/operations/dispatch.ts +348 -0
- package/dist/operations/error-results.ts +31 -0
- package/dist/operations/errors/catalog.ts +168 -0
- package/dist/operations/errors/classes.ts +51 -0
- package/dist/operations/errors/errors.ts +314 -0
- package/dist/operations/generators/capability.js +29 -19
- package/dist/operations/generators/capability.ts +704 -0
- package/dist/operations/generators/compile.js +20 -1
- package/dist/operations/generators/compile.ts +643 -0
- package/dist/operations/generators/grant.ts +336 -0
- package/dist/operations/generators/operation.ts +972 -0
- package/dist/operations/generators/permits.ts +223 -0
- package/dist/operations/generators/seed.ts +347 -0
- package/dist/operations/generators/trial.js +4 -1
- package/dist/operations/generators/trial.ts +529 -0
- package/dist/operations/http.ts +164 -0
- package/dist/operations/makers/capability.ts +166 -0
- package/dist/operations/makers/trial.ts +520 -0
- package/dist/operations/memory.ts +470 -0
- package/dist/operations/metering.ts +328 -0
- package/dist/operations/nodes.ts +54 -0
- package/dist/operations/operations.ts +32 -0
- package/dist/operations/queue-policy.ts +10 -0
- package/dist/operations/result.ts +28 -0
- package/dist/operations/seams.d.ts +4 -4
- package/dist/operations/seams.ts +364 -0
- package/dist/operations/store.ts +29 -0
- package/package.json +8 -1
- package/dist/integrations/generators/sdk.d.ts +0 -1
- package/dist/integrations/generators/sdk.js +0 -148
- /package/dist/integrations/{sdk.d.ts → module.d.ts} +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process'
|
|
2
|
+
import { existsSync, readdirSync } from 'node:fs'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { execPath } from 'node:process'
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
6
|
+
|
|
7
|
+
import type { Row } from './descend.ts'
|
|
8
|
+
import { findTree, type Tree } from './tree.ts'
|
|
9
|
+
|
|
10
|
+
const STATING = 'derivation.ts'
|
|
11
|
+
|
|
12
|
+
export async function generators(tree: Tree = findTree()): Promise<readonly Row[]> {
|
|
13
|
+
if (!existsSync(tree.dir)) return []
|
|
14
|
+
|
|
15
|
+
const sheets = readdirSync(tree.dir)
|
|
16
|
+
.filter((one) => one.endsWith('.ts'))
|
|
17
|
+
.sort((one, two) => (one === STATING ? -1 : two === STATING ? 1 : one < two ? -1 : one > two ? 1 : 0))
|
|
18
|
+
|
|
19
|
+
const found: Row[] = []
|
|
20
|
+
for (const name of sheets) {
|
|
21
|
+
const sheet = join(tree.dir, name)
|
|
22
|
+
try {
|
|
23
|
+
const held = (await import(pathToFileURL(sheet).href)) as { GENERATORS?: readonly Row[] }
|
|
24
|
+
found.push(...(held.GENERATORS ?? []))
|
|
25
|
+
} catch (thrown) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`${sheet} is one of the sheets where this tree states the commands it offers, and reading it threw: ` +
|
|
28
|
+
`${thrown instanceof Error ? thrown.message : String(thrown)}. A tree whose generators cannot be read ` +
|
|
29
|
+
'offers exactly what a tree declaring none offers, so everything derived from your declarations would be ' +
|
|
30
|
+
'left stale by a command reporting that it had finished. Fix that file.',
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return found
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const offers = (all: readonly Row[]): ReadonlySet<string> =>
|
|
38
|
+
new Set(all.map((one) => (typeof one.by === 'string' ? one.by : '')).filter((one) => one !== ''))
|
|
39
|
+
|
|
40
|
+
const ROUNDS = 4
|
|
41
|
+
|
|
42
|
+
const word = (held: unknown): string => (typeof held === 'string' ? held.trim() : '')
|
|
43
|
+
|
|
44
|
+
const FROM_SOURCE = import.meta.url.endsWith('.ts')
|
|
45
|
+
|
|
46
|
+
const RUNNER = fileURLToPath(new URL(FROM_SOURCE ? './round.ts' : './round.js', import.meta.url))
|
|
47
|
+
|
|
48
|
+
const LOADER: readonly string[] = FROM_SOURCE ? ['--import', 'tsx'] : []
|
|
49
|
+
|
|
50
|
+
export const RAN = 'round: ran'
|
|
51
|
+
export const REFUSED_BY = 'round: refused'
|
|
52
|
+
|
|
53
|
+
export function batched(
|
|
54
|
+
at: string,
|
|
55
|
+
commands: readonly string[],
|
|
56
|
+
within?: number,
|
|
57
|
+
): readonly { readonly command: string; readonly ok: boolean; readonly said: string }[] {
|
|
58
|
+
if (commands.length === 0) return []
|
|
59
|
+
|
|
60
|
+
const out = spawnSync(execPath, [...LOADER, RUNNER, ...new Set(commands)], {
|
|
61
|
+
cwd: at,
|
|
62
|
+
encoding: 'utf8',
|
|
63
|
+
...(within === undefined ? {} : { timeout: within, killSignal: 'SIGKILL' as const }),
|
|
64
|
+
})
|
|
65
|
+
const lines = `${out.stdout ?? ''}${out.stderr ?? ''}`.split('\n')
|
|
66
|
+
|
|
67
|
+
const found = new Map<string, { readonly command: string; readonly ok: boolean; readonly said: string }>()
|
|
68
|
+
let held: string[] = []
|
|
69
|
+
for (const line of lines) {
|
|
70
|
+
const mark = line.startsWith(RAN) ? RAN : line.startsWith(REFUSED_BY) ? REFUSED_BY : undefined
|
|
71
|
+
if (mark === undefined) {
|
|
72
|
+
held.push(line)
|
|
73
|
+
continue
|
|
74
|
+
}
|
|
75
|
+
const command = line.slice(mark.length).trim()
|
|
76
|
+
found.set(command, { command, ok: mark === RAN, said: held.join('\n').trim() })
|
|
77
|
+
held = []
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const orphaned = held.join('\n').trim()
|
|
81
|
+
const died =
|
|
82
|
+
out.error !== undefined
|
|
83
|
+
? ` The runner itself failed to start or was stopped: ${out.error.message}.`
|
|
84
|
+
: out.signal !== null && out.signal !== undefined
|
|
85
|
+
? ` The runner was killed by ${out.signal}, so everything after the command it was running is unreported rather than refused.`
|
|
86
|
+
: found.size === 0 && out.status !== 0
|
|
87
|
+
? ` The runner exited ${String(out.status)} having reported nothing, so it died before the first command finished.`
|
|
88
|
+
: ''
|
|
89
|
+
let firstUnreached = true
|
|
90
|
+
return commands.map((one) => {
|
|
91
|
+
const has = found.get(one)
|
|
92
|
+
if (has !== undefined) return has
|
|
93
|
+
const why = `settle: the runner never reported on \`${one}\`, so it was not run and is not settled.${died}`
|
|
94
|
+
const said = firstUnreached && orphaned !== '' ? `${orphaned}\n${why}` : why
|
|
95
|
+
firstUnreached = false
|
|
96
|
+
return { command: one, ok: false, said }
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const WITHIN = 300_000
|
|
101
|
+
|
|
102
|
+
function batch(
|
|
103
|
+
at: string,
|
|
104
|
+
commands: readonly string[],
|
|
105
|
+
): { readonly said: readonly string[]; readonly refused: readonly string[] } {
|
|
106
|
+
const all = batched(at, commands, WITHIN)
|
|
107
|
+
return {
|
|
108
|
+
said: all.map((one) => one.said).filter((one) => one !== ''),
|
|
109
|
+
refused: all.filter((one) => !one.ok).map((one) => one.command),
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function settling(
|
|
114
|
+
at: string,
|
|
115
|
+
all: readonly Row[],
|
|
116
|
+
skip: readonly string[] = [],
|
|
117
|
+
): { readonly ran: readonly string[]; readonly unsettled: readonly string[]; readonly rounds: number } {
|
|
118
|
+
const mine = all
|
|
119
|
+
.filter((one) => word(one.by) !== '' && word(one.runs) !== '' && word(one.by) !== word(one.runs) && !skip.includes(word(one.by)))
|
|
120
|
+
.filter((one, order, every) => every.findIndex((each) => word(each.by) === word(one.by)) === order)
|
|
121
|
+
|
|
122
|
+
const ran: string[] = []
|
|
123
|
+
let round = 0
|
|
124
|
+
let before: readonly string[] | undefined
|
|
125
|
+
|
|
126
|
+
while (round < ROUNDS) {
|
|
127
|
+
round += 1
|
|
128
|
+
|
|
129
|
+
const asking = round === 1 ? mine.map((one) => word(one.runs)) : batch(at, mine.map((one) => word(one.runs))).refused
|
|
130
|
+
const unhappy = mine.filter((one) => asking.includes(word(one.runs)))
|
|
131
|
+
if (unhappy.length === 0) return { ran, unsettled: [], rounds: round }
|
|
132
|
+
|
|
133
|
+
const still = unhappy.map((one) => word(one.runs))
|
|
134
|
+
const seen = before
|
|
135
|
+
if (seen !== undefined && still.length === seen.length && still.every((one) => seen.includes(one))) {
|
|
136
|
+
return { ran, unsettled: still, rounds: round }
|
|
137
|
+
}
|
|
138
|
+
before = still
|
|
139
|
+
|
|
140
|
+
const writing = batch(at, unhappy.map((one) => word(one.by)))
|
|
141
|
+
for (const said of writing.said) ran.push(said)
|
|
142
|
+
const refused = unhappy.filter((one) => writing.refused.includes(word(one.by))).map((one) => word(one.runs))
|
|
143
|
+
|
|
144
|
+
if (refused.length === unhappy.length) return { ran, unsettled: refused, rounds: round }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return { ran, unsettled: batch(at, mine.map((one) => word(one.runs))).refused, rounds: round }
|
|
148
|
+
}
|
package/dist/core/cli.js
CHANGED
|
@@ -59,13 +59,48 @@ const commanded = (word, one) => {
|
|
|
59
59
|
const opens = `Declares ${/^[aeiou]/.test(word) ? 'an' : 'a'} ${word}`;
|
|
60
60
|
return meaning === '' ? `${opens}.` : `${opens} — ${meaning.slice(0, 1).toLowerCase()}${meaning.slice(1)}.`;
|
|
61
61
|
};
|
|
62
|
+
const fielded = (word, one) => {
|
|
63
|
+
if (one === undefined || one.fields.length === 0)
|
|
64
|
+
return [];
|
|
65
|
+
const room = Math.max(...one.fields.map((each) => each.name.length));
|
|
66
|
+
const kind = (each) => each.list ? 'a list' : each.map ? 'a table' : each.boolean ? 'yes or no' : each.worded ? 'a word' : 'a value';
|
|
67
|
+
const base = ['id', 'at', 'describes', 'version'];
|
|
68
|
+
const order = (each) => {
|
|
69
|
+
const held = base.indexOf(each.name);
|
|
70
|
+
return held === -1 ? (each.required ? 100 : 200) : held;
|
|
71
|
+
};
|
|
72
|
+
return [
|
|
73
|
+
'',
|
|
74
|
+
`every ${word} row states these:`,
|
|
75
|
+
'',
|
|
76
|
+
...[...one.fields].sort((a, b) => order(a) - order(b) || (a.name < b.name ? -1 : 1)).flatMap((each) => columned(each.name, `${each.required ? '' : 'optional, '}${kind(each)}${each.guide === '' ? '' : `. ${each.guide}`}`, room + 2)),
|
|
77
|
+
];
|
|
78
|
+
};
|
|
79
|
+
const doing = (word, holds, answers, at) => {
|
|
80
|
+
const held = [
|
|
81
|
+
...(holds === undefined
|
|
82
|
+
? []
|
|
83
|
+
: [
|
|
84
|
+
...columned(`${TYPED} create ${word}`, 'What it asks for, and everything already declared.', 34),
|
|
85
|
+
...columned(`${TYPED} create ${word} read <mark>`, 'One of them in full. It writes nothing.', 34),
|
|
86
|
+
]),
|
|
87
|
+
...(answers?.by === undefined
|
|
88
|
+
? []
|
|
89
|
+
: [
|
|
90
|
+
...columned(answers.by, first(answers.describes ?? ''), 34),
|
|
91
|
+
...(answers.runs === undefined ? [] : columned(answers.runs, 'Proves it is still what its command writes.', 34)),
|
|
92
|
+
]),
|
|
93
|
+
...(at === undefined ? [] : columned(`${TYPED} read ${at}`, 'Prints the file itself.', 34)),
|
|
94
|
+
];
|
|
95
|
+
return held.length === 0 ? [] : ['', 'to do something with it:', ...held];
|
|
96
|
+
};
|
|
62
97
|
const OWN = [
|
|
63
98
|
{
|
|
64
99
|
said: 'read <path>',
|
|
65
100
|
describes: 'Print any file with line numbers, or list a directory. `--find <text>` searches every file in this tree. Reach for this first; `inspect <word>` reads rows instead, which is a different question.',
|
|
66
101
|
},
|
|
67
|
-
{ said: 'init'
|
|
68
|
-
{ said: 'attach <package>'
|
|
102
|
+
{ said: 'init' },
|
|
103
|
+
{ said: 'attach <package>' },
|
|
69
104
|
{ said: 'detach <package>', describes: 'Give a package back, withdrawing every row it put here.' },
|
|
70
105
|
{ said: 'create <noun>', describes: 'Declare a thing. Run it with no noun to see what this tree makes.' },
|
|
71
106
|
{ said: 'run <noun>', describes: 'Run a thing that was declared.' },
|
|
@@ -86,6 +121,54 @@ const OWN = [
|
|
|
86
121
|
describes: 'Writes every derived file again from the rows, running each generator until a full pass changes nothing, and touches nothing you wrote. Run it when the package manifests fell out of step with the rows and pnpm refuses to start: it needs no pnpm in front of it, so `npx thread repair` in an app and `node --import tsx thread/core/cli.ts repair` in the framework repository both reach it.',
|
|
87
122
|
},
|
|
88
123
|
];
|
|
124
|
+
let COINED;
|
|
125
|
+
const coining = () => {
|
|
126
|
+
const found = new Map();
|
|
127
|
+
try {
|
|
128
|
+
const pass = descend();
|
|
129
|
+
for (const [, threadings] of pass.threaded) {
|
|
130
|
+
for (const one of threadings) {
|
|
131
|
+
const id = one.row.id;
|
|
132
|
+
const says = one.row.describes;
|
|
133
|
+
if (typeof id === 'string' && typeof says === 'string' && says !== '' && !found.has(id))
|
|
134
|
+
found.set(id, says);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
for (const [id, row] of pass.stated) {
|
|
138
|
+
const says = row.describes;
|
|
139
|
+
if (typeof says === 'string' && says !== '' && !found.has(id))
|
|
140
|
+
found.set(id, says);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return found;
|
|
145
|
+
}
|
|
146
|
+
return found;
|
|
147
|
+
};
|
|
148
|
+
const coined = () => (COINED ??= coining());
|
|
149
|
+
const verb = (one) => one.said.split(' ')[0] ?? one.said;
|
|
150
|
+
const framework = () => OWN.map((one) => ({ said: one.said, describes: coined().get(verb(one)) ?? one.describes ?? '' }));
|
|
151
|
+
const WORKS = [
|
|
152
|
+
'Everything this app is, it DECLARES — in `_threads/`, one row per thing. You never write those rows',
|
|
153
|
+
'by hand: `npx thread create <noun>` asks what it needs and writes one. Everything else is DERIVED',
|
|
154
|
+
'from them — the schema, the migrations, the routes, the docs — by generators that re-run themselves',
|
|
155
|
+
'whenever a row changes, so nothing has to be kept in step. `npx thread gate` refuses the tree if any',
|
|
156
|
+
'of it has drifted, and a build reads that refusal.',
|
|
157
|
+
];
|
|
158
|
+
const heading = (short) => [
|
|
159
|
+
...framework().flatMap((one) => columned(one.said, short ? opening(one.describes) : one.describes)),
|
|
160
|
+
...untold(),
|
|
161
|
+
];
|
|
162
|
+
const untold = () => {
|
|
163
|
+
const held = OWN.map(verb).filter((one) => !coined().has(one));
|
|
164
|
+
if (held.length === 0)
|
|
165
|
+
return [];
|
|
166
|
+
return [
|
|
167
|
+
'',
|
|
168
|
+
...over(`${held.join(', ')} — no row coins these, so the sentence beside each is typed into this command rather ` +
|
|
169
|
+
`than read from the tree. \`${TYPED} create concept\` declares one, and this page reads it from there.`, '', 88),
|
|
170
|
+
];
|
|
171
|
+
};
|
|
89
172
|
const WITHIN = '--in';
|
|
90
173
|
function within(root, path) {
|
|
91
174
|
const held = resolve(root, path);
|
|
@@ -464,9 +547,11 @@ async function listing() {
|
|
|
464
547
|
stdout.write([
|
|
465
548
|
`${TYPED} list`,
|
|
466
549
|
'',
|
|
550
|
+
...WORKS,
|
|
551
|
+
'',
|
|
467
552
|
`every command this tree answers. These ${String(OWN.length)} are this framework's own and are here in every tree:`,
|
|
468
553
|
'',
|
|
469
|
-
...
|
|
554
|
+
...heading(false),
|
|
470
555
|
...(broke === ''
|
|
471
556
|
? []
|
|
472
557
|
: [
|
|
@@ -540,7 +625,7 @@ async function helping(word) {
|
|
|
540
625
|
outright = undefined;
|
|
541
626
|
unread = thrown instanceof Error ? thrown.message : String(thrown);
|
|
542
627
|
}
|
|
543
|
-
const own =
|
|
628
|
+
const own = framework().find((one) => verb(one) === word);
|
|
544
629
|
const holds = told.get(word);
|
|
545
630
|
const named = every.filter((one) => one.row.id === word);
|
|
546
631
|
const answers = rows.find((one) => one.by === `thread ${word}` || one.by === `thread create ${word}` || one.by === `thread run ${word}`);
|
|
@@ -577,17 +662,9 @@ async function helping(word) {
|
|
|
577
662
|
holds.holds === 0
|
|
578
663
|
? ` nothing is declared as one yet. They are listed in ${holds.at}`
|
|
579
664
|
: ` ${String(holds.holds)} ${holds.holds === 1 ? 'is' : 'are'} declared, listed in ${holds.at}`,
|
|
580
|
-
...(holds.shape === undefined ? [] : [` every ${word} states the same things, and this asks for each of them`]),
|
|
581
665
|
]),
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
...(holds === undefined
|
|
585
|
-
? []
|
|
586
|
-
: columned(`${TYPED} create ${word}`, 'What it asks for, and everything already declared.', 34).concat(columned(`${TYPED} create ${word} read <mark>`, 'One of them in full. It writes nothing.', 34))),
|
|
587
|
-
...(answers?.by === undefined
|
|
588
|
-
? []
|
|
589
|
-
: columned(answers.by, 'Runs it.', 34).concat(answers.runs === undefined ? [] : columned(answers.runs, 'Proves it is still what its command writes.', 34))),
|
|
590
|
-
...(named.length === 0 ? [] : columned(`${TYPED} read ${named[0]?.at ?? ''}`, 'Prints the file itself.', 34)),
|
|
666
|
+
...fielded(word, holds),
|
|
667
|
+
...doing(word, holds, answers, named[0]?.at),
|
|
591
668
|
'',
|
|
592
669
|
].join('\n'));
|
|
593
670
|
return 0;
|
|
@@ -678,7 +755,7 @@ async function offered() {
|
|
|
678
755
|
exit(1);
|
|
679
756
|
}
|
|
680
757
|
}
|
|
681
|
-
const MINE = '
|
|
758
|
+
const MINE = 'thread';
|
|
682
759
|
const UNDER = 'generators';
|
|
683
760
|
const MAKING = 'makers';
|
|
684
761
|
function own(name, under = UNDER) {
|
|
@@ -687,7 +764,7 @@ function own(name, under = UNDER) {
|
|
|
687
764
|
for (const entry of readdirSync(at, { withFileTypes: true })) {
|
|
688
765
|
if (!entry.isDirectory() || entry.name === 'node_modules')
|
|
689
766
|
continue;
|
|
690
|
-
const made = join(at, entry.name,
|
|
767
|
+
const made = join(at, entry.name, under, `${name}.ts`);
|
|
691
768
|
try {
|
|
692
769
|
readFileSync(made);
|
|
693
770
|
found = made;
|
|
@@ -1345,7 +1422,7 @@ async function attachable(verb) {
|
|
|
1345
1422
|
return verb === 'attach'
|
|
1346
1423
|
? [
|
|
1347
1424
|
`nothing to attach — no \`${named('*')}\` package is installed here beyond the CLI itself.`,
|
|
1348
|
-
`Install one with \`npm install ${named('<name>')}\` and run this again to see it listed.`,
|
|
1425
|
+
`Install one with \`npm install -D ${named('<name>')}\` — this framework is scaffolding, so it goes in \`devDependencies\` and a host installs none of it — then run this again to see it listed.`,
|
|
1349
1426
|
]
|
|
1350
1427
|
: [
|
|
1351
1428
|
'nothing to detach — this tree has taken on no package yet.',
|
|
@@ -1453,9 +1530,11 @@ async function run(name) {
|
|
|
1453
1530
|
stderr.write([
|
|
1454
1531
|
`${TYPED} <command>`,
|
|
1455
1532
|
'',
|
|
1533
|
+
...WORKS,
|
|
1534
|
+
'',
|
|
1456
1535
|
`a tree is made, attached to, and then declared into. These ${String(OWN.length)} are this framework's own:`,
|
|
1457
1536
|
'',
|
|
1458
|
-
...
|
|
1537
|
+
...heading(true),
|
|
1459
1538
|
...(unread === ''
|
|
1460
1539
|
? []
|
|
1461
1540
|
: [
|