@shield-agent/kya 0.32.9 → 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 +178 -12
- 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 +149 -16
- package/dist/cli.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 +120 -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/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/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 +9 -3
- package/dist/fs-atomic.d.ts.map +1 -1
- package/dist/fs-atomic.js +17 -11
- 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/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 +48 -12
- package/dist/never-list-input.d.ts.map +1 -1
- package/dist/never-list-input.js +696 -29
- package/dist/never-list-input.js.map +1 -1
- 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 +26 -1
- package/dist/offline-evaluate.d.ts.map +1 -1
- package/dist/offline-evaluate.js +33 -4
- 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/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 +28 -10
- package/dist/receipt/embeddings.d.ts.map +1 -1
- package/dist/receipt/embeddings.js +221 -35
- 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 +9 -1
- package/dist/trail.d.ts.map +1 -1
- package/dist/trail.js +24 -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 -4
- 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
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":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIpD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,aAAa,GACxB,8GAA8G,CAAC;AAEjH,uHAAuH;AACvH,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAW,CAAC;AAGhH,4EAA4E;AAC5E,MAAM,UAAU,QAAQ,CAAC,CAAW;IAClC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC9B,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC9B,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IACtC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AAC1E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;AAC3H,CAAC;AAED;;;GAGG;AACH,MAAM,YAAY,GAAG,kFAAkF,CAAC;AACxG,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,GAAG,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC7H,CAAC;AAED,gIAAgI;AAChI,MAAM,UAAU,SAAS,CAAC,KAAe;IACvC,OAAO;QACL,OAAO,EAAE,WAAW;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC;YACtC,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE;YACtB,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;YACnB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,MAAM,EAAE,CAAC,CAAC,MAAM;SACjB,CAAC,CAAC;QACH,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YAClC,OAAO;gBACL,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,MAAM,EAAE,CAAC,CAAC,IAAI;gBACd,MAAM,EAAE,CAAC,CAAC,EAAE;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI;gBACpB,IAAI;gBACJ,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC;gBACzB,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;gBACzB,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,MAAM,EAAE,CAAC,CAAC,MAAM;aACjB,CAAC;QACJ,CAAC,CAAC;KACH,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,CAAU;IAC1B,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC;IACxC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACnF,OAAO,CAAC,CAAC,EAAE,CAAC;AACd,CAAC;AAED,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB,SAAS,GAAG,CAAC,IAAuB;IAClC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,2EAA2E;AAC3E,SAAS,KAAK,CAAC,KAAa,EAAE,GAAW;IACvC,IAAI,KAAK,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IACrC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,WAAW,CAAC,KAAe;IAClC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/F,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK;SACxB,MAAM,CAAC,CAAC,CAAC,EAA6C,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC;SACxG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACzF,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;IAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM;QACxB,CAAC,CAAC,uBAAuB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO;QAC/G,CAAC,CAAC,qCAAqC,CAAC;IAC1C,OAAO;eACM,MAAM,8BAA8B,QAAQ,gCAAgC,OAAO,CAAC,MAAM,mBAAmB,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG;yBAClI,aAAa;IAClC,GAAG;OACA,CAAC;AACR,CAAC;AAED,SAAS,SAAS,CAAC,IAAU;IAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvG,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;YACjD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAE,CAAC,CAAC,CAAE,CAAC;YACzC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,GAAG,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,SAAS,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC3I,OAAO,eAAe,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,YAAY,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,EAAE,OAAO,CAAC;QACxG,CAAC,CAAC,CAAC;QACH,OAAO,uBAAuB,GAAG,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;IACtE,CAAC,CAAC,CAAC;IACH,OAAO;;uCAE8B,IAAI;WAChC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;SACf,CAAC;AACV,CAAC;AAED,SAAS,UAAU,CAAC,IAAU;IAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,GAAW,EAAE,EAAE,CAC1C,eAAe,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,KAAK,MAAM,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,EAAE,OAAO,CAAC;QAClH,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC7E,OAAO,6BAA6B,GAAG,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC;IACzK,CAAC,CAAC,CAAC;IACH,OAAO;;;WAGE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,wDAAwD;SAC3E,CAAC;AACV,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAe,EAAE,IAAU,EAAE,IAAY;IACrE,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACvF,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,8CAA8C,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACjG,MAAM,UAAU,GACd,MAAM,KAAK,CAAC;QACV,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC;;;;sJAI8I,CAAC;IACrJ,OAAO;4BACmB,GAAG,CAAC,aAAa,CAAC;IAC1C,WAAW,CAAC,KAAK,CAAC;IAClB,KAAK;IACL,UAAU;;4BAEc,SAAS,CAAC,IAAI,CAAC;;4BAEf,UAAU,CAAC,IAAI,CAAC;sDACU,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;OAC9E,CAAC;AACR,CAAC;AAED,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,yCAAyC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzF,IAAI,aAAiC,CAAC;AAEtC,wHAAwH;AACxH,MAAM,UAAU,eAAe;IAC7B,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,aAAa,GAAG,YAAY,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IACvG,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,qFAAqF;AACrF,MAAM,CAAC,MAAM,OAAO,GAAG,0FAA0F,CAAC;AAElH;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA+GpB,CAAC;AAEP;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,wBAAwB,UAAU,WAAW,CAAC;AACvD,CAAC;AAED,sIAAsI;AACtI,MAAM,CAAC,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBtB,CAAC;AAEF,8FAA8F;AAC9F,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;CAOhC,CAAC;AAEF,yFAAyF;AACzF,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;CAM3B,CAAC;AAEF,qDAAqD;AACrD,MAAM,UAAU,aAAa,CAAC,KAAmE;IAC/F,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAChE,OAAO;;;;;sDAK6C,OAAO;;SAEpD,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;SAChB,YAAY,GAAG,OAAO;;;;;;yBAMN,KAAK,CAAC,IAAI;;EAEjC,IAAI;;6BAEuB,eAAe,EAAE;uBACvB,UAAU;;;CAGhC,CAAC;AACF,CAAC"}
|
|
@@ -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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { isSecretPath } from "../never-list-input.js";
|
|
2
|
+
/** Same shape as the redacted shell line written by `summarizeShellCommand`. Only the binary and the arg count survive. */
|
|
3
|
+
const SHELL_SUMMARY = /^shell (\S+?)( \(\+\d+ args\))?$/;
|
|
4
|
+
const URL_SCHEME = /^[a-z][a-z0-9+.-]*:\/\//i;
|
|
5
|
+
const BIN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,63}$/;
|
|
6
|
+
const TMP_ROOTS = ["/tmp", "/private/tmp", "/var/folders", "/private/var/folders"];
|
|
7
|
+
const SYSTEM_ROOTS = ["/private/etc", "/etc", "/usr", "/bin", "/sbin", "/System", "/Library", "/opt", "/boot", "/dev", "/proc"];
|
|
8
|
+
/** A path segment shown in a class. Anything that could carry a credential (`user:pass@`, `?x=`) becomes `(other)`. */
|
|
9
|
+
function seg(s) {
|
|
10
|
+
return s === "" || s === "." || s === ".." || s.length > 64 || /[:@?#=&%\u0000-\u001f]/.test(s) ? "(other)" : s;
|
|
11
|
+
}
|
|
12
|
+
const NET_SCHEMES = new Set(["http:", "https:", "ws:", "wss:", "ftp:"]);
|
|
13
|
+
const HOST = /^(?:[a-z0-9-]+(?:\.[a-z0-9-]+)*|\[[0-9a-f:.]+\])$/;
|
|
14
|
+
/** Host of an absolute URL, or undefined. Only network schemes; the host must look like a host (no opaque text). */
|
|
15
|
+
function urlHost(s) {
|
|
16
|
+
try {
|
|
17
|
+
const u = new URL(s);
|
|
18
|
+
const host = u.hostname.toLowerCase();
|
|
19
|
+
return NET_SCHEMES.has(u.protocol) && host.length <= 253 && HOST.test(host) ? host : undefined;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** Local path of a file: URL, or undefined for any other scheme. The path stays inside this module: only a class leaves it. */
|
|
26
|
+
function fileUrlPath(s) {
|
|
27
|
+
if (!/^file:\/\//i.test(s))
|
|
28
|
+
return undefined;
|
|
29
|
+
try {
|
|
30
|
+
const u = new URL(s);
|
|
31
|
+
if (u.protocol !== "file:")
|
|
32
|
+
return undefined;
|
|
33
|
+
try {
|
|
34
|
+
return decodeURIComponent(u.pathname);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return u.pathname;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return "/";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Directory names that carry no personal data. Used when the working directory is unknown (rows written before `targetClass`). */
|
|
45
|
+
const COMMON_DIRS = new Set(["src", "lib", "test", "tests", "docs", "app", "web", "api", "scripts", "public", "dist", "build", "node_modules", ".github", ".kya", ".claude"]);
|
|
46
|
+
const RESERVED_PROJECT = new Set(["home", "Users", "root", "tmp", "var", "etc", "usr", "opt", "private"]);
|
|
47
|
+
/** `s` without trailing slashes. A loop, not `/\/+$/`: that regex is quadratic on a long run of slashes before another character. */
|
|
48
|
+
function trimTrailingSlashes(s) {
|
|
49
|
+
let end = s.length;
|
|
50
|
+
while (end > 0 && s.charCodeAt(end - 1) === 47)
|
|
51
|
+
end--;
|
|
52
|
+
return s.slice(0, end);
|
|
53
|
+
}
|
|
54
|
+
/** Part of `t` inside the project, or undefined. Exact when `cwd` is known; a guarded guess from the project name otherwise. */
|
|
55
|
+
function projectRest(t, input) {
|
|
56
|
+
const project = input.project;
|
|
57
|
+
if (!project || RESERVED_PROJECT.has(project))
|
|
58
|
+
return undefined;
|
|
59
|
+
const cwd = input.cwd === undefined ? undefined : trimTrailingSlashes(input.cwd);
|
|
60
|
+
if (cwd && cwd.startsWith("/")) {
|
|
61
|
+
// A project folder that is the home folder or above it names a user: no project class.
|
|
62
|
+
if (cwd === "" || (input.home && (cwd === input.home || input.home.startsWith(cwd + "/"))))
|
|
63
|
+
return undefined;
|
|
64
|
+
// Shaped like a home folder (another user, a container, a sandbox HOME): its name is a user name.
|
|
65
|
+
if (/^\/(?:Users|home)\/[^/]+$/.test(cwd) || cwd === "/root")
|
|
66
|
+
return undefined;
|
|
67
|
+
if (t === cwd)
|
|
68
|
+
return { rest: "", exact: true };
|
|
69
|
+
return t.startsWith(cwd + "/") ? { rest: t.slice(cwd.length + 1), exact: true } : undefined;
|
|
70
|
+
}
|
|
71
|
+
const at = t.indexOf(`/${project}/`);
|
|
72
|
+
return at > 0 ? { rest: t.slice(at + project.length + 2), exact: false } : undefined;
|
|
73
|
+
}
|
|
74
|
+
/** Secret family, a fixed label chosen from the path shape. `isSecretPath` decides whether it is secret. */
|
|
75
|
+
function secretLabel(p) {
|
|
76
|
+
const base = p.slice(p.lastIndexOf("/") + 1);
|
|
77
|
+
if (/(^|\/)\.ssh\//.test(p))
|
|
78
|
+
return "ssh-key";
|
|
79
|
+
if (/(^|\/)\.aws\/|gcloud/.test(p))
|
|
80
|
+
return "cloud-credential";
|
|
81
|
+
if (base.startsWith(".env"))
|
|
82
|
+
return "env-file";
|
|
83
|
+
if (/\.(pem|key)$/.test(base))
|
|
84
|
+
return "key-file";
|
|
85
|
+
return "other";
|
|
86
|
+
}
|
|
87
|
+
/** Home-relative remainder of a path (`/.zshrc`, `/Documents/x`), or undefined when the path is not under a home. */
|
|
88
|
+
function homeRest(p, home) {
|
|
89
|
+
if (home && (p === home || p.startsWith(home + "/")))
|
|
90
|
+
return p.slice(home.length);
|
|
91
|
+
if (p === "~" || p.startsWith("~/"))
|
|
92
|
+
return p.slice(1);
|
|
93
|
+
const user = /^\/(?:Users|home)\/[^/]+(\/.*)?$/.exec(p);
|
|
94
|
+
if (user)
|
|
95
|
+
return user[1] ?? "";
|
|
96
|
+
const root = /^\/root(\/.*)?$/.exec(p);
|
|
97
|
+
return root ? (root[1] ?? "") : undefined;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 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.
|
|
101
|
+
* Output is a class only: a host for network, a binary for command, no path, file name or argument.
|
|
102
|
+
*/
|
|
103
|
+
export function classifyTarget(input) {
|
|
104
|
+
let t = input.targetPath;
|
|
105
|
+
if (t && URL_SCHEME.test(t)) {
|
|
106
|
+
const file = fileUrlPath(t);
|
|
107
|
+
if (file === undefined) {
|
|
108
|
+
const host = urlHost(t);
|
|
109
|
+
return { class: `network:${host ?? "other"}`, family: "network" };
|
|
110
|
+
}
|
|
111
|
+
t = file; // file:///home/a/.aws/credentials is a path: the secret, system and home rules decide
|
|
112
|
+
}
|
|
113
|
+
if (t && isSecretPath(t, input.home))
|
|
114
|
+
return { class: `secret:${secretLabel(t)}`, family: "secret" };
|
|
115
|
+
if (t && TMP_ROOTS.some((r) => t === r || t.startsWith(r + "/")))
|
|
116
|
+
return { class: "tmp:/**", family: "tmp" };
|
|
117
|
+
const sys = t && SYSTEM_ROOTS.find((r) => t === r || t.startsWith(r + "/"));
|
|
118
|
+
if (sys)
|
|
119
|
+
return { class: `system:${sys}/**`, family: "system" };
|
|
120
|
+
const inProject = t ? projectRest(t, input) : undefined;
|
|
121
|
+
if (t && inProject) {
|
|
122
|
+
const name = seg(input.project ?? "");
|
|
123
|
+
const slash = inProject.rest.indexOf("/");
|
|
124
|
+
const dir = slash < 0 ? "" : inProject.rest.slice(0, slash);
|
|
125
|
+
const shown = inProject.exact || COMMON_DIRS.has(dir) ? seg(dir) : "(other)";
|
|
126
|
+
return { class: slash < 0 ? `project:${name}/*` : `project:${name}/${shown}/**`, family: "project" };
|
|
127
|
+
}
|
|
128
|
+
if (t && !t.startsWith("/") && !t.startsWith("~") && !t.startsWith("\\") && !/^[A-Za-z]:[\\/]/.test(t)) {
|
|
129
|
+
const slash = t.indexOf("/");
|
|
130
|
+
return { class: slash < 0 ? "project:(relative)/*" : `project:(relative)/${seg(t.slice(0, slash))}/**`, family: "project" };
|
|
131
|
+
}
|
|
132
|
+
const rest = t ? homeRest(t, input.home) : undefined;
|
|
133
|
+
if (rest !== undefined) {
|
|
134
|
+
const first = rest.replace(/^\/+/, "").split("/")[0] ?? "";
|
|
135
|
+
return first.startsWith(".") ? { class: "home:dot/**", family: "home" } : { class: "home:other", family: "home" };
|
|
136
|
+
}
|
|
137
|
+
if (t)
|
|
138
|
+
return { class: "absolute:other", family: "other" };
|
|
139
|
+
const m = input.summary ? SHELL_SUMMARY.exec(input.summary) : null;
|
|
140
|
+
if (m) {
|
|
141
|
+
const token = m[1] ?? "";
|
|
142
|
+
if (token.includes("://")) {
|
|
143
|
+
const host = urlHost(token);
|
|
144
|
+
return { class: `network:${host ?? "other"}`, family: "network" };
|
|
145
|
+
}
|
|
146
|
+
const bin = token.slice(token.lastIndexOf("/") + 1);
|
|
147
|
+
return { class: `command:${BIN.test(bin) ? bin : "other"}`, family: "command" };
|
|
148
|
+
}
|
|
149
|
+
return { class: "none", family: "none" };
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=target-class.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target-class.js","sourceRoot":"","sources":["../../src/map/target-class.ts"],"names":[],"mappings":"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"}
|