@vibe-agent-toolkit/cli 0.2.0-rc.4 → 0.2.0-rc.6
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/bin.js +35 -2
- package/dist/bin.js.map +1 -1
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +169 -17
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/claude/claude-config.d.ts.map +1 -1
- package/dist/commands/claude/claude-config.js +6 -0
- package/dist/commands/claude/claude-config.js.map +1 -1
- package/dist/commands/claude/org/helpers.d.ts +59 -1
- package/dist/commands/claude/org/helpers.d.ts.map +1 -1
- package/dist/commands/claude/org/helpers.js +58 -7
- package/dist/commands/claude/org/helpers.js.map +1 -1
- package/dist/commands/claude/org/index.d.ts.map +1 -1
- package/dist/commands/claude/org/index.js +24 -16
- package/dist/commands/claude/org/index.js.map +1 -1
- package/dist/commands/claude/org/skills.d.ts +428 -0
- package/dist/commands/claude/org/skills.d.ts.map +1 -1
- package/dist/commands/claude/org/skills.js +1189 -91
- package/dist/commands/claude/org/skills.js.map +1 -1
- package/dist/commands/claude/org/users.d.ts.map +1 -1
- package/dist/commands/claude/org/users.js +3 -1
- package/dist/commands/claude/org/users.js.map +1 -1
- package/dist/commands/claude/org/workspaces.d.ts.map +1 -1
- package/dist/commands/claude/org/workspaces.js +5 -2
- package/dist/commands/claude/org/workspaces.js.map +1 -1
- package/dist/commands/claude/plugin/install.js +0 -1
- package/dist/commands/claude/plugin/install.js.map +1 -1
- package/dist/commands/corpus/runner.d.ts.map +1 -1
- package/dist/commands/corpus/runner.js +1 -19
- package/dist/commands/corpus/runner.js.map +1 -1
- package/dist/commands/inventory.js +1 -1
- package/dist/commands/inventory.js.map +1 -1
- package/dist/commands/resources/check-progress.d.ts +145 -0
- package/dist/commands/resources/check-progress.d.ts.map +1 -0
- package/dist/commands/resources/check-progress.js +205 -0
- package/dist/commands/resources/check-progress.js.map +1 -0
- package/dist/commands/resources/check-supervisor.d.ts +465 -0
- package/dist/commands/resources/check-supervisor.d.ts.map +1 -0
- package/dist/commands/resources/check-supervisor.js +566 -0
- package/dist/commands/resources/check-supervisor.js.map +1 -0
- package/dist/commands/resources/check.d.ts +454 -0
- package/dist/commands/resources/check.d.ts.map +1 -0
- package/dist/commands/resources/check.js +1237 -0
- package/dist/commands/resources/check.js.map +1 -0
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +277 -6
- package/dist/commands/resources/index.js.map +1 -1
- package/dist/commands/resources/query.d.ts +89 -0
- package/dist/commands/resources/query.d.ts.map +1 -0
- package/dist/commands/resources/query.js +146 -0
- package/dist/commands/resources/query.js.map +1 -0
- package/dist/commands/resources/scan.js +1 -1
- package/dist/commands/resources/scan.js.map +1 -1
- package/dist/commands/skill/review-checklist.d.ts.map +1 -1
- package/dist/commands/skill/review-checklist.js +35 -0
- package/dist/commands/skill/review-checklist.js.map +1 -1
- package/dist/commands/skill/test/configure.d.ts +37 -0
- package/dist/commands/skill/test/configure.d.ts.map +1 -1
- package/dist/commands/skill/test/configure.js +57 -12
- package/dist/commands/skill/test/configure.js.map +1 -1
- package/dist/commands/skills/install.js +0 -1
- package/dist/commands/skills/install.js.map +1 -1
- package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
- package/dist/commands/skills/skill-discovery.js +4 -2
- package/dist/commands/skills/skill-discovery.js.map +1 -1
- package/dist/utils/agent-runner.d.ts.map +1 -1
- package/dist/utils/agent-runner.js +7 -3
- package/dist/utils/agent-runner.js.map +1 -1
- package/dist/utils/command-error.d.ts +56 -1
- package/dist/utils/command-error.d.ts.map +1 -1
- package/dist/utils/command-error.js +66 -3
- package/dist/utils/command-error.js.map +1 -1
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +30 -7
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/issue-severity.d.ts +12 -5
- package/dist/utils/issue-severity.d.ts.map +1 -1
- package/dist/utils/issue-severity.js +1 -1
- package/dist/utils/issue-severity.js.map +1 -1
- package/dist/utils/projection-query.d.ts +263 -0
- package/dist/utils/projection-query.d.ts.map +1 -0
- package/dist/utils/projection-query.js +262 -0
- package/dist/utils/projection-query.js.map +1 -0
- package/dist/utils/projection-store.d.ts +104 -2
- package/dist/utils/projection-store.d.ts.map +1 -1
- package/dist/utils/projection-store.js +126 -4
- package/dist/utils/projection-store.js.map +1 -1
- package/dist/utils/vat-bin-path.d.ts +36 -0
- package/dist/utils/vat-bin-path.d.ts.map +1 -0
- package/dist/utils/vat-bin-path.js +49 -0
- package/dist/utils/vat-bin-path.js.map +1 -0
- package/package.json +25 -14
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Populating a tree's resource projection and putting it somewhere ASKABLE —
|
|
3
|
+
* the shared half of every command that runs SQL over it.
|
|
4
|
+
*
|
|
5
|
+
* `vat resources query` runs one statement a person typed; `vat resources check`
|
|
6
|
+
* runs the statements a project wrote down. They differ in what they do with
|
|
7
|
+
* rows and in nothing else: same population, same store selection, same
|
|
8
|
+
* ephemeral fallback, same cache tell. This module is that "and in nothing
|
|
9
|
+
* else", stated once so the two cannot drift into answering about different
|
|
10
|
+
* corpora.
|
|
11
|
+
*
|
|
12
|
+
* ## 🚨 The SQL ALWAYS runs against a per-run in-memory database. Never the store.
|
|
13
|
+
*
|
|
14
|
+
* This is a correctness property, not an optimisation choice, and it was learned
|
|
15
|
+
* the expensive way. The on-disk projection store is **one database per VAT
|
|
16
|
+
* release, shared by every root on the machine** (`defaultStoreDirectory()` is
|
|
17
|
+
* `tmpdir/.vat-cache/<version>/projection-<shapeDigest>`), it retains three tree
|
|
18
|
+
* hashes per root, and its blob tier is never evicted and carries no tree key at
|
|
19
|
+
* all. `ProjectionStore.readExtent` narrows by `(rootId, treeHash)`; **arbitrary
|
|
20
|
+
* SQL does not**, and cannot be made to — a `WHERE` clause the caller wrote is
|
|
21
|
+
* not a key predicate.
|
|
22
|
+
*
|
|
23
|
+
* So running a user's statement against the file-backed store answered from
|
|
24
|
+
* every projection on the machine. Measured on a two-file scratch repository:
|
|
25
|
+
* `SELECT COUNT(*) FROM resource_realizations` returned **3** with no store and
|
|
26
|
+
* **5,779** with one, and `WHERE path LIKE 'packages/%'` returned paths from a
|
|
27
|
+
* different repository entirely. That is a wrong answer and a cross-project
|
|
28
|
+
* disclosure of link text, heading text and frontmatter — the same material
|
|
29
|
+
* `store.ts` cites as the reason it chmods the cache `0o700`.
|
|
30
|
+
*
|
|
31
|
+
* ⇒ The store's job is to make the POPULATION cheap, and that is all. Whatever
|
|
32
|
+
* `populate()` returns — served from the store or derived — is written into a
|
|
33
|
+
* fresh in-memory database that holds this tree and nothing else, and the SQL
|
|
34
|
+
* runs there. The saving is untouched (it was always in the population: on this
|
|
35
|
+
* repository {@link ProjectionProvenance.populationMs} reads 1.16-1.18 s derived
|
|
36
|
+
* against 0.29-0.31 s served), and "one tree, one answer" stops being a claim
|
|
37
|
+
* about how callers behave and becomes a property of the shape.
|
|
38
|
+
*
|
|
39
|
+
* ## The store never reaches a caller
|
|
40
|
+
*
|
|
41
|
+
* Work runs against an `ask` closure rather than a store handle. That is
|
|
42
|
+
* deliberate: `utils/projection-store.ts` is the one module in the toolkit that
|
|
43
|
+
* knows `@vibe-agent-toolkit/projection-sqlite` exists, and handing commands a
|
|
44
|
+
* backend-typed object would spread that knowledge to every future verb. A
|
|
45
|
+
* closure also puts the legible-failure wrapper on the single path that can
|
|
46
|
+
* throw, so no command can forget it.
|
|
47
|
+
*/
|
|
48
|
+
import { performance } from 'node:perf_hooks';
|
|
49
|
+
import { buildResourceProjection, PROJECTION_TABLES, splitProjectionByScope, } from '@vibe-agent-toolkit/resources';
|
|
50
|
+
import { gitTrackerForProjectRoot } from '../commands/audit/distributed-tree.js';
|
|
51
|
+
import { populationWiring } from './population-wiring.js';
|
|
52
|
+
import { openEphemeralQueryStore, withPopulationCache } from './projection-store.js';
|
|
53
|
+
/**
|
|
54
|
+
* The tree hash an in-memory store's one population is filed under.
|
|
55
|
+
*
|
|
56
|
+
* ⚠️ Deliberately NOT a tree hash. Nothing else ever opens this database, no
|
|
57
|
+
* read-back compares the key against another run's, and the store is gone at the
|
|
58
|
+
* end of the call — so the key only has to be internally consistent. A real
|
|
59
|
+
* `git write-tree` here would cost a spawn to produce a value nobody reads, and
|
|
60
|
+
* would invite the reader to believe the ephemeral store is shareable.
|
|
61
|
+
*/
|
|
62
|
+
const EPHEMERAL_TREE_HASH = 'ephemeral';
|
|
63
|
+
/** What SQLite says when a statement names something the schema does not have. */
|
|
64
|
+
const NAME_NOT_FOUND = ['no such table:', 'no such column:'];
|
|
65
|
+
/**
|
|
66
|
+
* Compile every statement a run intends to ask, against the schema and NO rows,
|
|
67
|
+
* before anything is populated.
|
|
68
|
+
*
|
|
69
|
+
* ## 🔑 What this buys, measured
|
|
70
|
+
*
|
|
71
|
+
* SQLite resolves table and column names when a statement is *prepared*, not
|
|
72
|
+
* when it is stepped — so a typo is knowable before a single row exists. It was
|
|
73
|
+
* not knowable in practice, because the only place a statement met the schema
|
|
74
|
+
* was after the projection had been built. On a real adopter tree, `SELECT path,
|
|
75
|
+
* no_such_column …` cost **8.3 s**, every millisecond of it spent building a
|
|
76
|
+
* projection the statement could never have read. The same typo now costs the
|
|
77
|
+
* price of an empty in-memory database — one extra `createSchema` into
|
|
78
|
+
* `:memory:`, which is the whole overhead this adds on the happy path.
|
|
79
|
+
*
|
|
80
|
+
* It also moves the KIND refusals — a second statement, an `ATTACH`, a `PRAGMA`
|
|
81
|
+
* — in front of the population, so a statement rejected for what it is costs no
|
|
82
|
+
* more than one rejected for what it names.
|
|
83
|
+
*
|
|
84
|
+
* ⚠️ **This is a pre-flight, not a second gate.** `ask` still compiles and runs
|
|
85
|
+
* the real statement against the real projection, and nothing here is trusted in
|
|
86
|
+
* place of that. A statement that compiles here can still fail there — SQLite
|
|
87
|
+
* resolves names against a schema, and this is the same schema, but a run-time
|
|
88
|
+
* error (a bad cast, an overflow) belongs to stepping and is unreachable from a
|
|
89
|
+
* prepare.
|
|
90
|
+
*
|
|
91
|
+
* ⚠️ It deliberately does not STEP anything. Stepping is where a check's
|
|
92
|
+
* unbounded cost lives, and a preflight that ran `WITH RECURSIVE …` would hang
|
|
93
|
+
* before the run it exists to make cheap had begun.
|
|
94
|
+
*
|
|
95
|
+
* @param statements - Every statement the run will ask, in any order
|
|
96
|
+
* @throws The same legible failure `ask` throws, for the first statement that
|
|
97
|
+
* does not compile
|
|
98
|
+
*/
|
|
99
|
+
export async function assertQueriesCompile(statements) {
|
|
100
|
+
if (statements.length === 0)
|
|
101
|
+
return;
|
|
102
|
+
const probe = await openEphemeralQueryStore();
|
|
103
|
+
try {
|
|
104
|
+
for (const sql of statements) {
|
|
105
|
+
try {
|
|
106
|
+
probe.assertCompiles(sql);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
throw new Error(describeQueryFailure(sql, error instanceof Error ? error.message : String(error)));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
await probe.close();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Populate the tree, load it into something askable, and hand the caller a way
|
|
119
|
+
* to ask.
|
|
120
|
+
*
|
|
121
|
+
* @param options - The run
|
|
122
|
+
* @param options.root - Absolute corpus root
|
|
123
|
+
* @param options.logger - Where blob-stage refusals are reported (stderr, so a
|
|
124
|
+
* parseable document on stdout stays parseable)
|
|
125
|
+
* @param options.preflight - Every statement this run intends to ask, compiled
|
|
126
|
+
* against the empty schema BEFORE the population starts. See
|
|
127
|
+
* {@link assertQueriesCompile}
|
|
128
|
+
* @param work - Given the asker, where its rows came from, and how much of the
|
|
129
|
+
* tree they cover. The store is open for exactly this call and closed however
|
|
130
|
+
* it ends
|
|
131
|
+
* @returns Whatever `work` returned
|
|
132
|
+
*/
|
|
133
|
+
export async function withQueriedProjection(options, work) {
|
|
134
|
+
const { root, logger } = options;
|
|
135
|
+
// 🔑 BEFORE the clock and before the population, because being before the
|
|
136
|
+
// population is the entire point — see {@link assertQueriesCompile}. It is an
|
|
137
|
+
// option rather than a step each verb remembers for the same reason everything
|
|
138
|
+
// else here is shared: a verb that forgot it would silently go back to paying
|
|
139
|
+
// a full population to learn about a typo, and nothing in its output would say
|
|
140
|
+
// so.
|
|
141
|
+
await assertQueriesCompile(options.preflight ?? []);
|
|
142
|
+
// 🚨 OUTSIDE `withPopulationCache`, and it must stay outside. That helper
|
|
143
|
+
// awaits `openPopulationCache` — a `git write-tree` spawn plus the backend's
|
|
144
|
+
// dynamic import and `openSqliteProjectionStore()` — BEFORE it invokes the
|
|
145
|
+
// callback below, and it pays that cost ONLY when a store is selected. A clock
|
|
146
|
+
// started inside the callback therefore drops the store's own setup out of the
|
|
147
|
+
// measurement on precisely the arm the number is used to praise. See
|
|
148
|
+
// `populationMs` for what that shipped as.
|
|
149
|
+
//
|
|
150
|
+
// What is NOT in the span, deliberately: `withPopulationCache`'s `finally`,
|
|
151
|
+
// which closes the opened cache AFTER `work` returns. A span that ends before
|
|
152
|
+
// `work` begins cannot contain it, and stretching the span past `work` would
|
|
153
|
+
// fold the caller's statements into a number whose entire purpose is to be
|
|
154
|
+
// read against them. The close is a handle release on an already-open
|
|
155
|
+
// database, not population.
|
|
156
|
+
let contributorRecords = 0;
|
|
157
|
+
const populationStart = performance.now();
|
|
158
|
+
// The file-backed store, when one is selected, and ONLY as a population cache.
|
|
159
|
+
// Its rows are never queried — see the header.
|
|
160
|
+
return withPopulationCache({ root }, async (cache) => {
|
|
161
|
+
// The cache tell. `populate()` short-circuits a hit before any contributor
|
|
162
|
+
// is constructed, so this staying at zero is the ONLY observable difference
|
|
163
|
+
// between a served population and a re-derived one. Declared with the clock
|
|
164
|
+
// above rather than here so the two cannot drift apart when one moves.
|
|
165
|
+
const gitTracker = await gitTrackerForProjectRoot(root);
|
|
166
|
+
const projection = await buildResourceProjection({
|
|
167
|
+
root,
|
|
168
|
+
...populationWiring(logger, gitTracker, cache, root),
|
|
169
|
+
onContributorTiming: () => {
|
|
170
|
+
contributorRecords += 1;
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
// ONE tree, in a database nothing else can reach, built fresh for this call.
|
|
174
|
+
const store = await openEphemeralQueryStore();
|
|
175
|
+
try {
|
|
176
|
+
// The key is read OFF the projection rather than re-derived from the root.
|
|
177
|
+
// The driver mints `roots.id` with `rootIdFor` and every
|
|
178
|
+
// `resolution_contexts.rootId` is a foreign key into it, so taking it from
|
|
179
|
+
// the rows means the key provably describes them — a second derivation
|
|
180
|
+
// could drift from the first and file rows under an id they do not carry.
|
|
181
|
+
const rootId = projection.roots[0]?.id;
|
|
182
|
+
if (rootId === undefined) {
|
|
183
|
+
throw new Error('The population produced no root row, so there is no id to file its extent under.'
|
|
184
|
+
+ ' This is a driver invariant rather than a user error — `populate()` adds exactly'
|
|
185
|
+
+ ' one, and a projection without it cannot be stored or queried.');
|
|
186
|
+
}
|
|
187
|
+
const { blobs, extent } = splitProjectionByScope(projection);
|
|
188
|
+
await store.writeBlobFacts(blobs);
|
|
189
|
+
await store.writeExtent({ rootId, treeHash: EPHEMERAL_TREE_HASH }, extent);
|
|
190
|
+
// The shared setup is done. Everything after this line is the caller's.
|
|
191
|
+
const populationMs = performance.now() - populationStart;
|
|
192
|
+
const ask = (sql, ...parameters) => {
|
|
193
|
+
try {
|
|
194
|
+
return store.query(sql, ...parameters);
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
throw new Error(describeQueryFailure(sql, error instanceof Error ? error.message : String(error)));
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
return await work(ask, { population: contributorRecords === 0 ? 'store' : 'derived', populationMs },
|
|
201
|
+
// Read off the PROJECTION rather than counted back out of the store with
|
|
202
|
+
// a `SELECT COUNT(*)`: a count that travelled through the same `ask` the
|
|
203
|
+
// caller's statements do would be broken by the very schema drift it
|
|
204
|
+
// exists to survive, and it is the population's size either way.
|
|
205
|
+
{ membersEnumerated: projection.resourceRealizations.length });
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
// Closed however the work ends. An in-memory database is reclaimed with the
|
|
209
|
+
// process either way, but a command that runs several of these in one
|
|
210
|
+
// process would otherwise hold every one of them open.
|
|
211
|
+
await store.close();
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Turn a rejected statement into a message that names the surface it missed.
|
|
217
|
+
*
|
|
218
|
+
* ## Why this wrapper exists
|
|
219
|
+
*
|
|
220
|
+
* VAT ships no schema version, by standing rule — the *cache* is safe across a
|
|
221
|
+
* shape change because its digest self-invalidates, but submitted SQL is not: it
|
|
222
|
+
* simply breaks. Pre-1.0 that is acceptable. A raw SQLite error reaching the
|
|
223
|
+
* user is not, because `no such column: contentHash` says nothing about what the
|
|
224
|
+
* column is called now. It matters more for a CHECK than for a query: a query's
|
|
225
|
+
* author is at the keyboard, while a check's author wrote it months ago and the
|
|
226
|
+
* person reading the failure is someone else.
|
|
227
|
+
*
|
|
228
|
+
* ⚠️ **A legibility wrapper, not a validator.** It does not parse SQL and does
|
|
229
|
+
* not check a statement before running it — it reacts to a failure by listing
|
|
230
|
+
* what the query COULD have named. When the statement mentions a known table,
|
|
231
|
+
* that table's columns are listed, which is the case that actually answers "what
|
|
232
|
+
* moved"; otherwise the table names are, which at least answers "what is there".
|
|
233
|
+
*
|
|
234
|
+
* 🪤 **Only a name that was not found gets the listing.** The engine also refuses
|
|
235
|
+
* a write and this backend refuses a second statement, and neither is answered by
|
|
236
|
+
* a column list — appending one says the problem is the schema when the problem
|
|
237
|
+
* is what the caller asked for. A wrapper that decorates every failure identically
|
|
238
|
+
* teaches the reader to skip the decoration, which costs the case it was written for.
|
|
239
|
+
*
|
|
240
|
+
* Matching is a plain lowercase substring test rather than a regex: the input is
|
|
241
|
+
* user text, and a pattern built from it is both a lint failure here and a
|
|
242
|
+
* needless hazard.
|
|
243
|
+
*
|
|
244
|
+
* @param sql - The statement that was submitted
|
|
245
|
+
* @param message - What the engine said
|
|
246
|
+
* @returns The message to surface, with the queryable surface appended when the
|
|
247
|
+
* failure was a name this projection does not have
|
|
248
|
+
*/
|
|
249
|
+
export function describeQueryFailure(sql, message) {
|
|
250
|
+
if (!NAME_NOT_FOUND.some((prefix) => message.includes(prefix)))
|
|
251
|
+
return message;
|
|
252
|
+
const lowered = sql.toLowerCase();
|
|
253
|
+
const named = Object.values(PROJECTION_TABLES).filter((spec) => lowered.includes(spec.name.toLowerCase()));
|
|
254
|
+
const surface = named.length > 0
|
|
255
|
+
? named.map((spec) => ` ${spec.name}(${spec.columns.join(', ')})`).join('\n')
|
|
256
|
+
: Object.values(PROJECTION_TABLES).map((spec) => ` ${spec.name}`).join('\n');
|
|
257
|
+
const heading = named.length > 0
|
|
258
|
+
? 'The tables this statement names hold these columns:'
|
|
259
|
+
: 'The projection holds these tables:';
|
|
260
|
+
return `${message}\n\n${heading}\n${surface}`;
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=projection-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection-query.js","sourceRoot":"","sources":["../../src/utils/projection-query.ts"],"names":[],"mappings":"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"}
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
* standard legible error, and a tree that cannot be keyed says so on stderr
|
|
45
45
|
* rather than silently declining.
|
|
46
46
|
*/
|
|
47
|
+
import type * as ProjectionSqlite from '@vibe-agent-toolkit/projection-sqlite';
|
|
47
48
|
import type { PopulationCache } from '@vibe-agent-toolkit/resources';
|
|
48
49
|
/**
|
|
49
50
|
* The env var that selects a projection store for this process.
|
|
@@ -90,6 +91,34 @@ import type { PopulationCache } from '@vibe-agent-toolkit/resources';
|
|
|
90
91
|
export declare const PROJECTION_STORE_ENV = "VAT_PROJECTION_STORE";
|
|
91
92
|
/** {@link PROJECTION_STORE_ENV}'s value that selects the SQLite backend. */
|
|
92
93
|
export declare const PROJECTION_STORE_SQLITE = "sqlite";
|
|
94
|
+
/**
|
|
95
|
+
* Where the projection store's database lives, overriding the default.
|
|
96
|
+
*
|
|
97
|
+
* The default is `tmpdir/.vat-cache/<version>/projection-<shapeDigest>` — one
|
|
98
|
+
* database per VAT release, shared by every root on the machine. This names a
|
|
99
|
+
* different one **explicitly**, which is what an adopter with a per-job cache
|
|
100
|
+
* directory, a shared build agent running two jobs at once, or a test arm that
|
|
101
|
+
* must not touch the developer's live cache actually needs.
|
|
102
|
+
*
|
|
103
|
+
* 🪤 **What it replaces is redirecting `TMPDIR`, which works and is the wrong
|
|
104
|
+
* instrument.** `defaultStoreDirectory()` resolves through
|
|
105
|
+
* `vatCacheNamespaceRoot()` → `normalizedTmpdir()`, so pointing the OS temp
|
|
106
|
+
* directory elsewhere does move the store — along with every other temp
|
|
107
|
+
* consumer in the process, on a variable whose name is not the same on both
|
|
108
|
+
* platforms (`TMPDIR` on POSIX; `TEMP`, then `TMP`, on Windows, so setting one
|
|
109
|
+
* is silently inert on the other). It relocates the store as a side effect of
|
|
110
|
+
* relocating something larger. This variable says the one thing meant.
|
|
111
|
+
*
|
|
112
|
+
* ⚠️ It does **not** consult `XDG_CACHE_HOME` or `HOME`. A caller that set
|
|
113
|
+
* those believed it had its own database and was writing into the shared one;
|
|
114
|
+
* the fix is to name the directory here, not to add more implicit roots.
|
|
115
|
+
*
|
|
116
|
+
* An environment variable rather than a config field, for the same reason
|
|
117
|
+
* {@link PROJECTION_STORE_ENV} is one: it says where an INSTRUMENT keeps its
|
|
118
|
+
* scratch space, not what the project means, and it has to be reachable from a
|
|
119
|
+
* harness that spawns the binary.
|
|
120
|
+
*/
|
|
121
|
+
export declare const PROJECTION_STORE_DIR_ENV = "VAT_PROJECTION_STORE_DIR";
|
|
93
122
|
/**
|
|
94
123
|
* The env var that turns VAT's disk caches off for a run.
|
|
95
124
|
*
|
|
@@ -133,7 +162,19 @@ export declare const CACHE_DISABLED = "0";
|
|
|
133
162
|
* @returns `true` when a store is selected
|
|
134
163
|
*/
|
|
135
164
|
export declare function projectionStoreSelected(): boolean;
|
|
136
|
-
/**
|
|
165
|
+
/**
|
|
166
|
+
* An open store, the key half it is used with, and the way to let it go.
|
|
167
|
+
*
|
|
168
|
+
* ⚠️ **Deliberately NOT typed for SQL, and do not re-widen it.** This handle
|
|
169
|
+
* reaches the database at {@link PROJECTION_STORE_DIR_ENV}'s directory, which
|
|
170
|
+
* defaults to one file per VAT release shared by every root on the machine —
|
|
171
|
+
* holding other repositories' link text, heading text and frontmatter. A field
|
|
172
|
+
* typed `SqlQueryableStore` used to live here "for a caller that needs to ASK
|
|
173
|
+
* the store something", and that caller was removed precisely because arbitrary
|
|
174
|
+
* SQL over this store answers from trees the asker never named. `populate()`
|
|
175
|
+
* needs the engine-free {@link PopulationCache} and nothing more; a query lane
|
|
176
|
+
* builds its own store (see `projection-query.ts`).
|
|
177
|
+
*/
|
|
137
178
|
export interface OpenedPopulationCache {
|
|
138
179
|
/** Hand this to `populate()`. */
|
|
139
180
|
readonly cache: PopulationCache;
|
|
@@ -163,6 +204,57 @@ export interface OpenedPopulationCache {
|
|
|
163
204
|
export declare function openPopulationCache(options: {
|
|
164
205
|
root: string;
|
|
165
206
|
}): Promise<OpenedPopulationCache | undefined>;
|
|
207
|
+
/**
|
|
208
|
+
* Open a store that lives only in this process's memory.
|
|
209
|
+
*
|
|
210
|
+
* 🔑 **This is what keeps the query surface an ANSWER rather than a privilege.**
|
|
211
|
+
* A caller with no store selected — CI's first run, or a developer who never set
|
|
212
|
+
* the selector — still gets the same SQL over the same schema; the on-disk store
|
|
213
|
+
* only makes the second run cheap. Without it, "what does this tree contain"
|
|
214
|
+
* would be answerable only where a cache happened to exist, and two callers
|
|
215
|
+
* would hold differently-shaped views of one tree.
|
|
216
|
+
*
|
|
217
|
+
* It is a cache that cannot hit: nothing survives the close, so a caller must
|
|
218
|
+
* write the projection into it before asking anything.
|
|
219
|
+
*
|
|
220
|
+
* @returns An open, empty store; close it when done
|
|
221
|
+
*/
|
|
222
|
+
export declare function openEphemeralQueryStore(): Promise<ProjectionSqlite.SqlQueryableStore>;
|
|
223
|
+
/**
|
|
224
|
+
* The legible failure for "your Node is too old", or `undefined` when this is
|
|
225
|
+
* some other failure — including "the package is absent".
|
|
226
|
+
*
|
|
227
|
+
* Exported, and returning the error rather than throwing it, so the DIAGNOSIS
|
|
228
|
+
* is unit-testable without a mocked dynamic import. A test cannot make a mocked
|
|
229
|
+
* `import()` reject with a plain `{ code }` — the test runner wraps whatever a
|
|
230
|
+
* module factory throws in its own error, so the code never survives to be
|
|
231
|
+
* read — and the branch's whole value is the message it produces.
|
|
232
|
+
*
|
|
233
|
+
* 🪤 The two are **different error codes**, and only one of them reaches
|
|
234
|
+
* {@link isModuleMissing}. `@vibe-agent-toolkit/projection-sqlite` imports
|
|
235
|
+
* `node:sqlite`, which arrived in Node 22.13.0; on 22.0–22.12 the import fails
|
|
236
|
+
* with `ERR_UNKNOWN_BUILTIN_MODULE`, not `ERR_MODULE_NOT_FOUND`. Without this
|
|
237
|
+
* branch the user gets a bare `No such built-in module: node:sqlite` — which
|
|
238
|
+
* names neither the version floor nor the fix.
|
|
239
|
+
*
|
|
240
|
+
* ⚠️ It is reachable on EVERY `vat resources query`/`check` run, and not a
|
|
241
|
+
* corner: VAT's own floor is `>=22.0.0`, so a supported Node hits it. That was
|
|
242
|
+
* already true before the store-selected path stopped querying a shared
|
|
243
|
+
* database — the query lane has always fallen back to
|
|
244
|
+
* {@link openEphemeralQueryStore} when no store is selected, which is the
|
|
245
|
+
* default, so `node:sqlite` was required on every default run. Nothing here
|
|
246
|
+
* became newly reachable; the branch is load-bearing because the FLOOR is,
|
|
247
|
+
* whichever way the lane resolves its store.
|
|
248
|
+
*
|
|
249
|
+
* The repair stays distinct from the missing-package one on purpose:
|
|
250
|
+
* "install this package" is the wrong instruction for "upgrade Node", and
|
|
251
|
+
* sending someone round that loop cannot terminate.
|
|
252
|
+
*
|
|
253
|
+
* @param error - Whatever the dynamic import threw
|
|
254
|
+
* @returns The error to raise when Node itself lacks the builtin; `undefined`
|
|
255
|
+
* when this failure is something else and the caller should keep diagnosing
|
|
256
|
+
*/
|
|
257
|
+
export declare function nodeSqliteFloorFailure(error: unknown): Error | undefined;
|
|
166
258
|
/**
|
|
167
259
|
* Run one command's work with a projection store open for its whole duration,
|
|
168
260
|
* and closed however it ends.
|
|
@@ -175,7 +267,17 @@ export declare function openPopulationCache(options: {
|
|
|
175
267
|
*
|
|
176
268
|
* It is also the `withGitSnapshotCache` bracket for the work inside it, so the
|
|
177
269
|
* key and the extent filed under it come from ONE git snapshot — see the note
|
|
178
|
-
*
|
|
270
|
+
* in the body.
|
|
271
|
+
*
|
|
272
|
+
* `undefined` on a run with no store selected, which is the shape every
|
|
273
|
+
* population lane wants: no store means re-derive, not fail.
|
|
274
|
+
*
|
|
275
|
+
* ⚠️ A caller that wants to run SQL must NOT query this store. It is one
|
|
276
|
+
* database per VAT release, shared by every root on the machine, so arbitrary
|
|
277
|
+
* SQL over it answers from other repositories — see `projection-query.ts`.
|
|
278
|
+
* That is also why this is the ONLY scope over the opened store: there is no
|
|
279
|
+
* separate "opened handle" bracket for a caller wanting more than the cache,
|
|
280
|
+
* because there is nothing legitimate for such a caller to want.
|
|
179
281
|
*
|
|
180
282
|
* @param options - Where the corpus is
|
|
181
283
|
* @param options.root - The absolute corpus root
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projection-store.d.ts","sourceRoot":"","sources":["../../src/utils/projection-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"projection-store.d.ts","sourceRoot":"","sources":["../../src/utils/projection-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,KAAK,gBAAgB,MAAM,uCAAuC,CAAC;AAC/E,OAAO,KAAK,EAAE,eAAe,EAAmB,MAAM,+BAA+B,CAAC;AAKtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAE3D,4EAA4E;AAC5E,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAEnE;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,cAAc,CAAC;AAErC,gHAAgH;AAChH,eAAO,MAAM,cAAc,MAAM,CAAC;AAkBlC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAGjD;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,qBAAqB;IACpC,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC;;;;;;OAMG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE;IACjD,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAsB7C;AA2BD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAE3F;AAkBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,GAAG,SAAS,CAaxE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EACzC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACzB,IAAI,EAAE,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GACvD,OAAO,CAAC,CAAC,CAAC,CA0BZ"}
|
|
@@ -91,6 +91,34 @@ import { isModuleMissing, reportMissingBackend } from './optional-backend.js';
|
|
|
91
91
|
export const PROJECTION_STORE_ENV = 'VAT_PROJECTION_STORE';
|
|
92
92
|
/** {@link PROJECTION_STORE_ENV}'s value that selects the SQLite backend. */
|
|
93
93
|
export const PROJECTION_STORE_SQLITE = 'sqlite';
|
|
94
|
+
/**
|
|
95
|
+
* Where the projection store's database lives, overriding the default.
|
|
96
|
+
*
|
|
97
|
+
* The default is `tmpdir/.vat-cache/<version>/projection-<shapeDigest>` — one
|
|
98
|
+
* database per VAT release, shared by every root on the machine. This names a
|
|
99
|
+
* different one **explicitly**, which is what an adopter with a per-job cache
|
|
100
|
+
* directory, a shared build agent running two jobs at once, or a test arm that
|
|
101
|
+
* must not touch the developer's live cache actually needs.
|
|
102
|
+
*
|
|
103
|
+
* 🪤 **What it replaces is redirecting `TMPDIR`, which works and is the wrong
|
|
104
|
+
* instrument.** `defaultStoreDirectory()` resolves through
|
|
105
|
+
* `vatCacheNamespaceRoot()` → `normalizedTmpdir()`, so pointing the OS temp
|
|
106
|
+
* directory elsewhere does move the store — along with every other temp
|
|
107
|
+
* consumer in the process, on a variable whose name is not the same on both
|
|
108
|
+
* platforms (`TMPDIR` on POSIX; `TEMP`, then `TMP`, on Windows, so setting one
|
|
109
|
+
* is silently inert on the other). It relocates the store as a side effect of
|
|
110
|
+
* relocating something larger. This variable says the one thing meant.
|
|
111
|
+
*
|
|
112
|
+
* ⚠️ It does **not** consult `XDG_CACHE_HOME` or `HOME`. A caller that set
|
|
113
|
+
* those believed it had its own database and was writing into the shared one;
|
|
114
|
+
* the fix is to name the directory here, not to add more implicit roots.
|
|
115
|
+
*
|
|
116
|
+
* An environment variable rather than a config field, for the same reason
|
|
117
|
+
* {@link PROJECTION_STORE_ENV} is one: it says where an INSTRUMENT keeps its
|
|
118
|
+
* scratch space, not what the project means, and it has to be reachable from a
|
|
119
|
+
* harness that spawns the binary.
|
|
120
|
+
*/
|
|
121
|
+
export const PROJECTION_STORE_DIR_ENV = 'VAT_PROJECTION_STORE_DIR';
|
|
94
122
|
/**
|
|
95
123
|
* The env var that turns VAT's disk caches off for a run.
|
|
96
124
|
*
|
|
@@ -111,6 +139,8 @@ export const CACHE_DISABLED = '0';
|
|
|
111
139
|
* it: RAG carries a platform-native binary, while this one carries a Node
|
|
112
140
|
* version floor.
|
|
113
141
|
*/
|
|
142
|
+
/** What Node throws for `import('node:sqlite')` before 22.13.0. */
|
|
143
|
+
const UNKNOWN_BUILTIN_MODULE = 'ERR_UNKNOWN_BUILTIN_MODULE';
|
|
114
144
|
const PROJECTION_STORE_BACKEND = {
|
|
115
145
|
feature: 'The projection store',
|
|
116
146
|
packageName: '@vibe-agent-toolkit/projection-sqlite',
|
|
@@ -193,19 +223,101 @@ export async function openPopulationCache(options) {
|
|
|
193
223
|
* for "upgrade Node", and diagnosing a version floor as a missing dependency
|
|
194
224
|
* sends a user round a loop that cannot terminate.
|
|
195
225
|
*
|
|
196
|
-
* @returns The opened store
|
|
226
|
+
* @returns The opened store, typed as the engine-free contract — the SQLite
|
|
227
|
+
* backend really does return a `SqlQueryableStore`, and this narrows it away
|
|
228
|
+
* on purpose so the population path cannot grow a query
|
|
197
229
|
*/
|
|
198
230
|
async function loadStore() {
|
|
231
|
+
const directory = process.env[PROJECTION_STORE_DIR_ENV];
|
|
232
|
+
// Spread rather than passed, because the backend defaults the field when it is
|
|
233
|
+
// ABSENT and an explicit `undefined` is a different argument under
|
|
234
|
+
// `exactOptionalPropertyTypes`. Empty string is treated as unset: an unset
|
|
235
|
+
// variable and one exported as `''` are the same intent, and `''` would
|
|
236
|
+
// otherwise resolve to the process cwd.
|
|
237
|
+
return (await loadBackend()).openSqliteProjectionStore(directory === undefined || directory === '' ? {} : { directory });
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Open a store that lives only in this process's memory.
|
|
241
|
+
*
|
|
242
|
+
* 🔑 **This is what keeps the query surface an ANSWER rather than a privilege.**
|
|
243
|
+
* A caller with no store selected — CI's first run, or a developer who never set
|
|
244
|
+
* the selector — still gets the same SQL over the same schema; the on-disk store
|
|
245
|
+
* only makes the second run cheap. Without it, "what does this tree contain"
|
|
246
|
+
* would be answerable only where a cache happened to exist, and two callers
|
|
247
|
+
* would hold differently-shaped views of one tree.
|
|
248
|
+
*
|
|
249
|
+
* It is a cache that cannot hit: nothing survives the close, so a caller must
|
|
250
|
+
* write the projection into it before asking anything.
|
|
251
|
+
*
|
|
252
|
+
* @returns An open, empty store; close it when done
|
|
253
|
+
*/
|
|
254
|
+
export async function openEphemeralQueryStore() {
|
|
255
|
+
return (await loadBackend()).openEphemeralProjectionStore();
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Load the selected backend module, or report it as uninstalled and exit.
|
|
259
|
+
*
|
|
260
|
+
* @returns The backend's module namespace
|
|
261
|
+
*/
|
|
262
|
+
async function loadBackend() {
|
|
199
263
|
try {
|
|
200
|
-
|
|
201
|
-
return backend.openSqliteProjectionStore();
|
|
264
|
+
return await import('@vibe-agent-toolkit/projection-sqlite');
|
|
202
265
|
}
|
|
203
266
|
catch (error) {
|
|
267
|
+
const floor = nodeSqliteFloorFailure(error);
|
|
268
|
+
if (floor !== undefined)
|
|
269
|
+
throw floor;
|
|
204
270
|
if (!isModuleMissing(error))
|
|
205
271
|
throw error;
|
|
206
272
|
reportMissingBackend(PROJECTION_STORE_BACKEND);
|
|
207
273
|
}
|
|
208
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* The legible failure for "your Node is too old", or `undefined` when this is
|
|
277
|
+
* some other failure — including "the package is absent".
|
|
278
|
+
*
|
|
279
|
+
* Exported, and returning the error rather than throwing it, so the DIAGNOSIS
|
|
280
|
+
* is unit-testable without a mocked dynamic import. A test cannot make a mocked
|
|
281
|
+
* `import()` reject with a plain `{ code }` — the test runner wraps whatever a
|
|
282
|
+
* module factory throws in its own error, so the code never survives to be
|
|
283
|
+
* read — and the branch's whole value is the message it produces.
|
|
284
|
+
*
|
|
285
|
+
* 🪤 The two are **different error codes**, and only one of them reaches
|
|
286
|
+
* {@link isModuleMissing}. `@vibe-agent-toolkit/projection-sqlite` imports
|
|
287
|
+
* `node:sqlite`, which arrived in Node 22.13.0; on 22.0–22.12 the import fails
|
|
288
|
+
* with `ERR_UNKNOWN_BUILTIN_MODULE`, not `ERR_MODULE_NOT_FOUND`. Without this
|
|
289
|
+
* branch the user gets a bare `No such built-in module: node:sqlite` — which
|
|
290
|
+
* names neither the version floor nor the fix.
|
|
291
|
+
*
|
|
292
|
+
* ⚠️ It is reachable on EVERY `vat resources query`/`check` run, and not a
|
|
293
|
+
* corner: VAT's own floor is `>=22.0.0`, so a supported Node hits it. That was
|
|
294
|
+
* already true before the store-selected path stopped querying a shared
|
|
295
|
+
* database — the query lane has always fallen back to
|
|
296
|
+
* {@link openEphemeralQueryStore} when no store is selected, which is the
|
|
297
|
+
* default, so `node:sqlite` was required on every default run. Nothing here
|
|
298
|
+
* became newly reachable; the branch is load-bearing because the FLOOR is,
|
|
299
|
+
* whichever way the lane resolves its store.
|
|
300
|
+
*
|
|
301
|
+
* The repair stays distinct from the missing-package one on purpose:
|
|
302
|
+
* "install this package" is the wrong instruction for "upgrade Node", and
|
|
303
|
+
* sending someone round that loop cannot terminate.
|
|
304
|
+
*
|
|
305
|
+
* @param error - Whatever the dynamic import threw
|
|
306
|
+
* @returns The error to raise when Node itself lacks the builtin; `undefined`
|
|
307
|
+
* when this failure is something else and the caller should keep diagnosing
|
|
308
|
+
*/
|
|
309
|
+
export function nodeSqliteFloorFailure(error) {
|
|
310
|
+
const isFloor = typeof error === 'object'
|
|
311
|
+
&& error !== null
|
|
312
|
+
&& 'code' in error
|
|
313
|
+
&& error.code === UNKNOWN_BUILTIN_MODULE;
|
|
314
|
+
if (!isFloor)
|
|
315
|
+
return undefined;
|
|
316
|
+
return new Error('The projection store needs `node:sqlite`, which this Node does not have.'
|
|
317
|
+
+ ` VAT runs on Node >= 22.0.0, but \`node:sqlite\` arrived in 22.13.0 — you are on ${process.version}.`
|
|
318
|
+
+ ' Upgrade Node to 22.13.0 or newer. Installing a package will not help:'
|
|
319
|
+
+ ' the module is built into Node, not published to npm.');
|
|
320
|
+
}
|
|
209
321
|
/**
|
|
210
322
|
* Run one command's work with a projection store open for its whole duration,
|
|
211
323
|
* and closed however it ends.
|
|
@@ -218,7 +330,17 @@ async function loadStore() {
|
|
|
218
330
|
*
|
|
219
331
|
* It is also the `withGitSnapshotCache` bracket for the work inside it, so the
|
|
220
332
|
* key and the extent filed under it come from ONE git snapshot — see the note
|
|
221
|
-
*
|
|
333
|
+
* in the body.
|
|
334
|
+
*
|
|
335
|
+
* `undefined` on a run with no store selected, which is the shape every
|
|
336
|
+
* population lane wants: no store means re-derive, not fail.
|
|
337
|
+
*
|
|
338
|
+
* ⚠️ A caller that wants to run SQL must NOT query this store. It is one
|
|
339
|
+
* database per VAT release, shared by every root on the machine, so arbitrary
|
|
340
|
+
* SQL over it answers from other repositories — see `projection-query.ts`.
|
|
341
|
+
* That is also why this is the ONLY scope over the opened store: there is no
|
|
342
|
+
* separate "opened handle" bracket for a caller wanting more than the cache,
|
|
343
|
+
* because there is nothing legitimate for such a caller to want.
|
|
222
344
|
*
|
|
223
345
|
* @param options - Where the corpus is
|
|
224
346
|
* @param options.root - The absolute corpus root
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projection-store.js","sourceRoot":"","sources":["../../src/utils/projection-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;
|
|
1
|
+
{"version":3,"file":"projection-store.js","sourceRoot":"","sources":["../../src/utils/projection-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the built vat CLI entry is, for the commands that re-invoke it as a
|
|
3
|
+
* child process.
|
|
4
|
+
*
|
|
5
|
+
* ## 🪤 `dist/bin.js`, deliberately NOT `dist/bin/vat.js`
|
|
6
|
+
*
|
|
7
|
+
* `packages/lab/src/harness/instrument.ts` documents `dist/bin/vat.js` as a
|
|
8
|
+
* re-resolving WRAPPER: it looks the CLI up again at run time, so spawning it
|
|
9
|
+
* can execute a different build than the one the caller is running from. A
|
|
10
|
+
* supervisor that thinks it is bounding its own code, and a corpus runner that
|
|
11
|
+
* thinks it is auditing with its own validators, both need the entry point that
|
|
12
|
+
* cannot be redirected.
|
|
13
|
+
*
|
|
14
|
+
* ## Why the two branches
|
|
15
|
+
*
|
|
16
|
+
* `node` cannot execute `.ts`, so a caller running from SOURCE under vitest
|
|
17
|
+
* still has to reach the COMPILED entry — which is why the source-tree branch
|
|
18
|
+
* walks across to `packages/cli/dist/bin.js` rather than to a sibling. A build
|
|
19
|
+
* is therefore a precondition for every test that spawns the CLI, and a system
|
|
20
|
+
* test that skipped it would prove things about a stale `dist`.
|
|
21
|
+
*
|
|
22
|
+
* 🪤 Shared rather than copied. This resolution lived inline in
|
|
23
|
+
* `commands/corpus/runner.ts` and a second caller wanted it; a second copy is a
|
|
24
|
+
* duplication-gate failure under this repo's zero-tolerance policy, and — worse
|
|
25
|
+
* — two copies drift, so one caller would keep spawning the wrapper long after
|
|
26
|
+
* the other stopped. The `__dirname`-relative hops below are correct for THIS
|
|
27
|
+
* module's location and nothing else, which is precisely why it is not a snippet
|
|
28
|
+
* to paste.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Resolve the path to the built vat CLI entry.
|
|
32
|
+
*
|
|
33
|
+
* @returns An absolute path to `dist/bin.js`
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveVatBinPath(): string;
|
|
36
|
+
//# sourceMappingURL=vat-bin-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vat-bin-path.d.ts","sourceRoot":"","sources":["../../src/utils/vat-bin-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAUH;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAO1C"}
|