@vibe-agent-toolkit/cli 0.2.0-rc.2 → 0.2.0-rc.4
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/vat +68 -16
- package/dist/bin/vat.js +68 -16
- package/dist/bin/vat.js.map +1 -1
- package/dist/bin.js +157 -37
- package/dist/bin.js.map +1 -1
- package/dist/command-loaders.d.ts +44 -0
- package/dist/command-loaders.d.ts.map +1 -0
- package/dist/command-loaders.js +58 -0
- package/dist/command-loaders.js.map +1 -0
- package/dist/commands/agent/index.js +1 -1
- package/dist/commands/agent/install.d.ts.map +1 -1
- package/dist/commands/agent/install.js +46 -5
- package/dist/commands/agent/install.js.map +1 -1
- package/dist/commands/audit/distributed-tree.d.ts +2 -2
- package/dist/commands/audit/distributed-tree.d.ts.map +1 -1
- package/dist/commands/audit/distributed-tree.js +2 -1
- package/dist/commands/audit/distributed-tree.js.map +1 -1
- package/dist/commands/audit/git-url-clone.d.ts +1 -1
- package/dist/commands/audit/git-url-clone.d.ts.map +1 -1
- package/dist/commands/audit/git-url-clone.js.map +1 -1
- package/dist/commands/audit/hierarchical-output.d.ts +1 -1
- package/dist/commands/audit/hierarchical-output.d.ts.map +1 -1
- package/dist/commands/audit/hierarchical-output.js +1 -1
- package/dist/commands/audit/hierarchical-output.js.map +1 -1
- package/dist/commands/audit.d.ts +22 -1
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +224 -24
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/build.d.ts +1 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +15 -12
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/cache/cache-control.d.ts +82 -0
- package/dist/commands/cache/cache-control.d.ts.map +1 -0
- package/dist/commands/cache/cache-control.js +86 -0
- package/dist/commands/cache/cache-control.js.map +1 -0
- package/dist/commands/cache/clear.d.ts +17 -3
- package/dist/commands/cache/clear.d.ts.map +1 -1
- package/dist/commands/cache/clear.js +68 -3
- package/dist/commands/cache/clear.js.map +1 -1
- package/dist/commands/cache/index.d.ts +13 -63
- package/dist/commands/cache/index.d.ts.map +1 -1
- package/dist/commands/cache/index.js +38 -79
- package/dist/commands/cache/index.js.map +1 -1
- package/dist/commands/claude/budget.d.ts +157 -0
- package/dist/commands/claude/budget.d.ts.map +1 -0
- package/dist/commands/claude/budget.js +412 -0
- package/dist/commands/claude/budget.js.map +1 -0
- package/dist/commands/claude/context.d.ts +340 -0
- package/dist/commands/claude/context.d.ts.map +1 -0
- package/dist/commands/claude/context.js +1079 -0
- package/dist/commands/claude/context.js.map +1 -0
- package/dist/commands/claude/index.d.ts +13 -0
- package/dist/commands/claude/index.d.ts.map +1 -1
- package/dist/commands/claude/index.js +24 -2
- package/dist/commands/claude/index.js.map +1 -1
- package/dist/commands/claude/marketplace/git-publish.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/git-publish.js +18 -19
- package/dist/commands/claude/marketplace/git-publish.js.map +1 -1
- package/dist/commands/claude/marketplace/validate.d.ts +19 -1
- package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/validate.js +41 -21
- package/dist/commands/claude/marketplace/validate.js.map +1 -1
- package/dist/commands/claude/plugin/build.d.ts +18 -2
- package/dist/commands/claude/plugin/build.d.ts.map +1 -1
- package/dist/commands/claude/plugin/build.js +55 -18
- package/dist/commands/claude/plugin/build.js.map +1 -1
- package/dist/commands/claude/plugin/helpers.d.ts.map +1 -1
- package/dist/commands/claude/plugin/helpers.js +2 -1
- package/dist/commands/claude/plugin/helpers.js.map +1 -1
- package/dist/commands/claude/plugin/install.d.ts.map +1 -1
- package/dist/commands/claude/plugin/install.js +24 -3
- package/dist/commands/claude/plugin/install.js.map +1 -1
- package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
- package/dist/commands/claude/plugin/tree-copy.js +2 -1
- package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
- package/dist/commands/consistency-check.d.ts.map +1 -1
- package/dist/commands/consistency-check.js +4 -3
- package/dist/commands/consistency-check.js.map +1 -1
- package/dist/commands/corpus/report.d.ts +1 -1
- package/dist/commands/corpus/report.d.ts.map +1 -1
- package/dist/commands/corpus/runner.d.ts.map +1 -1
- package/dist/commands/corpus/runner.js +3 -2
- package/dist/commands/corpus/runner.js.map +1 -1
- package/dist/commands/corpus/scan.d.ts.map +1 -1
- package/dist/commands/corpus/scan.js +18 -8
- package/dist/commands/corpus/scan.js.map +1 -1
- package/dist/commands/doctor.d.ts +36 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +99 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/inventory.d.ts +13 -1
- package/dist/commands/inventory.d.ts.map +1 -1
- package/dist/commands/inventory.js +118 -13
- package/dist/commands/inventory.js.map +1 -1
- package/dist/commands/mcp/collections.d.ts +1 -1
- package/dist/commands/mcp/collections.d.ts.map +1 -1
- package/dist/commands/phase-utils.d.ts +155 -104
- package/dist/commands/phase-utils.d.ts.map +1 -1
- package/dist/commands/phase-utils.js +109 -155
- package/dist/commands/phase-utils.js.map +1 -1
- package/dist/commands/rag/index-command.d.ts +39 -0
- package/dist/commands/rag/index-command.d.ts.map +1 -1
- package/dist/commands/rag/index-command.js +28 -2
- package/dist/commands/rag/index-command.js.map +1 -1
- package/dist/commands/rag/index.d.ts.map +1 -1
- package/dist/commands/rag/index.js +21 -10
- package/dist/commands/rag/index.js.map +1 -1
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +10 -2
- package/dist/commands/resources/index.js.map +1 -1
- package/dist/commands/resources/scan.d.ts +24 -0
- package/dist/commands/resources/scan.d.ts.map +1 -1
- package/dist/commands/resources/scan.js +19 -6
- package/dist/commands/resources/scan.js.map +1 -1
- package/dist/commands/resources/validate.d.ts +12 -1
- package/dist/commands/resources/validate.d.ts.map +1 -1
- package/dist/commands/resources/validate.js +102 -51
- package/dist/commands/resources/validate.js.map +1 -1
- package/dist/commands/skill/review-checklist.d.ts.map +1 -1
- package/dist/commands/skill/review-checklist.js +1 -0
- package/dist/commands/skill/review-checklist.js.map +1 -1
- package/dist/commands/skill/review.js +2 -2
- package/dist/commands/skill/review.js.map +1 -1
- package/dist/commands/skill/test/configure.d.ts +19 -0
- package/dist/commands/skill/test/configure.d.ts.map +1 -1
- package/dist/commands/skill/test/configure.js +18 -3
- package/dist/commands/skill/test/configure.js.map +1 -1
- package/dist/commands/skill/test/run.d.ts +51 -4
- package/dist/commands/skill/test/run.d.ts.map +1 -1
- package/dist/commands/skill/test/run.js +123 -12
- package/dist/commands/skill/test/run.js.map +1 -1
- package/dist/commands/skills/build.d.ts +11 -1
- package/dist/commands/skills/build.d.ts.map +1 -1
- package/dist/commands/skills/build.js +154 -61
- package/dist/commands/skills/build.js.map +1 -1
- package/dist/commands/skills/package.d.ts +1 -1
- package/dist/commands/skills/package.d.ts.map +1 -1
- package/dist/commands/skills/package.js.map +1 -1
- package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
- package/dist/commands/skills/skill-discovery.js +2 -1
- package/dist/commands/skills/skill-discovery.js.map +1 -1
- package/dist/commands/skills/validate.d.ts +79 -2
- package/dist/commands/skills/validate.d.ts.map +1 -1
- package/dist/commands/skills/validate.js +101 -48
- package/dist/commands/skills/validate.js.map +1 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +26 -16
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/verify.d.ts +11 -10
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +49 -38
- package/dist/commands/verify.js.map +1 -1
- package/dist/utils/command-error.d.ts +33 -2
- package/dist/utils/command-error.d.ts.map +1 -1
- package/dist/utils/command-error.js +34 -10
- 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 +7 -1
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/context-budget-issues.d.ts +108 -0
- package/dist/utils/context-budget-issues.d.ts.map +1 -0
- package/dist/utils/context-budget-issues.js +280 -0
- package/dist/utils/context-budget-issues.js.map +1 -0
- package/dist/utils/corpus-target.d.ts +48 -0
- package/dist/utils/corpus-target.d.ts.map +1 -0
- package/dist/utils/corpus-target.js +61 -0
- package/dist/utils/corpus-target.js.map +1 -0
- package/dist/utils/issue-anchor.d.ts +2 -2
- package/dist/utils/issue-anchor.d.ts.map +1 -1
- package/dist/utils/issue-anchor.js +1 -1
- package/dist/utils/issue-rendering.d.ts +1 -1
- package/dist/utils/issue-rendering.d.ts.map +1 -1
- package/dist/utils/issue-rendering.js +1 -1
- package/dist/utils/issue-rendering.js.map +1 -1
- package/dist/utils/issue-severity.d.ts +1 -1
- 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/optional-backend.d.ts +77 -0
- package/dist/utils/optional-backend.d.ts.map +1 -0
- package/dist/utils/optional-backend.js +115 -0
- package/dist/utils/optional-backend.js.map +1 -0
- package/dist/utils/output.d.ts +17 -0
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +19 -0
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/population-wiring.d.ts +100 -0
- package/dist/utils/population-wiring.d.ts.map +1 -0
- package/dist/utils/population-wiring.js +98 -0
- package/dist/utils/population-wiring.js.map +1 -0
- package/dist/utils/projection-store.d.ts +188 -0
- package/dist/utils/projection-store.d.ts.map +1 -0
- package/dist/utils/projection-store.js +257 -0
- package/dist/utils/projection-store.js.map +1 -0
- package/dist/utils/resource-loader.d.ts +128 -2
- package/dist/utils/resource-loader.d.ts.map +1 -1
- package/dist/utils/resource-loader.js +234 -7
- package/dist/utils/resource-loader.js.map +1 -1
- package/dist/utils/verdict-helpers.d.ts +1 -1
- package/dist/utils/verdict-helpers.d.ts.map +1 -1
- package/dist/utils/verdict-helpers.js +1 -1
- package/dist/utils/verdict-helpers.js.map +1 -1
- package/docs/agent.md +2 -2
- package/docs/mcp.md +2 -2
- package/docs/resources.md +8 -1
- package/package.json +15 -12
- package/dist/commands/resources/command-helpers.d.ts +0 -5
- package/dist/commands/resources/command-helpers.d.ts.map +0 -1
- package/dist/commands/resources/command-helpers.js +0 -6
- package/dist/commands/resources/command-helpers.js.map +0 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Selecting, opening and keying the **projection store** — the cross-process
|
|
3
|
+
* cache that makes a second population of an unchanged tree cheap.
|
|
4
|
+
*
|
|
5
|
+
* ## Why the CLI owns this and `resources` does not
|
|
6
|
+
*
|
|
7
|
+
* `@vibe-agent-toolkit/resources` states the {@link ProjectionStore} contract
|
|
8
|
+
* and never picks a backend, for the same reason it states the parse contract
|
|
9
|
+
* and never picks a parser: it is the toolkit's most widely installed package,
|
|
10
|
+
* and a storage engine is a *choice*. The choice is made here, at the edge that
|
|
11
|
+
* already owns every other optional backend — see `optional-backend.ts`, whose
|
|
12
|
+
* header names a projection store as one of the shapes it exists for.
|
|
13
|
+
*
|
|
14
|
+
* So `populate()` takes a {@link PopulationCache} it is handed, and this module
|
|
15
|
+
* is the only place in the toolkit that knows `@vibe-agent-toolkit/projection-
|
|
16
|
+
* sqlite` exists.
|
|
17
|
+
*
|
|
18
|
+
* ## The key, and why it is a whole-repository tree hash
|
|
19
|
+
*
|
|
20
|
+
* A stored extent is filed under `(rootId, treeHash)`. `populate()` derives the
|
|
21
|
+
* root id itself so a caller cannot file one root's contents under another's;
|
|
22
|
+
* this module supplies the other half.
|
|
23
|
+
*
|
|
24
|
+
* {@link gitTreeSnapshot} answers it with `git write-tree` against a throwaway
|
|
25
|
+
* index, which covers staged edits, unstaged edits and untracked files, and
|
|
26
|
+
* carries **no timestamp** — byte-identical content always produces the same
|
|
27
|
+
* hash. 🪤 Never `git stash create`: a stash is a *commit*, so two calls over
|
|
28
|
+
* identical content agree only within the same wall-clock second, and every
|
|
29
|
+
* read would miss.
|
|
30
|
+
*
|
|
31
|
+
* ⚠️ That hash covers the whole **repository**, not the subtree the root names.
|
|
32
|
+
* An edit anywhere in the repository therefore cools the cache for every root
|
|
33
|
+
* inside it. This is conservative in the safe direction and cheap to be
|
|
34
|
+
* conservative about — `git write-tree` against a throwaway index is the same
|
|
35
|
+
* call `vibe-validate` makes on every commit.
|
|
36
|
+
*
|
|
37
|
+
* ## An opted-in cache that quietly does nothing is worse than no cache
|
|
38
|
+
*
|
|
39
|
+
* Every failure here is loud, and that is deliberate rather than harsh. A
|
|
40
|
+
* selector nobody honours produces a measurement arm that believes it is
|
|
41
|
+
* testing a cache and is testing an ordinary cold run — the "subject that
|
|
42
|
+
* exercises nothing looks like a clean result" failure that has already cost
|
|
43
|
+
* this project one whole A/B. So an uninstalled backend exits with the seam's
|
|
44
|
+
* standard legible error, and a tree that cannot be keyed says so on stderr
|
|
45
|
+
* rather than silently declining.
|
|
46
|
+
*/
|
|
47
|
+
import { gitTreeSnapshot, withGitSnapshotCache } from '@vibe-agent-toolkit/utils/git';
|
|
48
|
+
import { isModuleMissing, reportMissingBackend } from './optional-backend.js';
|
|
49
|
+
/**
|
|
50
|
+
* The env var that selects a projection store for this process.
|
|
51
|
+
*
|
|
52
|
+
* An environment switch rather than a config field, for the same reason
|
|
53
|
+
* `VAT_INVENTORY_CRAWL` and `VAT_RESOURCES_CRAWL` are: it selects which
|
|
54
|
+
* INSTRUMENT runs, not what the project means, and it has to be reachable from
|
|
55
|
+
* the lab, which spawns the binary and controls its environment. A config field
|
|
56
|
+
* would put the A and B arms inside the subject's own tree, where a measurement
|
|
57
|
+
* edits the thing it measures.
|
|
58
|
+
*
|
|
59
|
+
* 🔑 It is read from the environment, and **every phase now runs in the process
|
|
60
|
+
* that read it** — phases used to be child processes inheriting it across a
|
|
61
|
+
* `spawnSync`, which reached the same place by a longer route. `vat validate`'s
|
|
62
|
+
* phases see the same selection their orchestrator did, and can no longer fail
|
|
63
|
+
* to.
|
|
64
|
+
*
|
|
65
|
+
* 🔑 **That sharing has a within-verb instance.** `vat build`'s two
|
|
66
|
+
* phases — `skills build` and `claude plugin build` — both reach the lane
|
|
67
|
+
* through `withResourcePopulationSource` (see `resource-loader.ts`), and both
|
|
68
|
+
* root their population at the same directory, so phase 2 reads the extent
|
|
69
|
+
* phase 1 wrote. Measured on `packages/vat-development-agents` with
|
|
70
|
+
* `VAT_CRAWL_TIMING`: with a cold store phase 1 files `builtin:filesystem`
|
|
71
|
+
* 39.2 ms and `projection-store:write` 10.1 ms, phase 2 files neither and its
|
|
72
|
+
* `resource-registry:enumerate` reads 3.6 ms against phase 1's 66.6 ms.
|
|
73
|
+
*
|
|
74
|
+
* It did NOT need the closure to emit reasons, which is what an earlier reading
|
|
75
|
+
* of this expected: the packaging lanes consume `resource_realizations` and let
|
|
76
|
+
* `walkLinkGraph` keep running on top of the registry, so the base extent alone
|
|
77
|
+
* answers them — the same shape `buildResourcePopulation` already had.
|
|
78
|
+
*
|
|
79
|
+
* The cross-INVOCATION win is unchanged and independent: `vat validate` and
|
|
80
|
+
* `vat verify` spawn a byte-identical `resources validate` child, so the second
|
|
81
|
+
* hits the store.
|
|
82
|
+
*
|
|
83
|
+
* ⚠️ One packaging enumeration is still on the walk: `vat claude plugin build`'s
|
|
84
|
+
* per-skill post-build validation, which reaches `crawlAndResolveRegistry` in
|
|
85
|
+
* `packaging-validator.ts` without a source — its `withResourcePopulationSource`
|
|
86
|
+
* bracket closes around `createProjectRegistry` and does not span the
|
|
87
|
+
* marketplace loop. `vat skills build` no longer does: it holds one bracket over
|
|
88
|
+
* the whole run, and the registry memo is keyed on the population source, so
|
|
89
|
+
* both of its registries source from the projection.
|
|
90
|
+
*/
|
|
91
|
+
export const PROJECTION_STORE_ENV = 'VAT_PROJECTION_STORE';
|
|
92
|
+
/** {@link PROJECTION_STORE_ENV}'s value that selects the SQLite backend. */
|
|
93
|
+
export const PROJECTION_STORE_SQLITE = 'sqlite';
|
|
94
|
+
/**
|
|
95
|
+
* The env var that turns VAT's disk caches off for a run.
|
|
96
|
+
*
|
|
97
|
+
* Not this module's invention — `ParseCache` has read it since the parse cache
|
|
98
|
+
* shipped, and `vat`'s root `--no-cache` exports it from a `preAction` hook so
|
|
99
|
+
* the decision reaches every spawned phase. Named here rather than spelled
|
|
100
|
+
* inline so the projection store is visibly the same tenant as the caches the
|
|
101
|
+
* flag was written for.
|
|
102
|
+
*/
|
|
103
|
+
export const CACHE_ENV = 'VAT_CACHE';
|
|
104
|
+
/** {@link CACHE_ENV}'s one off value. Exactly `'0'`, never truthiness — see {@link projectionStoreSelected}. */
|
|
105
|
+
export const CACHE_DISABLED = '0';
|
|
106
|
+
/**
|
|
107
|
+
* The backend as a user is told to install it.
|
|
108
|
+
*
|
|
109
|
+
* Named separately from the RAG backend's entry because the *reason* it ships
|
|
110
|
+
* apart is different, and the install message is the only place a user learns
|
|
111
|
+
* it: RAG carries a platform-native binary, while this one carries a Node
|
|
112
|
+
* version floor.
|
|
113
|
+
*/
|
|
114
|
+
const PROJECTION_STORE_BACKEND = {
|
|
115
|
+
feature: 'The projection store',
|
|
116
|
+
packageName: '@vibe-agent-toolkit/projection-sqlite',
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Whether this process should read and write a projection store.
|
|
120
|
+
*
|
|
121
|
+
* **Off unless asked for**, which is the opposite of `vat inventory`'s crawl
|
|
122
|
+
* selector and matches `vat resources scan`'s. A cache changes no answer, so
|
|
123
|
+
* the reason to hold it back is not correctness but evidence: the win is a
|
|
124
|
+
* claim about cost, and a default flipped before the cost is measured on real
|
|
125
|
+
* corpora is a claim nobody checked.
|
|
126
|
+
*
|
|
127
|
+
* Read from the environment at each call rather than memoized at module load:
|
|
128
|
+
* `vitest.setup.js` deletes every `VAT_*` variable before any test module
|
|
129
|
+
* loads, so a module-level binding would make the switch unobservable to every
|
|
130
|
+
* test that sets it.
|
|
131
|
+
*
|
|
132
|
+
* ## The two switches are AND-ed, and the second one is a veto
|
|
133
|
+
*
|
|
134
|
+
* {@link PROJECTION_STORE_ENV} says *which* backend; {@link CACHE_ENV} says
|
|
135
|
+
* whether this run caches at all. A store selected while `VAT_CACHE=0` was
|
|
136
|
+
* measured writing a 9.8 MB, 18,079-row store on this repository and hitting it
|
|
137
|
+
* on the next run — a user who asked for no cache silently got one, and
|
|
138
|
+
* `vat cache`'s own help text described three caches while a fourth was being
|
|
139
|
+
* written beside them.
|
|
140
|
+
*
|
|
141
|
+
* 🪤 Compared against `'0'` exactly, never for truthiness, matching
|
|
142
|
+
* `ParseCache`'s `env['VAT_CACHE'] !== '0'`. `VAT_CACHE=1` is the value an
|
|
143
|
+
* operator writes to turn caching ON, and a truthiness test would read it as a
|
|
144
|
+
* reason to decline.
|
|
145
|
+
*
|
|
146
|
+
* @returns `true` when a store is selected
|
|
147
|
+
*/
|
|
148
|
+
export function projectionStoreSelected() {
|
|
149
|
+
if (process.env[CACHE_ENV] === CACHE_DISABLED)
|
|
150
|
+
return false;
|
|
151
|
+
return process.env[PROJECTION_STORE_ENV] === PROJECTION_STORE_SQLITE;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Open the projection store this process selected, keyed to one tree.
|
|
155
|
+
*
|
|
156
|
+
* Returns `undefined` when no store is selected, and when the tree cannot be
|
|
157
|
+
* keyed — the two "carry on without a cache" answers. It does **not** return
|
|
158
|
+
* `undefined` for an uninstalled backend: a user who set the selector asked for
|
|
159
|
+
* a store, and answering that request by silently not having one is how an
|
|
160
|
+
* opted-in cache becomes an unmeasured one.
|
|
161
|
+
*
|
|
162
|
+
* @param options - Where the corpus is
|
|
163
|
+
* @param options.root - The absolute corpus root. Used to find the repository;
|
|
164
|
+
* the resulting hash covers that whole repository, not this subtree
|
|
165
|
+
* @returns The cache and its closer, or `undefined` to populate uncached
|
|
166
|
+
*/
|
|
167
|
+
export async function openPopulationCache(options) {
|
|
168
|
+
if (!projectionStoreSelected())
|
|
169
|
+
return undefined;
|
|
170
|
+
// Before the import, so a corpus outside a repository costs nothing and says
|
|
171
|
+
// why. `gitTreeSnapshot` returns null for every "git could not answer" case —
|
|
172
|
+
// no `git` on PATH, not a repository, a bare or unreadable one — and an empty
|
|
173
|
+
// snapshot of an initialized repository stays distinguishable from it.
|
|
174
|
+
const snapshot = gitTreeSnapshot({ cwd: options.root });
|
|
175
|
+
if (snapshot === null) {
|
|
176
|
+
process.stderr.write(`${PROJECTION_STORE_ENV} is set, but ${options.root} is not inside a readable git`
|
|
177
|
+
+ ' repository, so there is no deterministic key to store a projection under.'
|
|
178
|
+
+ ' Populating without a cache.\n');
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
const store = await loadStore();
|
|
182
|
+
return {
|
|
183
|
+
cache: { store, treeHash: snapshot.hash },
|
|
184
|
+
close: () => store.close(),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Load the selected backend, or report it as uninstalled and exit.
|
|
189
|
+
*
|
|
190
|
+
* 🪤 Only `ERR_MODULE_NOT_FOUND` means "not installed". A Node older than
|
|
191
|
+
* 22.13.0 has no `node:sqlite` at all and fails with a *different* code, which
|
|
192
|
+
* must propagate as itself: "install this package" would be the wrong repair
|
|
193
|
+
* for "upgrade Node", and diagnosing a version floor as a missing dependency
|
|
194
|
+
* sends a user round a loop that cannot terminate.
|
|
195
|
+
*
|
|
196
|
+
* @returns The opened store
|
|
197
|
+
*/
|
|
198
|
+
async function loadStore() {
|
|
199
|
+
try {
|
|
200
|
+
const backend = await import('@vibe-agent-toolkit/projection-sqlite');
|
|
201
|
+
return backend.openSqliteProjectionStore();
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
if (!isModuleMissing(error))
|
|
205
|
+
throw error;
|
|
206
|
+
reportMissingBackend(PROJECTION_STORE_BACKEND);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Run one command's work with a projection store open for its whole duration,
|
|
211
|
+
* and closed however it ends.
|
|
212
|
+
*
|
|
213
|
+
* A scope rather than a bare open/close pair, because the store must outlive the
|
|
214
|
+
* call that builds a population source and not merely the call that uses it: the
|
|
215
|
+
* inventory extractor MEMOIZES its population provider and may reach it well
|
|
216
|
+
* after the frame that supplied it has returned. A store closed at the end of
|
|
217
|
+
* that frame would be closed under its own consumer.
|
|
218
|
+
*
|
|
219
|
+
* It is also the `withGitSnapshotCache` bracket for the work inside it, so the
|
|
220
|
+
* key and the extent filed under it come from ONE git snapshot — see the note
|
|
221
|
+
* on the call below.
|
|
222
|
+
*
|
|
223
|
+
* @param options - Where the corpus is
|
|
224
|
+
* @param options.root - The absolute corpus root
|
|
225
|
+
* @param work - Given the cache, or `undefined` when there is none to give
|
|
226
|
+
* @returns Whatever `work` returned
|
|
227
|
+
*/
|
|
228
|
+
export async function withPopulationCache(options, work) {
|
|
229
|
+
// ONE git snapshot for the whole scope, and this is the level that gets it:
|
|
230
|
+
// `openPopulationCache` below takes one to derive the store key, and the crawl
|
|
231
|
+
// that runs inside `work` takes another to enumerate the extent — same
|
|
232
|
+
// repository, sequentially, ~195 ms and ~159 ms measured on a large monorepo.
|
|
233
|
+
//
|
|
234
|
+
// The correctness half matters more than the saving. Taken separately, a
|
|
235
|
+
// working-tree edit landing between them makes the two snapshots DIFFERENT
|
|
236
|
+
// answers, and the extent from the second is then filed under the key from the
|
|
237
|
+
// first: a cache entry whose key does not describe its contents, written
|
|
238
|
+
// silently. The bracket closes that race rather than merely deduplicating.
|
|
239
|
+
//
|
|
240
|
+
// Opened here rather than around either consumer because it must enclose BOTH
|
|
241
|
+
// — a bracket opened deeper than one of them dedupes nothing while looking
|
|
242
|
+
// exactly like a bracket that works. Every CLI entry into the projection lane
|
|
243
|
+
// (`inventory`, `resource-loader`'s two) reaches the store through this scope,
|
|
244
|
+
// so this one placement covers all of them.
|
|
245
|
+
return withGitSnapshotCache(async () => {
|
|
246
|
+
const opened = await openPopulationCache(options);
|
|
247
|
+
if (opened === undefined)
|
|
248
|
+
return work(undefined);
|
|
249
|
+
try {
|
|
250
|
+
return await work(opened.cache);
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
await opened.close();
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=projection-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection-store.js","sourceRoot":"","sources":["../../src/utils/projection-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAGH,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAEtF,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAwB,MAAM,uBAAuB,CAAC;AAEpG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAE3D,4EAA4E;AAC5E,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC;AAEhD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAC;AAErC,gHAAgH;AAChH,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAC;AAElC;;;;;;;GAOG;AACH,MAAM,wBAAwB,GAAoB;IAChD,OAAO,EAAE,sBAAsB;IAC/B,WAAW,EAAE,uCAAuC;CACrD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,uBAAuB;IACrC,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,cAAc;QAAE,OAAO,KAAK,CAAC;IAC5D,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,KAAK,uBAAuB,CAAC;AACvE,CAAC;AAgBD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAEzC;IACC,IAAI,CAAC,uBAAuB,EAAE;QAAE,OAAO,SAAS,CAAC;IAEjD,6EAA6E;IAC7E,8EAA8E;IAC9E,8EAA8E;IAC9E,uEAAuE;IACvE,MAAM,QAAQ,GAAG,eAAe,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACxD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,oBAAoB,gBAAgB,OAAO,CAAC,IAAI,+BAA+B;cAChF,4EAA4E;cAC5E,gCAAgC,CACnC,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAChC,OAAO;QACL,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE;QACzC,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE;KAC3B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,KAAK,UAAU,SAAS;IACtB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,uCAAuC,CAAC,CAAC;QACtE,OAAO,OAAO,CAAC,yBAAyB,EAAE,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;YAAE,MAAM,KAAK,CAAC;QACzC,oBAAoB,CAAC,wBAAwB,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAyB,EACzB,IAAwD;IAExD,4EAA4E;IAC5E,+EAA+E;IAC/E,uEAAuE;IACvE,8EAA8E;IAC9E,EAAE;IACF,yEAAyE;IACzE,2EAA2E;IAC3E,+EAA+E;IAC/E,yEAAyE;IACzE,2EAA2E;IAC3E,EAAE;IACF,8EAA8E;IAC9E,2EAA2E;IAC3E,8EAA8E;IAC9E,+EAA+E;IAC/E,4CAA4C;IAC5C,OAAO,oBAAoB,CAAC,KAAK,IAAI,EAAE;QACrC,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,15 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Utilities for loading and crawling resources
|
|
3
3
|
*/
|
|
4
|
-
import { ResourceRegistry, type ProjectConfig } from '@vibe-agent-toolkit/resources';
|
|
5
|
-
import { GitTracker } from '@vibe-agent-toolkit/utils';
|
|
4
|
+
import { ResourceRegistry, type CrawlSourceKind, type ProjectConfig, type ResourcePopulationSource } from '@vibe-agent-toolkit/resources';
|
|
5
|
+
import { GitTracker } from '@vibe-agent-toolkit/utils/git';
|
|
6
6
|
import type { Logger } from './logger.js';
|
|
7
|
+
/**
|
|
8
|
+
* Which enumerator produced a load's population.
|
|
9
|
+
*
|
|
10
|
+
* `walk` is the incumbent `crawlDirectory` route; `projection` is the
|
|
11
|
+
* projection lane behind {@link RESOURCES_CRAWL_ENV}.
|
|
12
|
+
*/
|
|
13
|
+
export type ResourceCrawlLane = 'walk' | 'projection';
|
|
7
14
|
export interface ResourceLoadResult {
|
|
8
15
|
scanPath: string;
|
|
9
16
|
projectRoot: string;
|
|
10
17
|
config: ProjectConfig | undefined;
|
|
11
18
|
registry: ResourceRegistry;
|
|
12
19
|
gitTracker: GitTracker | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Which lane enumerated, as a fact about the run rather than about the
|
|
22
|
+
* environment that requested it.
|
|
23
|
+
*
|
|
24
|
+
* Reported so that a population can be held against another one: two scans of
|
|
25
|
+
* the same tree that disagree are only interpretable if each says which
|
|
26
|
+
* enumerator produced it. Reading the env var back instead would prove what
|
|
27
|
+
* was ASKED for, never what happened — a distinction that has already voided
|
|
28
|
+
* one whole A/B on this codebase, where both arms silently ran the incumbent.
|
|
29
|
+
*/
|
|
30
|
+
lane: ResourceCrawlLane;
|
|
31
|
+
/**
|
|
32
|
+
* Which enumerator the projection lane used, or `null` when the walk ran and
|
|
33
|
+
* there was no extent to source.
|
|
34
|
+
*
|
|
35
|
+
* Reported for the same reason {@link ResourceCrawlLane} is, one level down.
|
|
36
|
+
* `lane` distinguishes the walk from the projection; it does NOT distinguish
|
|
37
|
+
* the projection's two enumerators, and `VAT_EXTENT_SOURCE` is exactly the
|
|
38
|
+
* axis a flip decision turns on. Without this, both arms of that A/B report
|
|
39
|
+
* `projection` and two identical populations mean either "the enumerators
|
|
40
|
+
* agree" or "the switch was ignored" — indistinguishable, and the second is
|
|
41
|
+
* reachable, because `crawlSourceFor` falls back to the walk without saying
|
|
42
|
+
* so when the root is not in a repository.
|
|
43
|
+
*/
|
|
44
|
+
extentSource: CrawlSourceKind | null;
|
|
13
45
|
}
|
|
14
46
|
/**
|
|
15
47
|
* Scope resource include patterns to a subdirectory of the crawl base.
|
|
@@ -23,6 +55,100 @@ export interface ResourceLoadResult {
|
|
|
23
55
|
* `docs/**\/*.md` still matches `docs/a.md`.
|
|
24
56
|
*/
|
|
25
57
|
export declare function scopeIncludeToSubtree(include: readonly string[], relDir: string): string[];
|
|
58
|
+
/**
|
|
59
|
+
* The env var that selects the crawler behind every resources-crawling verb —
|
|
60
|
+
* `vat resources scan`/`validate`, `vat rag index`, the pipeline oracles, and
|
|
61
|
+
* (via {@link withResourcePopulationSource}) the packaging verbs
|
|
62
|
+
* `vat skills build`/`validate` and `vat claude plugin build`, which is what
|
|
63
|
+
* puts `vat build` on the lane at all.
|
|
64
|
+
*
|
|
65
|
+
* An environment switch rather than a config field, for the same reason
|
|
66
|
+
* `VAT_INVENTORY_CRAWL` is one: it selects which INSTRUMENT runs, not what
|
|
67
|
+
* the project means, and it has to be reachable from the lab, which spawns the
|
|
68
|
+
* binary and controls its environment. A config field would put the A and B arms
|
|
69
|
+
* inside the subject's own tree, where a measurement edits the thing it measures.
|
|
70
|
+
*/
|
|
71
|
+
export declare const RESOURCES_CRAWL_ENV = "VAT_RESOURCES_CRAWL";
|
|
72
|
+
/** {@link RESOURCES_CRAWL_ENV}'s value that selects the projection lane. */
|
|
73
|
+
export declare const RESOURCES_CRAWL_PROJECTION = "projection";
|
|
74
|
+
/**
|
|
75
|
+
* {@link RESOURCES_CRAWL_ENV}'s value that opts BACK to the incumbent walk.
|
|
76
|
+
*
|
|
77
|
+
* The projection lane is the default now, so this is the escape hatch rather
|
|
78
|
+
* than the selector. Any other value — including the historical `projection` —
|
|
79
|
+
* leaves the projection lane selected, so existing scripts and lab arms that
|
|
80
|
+
* name it explicitly keep working and keep MEANING the same thing.
|
|
81
|
+
*/
|
|
82
|
+
export declare const RESOURCES_CRAWL_WALK = "walk";
|
|
83
|
+
/**
|
|
84
|
+
* Whether this process should source the resources population from a projection.
|
|
85
|
+
*
|
|
86
|
+
* **Defaults to the projection lane.** Both lanes now enumerate
|
|
87
|
+
* `tracked ∪ (untracked ∧ ¬ignored)` — `ResourceRegistry.crawl` passes
|
|
88
|
+
* `includeUntracked: true` per `docs/architecture/resource-scanning-and-caching.md`
|
|
89
|
+
* §2.1 — so the population question they answer is the same one.
|
|
90
|
+
*
|
|
91
|
+
* ⚠️⚠️ **ONE DISAGREEMENT SURVIVES, AND IT DROPS FINDINGS: SYMLINKS.** The
|
|
92
|
+
* `filesystem` extent crawls with `followSymlinks: false` and records no link's
|
|
93
|
+
* own path, and `GitCrawlSource` skips mode `120000` deliberately to match it —
|
|
94
|
+
* so BOTH projection extents omit a committed symlink that the incumbent walk
|
|
95
|
+
* includes. For an out-of-tree target those bytes have no other path into the
|
|
96
|
+
* population, which means **a broken symlink the walk reports as
|
|
97
|
+
* `LINK_BROKEN_FILE` is not reported on this lane.** That is a real loss, it is
|
|
98
|
+
* known, and it is the cost this default was accepted at; closing it is its own
|
|
99
|
+
* change (teaching an extent to admit `120000` entries as their own paths).
|
|
100
|
+
* {@link RESOURCES_CRAWL_WALK} is the one-value escape hatch meanwhile.
|
|
101
|
+
*
|
|
102
|
+
* Read from the environment at each call rather than memoized at module load:
|
|
103
|
+
* `vitest.setup.js` deletes every `VAT_*` variable before any test module loads,
|
|
104
|
+
* so a module-level binding would make the switch unobservable to every test
|
|
105
|
+
* that sets it.
|
|
106
|
+
*
|
|
107
|
+
* @returns `true` when the projection lane is selected
|
|
108
|
+
*/
|
|
109
|
+
export declare function resourcesProjectionCrawlSelected(): boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Run one command's work with the projection-backed population source it
|
|
112
|
+
* selected, and the store that answers it open for the whole call.
|
|
113
|
+
*
|
|
114
|
+
* The lane-selection seam for every command that builds its OWN registry rather
|
|
115
|
+
* than going through {@link loadResourcesWithConfig} — `vat skills build` and
|
|
116
|
+
* `vat claude plugin build` (via `createProjectRegistry`) and
|
|
117
|
+
* `vat skills validate` (via its shared-context registry). Those three are what
|
|
118
|
+
* put `vat build` on the projection lane at all: before this, that verb reached
|
|
119
|
+
* a projection store on NO phase.
|
|
120
|
+
*
|
|
121
|
+
* Same selector, same store, same ignore oracle as the resource loader —
|
|
122
|
+
* deliberately, and not merely for tidiness. A second way to decide the lane is
|
|
123
|
+
* a second thing to keep in step, and a packaging lane that answered the
|
|
124
|
+
* selector differently from the validation lane would make a whole-run A/B
|
|
125
|
+
* uninterpretable: half the phases on one population, half on the other, and
|
|
126
|
+
* nothing in the output saying so.
|
|
127
|
+
*
|
|
128
|
+
* ⚠️ The tracker is **not optional dressing**. With no `GitTracker` every
|
|
129
|
+
* realization row reads `gitignored: false`, so the population would admit the
|
|
130
|
+
* ignored half of a git tree — generated markdown, caches, vendored corpora —
|
|
131
|
+
* and the packaging run would start bundling and validating files the project
|
|
132
|
+
* told git to forget. One is built here when the caller has none, rooted at the
|
|
133
|
+
* same root the population is enumerated from.
|
|
134
|
+
*
|
|
135
|
+
* @param options - Where the corpus is, and what to reuse
|
|
136
|
+
* @param options.root - The absolute corpus root, which is also the basis every
|
|
137
|
+
* enumerated path is returned against
|
|
138
|
+
* @param options.gitTracker - An already-initialized tracker to reuse. Omit to
|
|
139
|
+
* have one built, which costs a `git ls-files` spawn — and only when the lane
|
|
140
|
+
* is actually selected
|
|
141
|
+
* @param options.observeExtentSource - Called with the enumerator that ran, once
|
|
142
|
+
* per enumerated root. 🪤 NOT a cache-hit marker: on a hit no enumerator runs
|
|
143
|
+
* and this still reports the one this process selected
|
|
144
|
+
* @param work - Given the source, or `undefined` when the walk stays selected
|
|
145
|
+
* @returns Whatever `work` returned
|
|
146
|
+
*/
|
|
147
|
+
export declare function withResourcePopulationSource<T>(options: {
|
|
148
|
+
root: string;
|
|
149
|
+
gitTracker?: GitTracker | undefined;
|
|
150
|
+
observeExtentSource?: ((kind: CrawlSourceKind) => void) | undefined;
|
|
151
|
+
}, work: (populationSource: ResourcePopulationSource | undefined) => Promise<T>): Promise<T>;
|
|
26
152
|
/**
|
|
27
153
|
* Load resources from a path with config support
|
|
28
154
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-loader.d.ts","sourceRoot":"","sources":["../../src/utils/resource-loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,
|
|
1
|
+
{"version":3,"file":"resource-loader.d.ts","sourceRoot":"","sources":["../../src/utils/resource-loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAIL,gBAAgB,EAEhB,KAAK,eAAe,EAEpB,KAAK,aAAa,EAClB,KAAK,wBAAwB,EAE9B,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,UAAU,EAAmB,MAAM,+BAA+B,CAAC;AAG5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAI1C;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,YAAY,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,aAAa,GAAG,SAAS,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC;IACnC;;;;;;;;;OASG;IACH,IAAI,EAAE,iBAAiB,CAAC;IACxB;;;;;;;;;;;;OAYG;IACH,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;CACtC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAK1F;AA+CD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AAEzD,4EAA4E;AAC5E,eAAO,MAAM,0BAA0B,eAAe,CAAC;AAEvD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,gCAAgC,IAAI,OAAO,CAE1D;AAsED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,4BAA4B,CAAC,CAAC,EAClD,OAAO,EAAE;IACP,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACpC,mBAAmB,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACrE,EACD,IAAI,EAAE,CAAC,gBAAgB,EAAE,wBAAwB,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GAC3E,OAAO,CAAC,CAAC,CAAC,CAoBZ;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,CAAC,CA8G7B"}
|