@klhapp/skillmux 1.9.3 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,21 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.10.0](https://github.com/klhq/skillmux/compare/v1.9.3...v1.10.0) (2026-09-01)
9
+
10
+
11
+ ### Added
12
+
13
+ * **cli:** reject remote context for local-only commands ([#165](https://github.com/klhq/skillmux/issues/165)) ([934bb18](https://github.com/klhq/skillmux/commit/934bb18bce2b86dca8ac44cd8431ebdb53d12024))
14
+ * **cli:** remote admin parity for report, audit prune, eval, doctor ([#166](https://github.com/klhq/skillmux/issues/166)) ([615a396](https://github.com/klhq/skillmux/commit/615a396212d5c0e2df07712bf588c25e91e99773))
15
+
16
+
17
+ ### Changed
18
+
19
+ * **cli:** align context terminology ([#163](https://github.com/klhq/skillmux/issues/163)) ([e942075](https://github.com/klhq/skillmux/commit/e94207584d10e16c17d6d2f5ca9c23bd8aa7846f))
20
+ * **server:** consolidate redactedErrorLog into logger.ts ([#169](https://github.com/klhq/skillmux/issues/169)) ([f7f29e4](https://github.com/klhq/skillmux/commit/f7f29e4ed6ea516e243d47d677e7ede207e47937))
21
+ * split db.ts, extract cli.ts commands, consolidate flag parsing ([#168](https://github.com/klhq/skillmux/issues/168)) ([28a798a](https://github.com/klhq/skillmux/commit/28a798abacfb830aff7a6510c6e892bb28009e5c))
22
+
8
23
  ## [1.9.3](https://github.com/klhq/skillmux/compare/v1.9.2...v1.9.3) (2026-08-31)
9
24
 
10
25
 
package/README.md CHANGED
@@ -189,7 +189,7 @@ for all three setups.
189
189
  | Surface | User | Purpose | CLI required |
190
190
  | --- | --- | --- | --- |
191
191
  | `/mcp` | AI clients | Resolve and fetch skills | No |
192
- | `/admin/v1/*` | Operators | Inspect or update server configuration | Yes, when using named CLI contexts |
192
+ | `/admin/v1/*` (and `GET /stats`) | Operators | Inspect/update config, stats, audit prune, evaluation, and remote diagnostics | Yes, when using named CLI contexts |
193
193
 
194
194
  MCP clients authenticate only to `/mcp` with the MCP bearer token. Operators
195
195
  use a separate administrative bearer token for `/admin/v1/*`; neither token
package/docs/README.md CHANGED
@@ -34,7 +34,7 @@ to customize behavior; see [Configuration](configuration.md#machine-config-boots
34
34
  | Surface | User | Purpose | CLI required |
35
35
  | --- | --- | --- | --- |
36
36
  | `/mcp` | AI clients | Resolve and fetch skills | No |
37
- | `/admin/v1/*` | Operators | Inspect or update server configuration | Yes, when using named CLI contexts |
37
+ | `/admin/v1/*` (and `GET /stats`) | Operators | Inspect/update config, stats, audit prune, evaluation, and remote diagnostics | Yes, when using named CLI contexts |
38
38
 
39
39
  The MCP and administrative surfaces use separate bearer tokens; possession of
40
40
  one does not grant access to the other. A named CLI context administers the
package/docs/cli.md CHANGED
@@ -14,6 +14,9 @@ In this guide, **local target** means the filesystem and process selected by
14
14
  the built-in CLI context. It does not describe local inference. A local target
15
15
  can call remote inference endpoints.
16
16
 
17
+ Run `skillmux --help` for the full command list, or `skillmux <command> --help`
18
+ (`-h` also works) for one command's usage and flags.
19
+
17
20
  For task-oriented workflows, start with [Getting started](getting-started.md)
18
21
  or [Managing skills](skill-management.md).
19
22
 
@@ -25,13 +28,31 @@ CLI. Its `skillmux --help` surface is intentionally limited to `serve`,
25
28
  `skill which`, and read-only `config` inspection (`show`, `get`, `validate`,
26
29
  `diff`, and `status`). Run `init`, `install`, pinning, `sync`, project or
27
30
  target management, model downloads, contexts, and bare `eval` (vault ranking
28
- evaluation, which needs local embeddings and the vault) on the host.
31
+ evaluation, which needs an embeddings client and the vault) on the host.
29
32
 
30
33
  When the image rejects one of those commands, it exits with code 2. JSON mode
31
34
  uses `CONTAINER_COMMAND_UNSUPPORTED` and includes `rejected_command`,
32
35
  `recommended_host_command`, and a deployment-guide URL. See [the container
33
36
  command contract](deployment.md#container-command-contract) for examples.
34
37
 
38
+ ## Local-only commands and remote context rejection
39
+
40
+ Commands that operate directly on the local vault checkout reject `--context` and
41
+ `--server` (or a configured remote default context) with exit code 2. These 14
42
+ commands are local-only: `install`, `update`, `outdated`, `sync`, `core`,
43
+ `project`, `target`, `local-vault`, `index`, `models`, `scan`, `init`, `serve`,
44
+ and `skill which`.
45
+
46
+ When one of these commands receives a remote context, it exits with code 2.
47
+ Human-mode output reports:
48
+
49
+ ```
50
+ error: `<command>` operates on the local vault only; --context/--server isn't supported here
51
+ ```
52
+
53
+ In `--json` mode, the CLI emits a structured error envelope with `code: "REMOTE_CONTEXT_UNSUPPORTED"`
54
+ and includes `rejected_command`.
55
+
35
56
  ## Global options and target resolution
36
57
 
37
58
  Every target-aware command resolves its execution target deterministically in this order:
@@ -52,6 +73,27 @@ Every target-aware command resolves its execution target deterministically in th
52
73
  | `--allow-insecure` | Allow plaintext HTTP admin requests to non-loopback addresses |
53
74
  | `--verbose` | Output diagnostic stack traces for errors |
54
75
 
76
+ `--context`/`--server` selects which Skillmux admin instance a command talks to
77
+ over `/admin/v1/*` — nothing more. That's one of three independent axes in this
78
+ system:
79
+
80
+ 1. Which vault checkout backs Core/Project pinning — always a local Git checkout
81
+ on the machine running the CLI. `install`/`update`/`sync`/`core`/`project`/
82
+ `target`/`local-vault`/`index`/`models`/`scan`/`init`/`outdated`/`serve`/
83
+ `skill which` operate on it. There is no remote version of this — Git and the
84
+ deployment process move content between checkouts, not Skillmux's own
85
+ commands.
86
+ 2. Which MCP server an agent queries for Routed retrieval — the agent's own MCP
87
+ client configuration (local stdio vs. remote HTTP), entirely separate from
88
+ `skillmux context`.
89
+ 3. Which Skillmux instance the CLI's admin commands act on — `config`, `report`,
90
+ `audit prune`, `eval`/`eval promote`, and `doctor`. This is the only thing
91
+ `--context`/`--server` actually selects.
92
+
93
+ The commands above belong entirely to axis 1. `--context` has no meaning for
94
+ them — not "risky," a category error, the same way `--context prod` wouldn't
95
+ mean anything on `ls`.
96
+
55
97
  ---
56
98
 
57
99
  ## Context management (`skillmux context`)
@@ -286,6 +328,11 @@ Show which root actually serves a skill_id, and every root it shadows:
286
328
  skillmux skill which csv-formatter
287
329
  ```
288
330
 
331
+ > [!NOTE]
332
+ > `skill which` performs local vault-checkout shadow resolution (which root
333
+ > wins on the local filesystem) and is unrelated to semantic MCP skill routing
334
+ > (`resolve_skill`/`fetch_skill`).
335
+
289
336
  ---
290
337
 
291
338
  ## Observability and evaluation (`skillmux report`, `audit`, `eval`)
@@ -352,10 +399,10 @@ The HTTP server has two separate surfaces:
352
399
  | Surface | User | Purpose | CLI required |
353
400
  | --- | --- | --- | --- |
354
401
  | `/mcp` | AI clients | Resolve and fetch skills | No |
355
- | `/admin/v1/*` | Operators | Inspect or update server configuration | Yes, when using named CLI contexts |
402
+ | `/admin/v1/*` (and `GET /stats`) | Operators | Inspect/update config, stats, audit prune, evaluation, and remote diagnostics | Yes, when using named CLI contexts |
356
403
 
357
404
  The MCP bearer token applies only to `/mcp`. The administrative bearer token
358
- below applies only to `/admin/v1/*`; neither credential grants access to the
405
+ below applies only to `/admin/v1/*` (and `GET /stats`); neither credential grants access to the
359
406
  other surface. Named contexts use the latter to administer the deployed server,
360
407
  not any remote client skill directory.
361
408
 
@@ -374,6 +421,30 @@ Requests require `Authorization: Bearer <token>` where `<token>` matches the env
374
421
  | `/admin/v1/capabilities` | `GET` | Advertises server features (`config_read`, `config_write`, `persistence`) |
375
422
  | `/admin/v1/config` | `GET` | Returns desired/effective config, sources, and `ETag` revision hash |
376
423
  | `/admin/v1/config` | `PATCH` | Applies dotted-key updates; requires matching `If-Match` header |
424
+ | `/admin/v1/audit/prune` | `POST` | Prunes audit/fetch/admin_audit rows older than cutoff; requires `confirm: true` unless `dry_run: true` |
425
+ | `/admin/v1/eval` | `POST` | Runs vault ranking evaluation server-side and returns `EvalReport` |
426
+ | `/admin/v1/eval/promote` | `POST` | Returns candidate promoted eval cases from the server's audit database; requires `since` |
427
+
428
+ ### Remote command capabilities
429
+
430
+ Named CLI contexts (`--context <name>` or `--server <url>`) support the following administrative and diagnostic operations:
431
+
432
+ - `skillmux config` (`show`, `get`, `set`, `validate`, `diff`, `status`): inspect and modify remote server configuration over `/admin/v1/*`.
433
+ - `skillmux report --since <window>`: fetches usage and retrieval metrics from the remote server's `GET /stats`.
434
+ - `skillmux audit prune [--older-than <window>] [--dry-run] [--yes]`: prunes or dry-run counts audit records on the remote server via `POST /admin/v1/audit/prune`.
435
+ - `skillmux eval`: executes ranking evaluation against the remote server's in-process runtime via `POST /admin/v1/eval`.
436
+ - `skillmux eval promote --since <window>`: fetches promotable candidates from the remote server's audit db via `POST /admin/v1/eval/promote`, dedups against the local fixture file, and writes locally.
437
+ - `skillmux doctor`: inspects remote server status, readiness, deployment runtime, and capabilities without requiring local vault access.
438
+
439
+ ---
440
+
441
+ ## Color
442
+
443
+ Interactive terminal output uses a small amount of color: red for error
444
+ messages, yellow for `warning:` lines, green/red for `doctor`'s `ok`/`fail`
445
+ checks, and bold table headers. Color is automatic — it's on only when
446
+ stdout is a TTY and off whenever `NO_COLOR` is set or output is piped or
447
+ redirected. `--json` output never includes color codes.
377
448
 
378
449
  ---
379
450
 
package/docs/concepts.md CHANGED
@@ -94,7 +94,7 @@ An HTTP server has two separate surfaces:
94
94
  | Surface | User | Purpose | CLI required |
95
95
  | --- | --- | --- | --- |
96
96
  | `/mcp` | AI clients | Resolve and fetch skills | No |
97
- | `/admin/v1/*` | Operators | Inspect or update server configuration | Yes, when using named CLI contexts |
97
+ | `/admin/v1/*` (and `GET /stats`) | Operators | Inspect/update config, stats, audit prune, evaluation, and remote diagnostics | Yes, when using named CLI contexts |
98
98
 
99
99
  MCP authentication protects `/mcp`; administrative authentication protects
100
100
  `/admin/v1/*`. Their bearer tokens are distinct and do not grant access across
@@ -184,7 +184,7 @@ The HTTP server provides separate MCP and administrative surfaces:
184
184
  | Surface | User | Purpose | CLI required |
185
185
  | --- | --- | --- | --- |
186
186
  | `/mcp` | AI clients | Resolve and fetch skills | No |
187
- | `/admin/v1/*` | Operators | Inspect or update server configuration | Yes, when using named CLI contexts |
187
+ | `/admin/v1/*` (and `GET /stats`) | Operators | Inspect/update config, stats, audit prune, evaluation, and remote diagnostics | Yes, when using named CLI contexts |
188
188
 
189
189
  ```toml
190
190
  [server]
@@ -180,7 +180,7 @@ The shared server exposes two distinct HTTP surfaces:
180
180
  | Surface | User | Purpose | CLI required |
181
181
  | --- | --- | --- | --- |
182
182
  | `/mcp` | AI clients | Resolve and fetch skills | No |
183
- | `/admin/v1/*` | Operators | Inspect or update server configuration | Yes, when using named CLI contexts |
183
+ | `/admin/v1/*` (and `GET /stats`) | Operators | Inspect/update config, stats, audit prune, evaluation, and remote diagnostics | Yes, when using named CLI contexts |
184
184
 
185
185
  Configure and distribute separate bearer tokens. An MCP token authenticates an
186
186
  AI client to `/mcp` only; an administrative token authenticates an operator to
@@ -280,6 +280,9 @@ skillmux context add prod \
280
280
  --token-env SKILLMUX_PROD_ADMIN_TOKEN
281
281
  skillmux context use prod
282
282
  skillmux config status
283
+ skillmux --context prod report --since 7d
284
+ skillmux --context prod audit prune --dry-run
285
+ skillmux --context prod doctor
283
286
  ```
284
287
 
285
288
  The context stores the token environment variable name. Export its value in
@@ -291,11 +294,12 @@ Enable the admin API and use a separate admin token in server configuration.
291
294
  Read [CLI reference](cli.md#administrative-http-api-adminv1) for routes and
292
295
  [Configuration](configuration.md#http-server) for reload behavior.
293
296
 
294
- Named contexts administer the deployed server configuration only. They do not
295
- install, pin, synchronize, or otherwise manage skill directories on remote
296
- client machines. Run those filesystem-management commands through Skillmux CLI
297
- on the machine that owns the directories. The full and slim server images read
298
- their mounted vault checkout and do not manage host agent directories.
297
+ Named contexts administer the deployed server only configuration, stats,
298
+ audit prune, evaluation, and remote diagnostics. They do not install, pin,
299
+ synchronize, or otherwise manage skill directories on remote client machines.
300
+ Run those filesystem-management commands through Skillmux CLI on the machine
301
+ that owns the directories. The full and slim server images read their mounted
302
+ vault checkout and do not manage host agent directories.
299
303
 
300
304
  ## Persistent data and backups
301
305
 
@@ -261,7 +261,7 @@ The server keeps its two HTTP surfaces separate:
261
261
  | Surface | User | Purpose | CLI required |
262
262
  | --- | --- | --- | --- |
263
263
  | `/mcp` | AI clients | Resolve and fetch skills | No |
264
- | `/admin/v1/*` | Operators | Inspect or update server configuration | Yes, when using named CLI contexts |
264
+ | `/admin/v1/*` (and `GET /stats`) | Operators | Inspect/update config, stats, audit prune, evaluation, and remote diagnostics | Yes, when using named CLI contexts |
265
265
 
266
266
  Configure separate MCP and administrative bearer tokens; one never grants
267
267
  access to the other. Named CLI contexts can administer this deployed server,
@@ -267,6 +267,12 @@ true` with a token, or it refuses to start. `--stats-port` is rejected
267
267
  alongside `--transport http`, since that transport already serves `/stats` on
268
268
  `--port`.
269
269
 
270
+ `--context`/`--server` work the same way for `audit prune`, `eval`, `eval
271
+ promote`, and `doctor` — each hits the matching `/admin/v1/*` route on the
272
+ named deployment instead of the local vault and audit db. See [CLI
273
+ reference](cli.md#administrative-http-api-adminv1) for the full remote
274
+ command surface and route table.
275
+
270
276
  ## Target ownership and recovery
271
277
 
272
278
  `skillmux target remove <name> --yes` removes the manifest record and preserves
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klhapp/skillmux",
3
- "version": "1.9.3",
3
+ "version": "1.10.0",
4
4
  "description": "Skill management and retrieval for AI agents: sync native skills across clients and route the long tail over MCP",
5
5
  "type": "module",
6
6
  "private": false,
package/src/adapters.ts CHANGED
@@ -14,8 +14,11 @@ import {
14
14
  type ConfigStatusResponse,
15
15
  type SetConfigResult,
16
16
  } from "./config-service";
17
- import type { ResolvedTarget } from "./context";
17
+ import type { ResolvedContext } from "./context";
18
18
  import type { Clients, Config } from "./types";
19
+ import { getStats, parseSince, type StatsResponse } from "./stats";
20
+ import { countPrunable, openAudit, pruneAuditBefore, type PruneResult } from "./db";
21
+ import { buildPromotedCases, evalVault, queryPromotableFetches, type EvalCase, type EvalReport } from "./eval";
19
22
 
20
23
  export interface Capabilities {
21
24
  config_read: boolean;
@@ -31,6 +34,21 @@ export interface TargetAdapterOptions {
31
34
  clients?: Clients;
32
35
  }
33
36
 
37
+ export interface AuditPruneOptions {
38
+ older_than?: string;
39
+ dry_run?: boolean;
40
+ confirm?: boolean;
41
+ }
42
+
43
+ export interface AuditPruneResult extends PruneResult {
44
+ dry_run: boolean;
45
+ cutoff: string | null;
46
+ }
47
+
48
+ /**
49
+ * Target adapter: `local` = this CLI process has the Skillmux runtime (vault, index,
50
+ * audit db, embeddings/reranker clients) in-process; `remote` = thin network client to an external process.
51
+ */
34
52
  export interface TargetAdapter {
35
53
  getCapabilities(): Promise<Capabilities>;
36
54
  getConfigShow(): Promise<{ effective: Config; sources: Record<string, string>; active_revision: string }>;
@@ -39,6 +57,11 @@ export interface TargetAdapter {
39
57
  configDiff(): Promise<{ diff: Record<string, { prior: unknown; resulting: unknown }> }>;
40
58
  configSet(key: string, rawValStr: string, opts?: { dryRun?: boolean }): Promise<SetConfigResult>;
41
59
  configStatus(): Promise<ConfigStatusResponse>;
60
+ getStats(since: string): Promise<StatsResponse>;
61
+ auditPrune(opts?: AuditPruneOptions): Promise<AuditPruneResult>;
62
+ auditCount(older_than?: string): Promise<AuditPruneResult>;
63
+ evalRun(): Promise<EvalReport>;
64
+ evalPromote(since: string): Promise<EvalCase[]>;
42
65
  }
43
66
 
44
67
  export function isLoopbackHost(hostname: string): boolean {
@@ -116,6 +139,75 @@ export class LocalAdapter implements TargetAdapter {
116
139
  async configStatus(): Promise<ConfigStatusResponse> {
117
140
  return getLocalConfigStatus(this.configPath);
118
141
  }
142
+
143
+ async getStats(since: string): Promise<StatsResponse> {
144
+ const config = await loadConfig(this.configPath);
145
+ const stateDir = expandHome(config.state_dir);
146
+ const db = openAudit(stateDir);
147
+ try {
148
+ return getStats(db, since);
149
+ } finally {
150
+ db.close();
151
+ }
152
+ }
153
+
154
+ async auditPrune(opts?: AuditPruneOptions): Promise<AuditPruneResult> {
155
+ const config = await loadConfig(this.configPath);
156
+ const stateDir = expandHome(config.state_dir);
157
+ const olderThan = opts?.older_than;
158
+ const dryRun = opts?.dry_run ?? false;
159
+
160
+ let cutoff: Date;
161
+ if (olderThan) {
162
+ cutoff = parseSince(olderThan);
163
+ } else {
164
+ const retentionDays = config.audit?.retention_days ?? 90;
165
+ if (retentionDays <= 0) {
166
+ return {
167
+ audit_deleted: 0,
168
+ fetch_deleted: 0,
169
+ admin_audit_deleted: 0,
170
+ dry_run: dryRun,
171
+ cutoff: null,
172
+ };
173
+ }
174
+ cutoff = new Date(Date.now() - retentionDays * 86_400_000);
175
+ }
176
+ const cutoffIso = cutoff.toISOString();
177
+
178
+ const db = openAudit(stateDir);
179
+ try {
180
+ if (dryRun) {
181
+ const counts = countPrunable(db, cutoffIso);
182
+ return { ...counts, dry_run: true, cutoff: cutoffIso };
183
+ }
184
+ const counts = pruneAuditBefore(db, cutoffIso);
185
+ return { ...counts, dry_run: false, cutoff: cutoffIso };
186
+ } finally {
187
+ db.close();
188
+ }
189
+ }
190
+
191
+ async auditCount(older_than?: string): Promise<AuditPruneResult> {
192
+ return this.auditPrune({ older_than, dry_run: true });
193
+ }
194
+
195
+ async evalRun(): Promise<EvalReport> {
196
+ return evalVault();
197
+ }
198
+
199
+ async evalPromote(since: string): Promise<EvalCase[]> {
200
+ const sinceDate = parseSince(since);
201
+ const sinceIso = sinceDate.toISOString();
202
+ const config = await loadConfig(this.configPath);
203
+ const stateDir = expandHome(config.state_dir);
204
+ const db = openAudit(stateDir);
205
+ try {
206
+ return buildPromotedCases(queryPromotableFetches(db, sinceIso));
207
+ } finally {
208
+ db.close();
209
+ }
210
+ }
119
211
  }
120
212
 
121
213
  export class RemoteAdapter implements TargetAdapter {
@@ -281,9 +373,63 @@ export class RemoteAdapter implements TargetAdapter {
281
373
  }
282
374
  return data.runtime;
283
375
  }
376
+
377
+ async getStats(since: string): Promise<StatsResponse> {
378
+ const searchParams = new URLSearchParams({ since });
379
+ const { status, data } = await this.fetchJson(`/stats?${searchParams.toString()}`);
380
+ if (status !== 200) {
381
+ throw new Error(`Remote stats fetch failed (${status}): ${typeof data === "object" ? data?.message || data?.error || JSON.stringify(data) : data}`);
382
+ }
383
+ return data as StatsResponse;
384
+ }
385
+
386
+ async auditPrune(opts?: AuditPruneOptions): Promise<AuditPruneResult> {
387
+ const { status, data } = await this.fetchJson("/admin/v1/audit/prune", {
388
+ method: "POST",
389
+ headers: { "Content-Type": "application/json" },
390
+ body: JSON.stringify({
391
+ ...(opts?.older_than ? { older_than: opts.older_than } : {}),
392
+ ...(opts?.dry_run !== undefined ? { dry_run: opts.dry_run } : {}),
393
+ ...(opts?.confirm !== undefined ? { confirm: opts.confirm } : {}),
394
+ }),
395
+ });
396
+ if (status !== 200) {
397
+ const message = typeof data === "object" ? data?.message || data?.error || JSON.stringify(data) : data;
398
+ throw new Error(`Remote audit prune failed (${status}): ${message}`);
399
+ }
400
+ return data as AuditPruneResult;
401
+ }
402
+
403
+ async auditCount(older_than?: string): Promise<AuditPruneResult> {
404
+ return this.auditPrune({ older_than, dry_run: true });
405
+ }
406
+
407
+ async evalRun(): Promise<EvalReport> {
408
+ const { status, data } = await this.fetchJson("/admin/v1/eval", {
409
+ method: "POST",
410
+ });
411
+ if (status !== 200) {
412
+ const message = typeof data === "object" ? data?.message || data?.error || JSON.stringify(data) : data;
413
+ throw new Error(`Remote eval failed (${status}): ${message}`);
414
+ }
415
+ return data as EvalReport;
416
+ }
417
+
418
+ async evalPromote(since: string): Promise<EvalCase[]> {
419
+ const { status, data } = await this.fetchJson("/admin/v1/eval/promote", {
420
+ method: "POST",
421
+ headers: { "Content-Type": "application/json" },
422
+ body: JSON.stringify({ since }),
423
+ });
424
+ if (status !== 200) {
425
+ const message = typeof data === "object" ? data?.message || data?.error || JSON.stringify(data) : data;
426
+ throw new Error(`Remote eval promote failed (${status}): ${message}`);
427
+ }
428
+ return data.candidates as EvalCase[];
429
+ }
284
430
  }
285
431
 
286
- export function createTargetAdapter(target: ResolvedTarget, opts?: TargetAdapterOptions): TargetAdapter {
432
+ export function createTargetAdapter(target: ResolvedContext, opts?: TargetAdapterOptions): TargetAdapter {
287
433
  if (target.type === "local") {
288
434
  return new LocalAdapter(opts);
289
435
  } else {