@shield-agent/kya 0.32.7 → 0.32.9

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.
Files changed (79) hide show
  1. package/.cursor-plugin/plugin.json +1 -1
  2. package/.mcp.json +1 -1
  3. package/README.md +59 -10
  4. package/amp/settings.example.json +1 -1
  5. package/claude/claude_desktop_config.example.json +1 -1
  6. package/cline/cline_mcp_settings.example.json +1 -1
  7. package/copilot/mcp-config.example.json +1 -1
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +89 -38
  10. package/dist/cli.js.map +1 -1
  11. package/dist/client.d.ts +2 -0
  12. package/dist/client.d.ts.map +1 -1
  13. package/dist/client.js +1 -1
  14. package/dist/client.js.map +1 -1
  15. package/dist/commands/eval-tool.js +1 -1
  16. package/dist/commands/eval-tool.js.map +1 -1
  17. package/dist/commands/hook.d.ts.map +1 -1
  18. package/dist/commands/hook.js +21 -6
  19. package/dist/commands/hook.js.map +1 -1
  20. package/dist/commands/login.d.ts +34 -0
  21. package/dist/commands/login.d.ts.map +1 -0
  22. package/dist/commands/login.js +74 -0
  23. package/dist/commands/login.js.map +1 -0
  24. package/dist/config.d.ts +2 -0
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js.map +1 -1
  27. package/dist/cta.d.ts +23 -0
  28. package/dist/cta.d.ts.map +1 -0
  29. package/dist/cta.js +86 -0
  30. package/dist/cta.js.map +1 -0
  31. package/dist/fs-atomic.d.ts +6 -0
  32. package/dist/fs-atomic.d.ts.map +1 -1
  33. package/dist/fs-atomic.js +14 -3
  34. package/dist/fs-atomic.js.map +1 -1
  35. package/dist/login/credentials.d.ts +17 -0
  36. package/dist/login/credentials.d.ts.map +1 -0
  37. package/dist/login/credentials.js +64 -0
  38. package/dist/login/credentials.js.map +1 -0
  39. package/dist/login/device-flow.d.ts +44 -0
  40. package/dist/login/device-flow.d.ts.map +1 -0
  41. package/dist/login/device-flow.js +205 -0
  42. package/dist/login/device-flow.js.map +1 -0
  43. package/dist/mcp/protocol.js +1 -1
  44. package/dist/mcp/protocol.js.map +1 -1
  45. package/dist/never-list-input.d.ts +56 -0
  46. package/dist/never-list-input.d.ts.map +1 -0
  47. package/dist/never-list-input.js +1222 -0
  48. package/dist/never-list-input.js.map +1 -0
  49. package/dist/offline-evaluate.d.ts +17 -5
  50. package/dist/offline-evaluate.d.ts.map +1 -1
  51. package/dist/offline-evaluate.js +67 -9
  52. package/dist/offline-evaluate.js.map +1 -1
  53. package/dist/otel.d.ts +8 -2
  54. package/dist/otel.d.ts.map +1 -1
  55. package/dist/otel.js +32 -16
  56. package/dist/otel.js.map +1 -1
  57. package/dist/receipt/embeddings.d.ts +5 -1
  58. package/dist/receipt/embeddings.d.ts.map +1 -1
  59. package/dist/receipt/embeddings.js +71 -8
  60. package/dist/receipt/embeddings.js.map +1 -1
  61. package/dist/trail.d.ts +4 -0
  62. package/dist/trail.d.ts.map +1 -1
  63. package/dist/trail.js +14 -0
  64. package/dist/trail.js.map +1 -1
  65. package/droid/README.md +1 -1
  66. package/droid/mcp.example.json +1 -1
  67. package/gemini/settings.example.json +1 -1
  68. package/grok/README.md +1 -1
  69. package/kilo/kilo.example.json +1 -1
  70. package/kimi/mcp.example.json +1 -1
  71. package/kiro/mcp.example.json +1 -1
  72. package/manifest.json +1 -1
  73. package/mastracode/mcp.example.json +1 -1
  74. package/mcp.json +1 -1
  75. package/openai/codex.config.example.toml +1 -1
  76. package/opencode/opencode.example.json +1 -1
  77. package/package.json +1 -4
  78. package/qwen/settings.example.json +1 -1
  79. package/server.json +2 -2
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shield-kya",
3
- "version": "0.32.7",
3
+ "version": "0.32.9",
4
4
  "description": "Audit trail and traceability for AI agents. See what every coding agent did and check each tool call against policy.",
