@event4u/agent-config 14.19.0 → 14.21.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +351 -156
- package/README.md +1 -1
- package/agents/templates/.ai-council.yml.example +10 -0
- package/dist/agent-src/commands/agent-handoff.md +42 -41
- package/dist/agent-src/commands/analyze/inbox.md +1 -1
- package/dist/agent-src/commands/analyze/{reference-repo.md → repo.md} +247 -32
- package/dist/agent-src/commands/analyze/roadmap-repos.md +129 -0
- package/dist/agent-src/commands/analyze.md +12 -7
- package/dist/agent-src/commands/feature/plan.md +55 -16
- package/dist/agent-src/commands/feature/refactor.md +8 -3
- package/dist/agent-src/commands/humanize.md +48 -4
- package/dist/agent-src/contexts/execution/contract-decision-sheet.md +22 -1
- package/dist/agent-src/contexts/execution/host-capability-manifest.md +11 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +35 -2
- package/dist/agent-src/contexts/execution/terminal-states.md +4 -1
- package/dist/agent-src/rules/evaluator-independence.md +4 -4
- package/dist/agent-src/rules/external-reference-deep-dive.md +2 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +0 -2
- package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
- package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +1 -1
- package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +27 -11
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +1 -1
- package/dist/agent-src/skills/markitdown/SKILL.md +2 -2
- package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +28 -6
- package/dist/agent-src/skills/technical-specification/SKILL.md +4 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -3
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/features.md +5 -0
- package/dist/agent-src/templates/roadmaps.md +29 -1
- package/dist/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
- package/dist/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
- package/dist/agent-src/templates/scripts/telemetry_report.ts +22 -2
- package/dist/cli/mcp/dispatch.js +10 -0
- package/dist/cli/mcp/stdio.js +33 -2
- package/dist/cli/mcp/telemetry.js +227 -0
- package/dist/cli-delegate/{chunk-KPBWFOPZ.js → chunk-2FTMENJL.js} +194 -37
- package/dist/cli-delegate/{chunk-PMEKGDED.js → chunk-2TAQ2K4V.js} +166 -1
- package/dist/cli-delegate/{chunk-GZTMRYCN.js → chunk-643Z7FIC.js} +79 -12
- package/dist/cli-delegate/{chunk-CYH5SP6M.js → chunk-I6RHFQEG.js} +151 -16
- package/dist/cli-delegate/{chunk-IDHUQIXP.js → chunk-J3RFNKG4.js} +41 -5
- package/dist/cli-delegate/{chunk-7PRE6ZV2.js → chunk-YS6XTLEK.js} +199 -4
- package/dist/cli-delegate/chunk-ZVBOHSVF.js +1109 -0
- package/dist/cli-delegate/cmd_conformance.js +88 -110
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +42 -12
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_prune.js +2 -2
- package/dist/cli-delegate/cmd_route_audit.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +59 -902
- package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
- package/dist/cli-delegate/cmd_sync.js +2 -2
- package/dist/cli-delegate/cmd_uninstall.js +2 -2
- package/dist/cli-delegate/cmd_validate.js +2 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +62 -31
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -6
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -5
- package/dist/hooks/dispatch.js +3801 -2803
- package/dist/install/install.mjs +396 -168
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +809 -180
- package/dist/scripts/ai_council/content_ceiling.js +63 -0
- package/dist/scripts/ai_council/seat_policy.js +106 -0
- package/dist/scripts/ai_council/transport_resolver.js +21 -0
- package/dist/scripts/mcp_server/telemetry.js +148 -0
- package/docs/guidelines/agent-infra/naming.md +1 -1
- package/docs/guidelines/agent-infra/security-lint-containment.md +46 -6
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +4 -4
- package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +1 -1
- package/docs/guidelines/redundancy-taxonomy.md +28 -0
- package/llms.txt +14 -14
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
- package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
- package/src/agent-src/templates/scripts/telemetry_report.ts +22 -2
- package/src/config/assurance-capability-registry.json +9 -0
- package/src/config/gate-coverage.yml +55 -0
- package/src/config/gate-violation-baselines.json +18 -6
- package/src/config/release-gate-locality.yml +4 -3
- package/src/scripts/_cli/cmd_session_recycle.ts +51 -3
- package/src/scripts/_lib/audit_field_provenance.ts +44 -3
- package/src/scripts/_lib/blocked_by_marker.ts +189 -0
- package/src/scripts/_lib/host_capability.ts +76 -1
- package/src/scripts/_lib/install_reach_checks.ts +33 -1
- package/src/scripts/_lib/mcp_bridge.ts +222 -10
- package/src/scripts/_lib/mcp_consent_residual.ts +173 -0
- package/src/scripts/_lib/orchestration_record.ts +23 -1
- package/src/scripts/_lib/recycle_envelope_paths.ts +190 -0
- package/src/scripts/_lib/release_highlights.ts +19 -211
- package/src/scripts/_lib/release_material.ts +27 -77
- package/src/scripts/_lib/release_position.ts +96 -0
- package/src/scripts/_lib/review_skipped_record.ts +17 -1
- package/src/scripts/_lib/security_lint.ts +179 -7
- package/src/scripts/_lib/self_repair.ts +141 -6
- package/src/scripts/_lib/self_repair_store.ts +273 -7
- package/src/scripts/_lib/structured_ask.ts +117 -0
- package/src/scripts/_lib/subagent_capsule.ts +155 -3
- package/src/scripts/_lib/tty_prompt.ts +76 -0
- package/src/scripts/ai_council/api_transport.ts +163 -0
- package/src/scripts/ai_council/clients.ts +58 -63
- package/src/scripts/ai_council/config.ts +13 -0
- package/src/scripts/ai_council/content_ceiling.ts +79 -0
- package/src/scripts/ai_council/jury_aggregate.ts +178 -0
- package/src/scripts/ai_council/seat_policy.ts +137 -0
- package/src/scripts/ai_council/status_surface.ts +79 -0
- package/src/scripts/ai_council/transport_resolver.ts +59 -1
- package/src/scripts/ai_tells_rules.ts +446 -5
- package/src/scripts/ask_block_census.ts +499 -0
- package/src/scripts/bench_humanizer_eval.ts +264 -40
- package/src/scripts/bench_prose_tells_fp.ts +198 -0
- package/src/scripts/build_rule_trigger_matrix.ts +5 -0
- package/src/scripts/check_branch_work_committed.ts +234 -0
- package/src/scripts/check_mcp_doc_drift.ts +217 -0
- package/src/scripts/check_pack_size.ts +321 -3
- package/src/scripts/check_release_highlights.ts +0 -157
- package/src/scripts/council_cli.ts +18 -27
- package/src/scripts/detect_ai_tells.ts +142 -20
- package/src/scripts/handoff_context_hook.ts +54 -7
- package/src/scripts/harvest_reference_tokens.ts +698 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +31 -1
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +45 -1
- package/src/scripts/hooks/one_question_per_ask_hook.ts +191 -0
- package/src/scripts/hooks/session_eol_hook.ts +18 -7
- package/src/scripts/install-hooks.sh +52 -0
- package/src/scripts/install.ts +4 -4
- package/src/scripts/lint_agent_security.ts +316 -25
- package/src/scripts/lint_confusables.ts +42 -6
- package/src/scripts/lint_handoffs.ts +0 -132
- package/src/scripts/lint_hidden_unicode.ts +49 -7
- package/src/scripts/lint_instruction_smuggling.ts +42 -6
- package/src/scripts/lint_mcp_config_security.ts +42 -6
- package/src/scripts/lint_roadmap_blockers.ts +51 -1
- package/src/scripts/lint_roadmap_later_disposition.ts +217 -27
- package/src/scripts/lint_skill_frontmatter_safety.ts +43 -7
- package/src/scripts/mcp_server/resources.ts +41 -0
- package/src/scripts/mcp_server/telemetry.ts +19 -4
- package/src/scripts/migrate_command_suggestions.ts +1 -1
- package/src/scripts/orchestration_record.ts +12 -1
- package/src/scripts/probe_unblocked_ask.ts +135 -2
- package/src/scripts/release.ts +50 -95
- package/src/scripts/release_drill.ts +6 -10
- package/src/scripts/release_env.ts +1 -0
- package/src/scripts/release_publication.ts +40 -31
- package/src/scripts/self_repair_cli.ts +31 -1
- package/src/scripts/self_review_gate.ts +409 -15
- package/src/scripts/skill_scout.ts +69 -0
- package/dist/cli-delegate/chunk-2GNWGMAL.js +0 -172
- package/dist/cli-delegate/chunk-LPPWO5CE.js +0 -161
|
@@ -968,6 +968,167 @@ function splitlines2(text) {
|
|
|
968
968
|
return parts;
|
|
969
969
|
}
|
|
970
970
|
|
|
971
|
+
// src/scripts/_lib/host_capability.ts
|
|
972
|
+
import process2 from "node:process";
|
|
973
|
+
var SAFE_DEFAULT = {
|
|
974
|
+
schema_version: 1,
|
|
975
|
+
subagent_spawn: false,
|
|
976
|
+
parallel_spawn: false,
|
|
977
|
+
status_polling: false,
|
|
978
|
+
separate_quota_pool: false,
|
|
979
|
+
agent_teams: false,
|
|
980
|
+
worker_respawn: false,
|
|
981
|
+
structured_ask: false,
|
|
982
|
+
reads_project_mcp_config: false,
|
|
983
|
+
// `true` because the safe answer here is "there is still a step", not
|
|
984
|
+
// "there is nothing to do" — see the field's own note.
|
|
985
|
+
mcp_needs_manual_activation: true
|
|
986
|
+
};
|
|
987
|
+
function asBool(value) {
|
|
988
|
+
return value === true;
|
|
989
|
+
}
|
|
990
|
+
function normalizeHostManifest(input) {
|
|
991
|
+
if (input === null || typeof input !== "object") {
|
|
992
|
+
return { ...SAFE_DEFAULT };
|
|
993
|
+
}
|
|
994
|
+
const src = input;
|
|
995
|
+
return {
|
|
996
|
+
schema_version: 1,
|
|
997
|
+
subagent_spawn: asBool(src.subagent_spawn),
|
|
998
|
+
parallel_spawn: asBool(src.parallel_spawn),
|
|
999
|
+
status_polling: asBool(src.status_polling),
|
|
1000
|
+
separate_quota_pool: asBool(src.separate_quota_pool),
|
|
1001
|
+
agent_teams: asBool(src.agent_teams),
|
|
1002
|
+
worker_respawn: asBool(src.worker_respawn),
|
|
1003
|
+
structured_ask: asBool(src.structured_ask),
|
|
1004
|
+
reads_project_mcp_config: asBool(src.reads_project_mcp_config),
|
|
1005
|
+
// Inverted coercion, matching the inverted default: only an explicit
|
|
1006
|
+
// `false` clears the residual, so an absent or malformed value keeps
|
|
1007
|
+
// the manual step visible instead of silently dropping it.
|
|
1008
|
+
mcp_needs_manual_activation: src.mcp_needs_manual_activation !== false
|
|
1009
|
+
};
|
|
1010
|
+
}
|
|
1011
|
+
var HOST_CAPABILITY_REGISTRY = {
|
|
1012
|
+
claude: { subagent_spawn: true, parallel_spawn: true, structured_ask: false }
|
|
1013
|
+
};
|
|
1014
|
+
function resolveHostCapabilities(hostId, override) {
|
|
1015
|
+
if (override !== void 0 && override !== null && typeof override === "object" && !Array.isArray(override)) {
|
|
1016
|
+
return normalizeHostManifest(override);
|
|
1017
|
+
}
|
|
1018
|
+
const row = hostId !== null && hostId !== void 0 ? HOST_CAPABILITY_REGISTRY[hostId] : void 0;
|
|
1019
|
+
if (row === void 0) {
|
|
1020
|
+
return { ...SAFE_DEFAULT };
|
|
1021
|
+
}
|
|
1022
|
+
return { ...SAFE_DEFAULT, ...row, schema_version: 1 };
|
|
1023
|
+
}
|
|
1024
|
+
function probeHostCapabilities(hostId) {
|
|
1025
|
+
const base = resolveHostCapabilities(hostId);
|
|
1026
|
+
const flag = process2.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
|
|
1027
|
+
const probedAgentTeams = typeof flag === "string" && flag !== "";
|
|
1028
|
+
return { ...base, agent_teams: base.agent_teams || probedAgentTeams };
|
|
1029
|
+
}
|
|
1030
|
+
var CAPABILITY_FIELDS = [
|
|
1031
|
+
"subagent_spawn",
|
|
1032
|
+
"parallel_spawn",
|
|
1033
|
+
"status_polling",
|
|
1034
|
+
"separate_quota_pool",
|
|
1035
|
+
"agent_teams",
|
|
1036
|
+
"worker_respawn",
|
|
1037
|
+
"structured_ask",
|
|
1038
|
+
"reads_project_mcp_config",
|
|
1039
|
+
"mcp_needs_manual_activation"
|
|
1040
|
+
];
|
|
1041
|
+
function describeHostCapabilities(hostId) {
|
|
1042
|
+
const manifest = probeHostCapabilities(hostId);
|
|
1043
|
+
const row = hostId !== null && hostId !== void 0 ? HOST_CAPABILITY_REGISTRY[hostId] : void 0;
|
|
1044
|
+
const flag = process2.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
|
|
1045
|
+
const probedAgentTeams = typeof flag === "string" && flag !== "";
|
|
1046
|
+
const sources = {};
|
|
1047
|
+
for (const field of CAPABILITY_FIELDS) {
|
|
1048
|
+
if (row !== void 0 && typeof row[field] === "boolean") {
|
|
1049
|
+
sources[field] = "registry";
|
|
1050
|
+
} else if (field === "agent_teams" && probedAgentTeams) {
|
|
1051
|
+
sources[field] = "live-probe";
|
|
1052
|
+
} else {
|
|
1053
|
+
sources[field] = "default";
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
return { manifest, sources };
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
// src/scripts/_lib/mcp_consent_residual.ts
|
|
1060
|
+
var SEEDED = {
|
|
1061
|
+
claude: {
|
|
1062
|
+
hostId: "claude",
|
|
1063
|
+
residual: "Approve the project-scoped `agent-config` server the first time the host prompts \u2014 the installer writes `.mcp.json` but does not pre-approve it.",
|
|
1064
|
+
source: "vendor-doc",
|
|
1065
|
+
cite: "Host documentation: a project-scope MCP server requires explicit approval, suppressible only through the user-global `enabledMcpjsonServers` key, which this package deliberately does not write (blocker `mcp-user-scope-approval-consent`)."
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
var TOOL_TO_HOST = {
|
|
1069
|
+
"claude-code": "claude",
|
|
1070
|
+
cursor: "cursor",
|
|
1071
|
+
"gemini-cli": "gemini",
|
|
1072
|
+
windsurf: "windsurf",
|
|
1073
|
+
cline: "cline",
|
|
1074
|
+
copilot: "copilot",
|
|
1075
|
+
augment: "augment"
|
|
1076
|
+
};
|
|
1077
|
+
function residualFor(hostId) {
|
|
1078
|
+
const { manifest, sources } = describeHostCapabilities(hostId);
|
|
1079
|
+
if (sources.mcp_needs_manual_activation === "registry" && !manifest.mcp_needs_manual_activation) {
|
|
1080
|
+
return null;
|
|
1081
|
+
}
|
|
1082
|
+
return SEEDED[hostId] ?? null;
|
|
1083
|
+
}
|
|
1084
|
+
function isRecorded(hostId) {
|
|
1085
|
+
const { sources } = describeHostCapabilities(hostId);
|
|
1086
|
+
return hostId in SEEDED || sources.mcp_needs_manual_activation === "registry";
|
|
1087
|
+
}
|
|
1088
|
+
function residualLine(hostId) {
|
|
1089
|
+
const r = residualFor(hostId);
|
|
1090
|
+
if (r !== null) {
|
|
1091
|
+
return {
|
|
1092
|
+
hostId,
|
|
1093
|
+
state: "residual",
|
|
1094
|
+
text: `${hostId}: ${r.residual} (source: ${r.source} \u2014 not observed here)`
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
if (isRecorded(hostId)) {
|
|
1098
|
+
return {
|
|
1099
|
+
hostId,
|
|
1100
|
+
state: "cleared",
|
|
1101
|
+
text: `${hostId}: nothing left to do (source: observed)`
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
return {
|
|
1105
|
+
hostId,
|
|
1106
|
+
state: "unrecorded",
|
|
1107
|
+
text: `${hostId}: no residual recorded \u2014 nobody checked this host, which is not the same as nothing to do`
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
function residualReport(toolIds) {
|
|
1111
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1112
|
+
const out = [];
|
|
1113
|
+
for (const toolId of toolIds) {
|
|
1114
|
+
const hostId = TOOL_TO_HOST[toolId];
|
|
1115
|
+
if (hostId === void 0 || seen.has(hostId)) continue;
|
|
1116
|
+
seen.add(hostId);
|
|
1117
|
+
const line = residualLine(hostId);
|
|
1118
|
+
if (line.state !== "cleared") out.push(line);
|
|
1119
|
+
}
|
|
1120
|
+
return out;
|
|
1121
|
+
}
|
|
1122
|
+
function printResiduals(toolIds, quiet, write = (s) => process.stdout.write(s)) {
|
|
1123
|
+
if (quiet) return;
|
|
1124
|
+
const lines = residualReport(toolIds);
|
|
1125
|
+
if (lines.length === 0) return;
|
|
1126
|
+
write(" Still needs you (MCP):\n");
|
|
1127
|
+
for (const line of lines) write(` \u2022 ${line.text}
|
|
1128
|
+
`);
|
|
1129
|
+
write("\n");
|
|
1130
|
+
}
|
|
1131
|
+
|
|
971
1132
|
export {
|
|
972
1133
|
SCHEMA_VERSIONS_SUPPORTED,
|
|
973
1134
|
DEFAULT_DEPLOY_ROOTS,
|
|
@@ -977,6 +1138,7 @@ export {
|
|
|
977
1138
|
ScopeMismatchError,
|
|
978
1139
|
upsert_tool,
|
|
979
1140
|
atomicAppendLine,
|
|
1141
|
+
probeHostCapabilities,
|
|
980
1142
|
MANAGED_SIGNATURE,
|
|
981
1143
|
build_claude_hook_matrix,
|
|
982
1144
|
ensure_managed_hooks,
|
|
@@ -988,5 +1150,8 @@ export {
|
|
|
988
1150
|
reap_tagged_orphans,
|
|
989
1151
|
record_deploy,
|
|
990
1152
|
is_ancestor,
|
|
991
|
-
global_deploy_inventory_exports
|
|
1153
|
+
global_deploy_inventory_exports,
|
|
1154
|
+
TOOL_TO_HOST,
|
|
1155
|
+
residualReport,
|
|
1156
|
+
printResiduals
|
|
992
1157
|
};
|
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
is_ancestor,
|
|
22
22
|
load_inventory,
|
|
23
23
|
manifest_path,
|
|
24
|
+
printResiduals,
|
|
25
|
+
probeHostCapabilities,
|
|
24
26
|
read_manifest,
|
|
25
27
|
reap_stale,
|
|
26
28
|
reap_tagged_orphans,
|
|
@@ -28,7 +30,7 @@ import {
|
|
|
28
30
|
save_inventory,
|
|
29
31
|
upsert_tool,
|
|
30
32
|
write_manifest
|
|
31
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-2TAQ2K4V.js";
|
|
32
34
|
import {
|
|
33
35
|
check_version,
|
|
34
36
|
classify_mismatch,
|
|
@@ -398,16 +400,82 @@ function is_claude_builtin_name(slug) {
|
|
|
398
400
|
import * as fs from "node:fs";
|
|
399
401
|
import * as path from "node:path";
|
|
400
402
|
var MCP_SERVER_KEY = "agent-config";
|
|
401
|
-
var
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
403
|
+
var MCP_PACKAGE_NAME = "@event4u/agent-config";
|
|
404
|
+
function mcpBridgeEntry(packageRoot) {
|
|
405
|
+
const version = readPackageVersion(packageRoot);
|
|
406
|
+
const spec = version === null ? MCP_PACKAGE_NAME : `${MCP_PACKAGE_NAME}@${version}`;
|
|
407
|
+
return {
|
|
408
|
+
mcpServers: {
|
|
409
|
+
[MCP_SERVER_KEY]: {
|
|
410
|
+
command: "npx",
|
|
411
|
+
args: ["-y", spec, "mcp-server"]
|
|
412
|
+
}
|
|
406
413
|
}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function readPackageVersion(packageRoot) {
|
|
417
|
+
try {
|
|
418
|
+
const raw = fs.readFileSync(path.join(packageRoot, "package.json"), "utf-8");
|
|
419
|
+
const v = JSON.parse(raw).version;
|
|
420
|
+
return typeof v === "string" && v.trim() !== "" ? v : null;
|
|
421
|
+
} catch {
|
|
422
|
+
return null;
|
|
407
423
|
}
|
|
408
|
-
}
|
|
424
|
+
}
|
|
409
425
|
function makeEnsureMcpBridge(mergeJsonFile) {
|
|
410
|
-
return (projectRoot, force) => mergeJsonFile(
|
|
426
|
+
return (projectRoot, force, packageRoot = projectRoot) => mergeJsonFile(
|
|
427
|
+
path.join(projectRoot, ".mcp.json"),
|
|
428
|
+
mcpBridgeEntry(packageRoot),
|
|
429
|
+
force,
|
|
430
|
+
".mcp.json"
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
var MCP_PROJECT_CONFIG = {
|
|
434
|
+
"claude-code": { hostId: "claude", relPath: ".mcp.json" },
|
|
435
|
+
cursor: { hostId: "cursor", relPath: ".cursor/mcp.json" },
|
|
436
|
+
"gemini-cli": { hostId: "gemini", relPath: ".gemini/settings.json" }
|
|
437
|
+
};
|
|
438
|
+
function mcpRegistrationTargets(tools, readsConfig) {
|
|
439
|
+
const out = [];
|
|
440
|
+
for (const [toolId, spec] of Object.entries(MCP_PROJECT_CONFIG)) {
|
|
441
|
+
if (toolId === "claude-code") continue;
|
|
442
|
+
if (!tools.has(toolId)) continue;
|
|
443
|
+
if (!readsConfig(spec.hostId)) continue;
|
|
444
|
+
out.push({ toolId, hostId: spec.hostId, relPath: spec.relPath });
|
|
445
|
+
}
|
|
446
|
+
return out;
|
|
447
|
+
}
|
|
448
|
+
function makeEnsureMcpRegistrations(mergeJsonFile) {
|
|
449
|
+
return (projectRoot, force, packageRoot, targets) => {
|
|
450
|
+
const merged = {};
|
|
451
|
+
for (const t of targets) {
|
|
452
|
+
merged[t.toolId] = mergeJsonFile(
|
|
453
|
+
path.join(projectRoot, ...t.relPath.split("/")),
|
|
454
|
+
mcpBridgeEntry(packageRoot),
|
|
455
|
+
force,
|
|
456
|
+
t.relPath
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
return merged;
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function readsProjectMcpConfig(hostId) {
|
|
463
|
+
return probeHostCapabilities(hostId).reads_project_mcp_config;
|
|
464
|
+
}
|
|
465
|
+
function registerMcpHosts(mergeJsonFile, projectRoot, force, packageRoot, tools, into, readsConfig = readsProjectMcpConfig) {
|
|
466
|
+
const ensure = makeEnsureMcpRegistrations(mergeJsonFile);
|
|
467
|
+
const claude = MCP_PROJECT_CONFIG["claude-code"];
|
|
468
|
+
if (tools.has("claude-code") && claude !== void 0) {
|
|
469
|
+
const merged = ensure(projectRoot, force, packageRoot, [
|
|
470
|
+
{ toolId: "claude-code", hostId: claude.hostId, relPath: claude.relPath }
|
|
471
|
+
]);
|
|
472
|
+
(into["claude-code"] ??= []).push(...merged["claude-code"] ?? []);
|
|
473
|
+
}
|
|
474
|
+
for (const [toolId, keys] of Object.entries(
|
|
475
|
+
ensure(projectRoot, force, packageRoot, mcpRegistrationTargets(tools, readsConfig))
|
|
476
|
+
)) {
|
|
477
|
+
(into[toolId] ??= []).push(...keys);
|
|
478
|
+
}
|
|
411
479
|
}
|
|
412
480
|
function projectionModeOf(raw) {
|
|
413
481
|
return raw === "scoped" ? "scoped" : raw === "tiered" ? "tiered" : "legacy-all";
|
|
@@ -6804,11 +6872,9 @@ function _main_project_install(opts, project_root, parsed_tools, is_first_run) {
|
|
|
6804
6872
|
...ensure_augment_bridge(project_root, opts.force)
|
|
6805
6873
|
];
|
|
6806
6874
|
if (_is_tool_enabled(tools, "claude-code")) {
|
|
6807
|
-
merged_keys_by_tool["claude-code"] =
|
|
6808
|
-
...ensure_claude_bridge(project_root, opts.force),
|
|
6809
|
-
...ensure_mcp_bridge(project_root, opts.force)
|
|
6810
|
-
];
|
|
6875
|
+
merged_keys_by_tool["claude-code"] = ensure_claude_bridge(project_root, opts.force);
|
|
6811
6876
|
}
|
|
6877
|
+
registerMcpHosts(merge_json_file, project_root, opts.force, package_root, tools, merged_keys_by_tool);
|
|
6812
6878
|
if (_is_tool_enabled(tools, "cursor")) {
|
|
6813
6879
|
merged_keys_by_tool["cursor"] = ensure_cursor_bridge(project_root, opts.force);
|
|
6814
6880
|
}
|
|
@@ -6902,6 +6968,7 @@ function _main_project_install(opts, project_root, parsed_tools, is_first_run) {
|
|
|
6902
6968
|
);
|
|
6903
6969
|
process2.stdout.write("\n");
|
|
6904
6970
|
}
|
|
6971
|
+
printResiduals(tools, state.QUIET);
|
|
6905
6972
|
if (_is_tool_enabled(tools, "claude-code")) {
|
|
6906
6973
|
const team_hint = _team_setup_hint_line(project_root);
|
|
6907
6974
|
if (team_hint !== null) {
|
|
@@ -25,6 +25,7 @@ import { spawnSync } from "node:child_process";
|
|
|
25
25
|
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
|
|
26
26
|
|
|
27
27
|
// src/scripts/_lib/security_lint.ts
|
|
28
|
+
import { createHash } from "node:crypto";
|
|
28
29
|
import * as fs from "node:fs";
|
|
29
30
|
import * as path from "node:path";
|
|
30
31
|
import { fileURLToPath } from "node:url";
|
|
@@ -41,7 +42,7 @@ var DEFAULT_SCAN_ROOTS = [
|
|
|
41
42
|
"dist/agent-src"
|
|
42
43
|
];
|
|
43
44
|
var _EXAMPLE_PATH = /(^|\/)(docs|evals|tests?|fixtures?)(\/|$)|example|template|sample|\/_template/i;
|
|
44
|
-
var _PRAGMA = /<!--\s*security-lint:\s*allow\s+([A-Za-z0-9_-]+)\s+"([^"]+)"\s*-->/g;
|
|
45
|
+
var _PRAGMA = /<!--\s*security-lint:\s*allow\s+([A-Za-z0-9_-]+)\s+"([^"]+)"((?:\s+sha256:[0-9a-f]{64})*)\s*-->/g;
|
|
45
46
|
var _FENCE = /^(\s*)(`{3,}|~{3,})\s*([A-Za-z0-9_-]*)\s*$/;
|
|
46
47
|
var SEVERITY_RANK = { LOW: 1, MED: 2, HIGH: 3 };
|
|
47
48
|
var Finding = class {
|
|
@@ -87,6 +88,10 @@ function is_example_path(rel_path) {
|
|
|
87
88
|
function path_weight(rel_path) {
|
|
88
89
|
return is_example_path(rel_path) ? 0.25 : 1;
|
|
89
90
|
}
|
|
91
|
+
var PROJECTION_PREFIX = "dist/agent-src/";
|
|
92
|
+
function source_identity(rel) {
|
|
93
|
+
return rel.startsWith(PROJECTION_PREFIX) ? `src/${rel.slice(PROJECTION_PREFIX.length)}` : rel;
|
|
94
|
+
}
|
|
90
95
|
var ScannedFile = class {
|
|
91
96
|
path;
|
|
92
97
|
// absolute or as-given path
|
|
@@ -97,8 +102,10 @@ var ScannedFile = class {
|
|
|
97
102
|
in_any_fence;
|
|
98
103
|
pragmas;
|
|
99
104
|
// check id → reason
|
|
105
|
+
/** check id → the sha256 fingerprints that pragma accepts. Empty = unbound. */
|
|
106
|
+
pragma_hashes;
|
|
100
107
|
weight;
|
|
101
|
-
constructor(pathArg, rel, lines, in_example_fence, in_any_fence, pragmas, weight) {
|
|
108
|
+
constructor(pathArg, rel, lines, in_example_fence, in_any_fence, pragmas, weight, pragma_hashes = {}) {
|
|
102
109
|
this.path = pathArg;
|
|
103
110
|
this.rel = rel;
|
|
104
111
|
this.lines = lines;
|
|
@@ -106,10 +113,74 @@ var ScannedFile = class {
|
|
|
106
113
|
this.in_any_fence = in_any_fence;
|
|
107
114
|
this.pragmas = pragmas;
|
|
108
115
|
this.weight = weight;
|
|
116
|
+
this.pragma_hashes = pragma_hashes;
|
|
109
117
|
}
|
|
110
118
|
pragma_allows(check) {
|
|
111
119
|
return Object.prototype.hasOwnProperty.call(this.pragmas, check);
|
|
112
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Which form of pragma this file carries for `check`.
|
|
123
|
+
*
|
|
124
|
+
* `absent` — no pragma; scan normally.
|
|
125
|
+
* `legacy` — a pragma with no fingerprint. Suppresses the whole file, as it
|
|
126
|
+
* always did, and says so: a key lookup accepts whatever the
|
|
127
|
+
* line is later changed to say, which is the defect being paid
|
|
128
|
+
* down, not a mode anybody should choose.
|
|
129
|
+
* `bound` — a pragma listing fingerprints. Suppresses exactly the matches
|
|
130
|
+
* whose evidence hashes to one of them; anything else survives.
|
|
131
|
+
*/
|
|
132
|
+
pragma_form(check) {
|
|
133
|
+
if (!this.pragma_allows(check)) return "absent";
|
|
134
|
+
return (this.pragma_hashes[check] ?? []).length > 0 ? "bound" : "legacy";
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The fingerprint one finding's evidence hashes to.
|
|
138
|
+
*
|
|
139
|
+
* WHAT IS HASHED, and each part earns its place:
|
|
140
|
+
* check id — the same line may legitimately be accepted for one check
|
|
141
|
+
* and not another.
|
|
142
|
+
* rel path — the location IDENTITY. Not the line NUMBER: an unrelated
|
|
143
|
+
* insert above would otherwise break every pragma in the
|
|
144
|
+
* file, and a suppression that breaks on unrelated edits
|
|
145
|
+
* gets deleted rather than re-derived. A `dist/agent-src/`
|
|
146
|
+
* path folds to its `src/` original first, because the
|
|
147
|
+
* projection is byte-exact by contract (ADR-201) and
|
|
148
|
+
* carries the pragma verbatim — without the fold, every
|
|
149
|
+
* migrated pragma would suppress the source and leave its
|
|
150
|
+
* own copy flagged, which is a gate that reds on a file
|
|
151
|
+
* nobody may edit.
|
|
152
|
+
* matched line, — the evidence. ASCII whitespace runs collapse so a reflow
|
|
153
|
+
* normalized does not invalidate the binding, `sha256:<hex>` tokens are
|
|
154
|
+
* removed, and NOTHING else is stripped: the zero-width
|
|
155
|
+
* characters this suite hunts are exactly what a wider
|
|
156
|
+
* normalizer would erase.
|
|
157
|
+
*
|
|
158
|
+
* WHY THE HASH TOKENS COME OUT. A pragma's own reason string can be the
|
|
159
|
+
* matched evidence — two in this tree are, because they quote the very
|
|
160
|
+
* phrases their check detects in order to explain themselves. Without this
|
|
161
|
+
* the fingerprint would have to be computed over a line that already
|
|
162
|
+
* contains it, which has no fixed point: writing the hash changes the line,
|
|
163
|
+
* which changes the hash. Stripping the tokens makes the fingerprint stable
|
|
164
|
+
* under the act of recording it, and costs nothing elsewhere — a `sha256:`
|
|
165
|
+
* token in ordinary prose is not evidence of anything a linter here checks.
|
|
166
|
+
*
|
|
167
|
+
* Deliberately NOT the whole file: incidental content elsewhere would make
|
|
168
|
+
* every unrelated edit re-fire the pragma, which is the noise that produces
|
|
169
|
+
* blanket suppressions.
|
|
170
|
+
*/
|
|
171
|
+
evidence_fingerprint(finding) {
|
|
172
|
+
const text = finding.line > 0 ? this.lines[finding.line - 1] ?? "" : "";
|
|
173
|
+
const normalized = text.replace(/\s*sha256:[0-9a-f]{64}/g, "").replace(/[ \t]+/g, " ").trim();
|
|
174
|
+
return createHash("sha256").update(`${finding.check}
|
|
175
|
+
${source_identity(this.rel)}
|
|
176
|
+
${normalized}`, "utf-8").digest("hex");
|
|
177
|
+
}
|
|
178
|
+
/** Drop the findings this file's BOUND pragma for `check` accepts. */
|
|
179
|
+
filter_bound_pragma(check, findings) {
|
|
180
|
+
const accepted = new Set(this.pragma_hashes[check] ?? []);
|
|
181
|
+
if (accepted.size === 0) return [...findings];
|
|
182
|
+
return findings.filter((f) => !accepted.has(this.evidence_fingerprint(f)));
|
|
183
|
+
}
|
|
113
184
|
/** Yield [lineno, text] honouring the fence masks (mirrors iter_lines). */
|
|
114
185
|
*iter_lines(opts = {}) {
|
|
115
186
|
const skip_example_fence = opts.skip_example_fence ?? true;
|
|
@@ -200,11 +271,18 @@ function scan_file(filePath) {
|
|
|
200
271
|
}
|
|
201
272
|
}
|
|
202
273
|
const pragmas = {};
|
|
274
|
+
const pragmaHashes = {};
|
|
203
275
|
for (const text of lines) {
|
|
204
276
|
_PRAGMA.lastIndex = 0;
|
|
205
277
|
let m;
|
|
206
278
|
while ((m = _PRAGMA.exec(text)) !== null) {
|
|
207
|
-
|
|
279
|
+
const check = m[1];
|
|
280
|
+
pragmas[check] = m[2];
|
|
281
|
+
const hashes = (m[3] ?? "").match(/sha256:([0-9a-f]{64})/g) ?? [];
|
|
282
|
+
pragmaHashes[check] = [
|
|
283
|
+
...pragmaHashes[check] ?? [],
|
|
284
|
+
...hashes.map((h) => h.slice("sha256:".length))
|
|
285
|
+
];
|
|
208
286
|
if (m.index === _PRAGMA.lastIndex) {
|
|
209
287
|
_PRAGMA.lastIndex += 1;
|
|
210
288
|
}
|
|
@@ -217,7 +295,29 @@ function scan_file(filePath) {
|
|
|
217
295
|
in_example,
|
|
218
296
|
in_any,
|
|
219
297
|
pragmas,
|
|
220
|
-
path_weight(rel)
|
|
298
|
+
path_weight(rel),
|
|
299
|
+
pragmaHashes
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
function scan_path(filePath, base) {
|
|
303
|
+
const sf = scan_file(filePath);
|
|
304
|
+
let rel;
|
|
305
|
+
const baseResolved = path.resolve(base);
|
|
306
|
+
const fileResolved = path.resolve(filePath);
|
|
307
|
+
if (fileResolved === baseResolved || fileResolved.startsWith(baseResolved + path.sep)) {
|
|
308
|
+
rel = path.relative(baseResolved, fileResolved).split(path.sep).join("/");
|
|
309
|
+
} else {
|
|
310
|
+
rel = path.basename(filePath);
|
|
311
|
+
}
|
|
312
|
+
return new ScannedFile(
|
|
313
|
+
sf.path,
|
|
314
|
+
rel,
|
|
315
|
+
sf.lines,
|
|
316
|
+
sf.in_example_fence,
|
|
317
|
+
sf.in_any_fence,
|
|
318
|
+
sf.pragmas,
|
|
319
|
+
path_weight(rel),
|
|
320
|
+
sf.pragma_hashes
|
|
221
321
|
);
|
|
222
322
|
}
|
|
223
323
|
function _rglobSorted(base) {
|
|
@@ -253,9 +353,9 @@ function _pathCmp(a, b) {
|
|
|
253
353
|
if (pa.length > pb.length) return 1;
|
|
254
354
|
return 0;
|
|
255
355
|
}
|
|
256
|
-
function* iter_corpus(roots = DEFAULT_SCAN_ROOTS, exts = [".md"]) {
|
|
356
|
+
function* iter_corpus(roots = DEFAULT_SCAN_ROOTS, exts = [".md"], scanBase = ROOT) {
|
|
257
357
|
for (const root of roots) {
|
|
258
|
-
const base = path.join(
|
|
358
|
+
const base = path.join(scanBase, root);
|
|
259
359
|
if (!fs.existsSync(base)) {
|
|
260
360
|
continue;
|
|
261
361
|
}
|
|
@@ -267,11 +367,27 @@ function* iter_corpus(roots = DEFAULT_SCAN_ROOTS, exts = [".md"]) {
|
|
|
267
367
|
continue;
|
|
268
368
|
}
|
|
269
369
|
if (st.isFile() && exts.includes(path.extname(p))) {
|
|
270
|
-
yield
|
|
370
|
+
yield scan_path(p, scanBase);
|
|
271
371
|
}
|
|
272
372
|
}
|
|
273
373
|
}
|
|
274
374
|
}
|
|
375
|
+
var LEGACY_PRAGMA_CHECK = "legacy-pragma";
|
|
376
|
+
function legacy_pragma_finding(sf, check) {
|
|
377
|
+
return new Finding(
|
|
378
|
+
sf.rel,
|
|
379
|
+
0,
|
|
380
|
+
LEGACY_PRAGMA_CHECK,
|
|
381
|
+
"LOW",
|
|
382
|
+
`unbound \`security-lint: allow ${check}\` pragma suppresses this whole file \u2014 it accepts whatever the matched text is later changed to say. Bind it with \`sha256:<hex>\` per accepted match.`,
|
|
383
|
+
sf.weight
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
var CHILD_SCANNED_PREFIX = "scanned: ";
|
|
387
|
+
function report_child_scanned(count) {
|
|
388
|
+
process.stderr.write(`${CHILD_SCANNED_PREFIX}${String(count)}
|
|
389
|
+
`);
|
|
390
|
+
}
|
|
275
391
|
function report(findings, opts) {
|
|
276
392
|
const check_label = opts.check_label;
|
|
277
393
|
if (findings.length === 0) {
|
|
@@ -647,9 +763,11 @@ function _cpName(cp) {
|
|
|
647
763
|
return n !== void 0 ? n : "<unnamed>";
|
|
648
764
|
}
|
|
649
765
|
function _scan(sf) {
|
|
650
|
-
|
|
651
|
-
|
|
766
|
+
const pragmaForm = sf.pragma_form(CHECK);
|
|
767
|
+
if (pragmaForm === "legacy") {
|
|
768
|
+
return [legacy_pragma_finding(sf, CHECK)];
|
|
652
769
|
}
|
|
770
|
+
const finish = (hits) => pragmaForm === "bound" ? sf.filter_bound_pragma(CHECK, hits) : hits;
|
|
653
771
|
const out = [];
|
|
654
772
|
for (const [lineno, text] of sf.iter_lines({ skip_example_fence: true })) {
|
|
655
773
|
let vs_run = 0;
|
|
@@ -687,7 +805,7 @@ function _scan(sf) {
|
|
|
687
805
|
);
|
|
688
806
|
}
|
|
689
807
|
}
|
|
690
|
-
return out;
|
|
808
|
+
return finish(out);
|
|
691
809
|
}
|
|
692
810
|
var _BINARY_EXT = /* @__PURE__ */ new Set([
|
|
693
811
|
"png",
|
|
@@ -848,7 +966,7 @@ function _sanitize(filePath) {
|
|
|
848
966
|
return out;
|
|
849
967
|
}
|
|
850
968
|
function _argError(msg) {
|
|
851
|
-
process.stderr.write("usage: lint_hidden_unicode [-h] [--json] [--fix]\n");
|
|
969
|
+
process.stderr.write("usage: lint_hidden_unicode [-h] [--json] [--fix] [--root DIR]\n");
|
|
852
970
|
process.stderr.write(`lint_hidden_unicode: error: ${msg}
|
|
853
971
|
`);
|
|
854
972
|
process.exit(2);
|
|
@@ -856,14 +974,27 @@ function _argError(msg) {
|
|
|
856
974
|
function parse_args(argv) {
|
|
857
975
|
const out = { json: false, fix: false };
|
|
858
976
|
const extra = [];
|
|
977
|
+
let rootPending = false;
|
|
859
978
|
for (const a of argv) {
|
|
979
|
+
if (rootPending) {
|
|
980
|
+
out.root = a;
|
|
981
|
+
rootPending = false;
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
860
984
|
if (a === "-h" || a === "--help") {
|
|
861
|
-
process.stdout.write("usage: lint_hidden_unicode [-h] [--json] [--fix]\n");
|
|
985
|
+
process.stdout.write("usage: lint_hidden_unicode [-h] [--json] [--fix] [--root DIR]\n");
|
|
862
986
|
process.exit(0);
|
|
863
987
|
} else if (a === "--json") {
|
|
864
988
|
out.json = true;
|
|
865
989
|
} else if (a === "--fix") {
|
|
866
990
|
out.fix = true;
|
|
991
|
+
} else if (a === "--root" || a.startsWith("--root=")) {
|
|
992
|
+
const eq = a.indexOf("=");
|
|
993
|
+
if (eq !== -1) {
|
|
994
|
+
out.root = a.slice(eq + 1);
|
|
995
|
+
} else {
|
|
996
|
+
rootPending = true;
|
|
997
|
+
}
|
|
867
998
|
} else {
|
|
868
999
|
extra.push(a);
|
|
869
1000
|
}
|
|
@@ -875,10 +1006,11 @@ function parse_args(argv) {
|
|
|
875
1006
|
}
|
|
876
1007
|
function main(argv = null) {
|
|
877
1008
|
const args = parse_args(argv ?? process.argv.slice(2));
|
|
1009
|
+
const scanBase = args.root === void 0 ? ROOT : path2.resolve(args.root);
|
|
878
1010
|
const findings = [];
|
|
879
1011
|
const flagged = /* @__PURE__ */ new Set();
|
|
880
1012
|
let corpusFiles = 0;
|
|
881
|
-
for (const sf of iter_corpus()) {
|
|
1013
|
+
for (const sf of iter_corpus(DEFAULT_SCAN_ROOTS, [".md"], scanBase)) {
|
|
882
1014
|
corpusFiles += 1;
|
|
883
1015
|
const hits = _scan(sf);
|
|
884
1016
|
for (const h of hits) {
|
|
@@ -903,7 +1035,7 @@ function main(argv = null) {
|
|
|
903
1035
|
}
|
|
904
1036
|
throw exc;
|
|
905
1037
|
}
|
|
906
|
-
const sourceFiles = _eligibleSourceFiles();
|
|
1038
|
+
const sourceFiles = args.root === void 0 ? _eligibleSourceFiles() : [];
|
|
907
1039
|
for (const h of _scanSourceControlBytes(sourceFiles)) {
|
|
908
1040
|
findings.push(h);
|
|
909
1041
|
}
|
|
@@ -922,6 +1054,9 @@ function main(argv = null) {
|
|
|
922
1054
|
`);
|
|
923
1055
|
}
|
|
924
1056
|
}
|
|
1057
|
+
if (args.json) {
|
|
1058
|
+
report_child_scanned(corpusFiles + (sourceFiles === null ? 0 : sourceFiles.length));
|
|
1059
|
+
}
|
|
925
1060
|
if (args.json) {
|
|
926
1061
|
const payload = py_json_dumps_indent2(findings.map((f) => f.toDict()));
|
|
927
1062
|
process.stdout.write(payload + "\n");
|
|
@@ -2298,7 +2433,7 @@ function queryIndex(indexPath, keys, types) {
|
|
|
2298
2433
|
}
|
|
2299
2434
|
|
|
2300
2435
|
// src/scripts/learning_sidecar.ts
|
|
2301
|
-
import { createHash } from "node:crypto";
|
|
2436
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
2302
2437
|
import * as fs6 from "node:fs";
|
|
2303
2438
|
import * as path6 from "node:path";
|
|
2304
2439
|
import process4 from "node:process";
|
|
@@ -2314,7 +2449,7 @@ function _parseTsMs(ts) {
|
|
|
2314
2449
|
return Number.isNaN(t) ? null : t;
|
|
2315
2450
|
}
|
|
2316
2451
|
function _bodyHash(body) {
|
|
2317
|
-
return
|
|
2452
|
+
return createHash2("sha256").update(body.trim().toLowerCase()).digest("hex").slice(0, 12);
|
|
2318
2453
|
}
|
|
2319
2454
|
function _globSignalFiles(dir) {
|
|
2320
2455
|
let names;
|