@shield-agent/kya 0.32.7 → 0.33.1
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 +1 -1
- package/.mcp.json +1 -1
- package/LIMITATIONS.md +2 -2
- package/README.md +232 -17
- package/amp/settings.example.json +1 -1
- 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/data/iocs.json +17 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +237 -53
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/commands/connect.d.ts +1 -1
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +11 -3
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/dash.d.ts.map +1 -1
- package/dist/commands/dash.js +25 -1
- package/dist/commands/dash.js.map +1 -1
- package/dist/commands/doctor.d.ts +8 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +26 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/eval-tool.d.ts +3 -0
- package/dist/commands/eval-tool.d.ts.map +1 -1
- package/dist/commands/eval-tool.js +2 -1
- package/dist/commands/eval-tool.js.map +1 -1
- package/dist/commands/export.d.ts +33 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +121 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/hook.d.ts.map +1 -1
- package/dist/commands/hook.js +135 -26
- package/dist/commands/hook.js.map +1 -1
- package/dist/commands/hosted-hook.d.ts +8 -1
- package/dist/commands/hosted-hook.d.ts.map +1 -1
- package/dist/commands/hosted-hook.js +15 -5
- package/dist/commands/hosted-hook.js.map +1 -1
- package/dist/commands/login.d.ts +34 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +74 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/map.d.ts +21 -0
- package/dist/commands/map.d.ts.map +1 -0
- package/dist/commands/map.js +76 -0
- package/dist/commands/map.js.map +1 -0
- package/dist/commands/notify-flush.d.ts.map +1 -1
- package/dist/commands/notify-flush.js +7 -1
- package/dist/commands/notify-flush.js.map +1 -1
- package/dist/commands/posture.d.ts +21 -0
- package/dist/commands/posture.d.ts.map +1 -0
- package/dist/commands/posture.js +177 -0
- package/dist/commands/posture.js.map +1 -0
- package/dist/commands/receipt-serve.d.ts +7 -0
- package/dist/commands/receipt-serve.d.ts.map +1 -1
- package/dist/commands/receipt-serve.js +50 -0
- package/dist/commands/receipt-serve.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +5 -1
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/team.d.ts.map +1 -1
- package/dist/commands/team.js +30 -11
- package/dist/commands/team.js.map +1 -1
- package/dist/commands/wire-hooks.d.ts +5 -1
- package/dist/commands/wire-hooks.d.ts.map +1 -1
- package/dist/commands/wire-hooks.js +23 -8
- package/dist/commands/wire-hooks.js.map +1 -1
- package/dist/commands/wrap.d.ts +38 -1
- package/dist/commands/wrap.d.ts.map +1 -1
- package/dist/commands/wrap.js +82 -6
- package/dist/commands/wrap.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/cta.d.ts +23 -0
- package/dist/cta.d.ts.map +1 -0
- package/dist/cta.js +86 -0
- package/dist/cta.js.map +1 -0
- package/dist/daily-slot.d.ts +2 -0
- package/dist/daily-slot.d.ts.map +1 -0
- package/dist/daily-slot.js +29 -0
- package/dist/daily-slot.js.map +1 -0
- package/dist/dash/dash.d.ts.map +1 -1
- package/dist/dash/dash.js +10 -0
- package/dist/dash/dash.js.map +1 -1
- package/dist/dash/entitlement.d.ts +1 -1
- package/dist/dash/entitlement.d.ts.map +1 -1
- package/dist/dash/entitlement.js +1 -0
- package/dist/dash/entitlement.js.map +1 -1
- package/dist/dash/input.d.ts +1 -1
- package/dist/dash/input.d.ts.map +1 -1
- package/dist/dash/input.js +3 -0
- package/dist/dash/input.js.map +1 -1
- package/dist/dash/render.js +1 -1
- package/dist/dash/render.js.map +1 -1
- package/dist/dash/screens/free.js +1 -1
- package/dist/dash/screens/free.js.map +1 -1
- package/dist/device-id.d.ts +5 -0
- package/dist/device-id.d.ts.map +1 -0
- package/dist/device-id.js +78 -0
- package/dist/device-id.js.map +1 -0
- package/dist/fs-atomic.d.ts +15 -3
- package/dist/fs-atomic.d.ts.map +1 -1
- package/dist/fs-atomic.js +31 -14
- package/dist/fs-atomic.js.map +1 -1
- package/dist/gate/config-gen.d.ts +26 -2
- package/dist/gate/config-gen.d.ts.map +1 -1
- package/dist/gate/config-gen.js +53 -4
- package/dist/gate/config-gen.js.map +1 -1
- package/dist/gate/otlp-receiver.d.ts.map +1 -1
- package/dist/gate/otlp-receiver.js +3 -1
- package/dist/gate/otlp-receiver.js.map +1 -1
- package/dist/guard-pack.d.ts +58 -0
- package/dist/guard-pack.d.ts.map +1 -0
- package/dist/guard-pack.js +753 -0
- package/dist/guard-pack.js.map +1 -0
- package/dist/ioc/exec.d.ts +19 -0
- package/dist/ioc/exec.d.ts.map +1 -0
- package/dist/ioc/exec.js +49 -0
- package/dist/ioc/exec.js.map +1 -0
- package/dist/ioc/format.d.ts +4 -0
- package/dist/ioc/format.d.ts.map +1 -0
- package/dist/ioc/format.js +23 -0
- package/dist/ioc/format.js.map +1 -0
- package/dist/ioc/list.d.ts +29 -0
- package/dist/ioc/list.d.ts.map +1 -0
- package/dist/ioc/list.js +25 -0
- package/dist/ioc/list.js.map +1 -0
- package/dist/ioc/result.d.ts +18 -0
- package/dist/ioc/result.d.ts.map +1 -0
- package/dist/ioc/result.js +26 -0
- package/dist/ioc/result.js.map +1 -0
- package/dist/ioc/scan.d.ts +21 -0
- package/dist/ioc/scan.d.ts.map +1 -0
- package/dist/ioc/scan.js +247 -0
- package/dist/ioc/scan.js.map +1 -0
- package/dist/ioc/spawn.d.ts +26 -0
- package/dist/ioc/spawn.d.ts.map +1 -0
- package/dist/ioc/spawn.js +52 -0
- package/dist/ioc/spawn.js.map +1 -0
- package/dist/login/credentials.d.ts +17 -0
- package/dist/login/credentials.d.ts.map +1 -0
- package/dist/login/credentials.js +64 -0
- package/dist/login/credentials.js.map +1 -0
- package/dist/login/device-flow.d.ts +44 -0
- package/dist/login/device-flow.d.ts.map +1 -0
- package/dist/login/device-flow.js +205 -0
- package/dist/login/device-flow.js.map +1 -0
- package/dist/map/build.d.ts +58 -0
- package/dist/map/build.d.ts.map +1 -0
- package/dist/map/build.js +439 -0
- package/dist/map/build.js.map +1 -0
- package/dist/map/heat.d.ts +44 -0
- package/dist/map/heat.d.ts.map +1 -0
- package/dist/map/heat.js +96 -0
- package/dist/map/heat.js.map +1 -0
- package/dist/map/load.d.ts +38 -0
- package/dist/map/load.d.ts.map +1 -0
- package/dist/map/load.js +38 -0
- package/dist/map/load.js.map +1 -0
- package/dist/map/page.d.ts +90 -0
- package/dist/map/page.d.ts.map +1 -0
- package/dist/map/page.js +374 -0
- package/dist/map/page.js.map +1 -0
- package/dist/map/target-class.d.ts +22 -0
- package/dist/map/target-class.d.ts.map +1 -0
- package/dist/map/target-class.js +151 -0
- package/dist/map/target-class.js.map +1 -0
- package/dist/map/types.d.ts +102 -0
- package/dist/map/types.d.ts.map +1 -0
- package/dist/map/types.js +3 -0
- package/dist/map/types.js.map +1 -0
- package/dist/mcp/protocol.d.ts.map +1 -1
- package/dist/mcp/protocol.js +16 -5
- package/dist/mcp/protocol.js.map +1 -1
- package/dist/never-code.d.ts +7 -0
- package/dist/never-code.d.ts.map +1 -0
- package/dist/never-code.js +9 -0
- package/dist/never-code.js.map +1 -0
- package/dist/never-list-input.d.ts +92 -0
- package/dist/never-list-input.d.ts.map +1 -0
- package/dist/never-list-input.js +1889 -0
- package/dist/never-list-input.js.map +1 -0
- package/dist/notify/dispatch.d.ts +4 -0
- package/dist/notify/dispatch.d.ts.map +1 -1
- package/dist/notify/dispatch.js +3 -1
- package/dist/notify/dispatch.js.map +1 -1
- package/dist/offline-evaluate.d.ts +42 -5
- package/dist/offline-evaluate.d.ts.map +1 -1
- package/dist/offline-evaluate.js +96 -9
- package/dist/offline-evaluate.js.map +1 -1
- package/dist/otel/exporter.d.ts +15 -2
- package/dist/otel/exporter.d.ts.map +1 -1
- package/dist/otel/exporter.js +52 -6
- package/dist/otel/exporter.js.map +1 -1
- package/dist/otel/map-attrs-optin.d.ts +39 -0
- package/dist/otel/map-attrs-optin.d.ts.map +1 -0
- package/dist/otel/map-attrs-optin.js +109 -0
- package/dist/otel/map-attrs-optin.js.map +1 -0
- package/dist/otel.d.ts +8 -2
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +32 -16
- package/dist/otel.js.map +1 -1
- package/dist/parse-args.d.ts +2 -0
- package/dist/parse-args.d.ts.map +1 -1
- package/dist/parse-args.js +4 -2
- package/dist/parse-args.js.map +1 -1
- package/dist/posture/card.d.ts +26 -0
- package/dist/posture/card.d.ts.map +1 -0
- package/dist/posture/card.js +46 -0
- package/dist/posture/card.js.map +1 -0
- package/dist/posture/collect.d.ts +19 -0
- package/dist/posture/collect.d.ts.map +1 -0
- package/dist/posture/collect.js +182 -0
- package/dist/posture/collect.js.map +1 -0
- package/dist/posture/send.d.ts +24 -0
- package/dist/posture/send.d.ts.map +1 -0
- package/dist/posture/send.js +162 -0
- package/dist/posture/send.js.map +1 -0
- package/dist/posture/spawn.d.ts +20 -0
- package/dist/posture/spawn.d.ts.map +1 -0
- package/dist/posture/spawn.js +33 -0
- package/dist/posture/spawn.js.map +1 -0
- package/dist/posture/store.d.ts +34 -0
- package/dist/posture/store.d.ts.map +1 -0
- package/dist/posture/store.js +107 -0
- package/dist/posture/store.js.map +1 -0
- package/dist/posture/validate.d.ts +33 -0
- package/dist/posture/validate.d.ts.map +1 -0
- package/dist/posture/validate.js +232 -0
- package/dist/posture/validate.js.map +1 -0
- package/dist/project-policy.d.ts +23 -0
- package/dist/project-policy.d.ts.map +1 -0
- package/dist/project-policy.js +95 -0
- package/dist/project-policy.js.map +1 -0
- package/dist/receipt/daemon.d.ts +9 -9
- package/dist/receipt/daemon.d.ts.map +1 -1
- package/dist/receipt/daemon.js +26 -11
- package/dist/receipt/daemon.js.map +1 -1
- package/dist/receipt/embeddings.d.ts +29 -7
- package/dist/receipt/embeddings.d.ts.map +1 -1
- package/dist/receipt/embeddings.js +282 -33
- package/dist/receipt/embeddings.js.map +1 -1
- package/dist/receipt/gate-page.d.ts.map +1 -1
- package/dist/receipt/gate-page.js +5 -22
- package/dist/receipt/gate-page.js.map +1 -1
- package/dist/receipt/live-server.d.ts +8 -0
- package/dist/receipt/live-server.d.ts.map +1 -1
- package/dist/receipt/live-server.js +136 -4
- package/dist/receipt/live-server.js.map +1 -1
- package/dist/receipt/render-receipt.d.ts +7 -1
- package/dist/receipt/render-receipt.d.ts.map +1 -1
- package/dist/receipt/render-receipt.js +101 -13
- package/dist/receipt/render-receipt.js.map +1 -1
- package/dist/receipt/search.d.ts +5 -0
- package/dist/receipt/search.d.ts.map +1 -1
- package/dist/receipt/search.js +23 -2
- package/dist/receipt/search.js.map +1 -1
- package/dist/receipt/semantic-setup.d.ts +21 -0
- package/dist/receipt/semantic-setup.d.ts.map +1 -0
- package/dist/receipt/semantic-setup.js +111 -0
- package/dist/receipt/semantic-setup.js.map +1 -0
- package/dist/receipt/semantic-status.d.ts +7 -0
- package/dist/receipt/semantic-status.d.ts.map +1 -0
- package/dist/receipt/semantic-status.js +26 -0
- package/dist/receipt/semantic-status.js.map +1 -0
- package/dist/sdk/govern.d.ts.map +1 -1
- package/dist/sdk/govern.js +7 -3
- package/dist/sdk/govern.js.map +1 -1
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +3 -23
- package/dist/telemetry.js.map +1 -1
- package/dist/trail-map-fields.d.ts +10 -0
- package/dist/trail-map-fields.d.ts.map +1 -0
- package/dist/trail-map-fields.js +53 -0
- package/dist/trail-map-fields.js.map +1 -0
- package/dist/trail-summary.d.ts.map +1 -1
- package/dist/trail-summary.js +11 -3
- package/dist/trail-summary.js.map +1 -1
- package/dist/trail.d.ts +13 -1
- package/dist/trail.d.ts.map +1 -1
- package/dist/trail.js +38 -1
- package/dist/trail.js.map +1 -1
- package/droid/README.md +1 -1
- package/droid/mcp.example.json +1 -1
- package/gemini/settings.example.json +1 -1
- package/grok/README.md +1 -1
- package/kilo/kilo.example.json +1 -1
- package/kimi/mcp.example.json +1 -1
- package/kiro/mcp.example.json +1 -1
- package/manifest.json +1 -1
- 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 +8 -7
- package/qwen/settings.example.json +1 -1
- package/server.json +2 -2
- package/vendor/cytoscape/LICENSE +19 -0
- package/vendor/cytoscape/README.md +7 -0
- package/vendor/cytoscape/cytoscape.min.js +31 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kya doctor - local checks. `--iocs` runs the IoC scan now and stores the result; without it the
|
|
3
|
+
* last stored result is shown. Advisory: exit code is 0 whatever the findings.
|
|
4
|
+
*/
|
|
5
|
+
import { iocEnabled } from "../ioc/spawn.js";
|
|
6
|
+
import { iocLines } from "../ioc/format.js";
|
|
7
|
+
import { readIocResult } from "../ioc/result.js";
|
|
8
|
+
import { runIocScanAndStore } from "../ioc/scan.js";
|
|
9
|
+
import { optInHint } from "../otel/map-attrs-optin.js";
|
|
10
|
+
export async function runDoctor(log, opts) {
|
|
11
|
+
// OTLP map-attribute opt-in that a check refuses: one line on stderr, so stdout (and --json) stays the same.
|
|
12
|
+
const hint = opts.warn ? optInHint(opts.cwd) : undefined;
|
|
13
|
+
if (hint)
|
|
14
|
+
opts.warn(hint);
|
|
15
|
+
const result = opts.iocs ? await runIocScanAndStore(opts.env) : readIocResult(opts.env);
|
|
16
|
+
const enabled = iocEnabled(opts.env);
|
|
17
|
+
if (opts.json) {
|
|
18
|
+
log(JSON.stringify({ iocs: { enabled, ran: opts.iocs, result: result ?? null } }, null, 2));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
for (const line of iocLines(result, enabled))
|
|
22
|
+
log(line);
|
|
23
|
+
}
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,GAA2B,EAC3B,IAAwJ;IAExJ,6GAA6G;IAC7G,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,IAAI,IAAI;QAAE,IAAI,CAAC,IAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxF,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,IAAI,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9F,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ResolvedConfig } from "../config.js";
|
|
2
2
|
import { KyaHttpClient, type PolicyEvaluateResponse } from "../client.js";
|
|
3
|
+
import type { GuardContext } from "../guard-pack.js";
|
|
3
4
|
import type { ParsedArgs } from "../parse-args.js";
|
|
4
5
|
export interface EvalToolResult {
|
|
5
6
|
readonly response: PolicyEvaluateResponse;
|
|
@@ -15,6 +16,8 @@ export declare function runEvalTool(config: ResolvedConfig, input: {
|
|
|
15
16
|
approvalStatus?: string;
|
|
16
17
|
sandboxId?: string;
|
|
17
18
|
offline?: boolean;
|
|
19
|
+
/** Guard pack context (cwd, home, env). Defaults to the process cwd and environment. */
|
|
20
|
+
guard?: GuardContext;
|
|
18
21
|
}, client?: KyaHttpClient): Promise<EvalToolResult>;
|
|
19
22
|
export declare function evalToolInputFromArgs(parsed: ParsedArgs): {
|
|
20
23
|
toolId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval-tool.d.ts","sourceRoot":"","sources":["../../src/commands/eval-tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAEL,aAAa,EACb,KAAK,sBAAsB,EAC5B,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"eval-tool.d.ts","sourceRoot":"","sources":["../../src/commands/eval-tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAEL,aAAa,EACb,KAAK,sBAAsB,EAC5B,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE;IACL,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wFAAwF;IACxF,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB,EACD,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,cAAc,CAAC,CA8DzB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB,CA8BA;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAc9D"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { buildEvaluateFromToolArgs, KyaHttpClient, } from "../client.js";
|
|
2
2
|
import { UsageError } from "../errors.js";
|
|
3
3
|
import { evaluateOffline } from "../offline-evaluate.js";
|
|
4
|
+
import { loadProjectPolicy } from "../project-policy.js";
|
|
4
5
|
import { deriveWireChangeFields } from "../diff-preview.js";
|
|
5
6
|
import { findSampleTool } from "../sample-tools.js";
|
|
6
7
|
import { flagBool, flagString } from "../parse-args.js";
|
|
@@ -27,7 +28,7 @@ export async function runEvalTool(config, input, client) {
|
|
|
27
28
|
? { ...req, actionClass, dataClass: sample?.dataClass }
|
|
28
29
|
: req;
|
|
29
30
|
if (input.offline || config.offline) {
|
|
30
|
-
const response = evaluateOffline(request, config.host);
|
|
31
|
+
const response = evaluateOffline(request, config.host, input.args, loadProjectPolicy(config.cwd), input.guard);
|
|
31
32
|
return {
|
|
32
33
|
response,
|
|
33
34
|
toolId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval-tool.js","sourceRoot":"","sources":["../../src/commands/eval-tool.ts"],"names":[],"mappings":"AACA,OAAO,EACL,yBAAyB,EACzB,aAAa,GAEd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AASxD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAsB,EACtB,
|
|
1
|
+
{"version":3,"file":"eval-tool.js","sourceRoot":"","sources":["../../src/commands/eval-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ParsedArgs } from "../parse-args.js";
|
|
2
|
+
import type { TrailEventLike } from "../map/types.js";
|
|
3
|
+
export declare const EXPORT_FORMATS: readonly ["agent-flow"];
|
|
4
|
+
export type ExportFormat = (typeof EXPORT_FORMATS)[number];
|
|
5
|
+
export interface ExportOptions {
|
|
6
|
+
readonly format: ExportFormat;
|
|
7
|
+
readonly days: number;
|
|
8
|
+
readonly session?: string;
|
|
9
|
+
readonly out?: string;
|
|
10
|
+
/** Replace an existing --out file. */
|
|
11
|
+
readonly force: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare function exportOptionsFromArgs(parsed: ParsedArgs): ExportOptions;
|
|
14
|
+
export interface AgentFlowEvent {
|
|
15
|
+
time: number;
|
|
16
|
+
type: "agent_spawn" | "tool_call_start" | "tool_call_end";
|
|
17
|
+
payload: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
/** A third-party MCP tool name can be any length. A longer one is replaced by its hash: a cut could keep a secret-shaped prefix. */
|
|
20
|
+
export declare const TOOL_MAX = 200;
|
|
21
|
+
export declare function toolLabel(toolId: string): string;
|
|
22
|
+
/** JSON.stringify keeps U+2028 and U+2029 raw. Readers that split lines on them (readline) would break the line. */
|
|
23
|
+
export declare function jsonLine(value: unknown): string;
|
|
24
|
+
/**
|
|
25
|
+
* Pure mapper. Rows are ordered by time, then by file order, so the same trail gives the same bytes.
|
|
26
|
+
* One `agent_spawn` per session at its first row, then a start and an end event per row at the same time.
|
|
27
|
+
*/
|
|
28
|
+
export declare function toAgentFlow(events: readonly TrailEventLike[], salt: string): AgentFlowEvent[];
|
|
29
|
+
export declare function runExport(opts: ExportOptions, io: {
|
|
30
|
+
log: (line: string) => void;
|
|
31
|
+
error: (line: string) => void;
|
|
32
|
+
}, cwd: string, env: NodeJS.ProcessEnv): Promise<number>;
|
|
33
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAWA,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAIzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAItD,eAAO,MAAM,cAAc,yBAA0B,CAAC;AACtD,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG,aAAa,CAevE;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,GAAG,iBAAiB,GAAG,eAAe,CAAC;IAC1D,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAGD,oIAAoI;AACpI,eAAO,MAAM,QAAQ,MAAM,CAAC;AAE5B,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,oHAAoH;AACpH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE/C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CA+B7F;AAGD,wBAAsB,SAAS,CAC7B,IAAI,EAAE,aAAa,EACnB,EAAE,EAAE;IAAE,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,EAClE,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,OAAO,CAAC,MAAM,CAAC,CAgCjB"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `kya export --format agent-flow`: the local trail as an agent-flow JSONL event log. Local only. Never changes a verdict.
|
|
3
|
+
* Each line is `{"time": <s since the first row>, "type": ..., "payload": {...}}`. The payload holds only a hashed session,
|
|
4
|
+
* the tool id, the verdict, the reason code, the target class, the device id and the mode. No args, hashes or paths.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
7
|
+
import { dirname, resolve } from "node:path";
|
|
8
|
+
import { installSalt } from "../device-id.js";
|
|
9
|
+
import { UsageError } from "../errors.js";
|
|
10
|
+
import { writeFileSync } from "node:fs";
|
|
11
|
+
import { ensureOutDir, projectWritePath, underRoot, writeOutFile } from "../fs-atomic.js";
|
|
12
|
+
import { flagBool, flagString } from "../parse-args.js";
|
|
13
|
+
import { sessionHash, targetOf } from "../map/build.js";
|
|
14
|
+
import { loadTrailEvents } from "../map/load.js";
|
|
15
|
+
import { scanMapOutput } from "../map/page.js";
|
|
16
|
+
import { trailPath } from "../trail.js";
|
|
17
|
+
import { daysFromArgs } from "./map.js";
|
|
18
|
+
export const EXPORT_FORMATS = ["agent-flow"];
|
|
19
|
+
export function exportOptionsFromArgs(parsed) {
|
|
20
|
+
const format = parsed.flags["format"];
|
|
21
|
+
if (typeof format !== "string" || !EXPORT_FORMATS.includes(format)) {
|
|
22
|
+
throw new UsageError(`--format must be one of: ${EXPORT_FORMATS.join(", ")} (for example --format agent-flow)`);
|
|
23
|
+
}
|
|
24
|
+
const days = daysFromArgs(parsed);
|
|
25
|
+
if (parsed.flags["session"] === true)
|
|
26
|
+
throw new UsageError("--session needs a session id");
|
|
27
|
+
if (parsed.flags["out"] === true)
|
|
28
|
+
throw new UsageError("--out needs a file path, for example --out flow.jsonl");
|
|
29
|
+
return {
|
|
30
|
+
format: format,
|
|
31
|
+
days,
|
|
32
|
+
session: flagString(parsed.flags, "session"),
|
|
33
|
+
out: flagString(parsed.flags, "out"),
|
|
34
|
+
force: flagBool(parsed.flags, "force"),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const DEVICE_ID = /^[0-9a-f]{16}$/;
|
|
38
|
+
/** A third-party MCP tool name can be any length. A longer one is replaced by its hash: a cut could keep a secret-shaped prefix. */
|
|
39
|
+
export const TOOL_MAX = 200;
|
|
40
|
+
export function toolLabel(toolId) {
|
|
41
|
+
return toolId.length <= TOOL_MAX ? toolId : `tool:${createHash("sha256").update(toolId, "utf8").digest("hex").slice(0, 16)}`;
|
|
42
|
+
}
|
|
43
|
+
/** JSON.stringify keeps U+2028 and U+2029 raw. Readers that split lines on them (readline) would break the line. */
|
|
44
|
+
export function jsonLine(value) {
|
|
45
|
+
return JSON.stringify(value).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Pure mapper. Rows are ordered by time, then by file order, so the same trail gives the same bytes.
|
|
49
|
+
* One `agent_spawn` per session at its first row, then a start and an end event per row at the same time.
|
|
50
|
+
*/
|
|
51
|
+
export function toAgentFlow(events, salt) {
|
|
52
|
+
const rows = events
|
|
53
|
+
.map((e, i) => ({ e, i, ms: Date.parse(e.ts) }))
|
|
54
|
+
.filter((r) => Number.isFinite(r.ms))
|
|
55
|
+
.sort((a, b) => a.ms - b.ms || a.i - b.i);
|
|
56
|
+
if (rows.length === 0)
|
|
57
|
+
return [];
|
|
58
|
+
const t0 = rows[0].ms;
|
|
59
|
+
const seen = new Set();
|
|
60
|
+
const out = [];
|
|
61
|
+
for (const { e, ms } of rows) {
|
|
62
|
+
const time = (ms - t0) / 1000;
|
|
63
|
+
const agent = sessionHash(salt, e.product ?? "unknown", e.sessionId);
|
|
64
|
+
const device = typeof e.deviceId === "string" && DEVICE_ID.test(e.deviceId) ? { deviceId: e.deviceId } : {};
|
|
65
|
+
if (!seen.has(agent)) {
|
|
66
|
+
seen.add(agent);
|
|
67
|
+
out.push({ time, type: "agent_spawn", payload: { name: agent, sessionId: agent, ...device } });
|
|
68
|
+
}
|
|
69
|
+
const call = {
|
|
70
|
+
agent,
|
|
71
|
+
sessionId: agent,
|
|
72
|
+
tool: toolLabel(e.toolId),
|
|
73
|
+
verdict: e.verdict,
|
|
74
|
+
reasonCode: e.reasonCode,
|
|
75
|
+
targetClass: targetOf(e).cls,
|
|
76
|
+
mode: e.mode,
|
|
77
|
+
...device,
|
|
78
|
+
};
|
|
79
|
+
out.push({ time, type: "tool_call_start", payload: call });
|
|
80
|
+
out.push({ time, type: "tool_call_end", payload: call });
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
export async function runExport(opts, io, cwd, env) {
|
|
85
|
+
const salt = installSalt(env) ?? randomBytes(16).toString("hex");
|
|
86
|
+
const { events } = await loadTrailEvents({ path: trailPath(cwd, env), days: opts.days, now: new Date(), session: opts.session });
|
|
87
|
+
const lines = toAgentFlow(events, salt).map(jsonLine);
|
|
88
|
+
if (lines.length === 0) {
|
|
89
|
+
io.error(`No events in the last ${opts.days} days. Nothing to export.`);
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
const body = `${lines.join("\n")}\n`;
|
|
93
|
+
scanMapOutput(body);
|
|
94
|
+
if (opts.out === undefined) {
|
|
95
|
+
io.log(body.trimEnd());
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
const target = resolve(cwd, opts.out);
|
|
99
|
+
// The project root already exists. ensureOutDir would check the root's parent and refuse it.
|
|
100
|
+
if (resolve(dirname(target)) !== resolve(cwd))
|
|
101
|
+
ensureOutDir(dirname(target), cwd);
|
|
102
|
+
if (opts.force) {
|
|
103
|
+
// Atomic replace, owner read and write only, also when the old file was wider. A link at the target is replaced, not followed.
|
|
104
|
+
writeOutFile(target, body, cwd, 0o600);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Exclusive create: no window between a check and the write, and an existing file or symlink is never replaced.
|
|
108
|
+
const dest = underRoot(target, cwd) ? projectWritePath(target, cwd) : target;
|
|
109
|
+
try {
|
|
110
|
+
writeFileSync(dest, body, { flag: "wx", mode: 0o600 });
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
if (err.code === "EEXIST")
|
|
114
|
+
throw new UsageError(`${target} exists. Pass --force to replace it.`);
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
io.error(`${lines.length} lines written to ${target}`);
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/commands/hook.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/commands/hook.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAW3D,OAAO,EAAoH,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEzK,sFAAsF;AACtF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,4FAA4F;IAC5F,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,4EAA4E;IAC5E,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,iDAAiD;IACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,qGAAqG;IACrG,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,8GAA8G;IAC9G,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACvF,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,CAAC,EAAE,iBAAiB,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gGAAgG;IAChG,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAyRD,wBAAsB,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CA2HnE"}
|
package/dist/commands/hook.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* (Claude Code, Codex, Grok, Kimi Code; Gemini CLI BeforeTool). Default: offline local evaluate only, no
|
|
4
4
|
* network, sub-second, fail-open on any internal error unless --fail-closed.
|
|
5
5
|
* DENY (local never-list) blocks; REQUIRE_APPROVE records advisory unless
|
|
6
|
-
* --strict. With --plane-config (
|
|
6
|
+
* --strict. With --plane-config (preview) it evaluates on the hosted plane and
|
|
7
7
|
* fails closed (runHostedHook below; --plane-shadow records without blocking).
|
|
8
8
|
*/
|
|
9
9
|
import { createHash } from "node:crypto";
|
|
@@ -12,8 +12,12 @@ import { isAbsolute, join } from "node:path";
|
|
|
12
12
|
import { configFilePath, globalConfigDir, resolveConfig } from "../config.js";
|
|
13
13
|
import { runEvalTool } from "./eval-tool.js";
|
|
14
14
|
import { appendTrail, defaultSessionId, hostToProduct } from "../trail.js";
|
|
15
|
+
import { trailMapFields } from "../trail-map-fields.js";
|
|
15
16
|
import { deriveWireChangeFields } from "../diff-preview.js";
|
|
16
17
|
import { matchesNeverList } from "../offline-evaluate.js";
|
|
18
|
+
import { neverListInputMatch } from "../never-list-input.js";
|
|
19
|
+
import { GUARD_DEFAULTS, guardContextFrom, guardHint, guardPackMatch, readGuardConfig } from "../guard-pack.js";
|
|
20
|
+
import { isNeverCode } from "../never-code.js";
|
|
17
21
|
import { maybeSpawnNotifyFlush } from "../notify/dispatch.js";
|
|
18
22
|
import { computeArgsHash } from "../hash.js";
|
|
19
23
|
import { evaluateHosted, hostedDecision, hostedEnvProblem, loadPlaneConfig, PlaneError, scrubNetworkEnv } from "./hosted-hook.js";
|
|
@@ -54,7 +58,23 @@ function geminiMcpToolId(raw) {
|
|
|
54
58
|
const isBeforeTool = (event) => /^BeforeTool$/i.test(event ?? "");
|
|
55
59
|
/** Gemini CLI reads the decision from stdout JSON (`decision`), not hookSpecificOutput: `--host gemini` or a BeforeTool payload. */
|
|
56
60
|
const geminiShape = (input, p) => input.host.trim().toLowerCase() === "gemini" || isBeforeTool(p?.event);
|
|
57
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* Copilot CLI camelCase preToolUse sends `toolArgs` as a JSON string. Parse it so the
|
|
63
|
+
* input rules and the trail see an object; a bad string stays a string (the rules then
|
|
64
|
+
* fail open, as for any unparseable input). No size cap: the whole payload was already
|
|
65
|
+
* parsed above, and a cap here would let padding turn a long command into an allow.
|
|
66
|
+
*/
|
|
67
|
+
function parseToolArgs(v) {
|
|
68
|
+
if (typeof v !== "string")
|
|
69
|
+
return v;
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(v);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return v;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Accept snake_case (Claude/Kimi) and camelCase (Grok, Copilot) envelopes. */
|
|
58
78
|
function parsePayload(stdinText) {
|
|
59
79
|
let raw;
|
|
60
80
|
try {
|
|
@@ -87,11 +107,27 @@ function parsePayload(stdinText) {
|
|
|
87
107
|
toolUseId: (typeof p.tool_use_id === "string" && p.tool_use_id) ||
|
|
88
108
|
(typeof p.toolUseId === "string" && p.toolUseId) ||
|
|
89
109
|
undefined,
|
|
90
|
-
toolInput: p.tool_input ?? p.toolInput,
|
|
110
|
+
toolInput: p.tool_input ?? p.toolInput ?? parseToolArgs(p.toolArgs),
|
|
91
111
|
usage: readUsageShape(p.usage) ?? readUsageShape(toolResponse?.usage),
|
|
92
112
|
};
|
|
93
113
|
}
|
|
94
114
|
const ALLOW = { exitCode: 0, stdout: "", stderr: "" };
|
|
115
|
+
/**
|
|
116
|
+
* Deny text. An input-rule hit names its rule id; the never-list cannot be overridden. A guard pack
|
|
117
|
+
* hit names its rule id and says what to do instead. It does not say where the allowlist lives: that file
|
|
118
|
+
* is writable by the agent, so the text points at the docs for the person. Never carries command text,
|
|
119
|
+
* a path or a matched secret.
|
|
120
|
+
*/
|
|
121
|
+
function denyReason(toolName, reasonCode, ruleId) {
|
|
122
|
+
if (reasonCode === "NEVER_EVENT" && ruleId) {
|
|
123
|
+
return `KYA denied ${toolName}: NEVER_EVENT (rule ${ruleId}; never-list rules cannot be overridden)`;
|
|
124
|
+
}
|
|
125
|
+
if (isNeverCode(reasonCode) && reasonCode !== "NEVER_EVENT" && ruleId) {
|
|
126
|
+
const hint = guardHint(ruleId);
|
|
127
|
+
return `KYA denied ${toolName}: ${reasonCode} (${ruleId}).${hint ? ` ${hint}` : ""} Ask the user; see docs/guard-pack.md.`;
|
|
128
|
+
}
|
|
129
|
+
return `KYA denied ${toolName}: ${reasonCode}`;
|
|
130
|
+
}
|
|
95
131
|
function deny(reason, gemini = false) {
|
|
96
132
|
// Gemini parses stdout JSON whatever the exit code, and a JSON body without `decision` means allow.
|
|
97
133
|
const body = gemini
|
|
@@ -181,7 +217,7 @@ function withTimeout(p, ms) {
|
|
|
181
217
|
* deduped by the tool_use_id claim: the other hook copy may have recorded an
|
|
182
218
|
* ALLOW, and the trail must also show that this copy blocked the call.
|
|
183
219
|
*/
|
|
184
|
-
function auditedDeny(reason, reasonCode, input, payload, dedupe = false) {
|
|
220
|
+
function auditedDeny(reason, reasonCode, input, payload, dedupe = false, ruleId) {
|
|
185
221
|
try {
|
|
186
222
|
// Only for NEVER_EVENT: every hook copy reaches the same never-list verdict,
|
|
187
223
|
// so the claim only collapses duplicate rows/notifies and never the verdict.
|
|
@@ -198,17 +234,50 @@ function auditedDeny(reason, reasonCode, input, payload, dedupe = false) {
|
|
|
198
234
|
verdict: "DENY",
|
|
199
235
|
reasonCode,
|
|
200
236
|
mode: "offline",
|
|
201
|
-
neverEvent: reasonCode
|
|
237
|
+
neverEvent: isNeverCode(reasonCode),
|
|
238
|
+
...(ruleId ? { neverRule: ruleId } : {}),
|
|
239
|
+
...trailMapFields(payload?.toolName ?? "unknown", payload?.toolInput, trailCwd, input.env),
|
|
202
240
|
};
|
|
203
241
|
try {
|
|
204
242
|
appendTrail(trailCwd, ev, input.env);
|
|
205
243
|
}
|
|
206
244
|
catch { /* audit is best effort */ }
|
|
207
|
-
maybeSpawnNotifyFlush({ env: input.env, cwd: trailCwd, event: ev });
|
|
245
|
+
maybeSpawnNotifyFlush({ env: input.env, cwd: trailCwd, event: ev, projectDir: trailCwd });
|
|
208
246
|
}
|
|
209
247
|
catch { /* never block the deny itself */ }
|
|
210
248
|
return deny(reason, geminiShape(input, payload));
|
|
211
249
|
}
|
|
250
|
+
/** cwd and env for the guard pack: the host's cwd when it sent an absolute one, else the hook's. */
|
|
251
|
+
function guardContextFor(payload, input) {
|
|
252
|
+
const c = payload?.cwd?.trim();
|
|
253
|
+
return guardContextFrom(c && isAbsolute(c) ? c : input.cwd, input.env);
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* A malformed guard config falls back to the defaults. Say so once an hour in the trail, so a person
|
|
257
|
+
* who edited `~/.kya/config.json` and sees no effect can find out why. Never throws.
|
|
258
|
+
*/
|
|
259
|
+
function noteGuardConfigProblem(ctx, input, payload) {
|
|
260
|
+
try {
|
|
261
|
+
const { problem } = readGuardConfig(ctx.home);
|
|
262
|
+
if (!problem)
|
|
263
|
+
return;
|
|
264
|
+
const hour = new Date().toISOString().slice(0, 13);
|
|
265
|
+
if (!claimToolUse(`guard-config:${hour}`, undefined, input.env))
|
|
266
|
+
return;
|
|
267
|
+
appendTrail(payload?.cwd?.trim() || input.cwd, {
|
|
268
|
+
ts: new Date().toISOString(),
|
|
269
|
+
sessionId: payload?.sessionId ?? defaultSessionId(input.env),
|
|
270
|
+
host: "ide",
|
|
271
|
+
product: hostToProduct(input.host),
|
|
272
|
+
toolId: "kya:guard-config",
|
|
273
|
+
verdict: "ALLOW",
|
|
274
|
+
reasonCode: "GUARD_CONFIG_INVALID",
|
|
275
|
+
mode: "offline",
|
|
276
|
+
summary: `guard config ignored (${problem}); defaults in force`,
|
|
277
|
+
}, input.env);
|
|
278
|
+
}
|
|
279
|
+
catch { /* best effort */ }
|
|
280
|
+
}
|
|
212
281
|
// Non-PreToolUse hook events that legitimately carry no gate decision.
|
|
213
282
|
const OTHER_EVENT = /^(post[_-]?tool[_-]?use.*|stop|subagent[_-]?(start|stop)|permission[_-]?request|elicitation.*|session[_-]?(start|end)|user[_-]?prompt[_-]?submit|notification|pre[_-]?compact)$/i;
|
|
214
283
|
export async function runHook(input) {
|
|
@@ -248,8 +317,10 @@ export async function runHook(input) {
|
|
|
248
317
|
config = resolve({ host: "ide" });
|
|
249
318
|
}
|
|
250
319
|
const cfg = config;
|
|
320
|
+
const guardCtx = guardContextFor(payload, input);
|
|
321
|
+
noteGuardConfigProblem(guardCtx, input, payload);
|
|
251
322
|
const evaluate = input.evaluate ??
|
|
252
|
-
(async (toolId, args) => (await runEvalTool(cfg, { toolId, args, offline: true })).response);
|
|
323
|
+
(async (toolId, args) => (await runEvalTool(cfg, { toolId, args, offline: true, guard: guardCtx })).response);
|
|
253
324
|
const evaluating = Promise.resolve().then(() => evaluate(toolName, payload?.toolInput ?? {}));
|
|
254
325
|
const response = input.failClosed
|
|
255
326
|
? await withTimeout(evaluating, input.evalTimeoutMs ?? 4000)
|
|
@@ -261,9 +332,12 @@ export async function runHook(input) {
|
|
|
261
332
|
// payload.cwd is host-supplied and only feeds the project-basename stamp;
|
|
262
333
|
// the trail path itself comes from env/KYA_HOME - no traversal risk.
|
|
263
334
|
const trailCwd = payload.cwd?.trim() || input.cwd;
|
|
335
|
+
// Map fields come from the raw input, before the secret strip below: a never deny or a secret read keeps its class.
|
|
336
|
+
const mapFields = trailMapFields(toolName, payload.toolInput ?? {}, trailCwd, input.env);
|
|
264
337
|
// Wire change fields (summary, diffPreview, targetPath) feed the receipt's
|
|
265
338
|
// Changes tab; redaction + opt-out live inside deriveWireChangeFields.
|
|
266
|
-
|
|
339
|
+
// A secret-shaped write is denied because its text is a secret: no preview of that text reaches the trail.
|
|
340
|
+
const changeFields = response.reasonCode === "NEVER_SECRET_WRITE" ? undefined : deriveWireChangeFields(toolName, payload.toolInput ?? {}, input.env);
|
|
267
341
|
const trailEvent = {
|
|
268
342
|
ts: new Date().toISOString(),
|
|
269
343
|
sessionId: payload.sessionId ?? defaultSessionId(input.env),
|
|
@@ -273,8 +347,10 @@ export async function runHook(input) {
|
|
|
273
347
|
verdict: response.verdict,
|
|
274
348
|
reasonCode: response.reasonCode ?? "",
|
|
275
349
|
mode: "offline",
|
|
276
|
-
neverEvent: response.reasonCode
|
|
350
|
+
neverEvent: isNeverCode(response.reasonCode),
|
|
351
|
+
...(response.ruleId ? { neverRule: response.ruleId } : {}),
|
|
277
352
|
argsHash: response.argsHash,
|
|
353
|
+
...mapFields,
|
|
278
354
|
...(changeFields ?? {}),
|
|
279
355
|
...(payload.usage?.tokensIn !== undefined ? { tokensIn: payload.usage.tokensIn } : {}),
|
|
280
356
|
...(payload.usage?.tokensOut !== undefined ? { tokensOut: payload.usage.tokensOut } : {}),
|
|
@@ -289,14 +365,14 @@ export async function runHook(input) {
|
|
|
289
365
|
}
|
|
290
366
|
// Webhooks + OTLP export ride a detached helper; the hook never waits on
|
|
291
367
|
// the network. No-op unless a sink is configured.
|
|
292
|
-
maybeSpawnNotifyFlush({ env: input.env, cwd: trailCwd, event: trailEvent });
|
|
368
|
+
maybeSpawnNotifyFlush({ env: input.env, cwd: trailCwd, event: trailEvent, projectDir: trailCwd });
|
|
293
369
|
}
|
|
294
370
|
}
|
|
295
371
|
catch {
|
|
296
372
|
/* observe path never breaks the gate */
|
|
297
373
|
}
|
|
298
374
|
if (response.verdict === "DENY") {
|
|
299
|
-
return { ...deny(
|
|
375
|
+
return { ...deny(denyReason(toolName, response.reasonCode, response.ruleId), geminiShape(input, payload)), firstSeen };
|
|
300
376
|
}
|
|
301
377
|
if (input.strict && response.verdict === "REQUIRE_APPROVE") {
|
|
302
378
|
return { ...deny(`KYA strict mode: ${toolName} requires approval (${response.reasonCode})`, geminiShape(input, payload)), firstSeen };
|
|
@@ -311,8 +387,16 @@ export async function runHook(input) {
|
|
|
311
387
|
// --fail-closed (hosted): enforcement must not silently lapse.
|
|
312
388
|
try {
|
|
313
389
|
// A never-list tool is logged as such in both modes (hosted counts stay right).
|
|
314
|
-
if (payload?.toolName
|
|
315
|
-
|
|
390
|
+
if (payload?.toolName) {
|
|
391
|
+
const inputHit = neverListInputMatch(payload.toolName, payload.toolInput, undefined, payload.cwd?.trim() || input.cwd);
|
|
392
|
+
if (inputHit || matchesNeverList(payload.toolName)) {
|
|
393
|
+
return auditedDeny(denyReason(payload.toolName, "NEVER_EVENT", inputHit?.rule), "NEVER_EVENT", input, payload, true, inputHit?.rule);
|
|
394
|
+
}
|
|
395
|
+
// Guard pack with its defaults: the fallback never reads config, so a broken or hostile one cannot lift a deny here.
|
|
396
|
+
const guardHit = guardPackMatch(payload.toolName, payload.toolInput, guardContextFor(payload, input), GUARD_DEFAULTS);
|
|
397
|
+
if (guardHit) {
|
|
398
|
+
return auditedDeny(denyReason(payload.toolName, guardHit.code, guardHit.rule), guardHit.code, input, payload, true, guardHit.rule);
|
|
399
|
+
}
|
|
316
400
|
}
|
|
317
401
|
}
|
|
318
402
|
catch { /* fall through */ }
|
|
@@ -325,8 +409,10 @@ export async function runHook(input) {
|
|
|
325
409
|
/** Env that steers the OSS hook and is ignored in hosted mode (design T2/T3). */
|
|
326
410
|
const HOSTED_IGNORED_ENV = ["KYA_OFFLINE", "KYA_BASE_URL", "KYA_API_KEY", "SHIELD_API_KEY", "KYA_AGENT_ID", "KYA_HOME", "KYA_HOST", "KYA_NOTIFY_WEBHOOK", "KYA_OTLP_EXPORT_ENDPOINT"];
|
|
327
411
|
/**
|
|
328
|
-
* Hosted mode. Order: payload, local never-list, env and config checks, plane
|
|
329
|
-
* call, then a raise-only merge in which the local never-list always
|
|
412
|
+
* Hosted mode. Order: payload, local never-list, local guard pack, env and config checks, plane
|
|
413
|
+
* call, then a raise-only merge in which the local never-list, then the guard pack, always win.
|
|
414
|
+
* The guard pack has the same rules, codes and user-level config as the local hook; only the
|
|
415
|
+
* failure stance differs (hosted fails closed).
|
|
330
416
|
* Every failure is a deny (fail-closed) unless --plane-shadow, which records
|
|
331
417
|
* the would-be verdict and allows. Nothing here reads resolveConfig, the repo's
|
|
332
418
|
* .kya/config.json or KYA_* env, so none of them can downgrade this path.
|
|
@@ -350,6 +436,8 @@ async function runHostedHook(input, plane) {
|
|
|
350
436
|
stderrNotes.push("KYA hosted mode: KYA_* env and the project .kya/config.json are ignored");
|
|
351
437
|
// Crash path state: unknown until the local never-list has been evaluated below.
|
|
352
438
|
hostedDecision.neverList = "unknown";
|
|
439
|
+
hostedDecision.code = undefined;
|
|
440
|
+
hostedDecision.rule = undefined;
|
|
353
441
|
let payload;
|
|
354
442
|
let verdict;
|
|
355
443
|
let response;
|
|
@@ -367,15 +455,28 @@ async function runHostedHook(input, plane) {
|
|
|
367
455
|
}
|
|
368
456
|
const toolName = payload?.toolName;
|
|
369
457
|
let neverListed = false;
|
|
370
|
-
|
|
371
|
-
|
|
458
|
+
let neverRule;
|
|
459
|
+
let guardHit;
|
|
460
|
+
// The local never-list and the guard pack run first, before any env, config or plane code, and
|
|
461
|
+
// are stored so a crash later can never lower them (crashDecision). A throw leaves it "unknown",
|
|
462
|
+
// which denies. The guard config is the user-level file under the hosted $HOME only.
|
|
372
463
|
try {
|
|
373
464
|
if (toolName) {
|
|
374
|
-
|
|
375
|
-
|
|
465
|
+
neverRule = neverListInputMatch(toolName, payload?.toolInput, undefined, payload?.cwd?.trim() || input.cwd)?.rule;
|
|
466
|
+
neverListed = matchesNeverList(toolName) || neverRule !== undefined;
|
|
467
|
+
if (!neverListed) {
|
|
468
|
+
const ctx = guardContextFor(payload, input);
|
|
469
|
+
guardHit = guardPackMatch(toolName, payload?.toolInput, ctx, readGuardConfig(ctx.home).config);
|
|
470
|
+
if (homeOk)
|
|
471
|
+
noteGuardConfigProblem(ctx, { ...input, env: stateEnv }, payload);
|
|
472
|
+
}
|
|
473
|
+
hostedDecision.neverList = neverListed || guardHit ? "deny" : "clear";
|
|
474
|
+
hostedDecision.code = neverListed ? "NEVER_EVENT" : guardHit?.code;
|
|
475
|
+
hostedDecision.rule = neverListed ? neverRule : guardHit?.rule;
|
|
376
476
|
}
|
|
377
477
|
}
|
|
378
478
|
catch { /* stays unknown */ }
|
|
479
|
+
const localDeny = neverListed || guardHit !== undefined;
|
|
379
480
|
if (!payload || !toolName) {
|
|
380
481
|
verdict = {
|
|
381
482
|
verdict: "DENY",
|
|
@@ -413,6 +514,7 @@ async function runHostedHook(input, plane) {
|
|
|
413
514
|
now: plane.now,
|
|
414
515
|
sleep: plane.sleep,
|
|
415
516
|
random: plane.random,
|
|
517
|
+
withholdChange: guardHit?.code === "NEVER_SECRET_WRITE",
|
|
416
518
|
});
|
|
417
519
|
}
|
|
418
520
|
catch (e) {
|
|
@@ -422,7 +524,10 @@ async function runHostedHook(input, plane) {
|
|
|
422
524
|
}
|
|
423
525
|
// Raise-only merge: the local never-list beats any plane answer or failure.
|
|
424
526
|
if (neverListed) {
|
|
425
|
-
verdict = { verdict: "DENY", reasonCode: "NEVER_EVENT", reason:
|
|
527
|
+
verdict = { verdict: "DENY", reasonCode: "NEVER_EVENT", reason: denyReason(toolName, "NEVER_EVENT", neverRule), dedupe: true, ruleId: neverRule };
|
|
528
|
+
}
|
|
529
|
+
else if (guardHit) {
|
|
530
|
+
verdict = { verdict: "DENY", reasonCode: guardHit.code, reason: denyReason(toolName, guardHit.code, guardHit.rule), dedupe: true, ruleId: guardHit.rule };
|
|
426
531
|
}
|
|
427
532
|
else if (failure || !response) {
|
|
428
533
|
const f = failure ?? { code: "FAIL_CLOSED", message: "internal error" };
|
|
@@ -442,9 +547,9 @@ async function runHostedHook(input, plane) {
|
|
|
442
547
|
}
|
|
443
548
|
const blocks = verdict.verdict === "DENY" ||
|
|
444
549
|
(input.strict && verdict.verdict === "REQUIRE_APPROVE");
|
|
445
|
-
// Shadow never blocks, except the LOCAL never-list. Keyed to the local evaluation,
|
|
446
|
-
// plane's reason code: the plane answers NEVER_EVENT for every registered DENY-tier tool.
|
|
447
|
-
const enforce = blocks && (!plane.shadow ||
|
|
550
|
+
// Shadow never blocks, except the LOCAL never-list and guard pack. Keyed to the local evaluation,
|
|
551
|
+
// never to the plane's reason code: the plane answers NEVER_EVENT for every registered DENY-tier tool.
|
|
552
|
+
const enforce = blocks && (!plane.shadow || localDeny);
|
|
448
553
|
let firstSeen = true;
|
|
449
554
|
try {
|
|
450
555
|
firstSeen = recordHostedRow(input, stateEnv, homeOk, home, payload, verdict, response, plane.shadow, configIgnored);
|
|
@@ -482,7 +587,8 @@ function recordHostedRow(input, stateEnv, homeOk, home, payload, verdict, respon
|
|
|
482
587
|
let changeFields;
|
|
483
588
|
try {
|
|
484
589
|
argsHash ??= payload?.toolName ? computeArgsHash(payload.toolInput ?? {}) : undefined;
|
|
485
|
-
|
|
590
|
+
// A secret-shaped write is denied because its text is a secret: no preview of that text reaches the trail.
|
|
591
|
+
changeFields = payload?.toolName && verdict.reasonCode !== "NEVER_SECRET_WRITE" ? deriveWireChangeFields(toolName, payload.toolInput ?? {}, input.env) : undefined;
|
|
486
592
|
}
|
|
487
593
|
catch { /* row without hash or preview */ }
|
|
488
594
|
const ev = {
|
|
@@ -494,8 +600,10 @@ function recordHostedRow(input, stateEnv, homeOk, home, payload, verdict, respon
|
|
|
494
600
|
verdict: verdict.verdict,
|
|
495
601
|
reasonCode: verdict.reasonCode,
|
|
496
602
|
mode: input.strict ? "hold" : "observe",
|
|
497
|
-
neverEvent: verdict.reasonCode
|
|
603
|
+
neverEvent: isNeverCode(verdict.reasonCode),
|
|
604
|
+
...(verdict.ruleId ? { neverRule: verdict.ruleId } : {}),
|
|
498
605
|
...(argsHash ? { argsHash } : {}),
|
|
606
|
+
...trailMapFields(toolName, payload?.toolInput, payload?.cwd?.trim() || input.cwd, stateEnv),
|
|
499
607
|
...(changeFields ?? {}),
|
|
500
608
|
...(payload?.usage?.tokensIn !== undefined ? { tokensIn: payload.usage.tokensIn } : {}),
|
|
501
609
|
...(payload?.usage?.tokensOut !== undefined ? { tokensOut: payload.usage.tokensOut } : {}),
|
|
@@ -507,7 +615,8 @@ function recordHostedRow(input, stateEnv, homeOk, home, payload, verdict, respon
|
|
|
507
615
|
}
|
|
508
616
|
catch { /* best effort */ }
|
|
509
617
|
// cwd = home: only the user-level notify config applies, never a repo's sinks.
|
|
510
|
-
|
|
618
|
+
// projectDir is the call's project, so the map-attribute opt-in check sees the repo even though cwd is home.
|
|
619
|
+
maybeSpawnNotifyFlush({ env: stateEnv, cwd: home, event: ev, projectDir: payload?.cwd?.trim() || input.cwd });
|
|
511
620
|
return true;
|
|
512
621
|
}
|
|
513
622
|
//# sourceMappingURL=hook.js.map
|