5
5
  "author": {
6
6
  "name": "Shield Agent",
package/.mcp.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "shield-kya": {
4
4
  "command": "npx",
5
- "args": ["--no-install", "@shield-agent/kya@0.32.7", "serve-mcp", "--stdio"],
5
+ "args": ["--no-install", "@shield-agent/kya@0.32.9", "serve-mcp", "--stdio"],
6
6
  "env": {
7
7
  "KYA_BASE_URL": "https://shield-agent.com",
8
8
  "KYA_API_KEY": "${KYA_API_KEY}",
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@shield-agent/kya.svg?logo=npm&label=npm)](https://www.npmjs.com/package/@shield-agent/kya)
4
4
  [![npm downloads/week](https://img.shields.io/npm/dw/@shield-agent/kya.svg?logo=npm&label=downloads%2Fweek)](https://www.npmjs.com/package/@shield-agent/kya)
5
- [![npm downloads](https://img.shields.io/npm/dt/@shield-agent/kya.svg?logo=npm&label=total%20downloads)](https://www.npmjs.com/package/@shield-agent/kya)
5
+ [![npm downloads, 18 months](https://img.shields.io/npm/d18m/@shield-agent/kya.svg?logo=npm&label=downloads%2C%2018%20months)](https://www.npmjs.com/package/@shield-agent/kya)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
7
7
  [![Install](https://img.shields.io/badge/install-shield--agent.com%2Finstall-0A0A0A)](https://shield-agent.com/install)
8
8
  [![X](https://img.shields.io/badge/X-%40coscosmico-000000?logo=x&logoColor=white)](https://x.com/coscosmico)
@@ -50,7 +50,7 @@ More ways to install (same package; npm stays the reference path):
50
50
 
51
51
  ```bash
52
52
  # Homebrew. Homebrew 7 may ask you to trust a third-party tap: run `brew tap The-Pixel-Boys/tap` first.
53
- # The formula installs about 270MB because of the optional semantic-search runtime.
53
+ # The formula does not install the semantic-search runtime. Search stays lexical until you opt in (see Natural-language search).
54
54
  brew install The-Pixel-Boys/tap/shield-kya
55
55
 
56
56
  # Scoop (not yet verified on Windows)
@@ -122,7 +122,7 @@ This repo is also a Claude Code plugin marketplace named `shield-kya` with one p
122
122
  /plugin install kya@shield-kya
123
123
  ```
124
124
 
125
- The plugin is **advisory and fails open**: it records every tool call on the local record (`~/.kya/trail.jsonl`) and blocks only the small never-list. If kya is missing, crashes or times out, the tool call proceeds and nothing is recorded. It evaluates offline, so it has no Hold and no approval. Hosted enforcement is the MCP gate path.
125
+ The plugin is **advisory and fails open**: it records every tool call on the local record (`~/.kya/trail.jsonl`) and blocks only the small never-list. If kya is missing, crashes or times out, the tool call proceeds and nothing is recorded. It evaluates offline, so it has no Hold and no approval. Hosted enforcement is the MCP policy path against a hosted workspace.
126
126
 
127
127
  Team rollout: commit `extraKnownMarketplaces` (the `shield-kya` GitHub source) and `enabledPlugins` (`"kya@shield-kya": true`) to the repository's `.claude/settings.json`, or force it org-wide with managed settings. Details and limits: [docs/hosts/claude-plugin.md](docs/hosts/claude-plugin.md).
128
128
 
@@ -196,7 +196,7 @@ Install hub: [https://shield-agent.com/install](https://shield-agent.com/install
196
196
 
197
197
  ## Activity record (global)
198
198
 
199
- One record (trail) for all projects: `~/.kya/trail.jsonl` (`KYA_HOME` overrides `~`). `kya receipt --open` from any directory shows activity from every project. Each event carries its project folder name. The report adds a Projects rollup once two or more projects appear, and shows the project on each feed entry. Older per-project `<project>/.kya/trail.jsonl` files are still read and merged; no migration. The record is capped at 1 MB (tail-read: oldest events drop away) and shared across all projects.
199
+ One record (trail) for all projects: `~/.kya/trail.jsonl` (`KYA_HOME` overrides `~`). `kya receipt --open` from any directory shows activity from every project. Each event carries its project folder name. The report adds a Projects rollup once two or more projects appear, and shows the project on each feed entry. Older per-project `<project>/.kya/trail.jsonl` files are still read and merged; no migration. Reports read only the last 1 MB of the record (oldest events drop out of the view); it is shared across all projects.
200
200
 
201
201
  The report itself is a dashboard. A hero row on top shows the live **Certify** result, the decision mix, an activity sparkline, and showback (cost per agent). Tabbed sections sit below: **Overview** (analytics, sessions, reasons), **Certify** (the full live requirement table: every requirement grouped by domain with status, evidence, and attestation), **Activity** (the filterable event feed), **System** (wired hosts, sandboxes, ORR). Everything is one standalone offline HTML page. The live view adds a single external link: "Star on GitHub". The live daemon from `kya start` re-renders it on every event.
202
202
 
@@ -208,14 +208,37 @@ Sharing is a single attempt by design (storm-proof: no silent retries against th
208
208
 
209
209
  ### Natural-language search
210
210
 
211
- The **Activity** search box understands plain English. It runs a hybrid of BM25 over tool IDs, summaries, reason codes, decisions, projects, and MCP server labels, plus local MiniLM semantic reranking (shipped as an optional dependency; the report falls back to lexical-only if the model runtime is unavailable). A built-in concept glossary maps everyday words to the vocabulary events actually use, so `dangerous` finds rm/kill/delete/sudo calls, `blocked` finds denials, and `held` finds approval requests. You can also type things like `failed stripe transfers`, `files written by grok`, or `approval required production`. Stopwords and stemming are handled automatically, and the same search works across the global record.
211
+ The **Activity** search box understands plain English. It runs a hybrid of BM25 over tool IDs, summaries, reason codes, decisions, projects, and MCP server labels, plus local MiniLM semantic reranking, which is opt-in. The runtime is not part of the default install. Without it, search stays lexical (BM25) and the live report server writes one line to its log (for `kya start`, the background report daemon log) that names the install command. Install it once:
212
+
213
+ ```bash
214
+ # macOS and Linux (bash or zsh)
215
+ npm install --prefix "$HOME/.kya/semantic" @shield-agent/fastembed@3.0.0
216
+ ```
217
+
218
+ ```bat
219
+ :: Windows cmd
220
+ npm install --prefix "%USERPROFILE%\.kya\semantic" @shield-agent/fastembed@3.0.0
221
+ ```
222
+
223
+ ```powershell
224
+ # Windows PowerShell
225
+ npm install --prefix "$env:USERPROFILE\.kya\semantic" @shield-agent/fastembed@3.0.0
226
+ ```
227
+
228
+ If `KYA_HOME` is set, the prefix is `$KYA_HOME/.kya/semantic` (`%KYA_HOME%\.kya\semantic` on Windows). A built-in concept glossary maps everyday words to the vocabulary events actually use, so `dangerous` finds rm/kill/delete/sudo calls, `blocked` finds denials, and `held` finds approval requests. You can also type things like `failed stripe transfers`, `files written by grok`, or `approval required production`. Stopwords and stemming are handled automatically, and the same search works across the global record.
212
229
 
213
230
  - Offline or `KYA_OFFLINE=1` keeps search purely lexical (no model download).
214
- - By default the live server downloads `BAAI/bge-small-en-v1.5` once into `~/.kya/models` and caches event vectors in `~/.kya/search-index.json`.
231
+ - After you opt in, the live server downloads `BAAI/bge-small-en-v1.5` once into `~/.kya/models` and caches event vectors in `~/.kya/search-index.json`.
215
232
  - `KYA_SEARCH_SEMANTIC=off` disables the model while still keeping BM25.
216
233
 
217
234
  The hosted console uses the same hybrid search on the server side (Postgres full-text + optional OpenAI-compatible embeddings), so queries typed in either place behave the same way.
218
235
 
236
+ ## Upgrade notes
237
+
238
+ - Semantic search is no longer installed by default (about 230 MB less on disk). After upgrading, activity search is lexical (BM25) only until you run the install command in [Natural-language search](#natural-language-search).
239
+ - The CLI loads the OpenTelemetry SDK only when an OTLP endpoint is set. A start error is logged once to stderr; metrics stay off and the command continues.
240
+ - Hook verdicts and fail-open rules are unchanged.
241
+
219
242
  ## Dual plane
220
243
 
221
244
  ```
@@ -229,6 +252,22 @@ The hosted console uses the same hybrid search on the server side (Postgres full
229
252
 
230
253
  Tag sessions with `KYA_HOST=ide` or `KYA_HOST=runtime`. Same policy path either way.
231
254
 
255
+ ## Plans (hosted, plan tiers v2)
256
+
257
+ The rows below apply only when the hosted service turns plan tiers v2 on. Until then the hosted plans are Free, Starter, Pro and Scale.
258
+
259
+ The hosted console has these plans. The CLI works on every plan. Solo and the no-card trial appear only when the hosted service turns plan tiers on.
260
+
261
+ | Plan | Price | Seats | Trail history | Notes |
262
+ |---|---|---|---|---|
263
+ | Free | $0 | 2 | 30 days | Start here |
264
+ | Solo | $90 a year | 1 | 90 days | CSV evidence export. Yearly only |
265
+ | Team | $29 a month | 5 | 90 days | Formerly "Starter" |
266
+ | Pro | $149 a month | 25 | 90 days | Compliance report PDF, signed evidence bundles |
267
+ | Scale | $499 a month | Unlimited | 365 days | SSO and SCIM |
268
+
269
+ n8n and Zapier access is included in every paid plan. There is no add-on price.
270
+
232
271
  ## Environment
233
272
 
234
273
  | Variable | Required | Meaning |
@@ -247,6 +286,9 @@ Tag sessions with `KYA_HOST=ide` or `KYA_HOST=runtime`. Same policy path either
247
286
  | `KYA_SHARE_URL` | No | `kya receipt --share` collector base (default `https://shield-agent.com`) |
248
287
  | `KYA_TELEMETRY` | No | `0`/`off` forces anonymous usage stats off ([docs/telemetry.md](docs/telemetry.md)); they are off unless you opted in |
249
288
  | `DO_NOT_TRACK` | No | `1` forces anonymous usage stats off, same as `KYA_TELEMETRY=0` |
289
+ | `KYA_BASE_URL` | No | Hosted console for `kya login` (default `https://shield-agent.com`; https or loopback only) |
290
+ | `KYA_QUIET` | No | Any true value hides the one-line hosted calls to action (`kya certify`, `kya receipt`) |
291
+ | `KYA_CTA` | No | `0`/`off` turns off the one-line hosted calls to action ([docs/login.md](docs/login.md#calls-to-action-one-line)) |
250
292
 
251
293
  Gate mode can also be set in the project's `.kya/config.json`:
252
294
  `{"gateMode": "hold"}` or `{"gateMode": "offline"}` (exact values only;
@@ -270,7 +312,7 @@ MCP Registry entry: `server.json` plus package `mcpName` `io.github.The-Pixel-Bo
270
312
  "mcpServers": {
271
313
  "shield-kya": {
272
314
  "command": "npx",
273
- "args": ["--no-install", "@shield-agent/kya@0.32.7", "serve-mcp", "--stdio"],
315
+ "args": ["--no-install", "@shield-agent/kya@0.32.9", "serve-mcp", "--stdio"],
274
316
  "env": {
275
317
  "KYA_BASE_URL": "http://127.0.0.1:8090",
276
318
  "KYA_API_KEY": "${KYA_API_KEY}",
@@ -304,7 +346,9 @@ const run = governed({ toolId: "write_file", server: "filesystem", fn: myWrite }
304
346
  await run({ path: "out.txt", content: "hi" }); // throws KyaDeniedError on DENY
305
347
  ```
306
348
 
307
- Offline evaluate by default (no network, no hosted plane); an explicit config uses the live plane. `governA2aSend` gates in-process agent-to-agent sends. A fail-open Python shim with a LangChain middleware is in development and not yet released. Support matrix and recipes: `docs/sdk-integrations.md`; runnable scripts: `examples/sdk/`.
349
+ Offline evaluate by default (no network, no hosted plane); an explicit config uses the live plane. `governA2aSend` gates in-process agent-to-agent sends. The `shield-kya` Python package on PyPI ships framework hooks (LangChain, CrewAI, OpenAI Agents SDK and others), fail-open like `kya hook`. Support matrix and recipes: `docs/sdk-integrations.md`; runnable scripts: `examples/sdk/`.
350
+
351
+ Framework recipes (each one tested with a scripted model and the published CLI): [LangChain](docs/sdk-integrations.md#langchain-python) · [OpenAI Agents SDK](docs/sdk-integrations.md#openai-agents-sdk-python) · [CrewAI](docs/sdk-integrations.md#crewai-python) · [LlamaIndex](docs/sdk-integrations.md#llamaindex-python) · [Mastra](docs/sdk-integrations.md#mastra-typescript) · [Vercel AI SDK](docs/sdk-integrations.md#vercel-ai-sdk-typescript)
308
352
 
309
353
  ## Claude connector
310
354
 
@@ -312,7 +356,7 @@ Offline evaluate by default (no network, no hosted plane); an explicit config us
312
356
 
313
357
  ```bash
314
358
  # Prefer a preinstalled package (no registry auto-install):
315
- npx --no-install @shield-agent/kya@0.32.7 serve-mcp --stdio
359
+ npx --no-install @shield-agent/kya@0.32.9 serve-mcp --stdio
316
360
  # Or after npm i -g / local install:
317
361
  kya serve-mcp --stdio
318
362
  ```
@@ -323,7 +367,7 @@ Copy `claude/claude_desktop_config.example.json` into Claude Desktop MCP setting
323
367
 
324
368
  ## OpenAI (Codex / Responses)
325
369
 
326
- **Codex CLI plugin (hooks):** see [Codex plugin](#codex-plugin). **Codex CLI / IDE (MCP):** copy `openai/codex.config.example.toml` into `~/.codex/config.toml`. Local stdio uses `npx --no-install @shield-agent/kya@0.32.7 serve-mcp --stdio`. Hosted Codex uses `url = "https://shield-agent.com/mcp"` with `bearer_token_env_var = "KYA_API_KEY"`.
370
+ **Codex CLI plugin (hooks):** see [Codex plugin](#codex-plugin). **Codex CLI / IDE (MCP):** copy `openai/codex.config.example.toml` into `~/.codex/config.toml`. Local stdio uses `npx --no-install @shield-agent/kya@0.32.9 serve-mcp --stdio`. Hosted Codex uses `url = "https://shield-agent.com/mcp"` with `bearer_token_env_var = "KYA_API_KEY"`.
327
371
 
328
372
  **Responses API:** see `openai/responses-mcp.example.json` (`server_url` + `Authorization: Bearer <KYA_API_KEY>`).
329
373
 
@@ -496,6 +540,7 @@ pnpm build
496
540
  - [Top-20 MCP server support matrix (taxonomy + gate recipes)](docs/mcp-servers.md)
497
541
  - [OTLP metrics (OSS + hosted)](docs/otlp.md)
498
542
  - [Anonymous usage stats (opt-in): what is sent, controls, retention](docs/telemetry.md)
543
+ - [Link this machine to the hosted console (kya login)](docs/login.md)
499
544
  - [OWASP MCP governance map](docs/owasp-mcp-governance.md)
500
545
  - [Claude Code plugin](docs/hosts/claude-plugin.md) · [Copilot CLI plugin](docs/hosts/copilot.md#plugin) · [Codex plugin](docs/hosts/codex.md#codex-plugin) · [Gemini CLI extension](docs/hosts/gemini.md#gemini-cli-extension)
501
546
  - [Import the AGT audit log (CLI)](docs/import-agt.md) · [hosted](docs/import-agt-hosted.md)
@@ -508,6 +553,10 @@ pnpm build
508
553
  - [What is open source and what is hosted](docs/oss-vs-hosted.md)
509
554
  - See also `LIMITATIONS.md` in this repo
510
555
 
556
+ ## Hosted console (`kya login`, optional)
557
+
558
+ `kya login` links this machine to your hosted Shield KYA workspace. It uses the device code flow: the CLI shows a short code, you approve it in the hosted console, and the CLI saves a full-workspace API key with mode 0600 in `~/.kya/hosted-credentials.json`. `kya logout` deletes that file. It does not revoke the key on the server, so revoke it in the console too. The OSS CLI works without an account, and `kya certify` and the hook never read the saved key. Details, failure cases and the one-line calls to action: [docs/login.md](docs/login.md).
559
+
511
560
  ## Anonymous usage stats (opt-in, off by default)
512
561
 
513
562
  The first time you run `kya start`, `kya init` or `kya connect` in a terminal, KYA asks once whether to share anonymous usage stats (`[y/N]`, the default is No). Only an explicit `y` or `yes` turns it on. Nothing is sent in CI, in non-interactive runs, with `--json`, or when `DO_NOT_TRACK=1` / `KYA_TELEMETRY=0` is set. `kya hook` itself never touches the network; when you opted in it starts a detached helper at most once a day that sends one `ping`, so hook-only installs still count as active.
@@ -2,7 +2,7 @@
2
2
  "amp.mcpServers": {
3
3
  "shield-kya": {
4
4
  "command": "npx",
5
- "args": ["--no-install", "@shield-agent/kya@0.32.7", "serve-mcp", "--stdio"],
5
+ "args": ["--no-install", "@shield-agent/kya@0.32.9", "serve-mcp", "--stdio"],
6
6
  "env": {
7
7
  "KYA_BASE_URL": "https://shield-agent.com",
8
8
  "KYA_API_KEY": "${KYA_API_KEY}",
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "shield-kya": {
4
4
  "command": "npx",
5
- "args": ["--no-install", "@shield-agent/kya@0.32.7", "serve-mcp", "--stdio"],
5
+ "args": ["--no-install", "@shield-agent/kya@0.32.9", "serve-mcp", "--stdio"],
6
6
  "env": {
7
7
  "KYA_BASE_URL": "https://shield-agent.com",
8
8
  "KYA_API_KEY": "${KYA_API_KEY}",
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "shield-kya": {
4
4
  "command": "npx",
5
- "args": ["--no-install", "@shield-agent/kya@0.32.7", "serve-mcp", "--stdio"],
5
+ "args": ["--no-install", "@shield-agent/kya@0.32.9", "serve-mcp", "--stdio"],
6
6
  "env": {
7
7
  "KYA_BASE_URL": "https://shield-agent.com",
8
8
  "KYA_API_KEY": "${KYA_API_KEY}",
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "shield-kya": {
4
4
  "command": "npx",
5
- "args": ["--no-install", "@shield-agent/kya@0.32.7", "serve-mcp", "--stdio"],
5
+ "args": ["--no-install", "@shield-agent/kya@0.32.9", "serve-mcp", "--stdio"],
6
6
  "env": {
7
7
  "KYA_BASE_URL": "https://shield-agent.com",
8
8
  "KYA_API_KEY": "${KYA_API_KEY}",
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AA8PH,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,qGAAqG;IACrG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACtD;AAWD,oGAAoG;AACpG,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,+FAA+F;AAC/F,wBAAsB,MAAM,CAC1B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,GAAE,KAAiB,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAwvBjB"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AA2JH,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,qGAAqG;IACrG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACtD;AAWD,oGAAoG;AACpG,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,+FAA+F;AAC/F,wBAAsB,MAAM,CAC1B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,GAAE,KAAiB,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,MAAM,CAAC,CA20BjB"}
package/dist/cli.js CHANGED
@@ -12,43 +12,9 @@ import { fileURLToPath } from "node:url";
12
12
  import { resolveConfig } from "./config.js";
13
13
  import { KyaError } from "./errors.js";
14
14
  import { flagBool, flagString, parseArgs } from "./parse-args.js";
15
- import { initFromArgs } from "./commands/init.js";
16
- import { registerAgentInputFromArgs, runRegisterAgent, } from "./commands/register-agent.js";
17
- import { evalToolInputFromArgs, formatEvalHuman, runEvalTool, } from "./commands/eval-tool.js";
18
- import { runServeMcp, serveMcpOptionsFromArgs, } from "./commands/serve-mcp.js";
19
- import { orrRunOptionsFromArgs, runOrr, } from "./commands/orr.js";
20
- import { certifyOptionsFromArgs, formatCertifySummary, runCertify, } from "./commands/certify.js";
21
- import { runDash } from "./commands/dash.js";
22
- import { formatAgentTable, formatApprovalTable, formatSessionTable, requireId, runGetAgent, runGetPassport, runKillAgent, runListAgents, runListApprovals, runListSessions, runShrinkSession, shrinkToFromArgs, } from "./commands/ops.js";
23
- import { formatWrapHuman, runWrap, verdictExitCode, wrapExitCode, wrapInputFromArgs, } from "./commands/wrap.js";
24
- import { formatReceiptHuman, openPath, receiptInputFromArgs, runReceipt, runReceiptShare, } from "./commands/receipt.js";
25
- import { formatShareLine, SHARE_HOSTED_HINT } from "./receipt/share.js";
26
- import { formatStartHuman, runStart } from "./commands/start.js";
27
- import { connectableHosts, formatConnectHuman, runConnect, } from "./commands/connect.js";
28
- import { appendTrail, defaultSessionId } from "./trail.js";
29
- import { deriveTargetPath } from "./trail-summary.js";
30
- import { decideIdFromArgs, runDecide } from "./commands/decide.js";
31
- import { formatInvokeHuman, invokeInputFromArgs, runInvoke, } from "./commands/invoke.js";
32
- import { runSandboxCommand } from "./commands/sandbox.js";
33
- import { runHook } from "./commands/hook.js";
34
- import { crashDecision, guardStream, hostedCrashHandler, planeBudgetMs } from "./commands/hosted-hook.js";
35
- import { importOptionsFromArgs, runImport } from "./commands/import-traces.js";
36
- import { investigateOptionsFromArgs, runInvestigate, } from "./commands/investigate.js";
37
- import { discoverOptionsFromArgs, runDiscover, } from "./commands/discover.js";
38
- import { runNotifyFlush } from "./commands/notify-flush.js";
39
- import { formatStopHuman, runStop } from "./commands/stop.js";
40
- import { runReceiptServe } from "./commands/receipt-serve.js";
41
- import { maybePrintStarCta } from "./star-cta.js";
42
- import { formatGateDoctorHuman, gateMcpUrl, gateSubcommand, runGateDoctor, runGateInit, runGateRun, runGateSetup, runGateStop, } from "./commands/gate.js";
43
- import { triggerHostedSyncFromEnv } from "./gate/hosted-sync.js";
44
- import { runGateServe } from "./commands/gate-serve.js";
45
15
  import { ensureSupportedNode } from "./node-upgrade.js";
46
16
  import { CLI_VERSION } from "./version.js";
47
- import { checkForUpdate, formatUpdateBanner, shouldSkipUpdateCheck, } from "./update-check.js";
48
- import { runUpdate } from "./commands/update.js";
49
- import { formatTeamInitHuman, managedSettings, runTeamInit } from "./commands/team.js";
50
- import { maybePromptConsent, maybeSpawnHookPing, runTelemetryCommand, startSessionBeacon, } from "./telemetry.js";
51
- const HELP = `Shield KYA light CLI - Know Your Agent (provider-agnostic)
17
+ const helpFor = (hosts) => `Shield KYA light CLI - Know Your Agent (provider-agnostic)
52
18
 
53
19
  Usage:
54
20
  kya <command> [options]
@@ -63,7 +29,7 @@ Commands:
63
29
  (--all also stops orphaned report daemons from other
64
30
  directories or older installs)
65
31
  connect <host> Wire KYA MCP into a coding host config
66
- (${connectableHosts().join("|")}; --project for project scope, --force to overwrite)
32
+ (${hosts}; --project for project scope, --force to overwrite)
67
33
  --hooks also wires the host's PreToolUse hook (claude|grok|kimi)
68
34
  --hooks --hosted --plane-config <abs path> wires the hosted hook (claude, beta)
69
35
  --gate points the host at the local kya gateway (kya gate run)
@@ -74,6 +40,9 @@ Commands:
74
40
  merges a tag-pinned marketplace + enabledPlugins into the project's
75
41
  .claude/settings.json (--dry-run shows the change, writes nothing)
76
42
  team managed-settings Print the managed-settings JSON an admin deploys
43
+ login Link this machine to the hosted console (device code). Saves a 0600
44
+ key in ~/.kya/hosted-credentials.json. --base-url <url> or KYA_BASE_URL
45
+ logout Delete the saved hosted key (the key stays active until you revoke it)
77
46
  update Self-update to the latest npm version (kya start warns when
78
47
  a newer release exists; --no-update-check / KYA_UPDATE_CHECK=0 opts out)
79
48
  register-agent POST /api/v1/kya/agents (human mint; server applies allow/break-glass/approve)
@@ -183,6 +152,11 @@ Examples:
183
152
  Docs: https://shield-agent.com/install · docs/guides/kya-light-install.md
184
153
  Doctrine: sole PEP is Shield; DENY is hard; missing APPROVED ⇒ no irreversible side effect.
185
154
  `;
155
+ /** Help text. The host list comes from the connect registry, loaded on demand so `kya hook` stays light. */
156
+ async function helpText() {
157
+ const { connectableHosts } = await import("./commands/connect.js");
158
+ return helpFor(connectableHosts().join("|"));
159
+ }
186
160
  const defaultIo = {
187
161
  log: (m) => console.log(m),
188
162
  error: (m) => console.error(m),
@@ -210,7 +184,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
210
184
  parsed.command === "help" ||
211
185
  parsed.flags["help"] === true ||
212
186
  parsed.flags["h"] === true) {
213
- io.log(HELP);
187
+ io.log(await helpText());
214
188
  return 0;
215
189
  }
216
190
  try {
@@ -219,6 +193,10 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
219
193
  return nodeHandoff;
220
194
  switch (parsed.command) {
221
195
  case "start": {
196
+ const { formatStartHuman, runStart } = await import("./commands/start.js");
197
+ const { maybePrintStarCta } = await import("./star-cta.js");
198
+ const { checkForUpdate, formatUpdateBanner, shouldSkipUpdateCheck } = await import("./update-check.js");
199
+ const { maybePromptConsent } = await import("./telemetry.js");
222
200
  const config = resolveConfig({
223
201
  cwd,
224
202
  env,
@@ -249,10 +227,26 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
249
227
  }
250
228
  return 0;
251
229
  }
230
+ case "login": {
231
+ const { loginBrowserOpener, runLogin } = await import("./commands/login.js");
232
+ const { openPath } = await import("./commands/receipt.js");
233
+ return await runLogin({
234
+ io,
235
+ env,
236
+ baseUrl: flagString(parsed.flags, "base-url"),
237
+ open: loginBrowserOpener(env, io.isTty ?? Boolean(process.stdout.isTTY), (url) => openPath(url)),
238
+ });
239
+ }
240
+ case "logout": {
241
+ const { runLogout } = await import("./commands/login.js");
242
+ return runLogout({ io, env });
243
+ }
252
244
  case "update": {
245
+ const { runUpdate } = await import("./commands/update.js");
253
246
  return await runUpdate();
254
247
  }
255
248
  case "stop": {
249
+ const { formatStopHuman, runStop } = await import("./commands/stop.js");
256
250
  const result = await runStop(cwd, { all: flagBool(parsed.flags, "all") });
257
251
  if (parsed.flags["json"] === true || parsed.flags["json"] === "true") {
258
252
  io.log(JSON.stringify(result, null, 2));
@@ -263,6 +257,9 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
263
257
  return 0;
264
258
  }
265
259
  case "receipt-serve": {
260
+ const { receiptInputFromArgs } = await import("./commands/receipt.js");
261
+ const { runReceiptServe } = await import("./commands/receipt-serve.js");
262
+ const { startSessionBeacon } = await import("./telemetry.js");
266
263
  // Internal: detached child of `kya start` / `kya receipt --open`.
267
264
  const config = resolveConfig({
268
265
  cwd,
@@ -286,6 +283,9 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
286
283
  return 0;
287
284
  }
288
285
  case "connect": {
286
+ const { formatConnectHuman, runConnect } = await import("./commands/connect.js");
287
+ const { gateMcpUrl } = await import("./commands/gate.js");
288
+ const { maybePromptConsent } = await import("./telemetry.js");
289
289
  if (parsed.flags["plane-config"] !== undefined && !flagBool(parsed.flags, "hosted")) {
290
290
  // Without --hosted this would quietly wire the local, fail-open hook.
291
291
  io.error("--plane-config needs --hosted (kya connect claude --hooks --hosted --plane-config <absolute path>)");
@@ -293,6 +293,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
293
293
  }
294
294
  const host = parsed.positionals[0];
295
295
  if (!host) {
296
+ const { connectableHosts } = await import("./commands/connect.js");
296
297
  io.error(`Usage: kya connect <host> (${connectableHosts().join("|")})`);
297
298
  return 2;
298
299
  }
@@ -329,6 +330,8 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
329
330
  return 0;
330
331
  }
331
332
  case "gate": {
333
+ const { formatGateDoctorHuman, gateSubcommand, runGateDoctor, runGateInit, runGateRun, runGateSetup, runGateStop } = await import("./commands/gate.js");
334
+ const { triggerHostedSyncFromEnv } = await import("./gate/hosted-sync.js");
332
335
  const sub = gateSubcommand(parsed);
333
336
  if (sub === "init") {
334
337
  const result = runGateInit(env);
@@ -399,6 +402,8 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
399
402
  return 0;
400
403
  }
401
404
  case "gate-serve": {
405
+ const { runGateServe } = await import("./commands/gate-serve.js");
406
+ const { startSessionBeacon } = await import("./telemetry.js");
402
407
  // Internal: detached supervisor child of `kya gate run`.
403
408
  const beacon = startSessionBeacon("gateway", { env, cwd });
404
409
  try {
@@ -410,6 +415,8 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
410
415
  return 0;
411
416
  }
412
417
  case "init": {
418
+ const { initFromArgs } = await import("./commands/init.js");
419
+ const { maybePromptConsent } = await import("./telemetry.js");
413
420
  if (!flagBool(parsed.flags, "json"))
414
421
  await maybePromptConsent(io, env);
415
422
  const result = initFromArgs(parsed, cwd);
@@ -427,6 +434,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
427
434
  return 0;
428
435
  }
429
436
  case "team": {
437
+ const { formatTeamInitHuman, managedSettings, runTeamInit } = await import("./commands/team.js");
430
438
  const sub = parsed.positionals[0];
431
439
  if (sub === "managed-settings") {
432
440
  io.log(JSON.stringify(managedSettings(), null, 2));
@@ -444,6 +452,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
444
452
  return 0;
445
453
  }
446
454
  case "register-agent": {
455
+ const { registerAgentInputFromArgs, runRegisterAgent } = await import("./commands/register-agent.js");
447
456
  const config = resolveConfig({
448
457
  cwd,
449
458
  env,
@@ -463,6 +472,10 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
463
472
  return 0;
464
473
  }
465
474
  case "eval-tool": {
475
+ const { evalToolInputFromArgs, formatEvalHuman, runEvalTool } = await import("./commands/eval-tool.js");
476
+ const { verdictExitCode } = await import("./commands/wrap.js");
477
+ const { appendTrail, defaultSessionId } = await import("./trail.js");
478
+ const { deriveTargetPath } = await import("./trail-summary.js");
466
479
  const input = evalToolInputFromArgs(parsed);
467
480
  const config = resolveConfig({
468
481
  cwd,
@@ -494,6 +507,9 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
494
507
  return verdictExitCode(result.response.verdict);
495
508
  }
496
509
  case "receipt": {
510
+ const { formatReceiptHuman, receiptInputFromArgs, runReceipt, runReceiptShare } = await import("./commands/receipt.js");
511
+ const { SHARE_HOSTED_HINT, formatShareLine } = await import("./receipt/share.js");
512
+ const { maybePrintStarCta } = await import("./star-cta.js");
497
513
  const config = resolveConfig({
498
514
  cwd,
499
515
  env,
@@ -531,10 +547,15 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
531
547
  io.log(formatReceiptHuman(result));
532
548
  if (result.liveUrl)
533
549
  maybePrintStarCta(cwd, result.days, io.log);
550
+ // One CTA per day at most: the truncation pitch wins over the --share hint.
551
+ const { maybeCta } = await import("./cta.js");
552
+ const { trailTruncated } = await import("./trail.js");
553
+ maybeCta(trailTruncated(cwd, env) ? "receipt-truncated" : "receipt-share", { env, cwd, isTty: io.isTty ?? Boolean(process.stdout.isTTY) }, io.log);
534
554
  }
535
555
  return 0;
536
556
  }
537
557
  case "wrap": {
558
+ const { formatWrapHuman, runWrap, wrapExitCode, wrapInputFromArgs } = await import("./commands/wrap.js");
538
559
  const input = wrapInputFromArgs(parsed);
539
560
  const config = resolveConfig({
540
561
  cwd,
@@ -565,6 +586,8 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
565
586
  return wrapExitCode(result);
566
587
  }
567
588
  case "invoke": {
589
+ const { verdictExitCode } = await import("./commands/wrap.js");
590
+ const { formatInvokeHuman, invokeInputFromArgs, runInvoke } = await import("./commands/invoke.js");
568
591
  const input = invokeInputFromArgs(parsed);
569
592
  const config = resolveConfig({
570
593
  cwd,
@@ -583,6 +606,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
583
606
  }
584
607
  case "approve":
585
608
  case "reject": {
609
+ const { decideIdFromArgs, runDecide } = await import("./commands/decide.js");
586
610
  const id = decideIdFromArgs(parsed, parsed.command);
587
611
  const config = resolveConfig({
588
612
  cwd,
@@ -603,6 +627,8 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
603
627
  return 0;
604
628
  }
605
629
  case "serve-mcp": {
630
+ const { runServeMcp, serveMcpOptionsFromArgs } = await import("./commands/serve-mcp.js");
631
+ const { startSessionBeacon } = await import("./telemetry.js");
606
632
  const config = resolveConfig({
607
633
  cwd,
608
634
  env,
@@ -642,6 +668,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
642
668
  return 0;
643
669
  }
644
670
  case "orr": {
671
+ const { orrRunOptionsFromArgs, runOrr } = await import("./commands/orr.js");
645
672
  const sub = parsed.positionals[0];
646
673
  if (sub !== "run") {
647
674
  io.error('Usage: kya orr run --path <dir> [options]');
@@ -661,6 +688,8 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
661
688
  return result.exitCode;
662
689
  }
663
690
  case "certify": {
691
+ const { certifyOptionsFromArgs, formatCertifySummary, runCertify } = await import("./commands/certify.js");
692
+ const { openPath } = await import("./commands/receipt.js");
664
693
  // Local-first, evidence-only: no resolveConfig, no API key, no network.
665
694
  const opts = certifyOptionsFromArgs(parsed);
666
695
  const result = runCertify({ ...opts, cwd, env });
@@ -675,6 +704,11 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
675
704
  io.log(` wrote ${p}`);
676
705
  }
677
706
  io.log("(evidence only - sole PEP remains Shield KYA; certify never allows or blocks)");
707
+ if (result.report.overall.result === "gap") {
708
+ // One-line CTA, silent in CI, non-TTY, quiet, opt-out and within 24 h of the last one. Never changes exit code.
709
+ const { maybeCta } = await import("./cta.js");
710
+ maybeCta("certify-gaps", { env, cwd, isTty: io.isTty ?? Boolean(process.stdout.isTTY), json: jsonOut, quiet: opts.quiet }, io.log);
711
+ }
678
712
  }
679
713
  // Attestation confirmation is safety-relevant (proof the attest write
680
714
  // happened): it prints even under --quiet, like the key notice;
@@ -703,6 +737,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
703
737
  return result.exitCode;
704
738
  }
705
739
  case "agents": {
740
+ const { formatAgentTable, runListAgents } = await import("./commands/ops.js");
706
741
  const config = resolveConfig({
707
742
  cwd,
708
743
  env,
@@ -714,6 +749,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
714
749
  return 0;
715
750
  }
716
751
  case "agent": {
752
+ const { formatAgentTable, requireId, runGetAgent } = await import("./commands/ops.js");
717
753
  const id = requireId(parsed, "agent");
718
754
  const config = resolveConfig({
719
755
  cwd,
@@ -726,6 +762,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
726
762
  return 0;
727
763
  }
728
764
  case "passport": {
765
+ const { requireId, runGetPassport } = await import("./commands/ops.js");
729
766
  const id = requireId(parsed, "passport");
730
767
  const config = resolveConfig({
731
768
  cwd,
@@ -738,6 +775,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
738
775
  return 0;
739
776
  }
740
777
  case "kill": {
778
+ const { requireId, runKillAgent } = await import("./commands/ops.js");
741
779
  const id = requireId(parsed, "kill");
742
780
  const config = resolveConfig({
743
781
  cwd,
@@ -753,6 +791,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
753
791
  return 0;
754
792
  }
755
793
  case "approvals": {
794
+ const { formatApprovalTable, runListApprovals } = await import("./commands/ops.js");
756
795
  const config = resolveConfig({
757
796
  cwd,
758
797
  env,
@@ -764,6 +803,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
764
803
  return 0;
765
804
  }
766
805
  case "sessions": {
806
+ const { formatSessionTable, runListSessions } = await import("./commands/ops.js");
767
807
  const config = resolveConfig({
768
808
  cwd,
769
809
  env,
@@ -775,6 +815,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
775
815
  return 0;
776
816
  }
777
817
  case "shrink": {
818
+ const { requireId, runShrinkSession, shrinkToFromArgs } = await import("./commands/ops.js");
778
819
  const id = requireId(parsed, "shrink");
779
820
  const to = shrinkToFromArgs(parsed);
780
821
  const config = resolveConfig({
@@ -791,6 +832,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
791
832
  return 0;
792
833
  }
793
834
  case "dash": {
835
+ const { runDash } = await import("./commands/dash.js");
794
836
  const config = resolveConfig({
795
837
  cwd,
796
838
  env,
@@ -802,9 +844,11 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
802
844
  return await runDash(config, parsed, io, env);
803
845
  }
804
846
  case "sandbox": {
847
+ const { runSandboxCommand } = await import("./commands/sandbox.js");
805
848
  return await runSandboxCommand(parsed);
806
849
  }
807
850
  case "telemetry": {
851
+ const { runTelemetryCommand } = await import("./telemetry.js");
808
852
  return runTelemetryCommand({
809
853
  sub: parsed.positionals[0],
810
854
  purge: flagBool(parsed.flags, "purge"),
@@ -812,6 +856,9 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
812
856
  }, io, env, cwd);
813
857
  }
814
858
  case "hook": {
859
+ const { runHook } = await import("./commands/hook.js");
860
+ const { crashDecision, guardStream, hostedCrashHandler, planeBudgetMs } = await import("./commands/hosted-hook.js");
861
+ const { maybeSpawnHookPing } = await import("./telemetry.js");
815
862
  const host = flagString(parsed.flags, "host") ?? "other";
816
863
  const strict = flagBool(parsed.flags, "strict");
817
864
  // Strict boolean: parseArgs would otherwise swallow a following word
@@ -886,21 +933,25 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
886
933
  return r.exitCode;
887
934
  }
888
935
  case "import": {
936
+ const { importOptionsFromArgs, runImport } = await import("./commands/import-traces.js");
889
937
  return await runImport(importOptionsFromArgs(parsed), io, cwd, env);
890
938
  }
891
939
  case "investigate": {
940
+ const { investigateOptionsFromArgs, runInvestigate } = await import("./commands/investigate.js");
892
941
  return await runInvestigate(investigateOptionsFromArgs(parsed), io, cwd, env);
893
942
  }
894
943
  case "discover": {
944
+ const { discoverOptionsFromArgs, runDiscover } = await import("./commands/discover.js");
895
945
  return await runDiscover(discoverOptionsFromArgs(parsed), io, cwd, env);
896
946
  }
897
947
  case "notify-flush": {
948
+ const { runNotifyFlush } = await import("./commands/notify-flush.js");
898
949
  // Internal: spawned detached by hook/wrap (src/notify/dispatch.ts).
899
950
  return await runNotifyFlush(env, cwd);
900
951
  }
901
952
  default:
902
953
  io.error(`Unknown command: ${parsed.command}`);
903
- io.log(HELP);
954
+ io.log(await helpText());
904
955
  return 2;
905
956
  }
906
957
  }