@lapxo/bound 0.1.0
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/CONTRIBUTING.md +44 -0
- package/LICENSE +22 -0
- package/README.md +97 -0
- package/TARGET.bound +361 -0
- package/dist/cli/accept.d.ts +23 -0
- package/dist/cli/accept.js +423 -0
- package/dist/cli/args.d.ts +10 -0
- package/dist/cli/args.js +34 -0
- package/dist/cli/host.d.ts +1 -0
- package/dist/cli/host.js +32 -0
- package/dist/cli/names.d.ts +25 -0
- package/dist/cli/names.js +12 -0
- package/dist/cli/observe.d.ts +1 -0
- package/dist/cli/observe.js +6 -0
- package/dist/cli/owner.d.ts +35 -0
- package/dist/cli/owner.js +119 -0
- package/dist/cli/pass.d.ts +6 -0
- package/dist/cli/pass.js +309 -0
- package/dist/cli/place.d.ts +74 -0
- package/dist/cli/place.js +290 -0
- package/dist/cli/takes.d.ts +30 -0
- package/dist/cli/takes.js +108 -0
- package/dist/cli/verb.d.ts +2 -0
- package/dist/cli/verb.js +478 -0
- package/dist/fold/ceilings.d.ts +24 -0
- package/dist/fold/ceilings.js +129 -0
- package/dist/fold/claims.d.ts +25 -0
- package/dist/fold/claims.js +107 -0
- package/dist/fold/closed.d.ts +15 -0
- package/dist/fold/closed.js +168 -0
- package/dist/fold/configures.d.ts +4 -0
- package/dist/fold/configures.js +22 -0
- package/dist/fold/digests.d.ts +29 -0
- package/dist/fold/digests.js +211 -0
- package/dist/fold/evidence.d.ts +32 -0
- package/dist/fold/evidence.js +22 -0
- package/dist/fold/fold-worker.d.ts +1 -0
- package/dist/fold/fold-worker.js +13 -0
- package/dist/fold/kept.d.ts +29 -0
- package/dist/fold/kept.js +142 -0
- package/dist/fold/keys.d.ts +17 -0
- package/dist/fold/keys.js +84 -0
- package/dist/fold/laid.d.ts +17 -0
- package/dist/fold/laid.js +90 -0
- package/dist/fold/nos.d.ts +8 -0
- package/dist/fold/nos.js +48 -0
- package/dist/fold/object.d.ts +17 -0
- package/dist/fold/object.js +38 -0
- package/dist/fold/observed.d.ts +33 -0
- package/dist/fold/observed.js +444 -0
- package/dist/fold/opened.d.ts +5 -0
- package/dist/fold/opened.js +33 -0
- package/dist/fold/own.d.ts +24 -0
- package/dist/fold/own.js +215 -0
- package/dist/fold/paid.d.ts +11 -0
- package/dist/fold/paid.js +92 -0
- package/dist/fold/place-inputs.d.ts +17 -0
- package/dist/fold/place-inputs.js +70 -0
- package/dist/fold/places.d.ts +20 -0
- package/dist/fold/places.js +84 -0
- package/dist/fold/rank.d.ts +3 -0
- package/dist/fold/rank.js +9 -0
- package/dist/fold/reach.d.ts +13 -0
- package/dist/fold/reach.js +65 -0
- package/dist/fold/readers.d.ts +44 -0
- package/dist/fold/readers.js +132 -0
- package/dist/fold/receipts.d.ts +8 -0
- package/dist/fold/receipts.js +47 -0
- package/dist/fold/region.d.ts +72 -0
- package/dist/fold/region.js +286 -0
- package/dist/fold/release-policy.d.ts +67 -0
- package/dist/fold/release-policy.js +103 -0
- package/dist/fold/resolved.d.ts +18 -0
- package/dist/fold/resolved.js +123 -0
- package/dist/fold/roles.d.ts +17 -0
- package/dist/fold/roles.js +59 -0
- package/dist/fold/second.d.ts +18 -0
- package/dist/fold/second.js +68 -0
- package/dist/fold/shards.d.ts +29 -0
- package/dist/fold/shards.js +100 -0
- package/dist/fold/signed.d.ts +18 -0
- package/dist/fold/signed.js +75 -0
- package/dist/fold/signers.d.ts +24 -0
- package/dist/fold/signers.js +58 -0
- package/dist/fold/stranger.d.ts +3 -0
- package/dist/fold/stranger.js +24 -0
- package/dist/fold/views.d.ts +27 -0
- package/dist/fold/views.js +66 -0
- package/dist/fold/wire.d.ts +19 -0
- package/dist/fold/wire.js +41 -0
- package/dist/fold/zoom.d.ts +16 -0
- package/dist/fold/zoom.js +80 -0
- package/dist/host/adapters/keys/ed25519.d.ts +7 -0
- package/dist/host/adapters/keys/ed25519.js +30 -0
- package/dist/host/archive.d.ts +11 -0
- package/dist/host/archive.js +152 -0
- package/dist/host/capsule-process.d.ts +20 -0
- package/dist/host/capsule-process.js +54 -0
- package/dist/host/capsule.d.ts +13 -0
- package/dist/host/capsule.js +149 -0
- package/dist/host/cell-receipts.d.ts +2 -0
- package/dist/host/cell-receipts.js +124 -0
- package/dist/host/digest.d.ts +3 -0
- package/dist/host/digest.js +15 -0
- package/dist/host/hash.d.ts +2 -0
- package/dist/host/hash.js +3 -0
- package/dist/host/io.d.ts +9 -0
- package/dist/host/io.js +9 -0
- package/dist/host/located.d.ts +4 -0
- package/dist/host/located.js +105 -0
- package/dist/host/objects.d.ts +5 -0
- package/dist/host/objects.js +18 -0
- package/dist/host/ports/store.d.ts +2 -0
- package/dist/host/ports/store.js +18 -0
- package/dist/host/provide.d.ts +23 -0
- package/dist/host/provide.js +81 -0
- package/dist/host/release.d.ts +12 -0
- package/dist/host/release.js +213 -0
- package/dist/host/selected-capsules.d.ts +8 -0
- package/dist/host/selected-capsules.js +19 -0
- package/dist/host/selected-topos.d.ts +17 -0
- package/dist/host/selected-topos.js +61 -0
- package/dist/host/source-content.d.ts +10 -0
- package/dist/host/source-content.js +94 -0
- package/dist/host/timing.d.ts +2 -0
- package/dist/host/timing.js +7 -0
- package/dist/judge/late.d.ts +7 -0
- package/dist/judge/late.js +33 -0
- package/dist/judge/take.d.ts +57 -0
- package/dist/judge/take.js +75 -0
- package/dist/judge/widening.d.ts +1 -0
- package/dist/judge/widening.js +25 -0
- package/dist/land/act.d.ts +4 -0
- package/dist/land/act.js +209 -0
- package/dist/land/alias.d.ts +10 -0
- package/dist/land/alias.js +41 -0
- package/dist/land/held.d.ts +7 -0
- package/dist/land/held.js +23 -0
- package/dist/land/inert.d.ts +26 -0
- package/dist/land/inert.js +33 -0
- package/dist/land/leaving.d.ts +14 -0
- package/dist/land/leaving.js +51 -0
- package/dist/land/ledger.d.ts +28 -0
- package/dist/land/ledger.js +148 -0
- package/dist/land/owned.d.ts +23 -0
- package/dist/land/owned.js +65 -0
- package/dist/land/sign.d.ts +16 -0
- package/dist/land/sign.js +30 -0
- package/dist/land/vouched.d.ts +21 -0
- package/dist/land/vouched.js +112 -0
- package/dist/land/withdraw.d.ts +14 -0
- package/dist/land/withdraw.js +24 -0
- package/dist/observe/files.d.ts +14 -0
- package/dist/observe/files.js +68 -0
- package/dist/observe/identity.d.ts +19 -0
- package/dist/observe/identity.js +61 -0
- package/dist/observe/match.d.ts +1 -0
- package/dist/observe/match.js +8 -0
- package/dist/observe/regions.d.ts +29 -0
- package/dist/observe/regions.js +200 -0
- package/dist/observe/run.d.ts +30 -0
- package/dist/observe/run.js +34 -0
- package/dist/observe/runner.d.ts +16 -0
- package/dist/observe/runner.js +83 -0
- package/dist/render/capsule.d.ts +24 -0
- package/dist/render/capsule.js +30 -0
- package/dist/render/field.d.ts +9 -0
- package/dist/render/field.js +46 -0
- package/dist/render/names.d.ts +3 -0
- package/dist/render/names.js +4 -0
- package/dist/render/open.d.ts +27 -0
- package/dist/render/open.js +61 -0
- package/dist/render/page.d.ts +3 -0
- package/dist/render/page.js +7 -0
- package/dist/render/receipts.d.ts +3 -0
- package/dist/render/receipts.js +46 -0
- package/dist/render/shape.d.ts +16 -0
- package/dist/render/shape.js +74 -0
- package/dist/render/target.d.ts +18 -0
- package/dist/render/target.js +52 -0
- package/dist/render/view.d.ts +22 -0
- package/dist/render/view.js +191 -0
- package/docs/readme-assets/atlas.svg +169 -0
- package/docs/usage.md +53 -0
- package/package.json +48 -0
- package/receipts.bound +59 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type Batch = {
|
|
2
|
+
readonly kind: 'signed';
|
|
3
|
+
readonly signed: readonly string[];
|
|
4
|
+
readonly epoch: number;
|
|
5
|
+
readonly keyId?: string;
|
|
6
|
+
} | {
|
|
7
|
+
readonly kind: 'once';
|
|
8
|
+
readonly proposed: readonly string[];
|
|
9
|
+
} | {
|
|
10
|
+
readonly kind: 'exit';
|
|
11
|
+
readonly code: number;
|
|
12
|
+
};
|
|
13
|
+
/** A batch signed as accept signs it: at the next epoch, by the key it names, each line read by the wire it would land under. */
|
|
14
|
+
export declare function signedBatch(root: string, args: readonly string[], files: readonly string[]): Promise<Batch>;
|
|
15
|
+
/**
|
|
16
|
+
* accept is one act under the descent of its lines. Every place, then the root where they join, only when those lines
|
|
17
|
+
* rest on every place; a line in one place's own lock is that place. It signs the batch at the epoch the lock
|
|
18
|
+
* stands at, folds it, judges every take of it, and lands only when all of it holds. A batch refused lands nothing.
|
|
19
|
+
* What a batch would move is read before it with `--as rank <batch>`. A cycle's lanes each sign
|
|
20
|
+
* their batch with `bound sign` at the epoch the act lands at, and one land takes them all, each line in its signer's
|
|
21
|
+
* ledger once it verifies against that signer: one signer never forks itself, and one act never forks itself.
|
|
22
|
+
*/
|
|
23
|
+
export declare function accept(root: string, args: readonly string[]): Promise<number>;
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { timing } from "../host/timing.js";
|
|
2
|
+
import { admittedObjects } from "../host/objects.js";
|
|
3
|
+
import { existsSync, rmdirSync, rmSync } from 'node:fs';
|
|
4
|
+
import { dirname, join, basename } from 'node:path';
|
|
5
|
+
import { closeReceipts, instrumentKeep, instrumentKept } from "../fold/closed.js";
|
|
6
|
+
import { bytesDigest, fullDigest, instrumentOf, signaturesOf } from "../fold/digests.js";
|
|
7
|
+
import { canonical, fromLine, LOCK, parse, wireAt } from '@lapxo/topos/wire';
|
|
8
|
+
import { fieldOf, isConfig, foldClaims, sayingOf, selfName } from "../fold/claims.js";
|
|
9
|
+
import { isReaderLock } from "../fold/observed.js";
|
|
10
|
+
import { authorityFor, publicKeyOf, rootSigner, writerFor } from "../fold/signers.js";
|
|
11
|
+
import { lockLines, lockStanding } from "../fold/keys.js";
|
|
12
|
+
import { keepVerdict, keptVerdict, land, landBlob, storeOf } from "../land/ledger.js";
|
|
13
|
+
import { signConsentLine, verifiesOwnerLine } from "../land/sign.js";
|
|
14
|
+
import { appliedIn } from "../fold/signed.js";
|
|
15
|
+
import { wordOf } from "../fold/wire.js";
|
|
16
|
+
import { hasVouchedTree, landCoordinates, locationsOf, vouchedCoordinates } from "../land/vouched.js";
|
|
17
|
+
import { entriesIn, observeFile, observeText } from "../observe/files.js";
|
|
18
|
+
import { coneOf, standingOf } from "./place.js";
|
|
19
|
+
import { ownLock, ownRoot, ownStore } from "../observe/runner.js";
|
|
20
|
+
import { widenedWithoutWitness } from "../judge/widening.js";
|
|
21
|
+
import { retractedTogether, withdrawal } from "../land/withdraw.js";
|
|
22
|
+
import { isCeiling } from "../fold/configures.js";
|
|
23
|
+
import { inertIn, rankedIn } from "../land/inert.js";
|
|
24
|
+
import { landSaid } from "./pass.js";
|
|
25
|
+
import { underTheLock, underTheRegions } from "../land/act.js";
|
|
26
|
+
import { openedBy } from "../fold/opened.js";
|
|
27
|
+
import { touchedBy } from "../fold/reach.js";
|
|
28
|
+
import { landOwned, ownedOf } from "../land/owned.js";
|
|
29
|
+
import { layReleases } from "../host/release.js";
|
|
30
|
+
import { foundableIn, placesIn } from "../fold/places.js";
|
|
31
|
+
import { outsideTheirCapsule } from "../fold/own.js";
|
|
32
|
+
import { lateFacts } from "../judge/late.js";
|
|
33
|
+
import { paidOf } from "../fold/paid.js";
|
|
34
|
+
import { aliasPinned } from "../land/alias.js";
|
|
35
|
+
import { coordinatesWithdrawn } from "../land/leaving.js";
|
|
36
|
+
import { ownerOf, epochOf, forksItself, forksJoinedBy, renderInto, sideOf, signedDemands, signedOwnerLines } from "./owner.js";
|
|
37
|
+
import { claimLinesIn, entryOf, namedPlaces, placesOfFile, positionalsOf, valueOf } from "./args.js";
|
|
38
|
+
import { FLAGS } from "./names.js";
|
|
39
|
+
import { judgeDemand, landTake } from "./takes.js";
|
|
40
|
+
/** A batch signed as accept signs it: at the next epoch, by the key it names, each line read by the wire it would land under. */
|
|
41
|
+
export async function signedBatch(root, args, files) {
|
|
42
|
+
const byFile = files.map((file) => [placesOfFile(file), claimLinesIn(file)]);
|
|
43
|
+
const proposed = byFile.flatMap(([, lines]) => lines);
|
|
44
|
+
if (!proposed.length) {
|
|
45
|
+
process.stderr.write(`${selfName()}: a batch is a file with claim lines\n`);
|
|
46
|
+
return { kind: 'exit', code: 2 };
|
|
47
|
+
}
|
|
48
|
+
const drafted = proposed.filter((line) => !fieldOf(line, 'sig'));
|
|
49
|
+
const bare = drafted.filter((line) => fieldOf(line, 'epoch') || !['', 'target'].includes(fieldOf(line, 'by')));
|
|
50
|
+
if (bare.length) {
|
|
51
|
+
for (const line of bare)
|
|
52
|
+
process.stderr.write(`BARE ${fieldOf(line, 'scope')} · by=${fieldOf(line, 'by') || '∅'}${fieldOf(line, 'epoch') ? ` epoch=${fieldOf(line, 'epoch')}` : ''}\n`);
|
|
53
|
+
process.stderr.write(`${selfName()}: REFUSE·bare nothing landed · ${bare.length} lines name a signer or an epoch they were not signed with: a drafted line proposes by=target and sign signs it, a line a lane signed carries its sig\n`);
|
|
54
|
+
return { kind: 'exit', code: 1 };
|
|
55
|
+
}
|
|
56
|
+
const store = storeOf(root);
|
|
57
|
+
const destinations = [...new Set([...namedPlaces(args), ...byFile.flatMap(([heads]) => heads)])];
|
|
58
|
+
const epoch = epochOf([...lockLines(store), ...destinations.flatMap((place) => appliedIn(root, place))]) + 1;
|
|
59
|
+
const stale = proposed.filter((line) => fieldOf(line, 'sig')).flatMap((line) => ((by, key) => (key === undefined || !verifiesOwnerLine(line, key, signaturesOf(store).admitted)
|
|
60
|
+
? [`${fieldOf(line, 'scope')} · the signature does not hold for ${by || '∅'}`]
|
|
61
|
+
: isConfig(line) && Number(fieldOf(line, 'epoch')) !== epoch ? [`${fieldOf(line, 'scope')} · signed by ${by} at epoch ${fieldOf(line, 'epoch')}, and this act lands at ${epoch}: sign it again`] : []))(fieldOf(line, 'by'), publicKeyOf(root, fieldOf(line, 'by'))));
|
|
62
|
+
if (stale.length) {
|
|
63
|
+
for (const one of stale)
|
|
64
|
+
process.stderr.write(`SIGNED ${one}\n`);
|
|
65
|
+
process.stderr.write(`${selfName()}: REFUSE·signed nothing landed · ${stale.length} lines a lane signed stand at no epoch this act\n`);
|
|
66
|
+
return { kind: 'exit', code: 1 };
|
|
67
|
+
}
|
|
68
|
+
const [named, places] = [namedPlaces(args), placesIn(root)];
|
|
69
|
+
const inLock = new Set(lockLines(store).map(sayingOf));
|
|
70
|
+
const inPlace = new Map(places.map((place) => [place, new Set(appliedIn(root, place).map(sayingOf))]));
|
|
71
|
+
const held = (line, at = named.length ? named : byFile.flatMap(([heads, lines]) => (lines.includes(line) ? heads : []))) => at.length
|
|
72
|
+
? at.every((place) => inPlace.get(place)?.has(sayingOf(line)))
|
|
73
|
+
: inLock.has(sayingOf(line)) || places.some((place) => inPlace.get(place)?.has(sayingOf(line)));
|
|
74
|
+
if (proposed.every((line) => held(line))) {
|
|
75
|
+
if (proposed.some(line => !isConfig(line))) {
|
|
76
|
+
try {
|
|
77
|
+
await admittedObjects(root, [...signedOwnerLines(store), ...proposed]);
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
process.stderr.write(`${selfName()}: ${String(e)} · nothing landed\n`);
|
|
81
|
+
return { kind: 'exit', code: 1 };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return { kind: 'once', proposed };
|
|
85
|
+
}
|
|
86
|
+
const keyFile = valueOf(args, FLAGS.keyFile);
|
|
87
|
+
const keyId = valueOf(args, FLAGS.key) ?? ownerOf(store);
|
|
88
|
+
if (drafted.length && (!keyFile || !existsSync(keyFile))) {
|
|
89
|
+
process.stderr.write(`${selfName()}: a drafted batch is signed with --key-file (PKCS8 PEM)\n`);
|
|
90
|
+
return { kind: 'exit', code: 2 };
|
|
91
|
+
}
|
|
92
|
+
const publicKey = drafted.length ? publicKeyOf(root, keyId) : undefined;
|
|
93
|
+
if (drafted.length && !publicKey) {
|
|
94
|
+
process.stderr.write(`${selfName()}: unknown key ${keyId} — name it in ${selfName()}.keys\n`);
|
|
95
|
+
return { kind: 'exit', code: 2 };
|
|
96
|
+
}
|
|
97
|
+
const privateKeyPem = keyFile ? observeText(keyFile) ?? '' : '';
|
|
98
|
+
const signed = proposed.filter((line) => fieldOf(line, 'sig'));
|
|
99
|
+
for (const line of drafted) {
|
|
100
|
+
const got = signConsentLine(line, privateKeyPem, { epoch, by: keyId, algorithm: signaturesOf(store).era });
|
|
101
|
+
if (got.kind === 'refuse') {
|
|
102
|
+
process.stderr.write(`${selfName()}: ${got.why}\n`);
|
|
103
|
+
return { kind: 'exit', code: 1 };
|
|
104
|
+
}
|
|
105
|
+
if (!verifiesOwnerLine(got.line, publicKey, signaturesOf(store).admitted)) {
|
|
106
|
+
process.stderr.write(`${selfName()}: REFUSE·accept the signature does not hold for ${keyId}\n`);
|
|
107
|
+
return { kind: 'exit', code: 1 };
|
|
108
|
+
}
|
|
109
|
+
signed.push(got.line);
|
|
110
|
+
}
|
|
111
|
+
const wireLines = [...signedOwnerLines(store), ...signed].flatMap((line) => {
|
|
112
|
+
const got = parse(line);
|
|
113
|
+
return got.kind === 'fact' ? [got.value.fields] : [];
|
|
114
|
+
});
|
|
115
|
+
for (const line of signed) {
|
|
116
|
+
const got = fromLine(line, wireAt(wireLines, Number(fieldOf(line, 'epoch'))));
|
|
117
|
+
if (got.kind !== 'fact') {
|
|
118
|
+
process.stderr.write(`${selfName()}: REFUSE·wire ${fieldOf(line, 'scope')} · ${got.why} · nothing landed\n`);
|
|
119
|
+
return { kind: 'exit', code: 1 };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (signed.some(line => !isConfig(line))) {
|
|
123
|
+
try {
|
|
124
|
+
await admittedObjects(root, [...signedOwnerLines(store), ...signed], text => process.stdout.write(text + '\n'));
|
|
125
|
+
}
|
|
126
|
+
catch (e) {
|
|
127
|
+
process.stderr.write(`${selfName()}: ${e instanceof Error ? e.message : String(e)} · nothing landed\n`);
|
|
128
|
+
return { kind: 'exit', code: 1 };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return { kind: 'signed', signed, epoch, ...(drafted.length ? { keyId } : {}) };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* accept is one act under the descent of its lines. Every place, then the root where they join, only when those lines
|
|
135
|
+
* rest on every place; a line in one place's own lock is that place. It signs the batch at the epoch the lock
|
|
136
|
+
* stands at, folds it, judges every take of it, and lands only when all of it holds. A batch refused lands nothing.
|
|
137
|
+
* What a batch would move is read before it with `--as rank <batch>`. A cycle's lanes each sign
|
|
138
|
+
* their batch with `bound sign` at the epoch the act lands at, and one land takes them all, each line in its signer's
|
|
139
|
+
* ledger once it verifies against that signer: one signer never forks itself, and one act never forks itself.
|
|
140
|
+
*/
|
|
141
|
+
export async function accept(root, args) {
|
|
142
|
+
const started = Date.now();
|
|
143
|
+
const named = namedPlaces(args);
|
|
144
|
+
const placed = positionalsOf(args).reduce((all, file) => ((places) => (places.length ? claimLinesIn(file).reduce((got, line) => got.set(sayingOf(line), [...new Set([...(got.get(sayingOf(line)) ?? []), ...places])]), all) : all))(placesOfFile(file)), new Map());
|
|
145
|
+
const rooted = lockStanding(storeOf(root));
|
|
146
|
+
const stray = [...new Set([...named, ...[...placed.values()].flat()])].filter((one) => !placesIn(root).includes(one) && !foundableIn(root, rooted, wordOf(rooted, 'families', 'region'), one));
|
|
147
|
+
if (stray.length) {
|
|
148
|
+
process.stderr.write(`${selfName()}: REFUSE·place nothing landed · ${stray.join(', ')} is no place of the tree, and no line of the root founds it: --place names the own lock a line lands in\n`);
|
|
149
|
+
return 2;
|
|
150
|
+
}
|
|
151
|
+
const batch = await signedBatch(root, args, positionalsOf(args));
|
|
152
|
+
if (batch.kind === 'exit')
|
|
153
|
+
return batch.code;
|
|
154
|
+
if (batch.kind === 'once')
|
|
155
|
+
return underTheLock(storeOf(root), 'land', () => repaid(root, batch.proposed, started));
|
|
156
|
+
const taken = retractedTogether(batch.signed);
|
|
157
|
+
if (taken.length) {
|
|
158
|
+
for (const pair of taken) {
|
|
159
|
+
process.stderr.write(`WITHDRAW ${sayingOf(pair.withdraw)}\n`);
|
|
160
|
+
process.stderr.write(`NEW ${sayingOf(pair.line)}\n`);
|
|
161
|
+
}
|
|
162
|
+
process.stderr.write(`${selfName()}: REFUSE·withdraw nothing landed · a withdraw matches a new line in this batch, so it takes that line too\n`);
|
|
163
|
+
return 1;
|
|
164
|
+
}
|
|
165
|
+
const store = storeOf(root);
|
|
166
|
+
const authority = authorityFor([...lockLines(store), ...batch.signed], rootSigner(root), signaturesOf(store).admitted);
|
|
167
|
+
const owned = ownedOf(root, batch.signed, (line) => authority.of(line).kind === 'admitted', (by) => authority.admitted.find((one) => one.id === by)?.coverage ?? [], named, (line) => placed.get(sayingOf(line)));
|
|
168
|
+
if (owned.nowhere.length) {
|
|
169
|
+
for (const line of owned.nowhere)
|
|
170
|
+
process.stderr.write(`NOWHERE ${fieldOf(line, 'scope')} · ${((got) => (got.kind === 'admitted' ? 'admitted' : got.why))(authority.of(line))}, and ${named.length ? `no place of ${named.join(', ')} takes it` : 'no one own lock it covers takes it: name the places with --place'}\n`);
|
|
171
|
+
process.stderr.write(`${selfName()}: REFUSE·nowhere nothing landed · ${owned.nowhere.length} lines neither the ledger nor an own lock admits: a line is landed signed where it stands, never written in bare\n`);
|
|
172
|
+
return 1;
|
|
173
|
+
}
|
|
174
|
+
if (owned.forked.length) {
|
|
175
|
+
for (const one of owned.forked)
|
|
176
|
+
process.stderr.write(`FORKED ${one.place}/${LOCK} · ${one.key} · the lot would leave two standing claims where the lock had one\n`);
|
|
177
|
+
process.stderr.write(`${selfName()}: REFUSE·forked nothing landed · ${owned.forked.length} claims an own lot would fork: a lot for many places lands the same lines at each, and lines meant for one place go in a lot of their own\n`);
|
|
178
|
+
return 1;
|
|
179
|
+
}
|
|
180
|
+
const places = placesIn(root);
|
|
181
|
+
const pinned = [...new Set([...owned.own.keys(), ...named])];
|
|
182
|
+
const touched = pinned.length === 0 && owned.ledger.length ? touchedBy(root, places, owned.ledger, lockStanding(store)) : [];
|
|
183
|
+
const every = pinned.length === 0 && touched.length === places.length && places.length > 0;
|
|
184
|
+
const regions = (pinned.length ? pinned : every ? places : touched).filter((one) => places.includes(one));
|
|
185
|
+
const where = every ? 'every place · then the root, where the places join' : regions.length ? regions.map((one) => `${one}/`).join(' · ') : 'the root alone, where the places join';
|
|
186
|
+
process.stdout.write(`ACTS ${where} · ${owned.ledger.length} lines to the ledger${[...owned.own].map(([place, lines]) => ` · ${lines.length} to ${place}'s own lock`).join('')} · before the lock\n`);
|
|
187
|
+
const asked = Date.now();
|
|
188
|
+
return underTheRegions(store, every ? [...regions, ''] : regions, 'land', () => acceptNow(root, { ...batch, signed: owned.ledger }, started, owned, asked, regions));
|
|
189
|
+
}
|
|
190
|
+
async function acceptNow(root, batch, started, owned, asked = started, descent = []) {
|
|
191
|
+
const waited = Date.now() - asked;
|
|
192
|
+
if (waited > 60000)
|
|
193
|
+
process.stdout.write(`RED wait ${Math.round(waited / 1000)} s for the lock before the act · a wait over a minute is a red\n`);
|
|
194
|
+
const spent = [`sign ${asked - started}`, `wait ${waited}`];
|
|
195
|
+
const took = timing(spent);
|
|
196
|
+
const { signed, epoch } = batch;
|
|
197
|
+
const store = storeOf(root);
|
|
198
|
+
if (signed.some(line => !isConfig(line))) {
|
|
199
|
+
try {
|
|
200
|
+
await admittedObjects(root, [...signedOwnerLines(store), ...signed]);
|
|
201
|
+
}
|
|
202
|
+
catch (e) {
|
|
203
|
+
process.stderr.write(`${selfName()}: ${e instanceof Error ? e.message : String(e)} · nothing landed\n`);
|
|
204
|
+
return 1;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const reads = !signed.some(isReaderLock) && signed.some(isCeiling);
|
|
208
|
+
const fold = reads ? took('cone', () => coneOf(root, entryOf(root), signed.filter(isCeiling), descent)) : { ...took('lines', () => standingOf(root)), observed: [], own: {}, kept: true };
|
|
209
|
+
const inert = inertIn(signed, { standing: fold.standing, ceiling: isCeiling, signsReader: !reads, observed: fold.observed, own: fold.own, epoch });
|
|
210
|
+
const widened = widenedWithoutWitness(signed, fold.standing, isCeiling, wordOf(fold.standing, 'at-classes', 'witness'));
|
|
211
|
+
if (widened.length) {
|
|
212
|
+
for (const line of widened)
|
|
213
|
+
process.stderr.write(`WIDER ${fieldOf(line, 'scope')} · ${fieldOf(line, 'value')}\n`);
|
|
214
|
+
process.stderr.write(`${selfName()}: REFUSE·widening nothing landed · a ceiling that admits more than it did gives back freedom the lock had spent: sign it under a witness that names what made the old ceiling wrong\n`);
|
|
215
|
+
return 1;
|
|
216
|
+
}
|
|
217
|
+
if (inert.length) {
|
|
218
|
+
for (const line of inert)
|
|
219
|
+
process.stderr.write(`INERT ${fieldOf(line, 'scope')} measure=${fieldOf(line, 'measure')}\n`);
|
|
220
|
+
process.stderr.write(`${selfName()}: REFUSE·inert nothing landed · no reading meets these ceilings: sign the reader that meets them in this batch, or leave them out\n`);
|
|
221
|
+
return 1;
|
|
222
|
+
}
|
|
223
|
+
const outside = outsideTheirCapsule(root, fold.standing, signed);
|
|
224
|
+
for (const line of outside)
|
|
225
|
+
process.stderr.write(`OUTSIDE ${fieldOf(line, 'scope')} · ${fieldOf(line, 'value')}\n`);
|
|
226
|
+
if (outside.length) {
|
|
227
|
+
process.stderr.write(`${selfName()}: REFUSE·outside nothing landed · a reader or a capsule lands in the capsule of its world, never in the wire or the instrument\n`);
|
|
228
|
+
return 1;
|
|
229
|
+
}
|
|
230
|
+
const forks = took('fork', () => forksJoinedBy(store, signed).filter((fork) => forksItself(fork.lines) || fork.lines.filter((line) => signed.includes(line)).length > 1));
|
|
231
|
+
if (forks.length) {
|
|
232
|
+
for (const fork of forks) {
|
|
233
|
+
process.stderr.write(`FORK ${fork.key}\n`);
|
|
234
|
+
for (const line of fork.lines)
|
|
235
|
+
process.stderr.write(` ${signed.includes(line) ? 'new ' : 'held'} by=${fieldOf(line, 'by')} ${sideOf(line, lockLines(store))}\n`);
|
|
236
|
+
}
|
|
237
|
+
process.stderr.write(`${selfName()}: REFUSE·fork nothing landed · one signer never forks itself, and one act never forks itself: withdraw the held side in this batch, or sign the other reading under its own scope\n`);
|
|
238
|
+
return 1;
|
|
239
|
+
}
|
|
240
|
+
if (reads)
|
|
241
|
+
for (const line of rankedIn(signed.filter(isCeiling), fold))
|
|
242
|
+
process.stdout.write(`${line}\n`);
|
|
243
|
+
const authority = took('authority', () => authorityFor([...lockLines(store), ...signed], rootSigner(root), signaturesOf(store).admitted));
|
|
244
|
+
for (const line of signed) {
|
|
245
|
+
const verdict = authority.of(line);
|
|
246
|
+
if (verdict.kind !== 'admitted') {
|
|
247
|
+
process.stderr.write(`${selfName()}: ${verdict.kind === 'refuse' ? verdict.why : `REFUSE·authority grey: ${verdict.why}`}\n`);
|
|
248
|
+
return 1;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const coordinates = coordinatesWithdrawn(root, store, signed, [...signed, ...fold.standing]);
|
|
252
|
+
if (coordinates.refused.length) {
|
|
253
|
+
for (const one of coordinates.refused)
|
|
254
|
+
process.stderr.write(`RUN ${one.path} · still read by ${one.by}\n`);
|
|
255
|
+
process.stderr.write(`${selfName()}: REFUSE·withdraw nothing landed · a file a block still reads cannot leave: withdraw what reads it first, or keep it\n`);
|
|
256
|
+
return 1;
|
|
257
|
+
}
|
|
258
|
+
const withdraws = signed.filter((line) => fieldOf(line, 'value') === 'withdraw');
|
|
259
|
+
const withdrawn = withdraws.length ? withdrawal(withdraws, lockLines(store)) : null;
|
|
260
|
+
const view = `${wordOf(fold.standing, 'families', 'view')}/`;
|
|
261
|
+
const lot = fullDigest(store, signed);
|
|
262
|
+
const tree = hasVouchedTree(store)
|
|
263
|
+
? fullDigest(store, [...vouchedCoordinates(store)].sort(([a], [b]) => a.localeCompare(b)).map(([coordinate, digest]) => `${coordinate} ${digest}`))
|
|
264
|
+
: 'key' in fold && typeof fold.key === 'string' ? fold.key : fullDigest(store, fold.standing);
|
|
265
|
+
const cached = keptTakes(keptVerdict(store, tree, lot));
|
|
266
|
+
const judged = cached ?? took('takes', () => signed.filter((one) => fieldOf(one, 'role') === 'demands' && fieldOf(one, 'value') !== 'withdraw' && !fieldOf(one, 'scope').startsWith(view))
|
|
267
|
+
.map((line) => judgeDemand(root, line)));
|
|
268
|
+
if (!cached)
|
|
269
|
+
keepVerdict(store, tree, lot, judged.map(packTake));
|
|
270
|
+
const refused = judged.filter((one) => one.kind === 'refused' || (one.kind === 'judged' && one.verdict.kind === 'refuse'));
|
|
271
|
+
if (refused.length) {
|
|
272
|
+
for (const one of refused)
|
|
273
|
+
process.stdout.write(`REFUSE take ${one.scope} · ${one.kind === 'judged' ? one.verdict.why : one.kind === 'refused' ? one.why : ''}\n`);
|
|
274
|
+
process.stderr.write(`${selfName()}: REFUSE·takes nothing landed · ${refused.length} takes refused: a batch lands whole or not at all\n`);
|
|
275
|
+
return 1;
|
|
276
|
+
}
|
|
277
|
+
const held = aliasPinned(root, signed);
|
|
278
|
+
if (held.length) {
|
|
279
|
+
for (const one of held)
|
|
280
|
+
process.stderr.write(`ALIAS ${one.scope} · ${one.digest} · ${one.by.join(' ')}\n`);
|
|
281
|
+
process.stderr.write(`${selfName()}: REFUSE·alias nothing landed · an alias is withdrawn only when no pin names its digest\n`);
|
|
282
|
+
return 1;
|
|
283
|
+
}
|
|
284
|
+
const told = took('told', () => standingOf(root, undefined, signed));
|
|
285
|
+
for (const name of openedBy(descent, told.standing, signed))
|
|
286
|
+
process.stderr.write(`OPEN ${name}\n`);
|
|
287
|
+
if (owned.own.size)
|
|
288
|
+
layReleases(store, ownRoot(), ownLock(), ownStore());
|
|
289
|
+
const landed = took('land', () => [...new Set(signed.map((line) => fieldOf(line, 'by')))].map((by) => land(store, by, signed.filter((line) => fieldOf(line, 'by') === by))));
|
|
290
|
+
for (const [place, lines] of owned.own)
|
|
291
|
+
landOwned(root, place, lines);
|
|
292
|
+
landSaid(store, writerFor(told.standing, 'fold'), []);
|
|
293
|
+
for (const line of signed) {
|
|
294
|
+
const value = fieldOf(line, 'value');
|
|
295
|
+
if (!/^[a-z0-9-]+:[0-9a-f]{32,}$/.test(value))
|
|
296
|
+
continue;
|
|
297
|
+
for (const need of locationsOf(fieldOf(line, 'needs')).locations) {
|
|
298
|
+
const at = join(root, need);
|
|
299
|
+
const bytes = observeFile(at);
|
|
300
|
+
if (bytes === undefined)
|
|
301
|
+
continue;
|
|
302
|
+
if (bytesDigest(store, bytes) === value)
|
|
303
|
+
landBlob(store, value, bytes);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (coordinates.taken.length) {
|
|
307
|
+
for (const path of coordinates.taken) {
|
|
308
|
+
if (existsSync(join(root, path)))
|
|
309
|
+
rmSync(join(root, path), { recursive: true });
|
|
310
|
+
for (let dir = dirname(path); dir !== '.' && existsSync(join(root, dir)) && !entriesIn(join(root, dir)).length; dir = dirname(dir))
|
|
311
|
+
rmdirSync(join(root, dir));
|
|
312
|
+
}
|
|
313
|
+
landCoordinates(store, new Map(), coordinates.taken, `withdraw:epoch-${epoch}`);
|
|
314
|
+
for (const path of coordinates.taken)
|
|
315
|
+
process.stdout.write(`GONE ${path} · withdrawn by its line\n`);
|
|
316
|
+
}
|
|
317
|
+
for (const one of judged)
|
|
318
|
+
landTake(root, one, []);
|
|
319
|
+
const standingAsked = [...signed, ...fold.standing].filter((line) => fieldOf(line, 'role') === 'demands' && fieldOf(line, 'value') !== 'withdraw');
|
|
320
|
+
const paidScopes = new Set(paidOf(store, standingAsked, fold.observed, view).paid.map((line) => fieldOf(line, 'scope')));
|
|
321
|
+
const late = lateFacts(store, [...signed, ...fold.standing], paidScopes);
|
|
322
|
+
if (late.length) {
|
|
323
|
+
land(store, 'judge', late);
|
|
324
|
+
for (const line of late)
|
|
325
|
+
if (fieldOf(line, 'measure') !== 'cone')
|
|
326
|
+
process.stdout.write(`LATE ${fieldOf(line, 'scope')} · answered from the landed cone\n`);
|
|
327
|
+
}
|
|
328
|
+
if (signed.some((line) => fieldOf(line, 'scope').startsWith(`${basename(ownRoot())}/`) && !fieldOf(line, 'scope').split('/').slice(1, -1).includes('uses'))) {
|
|
329
|
+
const code = instrumentOf(store, entryOf(root), told.standing, root, ownLock());
|
|
330
|
+
if (instrumentKept(store) !== code) {
|
|
331
|
+
const open = await closeReceipts(root, store);
|
|
332
|
+
instrumentKeep(store, code);
|
|
333
|
+
process.stderr.write(`open by instrument · ${open.length}\n`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const rendered = took('render', () => renderInto(root, store));
|
|
337
|
+
process.stdout.write(`RENDER 0\n`);
|
|
338
|
+
const own = new Set([...owned.own.values()].flat()).size;
|
|
339
|
+
const perLine = Math.round((Date.now() - started) / Math.max(1, signed.length + own));
|
|
340
|
+
const folder = writerFor(fold.standing, 'fold');
|
|
341
|
+
const beat = (ms, at) => canonical({ scope: 'beat/accept', role: 'writes', form: 'interval', measure: 'ms', value: `${ms}..${ms}`, by: folder ?? '', at: `place:${at}` });
|
|
342
|
+
if (folder !== undefined)
|
|
343
|
+
land(store, folder, [beat(perLine, 'line'), beat(1, fold.kept ? 'kept' : 'folded'), beat(Date.now() - started, 'total')]);
|
|
344
|
+
process.stdout.write(`FACT signed ${signed.length + own} · landed ${landed.length ? landed.map((one) => `${one.appended} in ${one.at}`).join(' · ') : '0'}${[...owned.own].map(([place, lines]) => ` · ${lines.length} in ${place}/${LOCK}`).join('')} · epoch ${epoch}\n`
|
|
345
|
+
+ `TARGET ${rendered.standing} claims · ${rendered.forks.length} forks · ${rendered.vacuous.length} vacuous · ${rendered.grey.length} grey · ${rendered.refused.length} refused · ${Date.now() - started} ms\n`
|
|
346
|
+
+ `SPENT ${spent.join(' ms · ')} ms · ${signed.length} lines\n`);
|
|
347
|
+
if (withdrawn) {
|
|
348
|
+
process.stdout.write(`WITHDRAW ${withdrawn.taken.length} taken · ${withdrawn.exact.length} exact on distributive scales · ${withdrawn.open.length} on open scales, not computed\n`);
|
|
349
|
+
for (const line of withdrawn.inexact)
|
|
350
|
+
process.stdout.write(`INEXACT ${fieldOf(line, 'scope')} · its scale is not distributive: what the others hold is not what they held without it\n`);
|
|
351
|
+
}
|
|
352
|
+
return 0;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* A batch landed twice is one: nothing of it lands again. What it left unpaid is judged again, the way it would be now:
|
|
356
|
+
* each of its demands the fold counts unpaid is taken, and the takes land only when all of it holds.
|
|
357
|
+
*/
|
|
358
|
+
function repaid(root, proposed, started) {
|
|
359
|
+
const store = storeOf(root);
|
|
360
|
+
const asked = new Set(proposed.filter((line) => fieldOf(line, 'role') === 'demands').map((line) => fieldOf(line, 'scope')));
|
|
361
|
+
const view = `${wordOf(foldClaims(signedOwnerLines(store)).standing, 'families', 'view')}/`;
|
|
362
|
+
const standingAsked = signedDemands(store).filter((line) => asked.has(fieldOf(line, 'scope')) && !fieldOf(line, 'scope').startsWith(view));
|
|
363
|
+
const owed = paidOf(store, standingAsked, [], view).missing;
|
|
364
|
+
if (!owed.length) {
|
|
365
|
+
process.stdout.write(`ONCE ${proposed.length} lines · every one already landed and every demand of it paid: a batch landed twice is one, nothing landed\n`);
|
|
366
|
+
return 0;
|
|
367
|
+
}
|
|
368
|
+
const judged = owed.map((line) => judgeDemand(root, line));
|
|
369
|
+
process.stdout.write(`ONCE ${proposed.length} lines · every one already landed · ${owed.length} of its demands unpaid, judged again\n`);
|
|
370
|
+
if (judged.every((one) => one.kind === 'owed')) {
|
|
371
|
+
for (const one of judged)
|
|
372
|
+
landTake(root, one, []);
|
|
373
|
+
return 0;
|
|
374
|
+
}
|
|
375
|
+
const refused = judged.filter((one) => one.kind === 'refused' || (one.kind === 'judged' && one.verdict.kind === 'refuse'));
|
|
376
|
+
if (refused.length) {
|
|
377
|
+
for (const one of refused)
|
|
378
|
+
process.stdout.write(`REFUSE take ${one.scope} · ${one.kind === 'judged' ? one.verdict.why : one.kind === 'refused' ? one.why : ''}\n`);
|
|
379
|
+
process.stderr.write(`${selfName()}: REFUSE·takes nothing landed · ${refused.length} takes refused: what a batch left unpaid is paid whole or not at all\n`);
|
|
380
|
+
return 1;
|
|
381
|
+
}
|
|
382
|
+
const standing = standingOf(root);
|
|
383
|
+
for (const one of judged)
|
|
384
|
+
landTake(root, one, []);
|
|
385
|
+
landSaid(store, writerFor(standing.standing, 'fold'), []);
|
|
386
|
+
const unpaidStanding = standing.standing.filter((line) => fieldOf(line, 'role') === 'demands' && fieldOf(line, 'value') !== 'withdraw');
|
|
387
|
+
const paidScopes = new Set(paidOf(store, unpaidStanding, [], `${wordOf(standing.standing, 'families', 'view')}/`).paid.map((line) => fieldOf(line, 'scope')));
|
|
388
|
+
const late = lateFacts(store, standing.standing, paidScopes);
|
|
389
|
+
if (late.length) {
|
|
390
|
+
land(store, 'judge', late);
|
|
391
|
+
for (const line of late)
|
|
392
|
+
if (fieldOf(line, 'measure') !== 'cone')
|
|
393
|
+
process.stdout.write(`LATE ${fieldOf(line, 'scope')} · answered from the landed cone\n`);
|
|
394
|
+
}
|
|
395
|
+
const rendered = renderInto(root, store);
|
|
396
|
+
process.stdout.write(`RENDER 0\n`);
|
|
397
|
+
process.stdout.write(`TARGET ${rendered.standing} claims · ${rendered.forks.length} forks · ${rendered.vacuous.length} vacuous · ${rendered.grey.length} grey · ${rendered.refused.length} refused · ${Date.now() - started} ms\n`);
|
|
398
|
+
return 0;
|
|
399
|
+
}
|
|
400
|
+
function packTake(one) {
|
|
401
|
+
return one.kind === 'judged'
|
|
402
|
+
? { kind: one.kind, scope: one.scope, demand: one.demand, locations: one.locations, before: [...one.before], after: [...one.after], verdict: one.verdict, ignored: [...one.ignored] }
|
|
403
|
+
: one;
|
|
404
|
+
}
|
|
405
|
+
function keptTakes(raw) {
|
|
406
|
+
if (raw === undefined)
|
|
407
|
+
return undefined;
|
|
408
|
+
const out = [];
|
|
409
|
+
for (const one of raw) {
|
|
410
|
+
if (one === null || typeof one !== 'object' || !('kind' in one) || !('scope' in one))
|
|
411
|
+
return undefined;
|
|
412
|
+
const row = one;
|
|
413
|
+
if (row.kind !== 'judged') {
|
|
414
|
+
out.push(row);
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
out.push({
|
|
418
|
+
kind: 'judged', scope: row.scope, demand: row.demand, locations: row.locations,
|
|
419
|
+
before: new Map(row.before), after: new Map(row.after), verdict: row.verdict, ignored: new Map(row.ignored), started: Date.now(),
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
return out;
|
|
423
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { VALUED } from './names.ts';
|
|
2
|
+
export { VALUED };
|
|
3
|
+
/** What the loop runs that is not source: its entry, the packages it imports and the readers it loads, read by where they lie. */
|
|
4
|
+
export declare function entryOf(root: string): string;
|
|
5
|
+
export declare function valueOf(args: readonly string[], flag: string): string | undefined;
|
|
6
|
+
export declare const valuesOf: (args: readonly string[], flag: string) => readonly string[];
|
|
7
|
+
export declare const namedPlaces: (args: readonly string[]) => readonly string[];
|
|
8
|
+
export declare function positionalsOf(args: readonly string[]): string[];
|
|
9
|
+
export declare const placesOfFile: (file: string) => readonly string[];
|
|
10
|
+
export declare function claimLinesIn(file: string): string[];
|
package/dist/cli/args.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { relative, sep } from 'node:path';
|
|
2
|
+
import { observeText } from "../observe/files.js";
|
|
3
|
+
import { sourceOf } from "../observe/runner.js";
|
|
4
|
+
import { PROTOCOL } from '@lapxo/topos/wire';
|
|
5
|
+
import { FLAGS, VALUED } from "./names.js";
|
|
6
|
+
export { VALUED };
|
|
7
|
+
/** What the loop runs that is not source: its entry, the packages it imports and the readers it loads, read by where they lie. */
|
|
8
|
+
export function entryOf(root) {
|
|
9
|
+
return relative(root, sourceOf()).split(sep).join('/');
|
|
10
|
+
}
|
|
11
|
+
export function valueOf(args, flag) {
|
|
12
|
+
const i = args.indexOf(flag);
|
|
13
|
+
return i >= 0 ? args[i + 1] : undefined;
|
|
14
|
+
}
|
|
15
|
+
export const valuesOf = (args, flag) => args.flatMap((arg, i) => (arg === flag && args[i + 1] !== undefined ? [args[i + 1]] : []));
|
|
16
|
+
export const namedPlaces = (args) => valuesOf(args, FLAGS.place).map((one) => one.replace(/\/$/, ''));
|
|
17
|
+
export function positionalsOf(args) {
|
|
18
|
+
const out = [];
|
|
19
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
20
|
+
const arg = args[i] ?? '';
|
|
21
|
+
if (VALUED.includes(arg)) {
|
|
22
|
+
i += 1;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (!arg.startsWith('--'))
|
|
26
|
+
out.push(arg);
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
export const placesOfFile = (file) => (observeText(file) ?? '').split('\n').map((line) => line.trim())
|
|
31
|
+
.filter((line) => line.startsWith('# place ')).map((line) => line.slice('# place '.length).trim().replace(/\/$/, '')).filter(Boolean);
|
|
32
|
+
export function claimLinesIn(file) {
|
|
33
|
+
return (observeText(file) ?? '').split('\n').map((line) => line.trim()).filter((line) => line.startsWith(PROTOCOL));
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli/host.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
10
|
+
import { resolve } from 'node:path';
|
|
11
|
+
import { pathToFileURL } from 'node:url';
|
|
12
|
+
import { respond } from '@lapxo/topos/contract';
|
|
13
|
+
import { provide } from "../host/provide.js";
|
|
14
|
+
/**
|
|
15
|
+
* The host end of the contract, a process of its own: it loads the one module a lock names, or the blob built from it
|
|
16
|
+
* with the module named beside it, hands it the requests on its standard input and prints on its last line what the
|
|
17
|
+
* contract answers. The instrument never loads a reader or a
|
|
18
|
+
* capsule into itself; this process is theirs, and the only one that reads a request off standard input.
|
|
19
|
+
*/
|
|
20
|
+
void (async () => {
|
|
21
|
+
try {
|
|
22
|
+
provide();
|
|
23
|
+
const loaded = (await import(__rewriteRelativeImportExtension(pathToFileURL(resolve(process.argv[2] ?? '')).href)));
|
|
24
|
+
const self = resolve(process.argv[3] ?? process.argv[2] ?? '');
|
|
25
|
+
process.stdout.write(`\n${respond(typeof loaded['load'] === 'function' ? await loaded['load']() : loaded, readFileSync(0, 'utf8'), self)}\n`);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
const message = (error instanceof Error ? error.message : String(error)).replace(/\s+/g, ' ').trim();
|
|
29
|
+
process.stderr.write(`LOAD index · module error · ${message}\n`);
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
}
|
|
32
|
+
})();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** The verbs bound answers by name: fold reads, land writes signed lines, sign is a key's act. A directory with no verb is a fold of that place. */
|
|
2
|
+
export declare const VERB_NAMES: readonly ["fold", "land", "sign"];
|
|
3
|
+
export type VerbName = (typeof VERB_NAMES)[number];
|
|
4
|
+
/** Every flag the CLI reads, spelled once; a valued flag takes the argument after it. */
|
|
5
|
+
export declare const FLAGS: {
|
|
6
|
+
readonly as: "--as";
|
|
7
|
+
readonly check: "--check";
|
|
8
|
+
readonly key: "--key";
|
|
9
|
+
readonly keyFile: "--key-file";
|
|
10
|
+
readonly out: "--out";
|
|
11
|
+
readonly place: "--place";
|
|
12
|
+
};
|
|
13
|
+
export declare const VALUED: readonly string[];
|
|
14
|
+
/** Views the CLI renders from these names, never from a handwritten usage string. */
|
|
15
|
+
export declare const NAMED_VIEWS: {
|
|
16
|
+
readonly help: "help";
|
|
17
|
+
readonly lines: "lines";
|
|
18
|
+
readonly because: "because";
|
|
19
|
+
};
|
|
20
|
+
export declare const EXIT: {
|
|
21
|
+
readonly closed: 0;
|
|
22
|
+
readonly refuse: 1;
|
|
23
|
+
readonly usage: 2;
|
|
24
|
+
};
|
|
25
|
+
export declare const helpLines: () => readonly string[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** The verbs bound answers by name: fold reads, land writes signed lines, sign is a key's act. A directory with no verb is a fold of that place. */
|
|
2
|
+
export const VERB_NAMES = ['fold', 'land', 'sign'];
|
|
3
|
+
/** Every flag the CLI reads, spelled once; a valued flag takes the argument after it. */
|
|
4
|
+
export const FLAGS = { as: '--as', check: '--check', key: '--key', keyFile: '--key-file', out: '--out', place: '--place' };
|
|
5
|
+
export const VALUED = [FLAGS.keyFile, FLAGS.key, FLAGS.out, FLAGS.as, FLAGS.place];
|
|
6
|
+
/** Views the CLI renders from these names, never from a handwritten usage string. */
|
|
7
|
+
export const NAMED_VIEWS = { help: 'help', lines: 'lines', because: 'because' };
|
|
8
|
+
export const EXIT = { closed: 0, refuse: 1, usage: 2 };
|
|
9
|
+
export const helpLines = () => [
|
|
10
|
+
`verbs ${VERB_NAMES.join(' ')}`,
|
|
11
|
+
`flags ${Object.values(FLAGS).join(' ')}`,
|
|
12
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { observedClaims } from "../fold/observed.js";
|
|
3
|
+
import { storeOf } from "../land/ledger.js";
|
|
4
|
+
/** One reader, run to the end behind a fold that did not wait for it: what it lands, the next fold reads. */
|
|
5
|
+
const [root = '.', only] = process.argv.slice(2);
|
|
6
|
+
observedClaims(resolve(root), storeOf(resolve(root)), { wait: true, ...(only === undefined ? {} : { only }) });
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { renderTarget } from '../render/target.ts';
|
|
2
|
+
export declare const ownerOf: (store: string, told?: readonly string[]) => string;
|
|
3
|
+
/** The signed lines standing in the lock: the owner's, and those of every key it admits to authorize, each in its own ledger. */
|
|
4
|
+
export declare function signedOwnerLines(store: string): string[];
|
|
5
|
+
export declare function standingDemands(store: string): string[];
|
|
6
|
+
/**
|
|
7
|
+
* A demand is history when it asks about a place that is gone: one the tree once held and holds no more. It paid, or
|
|
8
|
+
* did not, in its own time; whoever wants it again signs it against the region as it is. A place never held is not
|
|
9
|
+
* gone — it is still to be made, and its demand stays live.
|
|
10
|
+
*/
|
|
11
|
+
export declare function historyOf(root: string, store: string, demands: readonly string[]): {
|
|
12
|
+
readonly live: string[];
|
|
13
|
+
readonly history: string[];
|
|
14
|
+
};
|
|
15
|
+
export declare function signedDemands(store: string, root?: string): string[];
|
|
16
|
+
export declare function forkedScopes(store: string): Set<string>;
|
|
17
|
+
export declare function epochOf(lines: readonly string[]): number;
|
|
18
|
+
export declare function targetFile(root: string): string;
|
|
19
|
+
export declare function renderInto(root: string, store: string): {
|
|
20
|
+
readonly standing: number;
|
|
21
|
+
readonly superseded: readonly string[];
|
|
22
|
+
readonly forks: readonly {
|
|
23
|
+
readonly key: string;
|
|
24
|
+
}[];
|
|
25
|
+
readonly grey: readonly string[];
|
|
26
|
+
readonly refused: readonly string[];
|
|
27
|
+
readonly vacuous: readonly string[];
|
|
28
|
+
};
|
|
29
|
+
export declare function renderedLock(root: string, store: string, told?: readonly string[]): ReturnType<typeof renderTarget>;
|
|
30
|
+
export declare function forksJoinedBy(store: string, signed: readonly string[]): readonly {
|
|
31
|
+
readonly key: string;
|
|
32
|
+
readonly lines: readonly string[];
|
|
33
|
+
}[];
|
|
34
|
+
export declare function forksItself(lines: readonly string[]): boolean;
|
|
35
|
+
export declare function sideOf(line: string, landed: readonly string[]): string;
|