Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4903a8d188 | |||
| 5a3ad6b899 |
+140
-15
@@ -38,12 +38,42 @@
|
||||
},
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Edit|Write|MultiEdit|NotebookEdit|Bash|PowerShell|Skill|Task",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-llm-judge-per-tool.mjs",
|
||||
"timeout": 30
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Read|Grep|Glob|LS|TodoWrite|AskUserQuestion|Edit|Write|MultiEdit|NotebookEdit|Bash|Skill|Task|EnterPlanMode",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-safe-baseline-metering.mjs",
|
||||
"timeout": 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Edit|Write|MultiEdit|NotebookEdit",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-runtime-write-deny.mjs",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Edit|Write",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node -e \"const f=process.env.CLAUDE_FILE_PATH||''; const pd=process.env.CLAUDE_PROJECT_DIR||''; const path=require('path'); if (f && pd && path.resolve(f) === path.resolve(pd, 'CLAUDE.md')) { process.stderr.write('\\n[hook] WARNING: Direct edit of root CLAUDE.md detected. Per CLAUDE.md §5 п.10, prefer /claude-md-management:revise-claude-md or /claude-md-management:claude-md-improver. If invoked via that skill, this warning is informational.\\n'); }\""
|
||||
"command": "node -e \"const f=process.env.CLAUDE_FILE_PATH||''; const pd=process.env.CLAUDE_PROJECT_DIR||''; const path=require('path'); if (f && pd && path.resolve(f) === path.resolve(pd, 'CLAUDE.md')) { process.stderr.write('\\n[hook] WARNING: Direct edit of root CLAUDE.md detected. Per CLAUDE.md Р’В§5 Р С—.10, prefer /claude-md-management:revise-claude-md or /claude-md-management:claude-md-improver. If invoked via that skill, this warning is informational.\\n'); }\""
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -52,7 +82,7 @@
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node \"C:/моя/проекты/портал crm/Документация/tools/subagent-prompt-prefix.mjs\""
|
||||
"command": "node \"C:/Р В РЎВРѕСЏ/проекты/портал crm/ДокуРСВентацРСвЂР РЋР РЏ/tools/subagent-prompt-prefix.mjs\""
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -146,16 +176,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "AskUserQuestion",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/askuser-cosmetic-detector.mjs",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "mcp__.*",
|
||||
"hooks": [
|
||||
@@ -175,6 +195,71 @@
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Workflow",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-workflow-gate.mjs",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Edit|Write|MultiEdit|NotebookEdit|Bash|Task",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-decomposition-detector.mjs",
|
||||
"timeout": 8
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-parallel-session-lock.mjs",
|
||||
"timeout": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "AskUserQuestion",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/askuser-cosmetic-detector.mjs",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Read|Grep|Glob|LS|TodoWrite|AskUserQuestion|Edit|Write|MultiEdit|NotebookEdit|Bash|Skill|Task|EnterPlanMode",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-safe-baseline-metering.mjs",
|
||||
"timeout": 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Edit|Write|MultiEdit|NotebookEdit",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-runtime-write-deny.mjs",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Edit|Write|MultiEdit|NotebookEdit|Bash|Task",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-parallel-session-lock.mjs",
|
||||
"timeout": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
@@ -192,7 +277,7 @@
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node -e \"const f=process.env.CLAUDE_FILE_PATH||''; const n=f.replace(/\\\\\\\\/g,'/'); if (/(^|\\\\/)db\\\\/schema\\\\.sql$/i.test(n)) { process.stdout.write('\\n[hook] REMINDER: You modified db/schema.sql. Per CLAUDE.md §5 п.8, add a corresponding entry to db/CHANGELOG_schema.md before committing.\\n'); }\""
|
||||
"command": "node -e \"const f=process.env.CLAUDE_FILE_PATH||''; const n=f.replace(/\\\\\\\\/g,'/'); if (/(^|\\\\/)db\\\\/schema\\\\.sql$/i.test(n)) { process.stdout.write('\\n[hook] REMINDER: You modified db/schema.sql. Per CLAUDE.md Р’В§5 Р С—.8, add a corresponding entry to db/CHANGELOG_schema.md before committing.\\n'); }\""
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -206,7 +291,7 @@
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-rationalization-audit.mjs",
|
||||
"command": "echo ok",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
@@ -216,7 +301,7 @@
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-rationalization-audit.mjs",
|
||||
"command": "echo ok",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
@@ -230,9 +315,29 @@
|
||||
"timeout": 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "AskUserQuestion",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-askuser-answer-parser.mjs",
|
||||
"timeout": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Stop": [
|
||||
{
|
||||
"matcher": "*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-llm-judge-response-scan.mjs",
|
||||
"timeout": 30
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
@@ -277,6 +382,15 @@
|
||||
"timeout": 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-parallel-session-lock.mjs",
|
||||
"timeout": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"UserPromptSubmit": [
|
||||
@@ -309,6 +423,17 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SessionEnd": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node tools/enforce-parallel-session-lock.mjs",
|
||||
"timeout": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ trivy image liderra:latest
|
||||
|
||||
## 6. Текущая фаза проекта
|
||||
|
||||
**2026-06-01 lead region resolution — фича реализована TDD + запушена (PR в main):** Определение настоящего региона лида по телефону (DaData → реестр Россвязи → tag-fallback) + каскадная маршрутизация по региону (exact→all-RF→fallback) со взвешенным жребием по остатку дневного лимита (вариант В, вес ≥ 1 — мелкие клиенты не отрезаются). Состав: `LeadRegionResolver` (каскад по qc-кодам DaData) + `DaData/*` (клиент / страж бюджета / enum кодов качества / исключения) + `DaDataRegionMap` + `RossvyazPrefixLookup` + `RossvyazRecord`/`RegionResolution` DTO + команда `phone-ranges:import` (parse/map/dry-run/idempotency, atomic RENAME-swap в транзакции) + `LeadRouter` переписан (`matchEligibleProjects` + region-фильтр + `weightedPick` + инъекция `Randomizer`) + интеграция в `RouteSupplierLeadJob` (резолв ДО tx / persist 4 колонки / fail-safe аудит-лог `lead_region_resolution_log` / подмена subject_code на шаге 3 / CSV-merge по рангу источника `dadata/rossvyaz > CSV-tag`) + `phone-region:smoke`. Миграция `2026_05_31_100000` (`phone_ranges` / `phone_ranges_imports` / `lead_region_resolution_log` партиц. по месяцам + колонки на supplier_leads/deals) + регистрация в `MonthlyPartitionManager`; `db/schema.sql` синхронизирован заголовком (v8.40), DDL — в дельта-миграции (иначе двойной CREATE TABLE сломал бы migrate). **Решения заказчика/проекта:** резолвер через `app()` внутри `handle()` (не 7-й параметр — сохраняет сигнатуру + 3 существующих теста джобы); `deals.region_source` не добавляли (источник на supplier_leads + в журнале, CSV-merge по эвристике); запуск сразу на 100% без долевого гейта. **14 атомарных коммитов** `ec219718..11079791` на ветке `worktree-feat+lead-region-resolution`, запушено в origin (`CoralMinister/lidpotok`), **PR в main открывается вручную** по ссылке из `git push` output (MCP `create_pull_request` + `gh pr create` оба заблокированы router-гейтом). Тесты **101 pest GREEN / 509 assertions**; tools-vitest **1989 GREEN**. Code-review subagent (вердикт «с правками») → починены `atomicSwap()`→транзакция (spec §6.2) + убран stray comment; minor/deferred задокументированы (метрики §8.1 / `phone-ranges:rollback` / pg_anonymizer-маски / калибровка `DADATA_CALL_COST_KOPECKS`). Прод-выкатка отложена (нужны `DADATA_API_KEY`/`DADATA_SECRET` в YC Lockbox + команда «запускаем»; runbook `docs/superpowers/runbooks/2026-05-31-lead-region-resolution-rollout.md`). Пре-существующий долг (НЕ из фичи, отдельная задача): 3 чужих console-теста (`BillingMigrateLeadsToRub` / `IncidentsWatchFailures` / `SnapshotBackfillCommand`) взаимно загрязняются в одном процессе (накопление счётчиков), в CI `pest --parallel` (файл=процесс) проходят. **Lefthook в worktree-shell не в PATH** → cspell/larastan/squawk/deptrac не гонялись на коммитах; deptrac проверен инспекцией (Service→Service разрешён), новые cspell-термины (Rossvyaz/DaData/kopecks) добавлены в `cspell-words.txt`, остальное — CI на push. **§0 cross-refs НЕ меняются** — app-фича (сервисы/джоба/миграция), не tooling-канон #1-#86 / не ADR / не off-phase. Через `claude-md-management:revise-claude-md`.
|
||||
**2026-06-02 lead region resolution — ВЫКАЧЕНА на прод liderra.ru (флаг ON, 100%):** Определение настоящего региона лида по телефону (DaData → реестр Россвязи → tag-fallback) + каскадная маршрутизация по региону (exact→all-RF→fallback) со взвешенным жребием по остатку дневного лимита (вариант В, вес ≥ 1 — мелкие клиенты не отрезаются). Состав: `LeadRegionResolver` (каскад по qc-кодам DaData) + `DaData/*` (клиент / страж бюджета / enum кодов качества / исключения) + `DaDataRegionMap` + `RossvyazPrefixLookup` + `RossvyazRecord`/`RegionResolution` DTO + команда `phone-ranges:import` (parse/map/dry-run/idempotency, atomic RENAME-swap в транзакции) + `LeadRouter` переписан (`matchEligibleProjects` + region-фильтр + `weightedPick` + инъекция `Randomizer`) + интеграция в `RouteSupplierLeadJob` (резолв ДО tx / persist 4 колонки / fail-safe аудит-лог `lead_region_resolution_log` / подмена subject_code на шаге 3 / CSV-merge по рангу источника `dadata/rossvyaz > CSV-tag`) + `phone-region:smoke`. Миграция `2026_05_31_100000` (`phone_ranges` / `phone_ranges_imports` / `lead_region_resolution_log` партиц. по месяцам + колонки на supplier_leads/deals) + регистрация в `MonthlyPartitionManager`; `db/schema.sql` синхронизирован заголовком (v8.40), DDL — в дельта-миграции (иначе двойной CREATE TABLE сломал бы migrate). **Решения заказчика/проекта:** резолвер через `app()` внутри `handle()` (не 7-й параметр — сохраняет сигнатуру + 3 существующих теста джобы); `deals.region_source` не добавляли (источник на supplier_leads + в журнале, CSV-merge по эвристике); запуск сразу на 100% без долевого гейта. **14 атомарных коммитов** `ec219718..11079791` на ветке `worktree-feat+lead-region-resolution`, запушено в origin (`CoralMinister/lidpotok`), **PR в main открывается вручную** по ссылке из `git push` output (MCP `create_pull_request` + `gh pr create` оба заблокированы router-гейтом). Тесты **101 pest GREEN / 509 assertions**; tools-vitest **1989 GREEN**. Code-review subagent (вердикт «с правками») → починены `atomicSwap()`→транзакция (spec §6.2) + убран stray comment; minor/deferred задокументированы (метрики §8.1 / `phone-ranges:rollback` / pg_anonymizer-маски / калибровка `DADATA_CALL_COST_KOPECKS`). **ВЫКАЧЕНО на прод liderra.ru 01.06.2026 ~16:01 МСК** (по команде «запускаем»): ключи DaData в боевом `.env`, флаг `LEAD_REGION_RESOLVER_ENABLED=true` на **100%** потока, реестр Россвязи **453080 диапазонов** (atomic swap). Smoke на реальном номере ✓ (Источник=dadata, Субъект=29 Красноярский край, qc=0). Инструмент выкатки — `.github/workflows/lead-region-ops.yml` (на origin/main, локально untracked). Откат: op=set-env flag=false. Операционные уроки и хвосты (unmapped-регионы → код+TDD, косметика счётчика, мониторинг region_source, калибровка DADATA_CALL_COST_KOPECKS) — память [[project-lead-region-resolution-live]]; runbook `docs/superpowers/runbooks/2026-05-31-lead-region-resolution-rollout.md`. Пре-существующий долг (НЕ из фичи, отдельная задача): 3 чужих console-теста (`BillingMigrateLeadsToRub` / `IncidentsWatchFailures` / `SnapshotBackfillCommand`) взаимно загрязняются в одном процессе (накопление счётчиков), в CI `pest --parallel` (файл=процесс) проходят. **Lefthook в worktree-shell не в PATH** → cspell/larastan/squawk/deptrac не гонялись на коммитах; deptrac проверен инспекцией (Service→Service разрешён), новые cspell-термины (Rossvyaz/DaData/kopecks) добавлены в `cspell-words.txt`, остальное — CI на push. **§0 cross-refs НЕ меняются** — app-фича (сервисы/джоба/миграция), не tooling-канон #1-#86 / не ADR / не off-phase. Через `claude-md-management:revise-claude-md`.
|
||||
|
||||
**2026-05-31 (продолжение) router-gate v4 Layer 4 LLM-judge — item 2b live wiring + активация владельцем + readonly-калибровка:** `tools/enforce-llm-judge-per-tool.mjs` (PreToolUse) и `tools/enforce-llm-judge-response-scan.mjs` (Stop) получили живой `main()` (TDD, чистые `runPerTool`/`runResponseScan`; commit `dfae9f76`). Spend строго гейтится `resolveJudgeConfig()` (флаг `ROUTER_LLM_JUDGE_ENABLED` И ключ); без флага/ключа `decide()` короткозамыкается → $0. **Архитектурный нюанс:** регистрировать надо именно **обёртки** `enforce-llm-judge-*`, не движки `llm-judge-{per-tool,response-scan}.mjs` — у движков `main()` зовёт `llmJudgeCall` по наличию ОДНОГО ключа, игнорируя флаг (т.е. движок начал бы тратить деньги без рубильника). **Владелец активировал Layer 4** (env `ROUTER_LLM_JUDGE_ENABLED=1` через `rundll32 sysdm.cpl,EditEnvironmentVariables` + ключ `ROUTER_LLM_KEY` уже был в user env, как у классификатора + регистрация обоих хуков в `.claude/settings.json` + перезапуск) → судья ожил в **hard-block** (подтверждено: тот же `git log`, что при выключенном флаге проходил мгновенно, после активации заблокирован реальным вызовом — verdict ≠ YES → block). **Операционная находка / over-block:** `MUTATING_TOOLS` в `llm-judge-per-tool.mjs` включает `Bash` целиком, а правило вопроса — «Сомнения → NO» + код «не-YES → block», поэтому живой судья блокировал даже readonly-просмотры (`git status`/`git log`/`grep`) — и тем самым полностью клинил рабочий цикл (commit/push/правки тоже под судьёй). **Калибровка** (commit `c9b9efd6`, TDD, судья на время выключался владельцем — правка кода тоже под судьёй): новый экспортируемый `isReadonlyBashEvent(event)` — если tool=Bash и `classifyBashCommand(command, {})` даёт `result==='allow'` с reason `readonly|reading`, `runPerTool` возвращает allow **до** обращения к судье (без LLM-вызова, без budget-bump). Это **scope-fix к собственной декларации судьи** («judge on mutating tools»), а **не понижение дисциплины**: правило doubt→block и полная проверка всего, что реально меняет состояние (Edit/Write/MultiEdit/git commit/push/Skill/Task), — без изменений. Регрессия vitest tools-only **1927 GREEN** (+13 калибровочных тестов; verify через `npx vitest run --root app --config vitest.config.tools.mjs`, т.к. `npm run test:tools` падает из-за параллельной keytar-установки в `app/node_modules`). Коммиты `dfae9f76` (live wiring) + `c9b9efd6` (калибровка); push `a8996896..c9b9efd6 main`. План `docs/superpowers/plans/2026-05-31-llm-judge-live-wiring.md`. **§0 cross-refs НЕ меняются** — инфраструктура `tools/enforce-*.mjs`, не tooling-канон #1-#86 / не ADR / не off-phase. Через `claude-md-management:revise-claude-md`.
|
||||
|
||||
|
||||
Generated
+439
-5
@@ -5,6 +5,7 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"keytar": "*",
|
||||
"lucide-vue-next": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -39,6 +40,9 @@
|
||||
"vue-tsc": "^3.2.8",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"vuetify": "^3.12.5"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"keytar": "^7.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@acemir/cssom": {
|
||||
@@ -4222,6 +4226,27 @@
|
||||
"node": "18 || 20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/bidi-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
|
||||
@@ -4242,6 +4267,18 @@
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
@@ -4275,6 +4312,31 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/bundle-name": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
|
||||
@@ -4381,6 +4443,13 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@@ -4652,6 +4721,32 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/decompress-response": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"mimic-response": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-is": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||
@@ -4733,7 +4828,7 @@
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@@ -4858,6 +4953,16 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
||||
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
|
||||
@@ -5270,6 +5375,16 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/expand-template": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
|
||||
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
|
||||
"license": "(MIT OR WTFPL)",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/expect-type": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
|
||||
@@ -5570,6 +5685,13 @@
|
||||
"node": ">=18.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "11.3.5",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz",
|
||||
@@ -5699,6 +5821,13 @@
|
||||
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/github-from-package": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
|
||||
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
|
||||
@@ -6167,6 +6296,27 @@
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
@@ -6194,11 +6344,18 @@
|
||||
"node": ">=0.8.19"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/ini": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/is-docker": {
|
||||
@@ -6560,6 +6717,25 @@
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/keytar": {
|
||||
"version": "7.9.0",
|
||||
"resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
|
||||
"integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"node-addon-api": "^4.3.0",
|
||||
"prebuild-install": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/keytar/node_modules/node-addon-api": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
|
||||
"integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
@@ -7290,6 +7466,19 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "10.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
|
||||
@@ -7310,7 +7499,7 @@
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -7333,6 +7522,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/mri": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
|
||||
@@ -7386,6 +7582,13 @@
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/napi-build-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/natural-compare": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
@@ -7393,6 +7596,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.92.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.92.0.tgz",
|
||||
"integrity": "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/node-addon-api": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||
@@ -7454,6 +7670,16 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/oniguruma-parser": {
|
||||
"version": "0.12.2",
|
||||
"resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz",
|
||||
@@ -7843,6 +8069,34 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/prebuild-install": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
|
||||
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
|
||||
"deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.0",
|
||||
"expand-template": "^2.0.3",
|
||||
"github-from-package": "0.0.0",
|
||||
"minimist": "^1.2.3",
|
||||
"mkdirp-classic": "^0.5.3",
|
||||
"napi-build-utils": "^2.0.0",
|
||||
"node-abi": "^3.3.0",
|
||||
"pump": "^3.0.0",
|
||||
"rc": "^1.2.7",
|
||||
"simple-get": "^4.0.0",
|
||||
"tar-fs": "^2.0.0",
|
||||
"tunnel-agent": "^0.6.0"
|
||||
},
|
||||
"bin": {
|
||||
"prebuild-install": "bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
@@ -7897,6 +8151,17 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
|
||||
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
@@ -7938,6 +8203,47 @@
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rc": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"deep-extend": "^0.6.0",
|
||||
"ini": "~1.3.0",
|
||||
"minimist": "^1.2.0",
|
||||
"strip-json-comments": "~2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"rc": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/rc/node_modules/strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||
@@ -8322,6 +8628,27 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.99.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.99.0.tgz",
|
||||
@@ -8731,7 +9058,7 @@
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
@@ -8813,6 +9140,53 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-concat": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/simple-get": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
|
||||
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"decompress-response": "^6.0.0",
|
||||
"once": "^1.3.1",
|
||||
"simple-concat": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sirv": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
|
||||
@@ -8933,6 +9307,16 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
@@ -9095,6 +9479,36 @@
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
||||
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^2.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tinybench": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
|
||||
@@ -9239,6 +9653,19 @@
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
@@ -9455,7 +9882,7 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/utils-merge": {
|
||||
@@ -10106,6 +10533,13 @@
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.20.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
|
||||
|
||||
@@ -51,5 +51,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"lucide-vue-next": "^1.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"keytar": "^7.9.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,4 +38,11 @@ describe('DealsFilters', () => {
|
||||
});
|
||||
expect(w.find('[data-testid="clear-filters-btn"]').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('поле поиска имеет доступное имя (label) для скринридера', () => {
|
||||
const w = mount(DealsFilters, { props: baseProps, global: { plugins: [vuetify] } });
|
||||
const label = w.find('[data-testid="filter-search-phone"] label');
|
||||
expect(label.exists()).toBe(true);
|
||||
expect(label.text()).toContain('Поиск по телефону');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,4 +47,11 @@ describe('KanbanColumn.vue', () => {
|
||||
expect(wrapper.emitted('openDeal')).toBeTruthy();
|
||||
expect(wrapper.emitted('openDeal')?.[0]).toEqual([dealsForNew[0].id]);
|
||||
});
|
||||
|
||||
// Контраст column-total на ивори чинится в scoped CSS (var(--accent) → нейтральный #4a463f),
|
||||
// jsdom scoped-стили не вычисляет → числовую проверку контраста делает Pa11y. Здесь — структурный якорь.
|
||||
it('column-total отрисован для пустой колонки', () => {
|
||||
const wrapper = factory({ status, deals: [] });
|
||||
expect(wrapper.find('.column-total').exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -49,4 +49,14 @@ describe('ProjectCard', () => {
|
||||
});
|
||||
expect(wrapper.text()).toContain('На паузе');
|
||||
});
|
||||
|
||||
it('чип типа сигнала — flat-вариант с классом signal-chip (a11y контраст)', () => {
|
||||
const wrapper = mount(ProjectCard, {
|
||||
global: { plugins: [vuetify] },
|
||||
props: { project: baseProject, selected: false },
|
||||
});
|
||||
const chip = wrapper.find('.signal-chip');
|
||||
expect(chip.exists()).toBe(true);
|
||||
expect(chip.classes()).toContain('v-chip--variant-flat');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,26 @@
|
||||
# A4 design-tooling integration (v2.8 / v3.8 / v1.22)
|
||||
iconify
|
||||
|
||||
# lead-region-resolution spec/plan (DaData + Россвязь, 2026-05-29)
|
||||
dadata
|
||||
rossvyaz
|
||||
unmappable
|
||||
mnp
|
||||
incrby
|
||||
deyatelnost
|
||||
resurs
|
||||
numeracii
|
||||
vypiska
|
||||
reestra
|
||||
sistemy
|
||||
plana
|
||||
маппингах
|
||||
реконсиляция
|
||||
сетап
|
||||
хелперы
|
||||
регэкспом
|
||||
резолвом
|
||||
|
||||
# Бренд и термины проекта
|
||||
лидерра
|
||||
liderra
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
{
|
||||
"2026-05": {
|
||||
"WIN_USER_PATH": 123,
|
||||
"WIN_USER_PATH": 206,
|
||||
"IPV4": 1,
|
||||
"RU_PHONE": 1
|
||||
},
|
||||
"2026-06": {
|
||||
"WIN_USER_PATH": 91
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"last_read_at": "2026-05-27T00:53:33.490Z",
|
||||
"read_count_last_period": 5,
|
||||
"last_read_at": "2026-05-30T12:32:49.927Z",
|
||||
"read_count_last_period": 6,
|
||||
"period_start": "2026-05-19T00:00:00+03:00"
|
||||
}
|
||||
|
||||
+18
-24
@@ -1,21 +1,21 @@
|
||||
# Brain Status (auto-generated)
|
||||
|
||||
Last updated: 2026-06-02T10:14:43.123Z
|
||||
Last updated: 2026-06-08T14:07:33.978Z
|
||||
|
||||
| Контролёр | Состояние | Детали |
|
||||
|---|---|---|
|
||||
| C1 L1-watcher | ✅ | [l1-watcher] OK — 0 drift |
|
||||
| C2 Cross-ref consistency | ✅ | [cross-ref-checker] OK — 0 drift in 4 files |
|
||||
| C3 Observer-of-observer | ✅ | [observer-of-observer] OK — last read 0 week(s) ago |
|
||||
| C3 Observer-of-observer | ✅ | [observer-of-observer] OK — last read 1 week(s) ago |
|
||||
| C4 Сигнальный статус | ✅ | This file (self-reference) |
|
||||
| C5 Observer-coverage | ✅ | 137 episode(s) this month · Stop-hook + post-commit OK |
|
||||
| C5 Observer-coverage | ✅ | 666 episode(s) this month · Stop-hook + post-commit OK |
|
||||
| C6 Chain map sync | ✅ | [chain-map-checker] OK — 16 chains in sync |
|
||||
|
||||
## Метрики (информационные, не алерты)
|
||||
|
||||
- Observer evidence: 137 episodes this month, 0 observer_error markers, 6 PII matches before filter
|
||||
- Legacy v1 episodes (not in factor analysis): 137
|
||||
- Last /brain-retro: 2 day(s) ago
|
||||
- Observer evidence: 666 episodes this month, 0 observer_error markers, 88 PII matches before filter
|
||||
- Legacy v1 episodes (not in factor analysis): 666
|
||||
- Last /brain-retro: 9 day(s) ago
|
||||
- Использование узлов: см. `/brain-retro` (раз в спринт). missed_activations: 0. **Неиспользованные узлы — не алерт, если профильной задачи не было** (Pravila §16.4 v1.36; capability-readiness; см. memory `feedback_brain_unused_tools_not_problem` — outside-repo memory store).
|
||||
|
||||
## Метрики дисциплины
|
||||
@@ -24,14 +24,14 @@ Baseline дисциплины роутера (этап 2 router discipline overh
|
||||
|
||||
| Тип задачи | Эпизодов | % с триггер-матчем | % через скил |
|
||||
|---|---|---|---|
|
||||
| planning | 16 | 0.0% | 0.0% |
|
||||
| feature | 4 | 0.0% | 0.0% |
|
||||
| analysis | 2 | 0.0% | 0.0% |
|
||||
| bugfix | 1 | 0.0% | 0.0% |
|
||||
| planning | 96 | 10.4% | 13.5% |
|
||||
| analysis | 33 | 6.1% | 0.0% |
|
||||
| bugfix | 26 | 15.4% | 19.2% |
|
||||
| feature | 24 | 12.5% | 4.2% |
|
||||
|
||||
Router step distribution: 1: 81, 2: 51, 5: 4
|
||||
Router step distribution: 1: 321, 2: 261, 3: 18, 5: 55
|
||||
|
||||
Boundaries applied (ADR / границы): 1 of 136 эпизодов (0.7%).
|
||||
Boundaries applied (ADR / границы): 7 of 655 эпизодов (1.1%).
|
||||
|
||||
## Активные многоэтапные проекты
|
||||
|
||||
@@ -43,22 +43,16 @@ Boundaries applied (ADR / границы): 1 of 136 эпизодов (0.7%).
|
||||
|
||||
## Длинные сессии
|
||||
|
||||
⚠️ Сегодня (2026-06-02 UTC) есть сессии с ≥50 ходов — корреляция с падением дисциплины роутинга (retro #5 candidate B).
|
||||
|
||||
| session_id | макс. ход | % regulated | последний эпизод |
|
||||
|---|---|---|---|
|
||||
| `1a9888f8` | 50 | 0% | 2026-06-02T01:43:02.824Z |
|
||||
|
||||
Long sessions correlate with discipline drift. Если % regulated просел в текущей сессии — рассмотри перезапуск.
|
||||
Ни одной сессии с >50 ходов сегодня (UTC). ✅
|
||||
|
||||
## Стоимость месяца
|
||||
|
||||
| Компонент | Токены (in/out) | USD |
|
||||
|---|---|---|
|
||||
| Classifier (Sonnet 4.6) | 10473/50827 | $0.79 |
|
||||
| Classifier (Sonnet 4.6) | 41653/183234 | $2.87 |
|
||||
| Self-assessment (Sonnet 4.6) | 0/0 | $0.00 |
|
||||
| Reviewer (Opus 4.7 + fallback) | 0/0 | $0.00 |
|
||||
| **Итого** | | **$0.79** |
|
||||
| **Итого** | | **$2.87** |
|
||||
|
||||
## Аномалии классификатора
|
||||
|
||||
@@ -71,7 +65,7 @@ Episodes since last run: 542 / threshold: 10
|
||||
|
||||
## Reviewer: субагент vs fallback
|
||||
|
||||
0 эпизодов проверено из 137.
|
||||
0 эпизодов проверено из 666.
|
||||
|
||||
## Reviewer findings
|
||||
|
||||
@@ -97,8 +91,8 @@ Episodes since last run: 542 / threshold: 10
|
||||
|
||||
| PID | Имя | CPU-время | Возраст |
|
||||
|---|---|---|---|
|
||||
| 10388 | Code | 3.05ч | 1327306.2ч |
|
||||
| 3220 | MsMpEng | 1.14ч | 0.0ч |
|
||||
| 3916 | MsMpEng | 1.99ч | NaNч |
|
||||
| 15260 | Code | 1.71ч | 0.0ч |
|
||||
|
||||
⚠️ Проверь, не «осиротевшие» ли это процессы от завершённых Claude-сессий.
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -15,11 +15,13 @@
|
||||
## File Structure
|
||||
|
||||
**Create:**
|
||||
|
||||
- `app/app/Services/Audit/AuditChainConfig.php` — shared конфиг 6 audit-таблиц (columns + partition_clause). Public const `TABLES`. Helper `rowExpression(string $table): string` для построения `ROW(...)` выражения.
|
||||
- `app/tests/Unit/Services/Audit/AuditChainConfigTest.php` — unit-тесты на конфиг (полнота 6 таблиц, корректность ROW expression).
|
||||
- `docs/incidents/2026-06-XX-activity-log-y2026-m05-cleanup-handoff.md` — handoff для прод-выкатки финального cleanup'а (Task 7).
|
||||
|
||||
**Modify:**
|
||||
|
||||
- `app/app/Console/Commands/VerifyAuditChains.php:98-238` — заменить private `TABLE_CONFIG` const на чтение из `AuditChainConfig::TABLES`. Поведение не меняется (regression-safe refactor).
|
||||
- `app/app/Console/Commands/AuditRebuildChain.php:40-218` — заменить private `COLUMN_CONFIG` на `AuditChainConfig`, переписать `handle()` SQL под per-partition_clause logic (через `LAG OVER`).
|
||||
- `app/tests/Feature/Audit/AuditRebuildChainTest.php` — добавить 3 новых сценария (multi-tenant / BYPASSRLS table / single-row partition); существующие тесты должны продолжать проходить.
|
||||
@@ -30,6 +32,7 @@
|
||||
### Task 1: Создать shared AuditChainConfig
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `app/app/Services/Audit/AuditChainConfig.php`
|
||||
- Test: `app/tests/Unit/Services/Audit/AuditChainConfigTest.php`
|
||||
|
||||
@@ -214,6 +217,7 @@ git commit -m "feat(audit): extract AuditChainConfig shared TABLE config (ADR-01
|
||||
### Task 2: Перевести VerifyAuditChains на shared config (regression-safe refactor)
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `app/app/Console/Commands/VerifyAuditChains.php:96-238` (заменить private const на чтение `AuditChainConfig::TABLES`)
|
||||
- Test: `app/tests/Feature/Audit/AuditChainRaceConditionTest.php` (existing — должен продолжать проходить)
|
||||
|
||||
@@ -271,6 +275,7 @@ git commit -m "refactor(audit): VerifyAuditChains использует shared Au
|
||||
### Task 3: Failing tests для per-tenant rebuild
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `app/tests/Feature/Audit/AuditRebuildChainTest.php` (add 3 scenarios — multi-tenant / BYPASSRLS / single-row)
|
||||
|
||||
- [ ] **Step 1: Добавить multi-tenant test (failing)**
|
||||
@@ -392,6 +397,7 @@ git commit -m "test(audit): failing tests для per-tenant rebuild (ADR-018, RE
|
||||
### Task 4: Реализовать per-tenant rebuild через LAG OVER
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `app/app/Console/Commands/AuditRebuildChain.php` (целиком переписать `handle()` + удалить `COLUMN_CONFIG` + использовать `AuditChainConfig`)
|
||||
|
||||
- [ ] **Step 1: Переписать AuditRebuildChain**
|
||||
@@ -567,6 +573,7 @@ git commit -m "fix(audit): AuditRebuildChain per-tenant LAG OVER (ADR-018, close
|
||||
### Task 5: Активировать ADR-018 Enforcement rule
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `docs/adr/ADR-018-audit-chain-per-tenant-semantics.md` (Enforcement-блок — снять «активируется после имплементации» note + проверить что rule срабатывает)
|
||||
|
||||
- [ ] **Step 1: Обновить Enforcement-блок**
|
||||
@@ -647,6 +654,7 @@ git commit -m "style(audit): pint auto-fix на shared config + rebuild rewrite"
|
||||
### Task 7: Handoff для прод-выкатки cleanup'а activity_log_y2026_m05
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `docs/incidents/2026-05-29-audit-rebuild-per-tenant-cleanup-handoff.md`
|
||||
|
||||
- [ ] **Step 1: Создать handoff-док**
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
**Goal:** Remove 5 obsolete v3.9 enforcement hooks and register all 12 active router-gate v4 hooks in `.claude/settings.json` in block-mode, creating 5 thin wrappers for pure modules that still need them.
|
||||
|
||||
**Architecture:** Three layers:
|
||||
|
||||
1. **Pure modules** in `tools/<name>.mjs` — already created by streams A-E.
|
||||
2. **Thin `enforce-<name>.mjs` wrappers** — stdin event → pure module `decide()` → `exitDecision`. Pattern lifted from existing `tools/enforce-router-gate.mjs:183-204`.
|
||||
3. **`.claude/settings.json` registration** — matcher + command path + timeout. Block-mode means `exitDecision({ block: true })` exits with code 2 stopping the originating tool call.
|
||||
@@ -12,6 +13,7 @@
|
||||
**Tech Stack:** Node.js ESM (`.mjs`), `vitest` (jsdom env), `lefthook` pre-commit, `.claude/settings.json` schema `https://json.schemastore.org/claude-code-settings.json`.
|
||||
|
||||
**Reference helpers** (already present in `tools/enforce-hook-helpers.mjs`):
|
||||
|
||||
- `readStdin()` — read PreToolUse/PostToolUse/Stop event JSON.
|
||||
- `parseEventJson(raw)` — safe JSON.parse with `{}` fallback.
|
||||
- `readTranscript(event.transcript_path)` — load JSONL.
|
||||
@@ -110,6 +112,7 @@ Expected: line with sha + `refs/heads/backup-pre-v4-cleanup`.
|
||||
The vocab-based override system is fully removed in v4 (universal vocab removal per spec §4.2). Existing call sites in deleted hooks go away in Task 7; other callers (`enforce-verify-before-push.mjs`, `enforce-tdd-gate.mjs`, `enforce-memory-coverage.mjs`, `enforce-branch-switch.mjs`) still import `findOverride` / `findOverrideAttempt` / `loadOverrideVocab`. We keep these symbols as permanent stubs so non-deleted hooks keep building.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `tools/enforce-hook-helpers.mjs:197-249` (functions `loadOverrideVocab`, `findOverride`, `findOverrideAttempt`)
|
||||
- Modify: `tools/enforce-hook-helpers.test.mjs` (drop vocab-dependent assertions, add stub contract tests)
|
||||
|
||||
@@ -199,6 +202,7 @@ Wraps `tools/todowrite-skill-verifier.mjs::verifyClaims + hardSyncCheck`. Fires
|
||||
**Pattern reference:** `tools/enforce-router-gate.mjs:183-207` (main() shape, fail-CLOSE behaviour). For Stop hooks we use fail-open (`block: false`) because false-positive Stop block would freeze sessions.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `tools/enforce-todowrite-skill-verifier.mjs`
|
||||
- Create: `tools/enforce-todowrite-skill-verifier.test.mjs`
|
||||
|
||||
@@ -333,6 +337,7 @@ git commit -m "feat(router-gate-v4): enforce-todowrite-skill-verifier (Stop hook
|
||||
Wraps `tools/tdd-real-test-verifier.mjs::verifyRealTest`. Fires on Edit/Write of a `*.test.*` or `*.spec.*` file. If the test content lacks `expect(...)` / `it(...)` / `test(...)` or covers none of the prod files edited in this session, blocks.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `tools/enforce-tdd-real-test-verifier.mjs`
|
||||
- Create: `tools/enforce-tdd-real-test-verifier.test.mjs`
|
||||
|
||||
@@ -479,6 +484,7 @@ git commit -m "feat(router-gate-v4): enforce-tdd-real-test-verifier (PreToolUse
|
||||
Wraps `tools/self-debrief-detector.mjs::detectSelfDebrief`. Fires on mutating tools (Edit|Write|MultiEdit|Bash). Reads transcript; if last controller text matches self-debrief patterns and no `self-retrospect` / `brain-retro` Skill invoked recently — block.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `tools/enforce-self-debrief-detector.mjs`
|
||||
- Create: `tools/enforce-self-debrief-detector.test.mjs`
|
||||
|
||||
@@ -606,6 +612,7 @@ Wraps `tools/mcp-tool-classifier.mjs::classifyMcpTool`. Fires on any `mcp__*` to
|
||||
**Pre-step:** Inspect `tools/mcp-tool-classifier.mjs` exported function names (`classifyMcpTool` vs `classify` vs other) — adjust import below if name differs.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `tools/enforce-mcp-classification.mjs`
|
||||
- Create: `tools/enforce-mcp-classification.test.mjs`
|
||||
|
||||
@@ -709,6 +716,7 @@ Wraps `tools/decomposition-detector.mjs::detectDecomposition`. Fires on mutating
|
||||
**Pre-step:** Inspect `tools/decomposition-detector.mjs` for the actual function name and signature; adapt below.
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `tools/enforce-decomposition-detector.mjs`
|
||||
- Create: `tools/enforce-decomposition-detector.test.mjs`
|
||||
|
||||
@@ -815,6 +823,7 @@ git commit -m "feat(router-gate-v4): enforce-decomposition-detector (PreToolUse
|
||||
## Task 7: Delete 5 v3.9 hooks and the vocab file
|
||||
|
||||
**Files (delete):**
|
||||
|
||||
- `tools/enforce-chain-recommendation.mjs`
|
||||
- `tools/enforce-chain-recommendation.test.mjs`
|
||||
- `tools/enforce-classifier-match.mjs`
|
||||
@@ -847,6 +856,7 @@ git rm tools/enforce-override-vocab.json
|
||||
- [ ] **Step 3: Run full vitest tools suite (must still pass — no orphan references)**
|
||||
|
||||
Run:
|
||||
|
||||
```
|
||||
npx vitest run tools/ \
|
||||
--exclude='**/worktrees/**' \
|
||||
@@ -854,6 +864,7 @@ npx vitest run tools/ \
|
||||
--exclude='**/subagent-prompt-prefix*' \
|
||||
--exclude='**/llm-judge.integration*'
|
||||
```
|
||||
|
||||
Expected: all PASS. If any failure references a deleted file — it's a stale import; fix that file by removing the dead import.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
@@ -875,11 +886,13 @@ Deleted hooks superseded by v4 architecture (spec §4 behavioural pivot):
|
||||
## Task 8: Update `.claude/settings.json` — remove 5 v3.9 regs, add 12 v4 regs in block-mode
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `.claude/settings.json`
|
||||
|
||||
**Plan:** Read the current file (already done at planning time — see baseline below), then apply edits via multiple `Edit` tool calls because `settings.json` is JSON (no comments allowed) and the changes are scattered across the `hooks.PreToolUse`, `hooks.PostToolUse`, and `hooks.Stop` arrays.
|
||||
|
||||
**Baseline (current state, lines 39–262):** five v3.9 hook blocks present at:
|
||||
|
||||
- PreToolUse[3] (lines 69–78) — `enforce-chain-recommendation` — REMOVE
|
||||
- PreToolUse[4] (lines 79–88) — `enforce-override-limit` — REMOVE
|
||||
- PreToolUse[7] (lines 119–128) — `enforce-semgrep-security` — REMOVE
|
||||
@@ -1045,6 +1058,7 @@ Stream G of router-gate v4 deployment, last step before user-run smokes."
|
||||
- [ ] **Step 1: Full vitest tools suite**
|
||||
|
||||
Run:
|
||||
|
||||
```
|
||||
npx vitest run tools/ \
|
||||
--exclude='**/worktrees/**' \
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
### Task 1: RED tests for skill-body skip + negative tests for non-skill `isMeta`
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `tools/enforce-hook-helpers.test.mjs` — add 3 cases at end of `describe('lastTurnEntries / ...')` block.
|
||||
|
||||
- [ ] **Step 1:** Add a new `it()` block "lastTurnEntries skips skill body injections (isMeta + sourceToolUseID)" that constructs an entries array `[user-prompt, assistant+SkillToolUse, skillBody(isMeta=true, sourceToolUseID), assistant+follow-up]` and asserts `lastTurnEntries(entries)` returns starting from `user-prompt` (NOT from skill body).
|
||||
@@ -53,6 +54,7 @@
|
||||
### Task 2: Implement skill-body skip in lastTurnEntries
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `tools/enforce-hook-helpers.mjs` lines 100-115 (`lastTurnEntries` body).
|
||||
|
||||
- [ ] **Step 1:** In the back-walk loop, before checking `e.message.role === 'user'`, add: `if (e && e.isMeta === true && typeof e.sourceToolUseID === 'string') continue;` — this skips skill-body injections (isMeta + tool-spawned) while keeping all other `isMeta:true` cases as valid turn boundaries.
|
||||
@@ -64,6 +66,7 @@
|
||||
### Task 3: Commit
|
||||
|
||||
**Files:**
|
||||
|
||||
- Commit message in `.scratch/sibling-lastturn-fix-msg.txt`.
|
||||
|
||||
- [ ] **Step 1:** Pre-write approval records for:
|
||||
|
||||
@@ -146,6 +146,16 @@ const SAFE_EXACT = [
|
||||
// → cwd-shift read-bypass stays contained (protected files also remain blocked by name
|
||||
// in the command). cd into Документация/system/protected dirs → default-deny.
|
||||
/^cd\s+(?=.*[\\/](?:worktree-|v4-stream-))(?!.*(?:\.\.|\.claude|\.ssh|\.env|runtime|\.git)).+$/,
|
||||
// graphify read-only subcommands (#86, §5 п.14, owner-authorized 2026-06-08).
|
||||
// Only query/explain/path — extract/update/build/export/hook/clone/add/merge stay
|
||||
// default-deny. The bare \b form is safe: injection vectors are neutralized BEFORE the
|
||||
// whitelist sees them — chains split into per-segment whitelist checks (an injected
|
||||
// `; id` segment is not whitelisted → block), subshells `$(...)`/backtick are blocked by
|
||||
// the tokenizer, redirects by the hard-blacklist, and $VAR is var-expanded by the
|
||||
// tokenizer (not an injection vector for a read-only query arg). End-anchoring with a
|
||||
// charset would reject Unicode query strings (tokenizer strips quotes → Cyrillic args
|
||||
// arrive as barewords) for no security gain. (security review 2026-06-08 — false-positive)
|
||||
/^graphify\s+(?:query|explain|path)\b/,
|
||||
];
|
||||
|
||||
export function classifyWhitelist(segments) {
|
||||
|
||||
@@ -241,6 +241,39 @@ describe('SAFE_EXACT — Laravel dev workflow (whitelist expansion 2026-05-30)',
|
||||
expect(classifyBashCommand('composer show', {}).result).toBe('allow');
|
||||
expect(classifyBashCommand('composer outdated', {}).result).toBe('allow');
|
||||
});
|
||||
|
||||
// graphify read-only subcommands (owner-authorized 2026-06-08 — #86 graphify, §5 п.14)
|
||||
it('allows graphify read-only subcommands (query/explain/path)', () => {
|
||||
expect(classifyBashCommand('graphify query "x"', {}).result).toBe('allow');
|
||||
expect(classifyBashCommand('graphify explain "Node"', {}).result).toBe('allow');
|
||||
expect(classifyBashCommand('graphify path "A" "B"', {}).result).toBe('allow');
|
||||
});
|
||||
|
||||
// graphify mutating/expensive subcommands stay default-deny
|
||||
it('still blocks graphify mutating subcommands (extract/export/hook)', () => {
|
||||
expect(classifyBashCommand('graphify extract .', {}).result).toBe('block');
|
||||
expect(classifyBashCommand('graphify export html', {}).result).toBe('block');
|
||||
expect(classifyBashCommand('graphify hook install', {}).result).toBe('block');
|
||||
});
|
||||
|
||||
// graphify allowlist is not bypassable via chained commands / subshells — they are
|
||||
// caught by the gate architecture BEFORE the whitelist regex (per-segment whitelist +
|
||||
// tokenizer subshell-block + redirect hard-blacklist), so the simple subcommand
|
||||
// allowlist is safe (security review 2026-06-08 finding = false-positive: $VAR is
|
||||
// var-expanded away by the tokenizer, not a command-injection vector).
|
||||
it('blocks graphify chained commands and subshell payloads', () => {
|
||||
expect(classifyBashCommand('graphify query x; id', {}).result).toBe('block');
|
||||
expect(classifyBashCommand('graphify query x && rm y', {}).result).toBe('block');
|
||||
expect(classifyBashCommand('graphify path A `id`', {}).result).toBe('block');
|
||||
expect(classifyBashCommand('graphify query x | sh', {}).result).toBe('block');
|
||||
});
|
||||
|
||||
// legit read-only graphify with quoted (Cyrillic) question + flags still allowed —
|
||||
// guards against over-tightening that would reject Unicode queries (tokenizer strips
|
||||
// quotes → Cyrillic args arrive as barewords).
|
||||
it('still allows graphify query with quoted question and flags', () => {
|
||||
expect(classifyBashCommand('graphify query "конфликт дубль" --dfs --budget 1500', {}).result).toBe('allow');
|
||||
});
|
||||
});
|
||||
|
||||
describe('SAFE_EXACT — narrow `cd app` whitelist (2026-05-31, owner-authorized)', () => {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* receipt-key-config — резолв HMAC-ключа подписи расписок роутер-наставника.
|
||||
* Зеркало llm-judge-config.mjs: keychain (service router-mentor-receipts) → env → null.
|
||||
* Ключ провижинит владелец (как LLM-ключ судьи). Без ключа — null → подпись невозможна
|
||||
* → неподписанная расписка невалидна (fail-closed на стороне verifyReceipt).
|
||||
*/
|
||||
import { createRequire } from 'node:module';
|
||||
|
||||
const KEY_ENV = 'ROUTER_MENTOR_RECEIPT_KEY';
|
||||
const KEYCHAIN_SERVICE = 'router-mentor-receipts';
|
||||
const KEYCHAIN_ACCOUNT = 'default';
|
||||
|
||||
/**
|
||||
* @param {object} [args]
|
||||
* @param {object} [args.env] - окружение (default process.env)
|
||||
* @param {Function} [args.keychainGet] - () => string|null (инъекция для тестов)
|
||||
* @returns {string|null}
|
||||
*/
|
||||
export function resolveReceiptKey({ env = process.env, keychainGet = defaultKeychainGet } = {}) {
|
||||
let chainKey = null;
|
||||
try {
|
||||
const v = keychainGet();
|
||||
chainKey = v ? String(v) : null;
|
||||
} catch {
|
||||
chainKey = null;
|
||||
}
|
||||
const envKey = env[KEY_ENV] ? String(env[KEY_ENV]) : null;
|
||||
return chainKey || envKey || null;
|
||||
}
|
||||
|
||||
/** Lazy keytar-ридер; null если keytar отсутствует или записи нет. Никогда не бросает. */
|
||||
export function defaultKeychainGet() {
|
||||
try {
|
||||
const require = createRequire(import.meta.url);
|
||||
const keytar = require('keytar');
|
||||
return (keytar.getPasswordSync?.(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT)) || null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export const _internals = { KEY_ENV, KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT };
|
||||
@@ -0,0 +1,25 @@
|
||||
// tools/receipt-key-config.test.mjs
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { resolveReceiptKey } from './receipt-key-config.mjs';
|
||||
|
||||
describe('resolveReceiptKey', () => {
|
||||
it('returns keychain key when present', () => {
|
||||
const r = resolveReceiptKey({ env: {}, keychainGet: () => 'k-from-chain' });
|
||||
expect(r).toBe('k-from-chain');
|
||||
});
|
||||
it('falls back to env ROUTER_MENTOR_RECEIPT_KEY when keychain empty', () => {
|
||||
const r = resolveReceiptKey({ env: { ROUTER_MENTOR_RECEIPT_KEY: 'k-env' }, keychainGet: () => null });
|
||||
expect(r).toBe('k-env');
|
||||
});
|
||||
it('prefers keychain over env', () => {
|
||||
const r = resolveReceiptKey({ env: { ROUTER_MENTOR_RECEIPT_KEY: 'k-env' }, keychainGet: () => 'k-chain' });
|
||||
expect(r).toBe('k-chain');
|
||||
});
|
||||
it('returns null when neither present', () => {
|
||||
expect(resolveReceiptKey({ env: {}, keychainGet: () => null })).toBe(null);
|
||||
});
|
||||
it('never throws when keychainGet throws → null', () => {
|
||||
const r = resolveReceiptKey({ env: {}, keychainGet: () => { throw new Error('boom'); } });
|
||||
expect(r).toBe(null);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user