mcp-aws-manager 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -7
- package/README_KO.md +29 -8
- package/bin/lib/output-presentation.js +20 -1
- package/bin/mcp-aws-manager.js +283 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,13 +4,33 @@ AWS operations CLI + MCP stdio server (SSM-first).
|
|
|
4
4
|
|
|
5
5
|
This package orchestrates AWS operations (inventory/runtime/remediation) with a normalized output schema and `ACTION_REQUIRED` guidance. It is not a plain AWS CLI wrapper.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Agent-First Quick Start
|
|
8
|
+
|
|
9
|
+
Use this as the default flow for agent environments:
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
12
|
npm install -g mcp-aws-manager
|
|
11
|
-
mcp-aws-manager
|
|
13
|
+
mcp-aws-manager --version
|
|
14
|
+
mcp-aws-manager setup --force
|
|
12
15
|
mcp-aws-manager doctor
|
|
13
|
-
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Agent Prompt Examples:
|
|
19
|
+
|
|
20
|
+
Ask in natural language like below; the agent should run fetch/analysis steps as needed.
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
Give me a fresh full AWS server status summary.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Then try requests like:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
Compare current AWS server status with the previous check and show only what changed.
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
Summarize AWS server status with required actions and high-impact warnings in priority order.
|
|
14
34
|
```
|
|
15
35
|
|
|
16
36
|
## What It Does
|
|
@@ -152,16 +172,21 @@ Optional explicit registration:
|
|
|
152
172
|
|
|
153
173
|
```bash
|
|
154
174
|
mcp-aws-manager setup
|
|
155
|
-
mcp-aws-manager setup --clients
|
|
156
|
-
mcp-aws-manager setup --clients
|
|
175
|
+
mcp-aws-manager setup --clients cursor
|
|
176
|
+
mcp-aws-manager setup --clients codex
|
|
177
|
+
mcp-aws-manager setup --clients claude
|
|
157
178
|
```
|
|
158
179
|
|
|
180
|
+
Default behavior (`setup`/`bootstrap` without `--clients`) auto-detects installed clients and registers only detected CLIs.
|
|
181
|
+
|
|
159
182
|
2. Health check:
|
|
160
183
|
|
|
161
184
|
```bash
|
|
162
185
|
mcp-aws-manager doctor
|
|
163
186
|
```
|
|
164
187
|
|
|
188
|
+
Default behavior (`doctor` without `--clients`) auto-detects installed clients and skips non-installed CLIs.
|
|
189
|
+
|
|
165
190
|
3. Configure AWS auth (SSO recommended):
|
|
166
191
|
|
|
167
192
|
```bash
|
|
@@ -973,5 +998,3 @@ Document status:
|
|
|
973
998
|
- `docs/RECORDS_FIELD_REFERENCE_KO.md`: full `records[]` field reference (292 fields)
|
|
974
999
|
- `docs/RESPONSE_COMPATIBILITY_POLICY.md`: response schema/version compatibility rules
|
|
975
1000
|
- `schemas/mcp-tool-response.schema.json`: canonical tool response JSON schema
|
|
976
|
-
|
|
977
|
-
|
package/README_KO.md
CHANGED
|
@@ -4,13 +4,32 @@ SSM 우선(SSM-first) 방식의 AWS 운영 CLI + MCP stdio 서버입니다.
|
|
|
4
4
|
|
|
5
5
|
이 패키지는 AWS 운영 작업(인벤토리/런타임/조치)을 정규화된 응답 스키마와 `ACTION_REQUIRED` 가이드로 제공합니다. 단순 AWS CLI 래퍼가 아니라, 에이전트 친화적인 운영 워크플로우 실행을 목표로 합니다.
|
|
6
6
|
|
|
7
|
-
## 빠른 시작
|
|
7
|
+
## 에이전트 기준 빠른 시작
|
|
8
|
+
|
|
9
|
+
에이전트 환경에서는 아래 순서를 기본 플로우로 사용하세요.
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
12
|
npm install -g mcp-aws-manager
|
|
11
|
-
mcp-aws-manager
|
|
13
|
+
mcp-aws-manager --version
|
|
14
|
+
mcp-aws-manager setup --force
|
|
12
15
|
mcp-aws-manager doctor
|
|
13
|
-
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
에이전트 예시 프롬프트:
|
|
19
|
+
|
|
20
|
+
아래처럼 자연어로 요청하면, 에이전트가 필요 시 조회/분석 단계를 실행합니다.
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
AWS 서버 상태 전체를 최신으로 점검해서 요약해주세요.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
이후에는 이렇게 요청해보세요.
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
AWS 서버 상태를 지난 점검 결과와 비교해서 달라진 항목만 알려주세요.
|
|
30
|
+
```
|
|
31
|
+
```text
|
|
32
|
+
AWS 서버의 상태를 필수 조치 및 주요 경고 사항을 중심으로 우선순위에 따라 요약해주세요.
|
|
14
33
|
```
|
|
15
34
|
|
|
16
35
|
## 무엇을 제공하나요
|
|
@@ -152,16 +171,21 @@ bootstrap/setup 기본 동작은 단일 서버 1개를 등록합니다.
|
|
|
152
171
|
|
|
153
172
|
```bash
|
|
154
173
|
mcp-aws-manager setup
|
|
155
|
-
mcp-aws-manager setup --clients
|
|
156
|
-
mcp-aws-manager setup --clients
|
|
174
|
+
mcp-aws-manager setup --clients cursor
|
|
175
|
+
mcp-aws-manager setup --clients codex
|
|
176
|
+
mcp-aws-manager setup --clients claude
|
|
157
177
|
```
|
|
158
178
|
|
|
179
|
+
기본 동작(`--clients` 없이 `setup`/`bootstrap`)은 설치된 클라이언트를 자동 감지해, 감지된 CLI만 등록합니다.
|
|
180
|
+
|
|
159
181
|
2. 상태 점검:
|
|
160
182
|
|
|
161
183
|
```bash
|
|
162
184
|
mcp-aws-manager doctor
|
|
163
185
|
```
|
|
164
186
|
|
|
187
|
+
기본 동작(`--clients` 없이 `doctor`)은 설치된 클라이언트를 자동 감지하고, 미설치 CLI는 skip 처리합니다.
|
|
188
|
+
|
|
165
189
|
3. AWS 인증 설정(권장: SSO):
|
|
166
190
|
|
|
167
191
|
```bash
|
|
@@ -967,6 +991,3 @@ E2E 러너 검증 항목:
|
|
|
967
991
|
- `docs/RECORDS_FIELD_REFERENCE_KO.md`: `records[]` 전수 필드(292개) 레퍼런스
|
|
968
992
|
- `docs/RESPONSE_COMPATIBILITY_POLICY.md`: 응답 스키마/버전 호환 정책
|
|
969
993
|
- `schemas/mcp-tool-response.schema.json`: 표준 도구 응답 JSON 스키마
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
@@ -329,7 +329,8 @@ function pickSectionPayload(section, context) {
|
|
|
329
329
|
runFinishedAt: runMeta.runFinishedAt || null,
|
|
330
330
|
outputHash: runMeta.outputHash || null,
|
|
331
331
|
recordsHash: runMeta.recordsHash || null,
|
|
332
|
-
htmlHash: runMeta.htmlHash || null
|
|
332
|
+
htmlHash: runMeta.htmlHash || null,
|
|
333
|
+
generatedArtifacts: runMeta.generatedArtifacts || null
|
|
333
334
|
};
|
|
334
335
|
}
|
|
335
336
|
return {};
|
|
@@ -428,6 +429,12 @@ function renderMarkdown(bundle, templateName = "default") {
|
|
|
428
429
|
const fields = bundle && bundle.fields && Array.isArray(bundle.fields.effectiveFields)
|
|
429
430
|
? bundle.fields.effectiveFields
|
|
430
431
|
: ["resourceType", "resourceId", "profile", "region", "state"];
|
|
432
|
+
const runMeta = bundle && bundle.runMeta && typeof bundle.runMeta === "object"
|
|
433
|
+
? bundle.runMeta
|
|
434
|
+
: {};
|
|
435
|
+
const generatedArtifacts = runMeta.generatedArtifacts && typeof runMeta.generatedArtifacts === "object"
|
|
436
|
+
? runMeta.generatedArtifacts
|
|
437
|
+
: {};
|
|
431
438
|
|
|
432
439
|
const lines = [];
|
|
433
440
|
lines.push("# AWS Discovery Output");
|
|
@@ -451,6 +458,18 @@ function renderMarkdown(bundle, templateName = "default") {
|
|
|
451
458
|
lines.push(`| runtimeSnapshotSuccessCount | ${summary.runtimeSnapshotSuccessCount || 0} |`);
|
|
452
459
|
lines.push("");
|
|
453
460
|
|
|
461
|
+
lines.push("## Generated Artifacts");
|
|
462
|
+
lines.push("");
|
|
463
|
+
lines.push("| artifact | path |");
|
|
464
|
+
lines.push("|---|---|");
|
|
465
|
+
lines.push(`| output | ${generatedArtifacts.outputPath || (generatedArtifacts.outputChannel || "stdout")} |`);
|
|
466
|
+
lines.push(`| htmlReport | ${generatedArtifacts.htmlReportPath || "off"} |`);
|
|
467
|
+
lines.push(`| topology | ${generatedArtifacts.topologyPath || "off"} |`);
|
|
468
|
+
lines.push(`| relationships | ${generatedArtifacts.relationshipsPath || "off"} |`);
|
|
469
|
+
lines.push(`| governanceLog | ${generatedArtifacts.governanceLogPath || "off"} |`);
|
|
470
|
+
lines.push(`| incidentPayload | ${generatedArtifacts.incidentPayloadPath || "off"} |`);
|
|
471
|
+
lines.push("");
|
|
472
|
+
|
|
454
473
|
if (template === "default" && sections.length) {
|
|
455
474
|
lines.push("## Sections");
|
|
456
475
|
lines.push("");
|
package/bin/mcp-aws-manager.js
CHANGED
|
@@ -723,6 +723,8 @@ function usageText() {
|
|
|
723
723
|
return [
|
|
724
724
|
"Usage:",
|
|
725
725
|
" mcp-aws-manager",
|
|
726
|
+
" mcp-aws-manager version",
|
|
727
|
+
" mcp-aws-manager --version",
|
|
726
728
|
" mcp-aws-manager bootstrap [options]",
|
|
727
729
|
" mcp-aws-manager setup [options]",
|
|
728
730
|
" mcp-aws-manager doctor [options]",
|
|
@@ -734,6 +736,7 @@ function usageText() {
|
|
|
734
736
|
"SSM-first AWS inventory/runtime collector (EC2/Lambda/ALB/ASG/RDS/ElastiCache/Route53 + VPC/ECS/S3/IAM/KMS/CloudWatch/CloudTrail/Config/ECR/DynamoDB/SNS/SQS/Budgets/CostAnomaly + EBS/EFS/EKS/APIGateway/CloudFront/WAF/Shield/StepFunctions/CloudWatchLogs/X-Ray/Inspector2/Redshift/OpenSearch/Organizations/ControlTower + ACM/Kinesis/MSK) plus MCP client setup helper.",
|
|
735
737
|
"",
|
|
736
738
|
"Commands:",
|
|
739
|
+
" version Print CLI package version",
|
|
737
740
|
" bootstrap Ensure mcp-aws-manager MCP server is registered (default command)",
|
|
738
741
|
" setup Register/re-register MCP server for supported clients",
|
|
739
742
|
" doctor Check install and registration health",
|
|
@@ -743,7 +746,7 @@ function usageText() {
|
|
|
743
746
|
"",
|
|
744
747
|
"Setup/Bootstrap/Doctor options:",
|
|
745
748
|
" (target: mcp-aws-manager => auto-resolved runtime command for mcp-aws-manager-mcp)",
|
|
746
|
-
` --clients <${clientList}> (default:
|
|
749
|
+
` --clients <${clientList}> (default: auto-detect installed clients)`,
|
|
747
750
|
" --force (setup/bootstrap only; always remove then add)",
|
|
748
751
|
" -h, --help",
|
|
749
752
|
"",
|
|
@@ -995,6 +998,9 @@ function parseCommand(argv) {
|
|
|
995
998
|
}
|
|
996
999
|
|
|
997
1000
|
const first = String(args[0] || "");
|
|
1001
|
+
if (first === "-v" || first === "--version" || first === "version") {
|
|
1002
|
+
return { command: "version", args: [] };
|
|
1003
|
+
}
|
|
998
1004
|
if (first === "-h" || first === "--help") {
|
|
999
1005
|
return { command: "help", args: [] };
|
|
1000
1006
|
}
|
|
@@ -1071,10 +1077,12 @@ function parseRegistrationArgs(argv, opts = {}) {
|
|
|
1071
1077
|
}
|
|
1072
1078
|
|
|
1073
1079
|
const defaultTarget = resolveDefaultRegistrationTarget();
|
|
1080
|
+
const clientsExplicit = Boolean(options.clients && String(options.clients).trim());
|
|
1074
1081
|
return {
|
|
1075
1082
|
help: false,
|
|
1076
1083
|
targets: [defaultTarget],
|
|
1077
|
-
clients: options.clients ? parseClients(options.clients) :
|
|
1084
|
+
clients: options.clients ? parseClients(options.clients) : Array.from(SUPPORTED_CLIENTS),
|
|
1085
|
+
clientsExplicit,
|
|
1078
1086
|
force: options.force
|
|
1079
1087
|
};
|
|
1080
1088
|
}
|
|
@@ -2303,6 +2311,16 @@ function listLocalAwsProfiles() {
|
|
|
2303
2311
|
}
|
|
2304
2312
|
|
|
2305
2313
|
function runCLICommand(cliBin, args, options = {}) {
|
|
2314
|
+
// Cursor 2.x no longer reliably supports `cursor mcp ...` CLI subcommands.
|
|
2315
|
+
// Calling it can open editor tabs named like "mcp", "add", "get".
|
|
2316
|
+
if (String(cliBin).toLowerCase() === "cursor" && Array.isArray(args) && String(args[0] || "").toLowerCase() === "mcp") {
|
|
2317
|
+
return {
|
|
2318
|
+
status: 2,
|
|
2319
|
+
stdout: "",
|
|
2320
|
+
stderr: "cursor mcp subcommand is disabled; use ~/.cursor/mcp.json registration"
|
|
2321
|
+
};
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2306
2324
|
const execOptions = {
|
|
2307
2325
|
cwd: process.cwd(),
|
|
2308
2326
|
env: process.env,
|
|
@@ -2343,7 +2361,12 @@ function commandExists(bin, checkArgs) {
|
|
|
2343
2361
|
}
|
|
2344
2362
|
|
|
2345
2363
|
function clientHelpAttempts(cliBin) {
|
|
2346
|
-
if (cliBin === "cursor"
|
|
2364
|
+
if (cliBin === "cursor") {
|
|
2365
|
+
return [
|
|
2366
|
+
["--help"]
|
|
2367
|
+
];
|
|
2368
|
+
}
|
|
2369
|
+
if (cliBin === "windsurf" || cliBin === "antigravity") {
|
|
2347
2370
|
return [
|
|
2348
2371
|
["mcp", "--help"],
|
|
2349
2372
|
["--help"]
|
|
@@ -2352,6 +2375,118 @@ function clientHelpAttempts(cliBin) {
|
|
|
2352
2375
|
return [["mcp", "--help"]];
|
|
2353
2376
|
}
|
|
2354
2377
|
|
|
2378
|
+
function cursorMcpConfigPath() {
|
|
2379
|
+
const explicitPath = envText("CURSOR_MCP_CONFIG_PATH");
|
|
2380
|
+
if (explicitPath) {
|
|
2381
|
+
return path.resolve(explicitPath);
|
|
2382
|
+
}
|
|
2383
|
+
return path.join(os.homedir(), ".cursor", "mcp.json");
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
function normalizeComparableText(value) {
|
|
2387
|
+
const text = String(value == null ? "" : value).trim();
|
|
2388
|
+
return process.platform === "win32" ? text.toLowerCase() : text;
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
function normalizeComparableArgs(args) {
|
|
2392
|
+
return Array.isArray(args) ? args.map((arg) => normalizeComparableText(arg)) : [];
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2395
|
+
function readCursorMcpConfig() {
|
|
2396
|
+
const filePath = cursorMcpConfigPath();
|
|
2397
|
+
if (!fs.existsSync(filePath)) {
|
|
2398
|
+
return { ok: true, filePath, exists: false, data: { mcpServers: {} } };
|
|
2399
|
+
}
|
|
2400
|
+
try {
|
|
2401
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
2402
|
+
const normalizedRaw = raw.replace(/^\uFEFF/, "");
|
|
2403
|
+
if (!normalizedRaw.trim()) {
|
|
2404
|
+
return { ok: true, filePath, exists: true, data: { mcpServers: {} } };
|
|
2405
|
+
}
|
|
2406
|
+
const parsed = JSON.parse(normalizedRaw);
|
|
2407
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2408
|
+
return { ok: false, filePath, error: "Cursor MCP config must be a JSON object." };
|
|
2409
|
+
}
|
|
2410
|
+
const mcpServers = parsed.mcpServers && typeof parsed.mcpServers === "object" && !Array.isArray(parsed.mcpServers)
|
|
2411
|
+
? parsed.mcpServers
|
|
2412
|
+
: {};
|
|
2413
|
+
return { ok: true, filePath, exists: true, data: { ...parsed, mcpServers } };
|
|
2414
|
+
} catch (error) {
|
|
2415
|
+
return {
|
|
2416
|
+
ok: false,
|
|
2417
|
+
filePath,
|
|
2418
|
+
error: `Failed to parse Cursor MCP config: ${error && error.message ? error.message : String(error)}`
|
|
2419
|
+
};
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
function writeCursorMcpConfig(filePath, data) {
|
|
2424
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
2425
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
function cursorRegistrationMatches(entry, mcpCommand, mcpArgs = []) {
|
|
2429
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return false;
|
|
2430
|
+
const entryCommand = normalizeComparableText(entry.command);
|
|
2431
|
+
if (!entryCommand) return false;
|
|
2432
|
+
if (normalizeComparableText(mcpCommand) && entryCommand !== normalizeComparableText(mcpCommand)) {
|
|
2433
|
+
return false;
|
|
2434
|
+
}
|
|
2435
|
+
const expectedArgs = normalizeComparableArgs(mcpArgs);
|
|
2436
|
+
const actualArgs = normalizeComparableArgs(entry.args);
|
|
2437
|
+
if (expectedArgs.length !== actualArgs.length) return false;
|
|
2438
|
+
for (let i = 0; i < expectedArgs.length; i += 1) {
|
|
2439
|
+
if (expectedArgs[i] !== actualArgs[i]) return false;
|
|
2440
|
+
}
|
|
2441
|
+
return true;
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
function ensureCursorRegistered(serverName, mcpCommand, mcpArgs = [], force = false) {
|
|
2445
|
+
const loaded = readCursorMcpConfig();
|
|
2446
|
+
if (!loaded.ok) {
|
|
2447
|
+
return { ok: false, action: "cursor config invalid", detail: `${loaded.error} (${loaded.filePath})` };
|
|
2448
|
+
}
|
|
2449
|
+
const desiredEntry = {
|
|
2450
|
+
command: String(mcpCommand || ""),
|
|
2451
|
+
args: Array.isArray(mcpArgs) ? mcpArgs.map((arg) => String(arg)) : []
|
|
2452
|
+
};
|
|
2453
|
+
const config = loaded.data;
|
|
2454
|
+
const current = config.mcpServers[serverName];
|
|
2455
|
+
if (force || !cursorRegistrationMatches(current, desiredEntry.command, desiredEntry.args)) {
|
|
2456
|
+
config.mcpServers[serverName] = desiredEntry;
|
|
2457
|
+
try {
|
|
2458
|
+
writeCursorMcpConfig(loaded.filePath, config);
|
|
2459
|
+
} catch (error) {
|
|
2460
|
+
return {
|
|
2461
|
+
ok: false,
|
|
2462
|
+
action: "cursor registration failed",
|
|
2463
|
+
detail: `${error && error.message ? error.message : String(error)} (${loaded.filePath})`
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2466
|
+
return { ok: true, action: "registered", detail: loaded.filePath };
|
|
2467
|
+
}
|
|
2468
|
+
return { ok: true, action: "already registered", detail: loaded.filePath };
|
|
2469
|
+
}
|
|
2470
|
+
|
|
2471
|
+
function removeCursorRegistration(serverName) {
|
|
2472
|
+
const loaded = readCursorMcpConfig();
|
|
2473
|
+
if (!loaded.ok || !loaded.exists) return;
|
|
2474
|
+
if (!Object.prototype.hasOwnProperty.call(loaded.data.mcpServers, serverName)) return;
|
|
2475
|
+
delete loaded.data.mcpServers[serverName];
|
|
2476
|
+
try {
|
|
2477
|
+
writeCursorMcpConfig(loaded.filePath, loaded.data);
|
|
2478
|
+
} catch (_) {
|
|
2479
|
+
// ignore best-effort cleanup
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
function isCursorRegistered(serverName, mcpCommand, mcpArgs = []) {
|
|
2484
|
+
const loaded = readCursorMcpConfig();
|
|
2485
|
+
if (!loaded.ok) return false;
|
|
2486
|
+
const entry = loaded.data && loaded.data.mcpServers ? loaded.data.mcpServers[serverName] : null;
|
|
2487
|
+
return cursorRegistrationMatches(entry, mcpCommand, mcpArgs);
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2355
2490
|
function clientGetAttempts(cliBin, serverName) {
|
|
2356
2491
|
if (cliBin === "claude") {
|
|
2357
2492
|
return [
|
|
@@ -2419,13 +2554,22 @@ function clientAddAttempts(cliBin, serverName, mcpCommand, mcpArgs = []) {
|
|
|
2419
2554
|
}
|
|
2420
2555
|
|
|
2421
2556
|
function removeRegistration(cliBin, serverName) {
|
|
2557
|
+
if (cliBin === "cursor") {
|
|
2558
|
+
removeCursorRegistration(serverName);
|
|
2559
|
+
return;
|
|
2560
|
+
}
|
|
2422
2561
|
const attempts = clientRemoveAttempts(cliBin, serverName);
|
|
2423
2562
|
for (const args of attempts) {
|
|
2424
2563
|
runCLICommand(cliBin, args, { stdio: "ignore" });
|
|
2425
2564
|
}
|
|
2426
2565
|
}
|
|
2427
2566
|
|
|
2428
|
-
function isRegistered(cliBin, serverName) {
|
|
2567
|
+
function isRegistered(cliBin, serverName, target = null) {
|
|
2568
|
+
if (cliBin === "cursor") {
|
|
2569
|
+
const mcpCommand = target && target.mcpCommand ? target.mcpCommand : "";
|
|
2570
|
+
const mcpArgs = target && Array.isArray(target.mcpArgs) ? target.mcpArgs : [];
|
|
2571
|
+
return isCursorRegistered(serverName, mcpCommand, mcpArgs);
|
|
2572
|
+
}
|
|
2429
2573
|
const attempts = clientGetAttempts(cliBin, serverName);
|
|
2430
2574
|
for (const args of attempts) {
|
|
2431
2575
|
const run = runCLICommand(cliBin, args, { stdio: "ignore" });
|
|
@@ -2460,15 +2604,26 @@ function targetCommandLabel(target) {
|
|
|
2460
2604
|
return [command, ...args].join(" ");
|
|
2461
2605
|
}
|
|
2462
2606
|
|
|
2607
|
+
function detectClientAvailability(clients) {
|
|
2608
|
+
const candidateClients = Array.isArray(clients) && clients.length
|
|
2609
|
+
? clients
|
|
2610
|
+
: Array.from(SUPPORTED_CLIENTS);
|
|
2611
|
+
return candidateClients.map((cliBin) => {
|
|
2612
|
+
const exists = clientHelpAttempts(cliBin).some((args) => commandExists(cliBin, args));
|
|
2613
|
+
return { cliBin, exists };
|
|
2614
|
+
});
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2463
2617
|
function runSetupInternal(config, options = {}) {
|
|
2464
2618
|
const ensureOnly = options.ensureOnly === true;
|
|
2465
2619
|
const defaultTarget = resolveDefaultRegistrationTarget();
|
|
2466
2620
|
const targets = Array.isArray(config.targets) && config.targets.length
|
|
2467
2621
|
? config.targets
|
|
2468
2622
|
: [defaultTarget];
|
|
2469
|
-
const
|
|
2470
|
-
|
|
2471
|
-
);
|
|
2623
|
+
const clientsExplicit = config && config.clientsExplicit === true;
|
|
2624
|
+
const availability = detectClientAvailability(config.clients);
|
|
2625
|
+
const clients = availability.filter((row) => row.exists).map((row) => row.cliBin);
|
|
2626
|
+
const missingClients = availability.filter((row) => !row.exists).map((row) => row.cliBin);
|
|
2472
2627
|
const results = [];
|
|
2473
2628
|
const commandChecks = targets.map((target) => ({
|
|
2474
2629
|
...target,
|
|
@@ -2477,7 +2632,11 @@ function runSetupInternal(config, options = {}) {
|
|
|
2477
2632
|
|
|
2478
2633
|
process.stdout.write(ensureOnly ? "Bootstrap start.\n" : "Setup start.\n");
|
|
2479
2634
|
process.stdout.write(`Targets: ${targets.map((t) => `${t.serverName}=>${targetCommandLabel(t)}`).join(", ")}\n`);
|
|
2480
|
-
process.stdout.write(`Clients: ${
|
|
2635
|
+
process.stdout.write(`Clients(requested): ${availability.map((row) => row.cliBin).join(",")}\n`);
|
|
2636
|
+
process.stdout.write(`Clients(detected): ${clients.length ? clients.join(",") : "none"}\n`);
|
|
2637
|
+
if (!clientsExplicit && missingClients.length) {
|
|
2638
|
+
process.stdout.write(`Clients(skipped): ${missingClients.join(",")} (not installed or not available in PATH)\n`);
|
|
2639
|
+
}
|
|
2481
2640
|
|
|
2482
2641
|
if (!clients.length) {
|
|
2483
2642
|
process.stdout.write(`No supported client CLI found. Supported: ${Array.from(SUPPORTED_CLIENTS).join(", ")}\n`);
|
|
@@ -2508,11 +2667,36 @@ function runSetupInternal(config, options = {}) {
|
|
|
2508
2667
|
|
|
2509
2668
|
for (const cliBin of clients) {
|
|
2510
2669
|
for (const target of activeTargets) {
|
|
2511
|
-
const alreadyRegistered = isRegistered(cliBin, target.serverName);
|
|
2670
|
+
const alreadyRegistered = isRegistered(cliBin, target.serverName, target);
|
|
2512
2671
|
if (config.force || !ensureOnly || alreadyRegistered) {
|
|
2513
2672
|
removeRegistration(cliBin, target.serverName);
|
|
2514
2673
|
}
|
|
2515
2674
|
|
|
2675
|
+
if (cliBin === "cursor") {
|
|
2676
|
+
const registered = ensureCursorRegistered(target.serverName, target.mcpCommand, target.mcpArgs || [], config.force);
|
|
2677
|
+
if (registered.ok) {
|
|
2678
|
+
const action = ensureOnly
|
|
2679
|
+
? (alreadyRegistered ? "updated" : "registered")
|
|
2680
|
+
: (alreadyRegistered ? "re-registered" : "registered");
|
|
2681
|
+
results.push({
|
|
2682
|
+
cliBin,
|
|
2683
|
+
serverName: target.serverName,
|
|
2684
|
+
ok: true,
|
|
2685
|
+
action: `${action} (cursor mcp.json)`,
|
|
2686
|
+
detail: registered.detail || ""
|
|
2687
|
+
});
|
|
2688
|
+
} else {
|
|
2689
|
+
results.push({
|
|
2690
|
+
cliBin,
|
|
2691
|
+
serverName: target.serverName,
|
|
2692
|
+
ok: false,
|
|
2693
|
+
action: registered.action || "registration failed",
|
|
2694
|
+
detail: registered.detail || "unknown"
|
|
2695
|
+
});
|
|
2696
|
+
}
|
|
2697
|
+
continue;
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2516
2700
|
const registered = tryRegister(cliBin, target.serverName, target.mcpCommand, target.mcpArgs || []);
|
|
2517
2701
|
if (registered.ok) {
|
|
2518
2702
|
const action = ensureOnly
|
|
@@ -2531,7 +2715,7 @@ function runSetupInternal(config, options = {}) {
|
|
|
2531
2715
|
|
|
2532
2716
|
for (const row of results) {
|
|
2533
2717
|
process.stdout.write(`${row.cliBin}/${row.serverName}: ${row.action}\n`);
|
|
2534
|
-
if (!row.ok
|
|
2718
|
+
if (row.detail && (!row.ok || /\bcursor mcp\.json\b/i.test(String(row.action || "")))) {
|
|
2535
2719
|
process.stdout.write(` detail: ${row.detail}\n`);
|
|
2536
2720
|
}
|
|
2537
2721
|
}
|
|
@@ -2546,8 +2730,11 @@ function runDoctor(config) {
|
|
|
2546
2730
|
const targets = Array.isArray(config.targets) && config.targets.length
|
|
2547
2731
|
? config.targets
|
|
2548
2732
|
: [defaultTarget];
|
|
2733
|
+
const clientsExplicit = config && config.clientsExplicit === true;
|
|
2734
|
+
const availability = detectClientAvailability(config.clients);
|
|
2549
2735
|
process.stdout.write("Doctor start.\n");
|
|
2550
2736
|
process.stdout.write(`Targets: ${targets.map((t) => `${t.serverName}=>${targetCommandLabel(t)}`).join(", ")}\n`);
|
|
2737
|
+
process.stdout.write(`Clients(requested): ${availability.map((row) => row.cliBin).join(",")}\n`);
|
|
2551
2738
|
let hasIssue = false;
|
|
2552
2739
|
let foundClient = false;
|
|
2553
2740
|
|
|
@@ -2563,17 +2750,21 @@ function runDoctor(config) {
|
|
|
2563
2750
|
}
|
|
2564
2751
|
}
|
|
2565
2752
|
|
|
2566
|
-
for (const
|
|
2567
|
-
const
|
|
2568
|
-
if (!exists) {
|
|
2569
|
-
|
|
2570
|
-
|
|
2753
|
+
for (const row of availability) {
|
|
2754
|
+
const cliBin = row.cliBin;
|
|
2755
|
+
if (!row.exists) {
|
|
2756
|
+
if (clientsExplicit) {
|
|
2757
|
+
hasIssue = true;
|
|
2758
|
+
process.stdout.write(`${cliBin}: not installed or not available in PATH\n`);
|
|
2759
|
+
} else {
|
|
2760
|
+
process.stdout.write(`${cliBin}: skipped (not installed or not available in PATH)\n`);
|
|
2761
|
+
}
|
|
2571
2762
|
continue;
|
|
2572
2763
|
}
|
|
2573
2764
|
|
|
2574
2765
|
foundClient = true;
|
|
2575
2766
|
for (const target of targets) {
|
|
2576
|
-
const registered = isRegistered(cliBin, target.serverName);
|
|
2767
|
+
const registered = isRegistered(cliBin, target.serverName, target);
|
|
2577
2768
|
if (registered) {
|
|
2578
2769
|
process.stdout.write(`${cliBin}: registered (${target.serverName})\n`);
|
|
2579
2770
|
} else {
|
|
@@ -2586,6 +2777,7 @@ function runDoctor(config) {
|
|
|
2586
2777
|
}
|
|
2587
2778
|
|
|
2588
2779
|
if (!foundClient) {
|
|
2780
|
+
hasIssue = true;
|
|
2589
2781
|
process.stdout.write("No requested clients detected. Install at least one supported client first.\n");
|
|
2590
2782
|
}
|
|
2591
2783
|
|
|
@@ -8744,6 +8936,52 @@ function writeJsonArtifact(targetPath, payload, label, warnings, requiredActions
|
|
|
8744
8936
|
}
|
|
8745
8937
|
}
|
|
8746
8938
|
|
|
8939
|
+
function buildGeneratedArtifacts(config, state = {}) {
|
|
8940
|
+
return {
|
|
8941
|
+
outputPath: config && config.outPath ? config.outPath : null,
|
|
8942
|
+
outputChannel: config && config.outPath ? "file" : "stdout",
|
|
8943
|
+
htmlReportPath: state.htmlReportPath || null,
|
|
8944
|
+
topologyPath: state.topologyPath || null,
|
|
8945
|
+
relationshipsPath: state.relationshipsPath || null,
|
|
8946
|
+
governanceLogPath: state.governanceLogPath || null,
|
|
8947
|
+
incidentPayloadPath: state.incidentPayloadPath || null
|
|
8948
|
+
};
|
|
8949
|
+
}
|
|
8950
|
+
|
|
8951
|
+
function generatedArtifactsSummary(artifacts) {
|
|
8952
|
+
const item = artifacts && typeof artifacts === "object" ? artifacts : {};
|
|
8953
|
+
return [
|
|
8954
|
+
`output=${item.outputPath || (item.outputChannel || "stdout")}`,
|
|
8955
|
+
`html=${item.htmlReportPath || "off"}`,
|
|
8956
|
+
`topology=${item.topologyPath || "off"}`,
|
|
8957
|
+
`relationships=${item.relationshipsPath || "off"}`,
|
|
8958
|
+
`governance=${item.governanceLogPath || "off"}`,
|
|
8959
|
+
`incident=${item.incidentPayloadPath || "off"}`
|
|
8960
|
+
].join(", ");
|
|
8961
|
+
}
|
|
8962
|
+
|
|
8963
|
+
function syncRunMetaToPresentationBundle(presentationBundle, runMeta) {
|
|
8964
|
+
if (!presentationBundle || typeof presentationBundle !== "object") return;
|
|
8965
|
+
const meta = runMeta && typeof runMeta === "object" ? { ...runMeta } : {};
|
|
8966
|
+
presentationBundle.runMeta = meta;
|
|
8967
|
+
|
|
8968
|
+
const sections = presentationBundle.sections;
|
|
8969
|
+
const payload = sections && typeof sections === "object" ? sections.payload : null;
|
|
8970
|
+
const governance = payload && typeof payload === "object" ? payload.governance : null;
|
|
8971
|
+
if (!governance || typeof governance !== "object") return;
|
|
8972
|
+
|
|
8973
|
+
payload.governance = {
|
|
8974
|
+
...governance,
|
|
8975
|
+
runId: meta.runId || null,
|
|
8976
|
+
runStartedAt: meta.runStartedAt || null,
|
|
8977
|
+
runFinishedAt: meta.runFinishedAt || null,
|
|
8978
|
+
outputHash: meta.outputHash || null,
|
|
8979
|
+
recordsHash: meta.recordsHash || null,
|
|
8980
|
+
htmlHash: meta.htmlHash || null,
|
|
8981
|
+
generatedArtifacts: meta.generatedArtifacts || null
|
|
8982
|
+
};
|
|
8983
|
+
}
|
|
8984
|
+
|
|
8747
8985
|
function readLastGovernanceEntryHash(logPath) {
|
|
8748
8986
|
if (!logPath || !fs.existsSync(logPath)) return null;
|
|
8749
8987
|
try {
|
|
@@ -11954,6 +12192,14 @@ async function runWorkflow(config) {
|
|
|
11954
12192
|
incidentArtifactHash: incidentDispatch.artifactHash || null
|
|
11955
12193
|
};
|
|
11956
12194
|
const outputSummary = summarizeOutputRecords(outputRecords);
|
|
12195
|
+
const recordsHash = hashText(JSON.stringify(outputRecords));
|
|
12196
|
+
const runMeta = {
|
|
12197
|
+
...baseRunMeta,
|
|
12198
|
+
recordsHash,
|
|
12199
|
+
htmlOutPath: null,
|
|
12200
|
+
htmlHash: null,
|
|
12201
|
+
generatedArtifacts: null
|
|
12202
|
+
};
|
|
11957
12203
|
const presentationBundle = buildOutputBundle({
|
|
11958
12204
|
rawRecords: outputRecords,
|
|
11959
12205
|
summary: outputSummary,
|
|
@@ -11966,26 +12212,13 @@ async function runWorkflow(config) {
|
|
|
11966
12212
|
excludeFields: config.excludeFields,
|
|
11967
12213
|
sections: config.sections,
|
|
11968
12214
|
clientProfile: config.clientProfile,
|
|
11969
|
-
runMeta
|
|
12215
|
+
runMeta
|
|
11970
12216
|
});
|
|
11971
|
-
|
|
11972
|
-
const outputBody = renderOutput(config, presentationBundle);
|
|
11973
|
-
const outputHash = hashText(outputBody);
|
|
11974
|
-
const recordsHash = hashText(JSON.stringify(outputRecords));
|
|
11975
|
-
const runMeta = { ...baseRunMeta, outputHash, recordsHash };
|
|
11976
|
-
|
|
11977
|
-
presentationBundle.runMeta = {
|
|
11978
|
-
...(presentationBundle.runMeta && typeof presentationBundle.runMeta === "object" ? presentationBundle.runMeta : {}),
|
|
11979
|
-
...runMeta
|
|
11980
|
-
};
|
|
11981
|
-
writeOutput(config, outputBody);
|
|
12217
|
+
syncRunMetaToPresentationBundle(presentationBundle, runMeta);
|
|
11982
12218
|
const htmlPath = writeHtmlReport(config, outputRecords, domainInsights, runMeta, presentationBundle);
|
|
11983
12219
|
if (htmlPath) {
|
|
11984
12220
|
runMeta.htmlOutPath = htmlPath;
|
|
11985
12221
|
runMeta.htmlHash = hashText(fs.readFileSync(htmlPath, "utf8"));
|
|
11986
|
-
} else {
|
|
11987
|
-
runMeta.htmlOutPath = null;
|
|
11988
|
-
runMeta.htmlHash = null;
|
|
11989
12222
|
}
|
|
11990
12223
|
if (htmlPath && shouldAutoOpenHtml(config)) {
|
|
11991
12224
|
const opened = tryOpenFile(htmlPath);
|
|
@@ -11996,6 +12229,19 @@ async function runWorkflow(config) {
|
|
|
11996
12229
|
}
|
|
11997
12230
|
}
|
|
11998
12231
|
|
|
12232
|
+
runMeta.generatedArtifacts = buildGeneratedArtifacts(config, {
|
|
12233
|
+
htmlReportPath: runMeta.htmlOutPath,
|
|
12234
|
+
topologyPath: topologyWrite.path || null,
|
|
12235
|
+
relationshipsPath: relationshipsWrite.path || null,
|
|
12236
|
+
governanceLogPath: governancePersist.path || null,
|
|
12237
|
+
incidentPayloadPath: incidentDispatch.artifactPath || null
|
|
12238
|
+
});
|
|
12239
|
+
syncRunMetaToPresentationBundle(presentationBundle, runMeta);
|
|
12240
|
+
|
|
12241
|
+
const outputBody = renderOutput(config, presentationBundle);
|
|
12242
|
+
runMeta.outputHash = hashText(outputBody);
|
|
12243
|
+
writeOutput(config, outputBody);
|
|
12244
|
+
|
|
11999
12245
|
progress(config, 19, "END: emit execution summary and evidence metadata");
|
|
12000
12246
|
const outputEc2 = outputRecords.filter((r) => r.resourceType === "ec2");
|
|
12001
12247
|
const outputLambda = outputRecords.filter((r) => r.resourceType === "lambda");
|
|
@@ -12047,6 +12293,7 @@ async function runWorkflow(config) {
|
|
|
12047
12293
|
const ssmManaged = outputEc2.filter((r) => r.ssmManaged).length;
|
|
12048
12294
|
const ssmOnline = outputEc2.filter((r) => r.ssmOnline).length;
|
|
12049
12295
|
const publicCount = outputEc2.filter((r) => Boolean(r.publicIp)).length;
|
|
12296
|
+
eprint(`Artifacts: ${generatedArtifactsSummary(runMeta.generatedArtifacts)}`);
|
|
12050
12297
|
eprint(`Summary: execution_mode=${INTERNAL_BACKEND_ID}, manual_mode=${config.manualServerListPath ? "on" : "off"}, selected_surface=${selectedSurface}, selected_schema_tier=${selectedSchemaTier}, mode=${routing.modeInfo.mode}, mode_source=${routing.modeInfo.source}, profiles=${stats.profiles}, regions_scanned=${stats.regions}, region_errors=${stats.regionErrors}, ec2_scanned=${stats.instancesScanned}, lambda_scanned=${stats.lambdaFunctionsScanned}, alb_scanned=${stats.loadBalancersScanned}, targetgroup_scanned=${stats.targetGroupsScanned}, asg_scanned=${stats.autoScalingGroupsScanned}, rds_scanned=${stats.rdsInstancesScanned}, elasticache_scanned=${stats.elasticacheClustersScanned}, route53_zone_scanned=${stats.route53ZonesScanned}, vpc_scanned=${stats.vpcsScanned || 0}, subnet_scanned=${stats.subnetsScanned || 0}, security_group_scanned=${stats.securityGroupsScanned || 0}, ecs_cluster_scanned=${stats.ecsClustersScanned || 0}, ecs_service_scanned=${stats.ecsServicesScanned || 0}, s3_bucket_scanned=${stats.s3BucketsScanned || 0}, iam_role_scanned=${stats.iamRolesScanned || 0}, kms_key_scanned=${stats.kmsKeysScanned || 0}, cloudwatch_alarm_scanned=${stats.cloudwatchAlarmsScanned || 0}, cloudtrail_trail_scanned=${stats.cloudtrailTrailsScanned || 0}, config_recorder_scanned=${stats.configRecordersScanned || 0}, secret_scanned=${stats.secretsScanned || 0}, ssm_parameter_scanned=${stats.parametersScanned || 0}, ecr_repository_scanned=${stats.ecrRepositoriesScanned || 0}, dynamodb_table_scanned=${stats.dynamodbTablesScanned || 0}, sns_topic_scanned=${stats.snsTopicsScanned || 0}, eventbridge_bus_scanned=${stats.eventbridgeBusesScanned || 0}, sqs_queue_scanned=${stats.sqsQueuesScanned || 0}, acm_certificate_scanned=${stats.acmCertificatesScanned || 0}, kinesis_stream_scanned=${stats.kinesisStreamsScanned || 0}, msk_cluster_scanned=${stats.mskClustersScanned || 0}, budget_scanned=${stats.budgetsScanned || 0}, cost_anomaly_scanned=${stats.costAnomaliesScanned || 0}, ebs_volume_scanned=${stats.ebsVolumesScanned || 0}, efs_filesystem_scanned=${stats.efsFileSystemsScanned || 0}, eks_cluster_scanned=${stats.eksClustersScanned || 0}, apigateway_rest_api_scanned=${stats.apiGatewayRestApisScanned || 0}, apigatewayv2_api_scanned=${stats.apiGatewayV2ApisScanned || 0}, cloudfront_distribution_scanned=${stats.cloudFrontDistributionsScanned || 0}, waf_web_acl_scanned=${stats.wafWebAclsScanned || 0}, shield_protection_scanned=${stats.shieldProtectionsScanned || 0}, stepfunctions_scanned=${stats.stepFunctionsScanned || 0}, cloudwatch_log_group_scanned=${stats.cloudwatchLogGroupsScanned || 0}, xray_group_scanned=${stats.xrayGroupsScanned || 0}, inspector2_finding_scanned=${stats.inspector2FindingsScanned || 0}, redshift_cluster_scanned=${stats.redshiftClustersScanned || 0}, opensearch_domain_scanned=${stats.opensearchDomainsScanned || 0}, organizations_account_scanned=${stats.organizationsAccountsScanned || 0}, controltower_landing_zone_scanned=${stats.controlTowerLandingZonesScanned || 0}, manual_servers_scanned=${stats.manualServersScanned || 0}, manual_servers_loaded=${stats.manualServersLoaded || 0}, output_records=${outputRecords.length}, output_ec2=${outputEc2.length}, output_lambda=${outputLambda.length}, output_alb=${outputAlb.length}, output_target_group=${outputTargetGroups.length}, output_asg=${outputAsg.length}, output_rds=${outputRds.length}, output_elasticache=${outputElastiCache.length}, output_route53_zone=${outputRoute53.length}, output_vpc=${outputVpc.length}, output_subnet=${outputSubnet.length}, output_security_group=${outputSecurityGroup.length}, output_ecs_cluster=${outputEcsCluster.length}, output_ecs_service=${outputEcsService.length}, output_s3_bucket=${outputS3.length}, output_iam_role=${outputIam.length}, output_kms_key=${outputKms.length}, output_cloudwatch_alarm=${outputCloudwatch.length}, output_cloudtrail_trail=${outputCloudtrail.length}, output_config_recorder=${outputConfig.length}, output_secret=${outputSecret.length}, output_ssm_parameter=${outputParameter.length}, output_ecr_repository=${outputEcr.length}, output_dynamodb_table=${outputDynamodb.length}, output_sns_topic=${outputSns.length}, output_eventbridge_bus=${outputEventbridge.length}, output_sqs_queue=${outputSqs.length}, output_acm_certificate=${outputAcm.length}, output_kinesis_stream=${outputKinesis.length}, output_msk_cluster=${outputMsk.length}, output_budget=${outputBudget.length}, output_cost_anomaly=${outputCostAnomaly.length}, output_ebs_volume=${outputEbs.length}, output_efs_filesystem=${outputEfs.length}, output_eks_cluster=${outputEks.length}, output_apigateway_rest_api=${outputApiGateway.length}, output_apigatewayv2_api=${outputApiGatewayV2.length}, output_cloudfront_distribution=${outputCloudfront.length}, output_waf_web_acl=${outputWaf.length}, output_shield_protection=${outputShield.length}, output_stepfunctions=${outputStepFunctions.length}, output_cloudwatch_log_group=${outputCloudwatchLogs.length}, output_xray_group=${outputXray.length}, output_inspector2_finding=${outputInspector2.length}, output_redshift_cluster=${outputRedshift.length}, output_opensearch_domain=${outputOpensearch.length}, output_organizations_account=${outputOrganizations.length}, output_controltower_landing_zone=${outputControlTower.length}, ec2_public_ip_records=${publicCount}, ec2_ssm_managed=${ssmManaged}, ec2_ssm_online=${ssmOnline}, remediation_attempts=${runtimeStats.remediationAttempts}, remediation_changed=${runtimeStats.remediationChanged}, runtime_snapshot_attempted=${runtimeStats.snapshotAttempted}, runtime_snapshot_succeeded=${runtimeStats.snapshotSucceeded}, runtime_snapshot_ssm_attempted=${runtimeStats.snapshotSsmAttempted}, runtime_snapshot_ssm_succeeded=${runtimeStats.snapshotSsmSucceeded}, runtime_snapshot_ssh_attempted=${runtimeStats.snapshotSshAttempted}, runtime_snapshot_ssh_succeeded=${runtimeStats.snapshotSshSucceeded}, snapshot_profile=${config.snapshotProfile}, output_profile=${presentationBundle.outputProfile || "operator"}, output_profile_source=${presentationBundle.outputProfileSource || "default"}, client_profile=${presentationBundle.clientProfile || "none"}, renderer_template=${config.rendererTemplate || "default"}, topology_path=${topologyWrite.path || "off"}, relationships_path=${relationshipsWrite.path || "off"}, governance_persisted=${governancePersist.persisted ? "on" : "off"}, governance_chain_checked=${governanceVerify.checked ? "on" : "off"}, governance_chain_valid=${governanceVerify.valid == null ? "unknown" : (governanceVerify.valid ? "yes" : "no")}, incident_webhook_dispatched=${incidentDispatch.webhookDispatched ? "on" : "off"}, policy_pack=${integrationDispatch.activePolicyPack || "balanced"}, policy_gate=${policyDecision.allowed !== false ? "allow" : "blocked"}, integration_connectors_enabled=${integrationDispatch.enabledConnectors}, integration_incident_success=${integrationDispatch.incident ? integrationDispatch.incident.successCount : 0}, integration_incident_failure=${integrationDispatch.incident ? integrationDispatch.incident.failureCount : 0}, integration_action_success=${integrationDispatch.actionRequired ? integrationDispatch.actionRequired.successCount : 0}, integration_action_failure=${integrationDispatch.actionRequired ? integrationDispatch.actionRequired.failureCount : 0}, view_sections=${presentationBundle.sections && Array.isArray(presentationBundle.sections.effective) ? presentationBundle.sections.effective.join(",") : "none"}, view_fields=${presentationBundle.fields && Array.isArray(presentationBundle.fields.effectiveFields) ? presentationBundle.fields.effectiveFields.length : 0}, iac_stacks=${domainInsights.iac.scannedStacks || 0}, iac_drifted=${domainInsights.iac.driftedStacks || 0}, cicd_pipelines=${domainInsights.cicd.pipelinesScanned || 0}, cicd_failing=${domainInsights.cicd.pipelinesFailing || 0}, backup_plans=${domainInsights.backupDr.backupPlans || 0}, backup_protected=${domainInsights.backupDr.protectedResources || 0}, security_high_critical=${domainInsights.security.highOrCritical || 0}, finops_cost_7d_usd=${domainInsights.finops.totalCost7dUsd || 0}, app_runtime_coverage_pct=${domainInsights.application.runtimeCoveragePct == null ? "n/a" : domainInsights.application.runtimeCoveragePct}, app_degraded_hosts=${domainInsights.application.degradedHosts || 0}, app_ecs_degraded=${domainInsights.application.ecsServicesDegraded || 0}, app_managed_degraded=${domainInsights.application.managedServicesDegraded || 0}, app_lambda_degraded=${domainInsights.application.lambdaHealth && domainInsights.application.lambdaHealth.degraded ? domainInsights.application.lambdaHealth.degraded : 0}, incident_severity=${domainInsights.incident.severity || "none"}, warnings=${warnings.length}, required_actions=${requiredActions.length}`);
|
|
12051
12298
|
eprint(`EvidenceMeta: workflow_id=b60f0f18-cc45-4af9-a7c7-217284457759; schema=gesia.orflow.contract.v2; step_count=${TOTAL_STEPS}; execution_mode=${INTERNAL_BACKEND_ID}; run_id=${runId}; output_hash=${runMeta.outputHash}; records_hash=${runMeta.recordsHash}; html_hash=${runMeta.htmlHash || "n/a"}; topology_hash=${runMeta.topologyHash || "n/a"}; relationships_hash=${runMeta.relationshipsHash || "n/a"}; governance_entry_hash=${runMeta.governanceEntryHash || "n/a"}; governance_chain_valid=${runMeta.governanceChainValid == null ? "unknown" : (runMeta.governanceChainValid ? "yes" : "no")}; incident_artifact_hash=${runMeta.incidentArtifactHash || "n/a"}; policy_pack=${integrationDispatch.activePolicyPack || "balanced"}; policy_gate=${policyDecision.allowed !== false ? "allow" : "blocked"}; integration_connectors_enabled=${integrationDispatch.enabledConnectors}; inventory_ops=${operationPlan.inventoryOps.length}; runtime_ops=${operationPlan.runtimeOps.length}; analysis_ops=${operationPlan.analysisOps.length}`);
|
|
12052
12299
|
|
|
@@ -12065,6 +12312,11 @@ async function runWorkflow(config) {
|
|
|
12065
12312
|
async function main() {
|
|
12066
12313
|
try {
|
|
12067
12314
|
const parsed = parseCommand(process.argv.slice(2));
|
|
12315
|
+
if (parsed.command === "version") {
|
|
12316
|
+
process.stdout.write(`${readCurrentPackageVersion()}\n`);
|
|
12317
|
+
process.exitCode = 0;
|
|
12318
|
+
return;
|
|
12319
|
+
}
|
|
12068
12320
|
if (parsed.command === "help") {
|
|
12069
12321
|
process.stdout.write(usageText());
|
|
12070
12322
|
process.exitCode = 0;
|
package/package.json
CHANGED