@karmaniverous/jeeves-meta 0.20.0-0 → 0.20.0-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/cli/jeeves-meta/index.js +154 -67
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ jeeves-meta service install --config /path/to/jeeves-meta/config.json
|
|
|
56
56
|
|
|
57
57
|
| Method | Path | Description |
|
|
58
58
|
| --- | --- | --- |
|
|
59
|
-
| GET | `/status` | Service health, queue state, dependency checks, phase-state summary |
|
|
59
|
+
| GET | `/status` | Service health, queue state, dependency checks, phase-state summary. Meta counts come from the last meta list (at most 60 s old, refreshed in the background), so the check never waits on a corpus walk. |
|
|
60
60
|
| GET | `/metas` | List metas with summary stats and per-meta projection. Response includes `phaseState` and `owedPhase` per meta. |
|
|
61
61
|
| GET | `/metas/:path` | Full detail for a single meta, with optional archive history. Response includes `phaseState`, `owedPhase` and `crossRefs`. |
|
|
62
62
|
| GET | `/preview` | Dry-run: preview inputs for next synthesis |
|
|
@@ -71,7 +71,7 @@ jeeves-meta service install --config /path/to/jeeves-meta/config.json
|
|
|
71
71
|
| PATCH | `/metas/:path` | Update user-settable reserved properties (`_steer`, `_emphasis`, `_depth`, `_crossRefs`, `_disabled`) |
|
|
72
72
|
| GET | `/openapi.json` | The OpenAPI 3.1 document of every route above |
|
|
73
73
|
|
|
74
|
-
Every route is defined in `META_CATALOG` (`@karmaniverous/jeeves-meta-core`) and validated against it: a malformed request is answered 400 `FST_ERR_VALIDATION`.
|
|
74
|
+
Every route is defined in `META_CATALOG` (`@karmaniverous/jeeves-meta-core`) and validated against it: a malformed request is answered 400 `FST_ERR_VALIDATION`. While the service starts, `GET /status` answers 200 with `serviceState: "starting"` (no meta counts until the first meta list loads), `/config`, `/config/apply` and `/openapi.json` are served, and every other route answers 503 `META_NOT_READY`. Use [`@karmaniverous/jeeves-meta-sdk`](../sdk/README.md) for a typed client.
|
|
75
75
|
|
|
76
76
|
### Errors
|
|
77
77
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { sleepAsync, computeInsiderKey, fetchWithTimeout, DEFAULT_PORTS, createConfigQueryHandler, createStatusHandler, getBindAddress, getServiceUrl, jeevesComponentDescriptorSchema, createConfigApplyHandler, createServiceCli } from '@karmaniverous/jeeves';
|
|
2
|
+
import { sleepAsync, computeInsiderKey, fetchWithTimeout, DEFAULT_PORTS, createConfigQueryHandler, createStatusHandler, getBindAddress, rejectWindowsDrivePath, init, WORKSPACE_CONFIG_DEFAULTS, resolveConfigValue, loadWorkspaceConfig, getServiceUrl, jeevesComponentDescriptorSchema, createConfigApplyHandler, createServiceCli } from '@karmaniverous/jeeves';
|
|
3
3
|
import { normalizePath, metaConfigSchema, META_ERROR_STATUS, updateBodySchema, META_COMPONENT, META_CATALOG, META_OPENAPI_DOCUMENT } from '@karmaniverous/jeeves-meta-core';
|
|
4
4
|
import fs, { unlinkSync, writeFileSync, existsSync, readFileSync, statSync, mkdirSync, readdirSync, watchFile } from 'node:fs';
|
|
5
5
|
import path, { join, dirname, relative, posix, sep, resolve } from 'node:path';
|
|
@@ -657,7 +657,8 @@ function getDeltaFiles(generatedAt, scopeFiles) {
|
|
|
657
657
|
}
|
|
658
658
|
|
|
659
659
|
/**
|
|
660
|
-
* In-memory cache for listMetas results with TTL
|
|
660
|
+
* In-memory cache for listMetas results with TTL, concurrent refresh guard
|
|
661
|
+
* and a non-blocking read (`peek`) for health checks.
|
|
661
662
|
*
|
|
662
663
|
* @module cache
|
|
663
664
|
*/
|
|
@@ -677,6 +678,22 @@ class MetaCache {
|
|
|
677
678
|
}
|
|
678
679
|
return this.refresh(config, watcher);
|
|
679
680
|
}
|
|
681
|
+
/**
|
|
682
|
+
* The cached result without waiting on a stale one: when it has expired,
|
|
683
|
+
* return it anyway and refresh in the background. Only the first load,
|
|
684
|
+
* with nothing cached yet, is awaited. For callers that must answer fast
|
|
685
|
+
* (`GET /status`), where a 60 s-old list is good enough.
|
|
686
|
+
*/
|
|
687
|
+
async peek(config, watcher) {
|
|
688
|
+
if (!this.result)
|
|
689
|
+
return this.refresh(config, watcher);
|
|
690
|
+
if (Date.now() - this.updatedAt >= TTL_MS) {
|
|
691
|
+
// A failed background refresh keeps the old result; the next caller
|
|
692
|
+
// retries it.
|
|
693
|
+
this.refresh(config, watcher).catch(() => undefined);
|
|
694
|
+
}
|
|
695
|
+
return this.result;
|
|
696
|
+
}
|
|
680
697
|
/** Force-expire the cache so next get() triggers a refresh. */
|
|
681
698
|
invalidate() {
|
|
682
699
|
this.updatedAt = 0;
|
|
@@ -31854,6 +31871,8 @@ async function checkWatcher(url) {
|
|
|
31854
31871
|
function deriveServiceState(deps) {
|
|
31855
31872
|
if (deps.shuttingDown)
|
|
31856
31873
|
return 'stopping';
|
|
31874
|
+
if (!deps.ready)
|
|
31875
|
+
return 'starting';
|
|
31857
31876
|
if (deps.queue.currentPhase)
|
|
31858
31877
|
return 'synthesizing';
|
|
31859
31878
|
if (deps.queue.depth > 0)
|
|
@@ -31888,41 +31907,47 @@ function createStatusHandlers(deps) {
|
|
|
31888
31907
|
};
|
|
31889
31908
|
let nextPhase = null;
|
|
31890
31909
|
let metaCounts = null;
|
|
31891
|
-
|
|
31892
|
-
|
|
31893
|
-
|
|
31894
|
-
|
|
31895
|
-
|
|
31896
|
-
|
|
31897
|
-
|
|
31910
|
+
// While starting, the first meta list is still loading: report the
|
|
31911
|
+
// state, dependencies and stats without it (Decision 199).
|
|
31912
|
+
if (deps.ready) {
|
|
31913
|
+
try {
|
|
31914
|
+
// Never wait on a refresh of the whole corpus: a health check answers
|
|
31915
|
+
// from the last list, refreshed in the background.
|
|
31916
|
+
const metaResult = await cache.peek(config, watcher);
|
|
31917
|
+
// Count raw phase states (before retry) for display
|
|
31918
|
+
for (const entry of metaResult.entries) {
|
|
31919
|
+
const ps = derivePhaseState(entry.meta);
|
|
31920
|
+
for (const phase of ['architect', 'builder', 'critic']) {
|
|
31921
|
+
phaseStateSummary[phase][ps[phase]]++;
|
|
31922
|
+
}
|
|
31898
31923
|
}
|
|
31899
|
-
|
|
31900
|
-
|
|
31901
|
-
|
|
31902
|
-
|
|
31903
|
-
|
|
31904
|
-
|
|
31905
|
-
|
|
31906
|
-
|
|
31907
|
-
|
|
31908
|
-
|
|
31909
|
-
|
|
31924
|
+
// Build candidates (with auto-retry) for scheduling
|
|
31925
|
+
const candidates = buildPhaseCandidates(metaResult.entries, config.architectEvery);
|
|
31926
|
+
// Find next phase candidate
|
|
31927
|
+
const winner = selectPhaseCandidate(candidates, config.depthWeight);
|
|
31928
|
+
if (winner) {
|
|
31929
|
+
nextPhase = {
|
|
31930
|
+
path: winner.node.metaPath,
|
|
31931
|
+
phase: winner.owedPhase,
|
|
31932
|
+
band: winner.band,
|
|
31933
|
+
staleness: finiteOrNull(winner.effectiveStaleness),
|
|
31934
|
+
};
|
|
31935
|
+
}
|
|
31936
|
+
// Meta counts summary
|
|
31937
|
+
const summary = computeSummary(metaResult.entries, config.depthWeight);
|
|
31938
|
+
metaCounts = {
|
|
31939
|
+
total: summary.total,
|
|
31940
|
+
enabled: summary.total - summary.disabled,
|
|
31941
|
+
disabled: summary.disabled,
|
|
31942
|
+
neverSynthesized: summary.neverSynthesized,
|
|
31943
|
+
stale: summary.stale,
|
|
31944
|
+
errors: summary.errors,
|
|
31945
|
+
locked: summary.locked,
|
|
31910
31946
|
};
|
|
31911
31947
|
}
|
|
31912
|
-
|
|
31913
|
-
|
|
31914
|
-
|
|
31915
|
-
total: summary.total,
|
|
31916
|
-
enabled: summary.total - summary.disabled,
|
|
31917
|
-
disabled: summary.disabled,
|
|
31918
|
-
neverSynthesized: summary.neverSynthesized,
|
|
31919
|
-
stale: summary.stale,
|
|
31920
|
-
errors: summary.errors,
|
|
31921
|
-
locked: summary.locked,
|
|
31922
|
-
};
|
|
31923
|
-
}
|
|
31924
|
-
catch {
|
|
31925
|
-
// Watcher unreachable — phase summary unavailable
|
|
31948
|
+
catch {
|
|
31949
|
+
// Watcher unreachable — phase summary unavailable
|
|
31950
|
+
}
|
|
31926
31951
|
}
|
|
31927
31952
|
return {
|
|
31928
31953
|
serviceState: deriveServiceState(deps),
|
|
@@ -32169,7 +32194,12 @@ function registerRoutes(app, deps) {
|
|
|
32169
32194
|
* @module server
|
|
32170
32195
|
*/
|
|
32171
32196
|
/** Routes served while the service is starting (matched route URLs). */
|
|
32172
|
-
const UNGATED_ROUTES = new Set([
|
|
32197
|
+
const UNGATED_ROUTES = new Set([
|
|
32198
|
+
'/status',
|
|
32199
|
+
'/config',
|
|
32200
|
+
'/config/apply',
|
|
32201
|
+
'/openapi.json',
|
|
32202
|
+
]);
|
|
32173
32203
|
/**
|
|
32174
32204
|
* Create and configure the Fastify server.
|
|
32175
32205
|
*
|
|
@@ -32400,9 +32430,10 @@ async function startService(config, configPath, configApply) {
|
|
|
32400
32430
|
queue.onEnqueue(() => {
|
|
32401
32431
|
void queue.processQueue(synthesizeFn);
|
|
32402
32432
|
});
|
|
32403
|
-
// Startup: clean stale locks (gap #16)
|
|
32433
|
+
// Startup: clean stale locks (gap #16). Through the cache, so the first
|
|
32434
|
+
// GET /status after start-up answers without a second walk.
|
|
32404
32435
|
try {
|
|
32405
|
-
const metaResult = await
|
|
32436
|
+
const metaResult = await cache.get(config, watcher);
|
|
32406
32437
|
const metaPaths = metaResult.entries.map((e) => e.node.metaPath);
|
|
32407
32438
|
cleanupStaleLocks(metaPaths, logger);
|
|
32408
32439
|
}
|
|
@@ -32742,11 +32773,61 @@ function createMetaClient(options) {
|
|
|
32742
32773
|
return Object.fromEntries(methods);
|
|
32743
32774
|
}
|
|
32744
32775
|
|
|
32776
|
+
/**
|
|
32777
|
+
* Workspace and config root for the custom CLI commands, so they can ask
|
|
32778
|
+
* jeeves where meta runs (`getServiceUrl('meta')`, which reads the core
|
|
32779
|
+
* config under the config root).
|
|
32780
|
+
*
|
|
32781
|
+
* Each root follows jeeves' shared precedence: the flag, then
|
|
32782
|
+
* `JEEVES_WORKSPACE` / `JEEVES_CONFIG_ROOT`, then `core.*` in the
|
|
32783
|
+
* workspace's `jeeves.config.json`, then the defaults (`.`, `./config`).
|
|
32784
|
+
* jeeves does not export its own resolver, so this composes the exported
|
|
32785
|
+
* `loadWorkspaceConfig()` and `resolveConfigValue()` as jeeves-runner does;
|
|
32786
|
+
* karmaniverous/jeeves#169 moves this into jeeves.
|
|
32787
|
+
*
|
|
32788
|
+
* @module cliRoots
|
|
32789
|
+
*/
|
|
32790
|
+
/**
|
|
32791
|
+
* Resolve the workspace and config root by flag, env,
|
|
32792
|
+
* `jeeves.config.json`, then default.
|
|
32793
|
+
*
|
|
32794
|
+
* @param opts - The parsed flags.
|
|
32795
|
+
* @param env - Environment to read (default `process.env`).
|
|
32796
|
+
* @returns Both roots, as given (not yet made absolute).
|
|
32797
|
+
*/
|
|
32798
|
+
function resolveRoots(opts, env = process.env) {
|
|
32799
|
+
const defaults = WORKSPACE_CONFIG_DEFAULTS.core;
|
|
32800
|
+
const workspaceSeed = resolveConfigValue(opts.workspace, env['JEEVES_WORKSPACE'], undefined, defaults.workspace).value;
|
|
32801
|
+
const file = loadWorkspaceConfig(workspaceSeed);
|
|
32802
|
+
return {
|
|
32803
|
+
workspace: resolveConfigValue(opts.workspace, env['JEEVES_WORKSPACE'], file?.core?.workspace, defaults.workspace).value,
|
|
32804
|
+
configRoot: resolveConfigValue(opts.configRoot, env['JEEVES_CONFIG_ROOT'], file?.core?.configRoot, defaults.configRoot).value,
|
|
32805
|
+
};
|
|
32806
|
+
}
|
|
32807
|
+
/**
|
|
32808
|
+
* Resolve both roots and initialise jeeves with them.
|
|
32809
|
+
*
|
|
32810
|
+
* @param opts - The parsed flags.
|
|
32811
|
+
* @param env - Environment to read (default `process.env`).
|
|
32812
|
+
*/
|
|
32813
|
+
function initRoots(opts, env = process.env) {
|
|
32814
|
+
const roots = resolveRoots(opts, env);
|
|
32815
|
+
// Check the raw values: on Linux, resolve('j:/x') hides the drive letter.
|
|
32816
|
+
rejectWindowsDrivePath('configRoot', roots.configRoot);
|
|
32817
|
+
rejectWindowsDrivePath('workspacePath', roots.workspace);
|
|
32818
|
+
init({
|
|
32819
|
+
workspacePath: resolve(roots.workspace),
|
|
32820
|
+
configRoot: resolve(roots.configRoot),
|
|
32821
|
+
});
|
|
32822
|
+
}
|
|
32823
|
+
|
|
32745
32824
|
/**
|
|
32746
32825
|
* Custom CLI commands for the jeeves-meta service, built on the SDK
|
|
32747
32826
|
* (`@karmaniverous/jeeves-meta-sdk`, Decision 187). Each command calls one
|
|
32748
32827
|
* catalog entry and prints the response as JSON; a failure prints one
|
|
32749
|
-
* error line to stderr and sets exit code 1.
|
|
32828
|
+
* error line to stderr and sets exit code 1. The service URL comes from
|
|
32829
|
+
* jeeves (`getServiceUrl('meta')`) after the workspace and config root are
|
|
32830
|
+
* resolved (`cliRoots`); `--port` overrides its port.
|
|
32750
32831
|
*
|
|
32751
32832
|
* Registered via `descriptor.customCliCommands` and added to the
|
|
32752
32833
|
* standard service CLI produced by `createServiceCli`.
|
|
@@ -32754,15 +32835,17 @@ function createMetaClient(options) {
|
|
|
32754
32835
|
* @module customCliCommands
|
|
32755
32836
|
*/
|
|
32756
32837
|
/**
|
|
32757
|
-
* The service's base URL
|
|
32838
|
+
* The service's base URL: jeeves' URL for meta, with `--port` when it is
|
|
32839
|
+
* not the default.
|
|
32758
32840
|
*
|
|
32759
|
-
* @param
|
|
32841
|
+
* @param opts - The command's options.
|
|
32760
32842
|
* @returns The base URL.
|
|
32761
32843
|
*/
|
|
32762
|
-
function serviceBaseUrl(
|
|
32844
|
+
function serviceBaseUrl(opts) {
|
|
32845
|
+
initRoots(opts);
|
|
32763
32846
|
const url = new URL(getServiceUrl('meta'));
|
|
32764
|
-
if (port !== DEFAULT_PORT_STR)
|
|
32765
|
-
url.port = port;
|
|
32847
|
+
if (opts.port !== DEFAULT_PORT_STR)
|
|
32848
|
+
url.port = opts.port;
|
|
32766
32849
|
return url.origin;
|
|
32767
32850
|
}
|
|
32768
32851
|
/**
|
|
@@ -32781,12 +32864,12 @@ function errorLine(error) {
|
|
|
32781
32864
|
* Run one command: call the service, print the result as JSON, or print
|
|
32782
32865
|
* the error line and set exit code 1.
|
|
32783
32866
|
*
|
|
32784
|
-
* @param
|
|
32867
|
+
* @param opts - The command's options.
|
|
32785
32868
|
* @param call - The SDK call.
|
|
32786
32869
|
*/
|
|
32787
|
-
async function runCommand(
|
|
32870
|
+
async function runCommand(opts, call) {
|
|
32788
32871
|
try {
|
|
32789
|
-
const data = await call(createMetaClient({ baseUrl: serviceBaseUrl(
|
|
32872
|
+
const data = await call(createMetaClient({ baseUrl: serviceBaseUrl(opts) }));
|
|
32790
32873
|
console.log(JSON.stringify(data, null, 2));
|
|
32791
32874
|
}
|
|
32792
32875
|
catch (error) {
|
|
@@ -32794,27 +32877,38 @@ async function runCommand(port, call) {
|
|
|
32794
32877
|
process.exitCode = 1;
|
|
32795
32878
|
}
|
|
32796
32879
|
}
|
|
32880
|
+
/**
|
|
32881
|
+
* Add the options every service command takes: `--port`, and the roots
|
|
32882
|
+
* jeeves resolves the service URL from (no defaults, so the environment and
|
|
32883
|
+
* `jeeves.config.json` apply when a flag is absent).
|
|
32884
|
+
*
|
|
32885
|
+
* @param cmd - The command.
|
|
32886
|
+
* @returns It.
|
|
32887
|
+
*/
|
|
32888
|
+
function withServiceOptions(cmd) {
|
|
32889
|
+
return cmd
|
|
32890
|
+
.option('-p, --port <port>', 'Service port', DEFAULT_PORT_STR)
|
|
32891
|
+
.option('-w, --workspace <path>', 'Workspace root path')
|
|
32892
|
+
.option('--config-root <path>', 'Platform config root path');
|
|
32893
|
+
}
|
|
32797
32894
|
/**
|
|
32798
32895
|
* Register all custom meta commands on the parent program.
|
|
32799
32896
|
*
|
|
32800
32897
|
* @param program - The service CLI.
|
|
32801
32898
|
*/
|
|
32802
32899
|
function registerCustomCliCommands(program) {
|
|
32803
|
-
const command = (spec, description) => program
|
|
32804
|
-
|
|
32805
|
-
|
|
32806
|
-
.option('-p, --port <port>', 'Service port', DEFAULT_PORT_STR);
|
|
32807
|
-
command('list', 'List all discovered meta entities').action((opts) => runCommand(opts.port, (meta) => meta.listMetas()));
|
|
32808
|
-
command('detail <path>', 'Show full detail for a single meta entity').action((path, opts) => runCommand(opts.port, (meta) => meta.metaDetail({ path })));
|
|
32900
|
+
const command = (spec, description) => withServiceOptions(program.command(spec).description(description));
|
|
32901
|
+
command('list', 'List all discovered meta entities').action((opts) => runCommand(opts, (meta) => meta.listMetas()));
|
|
32902
|
+
command('detail <path>', 'Show full detail for a single meta entity').action((path, opts) => runCommand(opts, (meta) => meta.metaDetail({ path })));
|
|
32809
32903
|
command('preview', 'Dry-run: preview inputs for next synthesis cycle')
|
|
32810
32904
|
.option('--path <path>', 'Specific meta path to preview')
|
|
32811
|
-
.action((opts) => runCommand(opts
|
|
32905
|
+
.action((opts) => runCommand(opts, (meta) => meta.preview(opts.path ? { path: opts.path } : {})));
|
|
32812
32906
|
command('synthesize', 'Trigger synthesis (enqueues work)')
|
|
32813
32907
|
.option('--path <path>', 'Specific meta path to synthesize')
|
|
32814
|
-
.action((opts) => runCommand(opts
|
|
32815
|
-
command('seed <path>', 'Create .meta/ directory + meta.json for a path').action((path, opts) => runCommand(opts
|
|
32816
|
-
command('unlock <path>', 'Remove .lock file from a meta entity').action((path, opts) => runCommand(opts
|
|
32817
|
-
command('abort', 'Abort the current synthesis in progress').action((opts) => runCommand(opts
|
|
32908
|
+
.action((opts) => runCommand(opts, (meta) => meta.synthesize(opts.path ? { path: opts.path } : {})));
|
|
32909
|
+
command('seed <path>', 'Create .meta/ directory + meta.json for a path').action((path, opts) => runCommand(opts, (meta) => meta.seed({ path })));
|
|
32910
|
+
command('unlock <path>', 'Remove .lock file from a meta entity').action((path, opts) => runCommand(opts, (meta) => meta.unlock({ path })));
|
|
32911
|
+
command('abort', 'Abort the current synthesis in progress').action((opts) => runCommand(opts, (meta) => meta.abort()));
|
|
32818
32912
|
command('prune', 'Prune old archive snapshots beyond maxArchive').action(() => {
|
|
32819
32913
|
// The service has no prune route yet (jeeves-meta#69); 0.19.0 called a
|
|
32820
32914
|
// missing route and failed with HTTP 404.
|
|
@@ -32824,16 +32918,9 @@ function registerCustomCliCommands(program) {
|
|
|
32824
32918
|
const queue = program
|
|
32825
32919
|
.command('queue')
|
|
32826
32920
|
.description('Queue management commands');
|
|
32827
|
-
queue
|
|
32828
|
-
|
|
32829
|
-
|
|
32830
|
-
.option('-p, --port <port>', 'Service port', DEFAULT_PORT_STR)
|
|
32831
|
-
.action((opts) => runCommand(opts.port, (meta) => meta.queue()));
|
|
32832
|
-
queue
|
|
32833
|
-
.command('clear')
|
|
32834
|
-
.description('Remove all pending items from the queue')
|
|
32835
|
-
.option('-p, --port <port>', 'Service port', DEFAULT_PORT_STR)
|
|
32836
|
-
.action((opts) => runCommand(opts.port, (meta) => meta.queueClear()));
|
|
32921
|
+
const queueCommand = (name, description) => withServiceOptions(queue.command(name).description(description));
|
|
32922
|
+
queueCommand('list', 'Show current queue state').action((opts) => runCommand(opts, (meta) => meta.queue()));
|
|
32923
|
+
queueCommand('clear', 'Remove all pending items from the queue').action((opts) => runCommand(opts, (meta) => meta.queueClear()));
|
|
32837
32924
|
}
|
|
32838
32925
|
|
|
32839
32926
|
/**
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@karmaniverous/jeeves": "0.11.0",
|
|
11
|
-
"@karmaniverous/jeeves-meta-core": "^0.4.0-
|
|
11
|
+
"@karmaniverous/jeeves-meta-core": "^0.4.0-1",
|
|
12
12
|
"@karmaniverous/jeeves-meta-sdk": "^0.0.0 || ^0.1.0-0",
|
|
13
13
|
"@karmaniverous/jeeves-watcher-sdk": "^0.4.1",
|
|
14
14
|
"commander": "^15",
|
|
@@ -112,5 +112,5 @@
|
|
|
112
112
|
"wire:record": "vitest run --config vitest.wire-record.config.ts"
|
|
113
113
|
},
|
|
114
114
|
"type": "module",
|
|
115
|
-
"version": "0.20.0-
|
|
115
|
+
"version": "0.20.0-2"
|
|
116
116
|
}
|