@shield-agent/kya 0.33.6 → 0.35.3
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/.cursor-plugin/plugin.json +2 -2
- package/.mcp.json +1 -1
- package/LIMITATIONS.md +2 -1
- package/README.md +39 -640
- package/amp/settings.example.json +1 -1
- package/assets/report-blocked.png +0 -0
- package/assets/report-certify.png +0 -0
- package/assets/report-overview.png +0 -0
- package/assets/screenshot-features.json +18 -0
- package/claude/claude_desktop_config.example.json +1 -1
- package/cline/cline_mcp_settings.example.json +1 -1
- package/copilot/mcp-config.example.json +1 -1
- package/dist/alerts/config.d.ts +22 -0
- package/dist/alerts/config.d.ts.map +1 -0
- package/dist/alerts/config.js +59 -0
- package/dist/alerts/config.js.map +1 -0
- package/dist/alerts/constants.d.ts +5 -0
- package/dist/alerts/constants.d.ts.map +1 -0
- package/dist/alerts/constants.js +5 -0
- package/dist/alerts/constants.js.map +1 -0
- package/dist/alerts/desktop.d.ts +19 -0
- package/dist/alerts/desktop.d.ts.map +1 -0
- package/dist/alerts/desktop.js +57 -0
- package/dist/alerts/desktop.js.map +1 -0
- package/dist/alerts/incident-alert.d.ts +42 -0
- package/dist/alerts/incident-alert.d.ts.map +1 -0
- package/dist/alerts/incident-alert.js +84 -0
- package/dist/alerts/incident-alert.js.map +1 -0
- package/dist/alerts/scan.d.ts +37 -0
- package/dist/alerts/scan.d.ts.map +1 -0
- package/dist/alerts/scan.js +188 -0
- package/dist/alerts/scan.js.map +1 -0
- package/dist/alerts/state.d.ts +55 -0
- package/dist/alerts/state.d.ts.map +1 -0
- package/dist/alerts/state.js +178 -0
- package/dist/alerts/state.js.map +1 -0
- package/dist/alerts/triage-input.d.ts +36 -0
- package/dist/alerts/triage-input.d.ts.map +1 -0
- package/dist/alerts/triage-input.js +159 -0
- package/dist/alerts/triage-input.js.map +1 -0
- package/dist/alerts/triage-model.d.ts +42 -0
- package/dist/alerts/triage-model.d.ts.map +1 -0
- package/dist/alerts/triage-model.js +126 -0
- package/dist/alerts/triage-model.js.map +1 -0
- package/dist/alerts/triage-prompt.d.ts +23 -0
- package/dist/alerts/triage-prompt.d.ts.map +1 -0
- package/dist/alerts/triage-prompt.js +53 -0
- package/dist/alerts/triage-prompt.js.map +1 -0
- package/dist/alerts/triage-schema.json +52 -0
- package/dist/alerts/triage-setup.d.ts +77 -0
- package/dist/alerts/triage-setup.d.ts.map +1 -0
- package/dist/alerts/triage-setup.js +290 -0
- package/dist/alerts/triage-setup.js.map +1 -0
- package/dist/alerts/triage-status.d.ts +26 -0
- package/dist/alerts/triage-status.d.ts.map +1 -0
- package/dist/alerts/triage-status.js +61 -0
- package/dist/alerts/triage-status.js.map +1 -0
- package/dist/alerts/triage-tokenizer.d.ts +29 -0
- package/dist/alerts/triage-tokenizer.d.ts.map +1 -0
- package/dist/alerts/triage-tokenizer.js +82 -0
- package/dist/alerts/triage-tokenizer.js.map +1 -0
- package/dist/card-png.d.ts +3 -0
- package/dist/card-png.d.ts.map +1 -0
- package/dist/card-png.js +54 -0
- package/dist/card-png.js.map +1 -0
- package/dist/card.d.ts +62 -0
- package/dist/card.d.ts.map +1 -0
- package/dist/card.js +154 -0
- package/dist/card.js.map +1 -0
- package/dist/certify/evaluate.d.ts +11 -1
- package/dist/certify/evaluate.d.ts.map +1 -1
- package/dist/certify/evaluate.js +8 -1
- package/dist/certify/evaluate.js.map +1 -1
- package/dist/certify/render.d.ts.map +1 -1
- package/dist/certify/render.js +10 -1
- package/dist/certify/render.js.map +1 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +234 -49
- package/dist/cli.js.map +1 -1
- package/dist/commands/alerts.d.ts +16 -0
- package/dist/commands/alerts.d.ts.map +1 -0
- package/dist/commands/alerts.js +112 -0
- package/dist/commands/alerts.js.map +1 -0
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +4 -3
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +12 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/hook.d.ts.map +1 -1
- package/dist/commands/hook.js +94 -8
- package/dist/commands/hook.js.map +1 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +2 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/notify-flush.d.ts.map +1 -1
- package/dist/commands/notify-flush.js +3 -0
- package/dist/commands/notify-flush.js.map +1 -1
- package/dist/commands/receipt-serve.d.ts +1 -1
- package/dist/commands/receipt-serve.d.ts.map +1 -1
- package/dist/commands/receipt-serve.js +3 -2
- package/dist/commands/receipt-serve.js.map +1 -1
- package/dist/commands/receipt.d.ts +19 -0
- package/dist/commands/receipt.d.ts.map +1 -1
- package/dist/commands/receipt.js +21 -1
- package/dist/commands/receipt.js.map +1 -1
- package/dist/commands/serve-mcp.d.ts +2 -0
- package/dist/commands/serve-mcp.d.ts.map +1 -1
- package/dist/commands/serve-mcp.js +2 -0
- package/dist/commands/serve-mcp.js.map +1 -1
- package/dist/commands/start.d.ts +50 -2
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +233 -27
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/team.d.ts +19 -2
- package/dist/commands/team.d.ts.map +1 -1
- package/dist/commands/team.js +93 -13
- package/dist/commands/team.js.map +1 -1
- package/dist/commands/uninstall.d.ts +20 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +378 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/wire-hooks.d.ts +16 -2
- package/dist/commands/wire-hooks.d.ts.map +1 -1
- package/dist/commands/wire-hooks.js +86 -21
- package/dist/commands/wire-hooks.js.map +1 -1
- package/dist/cta.d.ts +3 -1
- package/dist/cta.d.ts.map +1 -1
- package/dist/cta.js +11 -6
- package/dist/cta.js.map +1 -1
- package/dist/fs-atomic.d.ts.map +1 -1
- package/dist/fs-atomic.js +9 -2
- package/dist/fs-atomic.js.map +1 -1
- package/dist/guard-demo.d.ts +23 -0
- package/dist/guard-demo.d.ts.map +1 -0
- package/dist/guard-demo.js +34 -0
- package/dist/guard-demo.js.map +1 -0
- package/dist/guard-entry.d.ts +2 -0
- package/dist/guard-entry.d.ts.map +1 -0
- package/dist/guard-entry.js +50 -0
- package/dist/guard-entry.js.map +1 -0
- package/dist/guard-lite.d.ts +27 -0
- package/dist/guard-lite.d.ts.map +1 -0
- package/dist/guard-lite.js +274 -0
- package/dist/guard-lite.js.map +1 -0
- package/dist/guard-pack.d.ts +7 -2
- package/dist/guard-pack.d.ts.map +1 -1
- package/dist/guard-pack.js +202 -4
- package/dist/guard-pack.js.map +1 -1
- package/dist/hook-health.d.ts +7 -0
- package/dist/hook-health.d.ts.map +1 -0
- package/dist/hook-health.js +105 -0
- package/dist/hook-health.js.map +1 -0
- package/dist/investigate/detectors.d.ts +6 -0
- package/dist/investigate/detectors.d.ts.map +1 -1
- package/dist/investigate/detectors.js +10 -0
- package/dist/investigate/detectors.js.map +1 -1
- package/dist/manifest.d.ts +106 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +454 -0
- package/dist/manifest.js.map +1 -0
- package/dist/mcp/http.d.ts +1 -0
- package/dist/mcp/http.d.ts.map +1 -1
- package/dist/mcp/http.js +1 -0
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/protocol.d.ts +2 -0
- package/dist/mcp/protocol.d.ts.map +1 -1
- package/dist/mcp/protocol.js +5 -1
- package/dist/mcp/protocol.js.map +1 -1
- package/dist/mcp/stdio.d.ts +1 -0
- package/dist/mcp/stdio.d.ts.map +1 -1
- package/dist/mcp/stdio.js +1 -0
- package/dist/mcp/stdio.js.map +1 -1
- package/dist/never-list-input.d.ts +2 -0
- package/dist/never-list-input.d.ts.map +1 -1
- package/dist/never-list-input.js +30 -30
- package/dist/never-list-input.js.map +1 -1
- package/dist/notify/dispatch.d.ts +1 -1
- package/dist/notify/dispatch.d.ts.map +1 -1
- package/dist/notify/dispatch.js +4 -1
- package/dist/notify/dispatch.js.map +1 -1
- package/dist/notify/incident-templates.d.ts +23 -0
- package/dist/notify/incident-templates.d.ts.map +1 -0
- package/dist/notify/incident-templates.js +128 -0
- package/dist/notify/incident-templates.js.map +1 -0
- package/dist/notify/index.d.ts +12 -0
- package/dist/notify/index.d.ts.map +1 -1
- package/dist/notify/index.js +50 -3
- package/dist/notify/index.js.map +1 -1
- package/dist/notify/templates.d.ts +6 -0
- package/dist/notify/templates.d.ts.map +1 -1
- package/dist/notify/templates.js +12 -2
- package/dist/notify/templates.js.map +1 -1
- package/dist/offline-evaluate.d.ts.map +1 -1
- package/dist/offline-evaluate.js +2 -1
- package/dist/offline-evaluate.js.map +1 -1
- package/dist/parse-args.js +1 -1
- package/dist/parse-args.js.map +1 -1
- package/dist/receipt/changes.d.ts +2 -1
- package/dist/receipt/changes.d.ts.map +1 -1
- package/dist/receipt/changes.js +9 -0
- package/dist/receipt/changes.js.map +1 -1
- package/dist/receipt/dashboard.d.ts +14 -1
- package/dist/receipt/dashboard.d.ts.map +1 -1
- package/dist/receipt/dashboard.js +20 -2
- package/dist/receipt/dashboard.js.map +1 -1
- package/dist/receipt/live-server.d.ts +19 -0
- package/dist/receipt/live-server.d.ts.map +1 -1
- package/dist/receipt/live-server.js +119 -0
- package/dist/receipt/live-server.js.map +1 -1
- package/dist/receipt/receipt-css.d.ts.map +1 -1
- package/dist/receipt/receipt-css.js +45 -0
- package/dist/receipt/receipt-css.js.map +1 -1
- package/dist/receipt/render-receipt.d.ts +17 -0
- package/dist/receipt/render-receipt.d.ts.map +1 -1
- package/dist/receipt/render-receipt.js +479 -80
- package/dist/receipt/render-receipt.js.map +1 -1
- package/dist/receipt/search.d.ts.map +1 -1
- package/dist/receipt/search.js +2 -0
- package/dist/receipt/search.js.map +1 -1
- package/dist/receipt/semantic-setup.d.ts +4 -0
- package/dist/receipt/semantic-setup.d.ts.map +1 -1
- package/dist/receipt/semantic-setup.js +10 -1
- package/dist/receipt/semantic-setup.js.map +1 -1
- package/dist/receipt/share.d.ts +15 -0
- package/dist/receipt/share.d.ts.map +1 -1
- package/dist/receipt/share.js +34 -1
- package/dist/receipt/share.js.map +1 -1
- package/dist/telemetry.d.ts +17 -2
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +67 -7
- package/dist/telemetry.js.map +1 -1
- package/dist/trail.d.ts +45 -0
- package/dist/trail.d.ts.map +1 -1
- package/dist/trail.js +38 -0
- package/dist/trail.js.map +1 -1
- package/dist/write-journal.d.ts +39 -0
- package/dist/write-journal.d.ts.map +1 -0
- package/dist/write-journal.js +107 -0
- package/dist/write-journal.js.map +1 -0
- package/droid/README.md +1 -1
- package/droid/mcp.example.json +1 -1
- package/gemini/settings.example.json +1 -1
- package/grok/README.md +2 -2
- package/kilo/kilo.example.json +1 -1
- package/kimi/mcp.example.json +1 -1
- package/kiro/mcp.example.json +1 -1
- package/manifest.json +2 -2
- package/mastracode/mcp.example.json +1 -1
- package/mcp.json +1 -1
- package/openai/codex.config.example.toml +1 -1
- package/opencode/opencode.example.json +1 -1
- package/package.json +9 -3
- package/qwen/settings.example.json +1 -1
- package/server.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { realpathSync, writeSync } from "node:fs";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
|
-
import { resolveConfig } from "./config.js";
|
|
12
|
+
import { globalConfigDir, resolveConfig } from "./config.js";
|
|
13
13
|
import { AuthRequiredError, KyaError } from "./errors.js";
|
|
14
14
|
import { flagBool, flagString, parseArgs } from "./parse-args.js";
|
|
15
15
|
import { ensureSupportedNode } from "./node-upgrade.js";
|
|
@@ -21,11 +21,19 @@ Usage:
|
|
|
21
21
|
kya <command> [options]
|
|
22
22
|
|
|
23
23
|
Commands:
|
|
24
|
+
Guard:
|
|
24
25
|
version Print the package version (same as --version)
|
|
25
|
-
start ONE LINER:
|
|
26
|
-
(
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
start ONE LINER: wire local MCP + open live report. Prints a plan first
|
|
27
|
+
(each file, created or merged, exact keys) and asks "Apply? [Y/n]".
|
|
28
|
+
--yes or KYA_YES=1 skips the question; off a terminal or in CI it
|
|
29
|
+
applies only with --yes. --dry-run prints the plan, writes nothing.
|
|
30
|
+
Wires only hosts found on this machine. Report runs in the
|
|
31
|
+
background - returns your terminal. Auto-bootstraps the gateway for
|
|
32
|
+
third-party MCP servers found in host configs (--no-gate or
|
|
33
|
+
KYA_GATE=off skips)
|
|
34
|
+
uninstall Undo kya start / kya connect from ~/.kya/manifest.json: removes only
|
|
35
|
+
the keys KYA added, deletes files KYA created if unchanged, prints
|
|
36
|
+
what it left alone (--project: this directory only, --dry-run)
|
|
29
37
|
stop Stop the background report server started by kya start
|
|
30
38
|
(--all also stops orphaned report daemons from other
|
|
31
39
|
directories or older installs)
|
|
@@ -37,21 +45,8 @@ Commands:
|
|
|
37
45
|
gate Local MCP gateway: govern + audit tool calls to any MCP server
|
|
38
46
|
(init | setup | doctor | status | run | stop)
|
|
39
47
|
init Scaffold .kya/ config + sample tools + .env.example
|
|
40
|
-
team init Enable the Claude Code plugin for everyone who opens this repo:
|
|
41
|
-
merges a tag-pinned marketplace + enabledPlugins into the project's
|
|
42
|
-
.claude/settings.json (--dry-run shows the change, writes nothing)
|
|
43
|
-
team managed-settings Print the managed-settings JSON an admin deploys
|
|
44
|
-
login Link this machine to the hosted console (device code). Saves a 0600
|
|
45
|
-
key in ~/.kya/hosted-credentials.json. --base-url <url> or KYA_BASE_URL
|
|
46
|
-
logout Delete the saved hosted key (the key stays active until you revoke it)
|
|
47
48
|
update Self-update to the latest npm version (kya start warns when
|
|
48
49
|
a newer release exists; --no-update-check / KYA_UPDATE_CHECK=0 opts out)
|
|
49
|
-
register-agent POST /api/v1/kya/agents (human mint; server applies allow/break-glass/approve)
|
|
50
|
-
eval-tool Policy evaluate (HTTP plane or --offline sample)
|
|
51
|
-
wrap Evaluate + record trail. With --tool-id it never executes.
|
|
52
|
-
wrap [--offline] -- <cmd...>: gate the command as a shell call, run it
|
|
53
|
-
only if allowed (exit = the command's; 1 denied, 4 Hold pending).
|
|
54
|
-
Default observe: no Hold ticket (no second approve). --hold / KYA_HOLD=1 for org Hold.
|
|
55
50
|
hook PreToolUse interception for native-hook hosts (claude|grok|kimi|…)
|
|
56
51
|
Reads the hook payload from stdin; exit 2 blocks. --strict denies advisory.
|
|
57
52
|
--fail-closed (hosted): internal error, malformed payload or async
|
|
@@ -73,12 +68,49 @@ Commands:
|
|
|
73
68
|
fail closed; key/URL/agent come only from that 0600 file.
|
|
74
69
|
--plane-shadow records hosted verdicts without blocking;
|
|
75
70
|
--plane-budget-ms <n> total plane budget (default 3000, max 4000).
|
|
71
|
+
wrap Evaluate + record trail. With --tool-id it never executes.
|
|
72
|
+
wrap [--offline] -- <cmd...>: gate the command as a shell call, run it
|
|
73
|
+
only if allowed (exit = the command's; 1 denied, 4 Hold pending).
|
|
74
|
+
Default observe: no Hold ticket (no second approve). --hold / KYA_HOLD=1 for org Hold.
|
|
75
|
+
doctor Local checks. doctor --iocs scans this machine now for known supply-chain
|
|
76
|
+
indicators (advisory; read-only, offline). --json for scripts. Last result: kya dash/receipt
|
|
77
|
+
Background daily scan (from kya hook) is off with KYA_IOC=0 or ioc.enabled=false in ~/.kya/config.json
|
|
78
|
+
serve-mcp Local MCP gate (HTTP default; --stdio for hosts)
|
|
79
|
+
sandbox Opt-in Firecracker wrap (spawn|exec|kill|status). Not MCP.
|
|
80
|
+
Requires KYA_SANDBOX=mock|firecracker. MCP still never execs.
|
|
81
|
+
telemetry Opt-in anonymous usage stats, OFF by default
|
|
82
|
+
(status | on | off [--purge] | show | reset) - see docs/telemetry.md
|
|
83
|
+
posture Developer posture report, OFF by default. status | on [--yes] | off |
|
|
84
|
+
send [--dry-run --json] | label NAME. "on" prints the exact report first.
|
|
85
|
+
Sent once a day only when the local toggle AND the workspace allow it.
|
|
86
|
+
|
|
87
|
+
Report:
|
|
76
88
|
receipt Activity report HTML/JSON/MD (default: last 3 days, all tools; --open)
|
|
77
89
|
--q pre-fills feed search · --share publishes a redacted summary (see --share-url)
|
|
78
90
|
map Map of agent actions: device, agent, tool and target graph with KYA verdicts (local only)
|
|
79
91
|
--days <n> window (default 3) · --json · --html <file> · --session <id>
|
|
80
92
|
export Local trail as an agent-flow JSONL event log (classes only, no args; local only)
|
|
81
93
|
--format agent-flow · --days <n> (default 3) · --session <id> · --out <file>
|
|
94
|
+
dash Terminal desk (FREE panes; actions on a TTY, --once for CI)
|
|
95
|
+
investigate Deterministic trail analysis: detectors, grouped incidents,
|
|
96
|
+
markdown fix briefs for coding agents (--json)
|
|
97
|
+
alerts Security alerts for detected incidents, optional local triage model, off by default, advisory
|
|
98
|
+
(status [--json] | test | on | off) - see docs/alerts.md
|
|
99
|
+
discover Scan this endpoint for AI agents, IDEs, runtimes, and MCP servers
|
|
100
|
+
(--json, --diff <snapshot>, --push)
|
|
101
|
+
|
|
102
|
+
Team and hosted:
|
|
103
|
+
team init Enable the Claude Code plugin for everyone who opens this repo:
|
|
104
|
+
merges a tag-pinned marketplace + enabledPlugins into the project's
|
|
105
|
+
.claude/settings.json (--dry-run shows the change, writes nothing).
|
|
106
|
+
--guard enables the kya-guard plugin instead: prints the diff and a README badge,
|
|
107
|
+
kya uninstall --project reverses it
|
|
108
|
+
team managed-settings Print the managed-settings JSON an admin deploys
|
|
109
|
+
login Link this machine to the hosted console (device code). Saves a 0600
|
|
110
|
+
key in ~/.kya/hosted-credentials.json. --base-url <url> or KYA_BASE_URL
|
|
111
|
+
logout Delete the saved hosted key (the key stays active until you revoke it)
|
|
112
|
+
register-agent POST /api/v1/kya/agents (human mint; server applies allow/break-glass/approve)
|
|
113
|
+
eval-tool Policy evaluate (HTTP plane or --offline sample)
|
|
82
114
|
invoke Authorize on the plane after Allow or APPROVED. Never runs the write here.
|
|
83
115
|
approve Human APPROVE an approval id (kya.approve scope)
|
|
84
116
|
reject Human REJECT an approval id (kya.approve scope)
|
|
@@ -89,32 +121,18 @@ Commands:
|
|
|
89
121
|
approvals List the human queue
|
|
90
122
|
sessions List observed sessions
|
|
91
123
|
shrink Drop session clearance (--id --to BUILD|READ|DEPLOY)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
(status | on | off [--purge] | show | reset) - see docs/telemetry.md
|
|
95
|
-
orr run Read-only ORR board (reporting only - not a second PEP)
|
|
96
|
-
Optional: --producer harness.agentshield [--agentshield-json <file>]
|
|
97
|
-
dash Terminal desk (FREE panes; actions on a TTY, --once for CI)
|
|
98
|
-
doctor Local checks. doctor --iocs scans this machine now for known supply-chain
|
|
99
|
-
indicators (advisory; read-only, offline). --json for scripts. Last result: kya dash/receipt
|
|
100
|
-
Background daily scan (from kya hook) is off with KYA_IOC=0 or ioc.enabled=false in ~/.kya/config.json
|
|
101
|
-
posture Developer posture report, OFF by default. status | on [--yes] | off |
|
|
102
|
-
send [--dry-run --json] | label NAME. "on" prints the exact report first.
|
|
103
|
-
Sent once a day only when the local toggle AND the workspace allow it.
|
|
104
|
-
sandbox Opt-in Firecracker wrap (spawn|exec|kill|status). Not MCP.
|
|
105
|
-
Requires KYA_SANDBOX=mock|firecracker. MCP still never execs.
|
|
124
|
+
|
|
125
|
+
Compliance and evidence:
|
|
106
126
|
certify Agent Trust Baseline gap report from local evidence
|
|
107
127
|
(JSON/MD/HTML to .kya/certify/; exit 1 on gaps, exit 2 usage)
|
|
108
128
|
--attest REQ-ID --text "…" records a local attestation
|
|
109
129
|
--sign also writes an ed25519-signed evidence-bundle.json
|
|
110
130
|
(self-signed: integrity + key continuity, NOT identity)
|
|
131
|
+
orr run Read-only ORR board (reporting only - not a second PEP)
|
|
132
|
+
Optional: --producer harness.agentshield [--agentshield-json <file>]
|
|
111
133
|
import Import foreign traces into the local trail so the receipt
|
|
112
134
|
and certify see them (--from langsmith|langfuse|phoenix|otel|adr-sensor|openshell
|
|
113
135
|
<file>, or --from agt [--file <path>] for the AGT audit log)
|
|
114
|
-
investigate Deterministic trail analysis: detectors, grouped incidents,
|
|
115
|
-
markdown fix briefs for coding agents (--json)
|
|
116
|
-
discover Scan this endpoint for AI agents, IDEs, runtimes, and MCP servers
|
|
117
|
-
(--json, --diff <snapshot>, --push)
|
|
118
136
|
|
|
119
137
|
Options (shared):
|
|
120
138
|
--base-url <url> Control plane origin (or KYA_BASE_URL)
|
|
@@ -126,6 +144,7 @@ Options (shared):
|
|
|
126
144
|
--days <n> receipt: history window (default 3)
|
|
127
145
|
--session <id> receipt: single session only (optional)
|
|
128
146
|
--q <query> receipt: pre-fill the activity-feed search
|
|
147
|
+
--card receipt: make a near-miss card (image, no private data) for the last denied call; --id <id> picks another
|
|
129
148
|
--share receipt: publish a redacted summary, print the public URL
|
|
130
149
|
--share-url <url> receipt: share endpoint base (or KYA_SHARE_URL; default https://shield-agent.com)
|
|
131
150
|
--share-retries <n> receipt: retry --share on 429/5xx/network with backoff (max 3; default 0 = single attempt)
|
|
@@ -141,6 +160,9 @@ Options (shared):
|
|
|
141
160
|
|
|
142
161
|
Examples:
|
|
143
162
|
kya start
|
|
163
|
+
kya start --dry-run
|
|
164
|
+
kya start --yes
|
|
165
|
+
kya uninstall
|
|
144
166
|
kya connect qwen
|
|
145
167
|
kya connect opencode --project
|
|
146
168
|
npx @shield-agent/kya init --base-url http://127.0.0.1:8090 --host ide
|
|
@@ -175,11 +197,59 @@ Examples:
|
|
|
175
197
|
Docs: https://shield-agent.com/install · docs/guides/kya-light-install.md
|
|
176
198
|
Doctrine: sole PEP is Shield; DENY is hard; missing APPROVED ⇒ no irreversible side effect.
|
|
177
199
|
`;
|
|
178
|
-
/**
|
|
200
|
+
/** Default help: the six commands a new user needs. `kya help --all` prints the full text above. */
|
|
201
|
+
const SHORT_HELP = `Shield KYA - stops your coding agent from deleting, leaking or dropping things.
|
|
202
|
+
|
|
203
|
+
Usage:
|
|
204
|
+
kya <command>
|
|
205
|
+
|
|
206
|
+
kya start Guard this machine and open the report
|
|
207
|
+
kya receipt Open or share the report
|
|
208
|
+
kya connect <host> Add another coding agent
|
|
209
|
+
kya doctor Check that the guard is live
|
|
210
|
+
kya stop Stop the report server
|
|
211
|
+
kya uninstall Remove everything KYA added
|
|
212
|
+
|
|
213
|
+
More commands: kya help --all
|
|
214
|
+
One command: kya help <command>
|
|
215
|
+
Docs: https://shield-agent.com/install
|
|
216
|
+
`;
|
|
217
|
+
/** Full help text. The host list comes from the connect registry, loaded on demand so `kya hook` stays light. */
|
|
179
218
|
async function helpText() {
|
|
180
219
|
const { connectableHosts } = await import("./commands/connect.js");
|
|
181
220
|
return helpFor(connectableHosts().join("|"));
|
|
182
221
|
}
|
|
222
|
+
/** The Commands entries whose first word is `name` (`orr` finds "orr run"), cut from the full help text. */
|
|
223
|
+
export function helpSection(full, name) {
|
|
224
|
+
const start = full.indexOf("\nCommands:\n") + "\nCommands:\n".length;
|
|
225
|
+
const entries = [];
|
|
226
|
+
for (const line of full.slice(start, full.indexOf("\nOptions (shared):")).split("\n")) {
|
|
227
|
+
if (/^ {2}\S/.test(line))
|
|
228
|
+
entries.push([line]);
|
|
229
|
+
else if (/^\s+\S/.test(line) && entries.length > 0)
|
|
230
|
+
entries[entries.length - 1].push(line);
|
|
231
|
+
}
|
|
232
|
+
const hits = entries.filter((e) => e[0].trim().split(/\s+/)[0] === name);
|
|
233
|
+
return hits.length > 0 ? hits.map((e) => e.join("\n")).join("\n") : undefined;
|
|
234
|
+
}
|
|
235
|
+
/** What `kya help`, `kya --help` and `kya <command> --help` print. Returns the exit code. */
|
|
236
|
+
async function printHelp(io, command, all) {
|
|
237
|
+
if (all) {
|
|
238
|
+
io.log(await helpText());
|
|
239
|
+
return 0;
|
|
240
|
+
}
|
|
241
|
+
if (command === undefined) {
|
|
242
|
+
io.log(SHORT_HELP);
|
|
243
|
+
return 0;
|
|
244
|
+
}
|
|
245
|
+
const section = helpSection(await helpText(), command);
|
|
246
|
+
if (section === undefined) {
|
|
247
|
+
io.error(`No help for "${command}". Run kya help --all to list every command.`);
|
|
248
|
+
return 2;
|
|
249
|
+
}
|
|
250
|
+
io.log(`${section}\n\nEvery command and option: kya help --all`);
|
|
251
|
+
return 0;
|
|
252
|
+
}
|
|
183
253
|
const defaultIo = {
|
|
184
254
|
log: (m) => console.log(m),
|
|
185
255
|
error: (m) => console.error(m),
|
|
@@ -209,8 +279,10 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
209
279
|
parsed.command === "help" ||
|
|
210
280
|
parsed.flags["help"] === true ||
|
|
211
281
|
parsed.flags["h"] === true) {
|
|
212
|
-
|
|
213
|
-
|
|
282
|
+
const all = parsed.flags["all"] !== undefined && parsed.flags["all"] !== false;
|
|
283
|
+
// `kya help <command>` names it in the first positional; `kya <command> --help` is the command itself.
|
|
284
|
+
const target = parsed.command === "help" ? parsed.positionals[0] : parsed.command;
|
|
285
|
+
return printHelp(io, target, all);
|
|
214
286
|
}
|
|
215
287
|
try {
|
|
216
288
|
const nodeHandoff = await ensureSupportedNode(io, env, argv, parsed.command);
|
|
@@ -218,7 +290,8 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
218
290
|
return nodeHandoff;
|
|
219
291
|
switch (parsed.command) {
|
|
220
292
|
case "start": {
|
|
221
|
-
const { formatStartHuman, runStart } = await import("./commands/start.js");
|
|
293
|
+
const { askApply, envYes, formatPlanHuman, formatStartHuman, planStart, runStart } = await import("./commands/start.js");
|
|
294
|
+
const { homedir } = await import("node:os");
|
|
222
295
|
const { maybePrintStarCta } = await import("./star-cta.js");
|
|
223
296
|
const { checkForUpdate, formatUpdateBanner, shouldSkipUpdateCheck } = await import("./update-check.js");
|
|
224
297
|
const { maybePromptConsent } = await import("./telemetry.js");
|
|
@@ -233,21 +306,66 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
233
306
|
const force = parsed.flags["force"] === true || parsed.flags["force"] === "true";
|
|
234
307
|
const noOpen = parsed.flags["no-open"] === true || parsed.flags["no-open"] === "true";
|
|
235
308
|
const noGate = parsed.flags["no-gate"] === true || parsed.flags["no-gate"] === "true";
|
|
309
|
+
const switchOn = (v) => v !== undefined && v !== false && !/^(false|0)$/i.test(String(v));
|
|
310
|
+
const dryRun = switchOn(parsed.flags["dry-run"]);
|
|
311
|
+
const yes = switchOn(parsed.flags["yes"]) || envYes(env);
|
|
312
|
+
const home = env.KYA_HOME?.trim() || undefined;
|
|
313
|
+
const plan = await planStart(config, { force, open: !noOpen, gate: !noGate, ...(home ? { home } : {}) });
|
|
314
|
+
const planHome = home ?? homedir();
|
|
315
|
+
if (!config.json)
|
|
316
|
+
io.log(formatPlanHuman(plan, cwd, planHome));
|
|
317
|
+
if (dryRun) {
|
|
318
|
+
if (config.json)
|
|
319
|
+
io.log(JSON.stringify({ applied: false, dryRun: true, plan }, null, 2));
|
|
320
|
+
else
|
|
321
|
+
io.log("Dry run: nothing was written.");
|
|
322
|
+
return 0;
|
|
323
|
+
}
|
|
324
|
+
if (plan.needsConsent && !yes) {
|
|
325
|
+
// A terminal gets one question; a pipe, CI or --json never applies without --yes / KYA_YES=1.
|
|
326
|
+
const interactive = (io.isTty ?? Boolean(process.stdin.isTTY && process.stdout.isTTY)) && !config.json && !env.CI;
|
|
327
|
+
const apply = interactive && /^(|y|yes)$/i.test((await (io.ask ?? askApply)("Apply? [Y/n]")).trim());
|
|
328
|
+
if (!apply) {
|
|
329
|
+
if (config.json)
|
|
330
|
+
io.log(JSON.stringify({ applied: false, dryRun: false, plan }, null, 2));
|
|
331
|
+
if (interactive) {
|
|
332
|
+
io.log("Nothing was changed.");
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
// On stderr (and on stdout in text mode), so a wrapper that only shows stderr still says why nothing happened.
|
|
336
|
+
const line = "Nothing was written (not a terminal). Run again with --yes (or KYA_YES=1) to apply, or --dry-run to preview.";
|
|
337
|
+
if (!config.json)
|
|
338
|
+
io.log(line);
|
|
339
|
+
io.error(line);
|
|
340
|
+
}
|
|
341
|
+
return 0;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
236
344
|
if (!config.json)
|
|
237
345
|
await maybePromptConsent(io, env);
|
|
238
346
|
// Before the report server starts, so the first search already sees the runtime. Never fails start.
|
|
239
347
|
if (!config.json) {
|
|
240
348
|
const { maybeOfferSemanticSearch } = await import("./receipt/semantic-setup.js");
|
|
241
|
-
|
|
349
|
+
// The "is off" hints are not printed here: `kya doctor` shows them (quietHint).
|
|
350
|
+
await maybeOfferSemanticSearch({ ...io, quietHint: true }, env).catch(() => undefined);
|
|
351
|
+
// Security alerts with optional local triage: asked once, after the search offer, same rules. Never fails start.
|
|
352
|
+
const { maybeOfferTriageAlerts } = await import("./alerts/triage-setup.js");
|
|
353
|
+
await maybeOfferTriageAlerts({ ...io, quietHint: true }, env).catch(() => undefined);
|
|
242
354
|
}
|
|
243
|
-
const result = await runStart(config, { force, open: !noOpen, gate: !noGate });
|
|
355
|
+
const result = await runStart(config, { force, open: !noOpen, gate: !noGate, ...(home ? { home } : {}) });
|
|
244
356
|
if (config.json) {
|
|
245
|
-
io.log(JSON.stringify(result, null, 2));
|
|
357
|
+
io.log(JSON.stringify({ ...result, applied: true, plan }, null, 2));
|
|
246
358
|
}
|
|
247
359
|
else {
|
|
248
360
|
io.log(formatStartHuman(result));
|
|
249
361
|
if (result.liveUrl)
|
|
250
362
|
maybePrintStarCta(cwd, 3, io.log);
|
|
363
|
+
// F4: once there is something worth sharing. Same once-a-day, terminal-only rules as every CTA.
|
|
364
|
+
const { maybeCta, START_SHARE_MIN_EVENTS } = await import("./cta.js");
|
|
365
|
+
const { readTrail } = await import("./trail.js");
|
|
366
|
+
if (readTrail(cwd, env).length >= START_SHARE_MIN_EVENTS) {
|
|
367
|
+
maybeCta("start-share", { env, cwd, isTty: io.isTty ?? Boolean(process.stdout.isTTY) }, io.log);
|
|
368
|
+
}
|
|
251
369
|
// Cached 24h; silent on any failure. Skipped in CI / --json / opt-out.
|
|
252
370
|
if (!shouldSkipUpdateCheck(parsed.command, parsed.flags, env)) {
|
|
253
371
|
const update = await checkForUpdate({ env });
|
|
@@ -257,6 +375,13 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
257
375
|
}
|
|
258
376
|
return 0;
|
|
259
377
|
}
|
|
378
|
+
case "uninstall": {
|
|
379
|
+
const { formatUninstallHuman, runUninstall } = await import("./commands/uninstall.js");
|
|
380
|
+
const sw = (v) => v !== undefined && v !== false && !/^(false|0)$/i.test(String(v));
|
|
381
|
+
const result = runUninstall({ env, cwd, project: sw(parsed.flags["project"]), dryRun: sw(parsed.flags["dry-run"]) });
|
|
382
|
+
io.log(flagBool(parsed.flags, "json") ? JSON.stringify(result, null, 2) : formatUninstallHuman(result, cwd));
|
|
383
|
+
return 0;
|
|
384
|
+
}
|
|
260
385
|
case "login": {
|
|
261
386
|
const { loginBrowserOpener, runLogin } = await import("./commands/login.js");
|
|
262
387
|
const { openPath } = await import("./commands/receipt.js");
|
|
@@ -353,7 +478,17 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
353
478
|
shadow: flagBool(parsed.flags, "plane-shadow"),
|
|
354
479
|
}
|
|
355
480
|
: undefined;
|
|
356
|
-
|
|
481
|
+
// Every write lands in ~/.kya/manifest.json so `kya uninstall` can undo it.
|
|
482
|
+
const { liveJournal } = await import("./manifest.js");
|
|
483
|
+
const { withJournal } = await import("./write-journal.js");
|
|
484
|
+
const { journal, finish } = liveJournal({ globalDir: globalConfigDir(env), cwd });
|
|
485
|
+
let result;
|
|
486
|
+
try {
|
|
487
|
+
result = await withJournal(journal, () => runConnect(config, { host, scope, force, hooks, hosted, ...(gate ? { gateUrl: gateMcpUrl(env) } : {}) }, env));
|
|
488
|
+
}
|
|
489
|
+
finally {
|
|
490
|
+
finish();
|
|
491
|
+
}
|
|
357
492
|
if (config.json) {
|
|
358
493
|
io.log(JSON.stringify(result, null, 2));
|
|
359
494
|
}
|
|
@@ -474,13 +609,29 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
474
609
|
return 0;
|
|
475
610
|
}
|
|
476
611
|
if (sub !== "init") {
|
|
477
|
-
io.error("Usage: kya team init [--dry-run] [--json] | kya team managed-settings");
|
|
612
|
+
io.error("Usage: kya team init [--guard] [--dry-run] [--json] | kya team managed-settings");
|
|
478
613
|
return 2;
|
|
479
614
|
}
|
|
480
615
|
// Present means on (like --fail-closed): parseArgs would let `--dry-run x` swallow x.
|
|
481
616
|
const dr = parsed.flags["dry-run"];
|
|
482
617
|
const dryRun = dr !== undefined && dr !== false && !/^(false|0)$/i.test(String(dr));
|
|
483
|
-
const
|
|
618
|
+
const guard = parsed.flags["guard"] !== undefined && parsed.flags["guard"] !== false && !/^(false|0)$/i.test(String(parsed.flags["guard"]));
|
|
619
|
+
let result;
|
|
620
|
+
if (guard && !dryRun) {
|
|
621
|
+
// Every write lands in ~/.kya/manifest.json so `kya uninstall --project` can undo it.
|
|
622
|
+
const { liveJournal } = await import("./manifest.js");
|
|
623
|
+
const { withJournal } = await import("./write-journal.js");
|
|
624
|
+
const { journal, finish } = liveJournal({ globalDir: globalConfigDir(env), cwd });
|
|
625
|
+
try {
|
|
626
|
+
result = await withJournal(journal, () => runTeamInit({ cwd, env, dryRun, guard }));
|
|
627
|
+
}
|
|
628
|
+
finally {
|
|
629
|
+
finish();
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
result = runTeamInit({ cwd, env, dryRun, guard });
|
|
634
|
+
}
|
|
484
635
|
io.log(flagBool(parsed.flags, "json") ? JSON.stringify(result, null, 2) : formatTeamInitHuman(result));
|
|
485
636
|
return 0;
|
|
486
637
|
}
|
|
@@ -543,7 +694,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
543
694
|
}
|
|
544
695
|
case "receipt": {
|
|
545
696
|
const { formatReceiptHuman, receiptInputFromArgs, runReceipt, runReceiptShare } = await import("./commands/receipt.js");
|
|
546
|
-
const { SHARE_HOSTED_HINT, formatShareLine } = await import("./receipt/share.js");
|
|
697
|
+
const { SHARE_CONNECT_HINT, SHARE_HOSTED_HINT, formatShareLine } = await import("./receipt/share.js");
|
|
547
698
|
const { maybePrintStarCta } = await import("./star-cta.js");
|
|
548
699
|
const config = resolveConfig({
|
|
549
700
|
cwd,
|
|
@@ -554,6 +705,17 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
554
705
|
offline: true,
|
|
555
706
|
});
|
|
556
707
|
const input = receiptInputFromArgs(parsed);
|
|
708
|
+
if (flagBool(parsed.flags, "card")) {
|
|
709
|
+
const { runReceiptCard } = await import("./commands/receipt.js");
|
|
710
|
+
const { cardCaption } = await import("./card.js");
|
|
711
|
+
const made = runReceiptCard(env, { id: flagString(parsed.flags, "id") });
|
|
712
|
+
if (!made.ok) {
|
|
713
|
+
io.error(made.message);
|
|
714
|
+
return 1;
|
|
715
|
+
}
|
|
716
|
+
io.log(config.json ? JSON.stringify({ id: made.id, svg: made.svgPath, png: made.pngPath ?? null, caption: cardCaption(made.input) }) : made.text.trimEnd());
|
|
717
|
+
return 0;
|
|
718
|
+
}
|
|
557
719
|
if (flagBool(parsed.flags, "share")) {
|
|
558
720
|
const shared = await runReceiptShare(config, {
|
|
559
721
|
sessionId: input.sessionId,
|
|
@@ -571,6 +733,7 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
571
733
|
else {
|
|
572
734
|
io.log(formatShareLine(shared.url, shared.expiresAt));
|
|
573
735
|
io.log(SHARE_HOSTED_HINT);
|
|
736
|
+
io.log(SHARE_CONNECT_HINT);
|
|
574
737
|
}
|
|
575
738
|
return 0;
|
|
576
739
|
}
|
|
@@ -715,11 +878,23 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
715
878
|
flags: parsed.flags,
|
|
716
879
|
requireApiKey: true,
|
|
717
880
|
});
|
|
718
|
-
|
|
881
|
+
// The client may say who it is before the beacon exists (it starts after the server): keep the name.
|
|
882
|
+
let client;
|
|
883
|
+
let setClient;
|
|
884
|
+
const opts = {
|
|
885
|
+
...serveMcpOptionsFromArgs(parsed),
|
|
886
|
+
onClientInfo: (name) => {
|
|
887
|
+
client ??= name;
|
|
888
|
+
setClient?.(name);
|
|
889
|
+
},
|
|
890
|
+
};
|
|
719
891
|
const result = await runServeMcp(config, opts);
|
|
720
892
|
// Opt-in anonymous session beacon. Silent by construction: no stdout/stderr, because an MCP
|
|
721
893
|
// stdio process owns stdout as its protocol channel.
|
|
722
894
|
const beacon = startSessionBeacon(result.mode === "http" ? "mcp-http" : "mcp-stdio", { env, cwd });
|
|
895
|
+
setClient = (name) => beacon.setClient(name);
|
|
896
|
+
if (client !== undefined)
|
|
897
|
+
beacon.setClient(client);
|
|
723
898
|
try {
|
|
724
899
|
if (result.mode === "http" && result.http) {
|
|
725
900
|
io.log(`KYA MCP gate listening on ${result.http.url} (host=${config.host})`);
|
|
@@ -1077,6 +1252,15 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
1077
1252
|
const { discoverOptionsFromArgs, runDiscover } = await import("./commands/discover.js");
|
|
1078
1253
|
return await runDiscover(discoverOptionsFromArgs(parsed), io, cwd, env);
|
|
1079
1254
|
}
|
|
1255
|
+
case "alerts": {
|
|
1256
|
+
const { runAlerts } = await import("./commands/alerts.js");
|
|
1257
|
+
return await runAlerts({
|
|
1258
|
+
io: { log: (line) => io.log(line), error: (line) => io.error(line) },
|
|
1259
|
+
env,
|
|
1260
|
+
sub: parsed.positionals[0],
|
|
1261
|
+
flags: parsed.flags,
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1080
1264
|
case "notify-flush": {
|
|
1081
1265
|
const { runNotifyFlush } = await import("./commands/notify-flush.js");
|
|
1082
1266
|
// Internal: spawned detached by hook/wrap (src/notify/dispatch.ts).
|
|
@@ -1084,7 +1268,8 @@ export async function runCli(argv, io = defaultIo, env = process.env, cwd = proc
|
|
|
1084
1268
|
}
|
|
1085
1269
|
default:
|
|
1086
1270
|
io.error(`Unknown command: ${parsed.command}`);
|
|
1087
|
-
io.
|
|
1271
|
+
io.error("Run kya help --all to list every command.");
|
|
1272
|
+
io.log(SHORT_HELP);
|
|
1088
1273
|
return 2;
|
|
1089
1274
|
}
|
|
1090
1275
|
}
|