@routinecrew/routinecode 2.31.30 → 2.31.32

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.
Files changed (83) hide show
  1. package/bin/prompt-vault.js +1 -1
  2. package/bin/setup.js +1 -1
  3. package/hooks/pending-drainer.sh +254 -0
  4. package/hooks/post-tool-universal.sh +23 -0
  5. package/hooks/pre-agent-spawn.mjs +1 -1
  6. package/hooks/pre-read-knowledge-inject.sh +65 -12
  7. package/hooks/recorder-runner.sh +20 -1
  8. package/hooks/session-start.sh +25 -0
  9. package/hooks/stop-usage-metrics.sh +27 -0
  10. package/mcp-db-manager/dist/analyzers/duplicate-detector.js +1 -1
  11. package/mcp-db-manager/dist/core/model-parser.js +1 -1
  12. package/mcp-db-manager/dist/core/schema-reader.js +1 -1
  13. package/mcp-db-manager/dist/executors/migration-executor.js +1 -1
  14. package/mcp-db-manager/dist/generators/migration-generator.js +1 -1
  15. package/mcp-db-manager/dist/index.js +1 -1
  16. package/mcp-db-manager/dist/validators/schema-validator.js +1 -1
  17. package/mcp-dev-tester/dist/analyzers/auth-diagnoser.js +1 -1
  18. package/mcp-dev-tester/dist/analyzers/backend-analyzer.js +1 -1
  19. package/mcp-dev-tester/dist/analyzers/endpoint-diagnoser.js +1 -1
  20. package/mcp-dev-tester/dist/analyzers/frontend-analyzer.js +1 -1
  21. package/mcp-dev-tester/dist/analyzers/runtime-diagnoser.js +1 -1
  22. package/mcp-dev-tester/dist/analyzers/type-comparator.js +1 -1
  23. package/mcp-dev-tester/dist/analyzers/validation-diagnoser.js +1 -1
  24. package/mcp-dev-tester/dist/browser/playwright-manager.js +1 -1
  25. package/mcp-dev-tester/dist/browser/ui-tester.js +1 -1
  26. package/mcp-dev-tester/dist/config/project-config.js +1 -1
  27. package/mcp-dev-tester/dist/index.js +1 -1
  28. package/mcp-dev-tester/dist/testers/api-tester.js +1 -1
  29. package/mcp-doc-fetcher/dist/index.js +1 -1
  30. package/mcp-html-renderer/dist/index.js +1 -1
  31. package/mcp-html-renderer/dist/preview.js +1 -1
  32. package/mcp-html-renderer/dist/template-engine.js +1 -1
  33. package/mcp-intelligence/dist/concept-catalog.d.ts +33 -0
  34. package/mcp-intelligence/dist/concept-catalog.d.ts.map +1 -1
  35. package/mcp-intelligence/dist/concept-catalog.js +1 -1
  36. package/mcp-intelligence/dist/concept-server-proxy.js +1 -1
  37. package/mcp-intelligence/dist/config-auth.js +1 -1
  38. package/mcp-intelligence/dist/contracts.generated.js +1 -1
  39. package/mcp-intelligence/dist/domain-templates.js +1 -1
  40. package/mcp-intelligence/dist/grounding.js +1 -1
  41. package/mcp-intelligence/dist/handlers.js +1 -1
  42. package/mcp-intelligence/dist/index.js +1 -1
  43. package/mcp-intelligence/dist/intelligence-file.js +1 -1
  44. package/mcp-intelligence/dist/knowledge-critic.js +1 -1
  45. package/mcp-intelligence/dist/knowledge-handlers.d.ts.map +1 -1
  46. package/mcp-intelligence/dist/knowledge-handlers.js +1 -1
  47. package/mcp-intelligence/dist/mention-extractor.js +1 -1
  48. package/mcp-intelligence/dist/provenance.js +1 -1
  49. package/mcp-intelligence/dist/semantic-embedder.js +1 -1
  50. package/mcp-log-watcher/dist/config-auth.js +1 -1
  51. package/mcp-log-watcher/dist/file-watcher.js +1 -1
  52. package/mcp-log-watcher/dist/index.js +1 -1
  53. package/mcp-log-watcher/dist/known-solutions.js +1 -1
  54. package/mcp-log-watcher/dist/log-store.js +1 -1
  55. package/mcp-log-watcher/dist/websocket-server.js +1 -1
  56. package/mcp-plan-manager/dist/__tests__/plan-parser.test.js +1 -1
  57. package/mcp-plan-manager/dist/file-ops.js +1 -1
  58. package/mcp-plan-manager/dist/index.js +1 -1
  59. package/mcp-plan-manager/dist/plan-parser.js +1 -1
  60. package/mcp-project-context/dist/git-ops.js +1 -1
  61. package/mcp-project-context/dist/index.js +1 -1
  62. package/mcp-project-context/dist/project-analysis.js +1 -1
  63. package/mcp-routinecode/dist/agent-tracker.js +1 -1
  64. package/mcp-routinecode/dist/blast-radius.js +1 -1
  65. package/mcp-routinecode/dist/config-auth.js +1 -1
  66. package/mcp-routinecode/dist/contracts.generated.js +1 -1
  67. package/mcp-routinecode/dist/explorer-advisor.js +1 -1
  68. package/mcp-routinecode/dist/failure-tracker.js +1 -1
  69. package/mcp-routinecode/dist/file-lock-registry.js +1 -1
  70. package/mcp-routinecode/dist/file-risk-scorer.js +1 -1
  71. package/mcp-routinecode/dist/index.js +1 -1
  72. package/mcp-routinecode/dist/known-solutions.js +1 -1
  73. package/mcp-routinecode/dist/ledger-miner.js +1 -1
  74. package/mcp-routinecode/dist/observed-draft.js +1 -1
  75. package/mcp-routinecode/dist/pattern-matcher.js +1 -1
  76. package/mcp-routinecode/dist/routines.d.ts +18 -0
  77. package/mcp-routinecode/dist/routines.js +1 -1
  78. package/mcp-routinecode/dist/rule-engine.js +1 -1
  79. package/mcp-routinecode/dist/rule-promoter.js +1 -1
  80. package/mcp-routinecode/dist/telemetry-analyzer.js +1 -1
  81. package/mcp-routinecode/dist/verification.js +0 -0
  82. package/mcp-routinecode/dist/viral-loop.js +1 -1
  83. package/package.json +1 -1
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env bash
2
+ # pending-drainer — pending-sync.jsonl 을 서버로 주기 백필. **MCP 비의존**(cwd 무관).
3
+ # session-start 훅이 백그라운드(nohup)로 기동. post-tool-universal 이 6h 안전망으로 재기동.
4
+ # 목표: 각 사용자 pending 이 세션 경계를 넘겨 쌓이지 않게 하고, 유실 0(실패=pending 또는 dead-letter).
5
+ #
6
+ # 설계 L5 (교차검증 97):
7
+ # - config.json(serverUrl/apiKey/tenantId/userId/machineId) 직접 읽어 Bearer POST
8
+ # ${serverUrl}/api/v1/ingest/${endpoint}.
9
+ # - payload body 엔벌로프는 sendToServer 와 **동일** 재구성:
10
+ # {...item.data, tenantId, userId, contributorHash: userId ? 'p:'+userId : machineId}
11
+ # (헤더만으론 서버 dedup/귀속이 깨짐 — body 의 contributorHash 사용)
12
+ # - 디바운스: .last-drain mtime <1h 면 skip. 성공 후 touch.
13
+ # - rate: 요청 간 >=2.5s(<=24/min). 429 는 지수 백오프.
14
+ # - nextAttemptAt(L4 백오프) 존중. 멱등(서버 dedup). claim-rename 으로 동시실행 방지.
15
+ # - 실패 분류/재큐/dead-letter 는 L4(knowledge-handlers) 와 동일 규칙.
16
+ set -u
17
+
18
+ KN="${ROUTINECODE_KNOWLEDGE_DIR:-${ROUTINECODE_DIR:-$HOME/.routinecode}/knowledge}"
19
+ CONFIG="${ROUTINECODE_CONFIG_PATH:-${ROUTINECODE_DIR:-$HOME/.routinecode}/config.json}"
20
+ PENDING="$KN/pending-sync.jsonl"
21
+ DEADLETTER="$KN/pending-sync.deadletter.jsonl"
22
+ MARKER="$KN/.last-drain"
23
+
24
+ # recorder 자신의 세션에서는 돌지 않음(불필요한 중첩 방지)
25
+ [ "${ROUTINECODE_RECORDER:-}" = "1" ] && exit 0
26
+ [ -f "$CONFIG" ] || exit 0
27
+ [ -f "$PENDING" ] || exit 0
28
+
29
+ # ── 디바운스: .last-drain mtime 이 1시간 이내면 skip ──────────────
30
+ # ROUTINECODE_DRAIN_FORCE=1 이면 무시(테스트/수동 트리거용).
31
+ if [ "${ROUTINECODE_DRAIN_FORCE:-}" != "1" ] && [ -f "$MARKER" ]; then
32
+ now_epoch=$(date +%s)
33
+ marker_epoch=$(python3 -c "import os,sys;print(int(os.path.getmtime('$MARKER')))" 2>/dev/null || echo 0)
34
+ if [ "$marker_epoch" -gt 0 ] && [ $((now_epoch - marker_epoch)) -lt 3600 ]; then
35
+ exit 0
36
+ fi
37
+ fi
38
+
39
+ # ── 원자적 claim (동시 실행 방지) ────────────────────────────────
40
+ # recorder-runner.sh 선례: mv 가 실패하면 다른 프로세스가 이미 claim 한 것 → 종료.
41
+ CLAIM="$PENDING.processing.$$"
42
+ mv "$PENDING" "$CLAIM" 2>/dev/null || exit 0
43
+
44
+ # ── drain (python3: 엔벌로프 재구성·분류·백오프·rate·dead-letter) ─
45
+ ROUTINECODE_DRAIN_CONFIG="$CONFIG" \
46
+ ROUTINECODE_DRAIN_CLAIM="$CLAIM" \
47
+ ROUTINECODE_DRAIN_PENDING="$PENDING" \
48
+ ROUTINECODE_DRAIN_DEADLETTER="$DEADLETTER" \
49
+ ROUTINECODE_DRAIN_MARKER="$MARKER" \
50
+ ROUTINECODE_DRAIN_DRY="${ROUTINECODE_DRAIN_DRY:-}" \
51
+ python3 - <<'PYEOF'
52
+ import json, os, sys, time, urllib.request, urllib.error
53
+
54
+ CONFIG = os.environ['ROUTINECODE_DRAIN_CONFIG']
55
+ CLAIM = os.environ['ROUTINECODE_DRAIN_CLAIM']
56
+ PENDING = os.environ['ROUTINECODE_DRAIN_PENDING']
57
+ DEADLETTER = os.environ['ROUTINECODE_DRAIN_DEADLETTER']
58
+ MARKER = os.environ['ROUTINECODE_DRAIN_MARKER']
59
+ DRY = os.environ.get('ROUTINECODE_DRAIN_DRY') == '1'
60
+
61
+ MAX_RETRIES = 10
62
+ BACKOFF_BASE = 5000 # ms
63
+ BACKOFF_CAP = 60*60*1000 # 1h ms
64
+ RATE_WINDOW = 60*1000 # 429 최소 백오프 ms
65
+ MIN_INTERVAL = 2.5 # 요청 간 최소 간격(초) → <=24/min
66
+ MAX_BATCH = 50 # 한 번 drain 상한 (초과분은 CLAIM→pending 로 이월)
67
+
68
+ def now_ms():
69
+ return int(time.time()*1000)
70
+
71
+ def read_config():
72
+ try:
73
+ with open(CONFIG, 'r') as f:
74
+ return json.load(f)
75
+ except Exception:
76
+ return None
77
+
78
+ def load_claim():
79
+ items = []
80
+ try:
81
+ with open(CLAIM, 'r') as f:
82
+ for line in f:
83
+ line = line.strip()
84
+ if not line:
85
+ continue
86
+ try:
87
+ items.append(json.loads(line))
88
+ except Exception:
89
+ pass # malformed line skip
90
+ except Exception:
91
+ pass
92
+ return items
93
+
94
+ def append_jsonl(path, obj):
95
+ try:
96
+ with open(path, 'a') as f:
97
+ f.write(json.dumps(obj, ensure_ascii=False) + '\n')
98
+ except Exception:
99
+ pass
100
+
101
+ def requeue(items):
102
+ # CLAIM 소비분 중 미전송/미도래 항목을 pending 으로 되돌림(append, 유실 방지).
103
+ for it in items:
104
+ append_jsonl(PENDING, it)
105
+
106
+ def restore_all_and_exit(items, code=0):
107
+ requeue(items)
108
+ try:
109
+ os.remove(CLAIM)
110
+ except Exception:
111
+ pass
112
+ sys.exit(code)
113
+
114
+ cfg = read_config()
115
+ if not cfg or not cfg.get('syncEnabled') or not cfg.get('serverUrl') or not cfg.get('apiKey'):
116
+ # sync 불가 → claim 원복(유실 금지)
117
+ restore_all_and_exit(load_claim(), 0)
118
+
119
+ server_url = cfg['serverUrl'].rstrip('/')
120
+ api_key = cfg['apiKey']
121
+ tenant_id = cfg.get('tenantId')
122
+ user_id = cfg.get('userId')
123
+ machine_id = cfg.get('machineId')
124
+ contributor = ('p:' + str(user_id)) if user_id else machine_id
125
+
126
+ items = load_claim()
127
+ leftover = [] # 이번 패스에서 전송하지 않고 pending 으로 되돌릴 항목(미도래/백오프/상한초과)
128
+ processed = 0
129
+ last_req_ts = 0.0
130
+
131
+ def classify(status):
132
+ # status 0 = 네트워크/타임아웃 → transient (L4 sendToServer catch 와 동일)
133
+ if status == 0:
134
+ return 'transient'
135
+ if status == 401:
136
+ return 'auth'
137
+ if status >= 500 or status == 429:
138
+ return 'transient'
139
+ return 'permanent' # 그 외 4xx(400/422 등)
140
+
141
+ def compute_next_attempt(retries, status):
142
+ delay = min(BACKOFF_BASE * (2 ** retries), BACKOFF_CAP)
143
+ if status == 429:
144
+ delay = max(delay, RATE_WINDOW)
145
+ return now_ms() + delay
146
+
147
+ def send(endpoint, data):
148
+ # 엔벌로프: sendToServer(:511-518) 와 동일. 헤더만으론 부족.
149
+ body = dict(data)
150
+ body['tenantId'] = tenant_id if tenant_id is not None else None
151
+ body['userId'] = user_id if user_id is not None else None
152
+ body['contributorHash'] = contributor
153
+ if endpoint.startswith('ontology/'):
154
+ url = server_url + '/api/v1/' + endpoint
155
+ else:
156
+ url = server_url + '/api/v1/ingest/' + endpoint
157
+ payload = json.dumps(body).encode('utf-8')
158
+ req = urllib.request.Request(url, data=payload, method='POST')
159
+ req.add_header('Content-Type', 'application/json')
160
+ req.add_header('Authorization', 'Bearer ' + str(api_key))
161
+ try:
162
+ with urllib.request.urlopen(req, timeout=5) as resp:
163
+ return resp.getcode(), ''
164
+ except urllib.error.HTTPError as e:
165
+ try:
166
+ rbody = e.read().decode('utf-8', 'replace')[:2000]
167
+ except Exception:
168
+ rbody = ''
169
+ return e.code, rbody
170
+ except Exception:
171
+ return 0, '' # 네트워크/타임아웃 → transient
172
+
173
+ cur = now_ms()
174
+ for idx, item in enumerate(items):
175
+ # 상한 초과 → 남은 항목 전부 pending 으로 이월
176
+ if processed >= MAX_BATCH:
177
+ leftover.append(item)
178
+ continue
179
+ # L4 백오프 존중: 미도래 항목은 전송하지 않고 되돌림
180
+ next_at = item.get('nextAttemptAt') or 0
181
+ if next_at > cur:
182
+ leftover.append(item)
183
+ continue
184
+
185
+ # DRY 모드: 전송하지 않고 재구성된 엔벌로프를 stderr 로 출력(검증용), 항목은 보존
186
+ if DRY:
187
+ body = dict(item.get('data', {}))
188
+ body['tenantId'] = tenant_id if tenant_id is not None else None
189
+ body['userId'] = user_id if user_id is not None else None
190
+ body['contributorHash'] = contributor
191
+ sys.stderr.write('[drain-dry] endpoint=%s envelope=%s\n'
192
+ % (item.get('endpoint'), json.dumps(body, ensure_ascii=False)))
193
+ leftover.append(item)
194
+ continue
195
+
196
+ # rate: 요청 간 >= MIN_INTERVAL
197
+ wait = MIN_INTERVAL - (time.time() - last_req_ts)
198
+ if wait > 0:
199
+ time.sleep(wait)
200
+
201
+ status, rbody = send(item.get('endpoint', ''), item.get('data', {}))
202
+ last_req_ts = time.time()
203
+ processed += 1
204
+
205
+ if 200 <= status < 300:
206
+ continue # 성공 → 소비(요건: pending/claim 어디에도 남기지 않음)
207
+
208
+ kind = classify(status)
209
+ if kind == 'permanent':
210
+ append_jsonl(DEADLETTER, {
211
+ 'endpoint': item.get('endpoint'),
212
+ 'data': item.get('data'),
213
+ 'ts': item.get('ts'),
214
+ 'retries': item.get('retries', 0),
215
+ 'reason': 'permanent_4xx',
216
+ 'status': status,
217
+ 'body': rbody[:2000],
218
+ 'deadLetteredAt': time.strftime('%Y-%m-%dT%H:%M:%S.000Z', time.gmtime()),
219
+ })
220
+ continue
221
+
222
+ # transient | auth → 백오프 재큐, MAX_RETRIES 초과 시 dead-letter(드롭 금지)
223
+ item['retries'] = int(item.get('retries', 0)) + 1
224
+ if item['retries'] >= MAX_RETRIES:
225
+ append_jsonl(DEADLETTER, {
226
+ 'endpoint': item.get('endpoint'),
227
+ 'data': item.get('data'),
228
+ 'ts': item.get('ts'),
229
+ 'retries': item['retries'],
230
+ 'reason': 'max_retries_exceeded',
231
+ 'status': status,
232
+ 'body': rbody[:2000],
233
+ 'deadLetteredAt': time.strftime('%Y-%m-%dT%H:%M:%S.000Z', time.gmtime()),
234
+ })
235
+ continue
236
+ item['nextAttemptAt'] = compute_next_attempt(item['retries'], status)
237
+ leftover.append(item)
238
+
239
+ # 미전송/재큐 항목을 pending 으로 되돌림
240
+ requeue(leftover)
241
+ try:
242
+ os.remove(CLAIM)
243
+ except Exception:
244
+ pass
245
+
246
+ # 디바운스 마커 갱신(이번 drain 완료 표시). DRY 모드에서도 갱신 않음(실제 drain 아님).
247
+ if not DRY:
248
+ try:
249
+ with open(MARKER, 'a'):
250
+ pass
251
+ os.utime(MARKER, None)
252
+ except Exception:
253
+ pass
254
+ PYEOF
@@ -151,3 +151,26 @@ if is_mcp_tool:
151
151
 
