prismalens 0.0.1 → 0.1.0
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/README.md +12 -2
- package/dist/bin/prismalens.js +13 -0
- package/dist/bin/prismalens.js.map +1 -1
- package/dist/src/cli/doctor.d.ts +15 -1
- package/dist/src/cli/doctor.d.ts.map +1 -1
- package/dist/src/cli/doctor.js +107 -56
- package/dist/src/cli/doctor.js.map +1 -1
- package/dist/src/cli/flags.d.ts +2 -0
- package/dist/src/cli/flags.d.ts.map +1 -0
- package/dist/src/cli/flags.js +25 -0
- package/dist/src/cli/flags.js.map +1 -0
- package/dist/src/cli/grouping.d.ts +18 -0
- package/dist/src/cli/grouping.d.ts.map +1 -0
- package/dist/src/cli/grouping.js +169 -0
- package/dist/src/cli/grouping.js.map +1 -0
- package/dist/src/cli/init.d.ts.map +1 -1
- package/dist/src/cli/init.js +26 -11
- package/dist/src/cli/init.js.map +1 -1
- package/dist/src/cli/investigate.d.ts +14 -0
- package/dist/src/cli/investigate.d.ts.map +1 -1
- package/dist/src/cli/investigate.js +149 -136
- package/dist/src/cli/investigate.js.map +1 -1
- package/dist/src/cli/listen.d.ts +50 -0
- package/dist/src/cli/listen.d.ts.map +1 -0
- package/dist/src/cli/listen.js +249 -0
- package/dist/src/cli/listen.js.map +1 -0
- package/dist/src/cli/report.d.ts +19 -0
- package/dist/src/cli/report.d.ts.map +1 -0
- package/dist/src/cli/report.js +60 -0
- package/dist/src/cli/report.js.map +1 -0
- package/dist/src/cli/serve.d.ts.map +1 -1
- package/dist/src/cli/serve.js +11 -2
- package/dist/src/cli/serve.js.map +1 -1
- package/dist/src/cli/status.d.ts +14 -0
- package/dist/src/cli/status.d.ts.map +1 -0
- package/dist/src/cli/status.js +83 -0
- package/dist/src/cli/status.js.map +1 -0
- package/dist/src/config/loader.d.ts.map +1 -1
- package/dist/src/config/loader.js +28 -2
- package/dist/src/config/loader.js.map +1 -1
- package/dist/src/config/schema.d.ts +121 -0
- package/dist/src/config/schema.d.ts.map +1 -1
- package/dist/src/config/schema.js +47 -1
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/core/caps.d.ts +36 -0
- package/dist/src/core/caps.d.ts.map +1 -0
- package/dist/src/core/caps.js +36 -0
- package/dist/src/core/caps.js.map +1 -0
- package/dist/src/core/db.d.ts +3 -0
- package/dist/src/core/db.d.ts.map +1 -0
- package/dist/src/core/db.js +71 -0
- package/dist/src/core/db.js.map +1 -0
- package/dist/src/core/file-session-store.js +2 -2
- package/dist/src/core/file-session-store.js.map +1 -1
- package/dist/src/core/run-investigation.d.ts +10 -0
- package/dist/src/core/run-investigation.d.ts.map +1 -1
- package/dist/src/core/run-investigation.js +85 -30
- package/dist/src/core/run-investigation.js.map +1 -1
- package/dist/src/core/session.d.ts +22 -1
- package/dist/src/core/session.d.ts.map +1 -1
- package/dist/src/core/session.js +6 -129
- package/dist/src/core/session.js.map +1 -1
- package/dist/src/core/slack-notify.d.ts +9 -0
- package/dist/src/core/slack-notify.d.ts.map +1 -0
- package/dist/src/core/slack-notify.js +57 -0
- package/dist/src/core/slack-notify.js.map +1 -0
- package/dist/src/core/sqlite-session-store.d.ts +39 -0
- package/dist/src/core/sqlite-session-store.d.ts.map +1 -0
- package/dist/src/core/sqlite-session-store.js +239 -0
- package/dist/src/core/sqlite-session-store.js.map +1 -0
- package/dist/src/http/server.d.ts +26 -0
- package/dist/src/http/server.d.ts.map +1 -0
- package/dist/src/http/server.js +151 -0
- package/dist/src/http/server.js.map +1 -0
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -79,6 +79,7 @@ binary and an LLM credential are present.
|
|
|
79
79
|
prismalens <command> [flags] # alias: pl
|
|
80
80
|
|
|
81
81
|
investigate Run a read-only root-cause investigation of a firing alert.
|
|
82
|
+
listen Start a token-authed local HTTP listener for Alertmanager webhooks.
|
|
82
83
|
serve Run the JSON-RPC 2.0 server over stdio (the LIVE channel for apps).
|
|
83
84
|
doctor Preflight-check the investigation environment.
|
|
84
85
|
init Scaffold a prismalens.config.yaml in the current directory.
|
|
@@ -100,8 +101,9 @@ The seed alert comes from **one of**:
|
|
|
100
101
|
| --- | --- |
|
|
101
102
|
| `--repo <dir>` | Path to the repository the harness investigates (its cwd). Defaults to the current directory. |
|
|
102
103
|
| `--query, -q <text>` | Synthesize an alert from this one-line description (alternative to piping a `FiringAlert` JSON on stdin). |
|
|
103
|
-
| `--config <path>` | Path to a `prismalens.config.yaml` (skips the upward config search). |
|
|
104
|
+
| `--config <path>` | Path to a `prismalens.config.yaml` (skips the upward config search; fails closed for missing, unreadable, or invalid paths). |
|
|
104
105
|
| `--model <id>` | Override `agent.model` — a bare model id, e.g. `gpt-oss:120b`. |
|
|
106
|
+
| `--max-turns <n>` | Per-run turn ceiling for the default harness. |
|
|
105
107
|
| `--harness <name>` | Tier-2 backend: `deepagents` \| `claude-code` \| `codex`. Defaults to `agent.default`. |
|
|
106
108
|
| `--json` | Print the `InvestigationReport` as JSON to stdout (suppresses the human renderer; implies quiet). |
|
|
107
109
|
| `--output <file>` | Also write the `InvestigationReport` JSON to this file. |
|
|
@@ -114,6 +116,14 @@ fabricated RCA).
|
|
|
114
116
|
|
|
115
117
|
A `FiringAlert` is `{ alertname, severity, labels, annotations, startsAt }`.
|
|
116
118
|
|
|
119
|
+
### `listen`
|
|
120
|
+
|
|
121
|
+
Start a token-authed local HTTP listener for Alertmanager webhooks; each firing alert triggers an investigation (Phase 1 R1).
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
PRISMALENS_LISTEN_TOKEN=xyz pl listen --config my-stack.yaml
|
|
125
|
+
```
|
|
126
|
+
|
|
117
127
|
### `serve`
|
|
118
128
|
|
|
119
129
|
Runs the JSON-RPC 2.0 server over stdio — the live channel apps drive (see
|
|
@@ -128,7 +138,7 @@ Preflight checklist that gates a run. Prints pass/fail per check; exits non-zero
|
|
|
128
138
|
`claude-code` → `claude`, `codex` → `codex` (for the harness from config).
|
|
129
139
|
- **HARD — an LLM credential:** any of `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` /
|
|
130
140
|
`GOOGLE_API_KEY` / `OLLAMA_API_KEY` / `GROQ_API_KEY` / `CUSTOM_LLM_API_KEY`,
|
|
131
|
-
or, for `claude-code`, a signed-in `~/.claude/.credentials.json`.
|
|
141
|
+
or, for `claude-code`, a signed-in `~/.claude/.credentials.json`. (Performs a live provider model ping by default, while `--no-ping` skips it.)
|
|
132
142
|
- **SOFT — workspace writable:** `workspace.base_dir` can be created/written.
|
|
133
143
|
|
|
134
144
|
### `init`
|
package/dist/bin/prismalens.js
CHANGED
|
@@ -13,6 +13,16 @@ import { cliVersion } from "../src/version.js";
|
|
|
13
13
|
// Off for the whole CLI; real per-warning notices still reach stderr via
|
|
14
14
|
// process.emitWarning.
|
|
15
15
|
globalThis.AI_SDK_LOG_WARNINGS = false;
|
|
16
|
+
const originalWarningListeners = process.listeners("warning");
|
|
17
|
+
process.removeAllListeners("warning");
|
|
18
|
+
process.on("warning", (warning) => {
|
|
19
|
+
if (warning.name === "ExperimentalWarning" &&
|
|
20
|
+
warning.message.includes("SQLite"))
|
|
21
|
+
return;
|
|
22
|
+
for (const listener of originalWarningListeners) {
|
|
23
|
+
listener(warning);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
16
26
|
/** Lazily import a command body's default export from src/cli. */
|
|
17
27
|
const lazy = (name) => () => import(`../src/cli/${name}.js`).then((m) => m.default);
|
|
18
28
|
const main = defineCommand({
|
|
@@ -23,9 +33,12 @@ const main = defineCommand({
|
|
|
23
33
|
},
|
|
24
34
|
subCommands: {
|
|
25
35
|
investigate: lazy("investigate"),
|
|
36
|
+
listen: lazy("listen"),
|
|
26
37
|
serve: lazy("serve"),
|
|
27
38
|
doctor: lazy("doctor"),
|
|
28
39
|
init: lazy("init"),
|
|
40
|
+
status: lazy("status"),
|
|
41
|
+
report: lazy("report"),
|
|
29
42
|
},
|
|
30
43
|
});
|
|
31
44
|
runMain(main);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prismalens.js","sourceRoot":"","sources":["../../bin/prismalens.ts"],"names":[],"mappings":";AACA,sCAAsC;AACtC,6BAA6B;AAE7B;;;;GAIG;AACH,OAAO,EAAmB,aAAa,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,+EAA+E;AAC/E,8EAA8E;AAC9E,yEAAyE;AACzE,uBAAuB;AACtB,UAAgD,CAAC,mBAAmB,GAAG,KAAK,CAAC;AAE9E,kEAAkE;AAClE,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,GAAwB,EAAE,CACxD,MAAM,CAAC,cAAc,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqB,CAAC,CAAC;AAEtE,MAAM,IAAI,GAAG,aAAa,CAAC;IAC1B,IAAI,EAAE;QACL,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,UAAU,EAAE;QACrB,WAAW,EACV,mFAAmF;KACpF;IACD,WAAW,EAAE;QACZ,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC;QAChC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC;QACpB,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;QACtB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"prismalens.js","sourceRoot":"","sources":["../../bin/prismalens.ts"],"names":[],"mappings":";AACA,sCAAsC;AACtC,6BAA6B;AAE7B;;;;GAIG;AACH,OAAO,EAAmB,aAAa,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,+EAA+E;AAC/E,8EAA8E;AAC9E,yEAAyE;AACzE,uBAAuB;AACtB,UAAgD,CAAC,mBAAmB,GAAG,KAAK,CAAC;AAE9E,MAAM,wBAAwB,GAAG,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AAC9D,OAAO,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;AACtC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAc,EAAE,EAAE;IACxC,IACC,OAAO,CAAC,IAAI,KAAK,qBAAqB;QACtC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAElC,OAAO;IACR,KAAK,MAAM,QAAQ,IAAI,wBAAwB,EAAE,CAAC;QACjD,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC;AACF,CAAC,CAAC,CAAC;AAEH,kEAAkE;AAClE,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,GAAwB,EAAE,CACxD,MAAM,CAAC,cAAc,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAqB,CAAC,CAAC;AAEtE,MAAM,IAAI,GAAG,aAAa,CAAC;IAC1B,IAAI,EAAE;QACL,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,UAAU,EAAE;QACrB,WAAW,EACV,mFAAmF;KACpF;IACD,WAAW,EAAE;QACZ,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC;QAChC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;QACtB,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC;QACpB,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;QACtB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;QAClB,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;QACtB,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;KACtB;CACD,CAAC,CAAC;AAEH,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
package/dist/src/cli/doctor.d.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import type { PlConfig } from "../config/schema.js";
|
|
2
|
+
interface Check {
|
|
3
|
+
name: string;
|
|
4
|
+
pass: boolean;
|
|
5
|
+
detail: string;
|
|
6
|
+
hard: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function checkListenToken(config: PlConfig): Check;
|
|
9
|
+
declare const _default: import("citty").CommandDef<{
|
|
10
|
+
readonly ping: {
|
|
11
|
+
readonly type: "boolean";
|
|
12
|
+
readonly description: "Live-ping the LLM credential (disable with --no-ping)";
|
|
13
|
+
readonly default: true;
|
|
14
|
+
};
|
|
15
|
+
}>;
|
|
2
16
|
export default _default;
|
|
3
17
|
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/doctor.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/doctor.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAMpD,UAAU,KAAK;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACd;AA8HD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK,CAgBxD;;;;;;;;AAED,wBAoDG"}
|
package/dist/src/cli/doctor.js
CHANGED
|
@@ -15,18 +15,18 @@
|
|
|
15
15
|
* Prints pass/fail per check; exits non-zero iff a HARD check fails. No tinyexec /
|
|
16
16
|
* check-tool helper here — availability is a dependency-free PATH scan.
|
|
17
17
|
*/
|
|
18
|
-
import { accessSync,
|
|
18
|
+
import { accessSync, constants as fsConstants } from "node:fs";
|
|
19
19
|
import { access, mkdir } from "node:fs/promises";
|
|
20
|
-
import { homedir } from "node:os";
|
|
21
20
|
import { delimiter, join } from "node:path";
|
|
21
|
+
import { resolveCredentials } from "@prismalens/config/credentials";
|
|
22
22
|
import { HARNESS_BINARY } from "@prismalens/config/harness";
|
|
23
|
-
import {
|
|
23
|
+
import { AUTO_SELECT_PROVIDER_IDS, LLM_PROVIDERS, } from "@prismalens/config/llm";
|
|
24
|
+
import { pingModel } from "@prismalens/config/model";
|
|
24
25
|
import { defineCommand } from "citty";
|
|
25
26
|
import consola from "consola";
|
|
26
27
|
import { loadConfig } from "../config/loader.js";
|
|
27
|
-
import { PlConfigSchema } from "../config/schema.js";
|
|
28
28
|
import { resolveBaseDir } from "../core/session.js";
|
|
29
|
-
|
|
29
|
+
import { assertKnownFlags } from "./flags.js";
|
|
30
30
|
function isOnPath(bin) {
|
|
31
31
|
const pathEnv = process.env.PATH ?? "";
|
|
32
32
|
const exts = process.platform === "win32"
|
|
@@ -41,7 +41,7 @@ function isOnPath(bin) {
|
|
|
41
41
|
return true;
|
|
42
42
|
}
|
|
43
43
|
catch {
|
|
44
|
-
//
|
|
44
|
+
// keep looking
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -59,35 +59,63 @@ function checkHarness(harness) {
|
|
|
59
59
|
hard: true,
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
-
function checkCredential(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
async function checkCredential(config, noPing) {
|
|
63
|
+
let providerId = config.synth.provider;
|
|
64
|
+
let creds;
|
|
65
|
+
if (providerId) {
|
|
66
|
+
creds = resolveCredentials(providerId, config.synth.base_url);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
for (const id of AUTO_SELECT_PROVIDER_IDS) {
|
|
70
|
+
const candidate = resolveCredentials(id, config.synth.base_url);
|
|
71
|
+
if (candidate.source !== "none") {
|
|
72
|
+
providerId = id;
|
|
73
|
+
creds = candidate;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!creds) {
|
|
78
|
+
creds = { providerId: "ollama", source: "none" };
|
|
79
|
+
providerId = "ollama";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (creds.source === "none") {
|
|
83
|
+
return {
|
|
84
|
+
name: "LLM credential",
|
|
85
|
+
pass: false,
|
|
86
|
+
detail: "none (reports will be RAW harness pass-through) — not verified",
|
|
87
|
+
hard: false,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const providerName = LLM_PROVIDERS[providerId].name;
|
|
91
|
+
if (noPing) {
|
|
67
92
|
return {
|
|
68
93
|
name: "LLM credential",
|
|
69
94
|
pass: true,
|
|
70
|
-
detail: `${
|
|
71
|
-
hard:
|
|
95
|
+
detail: `${providerName} (source: ${creds.source}) — ping skipped`,
|
|
96
|
+
hard: false,
|
|
72
97
|
};
|
|
73
98
|
}
|
|
74
|
-
|
|
99
|
+
const ping = await pingModel(providerId, config.synth.model, {
|
|
100
|
+
apiKey: creds.apiKey,
|
|
101
|
+
baseURL: creds.baseURL,
|
|
102
|
+
});
|
|
103
|
+
if (ping.success) {
|
|
75
104
|
return {
|
|
76
105
|
name: "LLM credential",
|
|
77
106
|
pass: true,
|
|
78
|
-
detail:
|
|
107
|
+
detail: `${providerName} (source: ${creds.source}) — ping OK`,
|
|
108
|
+
hard: false,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
return {
|
|
113
|
+
name: "LLM credential",
|
|
114
|
+
pass: false,
|
|
115
|
+
detail: `${providerName} (source: ${creds.source}) — ping failed: ${ping.error}`,
|
|
79
116
|
hard: true,
|
|
80
117
|
};
|
|
81
118
|
}
|
|
82
|
-
const hint = harness === "claude-code"
|
|
83
|
-
? "set ANTHROPIC_API_KEY or sign in with `claude` (creates ~/.claude/.credentials.json)"
|
|
84
|
-
: `set one of ${LLM_CREDENTIAL_ENV_VARS.join(", ")}`;
|
|
85
|
-
return {
|
|
86
|
-
name: "LLM credential",
|
|
87
|
-
pass: false,
|
|
88
|
-
detail: `no LLM credential found — ${hint}`,
|
|
89
|
-
hard: true,
|
|
90
|
-
};
|
|
91
119
|
}
|
|
92
120
|
async function checkWorkspace(config) {
|
|
93
121
|
const baseDir = resolveBaseDir(config.workspace.base_dir);
|
|
@@ -110,47 +138,70 @@ async function checkWorkspace(config) {
|
|
|
110
138
|
};
|
|
111
139
|
}
|
|
112
140
|
}
|
|
141
|
+
export function checkListenToken(config) {
|
|
142
|
+
if (config.listen.token) {
|
|
143
|
+
return {
|
|
144
|
+
name: "Listen intake",
|
|
145
|
+
pass: true,
|
|
146
|
+
detail: `token configured; \`pl listen\` will serve on port ${config.listen.port}`,
|
|
147
|
+
hard: false,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
name: "Listen intake",
|
|
152
|
+
pass: false,
|
|
153
|
+
detail: "listen.token is unset — `pl listen` will refuse to start (set listen.token in prismalens.config.yaml)",
|
|
154
|
+
hard: false,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
113
157
|
export default defineCommand({
|
|
114
158
|
meta: {
|
|
115
159
|
name: "doctor",
|
|
116
|
-
description: "Preflight check the investigation environment",
|
|
160
|
+
description: "Preflight check the investigation environment\n\nExamples:\n $ pl doctor --no-ping",
|
|
161
|
+
},
|
|
162
|
+
args: {
|
|
163
|
+
// citty models `--no-ping` as negation of a `ping` boolean — a literal
|
|
164
|
+
// `noPing` arg would never receive it.
|
|
165
|
+
ping: {
|
|
166
|
+
type: "boolean",
|
|
167
|
+
description: "Live-ping the LLM credential (disable with --no-ping)",
|
|
168
|
+
default: true,
|
|
169
|
+
},
|
|
117
170
|
},
|
|
118
|
-
async run() {
|
|
119
|
-
// loadConfig applies schema defaults, so this succeeds even with no config
|
|
120
|
-
// file. It only throws on an invalid file / unset ${VAR}; fall back to the
|
|
121
|
-
// built-in defaults so doctor can still report what it can.
|
|
122
|
-
let config;
|
|
171
|
+
async run({ args, cmd }) {
|
|
123
172
|
try {
|
|
124
|
-
|
|
173
|
+
assertKnownFlags(args, cmd);
|
|
174
|
+
const config = await loadConfig();
|
|
175
|
+
const harness = config.agent.default;
|
|
176
|
+
const noPing = !args.ping;
|
|
177
|
+
const checks = [
|
|
178
|
+
checkHarness(harness),
|
|
179
|
+
await checkCredential(config, noPing),
|
|
180
|
+
await checkWorkspace(config),
|
|
181
|
+
checkListenToken(config),
|
|
182
|
+
];
|
|
183
|
+
consola.log("");
|
|
184
|
+
for (const check of checks) {
|
|
185
|
+
const line = `${check.name}: ${check.detail}`;
|
|
186
|
+
if (check.pass)
|
|
187
|
+
consola.success(line);
|
|
188
|
+
else if (check.hard)
|
|
189
|
+
consola.error(line);
|
|
190
|
+
else
|
|
191
|
+
consola.warn(line);
|
|
192
|
+
}
|
|
193
|
+
consola.log("");
|
|
194
|
+
const hardFailures = checks.filter((c) => c.hard && !c.pass);
|
|
195
|
+
if (hardFailures.length > 0) {
|
|
196
|
+
consola.error(`${hardFailures.length} required check(s) failed — fix the above before investigating.`);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
consola.success("All required checks passed.");
|
|
125
200
|
}
|
|
126
201
|
catch (err) {
|
|
127
|
-
|
|
128
|
-
consola.warn(`Could not load config (${detail}); using built-in defaults.`);
|
|
129
|
-
config = PlConfigSchema.parse({});
|
|
130
|
-
}
|
|
131
|
-
const harness = config.agent.default;
|
|
132
|
-
const checks = [
|
|
133
|
-
checkHarness(harness),
|
|
134
|
-
checkCredential(harness),
|
|
135
|
-
await checkWorkspace(config),
|
|
136
|
-
];
|
|
137
|
-
consola.log("");
|
|
138
|
-
for (const check of checks) {
|
|
139
|
-
const line = `${check.name}: ${check.detail}`;
|
|
140
|
-
if (check.pass)
|
|
141
|
-
consola.success(line);
|
|
142
|
-
else if (check.hard)
|
|
143
|
-
consola.error(line);
|
|
144
|
-
else
|
|
145
|
-
consola.warn(line);
|
|
146
|
-
}
|
|
147
|
-
consola.log("");
|
|
148
|
-
const hardFailures = checks.filter((c) => c.hard && !c.pass);
|
|
149
|
-
if (hardFailures.length > 0) {
|
|
150
|
-
consola.error(`${hardFailures.length} required check(s) failed — fix the above before investigating.`);
|
|
202
|
+
consola.error(err instanceof Error ? err.message : String(err));
|
|
151
203
|
process.exit(1);
|
|
152
204
|
}
|
|
153
|
-
consola.success("All required checks passed.");
|
|
154
205
|
},
|
|
155
206
|
});
|
|
156
207
|
//# sourceMappingURL=doctor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/doctor.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,6BAA6B;AAE7B;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../../../src/cli/flags.ts"],"names":[],"mappings":"AASA,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,OAAO,QAmB3E"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2026 Sumit Patel
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
function kebabToCamel(str) {
|
|
5
|
+
return str.replace(/-([a-z])/g, (_, g) => g.toUpperCase());
|
|
6
|
+
}
|
|
7
|
+
export function assertKnownFlags(args, cmd) {
|
|
8
|
+
const declaredArgs = cmd?.args || {};
|
|
9
|
+
const allowedKeys = new Set(["_"]);
|
|
10
|
+
for (const key in declaredArgs) {
|
|
11
|
+
if (Object.hasOwn(declaredArgs, key)) {
|
|
12
|
+
allowedKeys.add(key);
|
|
13
|
+
allowedKeys.add(kebabToCamel(key));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
for (const key in args) {
|
|
17
|
+
if (Object.hasOwn(args, key)) {
|
|
18
|
+
if (!allowedKeys.has(key)) {
|
|
19
|
+
consola.error(`Unknown option: --${key}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=flags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../../../src/cli/flags.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,6BAA6B;AAE7B,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,SAAS,YAAY,CAAC,GAAW;IAChC,OAAO,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAA6B,EAAE,GAAY;IAC3E,MAAM,YAAY,GAAI,GAA0C,EAAE,IAAI,IAAI,EAAE,CAAC;IAC7E,MAAM,WAAW,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IAE3C,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAChC,IAAI,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,EAAE,CAAC;YACtC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACrB,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QACpC,CAAC;IACF,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC3B,OAAO,CAAC,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;gBAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjB,CAAC;QACF,CAAC;IACF,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SessionManager } from "../core/session.js";
|
|
2
|
+
export interface GroupingPort {
|
|
3
|
+
newGroupCount(firing: Record<string, unknown>[], payload: Record<string, unknown>): number;
|
|
4
|
+
pendingGroups(): number;
|
|
5
|
+
admit(firing: Record<string, unknown>[], payload: Record<string, unknown>): void;
|
|
6
|
+
shutdown(): void;
|
|
7
|
+
isShuttingDown(): boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface GroupingOptions {
|
|
10
|
+
windowMs: number;
|
|
11
|
+
sessions: SessionManager;
|
|
12
|
+
runInvestigation: (runId: string, alerts: Record<string, unknown>[]) => Promise<void>;
|
|
13
|
+
log: (msg: string) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function deriveGroupKey(alert: Record<string, unknown>, payload: Record<string, unknown>): string;
|
|
16
|
+
export declare function deriveDedupeKey(alert: Record<string, unknown>): string;
|
|
17
|
+
export declare function createGroupingLayer(options: GroupingOptions): GroupingPort;
|
|
18
|
+
//# sourceMappingURL=grouping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grouping.d.ts","sourceRoot":"","sources":["../../../src/cli/grouping.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEtE,MAAM,WAAW,YAAY;IAC5B,aAAa,CACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,MAAM,CAAC;IACV,aAAa,IAAI,MAAM,CAAC;IACxB,KAAK,CACJ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,IAAI,CAAC;IACR,QAAQ,IAAI,IAAI,CAAC;IACjB,cAAc,IAAI,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,cAAc,CAAC;IACzB,gBAAgB,EAAE,CACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAC7B,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3B;AAED,wBAAgB,cAAc,CAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,MAAM,CA8BR;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAetE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,YAAY,CAqJ1E"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2026 Sumit Patel
|
|
3
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
4
|
+
import { pickServiceLabel } from "../core/run-investigation.js";
|
|
5
|
+
export function deriveGroupKey(alert, payload) {
|
|
6
|
+
if (typeof payload.groupKey === "string" && payload.groupKey) {
|
|
7
|
+
return payload.groupKey;
|
|
8
|
+
}
|
|
9
|
+
if (payload.groupLabels && typeof payload.groupLabels === "object") {
|
|
10
|
+
const labels = payload.groupLabels;
|
|
11
|
+
const keys = Object.keys(labels);
|
|
12
|
+
if (keys.length > 0) {
|
|
13
|
+
const sorted = keys
|
|
14
|
+
.sort()
|
|
15
|
+
.map((k) => `${k}=${labels[k]}`)
|
|
16
|
+
.join(",");
|
|
17
|
+
return createHash("sha256").update(sorted).digest("hex");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const serviceLabel = pickServiceLabel(alert);
|
|
21
|
+
const alertname = alert.labels?.alertname || "";
|
|
22
|
+
if (serviceLabel) {
|
|
23
|
+
return `${alertname}\0${serviceLabel}`;
|
|
24
|
+
}
|
|
25
|
+
const alertLabels = alert.labels;
|
|
26
|
+
if (alertLabels && Object.keys(alertLabels).length > 0) {
|
|
27
|
+
const sorted = Object.keys(alertLabels)
|
|
28
|
+
.sort()
|
|
29
|
+
.map((k) => `${k}=${alertLabels[k]}`)
|
|
30
|
+
.join(",");
|
|
31
|
+
return createHash("sha256").update(sorted).digest("hex");
|
|
32
|
+
}
|
|
33
|
+
return "default";
|
|
34
|
+
}
|
|
35
|
+
export function deriveDedupeKey(alert) {
|
|
36
|
+
if (typeof alert.fingerprint === "string" && alert.fingerprint) {
|
|
37
|
+
return alert.fingerprint;
|
|
38
|
+
}
|
|
39
|
+
const alertLabels = alert.labels;
|
|
40
|
+
const alertname = alertLabels?.alertname || "";
|
|
41
|
+
const sorted = alertLabels
|
|
42
|
+
? Object.keys(alertLabels)
|
|
43
|
+
.sort()
|
|
44
|
+
.map((k) => `${k}=${alertLabels[k]}`)
|
|
45
|
+
.join(",")
|
|
46
|
+
: "";
|
|
47
|
+
const hash = createHash("sha256").update(sorted).digest("hex");
|
|
48
|
+
const startsAt = alert.startsAt || "";
|
|
49
|
+
return `${alertname}${hash}${startsAt}`;
|
|
50
|
+
}
|
|
51
|
+
export function createGroupingLayer(options) {
|
|
52
|
+
let shuttingDown = false;
|
|
53
|
+
const windows = new Map();
|
|
54
|
+
const running = new Map();
|
|
55
|
+
return {
|
|
56
|
+
isShuttingDown() {
|
|
57
|
+
return shuttingDown;
|
|
58
|
+
},
|
|
59
|
+
newGroupCount(firing, payload) {
|
|
60
|
+
const keys = new Set();
|
|
61
|
+
for (const alert of firing) {
|
|
62
|
+
const key = deriveGroupKey(alert, payload);
|
|
63
|
+
if (!windows.has(key) && !running.has(key)) {
|
|
64
|
+
keys.add(key);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return keys.size;
|
|
68
|
+
},
|
|
69
|
+
pendingGroups() {
|
|
70
|
+
return windows.size + running.size;
|
|
71
|
+
},
|
|
72
|
+
admit(firing, payload) {
|
|
73
|
+
if (shuttingDown) {
|
|
74
|
+
options.log("Dropped alert: grouping layer is shutting down");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
for (const alert of firing) {
|
|
78
|
+
const groupKey = deriveGroupKey(alert, payload);
|
|
79
|
+
const dedupeKey = deriveDedupeKey(alert);
|
|
80
|
+
if (running.has(groupKey)) {
|
|
81
|
+
const state = running.get(groupKey);
|
|
82
|
+
if (state && !state.seenKeys.has(dedupeKey)) {
|
|
83
|
+
state.seenKeys.add(dedupeKey);
|
|
84
|
+
// ATTACH
|
|
85
|
+
state.writeQueue = state.writeQueue
|
|
86
|
+
.then(() => options.sessions.appendGroupAlert(state.runId, alert))
|
|
87
|
+
.catch((err) => {
|
|
88
|
+
options.log(`Failed to attach late alert to group ${groupKey} (run ${state.runId}): ${err}`);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (windows.has(groupKey)) {
|
|
94
|
+
const state = windows.get(groupKey);
|
|
95
|
+
if (state && !state.seenKeys.has(dedupeKey)) {
|
|
96
|
+
state.seenKeys.add(dedupeKey);
|
|
97
|
+
state.alerts.push(alert);
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
// IDLE -> WINDOW_OPEN
|
|
102
|
+
const state = {
|
|
103
|
+
alerts: [alert],
|
|
104
|
+
seenKeys: new Set([dedupeKey]),
|
|
105
|
+
timer: setTimeout(() => {
|
|
106
|
+
// timer fires -> RUNNING
|
|
107
|
+
const alertsToRun = state.alerts;
|
|
108
|
+
const seenKeys = state.seenKeys;
|
|
109
|
+
windows.delete(groupKey);
|
|
110
|
+
const runId = randomUUID();
|
|
111
|
+
// synchronously set up the record
|
|
112
|
+
const rec = {
|
|
113
|
+
groupKey,
|
|
114
|
+
formedBy: "window",
|
|
115
|
+
alerts: alertsToRun,
|
|
116
|
+
lateAlerts: [],
|
|
117
|
+
};
|
|
118
|
+
const writePromise = Promise.resolve()
|
|
119
|
+
.then(() => options.sessions.writeGroupRecord(runId, rec))
|
|
120
|
+
.catch((err) => {
|
|
121
|
+
options.log(`Failed to write group record for group ${groupKey} (run ${runId}): ${err} — investigation will proceed without it`);
|
|
122
|
+
});
|
|
123
|
+
running.set(groupKey, {
|
|
124
|
+
runId,
|
|
125
|
+
seenKeys,
|
|
126
|
+
writeQueue: writePromise,
|
|
127
|
+
});
|
|
128
|
+
writePromise
|
|
129
|
+
.then(async () => {
|
|
130
|
+
// Shutdown may land between the timer firing and the write
|
|
131
|
+
// resolving; don't start a new investigation while closing.
|
|
132
|
+
if (shuttingDown) {
|
|
133
|
+
running.delete(groupKey);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
await options.runInvestigation(runId, alertsToRun);
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
options.log(`Investigation for group ${groupKey} failed: ${err}`);
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
running.delete(groupKey);
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
.catch((err) => {
|
|
147
|
+
options.log(`Investigation for group ${groupKey} failed: ${err}`);
|
|
148
|
+
running.delete(groupKey);
|
|
149
|
+
});
|
|
150
|
+
}, options.windowMs),
|
|
151
|
+
};
|
|
152
|
+
windows.set(groupKey, state);
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
shutdown() {
|
|
156
|
+
shuttingDown = true;
|
|
157
|
+
let dropped = 0;
|
|
158
|
+
for (const state of windows.values()) {
|
|
159
|
+
clearTimeout(state.timer);
|
|
160
|
+
dropped++;
|
|
161
|
+
}
|
|
162
|
+
windows.clear();
|
|
163
|
+
if (dropped > 0) {
|
|
164
|
+
options.log(`Shutdown: dropped ${dropped} pending grouping windows`);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=grouping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grouping.js","sourceRoot":"","sources":["../../../src/cli/grouping.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/init.ts"],"names":[],"mappings":";AAiFA,wBA8BG"}
|