@event4u/agent-config 9.25.0 → 9.26.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +87 -0
- package/README.md +1 -1
- package/dist/agent-src/commands/analyze/conformance.md +2 -2
- package/dist/agent-src/commands/review/changes.md +6 -5
- package/dist/agent-src/commands/roadmap/next.md +194 -0
- package/dist/agent-src/commands/roadmap.md +12 -4
- package/dist/agent-src/contexts/execution/subagent-routing.md +4 -1
- package/dist/agent-src/rules/delegation-policy.md +3 -2
- package/dist/agent-src/rules/design-fidelity.md +17 -1
- package/dist/agent-src/rules/design-review-after-ui-write.md +116 -0
- package/dist/agent-src/rules/evaluator-independence.md +9 -3
- package/dist/agent-src/rules/session-canary.md +2 -0
- package/dist/agent-src/rules/settings-ask-protocol.md +176 -0
- package/dist/agent-src/rules/token-budget-discipline.md +6 -3
- package/dist/agent-src/rules/ui-audit-gate.md +3 -0
- package/dist/agent-src/rules/user-interaction.md +3 -2
- package/dist/agent-src/skills/recursive-verification/SKILL.md +13 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli-delegate/cmd_route_audit.js +4 -1
- package/dist/cli-delegate/cmd_route_explain.js +4 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +94 -23
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +11 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +9 -6
- package/dist/hooks/dispatch.js +355 -63
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/router.json +1 -1
- package/dist/server/nicknameResolver.js +116 -0
- package/dist/server/nicknameResolver.js.map +1 -0
- package/dist/server/routes/ping.js +29 -11
- package/dist/server/routes/ping.js.map +1 -1
- package/dist/shared/interactiveContext.js +73 -0
- package/dist/shared/interactiveContext.js.map +1 -0
- package/dist/shared/nicknamePrefill.js +59 -0
- package/dist/shared/nicknamePrefill.js.map +1 -0
- package/dist/shared/settingsAsks.js +128 -0
- package/dist/shared/settingsAsks.js.map +1 -0
- package/dist/shared/settingsConsent.js +93 -0
- package/dist/shared/settingsConsent.js.map +1 -0
- package/package.json +1 -1
- package/src/config/agents-paths.yml +15 -0
- package/src/config/gate-coverage.yml +29 -1
- package/src/config/gate-violation-baselines.json +13 -7
- package/src/scripts/_cli/cmd_route_audit.ts +4 -1
- package/src/scripts/_cli/cmd_route_explain.ts +9 -1
- package/src/scripts/ai-video/stitch.sh +27 -9
- package/src/scripts/before_complete_hook.ts +23 -4
- package/src/scripts/bench_ab_v2_run.ts +272 -16
- package/src/scripts/bench_ab_v2_stats.ts +156 -3
- package/src/scripts/check_completion_review.ts +80 -3
- package/src/scripts/check_corpus_staleness.ts +692 -0
- package/src/scripts/check_gate_coverage.ts +67 -0
- package/src/scripts/check_hook_bundle_freshness.ts +183 -0
- package/src/scripts/conformance_scan.ts +47 -17
- package/src/scripts/dispatch_r2_reviewer.ts +31 -2
- package/src/scripts/git_authorization_hook.ts +75 -10
- package/src/scripts/hook_manifest.yaml +19 -0
- package/src/scripts/hooks/block_no_verify.ts +3 -1
- package/src/scripts/hooks/block_unauthorized_git.ts +133 -16
- package/src/scripts/hooks/design_slop_hook.ts +13 -1
- package/src/scripts/hooks/dispatch_hook.ts +97 -2
- package/src/scripts/hooks/evidence_independence.ts +40 -6
- package/src/scripts/language_mirror_hook.ts +200 -11
- package/src/scripts/lint_abstraction_thresholds.ts +41 -8
- package/src/scripts/lint_agents_layout.ts +2 -0
- package/src/scripts/lint_hook_manifest.ts +29 -0
- package/src/scripts/memory_learn_hook.ts +109 -6
- package/src/scripts/pr_url_reminder_hook.ts +17 -2
- package/src/scripts/release.ts +38 -1
- package/src/scripts/schemas/review-findings.schema.json +99 -0
- package/src/shared/interactiveContext.ts +98 -0
- package/src/shared/nicknamePrefill.ts +96 -0
- package/src/shared/settingsAsks.ts +176 -0
- package/src/shared/settingsConsent.ts +136 -0
package/dist/hooks/dispatch.js
CHANGED
|
@@ -15128,9 +15128,10 @@ var _VACUOUS_PATTERNS = [
|
|
|
15128
15128
|
function isVacuousOutput(output) {
|
|
15129
15129
|
const text = output.trim();
|
|
15130
15130
|
if (!text) {
|
|
15131
|
-
return
|
|
15131
|
+
return false;
|
|
15132
15132
|
}
|
|
15133
|
-
|
|
15133
|
+
const lines = text.split("\n").filter((l) => l.trim());
|
|
15134
|
+
return lines.every((l) => _VACUOUS_PATTERNS.some((re) => re.test(l)));
|
|
15134
15135
|
}
|
|
15135
15136
|
var _CI_POLL_RE = /\bgh\s+(?:pr\s+checks|run\s+(?:watch|list|view))\b/i;
|
|
15136
15137
|
function isCiPoll(command) {
|
|
@@ -15142,7 +15143,16 @@ function pendingCount(output) {
|
|
|
15142
15143
|
return Number(m[1]);
|
|
15143
15144
|
}
|
|
15144
15145
|
const rows = output.match(/^\S.*\b(pending|in_progress|queued)\b/gim);
|
|
15145
|
-
|
|
15146
|
+
if (rows) {
|
|
15147
|
+
return rows.length;
|
|
15148
|
+
}
|
|
15149
|
+
if (/\bno checks reported\b/i.test(output)) {
|
|
15150
|
+
return null;
|
|
15151
|
+
}
|
|
15152
|
+
if (/^\S+\s+(pass|fail|skipping|successful|failing)\b/im.test(output)) {
|
|
15153
|
+
return 0;
|
|
15154
|
+
}
|
|
15155
|
+
return null;
|
|
15146
15156
|
}
|
|
15147
15157
|
function _extract_output(payload) {
|
|
15148
15158
|
for (const key of ["tool_response", "toolResponse", "output", "stdout", "result"]) {
|
|
@@ -15834,15 +15844,53 @@ if (_isCliEntry11()) {
|
|
|
15834
15844
|
import fs22 from "node:fs";
|
|
15835
15845
|
import path21 from "node:path";
|
|
15836
15846
|
import { fileURLToPath as fileURLToPath16, pathToFileURL as pathToFileURL12 } from "node:url";
|
|
15847
|
+
|
|
15848
|
+
// src/shared/settingsClasses.ts
|
|
15849
|
+
function isConservativeDefault(value) {
|
|
15850
|
+
if (value === null || value === false || value === "" || value === 0) {
|
|
15851
|
+
return true;
|
|
15852
|
+
}
|
|
15853
|
+
if (Array.isArray(value)) {
|
|
15854
|
+
return value.length === 0;
|
|
15855
|
+
}
|
|
15856
|
+
if (typeof value === "object" && value !== null) {
|
|
15857
|
+
return Object.keys(value).length === 0;
|
|
15858
|
+
}
|
|
15859
|
+
return false;
|
|
15860
|
+
}
|
|
15861
|
+
|
|
15862
|
+
// src/shared/settingsConsent.ts
|
|
15863
|
+
var HUMAN_SOURCES = ["jit-answer", "gui", "manual"];
|
|
15864
|
+
function consentVerdict(query) {
|
|
15865
|
+
if (query.cls !== "B") {
|
|
15866
|
+
return "not-a-consent-key";
|
|
15867
|
+
}
|
|
15868
|
+
if (isConservativeDefault(query.value)) {
|
|
15869
|
+
return "withheld-default";
|
|
15870
|
+
}
|
|
15871
|
+
if (query.handEdited === true) {
|
|
15872
|
+
return "granted";
|
|
15873
|
+
}
|
|
15874
|
+
if (query.source === void 0) {
|
|
15875
|
+
return "withheld-unrecorded";
|
|
15876
|
+
}
|
|
15877
|
+
if (!HUMAN_SOURCES.includes(query.source)) {
|
|
15878
|
+
return "withheld-machine-inferred";
|
|
15879
|
+
}
|
|
15880
|
+
return "granted";
|
|
15881
|
+
}
|
|
15882
|
+
|
|
15883
|
+
// src/scripts/memory_learn_hook.ts
|
|
15837
15884
|
var SETTINGS_FILE4 = ".agent-settings.yml";
|
|
15838
15885
|
var BUDGET_MS = 2e3;
|
|
15839
|
-
|
|
15886
|
+
var LEARN_KEY_CLASS = "B";
|
|
15887
|
+
function readLearnValue(root) {
|
|
15840
15888
|
const p = path21.join(root, SETTINGS_FILE4);
|
|
15841
15889
|
let text;
|
|
15842
15890
|
try {
|
|
15843
15891
|
text = fs22.readFileSync(p, "utf8");
|
|
15844
15892
|
} catch {
|
|
15845
|
-
return
|
|
15893
|
+
return void 0;
|
|
15846
15894
|
}
|
|
15847
15895
|
let inMemory = false;
|
|
15848
15896
|
for (const rawLine of text.split("\n")) {
|
|
@@ -15860,7 +15908,17 @@ function enabled(root) {
|
|
|
15860
15908
|
if (m) return m[1] === "true";
|
|
15861
15909
|
}
|
|
15862
15910
|
}
|
|
15863
|
-
return
|
|
15911
|
+
return void 0;
|
|
15912
|
+
}
|
|
15913
|
+
function learnConsent(root) {
|
|
15914
|
+
return consentVerdict({
|
|
15915
|
+
cls: LEARN_KEY_CLASS,
|
|
15916
|
+
value: readLearnValue(root) ?? false,
|
|
15917
|
+
handEdited: true
|
|
15918
|
+
});
|
|
15919
|
+
}
|
|
15920
|
+
function enabled(root) {
|
|
15921
|
+
return learnConsent(root) === "granted";
|
|
15864
15922
|
}
|
|
15865
15923
|
function runLearn(root, nowIso, budgetMs = BUDGET_MS) {
|
|
15866
15924
|
const started = Date.now();
|
|
@@ -17199,6 +17257,10 @@ var _PR_URL = /https?:\/\/github\.com\/[^\s"'`<>]+\/pull\/\d+/i;
|
|
|
17199
17257
|
function _isObject4(v) {
|
|
17200
17258
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
17201
17259
|
}
|
|
17260
|
+
function _unwrap(envelope) {
|
|
17261
|
+
const inner = envelope["payload"];
|
|
17262
|
+
return _isObject4(inner) ? inner : envelope;
|
|
17263
|
+
}
|
|
17202
17264
|
function _extractCommand(payload) {
|
|
17203
17265
|
const toolRaw = payload["tool_name"] ?? payload["toolName"] ?? payload["tool"];
|
|
17204
17266
|
const tool = typeof toolRaw === "string" ? toolRaw : null;
|
|
@@ -17251,11 +17313,12 @@ function main21() {
|
|
|
17251
17313
|
if (!_isObject4(envelope)) {
|
|
17252
17314
|
return EXIT_ALLOW3;
|
|
17253
17315
|
}
|
|
17254
|
-
const
|
|
17316
|
+
const inner = _unwrap(envelope);
|
|
17317
|
+
const [tool, command] = _extractCommand(inner);
|
|
17255
17318
|
if (!_isPrCreate(tool, command)) {
|
|
17256
17319
|
return EXIT_ALLOW3;
|
|
17257
17320
|
}
|
|
17258
|
-
const match = _PR_URL.exec(_toolOutput(
|
|
17321
|
+
const match = _PR_URL.exec(_toolOutput(inner));
|
|
17259
17322
|
if (match === null) {
|
|
17260
17323
|
return EXIT_ALLOW3;
|
|
17261
17324
|
}
|
|
@@ -17472,16 +17535,39 @@ import fs33 from "node:fs";
|
|
|
17472
17535
|
import path33 from "node:path";
|
|
17473
17536
|
import { fileURLToPath as fileURLToPath25, pathToFileURL as pathToFileURL20 } from "node:url";
|
|
17474
17537
|
var EXIT_ALLOW5 = 0;
|
|
17538
|
+
var EXIT_WARN3 = 2;
|
|
17475
17539
|
var STATE_FILE5 = path33.join("agents", "state", "language-mirror.json");
|
|
17476
17540
|
function _isObject6(v) {
|
|
17477
17541
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
17478
17542
|
}
|
|
17479
|
-
var DE_MARKERS = /\b(der|die|das|den|dem|und|ist|sind|nicht|kein|keine|mach|mache|bitte|warum|wieso|weshalb|weiter|kannst|sollst|soll|musst|muss|hast|habe|haben|wir|ich|du|dann|noch|auch|schon|wenn|aber|alle|mit|ohne|damit|dass|wurde|werden|gibt|nochmal|erstell|erstelle|erstelle|fehler|regeln|arbeite|analysiere|fixe|nimm|lege|prüfe|pruefe|schau|zeig|mir|dir|sich|eine|einen|einem|einer|vom|zum|zur|beim|im
|
|
17543
|
+
var DE_MARKERS = /\b(der|die|das|den|dem|und|ist|sind|nicht|kein|keine|mach|mache|bitte|warum|wieso|weshalb|weiter|kannst|sollst|soll|musst|muss|hast|habe|haben|wir|ich|du|dann|noch|auch|schon|wenn|aber|alle|mit|ohne|damit|dass|wurde|werden|gibt|nochmal|erstell|erstelle|erstelle|fehler|regeln|arbeite|analysiere|fixe|nimm|lege|prüfe|pruefe|schau|zeig|mir|dir|sich|eine|einen|einem|einer|vom|zum|zur|beim|im)\b|[äöüÄÖÜß]/gi;
|
|
17480
17544
|
var EN_MARKERS = /\b(the|and|is|are|was|were|not|please|why|because|should|would|could|there|these|those|with|from|about|which|that|this|will|have|has|been|they|them|their|your|our|what|when|where|make|need|want|does|doesn't|don't|it's|let's)\b/gi;
|
|
17481
17545
|
var MIN_MARKERS = 2;
|
|
17546
|
+
function instructionText(prompt) {
|
|
17547
|
+
const OUTPUT_HEAD = /^\s*(To\s+\S+|remote:|error:|fatal:|hint:|warning:|npm ERR!|Error:|Traceback|Exception|[A-Za-z]*Error\b|at\s+\S+:\d+|\s{4,}\S|[-+]{3}\s|@@\s|\$\s|>\s|\||\d+\s*\|)/i;
|
|
17548
|
+
const kept = [];
|
|
17549
|
+
let inPaste = false;
|
|
17550
|
+
for (const line of prompt.replace(/```[\s\S]*?```/g, "\n\n").split("\n")) {
|
|
17551
|
+
if (!line.trim()) {
|
|
17552
|
+
inPaste = false;
|
|
17553
|
+
kept.push(line);
|
|
17554
|
+
continue;
|
|
17555
|
+
}
|
|
17556
|
+
if (OUTPUT_HEAD.test(line)) {
|
|
17557
|
+
inPaste = true;
|
|
17558
|
+
continue;
|
|
17559
|
+
}
|
|
17560
|
+
if (inPaste) {
|
|
17561
|
+
continue;
|
|
17562
|
+
}
|
|
17563
|
+
kept.push(line);
|
|
17564
|
+
}
|
|
17565
|
+
return kept.join("\n");
|
|
17566
|
+
}
|
|
17482
17567
|
function classify(prompt) {
|
|
17483
|
-
const
|
|
17484
|
-
const
|
|
17568
|
+
const text = instructionText(prompt);
|
|
17569
|
+
const de = (text.match(DE_MARKERS) ?? []).length;
|
|
17570
|
+
const en = (text.match(EN_MARKERS) ?? []).length;
|
|
17485
17571
|
if (de < MIN_MARKERS && en < MIN_MARKERS) {
|
|
17486
17572
|
return { language: "und", de_markers: de, en_markers: en };
|
|
17487
17573
|
}
|
|
@@ -17491,8 +17577,44 @@ var LANGUAGE_NAME = {
|
|
|
17491
17577
|
de: "German (Deutsch)",
|
|
17492
17578
|
en: "English"
|
|
17493
17579
|
};
|
|
17494
|
-
|
|
17580
|
+
var LOCALE_ENV_KEYS = ["LC_ALL", "LC_MESSAGES", "LANG", "LANGUAGE"];
|
|
17581
|
+
function systemLocaleVerdict(env = process.env) {
|
|
17582
|
+
for (const key of LOCALE_ENV_KEYS) {
|
|
17583
|
+
const raw = (env[key] ?? "").trim();
|
|
17584
|
+
if (!raw) {
|
|
17585
|
+
continue;
|
|
17586
|
+
}
|
|
17587
|
+
const first = raw.split(":")[0] ?? "";
|
|
17588
|
+
const primary = (first.split(/[._@-]/)[0] ?? "").toLowerCase();
|
|
17589
|
+
if (primary === "c" || primary === "posix" || !primary) {
|
|
17590
|
+
continue;
|
|
17591
|
+
}
|
|
17592
|
+
if (primary === "de") {
|
|
17593
|
+
return "de";
|
|
17594
|
+
}
|
|
17595
|
+
if (primary === "en") {
|
|
17596
|
+
return "en";
|
|
17597
|
+
}
|
|
17598
|
+
return "und";
|
|
17599
|
+
}
|
|
17600
|
+
return "und";
|
|
17601
|
+
}
|
|
17602
|
+
function noticeText(language, source) {
|
|
17603
|
+
const name = LANGUAGE_NAME[language];
|
|
17604
|
+
if (source === "system-locale") {
|
|
17605
|
+
return `Reply language for this turn: ${name} \u2014 the prompt carried no language markers, so this fell back to the system locale. Write in another language and the next turn follows the prompt instead.`;
|
|
17606
|
+
}
|
|
17607
|
+
return `Reply language for this turn: ${name}.`;
|
|
17608
|
+
}
|
|
17609
|
+
function pinText(language, source = "prompt") {
|
|
17495
17610
|
const name = LANGUAGE_NAME[language];
|
|
17611
|
+
if (source === "system-locale") {
|
|
17612
|
+
return `<language-pin>
|
|
17613
|
+
No language markers were found in this turn's prompt and no language was pinned yet, so the mirror target falls back to the environment's locale: ${name}. Use it for EVERY user-visible token this turn.
|
|
17614
|
+
|
|
17615
|
+
This is the WEAKER of the two provenances \u2014 it reflects the machine, not the user's own words. The first prompt that carries real markers replaces it. Do not treat it as a standing preference, and do not argue with the user about it if they write in something else.
|
|
17616
|
+
</language-pin>`;
|
|
17617
|
+
}
|
|
17496
17618
|
return `<language-pin>
|
|
17497
17619
|
The user submitted this turn's prompt in ${name}. That is the mirror target for EVERY user-visible token of your replies this turn \u2014 including the short inter-tool lines between tool calls, headings, table cells, bullets, status lines, and the recommendation label under any numbered-options block.
|
|
17498
17620
|
|
|
@@ -17508,12 +17630,27 @@ function _loadState(target) {
|
|
|
17508
17630
|
return {};
|
|
17509
17631
|
}
|
|
17510
17632
|
}
|
|
17511
|
-
function nextState(previous, classification, prompt_chars, session_id, now) {
|
|
17633
|
+
function nextState(previous, classification, prompt_chars, session_id, now, locale = "und") {
|
|
17512
17634
|
if (classification.language === "und") {
|
|
17513
|
-
|
|
17635
|
+
if (previous.language === "de" || previous.language === "en") {
|
|
17636
|
+
return null;
|
|
17637
|
+
}
|
|
17638
|
+
if (locale === "und") {
|
|
17639
|
+
return null;
|
|
17640
|
+
}
|
|
17641
|
+
return {
|
|
17642
|
+
language: locale,
|
|
17643
|
+
source: "system-locale",
|
|
17644
|
+
detected_at: now,
|
|
17645
|
+
prompt_chars,
|
|
17646
|
+
de_markers: classification.de_markers,
|
|
17647
|
+
en_markers: classification.en_markers,
|
|
17648
|
+
session_id
|
|
17649
|
+
};
|
|
17514
17650
|
}
|
|
17515
17651
|
return {
|
|
17516
17652
|
language: classification.language,
|
|
17653
|
+
source: "prompt",
|
|
17517
17654
|
detected_at: now,
|
|
17518
17655
|
prompt_chars,
|
|
17519
17656
|
de_markers: classification.de_markers,
|
|
@@ -17551,8 +17688,19 @@ function run7(stdin_text, options) {
|
|
|
17551
17688
|
const target = path33.join(options.consumer_root, STATE_FILE5);
|
|
17552
17689
|
const previous = _loadState(target);
|
|
17553
17690
|
const classification = classify(prompt);
|
|
17554
|
-
const next = nextState(
|
|
17691
|
+
const next = nextState(
|
|
17692
|
+
previous,
|
|
17693
|
+
classification,
|
|
17694
|
+
prompt.length,
|
|
17695
|
+
session_id,
|
|
17696
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
17697
|
+
// Injectable so the suite can pin a locale instead of inheriting the
|
|
17698
|
+
// machine's — a test whose verdict depends on the developer's `LANG` is a
|
|
17699
|
+
// test that passes here and fails in CI for reasons unrelated to the diff.
|
|
17700
|
+
systemLocaleVerdict(options.env ?? process.env)
|
|
17701
|
+
);
|
|
17555
17702
|
const effective = next?.language ?? previous.language;
|
|
17703
|
+
const effectiveSource = next?.source ?? (previous.source === "system-locale" ? "system-locale" : "prompt");
|
|
17556
17704
|
if (next) {
|
|
17557
17705
|
try {
|
|
17558
17706
|
atomic_write_json(target, next);
|
|
@@ -17561,9 +17709,10 @@ function run7(stdin_text, options) {
|
|
|
17561
17709
|
}
|
|
17562
17710
|
if (effective === "de" || effective === "en") {
|
|
17563
17711
|
process.stdout.write(
|
|
17564
|
-
`${JSON.stringify({ decision: "warn", reason:
|
|
17712
|
+
`${JSON.stringify({ decision: "warn", reason: noticeText(effective, effectiveSource), additional_context: pinText(effective, effectiveSource) })}
|
|
17565
17713
|
`
|
|
17566
17714
|
);
|
|
17715
|
+
return EXIT_WARN3;
|
|
17567
17716
|
}
|
|
17568
17717
|
return EXIT_ALLOW5;
|
|
17569
17718
|
}
|
|
@@ -17614,15 +17763,42 @@ function _isObject7(v) {
|
|
|
17614
17763
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
17615
17764
|
}
|
|
17616
17765
|
var PHRASES = [
|
|
17617
|
-
{ op: "commit", re: /\b(commit(e|et|ten
|
|
17618
|
-
{ op: "push", re: /\b(push(e|en|
|
|
17619
|
-
{ op: "branch", re: /\b(branch
|
|
17620
|
-
|
|
17621
|
-
{
|
|
17622
|
-
|
|
17623
|
-
|
|
17624
|
-
|
|
17766
|
+
{ op: "commit", re: /\b(commit(e|et|te|ten)?|committe|einchecken)\b/i },
|
|
17767
|
+
{ op: "push", re: /\b(push(e|en|t)?|hochladen|hochschieben|raufschieben)\b/i },
|
|
17768
|
+
{ op: "branch", re: /\b(branch|feature-branch|zweig)\b/i },
|
|
17769
|
+
// A creation verb is required — "schau dir den PR an" is not "open a PR".
|
|
17770
|
+
{
|
|
17771
|
+
op: "pr-create",
|
|
17772
|
+
re: /\b(erstell(e|en)?|mach(e|en)?|leg(e|en)?\s+an|(er)?(ö|oe)ffne|open|create|raise|aufmachen)\b[^.\n]{0,30}\b(pr|pull[- ]request)\b|\b(pr|pull[- ]request)\b[^.\n]{0,20}\b(erstellen|aufmachen|anlegen|(er)?(ö|oe)ffnen)\b/i
|
|
17773
|
+
},
|
|
17774
|
+
// `merge` as an ACTION, never as the noun in "merge conflict" / "merge commit".
|
|
17775
|
+
{ op: "pr-merge", re: /\b(merge|merg(e|en|st|t)|zusammenf(ü|ue)hren|reinmergen)\b(?!\s*[- ]?(conflict|konflikt|commit|base|queue|state|status))/i },
|
|
17776
|
+
// A tag is an ACTION here — bare "Tag" is the German word for day, and
|
|
17777
|
+
// "Version" is an ordinary noun. Both authorized a BLOCK op before this.
|
|
17778
|
+
{ op: "tag", re: /\b(tagge(n|st)?|tag\s+(setzen|anlegen|erstellen)|git\s+tag|--tags|--follow-tags)\b/i },
|
|
17779
|
+
// "die release notes sind falsch" is a noun phrase, not an authorization.
|
|
17780
|
+
{
|
|
17781
|
+
op: "release",
|
|
17782
|
+
re: /\b(releasen?|ver(ö|oe)ffentlich(e|en))\b(?!\s*[- ]?(notes?|branch|candidate|pr\b|datum|date|zweig))/i
|
|
17783
|
+
},
|
|
17784
|
+
{ op: "publish", re: /\b(publish(e|en)?|publiziere[n]?)\b/i }
|
|
17625
17785
|
];
|
|
17786
|
+
var OUTPUT_LINE = /^\s*(To\s+\S+|remote:|error:|fatal:|hint:|warning:|!\s|\?\?\s|\s*\^|[-+]{3}\s|@@\s|\$\s|>\s|\d+\s+(pass|fail)|npm ERR!|Error:|Traceback|at\s+\S+:\d+)/i;
|
|
17787
|
+
function isInterrogative(prose) {
|
|
17788
|
+
const t = prose.trim();
|
|
17789
|
+
if (!t) {
|
|
17790
|
+
return false;
|
|
17791
|
+
}
|
|
17792
|
+
const hasImperative = /\b(mach|mache|bitte|leg|lege|erstell|erstelle|f(ü|ue)hr|f(ü|ue)hre|setz|setze|starte|los|jetzt|go ahead|do it|ja[,.]?\s|ok[,.]?\s)\b/i.test(
|
|
17793
|
+
t
|
|
17794
|
+
);
|
|
17795
|
+
if (hasImperative) {
|
|
17796
|
+
return false;
|
|
17797
|
+
}
|
|
17798
|
+
return /\?\s*$/.test(t) || /^(was|wie|warum|wieso|weshalb|wann|wer|welche[rs]?|wo|ist|sind|kann|kannst|k(ö|oe)nnen|soll|sollen|darf|d(ü|ue)rfen|why|what|how|when|which|who|is|are|can|could|should|does|do)\b/i.test(
|
|
17799
|
+
t
|
|
17800
|
+
);
|
|
17801
|
+
}
|
|
17626
17802
|
var PASTED_COMMANDS = [
|
|
17627
17803
|
{ op: "publish", re: /\bnpm\s+publish\b/i },
|
|
17628
17804
|
{ op: "tag", re: /\bgit\s+push\s+[^\n]*--tags\b|\bgit\s+tag\s+-a\b/i },
|
|
@@ -17648,14 +17824,18 @@ function classifyAuthorization(prompt) {
|
|
|
17648
17824
|
const { prose, fences } = splitFences(prompt);
|
|
17649
17825
|
const authorized = /* @__PURE__ */ new Set();
|
|
17650
17826
|
const evidence = {};
|
|
17651
|
-
|
|
17652
|
-
|
|
17827
|
+
const instruction = prose.split("\n").filter((l) => !OUTPUT_LINE.test(l)).join("\n");
|
|
17828
|
+
for (const { op, re } of isInterrogative(instruction) ? [] : PHRASES) {
|
|
17829
|
+
const m = re.exec(instruction);
|
|
17653
17830
|
if (m) {
|
|
17654
17831
|
authorized.add(op);
|
|
17655
17832
|
evidence[op] = `prose: "${m[0]}"`;
|
|
17656
17833
|
}
|
|
17657
17834
|
}
|
|
17658
17835
|
for (const fence of fences) {
|
|
17836
|
+
if (fence.split("\n").some((l) => OUTPUT_LINE.test(l))) {
|
|
17837
|
+
continue;
|
|
17838
|
+
}
|
|
17659
17839
|
for (const line of _commandLines(fence)) {
|
|
17660
17840
|
for (const { op, re } of PASTED_COMMANDS) {
|
|
17661
17841
|
if (re.test(line)) {
|
|
@@ -17747,7 +17927,7 @@ import fs35 from "node:fs";
|
|
|
17747
17927
|
import path35 from "node:path";
|
|
17748
17928
|
import { fileURLToPath as fileURLToPath27, pathToFileURL as pathToFileURL22 } from "node:url";
|
|
17749
17929
|
var EXIT_ALLOW7 = 0;
|
|
17750
|
-
var EXIT_BLOCK =
|
|
17930
|
+
var EXIT_BLOCK = 1;
|
|
17751
17931
|
function _isObject8(v) {
|
|
17752
17932
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
17753
17933
|
}
|
|
@@ -17763,15 +17943,22 @@ var WARN_OPS = /* @__PURE__ */ new Set([
|
|
|
17763
17943
|
"pr-create",
|
|
17764
17944
|
"branch"
|
|
17765
17945
|
]);
|
|
17946
|
+
var G = "(?:-[A-Za-z-]+(?:=\\S+)?(?:\\s+\\S+)?\\s+)*";
|
|
17766
17947
|
var COMMAND_OPS = [
|
|
17767
|
-
{ op: "publish", re:
|
|
17768
|
-
{ op: "release", re: /\bgh\s+release\s+create\b/i },
|
|
17769
|
-
{
|
|
17770
|
-
|
|
17771
|
-
|
|
17772
|
-
|
|
17773
|
-
|
|
17774
|
-
|
|
17948
|
+
{ op: "publish", re: new RegExp(`\\b(npm|pnpm|yarn)\\s+${G}publish\\b`, "i") },
|
|
17949
|
+
{ op: "release", re: /\bgh\s+release\s+create\b|\bgh\s+api\b[^\n]*\/releases\b/i },
|
|
17950
|
+
{
|
|
17951
|
+
op: "tag",
|
|
17952
|
+
re: new RegExp(
|
|
17953
|
+
`\\bgit\\s+${G}push\\b[^\\n;|&]*(--tags|--follow-tags|refs\\/tags\\/)`,
|
|
17954
|
+
"i"
|
|
17955
|
+
)
|
|
17956
|
+
},
|
|
17957
|
+
{ op: "pr-merge", re: /\bgh\s+pr\s+merge\b|\bgh\s+api\b[^\n]*\/pulls\/\d+\/merge\b/i },
|
|
17958
|
+
{ op: "pr-create", re: /\bgh\s+pr\s+create\b|\bgh\s+api\b[^\n]*-X\s+POST[^\n]*\/pulls\b/i },
|
|
17959
|
+
{ op: "push", re: new RegExp(`\\bgit\\s+${G}push\\b`, "i") },
|
|
17960
|
+
{ op: "commit", re: new RegExp(`\\bgit\\s+${G}commit\\b`, "i") },
|
|
17961
|
+
{ op: "branch", re: new RegExp(`\\bgit\\s+${G}(checkout\\s+-b|switch\\s+-c)\\b`, "i") }
|
|
17775
17962
|
];
|
|
17776
17963
|
var COMMAND_TOOLS3 = /* @__PURE__ */ new Set([
|
|
17777
17964
|
"launch-process",
|
|
@@ -17800,19 +17987,62 @@ function extractCommand(envelope) {
|
|
|
17800
17987
|
}
|
|
17801
17988
|
return null;
|
|
17802
17989
|
}
|
|
17990
|
+
function invokedSegments(command, depth = 0) {
|
|
17991
|
+
if (depth > 3) {
|
|
17992
|
+
return [];
|
|
17993
|
+
}
|
|
17994
|
+
const out = [];
|
|
17995
|
+
const withoutHeredocs = command.replace(
|
|
17996
|
+
/<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1[\s\S]*?^\s*\2\s*$/gm,
|
|
17997
|
+
"<<HEREDOC"
|
|
17998
|
+
);
|
|
17999
|
+
for (const raw of withoutHeredocs.split(/\n|;|&&|\|\||\||&/)) {
|
|
18000
|
+
let seg = raw.trim();
|
|
18001
|
+
if (!seg) {
|
|
18002
|
+
continue;
|
|
18003
|
+
}
|
|
18004
|
+
seg = seg.replace(/^(?:[A-Za-z_][A-Za-z0-9_]*=(?:"[^"]*"|'[^']*'|\S*)\s+)+/, "");
|
|
18005
|
+
const wrapped = /^(?:\S*\/)?(?:ba|z|k)?sh\s+-[a-z]*c\s+(?:"([^"]*)"|'([^']*)'|(\S+))/.exec(seg);
|
|
18006
|
+
if (wrapped) {
|
|
18007
|
+
out.push(...invokedSegments(wrapped[1] ?? wrapped[2] ?? wrapped[3] ?? "", depth + 1));
|
|
18008
|
+
continue;
|
|
18009
|
+
}
|
|
18010
|
+
out.push(seg);
|
|
18011
|
+
}
|
|
18012
|
+
return out;
|
|
18013
|
+
}
|
|
17803
18014
|
function commandOp(command) {
|
|
17804
|
-
|
|
17805
|
-
|
|
17806
|
-
|
|
18015
|
+
let found = null;
|
|
18016
|
+
for (const seg of invokedSegments(command)) {
|
|
18017
|
+
if (!/^(?:\S*\/)?(git|gh|npm|pnpm|yarn)\b/.test(seg)) {
|
|
18018
|
+
continue;
|
|
18019
|
+
}
|
|
18020
|
+
for (const { op, re } of COMMAND_OPS) {
|
|
18021
|
+
if (re.test(seg)) {
|
|
18022
|
+
if (BLOCK_OPS.has(op)) {
|
|
18023
|
+
return op;
|
|
18024
|
+
}
|
|
18025
|
+
found ??= op;
|
|
18026
|
+
break;
|
|
18027
|
+
}
|
|
17807
18028
|
}
|
|
17808
18029
|
}
|
|
17809
|
-
return
|
|
18030
|
+
return found;
|
|
17810
18031
|
}
|
|
17811
|
-
|
|
18032
|
+
var LEDGER_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
18033
|
+
function _loadLedger(consumer_root, session_id, now) {
|
|
17812
18034
|
try {
|
|
17813
18035
|
const raw = fs35.readFileSync(path35.join(consumer_root, STATE_FILE6), "utf8");
|
|
17814
18036
|
const decoded = JSON.parse(raw);
|
|
17815
18037
|
if (_isObject8(decoded) && Array.isArray(decoded["authorized"])) {
|
|
18038
|
+
const ledgerSession = typeof decoded["session_id"] === "string" ? decoded["session_id"] : "";
|
|
18039
|
+
if (session_id && ledgerSession && ledgerSession !== session_id) {
|
|
18040
|
+
return { authorized: /* @__PURE__ */ new Set(), present: false };
|
|
18041
|
+
}
|
|
18042
|
+
const at = Date.parse(String(decoded["detected_at"] ?? ""));
|
|
18043
|
+
if (Number.isFinite(at) && now - at > LEDGER_MAX_AGE_MS) {
|
|
18044
|
+
return { authorized: /* @__PURE__ */ new Set(), present: false };
|
|
18045
|
+
}
|
|
17816
18046
|
return {
|
|
17817
18047
|
authorized: new Set(decoded["authorized"].filter(Boolean)),
|
|
17818
18048
|
present: true
|
|
@@ -17859,7 +18089,11 @@ function run9(stdin_text, options) {
|
|
|
17859
18089
|
return EXIT_ALLOW7;
|
|
17860
18090
|
}
|
|
17861
18091
|
}
|
|
17862
|
-
const
|
|
18092
|
+
const session_id = typeof envelope["session_id"] === "string" ? envelope["session_id"] : "";
|
|
18093
|
+
const decision = decide(
|
|
18094
|
+
extractCommand(envelope),
|
|
18095
|
+
_loadLedger(options.consumer_root, session_id, Date.now())
|
|
18096
|
+
);
|
|
17863
18097
|
if (decision.stdout) {
|
|
17864
18098
|
process.stdout.write(decision.stdout);
|
|
17865
18099
|
}
|
|
@@ -17911,7 +18145,7 @@ import fs36 from "node:fs";
|
|
|
17911
18145
|
import path36 from "node:path";
|
|
17912
18146
|
import { fileURLToPath as fileURLToPath28, pathToFileURL as pathToFileURL23 } from "node:url";
|
|
17913
18147
|
var EXIT_ALLOW8 = 0;
|
|
17914
|
-
var EXIT_BLOCK2 =
|
|
18148
|
+
var EXIT_BLOCK2 = 1;
|
|
17915
18149
|
var STATE_FILE7 = path36.join("agents", "state", "evidence-dispatch.json");
|
|
17916
18150
|
function _isObject9(v) {
|
|
17917
18151
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -17926,8 +18160,18 @@ var DISPATCH_TOOLS = /* @__PURE__ */ new Set([
|
|
|
17926
18160
|
"run_subagent",
|
|
17927
18161
|
"Subagent"
|
|
17928
18162
|
]);
|
|
17929
|
-
var EVALUATION_RE = /\b(review|reviewer|audit|auditor|judge|verdict|blind[- ]pass|blind review|adversarial|critique|assess(ment)?|verify (my|the) (work|change|diff|implementation)|find (any )?(bugs|issues|defects|problems) in (my|the))\b/i;
|
|
18163
|
+
var EVALUATION_RE = /\b(review|reviewer|audit|auditor|judge|verdict|blind[- ]pass|blind review|adversarial|critique|assess(ment)?|verify (my|the) (work|change|diff|implementation)|find (any )?(bugs|issues|defects|problems) in (my|the)|pr(ü|ue)f(e|ung)?|begutachte|gutachten|bewerte|(gegen)?check(e)?|durchsicht|review(e|iere))\b/i;
|
|
17930
18164
|
var PRELOADED_VERDICT_RE = [
|
|
18165
|
+
// German — the operator writes German, and an English-only list meant no
|
|
18166
|
+
// German dispatch was ever screened at all.
|
|
18167
|
+
/\bich erwarte (hier )?(keine|nichts)\b/i,
|
|
18168
|
+
/\b(du )?(wirst|solltest) (hier )?nichts finden\b/i,
|
|
18169
|
+
/\bbest(ä|ae)tige (nur|kurz)\b/i,
|
|
18170
|
+
/\b(ist|sollte) (wahrscheinlich|vermutlich|sicher) (sauber|korrekt|in ordnung|fine)\b/i,
|
|
18171
|
+
/\bkeine findings? (erwartet|zu erwarten)\b/i,
|
|
18172
|
+
// English paraphrases of the audited construct.
|
|
18173
|
+
/\bi am confident there is nothing\b/i,
|
|
18174
|
+
/\ba clean pass is the likely\b/i,
|
|
17931
18175
|
/\bno[- ]findings? (is|are) (expected|welcome|fine|acceptable|the likely)/i,
|
|
17932
18176
|
/\b(you )?(should|will|probably) find (nothing|no (issues|problems|bugs|findings))/i,
|
|
17933
18177
|
/\bconfirm (that )?there (are|is) no\b/i,
|
|
@@ -17968,6 +18212,18 @@ function extractDispatch(envelope) {
|
|
|
17968
18212
|
}
|
|
17969
18213
|
return [tool, ""];
|
|
17970
18214
|
}
|
|
18215
|
+
function _ledgerStamp(consumer_root) {
|
|
18216
|
+
try {
|
|
18217
|
+
const raw = fs36.readFileSync(
|
|
18218
|
+
path36.join(consumer_root, "agents", "state", "git-authorization.json"),
|
|
18219
|
+
"utf8"
|
|
18220
|
+
);
|
|
18221
|
+
const d = JSON.parse(raw);
|
|
18222
|
+
return typeof d["detected_at"] === "string" ? d["detected_at"] : "";
|
|
18223
|
+
} catch {
|
|
18224
|
+
return "";
|
|
18225
|
+
}
|
|
18226
|
+
}
|
|
17971
18227
|
function _load(target) {
|
|
17972
18228
|
try {
|
|
17973
18229
|
const decoded = JSON.parse(fs36.readFileSync(target, "utf8"));
|
|
@@ -18028,7 +18284,7 @@ function run10(stdin_text, options) {
|
|
|
18028
18284
|
const target = path36.join(options.consumer_root, STATE_FILE7);
|
|
18029
18285
|
const state = _load(target);
|
|
18030
18286
|
const session_id = typeof envelope["session_id"] === "string" ? envelope["session_id"] : "";
|
|
18031
|
-
const turnMarker =
|
|
18287
|
+
const turnMarker = `${session_id}:${_ledgerStamp(options.consumer_root)}`;
|
|
18032
18288
|
if (state.session_id !== turnMarker) {
|
|
18033
18289
|
state.session_id = turnMarker;
|
|
18034
18290
|
state.turn_started_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -18335,7 +18591,7 @@ function _check_command(cmd) {
|
|
|
18335
18591
|
if (/\bgit\b/.test(cmd)) {
|
|
18336
18592
|
return [
|
|
18337
18593
|
true,
|
|
18338
|
-
"command parse failed (shlex) on a git-containing command \u2014 fail-closed (git-history-discipline)"
|
|
18594
|
+
"command parse failed (shlex) on a git-containing command \u2014 fail-closed (git-history-discipline). \nMost common cause: an apostrophe or backtick inside a heredoc commit message in the SAME compound command as `git`. \nFix: write the message to a file and use `git commit -F <file>` \u2014 do not retry the heredoc."
|
|
18339
18595
|
];
|
|
18340
18596
|
}
|
|
18341
18597
|
return [false, ""];
|
|
@@ -18728,7 +18984,7 @@ import { fileURLToPath as fileURLToPath31, pathToFileURL as pathToFileURL26 } fr
|
|
|
18728
18984
|
var _HERE5 = fileURLToPath31(import.meta.url);
|
|
18729
18985
|
var EXIT_ALLOW9 = 0;
|
|
18730
18986
|
var EXIT_BLOCK3 = 1;
|
|
18731
|
-
var
|
|
18987
|
+
var EXIT_WARN4 = 2;
|
|
18732
18988
|
var SESSION_ENTRY_CAP = 20;
|
|
18733
18989
|
var SESSION_WARN_AT = 5;
|
|
18734
18990
|
function _isObject11(v) {
|
|
@@ -18895,7 +19151,7 @@ function main29() {
|
|
|
18895
19151
|
if (d.action === "warn") {
|
|
18896
19152
|
process.stdout.write(`${JSON.stringify({ decision: "warn", reason: d.reason })}
|
|
18897
19153
|
`);
|
|
18898
|
-
return
|
|
19154
|
+
return EXIT_WARN4;
|
|
18899
19155
|
}
|
|
18900
19156
|
}
|
|
18901
19157
|
return EXIT_ALLOW9;
|
|
@@ -19037,7 +19293,7 @@ function detectRtkCached(options = {}) {
|
|
|
19037
19293
|
// src/scripts/hooks/rtk_wrap_hook.ts
|
|
19038
19294
|
var SETTINGS_FILE6 = ".agent-settings.yml";
|
|
19039
19295
|
var EXIT_ALLOW10 = 0;
|
|
19040
|
-
var
|
|
19296
|
+
var EXIT_WARN5 = 2;
|
|
19041
19297
|
var _RTK_PROGRAMS = /* @__PURE__ */ new Set([
|
|
19042
19298
|
"git",
|
|
19043
19299
|
"phpstan",
|
|
@@ -19180,7 +19436,7 @@ function main30() {
|
|
|
19180
19436
|
const reason = `rtk is installed and wraps verbose CLI output (upstream reports 60\u201390% fewer output tokens). Re-run wrapped: \`rtk ${command.trim()}\`. (Skip for completeness-critical output like \`git diff\`.)`;
|
|
19181
19437
|
process.stdout.write(`${_jsonReason(reason)}
|
|
19182
19438
|
`);
|
|
19183
|
-
return
|
|
19439
|
+
return EXIT_WARN5;
|
|
19184
19440
|
}
|
|
19185
19441
|
function _isCliEntry26() {
|
|
19186
19442
|
if (true) {
|
|
@@ -19797,7 +20053,7 @@ if (invokedDirectly) main31();
|
|
|
19797
20053
|
// src/scripts/hooks/design_slop_hook.ts
|
|
19798
20054
|
var SETTINGS_FILE7 = ".agent-settings.yml";
|
|
19799
20055
|
var EXIT_ALLOW11 = 0;
|
|
19800
|
-
var
|
|
20056
|
+
var EXIT_WARN6 = 2;
|
|
19801
20057
|
var DEGRADE_AFTER = 3;
|
|
19802
20058
|
var UI_EXT = /\.(html|htm|css|scss|sass|less|vue|svelte|astro|jsx|tsx)$/i;
|
|
19803
20059
|
function isObject(v) {
|
|
@@ -19833,7 +20089,12 @@ function enabled2(root) {
|
|
|
19833
20089
|
}
|
|
19834
20090
|
return false;
|
|
19835
20091
|
}
|
|
19836
|
-
function
|
|
20092
|
+
function _unwrap2(envelope) {
|
|
20093
|
+
const inner = envelope["payload"];
|
|
20094
|
+
return isObject(inner) ? inner : envelope;
|
|
20095
|
+
}
|
|
20096
|
+
function extract(outer) {
|
|
20097
|
+
const envelope = _unwrap2(outer);
|
|
19837
20098
|
const ti = envelope["tool_input"] ?? envelope["toolInput"] ?? envelope["input"];
|
|
19838
20099
|
if (!isObject(ti)) return null;
|
|
19839
20100
|
const fileVal = ti["file_path"] ?? ti["path"] ?? ti["filePath"];
|
|
@@ -19909,7 +20170,7 @@ function main32() {
|
|
|
19909
20170
|
const lines = surfaced.map((f) => `${f.catalogId} (${f.rule}) ${f.file}:${f.line} \u2014 ${f.message}`).join("; ");
|
|
19910
20171
|
const reason = "\u26A0\uFE0F Anti-slop: high-severity aesthetic tell(s) in the proposed UI \u2014 " + lines + ". Rebuttable: declare intent in DESIGN.md, add design-slop-disable-next-line, or proceed if deliberate (this is a flag, not a block).";
|
|
19911
20172
|
process.stdout.write(JSON.stringify({ decision: "warn", reason }) + "\n");
|
|
19912
|
-
return
|
|
20173
|
+
return EXIT_WARN6;
|
|
19913
20174
|
}
|
|
19914
20175
|
function _isCliEntry27() {
|
|
19915
20176
|
if (true) {
|
|
@@ -20071,7 +20332,7 @@ function pickSource(verdicts) {
|
|
|
20071
20332
|
// src/scripts/hooks/code_graph_nudge_hook.ts
|
|
20072
20333
|
var SETTINGS_FILE8 = ".agent-settings.yml";
|
|
20073
20334
|
var EXIT_ALLOW12 = 0;
|
|
20074
|
-
var
|
|
20335
|
+
var EXIT_WARN7 = 2;
|
|
20075
20336
|
var CODE_EXT = /\.(php|ts|tsx|mts|cts|js|jsx|mjs|cjs)$/i;
|
|
20076
20337
|
function isObject2(v) {
|
|
20077
20338
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -20186,7 +20447,7 @@ function main33() {
|
|
|
20186
20447
|
latch(root, session);
|
|
20187
20448
|
process.stdout.write(`${JSON.stringify({ decision: "warn", reason })}
|
|
20188
20449
|
`);
|
|
20189
|
-
return
|
|
20450
|
+
return EXIT_WARN7;
|
|
20190
20451
|
}
|
|
20191
20452
|
function isCliEntry10() {
|
|
20192
20453
|
if (true) {
|
|
@@ -20292,7 +20553,7 @@ var REPO_ROOT = path45.resolve(
|
|
|
20292
20553
|
var MANIFEST_PATH = path45.join(REPO_ROOT, "src", "scripts", "hook_manifest.yaml");
|
|
20293
20554
|
var EXIT_ALLOW13 = 0;
|
|
20294
20555
|
var EXIT_BLOCK4 = 1;
|
|
20295
|
-
var
|
|
20556
|
+
var EXIT_WARN8 = 2;
|
|
20296
20557
|
var EVENT_VOCABULARY = /* @__PURE__ */ new Set([
|
|
20297
20558
|
"session_start",
|
|
20298
20559
|
"session_end",
|
|
@@ -20306,7 +20567,7 @@ var EVENT_VOCABULARY = /* @__PURE__ */ new Set([
|
|
|
20306
20567
|
var _SEVERITY_BY_EXIT = {
|
|
20307
20568
|
[EXIT_ALLOW13]: "allow",
|
|
20308
20569
|
[EXIT_BLOCK4]: "block",
|
|
20309
|
-
[
|
|
20570
|
+
[EXIT_WARN8]: "warn"
|
|
20310
20571
|
};
|
|
20311
20572
|
function _isObject13(v) {
|
|
20312
20573
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -20345,6 +20606,31 @@ function _load_yaml3(p) {
|
|
|
20345
20606
|
const data = (0, import_yaml6.parse)(text, { version: "1.1" });
|
|
20346
20607
|
return _isObject13(data) ? data : {};
|
|
20347
20608
|
}
|
|
20609
|
+
function _payload_tool_name(envelope) {
|
|
20610
|
+
const payload = envelope["payload"];
|
|
20611
|
+
if (!_isObject13(payload)) {
|
|
20612
|
+
return "";
|
|
20613
|
+
}
|
|
20614
|
+
const raw = payload["tool_name"];
|
|
20615
|
+
return typeof raw === "string" ? raw : "";
|
|
20616
|
+
}
|
|
20617
|
+
function _concern_matches_tool(concern, tool_name) {
|
|
20618
|
+
const raw = concern["tools"];
|
|
20619
|
+
if (raw === void 0 || raw === null) {
|
|
20620
|
+
return true;
|
|
20621
|
+
}
|
|
20622
|
+
if (!Array.isArray(raw) || raw.length === 0) {
|
|
20623
|
+
return true;
|
|
20624
|
+
}
|
|
20625
|
+
const names = raw.filter((t) => typeof t === "string");
|
|
20626
|
+
if (names.length === 0 || names.includes("*")) {
|
|
20627
|
+
return true;
|
|
20628
|
+
}
|
|
20629
|
+
if (tool_name === "") {
|
|
20630
|
+
return true;
|
|
20631
|
+
}
|
|
20632
|
+
return names.includes(tool_name);
|
|
20633
|
+
}
|
|
20348
20634
|
function _resolve_concerns(manifest, platform, event) {
|
|
20349
20635
|
const platformsRaw = manifest["platforms"];
|
|
20350
20636
|
const platforms = _isObject13(platformsRaw) ? platformsRaw : {};
|
|
@@ -20679,8 +20965,8 @@ function _reduce(rcs) {
|
|
|
20679
20965
|
if (rcs.some((rc) => rc === EXIT_BLOCK4)) {
|
|
20680
20966
|
return EXIT_BLOCK4;
|
|
20681
20967
|
}
|
|
20682
|
-
if (rcs.some((rc) => rc ===
|
|
20683
|
-
return
|
|
20968
|
+
if (rcs.some((rc) => rc === EXIT_WARN8)) {
|
|
20969
|
+
return EXIT_WARN8;
|
|
20684
20970
|
}
|
|
20685
20971
|
return EXIT_ALLOW13;
|
|
20686
20972
|
}
|
|
@@ -20750,7 +21036,7 @@ function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
|
|
|
20750
21036
|
function _record_rule_trips(envelope, entries) {
|
|
20751
21037
|
if (is_replay_mode()) return;
|
|
20752
21038
|
const tripped = entries.filter(
|
|
20753
|
-
(e) => e["exit_code"] === EXIT_BLOCK4 || e["exit_code"] ===
|
|
21039
|
+
(e) => e["exit_code"] === EXIT_BLOCK4 || e["exit_code"] === EXIT_WARN8
|
|
20754
21040
|
);
|
|
20755
21041
|
if (tripped.length === 0) return;
|
|
20756
21042
|
try {
|
|
@@ -20771,7 +21057,7 @@ function _record_rule_trips(envelope, entries) {
|
|
|
20771
21057
|
const prev = concerns[name] ?? { block: 0, warn: 0 };
|
|
20772
21058
|
concerns[name] = {
|
|
20773
21059
|
block: (Number(prev["block"]) || 0) + (e["exit_code"] === EXIT_BLOCK4 ? 1 : 0),
|
|
20774
|
-
warn: (Number(prev["warn"]) || 0) + (e["exit_code"] ===
|
|
21060
|
+
warn: (Number(prev["warn"]) || 0) + (e["exit_code"] === EXIT_WARN8 ? 1 : 0),
|
|
20775
21061
|
last_trip: today
|
|
20776
21062
|
};
|
|
20777
21063
|
}
|
|
@@ -20917,7 +21203,11 @@ function main34(argv) {
|
|
|
20917
21203
|
const feedback_entries = [];
|
|
20918
21204
|
const context_blocks = [];
|
|
20919
21205
|
const concern_messages = [];
|
|
21206
|
+
const tool_name = _payload_tool_name(envelope);
|
|
20920
21207
|
for (const concern of concerns) {
|
|
21208
|
+
if (!_concern_matches_tool(concern, tool_name)) {
|
|
21209
|
+
continue;
|
|
21210
|
+
}
|
|
20921
21211
|
const concern_started = _now_iso3();
|
|
20922
21212
|
const { rc: rawRcResult, stderr: stderr_text, stdout: stdout_text, duration_ms } = _run_concern(concern, envelope);
|
|
20923
21213
|
let rc = rawRcResult;
|
|
@@ -20937,13 +21227,15 @@ function main34(argv) {
|
|
|
20937
21227
|
`dispatch_hook: concern '${String(concern["name"])}' is declared severity: advisory but returned BLOCK \u2014 downgraded to warn.
|
|
20938
21228
|
`
|
|
20939
21229
|
);
|
|
20940
|
-
rc =
|
|
21230
|
+
rc = EXIT_WARN8;
|
|
20941
21231
|
}
|
|
20942
21232
|
rcs.push(rc);
|
|
20943
21233
|
const reply = _parse_concern_stdout(stdout_text);
|
|
20944
21234
|
const stated = typeof reply["reason"] === "string" && reply["reason"].trim() ? reply["reason"].trim() : stderr_text.trim();
|
|
20945
|
-
|
|
20946
|
-
|
|
21235
|
+
const extra = typeof reply["additional_context"] === "string" && reply["additional_context"].trim() ? reply["additional_context"].trim() : "";
|
|
21236
|
+
const message = [stated, extra].filter(Boolean).join("\n\n");
|
|
21237
|
+
if (message) {
|
|
21238
|
+
concern_messages.push({ rc, text: message });
|
|
20947
21239
|
}
|
|
20948
21240
|
if (args.event === "session_start" && rc === EXIT_ALLOW13 && typeof reply["context"] === "string" && reply["context"].trim()) {
|
|
20949
21241
|
context_blocks.push(reply["context"].trim());
|