152
152
  print('{"continue":true}')
153
153
  PYEOF
154
+
155
+ # --- L5 안전망: 장수 세션에서 drainer 재기동 (경량 stat 1회) ---
156
+ # session-start 가 유일 트리거면 장시간 열린 세션에서 drain 이 안 돈다.
157
+ # .last-drain mtime > 6h 일 때만 drainer 를 nohup 재기동한다(평소 비용 ~0).
158
+ # drainer 내부 디바운스(1h)가 중복 실행을 다시 막으므로 과기동해도 무해.
159
+ if [ "${ROUTINECODE_RECORDER:-}" != "1" ]; then
160
+ _RC_HOOKS_DIR="$(cd "$(dirname "$0")" 2>/dev/null && pwd)"
161
+ _RC_KN="${ROUTINECODE_KNOWLEDGE_DIR:-$HOME/.routinecode/knowledge}"
162
+ _RC_DRAINER="$_RC_HOOKS_DIR/pending-drainer.sh"
163
+ _RC_MARKER="$_RC_KN/.last-drain"
164
+ if [ -f "$_RC_DRAINER" ] && [ -f "$_RC_KN/pending-sync.jsonl" ]; then
165
+ # 마커 없음 OR mtime > 6h(21600s) → 재기동
166
+ _RC_STALE=1
167
+ if [ -f "$_RC_MARKER" ]; then
168
+ _RC_NOW=$(date +%s)
169
+ _RC_MT=$(python3 -c "import os;print(int(os.path.getmtime('$_RC_MARKER')))" 2>/dev/null || echo 0)
170
+ if [ "$_RC_MT" -gt 0 ] && [ $((_RC_NOW - _RC_MT)) -le 21600 ]; then _RC_STALE=0; fi
171
+ fi
172
+ if [ "$_RC_STALE" = "1" ]; then
173
+ nohup bash "$_RC_DRAINER" >/dev/null 2>&1 &
174
+ fi
175
+ fi
176
+ fi
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- const a0_0x56a23f=a0_0x49e5;(function(_0x5ea239,_0x570203){const _0x5a08e9=a0_0x49e5,_0x39d4a7=_0x5ea239();while(!![]){try{const _0x408aba=-parseInt(_0x5a08e9(0xd6,'LveC'))/(-0x1885+-0x16aa+0x2f30)*(-parseInt(_0x5a08e9(0x1b2,'Z0Jm'))/(-0x1*-0xeb9+0x706*-0x1+-0x7b1))+parseInt(_0x5a08e9(0x105,'U#&Q'))/(-0x8fc+-0x6*0x4a7+0x24e9)+-parseInt(_0x5a08e9(0x161,'WTD0'))/(0x231e+-0xe13*-0x1+-0x312d)*(-parseInt(_0x5a08e9(0x129,'ng)J'))/(0x36f*-0x7+0x3*-0xbf8+-0x266*-0x19))+parseInt(_0x5a08e9(0xcd,'U#&Q'))/(-0x1a91+-0x49d*0x3+0x286e)+-parseInt(_0x5a08e9(0x149,'IlXp'))/(0x64d*-0x1+0x5*-0x595+0x223d)*(-parseInt(_0x5a08e9(0x186,'qsb8'))/(-0x2675+0x6*0x3b7+0x1033))+-parseInt(_0x5a08e9(0x199,'IlXp'))/(0x26b+-0x7bc+0x2ad*0x2)*(-parseInt(_0x5a08e9(0x138,'LQZ('))/(0xcc4+0x3ab*0x7+-0x2667*0x1))+-parseInt(_0x5a08e9(0xb5,'LveC'))/(-0x2*0x553+0xb0c+-0x5b)*(parseInt(_0x5a08e9(0xb6,'$en$'))/(0x5*-0x4fb+-0x4*-0x6f3+-0x2d9));if(_0x408aba===_0x570203)break;else _0x39d4a7['push'](_0x39d4a7['shift']());}catch(_0x354333){_0x39d4a7['push'](_0x39d4a7['shift']());}}}(a0_0x56ae,-0x3f1*0xbf+-0x31c0e+0xbe490));import{fileURLToPath}from'node:url';function a0_0x56ae(){const _0x2f7450=['rqtdUJhcQa','w8knW4Lmxa','x8o9WPpdNqtcJM/dQ8ov','WQX3qW','j1ZcLMvxW5OZlxq','FCkxfSo7Ba','ltWNiu8','WPVcTeFcG3m','WOuOuSkjWRy','WPFdTKnMxa','W7HkWQXwW6y','W53dV1NdNuK','csepWP/cQa','WOX/iCo5o8o7WQmxfYe0WP9o','WOJcM8k0WRGK','xSoRWOW','W54nWRPJW6e','cYGhWQa','a8oQfCol','WPBdRuONoW','lSo1f8o6W5e','ySkgW4vyWRTIWRhdTg/dSmkxW4Sr','x8o3WPdcHMddLqVdR8obW5PJW5FdIa','a3NdHCo4W7jSWP/dNe8','vg/cHmo/W40','W60HEmkxqW','ACofWOqmWQq','WPydW5XHWQi','WRZdJ3BcV8kb','WRSOcSkVW5u','iZFdTmoNja','W5ZdJKqIW6u','Dwayr8kj','WPfKiCkSW4m','W58QFCkJzG','ccaBWPm','WOi5zSogWPy','BCo9WPZcUNO','o8k6k8oovq','DmkYi8oocq','WOBdTeLKDW','WRDaW4VcG8oz','WQBdQ0FdOmkh','gI4SWOjD','vCkkf8o+sG','WO4ae8kqbuVcH8oGW7eszgGF','qmkUW5ddMdW','qSoMWRKRmq','DmkTnG','W50lWRXHW78','WOBcRvFcRxa','W4K5W7rtWPK','W6dcI27dSKO','W6PJWPL7W6y','yLKNW5ZdIa','bZCvW47cOq','gbiwWR7cOa','qJVcHmosW5i','WOxcISkdWP0MWPD6mmkboCkbyMW','odixWR7cHW','W5X9rSodDq','W4KfWPHhW5G','WPOXWRKdga','WRSPWOqalq','vb7cSSkwca','W6XpaNf+','w8kTDSk4FW','iZldUmoZBq','WPCUWQiXhq','WO8SxG','FSk7s8kMqW','r8o+WOqmka','WPtdIhv/AW','W4FdKL8LW7G','zfKGWOy','W5O4W79vWOu','sstcOmoqW7q','felcTNtcMmo2CW','W6CsWR9yW4q','W5OAWOGUW5i','WPuOW7zeWOW','W6RcLs/dSf8','W4zOWQeRdmkRWQtdJa','WOe4WQHIta','WQuktCkVzW','bGVdUSkecW','jtedWPVcMa','rmoFW4jexW','WP3cICk+WOiP','dq0kmKW','WOCfW64LWOm','kmoTWRRcVwy','W5hcQHqYBKpdKWSIW7W','vX3dP0vI','ccOiWPNcVq','jmohWP8DW6W','WQqUWQGwaq','kYfXWOZdLW','y1nYW4RdHa','WRNdJxxdT8ot','W4OAWQzNW7y','yCkaW4vFWRfLW7FdJ0ZdSmkjW6K','WRWWW5XIWQi','gmkDW64','yfCMW4a','hwdcNCo9qa','WO7cIgBcRu0','WR/cJgddVCkg','hJaDWPJcQW','pqKJWP/cLW','Fv3cLmozW7y','d1dcQ37cRW','FWBdH3TO','WROOW6r8WOS','uxtcPSo6W68','W4uAWQCGW7S','WPCjW4bX','vmkGW4BdHdS','fJldTmobAW','W4tdNCoe','jNNcRq','WRO7omkzpW','W5JdL8osW4WU','WP8xmvJdIq','W5/dUSoWW5Pe','WPtdNM14DW','xmo9WPVcGsVcLh/dSmonW5G','WQfguSkJFW','W7ldK3RcHvK','qLBcUwlcSG','FvtcN8oyW7y','mcWJku4','ACoqbMXe','kcWYl0W','nSkaybm7W4ddH2OebIG5','rL3dOSopfSo+quDHWQq','amoQWQRcJg0','nJyWW5pcHW','W6JcL2pdPvK','ASoXsaOU','W7hdHg3dHG','xIpcO8oiW5K','W6P1WP1iW70','W5pcMmosW4XN','pmozWQmAW6W','WQOlvCkbzG','WOmzg8kspG','WPqwrmkgoG','aahcLSkyda','kY80WQhcVq','qCkrjq','W6lcLIRdSKu','mqFdKmoNCa','oCoYwreQ','fSoboCoTW7q','AgddG8oGAG','W7RdKxZdPfS','Emk+j8oztW','b8kFWPGDhCo8aSk4WPyceCo2aW','WQOcaCkMFW','ECkfq8kjqq','gqmzcvW','WOBdOfpcHgC','W43dMKBdSxC','nxJdSSo0rW','mmoAWOqmWQK','b8kPW5pdMZC','nCkeygfnWOpdNgau','vu4IW4tdJG','W5JdJmoLW4P7','EGZdGwD1','hCo1pCoLt8kOj8kladq','WPXkW6y4WQKDgYPogSobgW','oCk8xXCI','W6zJWP1rW6y','ts3dQubk','kSobi0n0','vYhcSSoTW7m','WRddNMi','W7blhwD1','vSoIAraH','WPGxWRS1aq','kgddSmo7ya','WRFdGKldHmk8','W4ddJLiQW6W','WPiBcSkekW','s8o9WOmGiq','W4TwEW','aCkQWO0','WOeiBSkAxa','W5KQWQWUbW','W7xdHtFdTfG','W7H/rYFcOG','WPCbW4DSWQG','mcyKiXa','b8kQW4BdLd0','W5JcMmo1W6zA','mcq0b1W','WOuOsCkpWRy','cmo/bmoPW4q','WQyJW41NW70','vSkTWQPZgW','pCownLfQ','W6mYwSoYWOW','WQFcJc7dPuC','b8o+hmohW4u','BCoeWReMmW','W50kWRjPW7q','eGhcQmkswW','WOPpW7JcMCoJ','W6P0wrdcJq','n8oZW7ffWQC','W40EWQfNW74','W5fnsCoixW','bSkyWPSDhmo6zSkkWPWqg8oJ','WOhcRKtdJg8','nY4UzLW','AbOlWQ7cJG','mY7dUSo7AW','W7FdIxRdL0G','WO5dEGNcIG','zSorjWj3','jZC3WOzD','WP8YWQi1aG','W6rXB8oMEa','WPmOECkPWPy','jN/cUSoH','W7Guud5Y','nSkLg05N','o3dcTSoWrW','W7zbgwW','l3mmWQdcKG','W559cLrQ','cdWvWOi','WOqXW6PWWQ8','W59NW5VdPSoL','W5HqrSoq','xCkrgmoQxq','W5ldIfTR','aYNcM8kfdW','WRlcRwdcLw4','pSoRWP3cTxS','gIWtWP5R','p8oqWPSmW6C','xCoWW75HWOa','imoqWOCCW6W','zIekWRJcLG','W58VFmkIta','vmkMhmobW5dcOSo/W6i','DWldG2f1','z27cSCo2FWVdRG','CX3dG2W','tSk2W4BdGtS','DhrIWPxdKqdcRxOvfYVdNG','eIBcN8k2ma','oXJcMmkzhq','W7XUWOjwW7S','aYyPWRJcIa','W5mPDSkLnW','WPOhW50LWRC','W5TiWRvWWRi'];a0_0x56ae=function(){return _0x2f7450;};return a0_0x56ae();}import{dirname,resolve}from'node:path';import{existsSync}from'node:fs';async function readStdin(){const _0x2d31c1=a0_0x49e5;let _0x4f01c7='';for await(const _0x5a962a of process[_0x2d31c1(0x120,'LHMM')])_0x4f01c7+=_0x5a962a;return _0x4f01c7;}function a0_0x49e5(_0x1e381d,_0x3db808){_0x1e381d=_0x1e381d-(0x61*-0x4b+-0x192b+0x3644);const _0xb34e80=a0_0x56ae();let _0xb9666a=_0xb34e80[_0x1e381d];if(a0_0x49e5['bhnCNj']===undefined){var _0x4f569c=function(_0x16754b){const _0x33dd60='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2dad5a='',_0xe21396='';for(let _0x2ac976=0xeab+-0x5*0x2f+0x37*-0x40,_0x1d68b3,_0x25abb8,_0x5dab50=-0x1*0x105c+-0x1b08+0x2b64;_0x25abb8=_0x16754b['charAt'](_0x5dab50++);~_0x25abb8&&(_0x1d68b3=_0x2ac976%(0x7*-0x71+0x10d3+-0xdb8)?_0x1d68b3*(-0x193c+0xd28+-0x107*-0xc)+_0x25abb8:_0x25abb8,_0x2ac976++%(0x1a45+0x1428+-0x2e69))?_0x2dad5a+=String['fromCharCode'](0x15b5+0x1aa6+-0xbd7*0x4&_0x1d68b3>>(-(-0x412+-0x50*-0x7a+-0x220c)*_0x2ac976&-0x1*-0x1583+-0x1c29+0xf4*0x7)):-0x596+0xc5d+-0x6c7){_0x25abb8=_0x33dd60['indexOf'](_0x25abb8);}for(let _0x396dc5=0x226c+0x537*-0x6+-0x1*0x322,_0x4f1fb0=_0x2dad5a['length'];_0x396dc5<_0x4f1fb0;_0x396dc5++){_0xe21396+='%'+('00'+_0x2dad5a['charCodeAt'](_0x396dc5)['toString'](-0x1*-0x29e+0x26*-0xd6+0x1d36))['slice'](-(0x11*-0x6b+0x5c7*-0x2+-0x3*-0x639));}return decodeURIComponent(_0xe21396);};const _0x5e3bfd=function(_0x255863,_0x2384a0){let _0x38dc4a=[],_0x19a480=0x2a7+0x1a3a+-0x1ce1,_0x21d5d5,_0x550d78='';_0x255863=_0x4f569c(_0x255863);let _0x47ded0;for(_0x47ded0=0xfa+-0x1*0x715+0x1*0x61b;_0x47ded0<-0x92*0x16+0x6a*-0x16+0x16a8;_0x47ded0++){_0x38dc4a[_0x47ded0]=_0x47ded0;}for(_0x47ded0=0x2*-0xd92+-0x1c65+0x3789;_0x47ded0<-0x13b0+-0x2f*0x17+0x1*0x18e9;_0x47ded0++){_0x19a480=(_0x19a480+_0x38dc4a[_0x47ded0]+_0x2384a0['charCodeAt'](_0x47ded0%_0x2384a0['length']))%(0x2cf*0x6+0x3cb*-0x2+-0x844),_0x21d5d5=_0x38dc4a[_0x47ded0],_0x38dc4a[_0x47ded0]=_0x38dc4a[_0x19a480],_0x38dc4a[_0x19a480]=_0x21d5d5;}_0x47ded0=-0x19*-0x14c+-0x4cf*0x4+0x2*-0x698,_0x19a480=0x174a+-0x2295+0xb4b;for(let _0x3bc204=-0x2225+0xaeb*0x3+-0x2*-0xb2;_0x3bc204<_0x255863['length'];_0x3bc204++){_0x47ded0=(_0x47ded0+(0x2ff+0x12e7*-0x1+0xfe9))%(0x25*0x51+0xb*0xa2+-0x11ab),_0x19a480=(_0x19a480+_0x38dc4a[_0x47ded0])%(0x105f+-0x718+0x1*-0x847),_0x21d5d5=_0x38dc4a[_0x47ded0],_0x38dc4a[_0x47ded0]=_0x38dc4a[_0x19a480],_0x38dc4a[_0x19a480]=_0x21d5d5,_0x550d78+=String['fromCharCode'](_0x255863['charCodeAt'](_0x3bc204)^_0x38dc4a[(_0x38dc4a[_0x47ded0]+_0x38dc4a[_0x19a480])%(-0x2431+-0x1afe+0x3*0x1565)]);}return _0x550d78;};a0_0x49e5['EHcxuN']=_0x5e3bfd,a0_0x49e5['HIIRaK']={},a0_0x49e5['bhnCNj']=!![];}const _0x44f9ae=_0xb34e80[0xd25+0x5*0x6f7+0x17fc*-0x2],_0x41cbe0=_0x1e381d+_0x44f9ae,_0x51198e=a0_0x49e5['HIIRaK'][_0x41cbe0];return!_0x51198e?(a0_0x49e5['LtiqRK']===undefined&&(a0_0x49e5['LtiqRK']=!![]),_0xb9666a=a0_0x49e5['EHcxuN'](_0xb9666a,_0x3db808),a0_0x49e5['HIIRaK'][_0x41cbe0]=_0xb9666a):_0xb9666a=_0x51198e,_0xb9666a;}function emit(_0x4f1745){const _0x2df082=a0_0x49e5;process[_0x2df082(0x13b,'Deqw')+'t'][_0x2df082(0x193,'IlXp')](JSON[_0x2df082(0x16d,'Qy!P')+_0x2df082(0x11b,'WTD0')](_0x4f1745)),process[_0x2df082(0x118,'^4ur')](-0xbf6+0x1328+-0x732);}async function main(){const _0x339617=a0_0x49e5,_0x26a8b1={'fnDVO':function(_0x1daba4){return _0x1daba4();},'AxAJc':function(_0x2a859a,_0x4641f4){return _0x2a859a||_0x4641f4;},'GJYOv':function(_0x36b093,_0x228e04){return _0x36b093(_0x228e04);},'nmtAv':_0x339617(0x194,'qsb8')+_0x339617(0xbc,'Qy!P'),'wGArt':_0x339617(0xfc,'DJBI'),'hhQBt':function(_0x5b223f,_0x9a5e77){return _0x5b223f===_0x9a5e77;},'xkVkH':_0x339617(0xf5,'hV8d')+'g','FNKPz':_0x339617(0xd5,'Z0Jm')+_0x339617(0x154,'M*1*')+'r','BqDjH':_0x339617(0x16a,'hXF#')+_0x339617(0xb2,'N#5z')+_0x339617(0x151,'!eZC')+_0x339617(0xe2,'$vbH')+_0x339617(0x1ac,'ng)J'),'OvBnf':function(_0x5babc9,_0xc30225){return _0x5babc9(_0xc30225);},'fHEAK':_0x339617(0x156,'MlOx'),'lKvwo':_0x339617(0xf1,'N#5z')+'fs','binbA':_0x339617(0x131,'MlOx')+_0x339617(0x19c,'hXF#'),'XmYKN':_0x339617(0x1ae,'OQ6#')+'os','HggRc':function(_0x23b8e6,_0x283f25,_0x292375,_0x4273b5,_0x27ad1e){return _0x23b8e6(_0x283f25,_0x292375,_0x4273b5,_0x27ad1e);},'ZmCyh':function(_0x11bc3f){return _0x11bc3f();},'uZFRu':_0x339617(0x125,'QBTN')+_0x339617(0xf2,'Z0Jm')+'de','nbUNG':_0x339617(0x10e,'qsb8')+_0x339617(0x157,'^4ur'),'EnOZL':_0x339617(0xb4,'N#5z')+_0x339617(0x1a4,'LQZ(')+'on','gzMII':function(_0x28b9d2,_0x41ed69,_0x57d61c,_0x39622d,_0x28759b){return _0x28b9d2(_0x41ed69,_0x57d61c,_0x39622d,_0x28759b);},'OPoge':_0x339617(0xb0,'Sjpz')+_0x339617(0x114,'ng)J')+_0x339617(0x17d,'J5I2'),'etBON':function(_0x46c351,_0x417576,_0x55b5cb){return _0x46c351(_0x417576,_0x55b5cb);},'wQYuh':_0x339617(0x1a0,'^4ur')+_0x339617(0xe1,'Dm!E'),'YfNTZ':function(_0x131311,_0x2bad2a,_0x26f125){return _0x131311(_0x2bad2a,_0x26f125);},'HUuHO':_0x339617(0x147,'(ihR'),'QwNuu':function(_0x2f862,_0x4727f2){return _0x2f862!==_0x4727f2;},'pSIEF':_0x339617(0xd9,'LQZ('),'uVjHo':function(_0x3613a4,_0x376d0a,_0x439c58){return _0x3613a4(_0x376d0a,_0x439c58);},'mbfVz':function(_0x558a06,_0x519686){return _0x558a06<_0x519686;},'ICQxd':function(_0xbd715c,_0x256152){return _0xbd715c(_0x256152);},'cDfjF':_0x339617(0xbd,'fTt9')+_0x339617(0x1ab,'OQ6#'),'IHWyL':_0x339617(0xd7,'hXF#')+'re','MuSPx':function(_0x30738a,_0x201127){return _0x30738a(_0x201127);},'OuIBC':function(_0x4bf3f1,_0x423391,_0x4530d2,_0x2c59ee,_0x23213d,_0x234648){return _0x4bf3f1(_0x423391,_0x4530d2,_0x2c59ee,_0x23213d,_0x234648);},'qcOHZ':_0x339617(0x150,'Dm!E')+_0x339617(0x153,'J5I2')+_0x339617(0x14f,'wLlM'),'NUDDm':_0x339617(0x1a8,'wLlM'),'SDJtf':_0x339617(0x128,'LQZ(')+_0x339617(0x10b,'P8w$')+_0x339617(0x1a7,'&K@p')+'s','FkHWr':function(_0x62e0d4,_0x3d75b2){return _0x62e0d4(_0x3d75b2);},'VIFZw':function(_0x18ccc3,_0x54a483){return _0x18ccc3(_0x54a483);},'ImjVU':_0x339617(0x124,'IlXp')+_0x339617(0x104,'WTD0'),'PgjWN':function(_0x18b2ba,_0x207ff8){return _0x18b2ba(_0x207ff8);},'BSzVq':_0x339617(0x109,')mOX')+'wn','iBFsP':function(_0x19ae7f,_0x5eaa45){return _0x19ae7f(_0x5eaa45);},'MNWMm':function(_0x3b8598,_0x2fbfd0){return _0x3b8598(_0x2fbfd0);}};let _0x7fafee;try{const _0x452357=await _0x26a8b1[_0x339617(0xe0,'Qy!P')](readStdin);_0x7fafee=JSON[_0x339617(0x175,'$vbH')](_0x26a8b1[_0x339617(0x191,'LQZ(')](_0x452357,'{}'));}catch{_0x26a8b1[_0x339617(0xfd,'0mE5')](emit,{'hookSpecificOutput':{'hookEventName':_0x26a8b1[_0x339617(0xc0,'haDq')],'permissionDecision':_0x26a8b1[_0x339617(0x11e,'$en$')]}});}const _0x64a95e=_0x7fafee[_0x339617(0x13d,'(ihR')+_0x339617(0xdd,'fTt9')]??{},_0x382fd5=_0x64a95e[_0x339617(0xe7,'J5I2')+_0x339617(0x169,'fTt9')+_0x339617(0x179,'hV8d')]??'',_0xd8e492=_0x26a8b1[_0x339617(0x163,'0mE5')](typeof _0x64a95e[_0x339617(0x144,'&K@p')+'t'],_0x26a8b1[_0x339617(0x180,'Qy!P')])?_0x64a95e[_0x339617(0x18b,'U#&Q')+'t']:'',_0x192aa2=new Set([_0x26a8b1[_0x339617(0x11c,'^*Nm')],_0x26a8b1[_0x339617(0x16b,'@RW4')]]);if(_0x192aa2[_0x339617(0xea,'P8w$')](_0x382fd5)){const _0x317e76=[/taskId[:\s]+['"]?([a-zA-Z0-9_-]+)/i,/task_id[:\s]+['"]?([a-zA-Z0-9_-]+)/i,/TASK_ID[:\s]+['"]?([a-zA-Z0-9_-]+)/,/task[:\s]+['"]?(\d+[a-zA-Z0-9_-]*)/i];let _0x82421d=null;for(const _0x46b442 of _0x317e76){const _0x5277aa=_0x46b442[_0x339617(0xbb,'b&DL')](_0xd8e492);if(_0x5277aa?.[0x379*-0x5+-0x26a4+-0x3802*-0x1]){_0x82421d=_0x5277aa[-0x2109*0x1+0x8*0x476+0x6*-0x71];break;}}!_0x82421d&&_0x26a8b1[_0x339617(0xe3,'L%2!')](emit,{'decision':_0x26a8b1[_0x339617(0x19e,'Deqw')],'reason':_0x339617(0xef,'P8w$')+_0x339617(0x123,'^Lg7')+_0x339617(0x168,'D!3]')+_0x339617(0x183,'&K@p')+_0x339617(0xb1,'Utv]')+_0x339617(0x15a,'^*Nm')+_0x339617(0x10c,'LveC')+_0x339617(0xe9,'0mE5')+_0x339617(0xc8,'L%2!')+_0x339617(0xfb,'D!3]')+_0x339617(0x15c,'(ihR')+_0x339617(0xb9,'D!3]')+_0x339617(0x15b,'^*Nm')+_0x339617(0x108,'QBTN')+_0x339617(0x187,'qsb8')+_0x339617(0x176,'P7Ii')+_0x339617(0x112,'$vbH')+_0x339617(0x134,'Sjpz')+_0x339617(0xf3,'OQ6#')+_0x339617(0x133,'fTt9')+_0x339617(0xba,'L%2!')+_0x339617(0xeb,'Z0Jm')});if(_0x82421d){const {existsSync:_0x1f68ee,readFileSync:_0x47ed36}=await import(_0x26a8b1[_0x339617(0xe4,'qsb8')]),{join:_0xd724c0}=await import(_0x26a8b1[_0x339617(0x126,'MlOx')]),{homedir:_0x552fe7}=await import(_0x26a8b1[_0x339617(0x10d,'O6a6')]),_0x2932c2=_0x26a8b1[_0x339617(0x148,'DJBI')](_0xd724c0,_0x26a8b1[_0x339617(0x11f,'Deqw')](_0x552fe7),_0x26a8b1[_0x339617(0x100,'fubE')],_0x26a8b1[_0x339617(0xb3,'LveC')],_0x26a8b1[_0x339617(0xec,'haDq')]),_0x43f81f=_0x26a8b1[_0x339617(0x171,'&K@p')](_0xd724c0,_0x26a8b1[_0x339617(0xe6,'Dm!E')](_0x552fe7),_0x26a8b1[_0x339617(0x1a1,'QBTN')],_0x26a8b1[_0x339617(0x130,'^4ur')],_0x26a8b1[_0x339617(0x19a,'wLlM')]),_0x28a4c5=_0x26a8b1[_0x339617(0x15f,'O6a6')](_0xd724c0,_0x2932c2,_0x339617(0x140,'^4ur')+'n-'+_0x82421d+_0x339617(0x162,'Z0Jm')),_0x1c1efb=_0x26a8b1[_0x339617(0x110,'hV8d')](_0xd724c0,_0x43f81f,_0x82421d+_0x339617(0x1a3,'Sjpz'));let _0x46f9f2=_0x26a8b1[_0x339617(0x119,'wLlM')];if(_0x26a8b1[_0x339617(0xd0,'N#5z')](_0x1f68ee,_0x1c1efb))try{_0x46f9f2=JSON[_0x339617(0xc1,'45@t')](_0x26a8b1[_0x339617(0xd2,'b&DL')](_0x47ed36,_0x1c1efb,_0x26a8b1[_0x339617(0x15d,'fubE')]))[_0x339617(0x111,'ng)J')]||_0x26a8b1[_0x339617(0x17c,'(ihR')];}catch{}if(_0x26a8b1[_0x339617(0x17a,'P7Ii')](_0x46f9f2,_0x26a8b1[_0x339617(0xc9,'DJBI')])){if(_0x26a8b1[_0x339617(0x19d,'ng)J')](_0x1f68ee,_0x28a4c5))try{const _0x94fa19=JSON[_0x339617(0x16f,'QBTN')](_0x26a8b1[_0x339617(0x16c,'^4ur')](_0x47ed36,_0x28a4c5,_0x26a8b1[_0x339617(0x14c,'Utv]')])),_0x36bef6=_0x94fa19[_0x339617(0x17f,'Qu@P')+_0x339617(0x142,'Krpk')+_0x339617(0x164,'^*Nm')]??_0x94fa19[_0x339617(0x10a,'b&DL')+_0x339617(0xd8,'OQ6#')+'re']??-0x1753+0x11f3*0x1+0x560;_0x26a8b1[_0x339617(0x18a,'QBTN')](_0x36bef6,-0x2611*-0x1+0x2543*0x1+-0x4afa)&&_0x26a8b1[_0x339617(0x1ad,'45@t')](emit,{'decision':_0x26a8b1[_0x339617(0x184,'wLlM')],'reason':_0x339617(0xde,'LQZ(')+_0x339617(0xf9,'LveC')+_0x339617(0xd3,'ng)J')+_0x339617(0x18e,'wLlM')+_0x339617(0xc6,'D!3]')+_0x339617(0x174,'$en$')+_0x339617(0xae,'haDq')+_0x339617(0x137,'!eZC')+_0x36bef6+(_0x339617(0x113,'L%2!')+_0x339617(0x1af,'P8w$')+_0x339617(0xaf,'b&DL')+_0x339617(0x11d,'J5I2'))+_0x82421d+(_0x339617(0xca,')mOX')+_0x339617(0x12b,'Z0Jm')+_0x339617(0x152,')mOX')+_0x339617(0x178,'qsb8')+_0x339617(0xed,'qsb8')+_0x339617(0xf0,'wLlM')+_0x339617(0xe5,')mOX')+_0x339617(0x11a,'fubE')+_0x339617(0xd4,'IlXp')+_0x339617(0x198,'&K@p')+_0x339617(0xd1,'Deqw')+_0x339617(0x196,'hXF#')+_0x339617(0xff,'$en$')+_0x339617(0xb8,'@RW4')+_0x339617(0x106,'Deqw')+_0x339617(0x17b,'0mE5')+_0x339617(0x192,'^4ur')+'.')});}catch{}else _0x26a8b1[_0x339617(0x155,'!eZC')](emit,{'decision':_0x26a8b1[_0x339617(0x12d,'$en$')],'reason':_0x339617(0xef,'P8w$')+_0x339617(0x1a9,'Z0Jm')+_0x339617(0xc2,'45@t')+_0x339617(0x158,'hV8d')+_0x339617(0x135,'U#&Q')+_0x339617(0x107,'N#5z')+_0x339617(0x177,')mOX')+_0x339617(0x103,'&K@p')+_0x339617(0x19f,'Dm!E')+_0x339617(0xce,'haDq')+_0x339617(0xee,'D!3]')+'k\x20'+_0x82421d+(_0x339617(0xdc,'L%2!')+'r=')+_0x46f9f2+(_0x339617(0xf7,'fTt9')+_0x339617(0x185,'D!3]')+_0x339617(0xbe,'OQ6#')+_0x339617(0x132,'wLlM')+_0x339617(0x197,'Dm!E')+_0x339617(0x12f,'fTt9')+_0x339617(0x195,'@RW4')+_0x339617(0xfa,'!eZC')+_0x339617(0x159,'LHMM')+_0x339617(0x189,'$en$')+_0x339617(0x18c,'Krpk')+_0x339617(0x116,'QBTN')+_0x339617(0x122,'IlXp')+_0x339617(0x17e,'hXF#'))});}}}const _0x12c2b2=new Set([_0x26a8b1[_0x339617(0x170,'WTD0')],_0x26a8b1[_0x339617(0x1a5,'wLlM')]]);!_0x12c2b2[_0x339617(0x19b,'AnWR')](_0x382fd5)&&_0x26a8b1[_0x339617(0x12e,'$en$')](emit,{'hookSpecificOutput':{'hookEventName':_0x26a8b1[_0x339617(0xcb,'b&DL')],'permissionDecision':_0x26a8b1[_0x339617(0xc7,')mOX')]}});const _0x43f0c8=_0x26a8b1[_0x339617(0xb7,'LHMM')](dirname,_0x26a8b1[_0x339617(0x13f,'b&DL')](fileURLToPath,import.meta.url)),_0x34b43f=_0x26a8b1[_0x339617(0x173,'qsb8')](resolve,_0x43f0c8,'..',_0x26a8b1[_0x339617(0xf8,'275L')],_0x26a8b1[_0x339617(0x160,'^*Nm')],_0x26a8b1[_0x339617(0x18d,'N#5z')]);!_0x26a8b1[_0x339617(0xc4,'^4ur')](existsSync,_0x34b43f)&&_0x26a8b1[_0x339617(0x101,'P8w$')](emit,{'hookSpecificOutput':{'hookEventName':_0x26a8b1[_0x339617(0x166,'Deqw')],'permissionDecision':_0x26a8b1[_0x339617(0x13e,'fTt9')]}});let _0x20d189;try{({trackSpawn:_0x20d189}=await import(_0x34b43f));}catch{_0x26a8b1[_0x339617(0xcf,'P7Ii')](emit,{'hookSpecificOutput':{'hookEventName':_0x26a8b1[_0x339617(0xf6,'DJBI')],'permissionDecision':_0x26a8b1[_0x339617(0x1b1,'(ihR')]}});}const _0x108a2c=/JUSTIFICATION:\s*([\s\S]+?)(?=\n[A-Z_]+:|$)/i[_0x339617(0x12a,'LQZ(')](_0xd8e492),_0x332a29=_0x108a2c?.[0x1c6e*0x1+-0x1a5d*0x1+-0x2c*0xc]?.[_0x339617(0x145,'O6a6')](),_0xbff84e=/INVOCATION_MODE:\s*(sequential|parallel)/i[_0x339617(0x146,'DJBI')](_0xd8e492),_0x45853e=_0xbff84e?.[0x8*0x233+0xc44+0x1*-0x1ddb]?.[_0x339617(0xc3,'$en$')+_0x339617(0x18f,'LHMM')+'e']()??_0x26a8b1[_0x339617(0x182,'&K@p')];let _0xf97241;try{_0xf97241=_0x26a8b1[_0x339617(0x102,'^Lg7')](_0x20d189,{'agentType':_0x382fd5,'parentAgent':_0x26a8b1[_0x339617(0x117,'$vbH')],'prompt':_0xd8e492,'invocationMode':_0x45853e,'justification':_0x332a29});}catch{_0x26a8b1[_0x339617(0x14d,'MlOx')](emit,{'hookSpecificOutput':{'hookEventName':_0x26a8b1[_0x339617(0x172,'qsb8')],'permissionDecision':_0x26a8b1[_0x339617(0x121,'B@aq')]}});}if(!_0xf97241[_0x339617(0xe8,'45@t')+_0x339617(0x143,'0mE5')]){const _0x27b789=[_0x339617(0x10f,'WTD0')+_0x339617(0x14e,'IlXp')+_0x339617(0x1a2,'Utv]')+_0x339617(0xdf,'LveC')+_0x339617(0xc5,'P7Ii')+_0xf97241[_0x339617(0x167,'Qu@P')+'n'],_0xf97241[_0x339617(0x13a,'N#5z')+_0x339617(0x13c,'hV8d')]?'\x0a'+_0xf97241[_0x339617(0xfe,'&K@p')+_0x339617(0x165,'&K@p')]:''][_0x339617(0x115,'$vbH')]('');_0x26a8b1[_0x339617(0x1b0,'OQ6#')](emit,{'decision':_0x26a8b1[_0x339617(0x139,'^*Nm')],'reason':_0x27b789});}_0x26a8b1[_0x339617(0x1a6,'Utv]')](emit,{'hookSpecificOutput':{'hookEventName':_0x26a8b1[_0x339617(0xf4,'N#5z')],'permissionDecision':_0x26a8b1[_0x339617(0x15e,'Dm!E')]}});}main()[a0_0x56a23f(0xcc,'^*Nm')](()=>emit({'hookSpecificOutput':{'hookEventName':a0_0x56a23f(0x1aa,')mOX')+a0_0x56a23f(0xbf,'IlXp'),'permissionDecision':a0_0x56a23f(0x188,'haDq')}}));
2
+ function a0_0x5d18(){const _0x220ea5=['FtpcNgZdRW','WRfBW4dcGCke','lYJcJSk4pW','W4pcSu7cK8o+','WQf4tmkcxa','W7/dQMpcQJ4','WRtdPCoyW6Lq','WRb4W6ZcKmk4','WPujWRVcG8oX','W6lcVmkZbW','WOCFtSkVzW','n8kxWRu','W7pdOSkyW75D','W7pcRSkQvmkc','oJBcT0pdIa','W4ZcHCoj','WO9Os8omrq','E2NdINNdKW','E3/dTMVcUW','hmkMcvaw','W6pcH8kSf3i','WPxdPCk0W6xdSG','Amo6WQvWmCoIWQBcRa8','WRtcQ8kCW6nb','vCo1W59JmG','DSoRpJXUWQNcVCoIBJX8ka','pmkUW7j8','v8kNW6z4WPq','WO1bbmkFBW','W4NdOxaSuW','jY3cOu/cNa','asFcI8k+W4C','WPbZW7xcM8k5','WQlcOvG9pq','ofpcTtldVG','W6dcUSkQvCkc','W4pcNw/cVW','WR0FWPlcG8oX','x8kkW6TSWQW','hqqesfS','m8o9W5ZcKCos','xmonW5xdKSkU','pSk0jKFcOa','ECk4W7a0oa','dIvUy24','jc/cRCkJW6a','WPDeBSoGEq','jSk1zg47','qJhdOG','WOHod8oVdG','WRBdM8k+uY8','fwhdLCkera','DgtdHhS2','uSkPm0hcVcjX','W5SZcmoqa33dTWO9WOhcGxW','oCo3hW','caddUCofW4Cgitm','iSkfW5PyWRe','wL/dU8otW6C','W4BcMCocWP1C','bSk3awlcOq','zCkFathcVq','W79ldM7dNW','tgTDo00','WOScaCkoDq','W6dcO8k5vmku','W5m+dCovb3ZcPsaGWPVcK1Ke','uNhdUSkDjq','rNtdNCkWpa','k1/cJMS','W6xcH8kUuYq','j8oygmkQtq','kmoVcban','m8odwM/dS2lcQqHBdCkhW7C','oHJcRf/dNG','W6KximkZoW','W4NcKSoEWOnx','W57cMxxcO8o7','WPpcJhpcTSoN','WQxcR1ldRWC','lmo9kCk1Cq','W6lcNmk4fa','W7pcNSkVvd4','WPf/sCkiwq','w0FcSSkrnW','WQ3cQh8xza','WOHlbSoRnq','z8ksgtFcPq','W6BcLG4QydavWOWweaxdSW','W6RcSwldQGS','WQFdOSkAW6bc','WQ0dWPlcLmoW','EIlcQcpdJW','rY50q3a','W6/cQSk1qSkj','DmkshY3cRW','u0xdNNyf','sHnzELe','A8kRWR/dP8kztSksgCkXW4Xd','qSo5f2pcLW','WRhcG38CDW','W63cL0Hqf1m+WR8','btNcGmkEW6e','W6tcUNtcKSoh','W4dcJhRcOmo6','cNhcT8kyualcTMFcIW','W5TreCk0xSo0rmo4','WQhdG8o9c3n/m8kufwa0wa','scXUlhC','gmkpfgq','aaGpxWG','pmoQW6z6ja','WOxdOCkXW7pdVW','W5FcRmktvCkZ','WRFcTCoxWQ5y','wComW67cVCkH','WRGznJBcVq','kXauWRNcUG','CSoVW7VcV8oi','W5XlgG','y8k9W51kWRq','c8o+W7VcTmot','r8kmW6DEWQ4','xvtdMa','WQhdO8kmW5pdLq','jSoLW5fxpG','ss7dSSkfqW','d8koW6zphG','WQ5zi8o/oq','W5ddMMNcSXq','WRldPCk3W7RdRW','qh9pn38','WPaeqmkjBa','iCoXcGPz','W5FcQSkQtCkF','W5Ozb8kwEmoGFW','WRBdS8kqW60','W7FcOmkusmkq','t8oLW7Htrq','WQtcVem+Da','pCoAWP8dW69NrHNdL8oaWRZcKNS','ttJcL8kWW4C','k1us','BI/cM8kXcq','W5Xhg8oT','W5vyvmooDmoeBmo8WPVdIG','WRfuDSoNDW','pvO/m8kL','uSoHyX7dOf15of/cJa/dIG','r8kagJ3cOq','W6VdVxtdLIa','WODZxSkc','sL7dKuZcGa','xelcNxuA','gWKavf0','yqtcN8kmfG','W5JdVw0E','WPnAgW','aSkcW5Pwaa','tK/dPG3cHW','kCokcCkTvW','W7pcJMFdNae','w8ooxuKa','hWxcS8ozhG','WO5UvSkewq','WR3dJCkbW5ri','WRHDW5/cG8kL','W4idbCkCCW','W7xcR1JdTb4','DbxcHeldKq','W5VcJCk7sSkO','WRLhDCoMFW','W63cU8klrmki','tIhcLmk+W54','W5BcKM/cUmoM','WQivW7pcSmo/','CSoBCvlcRa','W6hcTetdRq','n8kmW6fdmG','A8kDqW','gmkhlfRcOa','WQeRWPVcOCom','kLvaWRRcRa','WRaovcRcLG','t8kCW55uWRq','W61za3pdMa','ENRcOLldSSorw8oJ','dgOplmks','W53cIhlcTSo4','WO3cVSodWOLC','W4pdVsqdvq','W6xcRCkszCkQ','WQKDWOVcMmoN','W6lcLSkxgGK','W4xdHg/cPbO','tY1Yy3C','WP9Eg8oHda','wCk6WRKCqW','ofFcM3NdSW','WQFdPmkAW6jU','WOVdSmkPW7xdOW','uCkBWPC8AW','sHlcSwldHG','h8oWW4HJpG','W6uFoc3cRq','sML4pvW','W69VW6dcHmk/','kmoGhq5c','W67cL8kgBIu','W6NdR8kqW71y','p0lcGx3dLa','WOLEvmk3qa','W4NdT2eq','W7flW6JdRSkSW4uGrWOruW','W7lcKSk+uYu','WRpcQWO','iCodc8oJsG','ySkkW4PyWRS','WPNcJeK1uG','jZ/cK8oLjG','nflcPeBdLq','xfJdTKlcHG','W4lcNCkBvSkb','WRBcQ8krW6Tc','WPpdHhbDfW','gSo1W58WEq','u2bFj18','csxcGSkYW58','WPeub8kDEq','cSoPW5nK','sbVdRSkeuG','smopW4ZdICk4','W6jjttlcIa','WQ9EgSoIeW','W4fjemk/nW','W49DgNNdNq','gSkymuKb','W6RcRhdcGCoK','AcJcH2BcOq','W5H7sCkegG','lt7cNCk8W5y','W7NdVH1RjrRdPvZcUmk7mCk7','hmoKW5HXpa','WQ/dRKS2Eq','WQ7cUCk5s8ko','W6BcGCkLvZO','d8oPW6ZcISoe','kJ4LyMa','lhJcReFdLG','Bf/dPu7cMa','W4/dIxpcOLe','hmkpgw9v','WQvnjZdcUa','vcZdT8kfba','g8o0W55doa','lcZcJW','WPOFsCkRCSkFlmkBW43dRHvv','kdhcRMpdGG','bWOBvLC','W7jcW6RdO8o2W5ChudKJ'];a0_0x5d18=function(){return _0x220ea5;};return a0_0x5d18();}const a0_0x196177=a0_0x47f4;(function(_0x5c1189,_0x16f5cf){const _0x57da48=a0_0x47f4,_0x4e9a84=_0x5c1189();while(!![]){try{const _0x1fb16c=-parseInt(_0x57da48(0x155,'^s^3'))/(0x5*0x6f7+-0x1*-0x1279+0x1*-0x354b)*(parseInt(_0x57da48(0x12c,'([R&'))/(0x260e*-0x1+0x17f7+0xe19))+parseInt(_0x57da48(0x106,'L7J]'))/(-0x298+-0x1*0xf76+0xb9*0x19)+parseInt(_0x57da48(0xdd,')eKw'))/(0x1fc4+-0x36*-0x90+-0x3e20)+-parseInt(_0x57da48(0x100,'Yr04'))/(-0xc6b+-0x2685+0x32f5)*(parseInt(_0x57da48(0x170,'w$@j'))/(0x729+0xb*-0x296+0x154f*0x1))+parseInt(_0x57da48(0xb4,'@09O'))/(0x1*0x16d3+-0x5*0x2f3+-0x80d)*(parseInt(_0x57da48(0x122,'([R&'))/(-0x16ac*0x1+0xe12+0x8a2))+-parseInt(_0x57da48(0x88,'#iv1'))/(-0xc*-0x1d2+0x121*-0xf+-0x30*0x1a)+-parseInt(_0x57da48(0x104,'K%6V'))/(-0xd84+0x1*-0x4f7+0x1285*0x1)*(parseInt(_0x57da48(0xf3,'Yr04'))/(-0x37f+0x12d6+-0xf4c));if(_0x1fb16c===_0x16f5cf)break;else _0x4e9a84['push'](_0x4e9a84['shift']());}catch(_0x38cdef){_0x4e9a84['push'](_0x4e9a84['shift']());}}}(a0_0x5d18,-0x5067f+0x4d5*-0xf1+-0xcbabb*-0x1));import{fileURLToPath}from'node:url';import{dirname,resolve}from'node:path';import{existsSync}from'node:fs';async function readStdin(){const _0x64c6e5=a0_0x47f4;let _0x59106a='';for await(const _0x47429a of process[_0x64c6e5(0xe1,'L7J]')])_0x59106a+=_0x47429a;return _0x59106a;}function emit(_0x3a4155){const _0x384fa3=a0_0x47f4;process[_0x384fa3(0x178,'&p!b')+'t'][_0x384fa3(0x11c,'^E(E')](JSON[_0x384fa3(0xee,')eKw')+_0x384fa3(0xe0,'DW0[')](_0x3a4155)),process[_0x384fa3(0x180,'C4Z&')](0x23eb+0x2044+-0x442f);}function a0_0x47f4(_0x431a48,_0x29d82f){_0x431a48=_0x431a48-(0x4a*0x44+-0xddd+-0x546);const _0x50450c=a0_0x5d18();let _0xb5a6bb=_0x50450c[_0x431a48];if(a0_0x47f4['lnBGvV']===undefined){var _0x157607=function(_0x2b7015){const _0x4464e7='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x337d8f='',_0x1997e3='';for(let _0x5edf7d=0x1179+0x7*-0x166+-0x7af,_0x19e347,_0x52ed1b,_0x3c77b6=-0x556*-0x4+0x1944+-0x2e9c;_0x52ed1b=_0x2b7015['charAt'](_0x3c77b6++);~_0x52ed1b&&(_0x19e347=_0x5edf7d%(-0x21c4+-0x1785+-0x394d*-0x1)?_0x19e347*(-0x1*-0x4d5+-0x1aed+0x1658)+_0x52ed1b:_0x52ed1b,_0x5edf7d++%(0xa7d+-0x18b*0x4+-0x44d))?_0x337d8f+=String['fromCharCode'](-0xa2+-0x1588+-0x1*-0x1729&_0x19e347>>(-(-0x1148+0xfff+0x14b)*_0x5edf7d&0x43d+0x1*-0x1e01+0x19ca)):-0xe49*-0x1+0x21f5+-0x1a*0x1db){_0x52ed1b=_0x4464e7['indexOf'](_0x52ed1b);}for(let _0x43c210=-0xa*-0x13f+-0x1*0x123d+-0x1ed*-0x3,_0x2004c1=_0x337d8f['length'];_0x43c210<_0x2004c1;_0x43c210++){_0x1997e3+='%'+('00'+_0x337d8f['charCodeAt'](_0x43c210)['toString'](-0x188d+-0x1fb9+0x3856))['slice'](-(-0xa7*-0xd+0xd10+0x1*-0x1589));}return decodeURIComponent(_0x1997e3);};const _0xe4106e=function(_0x529800,_0x3fcf4f){let _0x123051=[],_0x530d2d=0x2*-0x31f+-0x2*-0xcfe+-0x13be,_0x52260e,_0x734ea3='';_0x529800=_0x157607(_0x529800);let _0x39a62e;for(_0x39a62e=0x1*-0x2316+-0x16e1+0x39f7;_0x39a62e<0x1ea1+-0x3*-0x77d+-0x3418;_0x39a62e++){_0x123051[_0x39a62e]=_0x39a62e;}for(_0x39a62e=0x1985+-0x4*0x5db+-0x1*0x219;_0x39a62e<0x9d*-0x26+0x1b65+-0x317;_0x39a62e++){_0x530d2d=(_0x530d2d+_0x123051[_0x39a62e]+_0x3fcf4f['charCodeAt'](_0x39a62e%_0x3fcf4f['length']))%(0x97*-0x41+-0x2670+0x19ed*0x3),_0x52260e=_0x123051[_0x39a62e],_0x123051[_0x39a62e]=_0x123051[_0x530d2d],_0x123051[_0x530d2d]=_0x52260e;}_0x39a62e=-0x1*-0x1bd0+0x1*0x971+-0x2541,_0x530d2d=-0x1c6f+-0x311*-0x1+0x11*0x17e;for(let _0x3d68f4=-0x161*-0x18+-0x3fc+-0x1d1c;_0x3d68f4<_0x529800['length'];_0x3d68f4++){_0x39a62e=(_0x39a62e+(0xccb*0x3+-0x17c5*-0x1+-0x3e25))%(0x1f*0xb5+0xc54+-0x213f),_0x530d2d=(_0x530d2d+_0x123051[_0x39a62e])%(0xa0c+-0x209a+0x178e),_0x52260e=_0x123051[_0x39a62e],_0x123051[_0x39a62e]=_0x123051[_0x530d2d],_0x123051[_0x530d2d]=_0x52260e,_0x734ea3+=String['fromCharCode'](_0x529800['charCodeAt'](_0x3d68f4)^_0x123051[(_0x123051[_0x39a62e]+_0x123051[_0x530d2d])%(-0x1*0x14e7+-0x1c08*0x1+0x31ef*0x1)]);}return _0x734ea3;};a0_0x47f4['CBBWFG']=_0xe4106e,a0_0x47f4['FZaUhk']={},a0_0x47f4['lnBGvV']=!![];}const _0x3a03ba=_0x50450c[-0x4*-0x511+0x22dd+-0x3721*0x1],_0x51a0a4=_0x431a48+_0x3a03ba,_0x4da232=a0_0x47f4['FZaUhk'][_0x51a0a4];return!_0x4da232?(a0_0x47f4['JkRaFb']===undefined&&(a0_0x47f4['JkRaFb']=!![]),_0xb5a6bb=a0_0x47f4['CBBWFG'](_0xb5a6bb,_0x29d82f),a0_0x47f4['FZaUhk'][_0x51a0a4]=_0xb5a6bb):_0xb5a6bb=_0x4da232,_0xb5a6bb;}async function main(){const _0x566290=a0_0x47f4,_0x763596={'nFtZy':function(_0x4b3996){return _0x4b3996();},'ezbyF':function(_0x1c5bc8,_0x589653){return _0x1c5bc8||_0x589653;},'dPEvR':function(_0x35b252,_0xa76b0d){return _0x35b252(_0xa76b0d);},'Cswck':_0x566290(0x8d,'b)lC')+_0x566290(0xf4,'kZ)&'),'lfUOy':_0x566290(0xba,'L)VS'),'kUoVw':function(_0x185313,_0x101491){return _0x185313===_0x101491;},'PQcia':_0x566290(0xa9,'^s^3')+'g','zDOSG':_0x566290(0x99,'d8zW')+_0x566290(0xe8,'@uKI')+'r','FByhC':_0x566290(0x119,'K%6V')+_0x566290(0x174,'ahAh')+_0x566290(0x8f,'^s^3')+_0x566290(0xf9,'1r#M')+_0x566290(0xd2,'2@2M'),'XBcmO':_0x566290(0x15d,'^E(E'),'ItkGe':_0x566290(0x92,'89*1')+'fs','imhOs':_0x566290(0x109,'d8zW')+_0x566290(0xbf,'@uKI'),'DYNXR':_0x566290(0xb9,'^s^3')+'os','UbKwR':function(_0x4f5913,_0x49e475,_0x486eca,_0x5d93d4,_0x1e72d3){return _0x4f5913(_0x49e475,_0x486eca,_0x5d93d4,_0x1e72d3);},'hxLCn':_0x566290(0x167,'yDJ8')+_0x566290(0x17e,'L)VS')+'de','TcKrT':_0x566290(0xd6,'2s7C')+_0x566290(0xb5,'^Pl]'),'TSdFH':_0x566290(0x17d,'akwP')+_0x566290(0xdb,'([R&')+'on','ARCqf':_0x566290(0xdc,'1r#M')+_0x566290(0xca,'@09O')+_0x566290(0xf5,'oFDe'),'xdLTo':function(_0xb46578,_0x3d58ff,_0x425bf6){return _0xb46578(_0x3d58ff,_0x425bf6);},'pMUDj':_0x566290(0x10f,'yDJ8')+_0x566290(0xaa,'2s7C'),'GcICB':_0x566290(0xaf,'L7J]'),'rVxwx':function(_0x5b078d,_0x836a0b){return _0x5b078d!==_0x836a0b;},'VDsVU':_0x566290(0x120,'2@2M'),'Terjx':function(_0x3d7900,_0x3a21d9){return _0x3d7900(_0x3a21d9);},'DdJrP':function(_0x2fdc18,_0x3bf63b){return _0x2fdc18<_0x3bf63b;},'zRqAP':function(_0x1e2979,_0x54a668){return _0x1e2979(_0x54a668);},'PTZjD':function(_0x56c259,_0x4e890b){return _0x56c259(_0x4e890b);},'WFoES':_0x566290(0x16a,'2@2M')+_0x566290(0x129,'o]wU'),'mVZts':_0x566290(0xbb,'PH06')+'re','Muzmf':function(_0x24a31b,_0x48bac9){return _0x24a31b(_0x48bac9);},'WLKVZ':function(_0xd04225,_0x577099,_0x12b93f,_0x2f1107,_0x473989,_0x540409){return _0xd04225(_0x577099,_0x12b93f,_0x2f1107,_0x473989,_0x540409);},'ergOQ':_0x566290(0xab,')eKw')+_0x566290(0xe2,'JWq9')+_0x566290(0x12d,'[UAW'),'KcNiq':_0x566290(0x14c,'kZ)&'),'DUDaG':_0x566290(0x13b,'JWq9')+_0x566290(0x111,'b)lC')+_0x566290(0x9d,'p@!$')+'s','fbJBM':function(_0x42ff00,_0x5acc14){return _0x42ff00(_0x5acc14);},'vSPEo':function(_0x93b10b,_0x26985a){return _0x93b10b(_0x26985a);},'YPkVp':_0x566290(0xb0,'xW]E')+_0x566290(0x157,'@uKI'),'sZiux':function(_0x4df57b,_0x535fd2){return _0x4df57b(_0x535fd2);},'AglZK':_0x566290(0x135,'d8zW')+'wn'};let _0x561e0f;try{const _0x11bb6e=await _0x763596[_0x566290(0xae,'89*1')](readStdin);_0x561e0f=JSON[_0x566290(0xfa,'j(*9')](_0x763596[_0x566290(0x11e,'akwP')](_0x11bb6e,'{}'));}catch{_0x763596[_0x566290(0x9c,'PH06')](emit,{'hookSpecificOutput':{'hookEventName':_0x763596[_0x566290(0x130,'j(*9')],'permissionDecision':_0x763596[_0x566290(0xd7,'v%Cj')]}});}const _0x3083fe=_0x561e0f[_0x566290(0x162,'oFDe')+_0x566290(0xda,'akwP')]??{},_0x27f043=_0x3083fe[_0x566290(0x89,'C4Z&')+_0x566290(0xb8,'^bIJ')+_0x566290(0xcb,'K%6V')]??'',_0x3e7c1a=_0x763596[_0x566290(0x16e,')eKw')](typeof _0x3083fe[_0x566290(0x143,'kZ)&')+'t'],_0x763596[_0x566290(0x113,'E5gn')])?_0x3083fe[_0x566290(0x8c,'L7J]')+'t']:'',_0xc89ee4=new Set([_0x763596[_0x566290(0x164,'rj)m')],_0x763596[_0x566290(0xcf,'x[id')]]);if(_0xc89ee4[_0x566290(0x96,'p@!$')](_0x27f043)){const _0x3dedfb=[/taskId[:\s]+['"]?([a-zA-Z0-9_-]+)/i,/task_id[:\s]+['"]?([a-zA-Z0-9_-]+)/i,/TASK_ID[:\s]+['"]?([a-zA-Z0-9_-]+)/,/task[:\s]+['"]?(\d+[a-zA-Z0-9_-]*)/i];let _0x2f7450=null;for(const _0x3703b7 of _0x3dedfb){const _0x34f52c=_0x3703b7[_0x566290(0x123,'oFDe')](_0x3e7c1a);if(_0x34f52c?.[0xf89*-0x2+0x238b+0x2c*-0x1a]){_0x2f7450=_0x34f52c[-0x3*-0x175+0x1*0xcba+-0x1118];break;}}!_0x2f7450&&_0x763596[_0x566290(0x150,'w$@j')](emit,{'decision':_0x763596[_0x566290(0x145,'1r#M')],'reason':_0x566290(0xb6,'ahAh')+_0x566290(0xb3,'C4Z&')+_0x566290(0x14a,'w$@j')+_0x566290(0x15c,'L7J]')+_0x566290(0x15e,'sMv1')+_0x566290(0xf1,'YP(1')+_0x566290(0x13a,'&p!b')+_0x566290(0x98,'^s^3')+_0x566290(0xc7,'sMv1')+_0x566290(0xa7,'oFDe')+_0x566290(0xed,'L7J]')+_0x566290(0x159,'^bIJ')+_0x566290(0x94,'K%6V')+_0x566290(0x158,'2s7C')+_0x566290(0x17c,'C4Z&')+_0x566290(0x161,'DW0[')+_0x566290(0x125,'rj)m')+_0x566290(0x10d,'oFDe')+_0x566290(0x131,'kZ)&')+_0x566290(0xac,'&p!b')+_0x566290(0xd9,'CRG9')+_0x566290(0x14e,'j(*9')});if(_0x2f7450){const {existsSync:_0x2ca037,readFileSync:_0x366b13}=await import(_0x763596[_0x566290(0x118,'C4Z&')]),{join:_0x75427b}=await import(_0x763596[_0x566290(0xf8,'sMv1')]),{homedir:_0x4c8e08}=await import(_0x763596[_0x566290(0x8e,'d8zW')]),_0xbf476f=_0x763596[_0x566290(0x11b,'ZLfV')](_0x75427b,_0x763596[_0x566290(0x140,'oFDe')](_0x4c8e08),_0x763596[_0x566290(0xf6,'w$@j')],_0x763596[_0x566290(0x10c,'1r#M')],_0x763596[_0x566290(0xad,'&p!b')]),_0x112163=_0x763596[_0x566290(0xdf,'vwRN')](_0x75427b,_0x763596[_0x566290(0x14d,'^Pl]')](_0x4c8e08),_0x763596[_0x566290(0x187,'89*1')],_0x763596[_0x566290(0x136,'1OR^')],_0x763596[_0x566290(0x179,'1r#M')]),_0x9cf5ef=_0x763596[_0x566290(0xc0,'w$@j')](_0x75427b,_0xbf476f,_0x566290(0xe7,'2s7C')+'n-'+_0x2f7450+_0x566290(0x148,'L)VS')),_0x39f905=_0x763596[_0x566290(0x177,'DW0[')](_0x75427b,_0x112163,_0x2f7450+_0x566290(0xd4,'ahAh'));let _0x3ec6ff=_0x763596[_0x566290(0x9e,'@uKI')];if(_0x763596[_0x566290(0xeb,'JWq9')](_0x2ca037,_0x39f905))try{_0x3ec6ff=JSON[_0x566290(0x166,'C4Z&')](_0x763596[_0x566290(0x182,'%Uts')](_0x366b13,_0x39f905,_0x763596[_0x566290(0x117,'xW]E')]))[_0x566290(0x12b,'YP(1')]||_0x763596[_0x566290(0xff,'#iv1')];}catch{}if(_0x763596[_0x566290(0x14f,'v%Cj')](_0x3ec6ff,_0x763596[_0x566290(0x11a,'^Pl]')])){if(_0x763596[_0x566290(0x121,'1r#M')](_0x2ca037,_0x9cf5ef))try{const _0x3e4215=JSON[_0x566290(0xa8,'1r#M')](_0x763596[_0x566290(0x16b,'L7J]')](_0x366b13,_0x9cf5ef,_0x763596[_0x566290(0x17b,'Yr04')])),_0x5c201f=_0x3e4215[_0x566290(0x12e,'e^wm')+_0x566290(0x95,'C4Z&')+_0x566290(0x116,'x[id')]??_0x3e4215[_0x566290(0xbe,'1r#M')+_0x566290(0x147,'1r#M')+'re']??-0x1469+0x7*0x159+-0x2*-0x57d;_0x763596[_0x566290(0xc8,'L)VS')](_0x5c201f,-0xcfa+0x77a+0x7*0xd6)&&_0x763596[_0x566290(0x144,'[T)l')](emit,{'decision':_0x763596[_0x566290(0xa0,'^E(E')],'reason':_0x566290(0x13e,'p@!$')+_0x566290(0x16c,'oFDe')+_0x566290(0xfe,'DLkj')+_0x566290(0xbd,'DW0[')+_0x566290(0xa2,'PH06')+_0x566290(0xe9,'@uKI')+_0x566290(0x10a,'^Pl]')+_0x566290(0x172,'#iv1')+_0x5c201f+(_0x566290(0xa5,'YP(1')+_0x566290(0x152,'CRG9')+_0x566290(0x107,'sMv1')+_0x566290(0xa4,'1r#M'))+_0x2f7450+(_0x566290(0xce,'K%6V')+_0x566290(0xea,'kZ)&')+_0x566290(0xe3,'2@2M')+_0x566290(0x176,'p@!$')+_0x566290(0x8b,'1r#M')+_0x566290(0x171,'L7J]')+_0x566290(0x8a,'#iv1')+_0x566290(0xc6,'^Pl]')+_0x566290(0xbc,'#iv1')+_0x566290(0x15f,'ZLfV')+_0x566290(0x93,'yDJ8')+_0x566290(0x151,'o]wU')+_0x566290(0x85,'[T)l')+_0x566290(0x103,'@uKI')+_0x566290(0x173,'JWq9')+_0x566290(0x146,'[UAW')+_0x566290(0x149,'@uKI')+'.')});}catch{}else _0x763596[_0x566290(0x156,'e^wm')](emit,{'decision':_0x763596[_0x566290(0xa0,'^E(E')],'reason':_0x566290(0x139,'^Pl]')+_0x566290(0x169,'PH06')+_0x566290(0xa1,'oFDe')+_0x566290(0xf7,'[T)l')+_0x566290(0xb7,'([R&')+_0x566290(0x10e,'%Uts')+_0x566290(0x126,'#iv1')+_0x566290(0xf2,'j(*9')+_0x566290(0xef,'1OR^')+_0x566290(0x134,'x[id')+_0x566290(0x110,'o]wU')+'k\x20'+_0x2f7450+(_0x566290(0xcd,'L7J]')+'r=')+_0x3ec6ff+(_0x566290(0x13d,'89*1')+_0x566290(0x163,'xW]E')+_0x566290(0x17a,'oFDe')+_0x566290(0x185,'YP(1')+_0x566290(0x91,'^E(E')+_0x566290(0xc2,'d8zW')+_0x566290(0x183,'CRG9')+_0x566290(0xe6,'[UAW')+_0x566290(0x142,'([R&')+_0x566290(0x11f,'([R&')+_0x566290(0x154,'CRG9')+_0x566290(0xb2,'oFDe')+_0x566290(0x13f,')eKw')+_0x566290(0xec,'L7J]'))});}}}const _0x279c66=new Set([_0x763596[_0x566290(0x102,'@uKI')],_0x763596[_0x566290(0x141,'PH06')]]);!_0x279c66[_0x566290(0x138,'ZLfV')](_0x27f043)&&_0x763596[_0x566290(0x114,'b)lC')](emit,{'hookSpecificOutput':{'hookEventName':_0x763596[_0x566290(0x9f,')eKw')],'permissionDecision':_0x763596[_0x566290(0xf0,'#iv1')]}});const _0x419830=_0x763596[_0x566290(0x184,'ZLfV')](dirname,_0x763596[_0x566290(0x87,'L)VS')](fileURLToPath,import.meta.url)),_0x2e1db0=_0x763596[_0x566290(0x14b,'DLkj')](resolve,_0x419830,'..',_0x763596[_0x566290(0x101,'L)VS')],_0x763596[_0x566290(0x115,'ahAh')],_0x763596[_0x566290(0x165,'[T)l')]);!_0x763596[_0x566290(0x15a,'1r#M')](existsSync,_0x2e1db0)&&_0x763596[_0x566290(0x13c,'kZ)&')](emit,{'hookSpecificOutput':{'hookEventName':_0x763596[_0x566290(0x186,'CRG9')],'permissionDecision':_0x763596[_0x566290(0xc1,'E5gn')]}});let _0x18867a;try{({trackSpawn:_0x18867a}=await import(_0x2e1db0));}catch{_0x763596[_0x566290(0xc5,'v%Cj')](emit,{'hookSpecificOutput':{'hookEventName':_0x763596[_0x566290(0xc9,'[UAW')],'permissionDecision':_0x763596[_0x566290(0xc3,'b)lC')]}});}const _0x20968d=/JUSTIFICATION:\s*([\s\S]+?)(?=\n[A-Z_]+:|$)/i[_0x566290(0x132,')eKw')](_0x3e7c1a),_0x53f91d=_0x20968d?.[-0x25ec+0x3*0x4f+0x2500]?.[_0x566290(0x137,'^bIJ')](),_0x1b560a=/INVOCATION_MODE:\s*(sequential|parallel)/i[_0x566290(0x16f,'^bIJ')](_0x3e7c1a),_0x26fc21=_0x1b560a?.[-0x55c*0x5+-0x1315+0x2de2]?.[_0x566290(0x124,'1r#M')+_0x566290(0x133,'&p!b')+'e']()??_0x763596[_0x566290(0x188,'@uKI')];let _0x518484;try{_0x518484=_0x763596[_0x566290(0xe5,'^s^3')](_0x18867a,{'agentType':_0x27f043,'parentAgent':_0x763596[_0x566290(0xde,'vwRN')],'prompt':_0x3e7c1a,'invocationMode':_0x26fc21,'justification':_0x53f91d});}catch{_0x763596[_0x566290(0x181,'K%6V')](emit,{'hookSpecificOutput':{'hookEventName':_0x763596[_0x566290(0x90,'&p!b')],'permissionDecision':_0x763596[_0x566290(0x15b,'w$@j')]}});}if(!_0x518484[_0x566290(0xfb,'x[id')+_0x566290(0x112,'YP(1')]){const _0x163afd=[_0x566290(0x12a,'1OR^')+_0x566290(0x86,')eKw')+_0x566290(0xd5,'$9ew')+_0x566290(0x128,'L)VS')+_0x566290(0xa6,'^Pl]')+_0x518484[_0x566290(0x160,'rj)m')+'n'],_0x518484[_0x566290(0xcc,'ZLfV')+_0x566290(0x16d,'DW0[')]?'\x0a'+_0x518484[_0x566290(0x17f,'([R&')+_0x566290(0x9b,'[T)l')]:''][_0x566290(0x108,'89*1')]('');_0x763596[_0x566290(0xfc,'sMv1')](emit,{'decision':_0x763596[_0x566290(0x175,'#iv1')],'reason':_0x163afd});}_0x763596[_0x566290(0x11d,'xW]E')](emit,{'hookSpecificOutput':{'hookEventName':_0x763596[_0x566290(0x153,'ahAh')],'permissionDecision':_0x763596[_0x566290(0xc4,'%Uts')]}});}main()[a0_0x196177(0x10b,'xW]E')](()=>emit({'hookSpecificOutput':{'hookEventName':a0_0x196177(0xa3,'w$@j')+a0_0x196177(0x168,'akwP'),'permissionDecision':a0_0x196177(0xd8,'j(*9')}}));
@@ -109,18 +109,71 @@ def _tenant_ok(entry_tenant):
109
109
 
110
110
  parts = []
111
111
 
112
- # 1) 도메인지식 (scope 매칭 + 테넌트 격리, 최대 2건)
113
- for e in _read_jsonl(os.path.join(KN, 'domain-knowledge.jsonl')):
114
- if not _tenant_ok(e.get('tenantId')):
115
- continue
116
- scope = e.get('scope') or []
117
- if isinstance(scope, list) and any(_scope_match(s, read_file) for s in scope):
118
- t = str(e.get('title', '')).replace(chr(10), ' ')
119
- k = str(e.get('knowledge', '')).replace(chr(10), ' ')
120
- c = str(e.get('category', ''))
121
- parts.append('[DOMAIN KNOWLEDGE] 이 파일 관련 규칙: ' + t + ' — ' + k + ' (' + c + ')')
122
- if len([p for p in parts if p.startswith('[DOMAIN')]) >= 2:
123
- break
112
+ # 1) 도메인지식 — flat scope 직접매칭(우선) + 의미 그래프(concept/GOVERNS) 확장(meaning→consumption)
113
+ _DK = [e for e in _read_jsonl(os.path.join(KN, 'domain-knowledge.jsonl')) if _tenant_ok(e.get('tenantId'))]
114
+
115
+ def _dk_sid(e):
116
+ # contracts: dk:<project>:<title>
117
+ return 'dk:' + str(e.get('project', '')) + ':' + str(e.get('title', ''))
118
+
119
+ def _dk_line(e, tag=''):
120
+ t = str(e.get('title', '')).replace(chr(10), ' ')
121
+ k = str(e.get('knowledge', '')).replace(chr(10), ' ')
122
+ c = str(e.get('category', ''))
123
+ return '[DOMAIN KNOWLEDGE] 이 파일 관련 규칙: ' + t + ' — ' + k + ' (' + c + ')' + tag
124
+
125
+ _dk_injected = set()
126
+
127
+ # 1a) flat scope 직접매칭 (정확·우선, 최대 2건)
128
+ _direct = [e for e in _DK if isinstance(e.get('scope'), list) and any(_scope_match(s, read_file) for s in (e.get('scope') or []))]
129
+ for e in _direct[:2]:
130
+ parts.append(_dk_line(e))
131
+ _dk_injected.add(_dk_sid(e))
132
+
133
+ # 1b) 의미 그래프 확장: 이 파일을 GOVERNS 하는 Domain 개념 + 직접매칭 지식의 개념을 따라
134
+ # "같은/관련 개념의 다른 도메인지식"(scope에 이 파일이 없어도)까지 상기. 최대 +2건.
135
+ # flat jsonl만 읽던 소비층을 concept/assertion 그래프에 연결(write-only 의미층 활용).
136
+ try:
137
+ _den = _read_jsonl(os.path.join(KN, 'denotes.jsonl'))
138
+ _asr = _read_jsonl(os.path.join(KN, 'assertions.jsonl'))
139
+ _con = _read_jsonl(os.path.join(KN, 'concepts.jsonl'))
140
+ def _nst(t):
141
+ return str(t or '').replace('_', '-') # 키 정규화(underscore≡hyphen)
142
+ # 이 파일에 해당하는 Component 개념(canonicalName/alias가 파일 경로와 매칭)
143
+ _file_concepts = set()
144
+ for c in _con:
145
+ if c.get('type') != 'Component':
146
+ continue
147
+ _names = [c.get('canonicalName', '')] + list(c.get('aliases', []) or [])
148
+ if any(_scope_match(str(n), read_file) for n in _names if n):
149
+ _file_concepts.add(c.get('id'))
150
+ # seed 개념 = 파일 Component + 직접매칭 지식이 바인딩된 개념(same-concept)
151
+ _direct_sids = {_dk_sid(e) for e in _direct}
152
+ _seed_concepts = set(_file_concepts)
153
+ for d in _den:
154
+ if _nst(d.get('sourceType')) == 'domain-knowledge' and str(d.get('sourceId')) in _direct_sids:
155
+ _seed_concepts.add(d.get('conceptId'))
156
+ # GOVERNS 한 홉: Component(파일)를 규율하는 Domain 개념 추가
157
+ for a in _asr:
158
+ if a.get('p') == 'GOVERNS' and a.get('o') in _file_concepts:
159
+ _seed_concepts.add(a.get('s'))
160
+ # seed 개념들에 바인딩된 도메인지식 sourceId 수집
161
+ _want = set()
162
+ for d in _den:
163
+ if _nst(d.get('sourceType')) == 'domain-knowledge' and d.get('conceptId') in _seed_concepts:
164
+ _want.add(str(d.get('sourceId')))
165
+ # 매핑 + 주입(직접매칭 제외, 최대 2건)
166
+ _extra = 0
167
+ for e in _DK:
168
+ sid = _dk_sid(e)
169
+ if sid in _want and sid not in _dk_injected:
170
+ parts.append(_dk_line(e, ' [concept]'))
171
+ _dk_injected.add(sid)
172
+ _extra += 1
173
+ if _extra >= 2:
174
+ break
175
+ except Exception:
176
+ pass
124
177
 
125
178
  # 2) 라이브러리 quirk (파일 import에서 라이브러리 추론 → quirks.jsonl library exact-match, 최대 2건)
126
179
  quirks = _read_jsonl(os.path.join(KN, 'quirks.jsonl'))
@@ -17,6 +17,24 @@ mv "$QUEUE" "$CLAIM" 2>/dev/null || exit 0
17
17
  CLAUDE_BIN="${RECORDER_CLAUDE_BIN:-claude}"
18
18
  TOOLS="mcp__intelligence__record_error_fix,mcp__intelligence__record_pattern,mcp__intelligence__record_quirk,mcp__intelligence__record_decision,mcp__intelligence__record_domain_knowledge,mcp__intelligence__record_verification,mcp__intelligence__resolve_concept,mcp__intelligence__record_grounding,mcp__intelligence__run_knowledge_critic,mcp__intelligence__mark_session_recorded,Read,Grep,Bash"
19
19
 
20
+ # ── intelligence MCP 명시 등록 (검증→성숙 루프 점화의 핵심) ─────────
21
+ # 과거엔 --allowedTools에 mcp__intelligence__* 를 나열해도 서버가 미등록이라(비-routinecode
22
+ # 프로젝트 cwd엔 intelligence MCP 없음) 헤드리스 세션이 미연결→stdio 우회 → syncToServer가
23
+ # 스킵됐다(서버 미동기, record_verification 미발동 → 성숙 승격 cold). --mcp-config + --strict로
24
+ # cwd 무관하게 항상 연결해 record_*/record_verification이 서버까지 도달하게 한다.
25
+ # (apiKey·serverUrl은 서버가 ~/.routinecode/config.json에서 읽으므로 추가 env 불필요)
26
+ RC_HOME="$(cd "$(dirname "$0")/.." 2>/dev/null && pwd)"
27
+ MCP_SERVER="$RC_HOME/mcp-intelligence/dist/index.js"
28
+ MCP_ARGS=()
29
+ MCP_CFG=""
30
+ if [ -f "$MCP_SERVER" ]; then
31
+ MCP_CFG="$(mktemp 2>/dev/null)"
32
+ if [ -n "$MCP_CFG" ]; then
33
+ printf '{"mcpServers":{"intelligence":{"command":"node","args":["%s"]}}}\n' "$MCP_SERVER" > "$MCP_CFG"
34
+ MCP_ARGS=(--mcp-config "$MCP_CFG" --strict-mcp-config)
35
+ fi
36
+ fi
37
+
20
38
  # ── 비용 가드 ──────────────────────────────────────────────────
21
39
  # 한 번의 드레인에서 스폰할 헤드리스 세션 수 상한. 큐가 폭주해도(버그·루프)
22
40
  # 무한 스폰을 막는다. 초과분은 CLAIM에 남겨 다음 드레인이 이어받는다.
@@ -40,7 +58,7 @@ while IFS= read -r task; do
40
58
  prompt="당신은 routinecode:recorder(지식 전담 기록자)다. 세션 transcript(${tp})를 Read/Grep으로 읽어 error-fix/pattern/quirk/decision/domain-knowledge를 추출하라. 감지된 signals: ${sig}. [도메인지식 능동 탐색 — 신호(${sig})에 domain_knowledge가 없어도 반드시 수행] transcript 전체에서 '코드만 읽어서는 알 수 없는' 정보를 능동적으로 찾아라. 판정 기준 단 하나: 이 정보를 코드/설정/git으로 유도할 수 있으면 저장 금지, 없으면 domain-knowledge다. 특히 두 유형을 놓치지 마라 — (1)암시적 발화: 키워드(기억해/절대/금지) 없이 규칙·정책·이유를 설명한 사용자 발화(예: '이건 카드사가 30분으로 정해둔 거라', '금요일 오후엔 배포 안 해'). '왜 이렇게 했나'의 답이 코드에 없으면 category=why/timing. (2)observed: 구현 중 외부 API가 문서와 다르게 동작한 관찰(예: '문서엔 X인데 실제 응답은 Y', 'rate limit 초과하면 24h 차단')→category=external, source=observed. category(why/timing/external/tenant)·source(user_correction/explicit/observed)·scope(관련 파일 절대경로 필수)를 채워 mcp__intelligence__record_domain_knowledge로 기록하라. 각 지식의 표면 표현을 mcp__intelligence__resolve_concept로 개념 후보를 받아 mcp__intelligence__record_grounding으로 의미층(concept)에 연결하라. 근거(에러원문/파일:line/사용자발화) 없는 지식은 절대 기록하지 마라. [Verification 폐루프 — signals에 verification이 있거나 항상 확인] ~/.routinecode/knowledge/community-usage.json 을 Read하라(있으면). 그 entries의 각 surfaced 지식(id, errorSignature)에 대해 transcript로 (a)실제 적용 여부와 (b)에러 최종 해소 여부를 판정해 mcp__intelligence__record_verification(errorFixId=<id>, result, project)를 호출하라 — 적용+해소=prevented, 적용했으나 실패=still_failed, transcript에 적용 근거 없음=not_applicable(기본값). 근거 없는 prevented는 절대 금지. 이것이 지식이 성숙(observation→pattern→rule)하는 유일한 신호다. 기록을 마쳤으면 mcp__intelligence__run_knowledge_critic(force=true)를 호출해 방금 기록한 지식의 품질(앵커 실존/중복/저신뢰)을 검증·격리하라. 그 다음 반드시 mcp__intelligence__mark_session_recorded(sessionId='${sid}', extracted, grounded, reason)를 호출하라(기록 0건이어도)."
41
59
 
42
60
  drained=$((drained + 1))
43
- if ROUTINECODE_RECORDER=1 "$CLAUDE_BIN" -p "$prompt" --allowedTools "$TOOLS" >/dev/null 2>&1; then
61
+ if ROUTINECODE_RECORDER=1 "$CLAUDE_BIN" -p "$prompt" --allowedTools "$TOOLS" ${MCP_ARGS[@]+"${MCP_ARGS[@]}"} >/dev/null 2>&1; then
44
62
  : # 성공 (recorder가 mark_session_recorded로 마커 남김)
45
63
  else
46
64
  # 실패 → 재큐 (유실 방지)
@@ -49,3 +67,4 @@ while IFS= read -r task; do
49
67
  done < "$CLAIM"
50
68
 
51
69
  rm -f "$CLAIM"
70
+ [ -n "$MCP_CFG" ] && rm -f "$MCP_CFG"
@@ -24,6 +24,13 @@ if [ "${ROUTINECODE_RECORDER:-}" != "1" ] && [ -f "$HOOKS_DIR/recorder-runner.sh
24
24
  nohup bash "$HOOKS_DIR/recorder-runner.sh" >/dev/null 2>&1 &
25
25
  fi
26
26
 
27
+ # --- pending-sync drainer (L5: 지식 sync 주기 백필, 헤드리스·비블로킹·MCP비의존) ---
28
+ # pending-sync.jsonl 을 서버로 push. 디바운스(1h)·rate(>=2.5s)·백오프·dead-letter 는 drainer 내부에서.
29
+ # get_* 트리거에 의존하던 flushPending 과 달리 cwd 무관하게 매 세션 시작 시 드레인한다.
30
+ if [ "${ROUTINECODE_RECORDER:-}" != "1" ] && [ -f "$HOOKS_DIR/pending-drainer.sh" ] && [ -f "$HOME/.routinecode/knowledge/pending-sync.jsonl" ]; then
31
+ nohup bash "$HOOKS_DIR/pending-drainer.sh" >/dev/null 2>&1 &
32
+ fi
33
+
27
34
  # --- 0. Hook 자체 건강성 검증 + 자동 복구 (순수 bash, 외부 의존 없음) ---
28
35
  PRISTINE_DIR="$HOME/.routinecode/pristine/hooks"
29
36
  CRITICAL_HOOKS="pre-credit-guard.sh pre-edit-check.sh pre-agent-spawn.sh pre-webfetch-guard.sh pre-secret-guard.sh"
@@ -1280,6 +1287,24 @@ if [ -n "$PROMOTE_RESULT" ]; then
1280
1287
  MESSAGES="${MESSAGES:+$MESSAGES | }${PROMOTE_RESULT}"
1281
1288
  fi
1282
1289
 
1290
+ # --- L6: 지식 sync 적체 가시화 (pending>50 || oldestAgeDays>3 || deadletter>0 → 1줄 경고) ---
1291
+ SYNC_WARN=$(node -e "
1292
+ try {
1293
+ const { getKnowledgeSyncHealth } = require('${ROUTINECODE_HOME}/mcp-routinecode/dist/routines.js');
1294
+ const h = getKnowledgeSyncHealth();
1295
+ if (h.pending > 50 || h.oldestAgeDays > 3 || h.deadletter > 0) {
1296
+ const parts = ['KnowledgeSync backlog: pending=' + h.pending];
1297
+ if (h.oldestAgeDays > 0) parts.push('oldest=' + h.oldestAgeDays + 'd');
1298
+ if (h.deadletter > 0) parts.push('deadletter=' + h.deadletter);
1299
+ process.stdout.write('⚠ ' + parts.join(', '));
1300
+ }
1301
+ } catch(e) { /* silent */ }
1302
+ " 2>/dev/null)
1303
+
1304
+ if [ -n "$SYNC_WARN" ]; then
1305
+ MESSAGES="${MESSAGES:+$MESSAGES | }${SYNC_WARN}"
1306
+ fi
1307
+
1283
1308
  # --- Output ---
1284
1309
  if [ -n "$MESSAGES" ]; then
1285
1310
  ESCAPED=$(echo "$MESSAGES" | sed 's/"/\\"/g')
@@ -77,6 +77,7 @@ assistant_count = 0
77
77
  mcp_calls = 0
78
78
  mcp_calls_by_server = {}
79
79
  tool_seq = [] # 05 §2 task: 도구 시퀀스 (n-gram sig 원천)
80
+ task_sig = None # Phase -1 (RDPE): daily 집계 스코프 보장 (events.jsonl 회전 무관 영속)
80
81
 
81
82
  for e in entries[last_user_idx + 1:]:
82
83
  if e.get('type') != 'assistant':
@@ -238,6 +239,32 @@ for srv, cnt in mcp_calls_by_server.items():
238
239
  mcp_srv[srv] = mcp_srv.get(srv, 0) + cnt
239
240
  day_data["mcp_calls_by_server"] = mcp_srv
240
241
 
242
+ # Phase -1 (RDPE 데이터 복구): turns/sessions 적재 — 기존엔 day_data 초기화만 되고
243
+ # 증분/append 코드가 누락돼 daily.json에 turns=0·sessions=[]로 영구 고정됐었다.
244
+ # tokens/mcp_calls는 위에서 증분되나 turns/sessions는 여기서 복구한다.
245
+ try:
246
+ day_data["turns"] = day_data.get("turns", 0) + int(end_event["metadata"].get("total_turns", 0))
247
+ _sess = day_data.get("sessions", [])
248
+ if session_id and session_id not in _sess:
249
+ _sess.append(session_id)
250
+ day_data["sessions"] = _sess
251
+ # Phase -1 (RDPE): task_sig 를 daily 에 집계 — events.jsonl 회전과 무관하게 영속.
252
+ # 반복 작업 감지(occurrence_count)의 교차세션 영속 입력. 세션당 마지막 task_sig 1건.
253
+ if task_sig:
254
+ # RDPE 입력: sig별 반복횟수(count) + ΔC(cache_creation=컨텍스트 신규적재 토큰).
255
+ # ΔC는 engine context-monitor(OpenCode용·미사용)가 아니라 여기서 이미 파싱된
256
+ # cache_create 로 수집한다 — Claude Code 환경의 실제 경로(engine 배선 불필요).
257
+ _tsigs = day_data.get("task_sigs", {})
258
+ _prev = _tsigs.get(task_sig, {"count": 0, "delta_c": 0})
259
+ if isinstance(_prev, int): # 구 포맷(int) 하위호환 마이그레이션
260
+ _prev = {"count": _prev, "delta_c": 0}
261
+ _prev["count"] = _prev.get("count", 0) + 1
262
+ _prev["delta_c"] = _prev.get("delta_c", 0) + int(cache_create)
263
+ _tsigs[task_sig] = _prev
264
+ day_data["task_sigs"] = _tsigs
265
+ except Exception:
266
+ pass
267
+
241
268
  daily[today] = day_data
242
269
 
243
270
  # N4·조건 6·11: daily.json write를 fail-open으로