@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,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads the map for one trail: streams the file, filters one session, builds the graph and the heat views.
|
|
3
|
+
* Shared by `kya map` and the live report, so both show the same numbers.
|
|
4
|
+
*/
|
|
5
|
+
import { type TrailRead } from "./build.js";
|
|
6
|
+
import { type Heat } from "./heat.js";
|
|
7
|
+
import type { MapGraph, TrailEventLike } from "./types.js";
|
|
8
|
+
/** The When view is always seven days, so the read covers at least seven. */
|
|
9
|
+
export declare const HEAT_DAYS = 7;
|
|
10
|
+
export interface LoadMapOptions {
|
|
11
|
+
readonly path: string;
|
|
12
|
+
/** Graph window in days. */
|
|
13
|
+
readonly days: number;
|
|
14
|
+
readonly now: Date;
|
|
15
|
+
/** Per-install salt for sessionHash. */
|
|
16
|
+
readonly salt: string;
|
|
17
|
+
readonly session?: string;
|
|
18
|
+
/** Offset east of UTC in minutes, for the When view. */
|
|
19
|
+
readonly tzOffsetMinutes: number;
|
|
20
|
+
}
|
|
21
|
+
export interface LoadedMap {
|
|
22
|
+
readonly graph: MapGraph;
|
|
23
|
+
readonly heat: Heat;
|
|
24
|
+
/** Events in the graph window (after the session filter). */
|
|
25
|
+
readonly windowEvents: number;
|
|
26
|
+
}
|
|
27
|
+
/** Rows of the last `days` days, one session when `session` is set. Shared by `kya map` and `kya export`. */
|
|
28
|
+
export declare function loadTrailEvents(opts: {
|
|
29
|
+
path: string;
|
|
30
|
+
days: number;
|
|
31
|
+
now: Date;
|
|
32
|
+
session?: string;
|
|
33
|
+
}): Promise<{
|
|
34
|
+
read: TrailRead;
|
|
35
|
+
events: TrailEventLike[];
|
|
36
|
+
}>;
|
|
37
|
+
export declare function loadMap(opts: LoadMapOptions): Promise<LoadedMap>;
|
|
38
|
+
//# sourceMappingURL=load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/map/load.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAA2B,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAa,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE3D,6EAA6E;AAC7E,eAAO,MAAM,SAAS,IAAI,CAAC;AAE3B,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4BAA4B;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;IACnB,wCAAwC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,6DAA6D;IAC7D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAcD,6GAA6G;AAC7G,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,cAAc,EAAE,CAAA;CAAE,CAAC,CAG/J;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC,CAWtE"}
|
package/dist/map/load.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loads the map for one trail: streams the file, filters one session, builds the graph and the heat views.
|
|
3
|
+
* Shared by `kya map` and the live report, so both show the same numbers.
|
|
4
|
+
*/
|
|
5
|
+
import { buildMap, readTrailFile } from "./build.js";
|
|
6
|
+
import { buildHeat } from "./heat.js";
|
|
7
|
+
/** The When view is always seven days, so the read covers at least seven. */
|
|
8
|
+
export const HEAT_DAYS = 7;
|
|
9
|
+
const EMPTY_READ = { events: [], rowsRead: 0, rowsSkipped: 0, rowsOutOfWindow: 0 };
|
|
10
|
+
/** A missing trail is an empty trail. Any other read error is thrown. */
|
|
11
|
+
async function readOrEmpty(path, days, now) {
|
|
12
|
+
try {
|
|
13
|
+
return await readTrailFile(path, { days, now });
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
if (err?.code === "ENOENT")
|
|
17
|
+
return EMPTY_READ;
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Rows of the last `days` days, one session when `session` is set. Shared by `kya map` and `kya export`. */
|
|
22
|
+
export async function loadTrailEvents(opts) {
|
|
23
|
+
const read = await readOrEmpty(opts.path, opts.days, opts.now);
|
|
24
|
+
return { read, events: opts.session ? read.events.filter((e) => e.sessionId === opts.session) : read.events };
|
|
25
|
+
}
|
|
26
|
+
export async function loadMap(opts) {
|
|
27
|
+
const { read, events } = await loadTrailEvents({ path: opts.path, days: Math.max(opts.days, HEAT_DAYS), now: opts.now, session: opts.session });
|
|
28
|
+
const graph = buildMap(events, {
|
|
29
|
+
salt: opts.salt,
|
|
30
|
+
now: opts.now,
|
|
31
|
+
days: opts.days,
|
|
32
|
+
read: { rowsRead: read.rowsRead, rowsSkipped: read.rowsSkipped, rowsOutOfWindow: read.rowsOutOfWindow },
|
|
33
|
+
});
|
|
34
|
+
const heat = buildHeat(events, { now: opts.now, days: HEAT_DAYS, tzOffsetMinutes: opts.tzOffsetMinutes });
|
|
35
|
+
const windowEvents = graph.nodes.filter((n) => n.kind === "device").reduce((s, n) => s + n.count, 0);
|
|
36
|
+
return { graph, heat, windowEvents };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=load.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/map/load.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAkB,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,SAAS,EAAa,MAAM,WAAW,CAAC;AAGjD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC;AAqB3B,MAAM,UAAU,GAAc,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC;AAE9F,yEAAyE;AACzE,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,IAAY,EAAE,GAAS;IAC9D,IAAI,CAAC;QACH,OAAO,MAAM,aAAa,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,EAAE,IAAI,KAAK,QAAQ;YAAE,OAAO,UAAU,CAAC;QACzE,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,6GAA6G;AAC7G,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAiE;IACrG,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;AAChH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAoB;IAChD,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAChJ,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE;QAC7B,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE;KACxG,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;IAC1G,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACrG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Heat } from "./heat.js";
|
|
2
|
+
import type { MapGraph, Verdicts } from "./types.js";
|
|
3
|
+
/** The one line that says what the map is not. Shown on every map page. */
|
|
4
|
+
export declare const ADVISORY_LINE = "Recorded by KYA. The open source check is advisory; this map shows what was recorded, not what was enforced.";
|
|
5
|
+
/** Edge colours by dominant verdict. Deny beats hold, hold beats observed, observed beats allow (schema section 3). */
|
|
6
|
+
export declare const TONE_COLOUR: {
|
|
7
|
+
readonly deny: "#b42318";
|
|
8
|
+
readonly hold: "#b54708";
|
|
9
|
+
readonly observed: "#667085";
|
|
10
|
+
readonly allow: "#067647";
|
|
11
|
+
};
|
|
12
|
+
export type EdgeTone = keyof typeof TONE_COLOUR;
|
|
13
|
+
/** Tone of an edge from its verdict counts. Any deny makes the edge red. */
|
|
14
|
+
export declare function edgeTone(v: Verdicts): EdgeTone;
|
|
15
|
+
/** Edge width grows with log(count): 1 for one event, about 3 for 10, about 5 for 100. */
|
|
16
|
+
export declare function edgeWidth(count: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* JSON for a `<script type="application/json">` body. `<`, `>` and `&` and the two line separators become
|
|
19
|
+
* \u escapes, so the text can never close the script element or start a tag. JSON.parse reads them back unchanged.
|
|
20
|
+
*/
|
|
21
|
+
export declare function jsonForScript(value: unknown): string;
|
|
22
|
+
export declare function scanMapOutput(text: string): void;
|
|
23
|
+
/** HTML text and attribute escape. */
|
|
24
|
+
export declare function esc(s: string): string;
|
|
25
|
+
/** Data the draw script reads: nodes with a label and detail, edges with tone and width (computed here, not in the browser). */
|
|
26
|
+
export declare function drawModel(graph: MapGraph): {
|
|
27
|
+
colours: {
|
|
28
|
+
readonly deny: "#b42318";
|
|
29
|
+
readonly hold: "#b54708";
|
|
30
|
+
readonly observed: "#667085";
|
|
31
|
+
readonly allow: "#067647";
|
|
32
|
+
};
|
|
33
|
+
nodes: {
|
|
34
|
+
id: string;
|
|
35
|
+
kind: "target" | "agent" | "device" | "tool";
|
|
36
|
+
label: string;
|
|
37
|
+
detail: string;
|
|
38
|
+
count: number;
|
|
39
|
+
verdicts: Verdicts;
|
|
40
|
+
firstTs: string;
|
|
41
|
+
lastTs: string;
|
|
42
|
+
}[];
|
|
43
|
+
edges: {
|
|
44
|
+
id: string;
|
|
45
|
+
source: string;
|
|
46
|
+
target: string;
|
|
47
|
+
kind: "runs" | "uses" | "touches";
|
|
48
|
+
tool: string | null;
|
|
49
|
+
tone: "hold" | "deny" | "allow" | "observed";
|
|
50
|
+
colour: "#b42318" | "#b54708" | "#667085" | "#067647";
|
|
51
|
+
width: number;
|
|
52
|
+
count: number;
|
|
53
|
+
verdicts: Verdicts;
|
|
54
|
+
firstTs: string;
|
|
55
|
+
lastTs: string;
|
|
56
|
+
}[];
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* The page body: summary, graph container, side panel, both heat tables, and the data. Used inside the standalone
|
|
60
|
+
* file and as the live report's Map fragment. The graph is drawn by MAP_SCRIPT from the data element.
|
|
61
|
+
*/
|
|
62
|
+
export declare function renderMapBody(graph: MapGraph, heat: Heat, days: number): string;
|
|
63
|
+
/** The vendored Cytoscape.js (MIT, see vendor/cytoscape/LICENSE). `</script` is broken so it cannot end the element. */
|
|
64
|
+
export declare function cytoscapeSource(): string;
|
|
65
|
+
/** Content-Security-Policy for the standalone file. No network: default-src none. */
|
|
66
|
+
export declare const MAP_CSP = "default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; img-src data:";
|
|
67
|
+
/**
|
|
68
|
+
* The browser part. Labels go to Cytoscape (canvas) or textContent. The live body is parsed with DOMParser (the body
|
|
69
|
+
* has no executable script), so this file never assigns innerHTML.
|
|
70
|
+
*/
|
|
71
|
+
export declare const MAP_SCRIPT = "(function () {\n 'use strict';\n var cy = null;\n var last = null;\n var live = !!document.querySelector('main[data-live-token]');\n function token() {\n var m = /(?:^|[?&])t=([^&]*)/.exec(location.search);\n if (!m) return '';\n try { return decodeURIComponent(m[1]); } catch (e) { return m[1]; }\n }\n function model() {\n var el = document.getElementById('kya-map-data');\n if (!el) return null;\n try { return JSON.parse(el.textContent || 'null'); } catch (e) { return null; }\n }\n function add(parent, tag, text) {\n var n = document.createElement(tag);\n n.textContent = String(text);\n parent.appendChild(n);\n return n;\n }\n function showNode(node) {\n var panel = document.getElementById('kya-map-panel');\n if (!panel) return;\n while (panel.firstChild) panel.removeChild(panel.firstChild);\n add(panel, 'h3', node.kind + ': ' + node.label);\n add(panel, 'p', 'Class: ' + node.detail);\n var list = document.createElement('dl');\n panel.appendChild(list);\n [['Events', node.count], ['Allow', node.verdicts.allow], ['Deny', node.verdicts.deny], ['Hold', node.verdicts.hold],\n ['Observed', node.verdicts.observed], ['First seen', node.firstTs || '-'], ['Last seen', node.lastTs || '-']]\n .forEach(function (r) { add(list, 'dt', r[0]); add(list, 'dd', r[1]); });\n }\n function style(d) {\n var out = [\n { selector: 'node', style: { 'label': 'data(label)', 'font-size': 10, 'text-wrap': 'ellipsis', 'text-max-width': 130, 'min-zoomed-font-size': 9,\n 'text-background-color': '#ffffff', 'text-background-opacity': 0.8, 'text-background-padding': 1,\n 'width': 18, 'height': 18, 'background-color': '#98a2b3', 'color': '#101828' } },\n { selector: 'node[kind = \"device\"]', style: { 'background-color': '#344054', 'shape': 'round-rectangle', 'width': 34, 'height': 34 } },\n { selector: 'node[kind = \"agent\"]', style: { 'background-color': '#1d4ed8' } },\n { selector: 'node[kind = \"tool\"]', style: { 'background-color': '#7a5af8', 'shape': 'round-rectangle' } },\n { selector: 'node[kind = \"target\"]', style: { 'background-color': '#0e9384' } },\n { selector: 'edge', style: { 'width': 'data(width)', 'line-color': 'data(colour)', 'target-arrow-color': 'data(colour)',\n 'target-arrow-shape': 'triangle', 'curve-style': 'bezier', 'opacity': 0.9 } }\n ];\n return out;\n }\n var MAX_DRAW_NODES = 400;\n function draw() {\n var host = document.getElementById('kya-map-graph');\n var d = model();\n if (cy) { cy.destroy(); cy = null; }\n if (!host || !d || !window.cytoscape || !d.nodes || !d.nodes.length) return;\n // A force layout on thousands of nodes hangs the tab. The JSON and both heat views still hold everything.\n if (d.nodes.length > MAX_DRAW_NODES) {\n host.textContent = 'Graph not drawn: ' + d.nodes.length + ' nodes is too many for the page. Use a shorter window (kya map --days 1) or kya map --json.';\n return;\n }\n cy = window.cytoscape({\n container: host,\n elements: {\n nodes: d.nodes.map(function (n) { return { data: n }; }),\n edges: d.edges.map(function (e) { return { data: e }; })\n },\n style: style(d),\n layout: { name: 'cose', animate: false, randomize: true, fit: true, padding: 24, numIter: 900, nodeRepulsion: function () { return 9000; }, idealEdgeLength: function () { return 80; }, nodeOverlap: 14, gravity: 0.35 }\n });\n cy.on('tap', 'node', function (evt) { showNode(evt.target.data()); });\n cy.fit();\n }\n function refresh() {\n if (!live) return;\n var host = document.getElementById('frag-map');\n if (!host) return;\n fetch('/fragments?t=' + encodeURIComponent(token()), {\n method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{\"map\":true}'\n })\n .then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); })\n .then(function (j) {\n if (!j || !j.ok || !j.fragments || typeof j.fragments.mapBody !== 'string') return;\n if (j.fragments.mapBody === last) return;\n last = j.fragments.mapBody;\n var doc = new DOMParser().parseFromString(j.fragments.mapBody, 'text/html');\n var nodes = Array.prototype.slice.call(doc.body.childNodes);\n while (host.firstChild) host.removeChild(host.firstChild);\n nodes.forEach(function (n) { host.appendChild(n); });\n draw();\n })\n .catch(function (err) { console.error('KYA map refresh failed', err); });\n }\n // Live only: fetch the vendored library with the token from this page's URL, then run it as a script element.\n function loadLibrary(next) {\n if (window.cytoscape) { next(); return; }\n fetch('/vendor/cytoscape.min.js?t=' + encodeURIComponent(token()))\n .then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.text(); })\n .then(function (text) {\n var s = document.createElement('script');\n s.id = 'kya-cytoscape';\n s.textContent = text;\n document.head.appendChild(s);\n next();\n })\n .catch(function (err) { console.error('KYA map library failed', err); });\n }\n window.kyaMapRefresh = refresh;\n window.addEventListener('hashchange', function () {\n if (location.hash !== '#map') return;\n refresh();\n setTimeout(function () { if (cy) { cy.resize(); cy.fit(); } }, 0);\n });\n if (live) loadLibrary(refresh); else draw();\n})();";
|
|
72
|
+
/**
|
|
73
|
+
* Live report: the draw script, in the page shell (not in the swapped fragment). The script reads the token from its
|
|
74
|
+
* own URL and fetches the library from /vendor/cytoscape.min.js, so the token never appears in the HTML.
|
|
75
|
+
*/
|
|
76
|
+
export declare function liveMapScripts(): string;
|
|
77
|
+
/** Map components. Shared by the standalone file and the live report, so it uses the report's tokens (--line, --mute, --fg, --bg). */
|
|
78
|
+
export declare const MAP_CSS = "\n .map-body .map-advisory { border-left: 3px solid var(--line, #d0d5dd); padding: 4px 10px; font-weight: 600; }\n .map-body .mute { color: var(--mute, #667085); }\n .map-stats p { margin: 4px 0; }\n .map-top { margin: 4px 0 12px 20px; padding: 0; }\n .map-canvas { display: grid; grid-template-columns: minmax(0, 1fr) 260px; gap: 12px; margin: 12px 0; }\n .map-graph { height: 60vh; min-height: 360px; border: 1px solid var(--line, #d0d5dd); border-radius: 6px; }\n .map-panel { border: 1px solid var(--line, #d0d5dd); border-radius: 6px; padding: 8px 12px; overflow: auto; }\n .map-panel dl { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; }\n .map-panel dt { color: var(--mute, #667085); }\n .map-panel dd { margin: 0; }\n .map-scroll { overflow-x: auto; }\n .map-heat { border-collapse: collapse; font-size: 12px; margin-bottom: 12px; }\n .map-heat caption { text-align: left; color: var(--mute, #667085); padding: 4px 0; }\n .map-heat th, .map-heat td { border: 1px solid var(--line, #d0d5dd); padding: 3px 5px; text-align: right; min-width: 22px; }\n .map-heat th { text-align: left; font-weight: 600; }\n .map-heat td.l0 { background: transparent; }\n .map-heat td.l1 { background: #d1fadf; color: #101828; }\n .map-heat td.l2 { background: #75e0a7; color: #101828; }\n .map-heat td.l3 { background: #12b76a; color: #fff; }\n .map-heat td.l4 { background: #027a48; color: #fff; }\n .map-heat td.deny { outline: 2px solid #b42318; outline-offset: -2px; }\n .map-empty { font-weight: 600; }\n @media (max-width: 760px) { .map-canvas { grid-template-columns: 1fr; } }\n";
|
|
79
|
+
/** Live report: the Map zone shows only on its tab (same :target rule as the other zones). */
|
|
80
|
+
export declare const MAP_LIVE_ZONE_CSS = "\n @supports selector(body:has(*)) {\n #map { display: none; }\n #map:target { display: block; }\n body:has(#map:target) #overview { display: none; }\n body:has(#map:target) .nav-link[href=\"#map\"] { color: var(--fg); background: var(--bg); border-color: var(--line); }\n }\n";
|
|
81
|
+
/** Standalone file only: its own tokens and page frame (the live report has its own). */
|
|
82
|
+
export declare const MAP_PAGE_CSS = "\n :root { --fg: #101828; --mute: #667085; --line: #d0d5dd; --bg: #ffffff; }\n @media (prefers-color-scheme: dark) { :root:not([data-theme=\"light\"]) { --fg: #f2f4f7; --mute: #98a2b3; --line: #344054; --bg: #101828; } }\n :root[data-theme=\"dark\"] { --fg: #f2f4f7; --mute: #98a2b3; --line: #344054; --bg: #101828; }\n body { background: var(--bg); color: var(--fg); font: 14px/1.45 system-ui, sans-serif; margin: 0; }\n .map-page { max-width: 1100px; margin: 0 auto; padding: 16px; }\n";
|
|
83
|
+
/** Standalone file: one page, no network, CSP on. */
|
|
84
|
+
export declare function renderMapPage(input: {
|
|
85
|
+
graph: MapGraph;
|
|
86
|
+
heat: Heat;
|
|
87
|
+
days: number;
|
|
88
|
+
title: string;
|
|
89
|
+
}): string;
|
|
90
|
+
//# sourceMappingURL=page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../src/map/page.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,QAAQ,EAAW,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE9D,2EAA2E;AAC3E,eAAO,MAAM,aAAa,iHACsF,CAAC;AAEjH,uHAAuH;AACvH,eAAO,MAAM,WAAW;;;;;CAAuF,CAAC;AAChH,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,WAAW,CAAC;AAEhD,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAK9C;AAED,0FAA0F;AAC1F,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEpD;AAOD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED,sCAAsC;AACtC,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAErC;AAED,gIAAgI;AAChI,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BxC;AAuED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAsB/E;AAKD,wHAAwH;AACxH,wBAAgB,eAAe,IAAI,MAAM,CAKxC;AAED,qFAAqF;AACrF,eAAO,MAAM,OAAO,6FAA6F,CAAC;AAElH;;;GAGG;AACH,eAAO,MAAM,UAAU,y5KA+GjB,CAAC;AAEP;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,sIAAsI;AACtI,eAAO,MAAM,OAAO,ilDAwBnB,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,iBAAiB,uSAO7B,CAAC;AAEF,yFAAyF;AACzF,eAAO,MAAM,YAAY,ifAMxB,CAAC;AAEF,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAyBzG"}
|
package/dist/map/page.js
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map page: one body renderer for `kya map --html` and the live report's Map tab, plus the browser draw script.
|
|
3
|
+
* Every string from the trail is untrusted. Server HTML escapes it with esc(). The embedded JSON escapes `<`, `>`,
|
|
4
|
+
* `&`, U+2028 and U+2029. The draw script writes labels through Cytoscape or textContent, never as HTML.
|
|
5
|
+
*/
|
|
6
|
+
import { readFileSync } from "node:fs";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { assertNoSecrets } from "../dash/render.js";
|
|
9
|
+
/** The one line that says what the map is not. Shown on every map page. */
|
|
10
|
+
export const ADVISORY_LINE = "Recorded by KYA. The open source check is advisory; this map shows what was recorded, not what was enforced.";
|
|
11
|
+
/** Edge colours by dominant verdict. Deny beats hold, hold beats observed, observed beats allow (schema section 3). */
|
|
12
|
+
export const TONE_COLOUR = { deny: "#b42318", hold: "#b54708", observed: "#667085", allow: "#067647" };
|
|
13
|
+
/** Tone of an edge from its verdict counts. Any deny makes the edge red. */
|
|
14
|
+
export function edgeTone(v) {
|
|
15
|
+
if (v.deny > 0)
|
|
16
|
+
return "deny";
|
|
17
|
+
if (v.hold > 0)
|
|
18
|
+
return "hold";
|
|
19
|
+
if (v.observed > 0)
|
|
20
|
+
return "observed";
|
|
21
|
+
return "allow";
|
|
22
|
+
}
|
|
23
|
+
/** Edge width grows with log(count): 1 for one event, about 3 for 10, about 5 for 100. */
|
|
24
|
+
export function edgeWidth(count) {
|
|
25
|
+
return Math.round((1 + 2 * Math.log10(Math.max(1, count))) * 100) / 100;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* JSON for a `<script type="application/json">` body. `<`, `>` and `&` and the two line separators become
|
|
29
|
+
* \u escapes, so the text can never close the script element or start a tag. JSON.parse reads them back unchanged.
|
|
30
|
+
*/
|
|
31
|
+
export function jsonForScript(value) {
|
|
32
|
+
return JSON.stringify(value).replace(/[<>&\u2028\u2029]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Secret scan for map output. The shared keyword rule reads `secret:<family>` class labels as a secret assignment
|
|
36
|
+
* (`secret:cloud-credential` is 16 characters), so those exact labels are masked first. Everything else is scanned.
|
|
37
|
+
*/
|
|
38
|
+
const SECRET_CLASS = /\bsecret:(ssh-key|cloud-credential|gpg|env-file|package-token|key-file|other)\b/g;
|
|
39
|
+
export function scanMapOutput(text) {
|
|
40
|
+
assertNoSecrets(text.replace(SECRET_CLASS, "secret-class:$1"));
|
|
41
|
+
}
|
|
42
|
+
/** HTML text and attribute escape. */
|
|
43
|
+
export function esc(s) {
|
|
44
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
45
|
+
}
|
|
46
|
+
/** Data the draw script reads: nodes with a label and detail, edges with tone and width (computed here, not in the browser). */
|
|
47
|
+
export function drawModel(graph) {
|
|
48
|
+
return {
|
|
49
|
+
colours: TONE_COLOUR,
|
|
50
|
+
nodes: graph.nodes.map((n) => ({
|
|
51
|
+
id: n.id,
|
|
52
|
+
kind: n.kind,
|
|
53
|
+
label: n.label ?? n.id,
|
|
54
|
+
detail: detailOf(n),
|
|
55
|
+
count: n.count,
|
|
56
|
+
verdicts: n.verdicts,
|
|
57
|
+
firstTs: n.firstTs,
|
|
58
|
+
lastTs: n.lastTs,
|
|
59
|
+
})),
|
|
60
|
+
edges: graph.edges.map((e, i) => {
|
|
61
|
+
const tone = edgeTone(e.verdicts);
|
|
62
|
+
return {
|
|
63
|
+
id: `e${i}`,
|
|
64
|
+
source: e.from,
|
|
65
|
+
target: e.to,
|
|
66
|
+
kind: e.kind,
|
|
67
|
+
tool: e.tool ?? null,
|
|
68
|
+
tone,
|
|
69
|
+
colour: TONE_COLOUR[tone],
|
|
70
|
+
width: edgeWidth(e.count),
|
|
71
|
+
count: e.count,
|
|
72
|
+
verdicts: e.verdicts,
|
|
73
|
+
firstTs: e.firstTs,
|
|
74
|
+
lastTs: e.lastTs,
|
|
75
|
+
};
|
|
76
|
+
}),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function detailOf(n) {
|
|
80
|
+
if (n.kind === "target")
|
|
81
|
+
return n.class;
|
|
82
|
+
if (n.kind === "tool")
|
|
83
|
+
return n.toolId;
|
|
84
|
+
if (n.kind === "agent")
|
|
85
|
+
return n.legacy ? `${n.product} (legacy rows)` : n.product;
|
|
86
|
+
return n.id;
|
|
87
|
+
}
|
|
88
|
+
const SHOWN_TARGETS = 5;
|
|
89
|
+
function sum(nums) {
|
|
90
|
+
return nums.reduce((a, b) => a + b, 0);
|
|
91
|
+
}
|
|
92
|
+
/** Level 0 to 4 for a count, relative to the largest count on the page. */
|
|
93
|
+
function level(count, max) {
|
|
94
|
+
if (count <= 0 || max <= 0)
|
|
95
|
+
return 0;
|
|
96
|
+
return Math.min(4, Math.ceil((4 * count) / max));
|
|
97
|
+
}
|
|
98
|
+
function summaryHtml(graph) {
|
|
99
|
+
const devices = graph.nodes.filter((n) => n.kind === "device");
|
|
100
|
+
const events = sum(devices.map((n) => n.count));
|
|
101
|
+
const sessions = sum(graph.nodes.filter((n) => n.kind === "agent").map((n) => n.grouped ?? 1));
|
|
102
|
+
const classes = graph.nodes
|
|
103
|
+
.filter((n) => n.kind === "target" && n.grouped === undefined)
|
|
104
|
+
.sort((a, b) => b.count - a.count || (a.class < b.class ? -1 : a.class > b.class ? 1 : 0))
|
|
105
|
+
.slice(0, SHOWN_TARGETS);
|
|
106
|
+
const top = classes.length
|
|
107
|
+
? `<ol class="map-top">${classes.map((c) => `<li><code>${esc(c.class)}</code> ${c.count}</li>`).join("")}</ol>`
|
|
108
|
+
: `<p class="mute">No targets yet.</p>`;
|
|
109
|
+
return `<div class="map-stats">
|
|
110
|
+
<p><strong>${events}</strong> events · <strong>${sessions}</strong> sessions · <strong>${devices.length}</strong> device${devices.length === 1 ? "" : "s"}</p>
|
|
111
|
+
<p class="small">Top ${SHOWN_TARGETS} target classes:</p>
|
|
112
|
+
${top}
|
|
113
|
+
</div>`;
|
|
114
|
+
}
|
|
115
|
+
function whenTable(heat) {
|
|
116
|
+
const head = heat.when.hours.map((h) => `<th scope="col">${String(h).padStart(2, "0")}</th>`).join("");
|
|
117
|
+
const rows = heat.when.days.map((day, d) => {
|
|
118
|
+
const cells = heat.when.cells[d].map((count, h) => {
|
|
119
|
+
const v = heat.when.verdictCells[d][h];
|
|
120
|
+
const deny = v.deny > 0 ? " deny" : "";
|
|
121
|
+
const title = `${day} ${String(h).padStart(2, "0")}:00 - ${count} event${count === 1 ? "" : "s"}${v.deny > 0 ? `, ${v.deny} denied` : ""}`;
|
|
122
|
+
return `<td class="l${level(count, heat.when.max)}${deny}" title="${esc(title)}">${count || ""}</td>`;
|
|
123
|
+
});
|
|
124
|
+
return `<tr><th scope="row">${esc(day)}</th>${cells.join("")}</tr>`;
|
|
125
|
+
});
|
|
126
|
+
return `<table class="map-heat map-when">
|
|
127
|
+
<caption>When: events per hour, last 7 days (local time). A red outline marks an hour with a deny.</caption>
|
|
128
|
+
<thead><tr><th scope="col">Day</th>${head}</tr></thead>
|
|
129
|
+
<tbody>${rows.join("")}</tbody>
|
|
130
|
+
</table>`;
|
|
131
|
+
}
|
|
132
|
+
function whereTable(heat) {
|
|
133
|
+
const rows = heat.where.rows.map((r) => {
|
|
134
|
+
const cell = (count, col) => `<td class="l${level(count, heat.where.max)}${col === "deny" && count > 0 ? " deny" : ""}">${count || ""}</td>`;
|
|
135
|
+
const name = r.grouped !== undefined ? `${r.class} (${r.grouped})` : r.class;
|
|
136
|
+
return `<tr><th scope="row"><code>${esc(name)}</code></th>${cell(r.allow, "allow")}${cell(r.deny, "deny")}${cell(r.hold, "hold")}${cell(r.observed, "observed")}</tr>`;
|
|
137
|
+
});
|
|
138
|
+
return `<table class="map-heat map-where">
|
|
139
|
+
<caption>Where: events per target class and verdict.</caption>
|
|
140
|
+
<thead><tr><th scope="col">Target class</th><th scope="col">Allow</th><th scope="col">Deny</th><th scope="col">Hold</th><th scope="col">Observed</th></tr></thead>
|
|
141
|
+
<tbody>${rows.join("") || `<tr><td colspan="5" class="mute">No targets.</td></tr>`}</tbody>
|
|
142
|
+
</table>`;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The page body: summary, graph container, side panel, both heat tables, and the data. Used inside the standalone
|
|
146
|
+
* file and as the live report's Map fragment. The graph is drawn by MAP_SCRIPT from the data element.
|
|
147
|
+
*/
|
|
148
|
+
export function renderMapBody(graph, heat, days) {
|
|
149
|
+
const events = sum(graph.nodes.filter((n) => n.kind === "device").map((n) => n.count));
|
|
150
|
+
const empty = events === 0 ? `<p class="map-empty">No events in the last ${days} days.</p>` : "";
|
|
151
|
+
const graphBlock = events === 0
|
|
152
|
+
? ""
|
|
153
|
+
: `<div class="map-canvas">
|
|
154
|
+
<div id="kya-map-graph" class="map-graph" aria-label="Map of agent actions"></div>
|
|
155
|
+
<aside id="kya-map-panel" class="map-panel" aria-live="polite"><p class="mute">Click a node to see its class, counts and first and last time.</p></aside>
|
|
156
|
+
</div>
|
|
157
|
+
<p class="map-legend small">Edges: red = deny, amber = hold, grey = observed (recorded, not enforced), green = allow. Width grows with the count.</p>`;
|
|
158
|
+
return `<div class="map-body">
|
|
159
|
+
<p class="map-advisory">${esc(ADVISORY_LINE)}</p>
|
|
160
|
+
${summaryHtml(graph)}
|
|
161
|
+
${empty}
|
|
162
|
+
${graphBlock}
|
|
163
|
+
<h2>When</h2>
|
|
164
|
+
<div class="map-scroll">${whenTable(heat)}</div>
|
|
165
|
+
<h2>Where</h2>
|
|
166
|
+
<div class="map-scroll">${whereTable(heat)}</div>
|
|
167
|
+
<script type="application/json" id="kya-map-data">${jsonForScript(drawModel(graph))}</script>
|
|
168
|
+
</div>`;
|
|
169
|
+
}
|
|
170
|
+
const LIBRARY_PATH = new URL("../../vendor/cytoscape/cytoscape.min.js", import.meta.url);
|
|
171
|
+
let librarySource;
|
|
172
|
+
/** The vendored Cytoscape.js (MIT, see vendor/cytoscape/LICENSE). `</script` is broken so it cannot end the element. */
|
|
173
|
+
export function cytoscapeSource() {
|
|
174
|
+
if (librarySource === undefined) {
|
|
175
|
+
librarySource = readFileSync(fileURLToPath(LIBRARY_PATH), "utf8").replace(/<\/(script)/gi, "<\\/$1");
|
|
176
|
+
}
|
|
177
|
+
return librarySource;
|
|
178
|
+
}
|
|
179
|
+
/** Content-Security-Policy for the standalone file. No network: default-src none. */
|
|
180
|
+
export const MAP_CSP = "default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; img-src data:";
|
|
181
|
+
/**
|
|
182
|
+
* The browser part. Labels go to Cytoscape (canvas) or textContent. The live body is parsed with DOMParser (the body
|
|
183
|
+
* has no executable script), so this file never assigns innerHTML.
|
|
184
|
+
*/
|
|
185
|
+
export const MAP_SCRIPT = `(function () {
|
|
186
|
+
'use strict';
|
|
187
|
+
var cy = null;
|
|
188
|
+
var last = null;
|
|
189
|
+
var live = !!document.querySelector('main[data-live-token]');
|
|
190
|
+
function token() {
|
|
191
|
+
var m = /(?:^|[?&])t=([^&]*)/.exec(location.search);
|
|
192
|
+
if (!m) return '';
|
|
193
|
+
try { return decodeURIComponent(m[1]); } catch (e) { return m[1]; }
|
|
194
|
+
}
|
|
195
|
+
function model() {
|
|
196
|
+
var el = document.getElementById('kya-map-data');
|
|
197
|
+
if (!el) return null;
|
|
198
|
+
try { return JSON.parse(el.textContent || 'null'); } catch (e) { return null; }
|
|
199
|
+
}
|
|
200
|
+
function add(parent, tag, text) {
|
|
201
|
+
var n = document.createElement(tag);
|
|
202
|
+
n.textContent = String(text);
|
|
203
|
+
parent.appendChild(n);
|
|
204
|
+
return n;
|
|
205
|
+
}
|
|
206
|
+
function showNode(node) {
|
|
207
|
+
var panel = document.getElementById('kya-map-panel');
|
|
208
|
+
if (!panel) return;
|
|
209
|
+
while (panel.firstChild) panel.removeChild(panel.firstChild);
|
|
210
|
+
add(panel, 'h3', node.kind + ': ' + node.label);
|
|
211
|
+
add(panel, 'p', 'Class: ' + node.detail);
|
|
212
|
+
var list = document.createElement('dl');
|
|
213
|
+
panel.appendChild(list);
|
|
214
|
+
[['Events', node.count], ['Allow', node.verdicts.allow], ['Deny', node.verdicts.deny], ['Hold', node.verdicts.hold],
|
|
215
|
+
['Observed', node.verdicts.observed], ['First seen', node.firstTs || '-'], ['Last seen', node.lastTs || '-']]
|
|
216
|
+
.forEach(function (r) { add(list, 'dt', r[0]); add(list, 'dd', r[1]); });
|
|
217
|
+
}
|
|
218
|
+
function style(d) {
|
|
219
|
+
var out = [
|
|
220
|
+
{ selector: 'node', style: { 'label': 'data(label)', 'font-size': 10, 'text-wrap': 'ellipsis', 'text-max-width': 130, 'min-zoomed-font-size': 9,
|
|
221
|
+
'text-background-color': '#ffffff', 'text-background-opacity': 0.8, 'text-background-padding': 1,
|
|
222
|
+
'width': 18, 'height': 18, 'background-color': '#98a2b3', 'color': '#101828' } },
|
|
223
|
+
{ selector: 'node[kind = "device"]', style: { 'background-color': '#344054', 'shape': 'round-rectangle', 'width': 34, 'height': 34 } },
|
|
224
|
+
{ selector: 'node[kind = "agent"]', style: { 'background-color': '#1d4ed8' } },
|
|
225
|
+
{ selector: 'node[kind = "tool"]', style: { 'background-color': '#7a5af8', 'shape': 'round-rectangle' } },
|
|
226
|
+
{ selector: 'node[kind = "target"]', style: { 'background-color': '#0e9384' } },
|
|
227
|
+
{ selector: 'edge', style: { 'width': 'data(width)', 'line-color': 'data(colour)', 'target-arrow-color': 'data(colour)',
|
|
228
|
+
'target-arrow-shape': 'triangle', 'curve-style': 'bezier', 'opacity': 0.9 } }
|
|
229
|
+
];
|
|
230
|
+
return out;
|
|
231
|
+
}
|
|
232
|
+
var MAX_DRAW_NODES = 400;
|
|
233
|
+
function draw() {
|
|
234
|
+
var host = document.getElementById('kya-map-graph');
|
|
235
|
+
var d = model();
|
|
236
|
+
if (cy) { cy.destroy(); cy = null; }
|
|
237
|
+
if (!host || !d || !window.cytoscape || !d.nodes || !d.nodes.length) return;
|
|
238
|
+
// A force layout on thousands of nodes hangs the tab. The JSON and both heat views still hold everything.
|
|
239
|
+
if (d.nodes.length > MAX_DRAW_NODES) {
|
|
240
|
+
host.textContent = 'Graph not drawn: ' + d.nodes.length + ' nodes is too many for the page. Use a shorter window (kya map --days 1) or kya map --json.';
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
cy = window.cytoscape({
|
|
244
|
+
container: host,
|
|
245
|
+
elements: {
|
|
246
|
+
nodes: d.nodes.map(function (n) { return { data: n }; }),
|
|
247
|
+
edges: d.edges.map(function (e) { return { data: e }; })
|
|
248
|
+
},
|
|
249
|
+
style: style(d),
|
|
250
|
+
layout: { name: 'cose', animate: false, randomize: true, fit: true, padding: 24, numIter: 900, nodeRepulsion: function () { return 9000; }, idealEdgeLength: function () { return 80; }, nodeOverlap: 14, gravity: 0.35 }
|
|
251
|
+
});
|
|
252
|
+
cy.on('tap', 'node', function (evt) { showNode(evt.target.data()); });
|
|
253
|
+
cy.fit();
|
|
254
|
+
}
|
|
255
|
+
function refresh() {
|
|
256
|
+
if (!live) return;
|
|
257
|
+
var host = document.getElementById('frag-map');
|
|
258
|
+
if (!host) return;
|
|
259
|
+
fetch('/fragments?t=' + encodeURIComponent(token()), {
|
|
260
|
+
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{"map":true}'
|
|
261
|
+
})
|
|
262
|
+
.then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); })
|
|
263
|
+
.then(function (j) {
|
|
264
|
+
if (!j || !j.ok || !j.fragments || typeof j.fragments.mapBody !== 'string') return;
|
|
265
|
+
if (j.fragments.mapBody === last) return;
|
|
266
|
+
last = j.fragments.mapBody;
|
|
267
|
+
var doc = new DOMParser().parseFromString(j.fragments.mapBody, 'text/html');
|
|
268
|
+
var nodes = Array.prototype.slice.call(doc.body.childNodes);
|
|
269
|
+
while (host.firstChild) host.removeChild(host.firstChild);
|
|
270
|
+
nodes.forEach(function (n) { host.appendChild(n); });
|
|
271
|
+
draw();
|
|
272
|
+
})
|
|
273
|
+
.catch(function (err) { console.error('KYA map refresh failed', err); });
|
|
274
|
+
}
|
|
275
|
+
// Live only: fetch the vendored library with the token from this page's URL, then run it as a script element.
|
|
276
|
+
function loadLibrary(next) {
|
|
277
|
+
if (window.cytoscape) { next(); return; }
|
|
278
|
+
fetch('/vendor/cytoscape.min.js?t=' + encodeURIComponent(token()))
|
|
279
|
+
.then(function (r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.text(); })
|
|
280
|
+
.then(function (text) {
|
|
281
|
+
var s = document.createElement('script');
|
|
282
|
+
s.id = 'kya-cytoscape';
|
|
283
|
+
s.textContent = text;
|
|
284
|
+
document.head.appendChild(s);
|
|
285
|
+
next();
|
|
286
|
+
})
|
|
287
|
+
.catch(function (err) { console.error('KYA map library failed', err); });
|
|
288
|
+
}
|
|
289
|
+
window.kyaMapRefresh = refresh;
|
|
290
|
+
window.addEventListener('hashchange', function () {
|
|
291
|
+
if (location.hash !== '#map') return;
|
|
292
|
+
refresh();
|
|
293
|
+
setTimeout(function () { if (cy) { cy.resize(); cy.fit(); } }, 0);
|
|
294
|
+
});
|
|
295
|
+
if (live) loadLibrary(refresh); else draw();
|
|
296
|
+
})();`;
|
|
297
|
+
/**
|
|
298
|
+
* Live report: the draw script, in the page shell (not in the swapped fragment). The script reads the token from its
|
|
299
|
+
* own URL and fetches the library from /vendor/cytoscape.min.js, so the token never appears in the HTML.
|
|
300
|
+
*/
|
|
301
|
+
export function liveMapScripts() {
|
|
302
|
+
return `<script id="kya-map">${MAP_SCRIPT}</script>`;
|
|
303
|
+
}
|
|
304
|
+
/** Map components. Shared by the standalone file and the live report, so it uses the report's tokens (--line, --mute, --fg, --bg). */
|
|
305
|
+
export const MAP_CSS = `
|
|
306
|
+
.map-body .map-advisory { border-left: 3px solid var(--line, #d0d5dd); padding: 4px 10px; font-weight: 600; }
|
|
307
|
+
.map-body .mute { color: var(--mute, #667085); }
|
|
308
|
+
.map-stats p { margin: 4px 0; }
|
|
309
|
+
.map-top { margin: 4px 0 12px 20px; padding: 0; }
|
|
310
|
+
.map-canvas { display: grid; grid-template-columns: minmax(0, 1fr) 260px; gap: 12px; margin: 12px 0; }
|
|
311
|
+
.map-graph { height: 60vh; min-height: 360px; border: 1px solid var(--line, #d0d5dd); border-radius: 6px; }
|
|
312
|
+
.map-panel { border: 1px solid var(--line, #d0d5dd); border-radius: 6px; padding: 8px 12px; overflow: auto; }
|
|
313
|
+
.map-panel dl { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; }
|
|
314
|
+
.map-panel dt { color: var(--mute, #667085); }
|
|
315
|
+
.map-panel dd { margin: 0; }
|
|
316
|
+
.map-scroll { overflow-x: auto; }
|
|
317
|
+
.map-heat { border-collapse: collapse; font-size: 12px; margin-bottom: 12px; }
|
|
318
|
+
.map-heat caption { text-align: left; color: var(--mute, #667085); padding: 4px 0; }
|
|
319
|
+
.map-heat th, .map-heat td { border: 1px solid var(--line, #d0d5dd); padding: 3px 5px; text-align: right; min-width: 22px; }
|
|
320
|
+
.map-heat th { text-align: left; font-weight: 600; }
|
|
321
|
+
.map-heat td.l0 { background: transparent; }
|
|
322
|
+
.map-heat td.l1 { background: #d1fadf; color: #101828; }
|
|
323
|
+
.map-heat td.l2 { background: #75e0a7; color: #101828; }
|
|
324
|
+
.map-heat td.l3 { background: #12b76a; color: #fff; }
|
|
325
|
+
.map-heat td.l4 { background: #027a48; color: #fff; }
|
|
326
|
+
.map-heat td.deny { outline: 2px solid #b42318; outline-offset: -2px; }
|
|
327
|
+
.map-empty { font-weight: 600; }
|
|
328
|
+
@media (max-width: 760px) { .map-canvas { grid-template-columns: 1fr; } }
|
|
329
|
+
`;
|
|
330
|
+
/** Live report: the Map zone shows only on its tab (same :target rule as the other zones). */
|
|
331
|
+
export const MAP_LIVE_ZONE_CSS = `
|
|
332
|
+
@supports selector(body:has(*)) {
|
|
333
|
+
#map { display: none; }
|
|
334
|
+
#map:target { display: block; }
|
|
335
|
+
body:has(#map:target) #overview { display: none; }
|
|
336
|
+
body:has(#map:target) .nav-link[href="#map"] { color: var(--fg); background: var(--bg); border-color: var(--line); }
|
|
337
|
+
}
|
|
338
|
+
`;
|
|
339
|
+
/** Standalone file only: its own tokens and page frame (the live report has its own). */
|
|
340
|
+
export const MAP_PAGE_CSS = `
|
|
341
|
+
:root { --fg: #101828; --mute: #667085; --line: #d0d5dd; --bg: #ffffff; }
|
|
342
|
+
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --fg: #f2f4f7; --mute: #98a2b3; --line: #344054; --bg: #101828; } }
|
|
343
|
+
:root[data-theme="dark"] { --fg: #f2f4f7; --mute: #98a2b3; --line: #344054; --bg: #101828; }
|
|
344
|
+
body { background: var(--bg); color: var(--fg); font: 14px/1.45 system-ui, sans-serif; margin: 0; }
|
|
345
|
+
.map-page { max-width: 1100px; margin: 0 auto; padding: 16px; }
|
|
346
|
+
`;
|
|
347
|
+
/** Standalone file: one page, no network, CSP on. */
|
|
348
|
+
export function renderMapPage(input) {
|
|
349
|
+
const body = renderMapBody(input.graph, input.heat, input.days);
|
|
350
|
+
return `<!DOCTYPE html>
|
|
351
|
+
<html lang="en">
|
|
352
|
+
<head>
|
|
353
|
+
<meta charset="utf-8"/>
|
|
354
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
355
|
+
<meta http-equiv="Content-Security-Policy" content="${MAP_CSP}"/>
|
|
356
|
+
<meta name="referrer" content="no-referrer"/>
|
|
357
|
+
<title>${esc(input.title)}</title>
|
|
358
|
+
<style>${MAP_PAGE_CSS}${MAP_CSS}</style>
|
|
359
|
+
</head>
|
|
360
|
+
<body>
|
|
361
|
+
<main class="map-page">
|
|
362
|
+
<header>
|
|
363
|
+
<h1>Map of agent actions</h1>
|
|
364
|
+
<p class="mute">Last ${input.days} days · local only</p>
|
|
365
|
+
</header>
|
|
366
|
+
${body}
|
|
367
|
+
</main>
|
|
368
|
+
<script id="kya-cytoscape">${cytoscapeSource()}</script>
|
|
369
|
+
<script id="kya-map">${MAP_SCRIPT}</script>
|
|
370
|
+
</body>
|
|
371
|
+
</html>
|
|
372
|
+
`;
|
|
373
|
+
}
|
|
374
|
+
//# sourceMappingURL=page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../src/map/page.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** A class string such as `secret:ssh-key` or `project:app/src/**`. Never a raw path, file name or argument. */
|
|
2
|
+
export type TargetClass = string;
|
|
3
|
+
/** `other` holds absolute paths that match no named class (schema 4.4 rule 9). */
|
|
4
|
+
export type TargetFamily = "network" | "secret" | "tmp" | "system" | "project" | "home" | "command" | "none" | "other";
|
|
5
|
+
export interface TargetInput {
|
|
6
|
+
readonly toolId: string;
|
|
7
|
+
readonly targetPath?: string;
|
|
8
|
+
readonly summary?: string;
|
|
9
|
+
readonly project?: string;
|
|
10
|
+
/** Absolute working directory of the call. With it a path is "in the project" only when it is under this directory. */
|
|
11
|
+
readonly cwd?: string;
|
|
12
|
+
readonly home?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Maps one event's target to a class. Pure: no fs, no env, no clock. Rules run in schema 4.4 order, first match wins.
|
|
16
|
+
* Output is a class only: a host for network, a binary for command, no path, file name or argument.
|
|
17
|
+
*/
|
|
18
|
+
export declare function classifyTarget(input: TargetInput): {
|
|
19
|
+
class: TargetClass;
|
|
20
|
+
family: TargetFamily;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=target-class.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target-class.d.ts","sourceRoot":"","sources":["../../src/map/target-class.ts"],"names":[],"mappings":"AAEA,gHAAgH;AAChH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC;AAEjC,kFAAkF;AAClF,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAEvH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,uHAAuH;IACvH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AA4FD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,CA2C/F"}
|