@intutic/sync-daemon 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/README.md +1 -1
  2. package/dist/agentReporter.d.ts +23 -11
  3. package/dist/agentReporter.d.ts.map +1 -1
  4. package/dist/agentReporter.js +20 -13
  5. package/dist/agentReporter.js.map +1 -1
  6. package/dist/configReader.d.ts +1 -3
  7. package/dist/configReader.d.ts.map +1 -1
  8. package/dist/configReader.js +0 -2
  9. package/dist/configReader.js.map +1 -1
  10. package/dist/configWriter.d.ts +11 -12
  11. package/dist/configWriter.d.ts.map +1 -1
  12. package/dist/configWriter.js +35 -58
  13. package/dist/configWriter.js.map +1 -1
  14. package/dist/disconnect/harnesses.d.ts +0 -2
  15. package/dist/disconnect/harnesses.d.ts.map +1 -1
  16. package/dist/disconnect/harnesses.js +157 -80
  17. package/dist/disconnect/harnesses.js.map +1 -1
  18. package/dist/disconnect/index.d.ts.map +1 -1
  19. package/dist/disconnect/index.js +11 -1
  20. package/dist/disconnect/index.js.map +1 -1
  21. package/dist/disconnect/mcp.d.ts +21 -0
  22. package/dist/disconnect/mcp.d.ts.map +1 -1
  23. package/dist/disconnect/mcp.js +71 -0
  24. package/dist/disconnect/mcp.js.map +1 -1
  25. package/dist/disconnect/recognise.d.ts +2 -2
  26. package/dist/disconnect/recognise.d.ts.map +1 -1
  27. package/dist/disconnect/recognise.js +15 -5
  28. package/dist/disconnect/recognise.js.map +1 -1
  29. package/dist/harness/aiderConfigMerger.d.ts +28 -8
  30. package/dist/harness/aiderConfigMerger.d.ts.map +1 -1
  31. package/dist/harness/aiderConfigMerger.js +59 -11
  32. package/dist/harness/aiderConfigMerger.js.map +1 -1
  33. package/dist/harness/antigravityCliHooks.d.ts +61 -0
  34. package/dist/harness/antigravityCliHooks.d.ts.map +1 -0
  35. package/dist/harness/antigravityCliHooks.js +207 -0
  36. package/dist/harness/antigravityCliHooks.js.map +1 -0
  37. package/dist/harness/antigravityHooks.d.ts +12 -2
  38. package/dist/harness/antigravityHooks.d.ts.map +1 -1
  39. package/dist/harness/antigravityHooks.js +36 -16
  40. package/dist/harness/antigravityHooks.js.map +1 -1
  41. package/dist/harness/antigravityProducts.d.ts +40 -0
  42. package/dist/harness/antigravityProducts.d.ts.map +1 -0
  43. package/dist/harness/antigravityProducts.js +109 -0
  44. package/dist/harness/antigravityProducts.js.map +1 -0
  45. package/dist/harness/claudeAgentsMd.d.ts +29 -0
  46. package/dist/harness/claudeAgentsMd.d.ts.map +1 -0
  47. package/dist/harness/claudeAgentsMd.js +80 -0
  48. package/dist/harness/claudeAgentsMd.js.map +1 -0
  49. package/dist/harness/claudeCodeHooks.d.ts +6 -5
  50. package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
  51. package/dist/harness/claudeCodeHooks.js +98 -24
  52. package/dist/harness/claudeCodeHooks.js.map +1 -1
  53. package/dist/harness/clineHooks.d.ts +0 -1
  54. package/dist/harness/clineHooks.d.ts.map +1 -1
  55. package/dist/harness/clineHooks.js +10 -4
  56. package/dist/harness/clineHooks.js.map +1 -1
  57. package/dist/harness/codexHooks.d.ts +2 -0
  58. package/dist/harness/codexHooks.d.ts.map +1 -1
  59. package/dist/harness/codexHooks.js +12 -4
  60. package/dist/harness/codexHooks.js.map +1 -1
  61. package/dist/harness/cursorHooks.d.ts +5 -2
  62. package/dist/harness/cursorHooks.d.ts.map +1 -1
  63. package/dist/harness/cursorHooks.js +9 -3
  64. package/dist/harness/cursorHooks.js.map +1 -1
  65. package/dist/harness/dshHooks.d.ts +5 -5
  66. package/dist/harness/dshHooks.d.ts.map +1 -1
  67. package/dist/harness/dshHooks.js +5 -5
  68. package/dist/harness/gateArtifacts.d.ts +35 -0
  69. package/dist/harness/gateArtifacts.d.ts.map +1 -0
  70. package/dist/harness/gateArtifacts.js +88 -0
  71. package/dist/harness/gateArtifacts.js.map +1 -0
  72. package/dist/harness/gateBody.d.ts +186 -69
  73. package/dist/harness/gateBody.d.ts.map +1 -1
  74. package/dist/harness/gateBody.js +820 -182
  75. package/dist/harness/gateBody.js.map +1 -1
  76. package/dist/harness/gateSightings.d.ts +47 -0
  77. package/dist/harness/gateSightings.d.ts.map +1 -0
  78. package/dist/harness/gateSightings.js +159 -0
  79. package/dist/harness/gateSightings.js.map +1 -0
  80. package/dist/harness/githubCopilotHooks.d.ts.map +1 -1
  81. package/dist/harness/githubCopilotHooks.js +7 -1
  82. package/dist/harness/githubCopilotHooks.js.map +1 -1
  83. package/dist/harness/gooseHardener.d.ts +0 -1
  84. package/dist/harness/gooseHardener.d.ts.map +1 -1
  85. package/dist/harness/gooseHardener.js +1 -1
  86. package/dist/harness/gooseHardener.js.map +1 -1
  87. package/dist/harness/gooseHooks.d.ts +14 -1
  88. package/dist/harness/gooseHooks.d.ts.map +1 -1
  89. package/dist/harness/gooseHooks.js +55 -29
  90. package/dist/harness/gooseHooks.js.map +1 -1
  91. package/dist/harness/grokHooks.d.ts +2 -2
  92. package/dist/harness/grokHooks.d.ts.map +1 -1
  93. package/dist/harness/grokHooks.js +11 -6
  94. package/dist/harness/grokHooks.js.map +1 -1
  95. package/dist/harness/hermesHooks.d.ts +18 -8
  96. package/dist/harness/hermesHooks.d.ts.map +1 -1
  97. package/dist/harness/hermesHooks.js +48 -17
  98. package/dist/harness/hermesHooks.js.map +1 -1
  99. package/dist/harness/mcpAutoWrite.d.ts +24 -9
  100. package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
  101. package/dist/harness/mcpAutoWrite.js +218 -25
  102. package/dist/harness/mcpAutoWrite.js.map +1 -1
  103. package/dist/harness/museHooks.d.ts +3 -3
  104. package/dist/harness/museHooks.d.ts.map +1 -1
  105. package/dist/harness/museHooks.js +9 -5
  106. package/dist/harness/museHooks.js.map +1 -1
  107. package/dist/harness/n8nHooks.d.ts +0 -1
  108. package/dist/harness/n8nHooks.d.ts.map +1 -1
  109. package/dist/harness/n8nHooks.js +4 -1
  110. package/dist/harness/n8nHooks.js.map +1 -1
  111. package/dist/harness/openCodeHooks.d.ts +2 -2
  112. package/dist/harness/openCodeHooks.d.ts.map +1 -1
  113. package/dist/harness/openCodeHooks.js +7 -3
  114. package/dist/harness/openCodeHooks.js.map +1 -1
  115. package/dist/harness/openWebuiHooks.d.ts +0 -1
  116. package/dist/harness/openWebuiHooks.d.ts.map +1 -1
  117. package/dist/harness/openWebuiHooks.js +5 -1
  118. package/dist/harness/openWebuiHooks.js.map +1 -1
  119. package/dist/harness/openclawHooks.d.ts +70 -18
  120. package/dist/harness/openclawHooks.d.ts.map +1 -1
  121. package/dist/harness/openclawHooks.js +213 -161
  122. package/dist/harness/openclawHooks.js.map +1 -1
  123. package/dist/harness/openhandsHooks.d.ts +24 -10
  124. package/dist/harness/openhandsHooks.d.ts.map +1 -1
  125. package/dist/harness/openhandsHooks.js +49 -48
  126. package/dist/harness/openhandsHooks.js.map +1 -1
  127. package/dist/harness/piHooks.d.ts +52 -17
  128. package/dist/harness/piHooks.d.ts.map +1 -1
  129. package/dist/harness/piHooks.js +177 -166
  130. package/dist/harness/piHooks.js.map +1 -1
  131. package/dist/harness/protectedPaths.d.ts +107 -25
  132. package/dist/harness/protectedPaths.d.ts.map +1 -1
  133. package/dist/harness/protectedPaths.js +342 -48
  134. package/dist/harness/protectedPaths.js.map +1 -1
  135. package/dist/harness/rulesSection.d.ts +62 -0
  136. package/dist/harness/rulesSection.d.ts.map +1 -0
  137. package/dist/harness/rulesSection.js +145 -0
  138. package/dist/harness/rulesSection.js.map +1 -0
  139. package/dist/harness/windsurfHooks.d.ts +0 -1
  140. package/dist/harness/windsurfHooks.d.ts.map +1 -1
  141. package/dist/harness/windsurfHooks.js +4 -1
  142. package/dist/harness/windsurfHooks.js.map +1 -1
  143. package/dist/index.d.ts +12 -8
  144. package/dist/index.d.ts.map +1 -1
  145. package/dist/index.js +11 -9
  146. package/dist/index.js.map +1 -1
  147. package/dist/inventory.d.ts +53 -0
  148. package/dist/inventory.d.ts.map +1 -0
  149. package/dist/inventory.js +133 -0
  150. package/dist/inventory.js.map +1 -0
  151. package/dist/lib/complianceProbes.d.ts +2 -1
  152. package/dist/lib/complianceProbes.d.ts.map +1 -1
  153. package/dist/lib/complianceProbes.js +1 -1
  154. package/dist/lib/complianceProbes.js.map +1 -1
  155. package/dist/lib/decisionsDigest.d.ts +34 -16
  156. package/dist/lib/decisionsDigest.d.ts.map +1 -1
  157. package/dist/lib/decisionsDigest.js +105 -46
  158. package/dist/lib/decisionsDigest.js.map +1 -1
  159. package/dist/lib/egressPolicy.d.ts +2 -2
  160. package/dist/lib/egressPolicy.js +2 -2
  161. package/dist/lib/mcpRegistryPy.d.ts +11 -0
  162. package/dist/lib/mcpRegistryPy.d.ts.map +1 -0
  163. package/dist/lib/mcpRegistryPy.js +173 -0
  164. package/dist/lib/mcpRegistryPy.js.map +1 -0
  165. package/dist/lib/phrasesPy.d.ts +11 -0
  166. package/dist/lib/phrasesPy.d.ts.map +1 -0
  167. package/dist/lib/phrasesPy.js +351 -0
  168. package/dist/lib/phrasesPy.js.map +1 -0
  169. package/dist/lib/policySnapshot.d.ts +46 -10
  170. package/dist/lib/policySnapshot.d.ts.map +1 -1
  171. package/dist/lib/policySnapshot.js +136 -47
  172. package/dist/lib/policySnapshot.js.map +1 -1
  173. package/dist/lib/processPoller.d.ts.map +1 -1
  174. package/dist/lib/processPoller.js +9 -2
  175. package/dist/lib/processPoller.js.map +1 -1
  176. package/dist/lib/regexLinearity.d.ts +43 -0
  177. package/dist/lib/regexLinearity.d.ts.map +1 -0
  178. package/dist/lib/regexLinearity.js +275 -0
  179. package/dist/lib/regexLinearity.js.map +1 -0
  180. package/dist/lib/runtimeEnv.d.ts +1 -3
  181. package/dist/lib/runtimeEnv.d.ts.map +1 -1
  182. package/dist/lib/runtimeEnv.js +0 -2
  183. package/dist/lib/runtimeEnv.js.map +1 -1
  184. package/dist/lib/sequencePy.d.ts +10 -0
  185. package/dist/lib/sequencePy.d.ts.map +1 -0
  186. package/dist/lib/sequencePy.js +102 -0
  187. package/dist/lib/sequencePy.js.map +1 -0
  188. package/dist/sessionReporter.d.ts +17 -11
  189. package/dist/sessionReporter.d.ts.map +1 -1
  190. package/dist/sessionReporter.js +36 -23
  191. package/dist/sessionReporter.js.map +1 -1
  192. package/dist/skillWriter.d.ts +23 -5
  193. package/dist/skillWriter.d.ts.map +1 -1
  194. package/dist/skillWriter.js +159 -16
  195. package/dist/skillWriter.js.map +1 -1
  196. package/dist/syncCycle.d.ts.map +1 -1
  197. package/dist/syncCycle.js +21 -9
  198. package/dist/syncCycle.js.map +1 -1
  199. package/dist/trajectoryMonitor.d.ts +1 -3
  200. package/dist/trajectoryMonitor.d.ts.map +1 -1
  201. package/dist/trajectoryMonitor.js +1 -4
  202. package/dist/trajectoryMonitor.js.map +1 -1
  203. package/dist/watcher/driftWatcher.d.ts +0 -1
  204. package/dist/watcher/driftWatcher.d.ts.map +1 -1
  205. package/dist/watcher/driftWatcher.js +1 -2
  206. package/dist/watcher/driftWatcher.js.map +1 -1
  207. package/dist/watcher/settingsGuard.d.ts +33 -7
  208. package/dist/watcher/settingsGuard.d.ts.map +1 -1
  209. package/dist/watcher/settingsGuard.js +373 -61
  210. package/dist/watcher/settingsGuard.js.map +1 -1
  211. package/dist/watcher/vscodeHookSettings.d.ts +30 -0
  212. package/dist/watcher/vscodeHookSettings.d.ts.map +1 -0
  213. package/dist/watcher/vscodeHookSettings.js +170 -0
  214. package/dist/watcher/vscodeHookSettings.js.map +1 -0
  215. package/dist/wsClient.d.ts +0 -1
  216. package/dist/wsClient.d.ts.map +1 -1
  217. package/dist/wsClient.js +0 -1
  218. package/dist/wsClient.js.map +1 -1
  219. package/package.json +5 -5
  220. package/dist/harness/claudeDesktopHooks.d.ts +0 -33
  221. package/dist/harness/claudeDesktopHooks.d.ts.map +0 -1
  222. package/dist/harness/claudeDesktopHooks.js +0 -256
  223. package/dist/harness/claudeDesktopHooks.js.map +0 -1
  224. package/dist/harness/continueHooks.d.ts +0 -63
  225. package/dist/harness/continueHooks.d.ts.map +0 -1
  226. package/dist/harness/continueHooks.js +0 -250
  227. package/dist/harness/continueHooks.js.map +0 -1
  228. package/dist/harness/gateKind.d.ts +0 -164
  229. package/dist/harness/gateKind.d.ts.map +0 -1
  230. package/dist/harness/gateKind.js +0 -144
  231. package/dist/harness/gateKind.js.map +0 -1
  232. package/dist/harness/rooCodeHooks.d.ts +0 -31
  233. package/dist/harness/rooCodeHooks.d.ts.map +0 -1
  234. package/dist/harness/rooCodeHooks.js +0 -281
  235. package/dist/harness/rooCodeHooks.js.map +0 -1
@@ -1,19 +1,45 @@
1
1
  /**
2
- * piHooks.ts — Pi (earendil-works/pi) coding agent governance hook injection.
2
+ * piHooks.ts — Pi (earendil-works/pi) extension gate and provider routing.
3
3
  *
4
- * Pi uses:
5
- * - `~/.pi/hooks.json` for PreToolUse hook matchers (stdin JSON, exit 2 = block)
6
- * - `~/.pi/models.json` for per-provider base URL routing
4
+ * Pi has no hook file. Its hooks are extensions: TypeScript or JavaScript
5
+ * modules it loads into its own process from `~/.pi/agent/extensions/` (and a
6
+ * trusted project's `.pi/extensions/`), each a default-exported factory that
7
+ * receives the `ExtensionAPI`. Earlier versions of this writer registered a
8
+ * Claude-Code-style `PreToolUse` hook in `~/.pi/hooks.json`, a file Pi never
9
+ * reads, and pointed providers at the proxy in `~/.pi/models.json`, where Pi
10
+ * does not look either: both live in the agent directory, `~/.pi/agent`.
11
+ * Sources, at earendil-works/pi 6fb2e7815167e6b19006fc526d1a5d0f5f998787:
7
12
  *
8
- * This module:
9
- * 1. Writes/merges `~/.pi/hooks.json` with intutic-governance hook entries.
10
- * 2. Writes/merges `~/.pi/models.json` to redirect LLM providers via proxyUrl.
11
- * 3. Writes `~/.intutic/hooks/pi-check.sh` — dual-path bash governance hook.
12
- * 4. Writes `.intutic/env/pi.env` — env snippet for IDE/shell integration.
13
+ * - discovery: `packages/coding-agent/src/core/extensions/loader.ts`
14
+ * (`discoverExtensionsInDir`: direct `*.ts`/`*.js` files, or `<dir>/index.*`;
15
+ * loaded with jiti, `{ default: true }`, and the default export must be a
16
+ * function), `packages/coding-agent/docs/configuration.md` (the agent
17
+ * directory and `models.json`);
18
+ * - the hook: `pi.on("tool_call", handler)`, with
19
+ * `event = { type: "tool_call", toolName, toolCallId, input }`, refused by
20
+ * returning `{ block: true, reason }` (`core/extensions/types.ts`,
21
+ * `ToolCallEventResult`). The agent loop turns the reason into the error
22
+ * result the model reads (`packages/agent/src/agent-loop.ts`).
23
+ * - failure: "A `tool_call` handler failure blocks the tool as a fail-safe"
24
+ * (`docs/extensions.md`); `ExtensionRunner.emitToolCall` awaits each
25
+ * handler with no timeout (`core/extensions/runner.ts`), so a handler that
26
+ * hangs hangs Pi. The gate body therefore runs under its own deadline
27
+ * (`gateDeadlineMs('pi')`), from the start of each call, and refuses past it.
13
28
  *
14
- * WS-C3 — Pi harness (Phase 3 cross-harness defence)
15
- * LLD #14 — Phase 3 cross-harness defence (Gap 3)
16
- * HLD §3.14 — Three-Tier Defense Cascade (Tier 1 Native Gating)
29
+ * The extension embeds the shared `emitJsGate` body (`'throw'` contract) and
30
+ * returns Pi's block result for the refusal it throws; any other fault is a
31
+ * block too. Pi names MCP tools `mcp__<server>__<tool>` already
32
+ * (`docs/mcp.md`), and calls a tool makes through `ctx.executeTool()` pass
33
+ * through `tool_call` handlers like the model's own (`docs/extensions.md`).
34
+ *
35
+ * The file is ESM with `createRequire`, the shape the OpenCode plugin uses:
36
+ * Node (Pi needs 22.19 or later) detects the module syntax, and jiti
37
+ * transforms the file where native loading fails and in Pi's compiled binary
38
+ * (`core/extensions/jiti-loader.ts`, `loader.ts`).
39
+ *
40
+ * Only the default agent directory is written. A user who moves it with
41
+ * `PI_CODING_AGENT_DIR` copies the extension there (the Pi integration page
42
+ * says so).
17
43
  *
18
44
  * @module
19
45
  */
@@ -21,127 +47,149 @@ import * as fs from 'node:fs/promises';
21
47
  import * as path from 'node:path';
22
48
  import * as os from 'node:os';
23
49
  import { createLogger } from '@intutic/logger';
24
- import { keepOriginal } from '../disconnect/originals.js';
50
+ import { keepOriginal, writeOwnedFile } from '../disconnect/originals.js';
25
51
  import { newIso } from '@intutic/id';
26
- import { emitShellGate, SHELL_EXTRACT, SHELL_FAIL_CLOSED } from './gateBody.js';
52
+ import { emitJsGate, REVIEW_REQUESTS_BASENAME } from './gateBody.js';
27
53
  import { readJsonObjectForMerge } from './jsonMergeTarget.js';
28
54
  import { anthropicBaseUrl, openaiBaseUrl } from '@intutic/shared-types';
29
55
  const log = createLogger('sync-pi-hooks');
30
- /** Path to the Pi hooks config. */
31
- const PI_HOOKS_CONFIG = path.join(os.homedir(), '.pi', 'hooks.json');
32
- /** Path to the Pi models config. */
33
- const PI_MODELS_CONFIG = path.join(os.homedir(), '.pi', 'models.json');
34
- // ─── Bash hook script template ────────────────────────────────────────────────
35
- function buildPiCheckScript(proxyUrl, workspaceRoot, workspaceId) {
56
+ /** Pi's default agent directory, relative to the home directory. */
57
+ export const PI_AGENT_DIR = path.join('.pi', 'agent');
58
+ /** The extension file, relative to the home directory. */
59
+ export const PI_EXTENSION_FILE = path.join(PI_AGENT_DIR, 'extensions', 'intutic-governance.js');
60
+ /** The first line of the extension's header, which disconnect recognises it by. */
61
+ export const PI_EXTENSION_MARKER = 'Intutic Pi governance extension.';
62
+ // ─── The extension ───────────────────────────────────────────────────────────
63
+ export function buildPiExtension(proxyUrl, workspaceRoot, workspaceId) {
36
64
  const hookEventsLog = path.join(workspaceRoot, '.intutic', 'events', 'hook-events.jsonl');
37
- const runtimeEnv = path.join(os.homedir(), '.intutic', 'env', 'runtime.env');
38
- return `#!/usr/bin/env bash
39
- # Intutic Pi (earendil-works/pi) PreToolUse governance gate.
40
- # Auto-generated by intutic sync-daemon. DO NOT EDIT.
41
- # Proxy: ${proxyUrl}
42
- # Generated: ${newIso()}
43
- # Workspace: ${workspaceId}
44
- set -euo pipefail
45
- ${SHELL_FAIL_CLOSED}
46
- # Source runtime credentials (never embedded in this file)
47
- if [ -f "${runtimeEnv}" ]; then
48
- # shellcheck disable=SC1090
49
- source "${runtimeEnv}"
50
- fi
51
-
52
- INTUTIC_HOST="\${INTUTIC_HOST:-https://api.intutic.ai}"
53
- INTUTIC_API_KEY="\${INTUTIC_API_KEY:-}"
54
- INTUTIC_WORKSPACE_ID="\${INTUTIC_WORKSPACE_ID:-${workspaceId}}"
65
+ return `/**
66
+ * ${PI_EXTENSION_MARKER}
67
+ * Auto-generated by intutic sync-daemon. DO NOT EDIT.
68
+ * Proxy: ${proxyUrl}
69
+ * Generated: ${newIso()}
70
+ *
71
+ * A tool_call handler Pi loads from its extensions directory. Refuses a tool
72
+ * call by returning { block: true, reason }. See
73
+ * services/sync-daemon/src/harness/piHooks.ts.
74
+ */
75
+ import { createRequire } from 'node:module';
76
+ const require = createRequire(import.meta.url);
77
+ const path = require('path');
78
+ const os = require('os');
79
+ const fs = require('fs');
80
+ const crypto = require('crypto');
81
+ const https = require('https');
55
82
 
56
- INPUT="$(cat)"
57
- ${SHELL_EXTRACT}
83
+ // Runtime credentials, read when Pi loads the extension.
84
+ const _runtimeEnvPath = path.join(os.homedir(), '.intutic', 'env', 'runtime.env');
85
+ let _intuticHost = 'https://api.intutic.ai', _intuticKey = '', _intuticWsId = ${JSON.stringify(workspaceId)};
86
+ try {
87
+ fs.readFileSync(_runtimeEnvPath, 'utf-8').split('\\n').forEach(line => {
88
+ const eq = line.indexOf('='); if (eq < 0) return;
89
+ const k = line.slice(0, eq).trim(), v = line.slice(eq + 1).trim();
90
+ if (k === 'INTUTIC_HOST' && v) _intuticHost = v;
91
+ if (k === 'INTUTIC_API_KEY' && v) _intuticKey = v;
92
+ if (k === 'INTUTIC_WORKSPACE_ID' && v) _intuticWsId = v;
93
+ });
94
+ } catch {}
58
95
 
59
- HOOK_EVENTS_LOG="${hookEventsLog}"
96
+ ${emitJsGate({ harness: 'pi', contract: 'throw', reviewRequestFile: path.join(workspaceRoot, '.intutic', 'events', REVIEW_REQUESTS_BASENAME) })}
60
97
 
61
- log_event() {
62
- local verdict="$1" tool="$2" reason="$3"
63
- # \`tool\`, \`reason\` and \`SESSION_ID\` carry agent-controlled text — the tool
64
- # name, the target path quoted into the block reason, and a field lifted
65
- # straight out of the hook's stdin — and all three are spliced into the JSON
66
- # string below. Escape first: one unescaped quote yields a line JSON.parse
67
- # rejects, and drainHookEvents drops malformed lines then wipes the log on a
68
- # successful drain, so the record of a block is destroyed rather than delayed.
69
- # A crafted path could otherwise close the string and forge fields.
70
- tool="\${tool//\\\\/\\\\\\\\}"; tool="\${tool//\\"/\\\\\\"}"
71
- reason="\${reason//\\\\/\\\\\\\\}"; reason="\${reason//\\"/\\\\\\"}"
72
- # Every C0 control character, not just newline and carriage return. JSON
73
- # forbids all of U+0000-U+001F unescaped, so a plain TAB in a filename — no
74
- # adversary required — was still enough to produce a line JSON.parse rejects.
75
- # (NUL cannot appear in a bash variable, so the range starts at \\x01.)
76
- tool="\${tool//[\$'\\x01'-\$'\\x1f']/ }"; reason="\${reason//[\$'\\x01'-\$'\\x1f']/ }"
77
- # The workspace id is spliced into the same JSON string. It comes from
78
- # runtime.env on disk rather than from the agent, so it is lower risk — but a
79
- # value with a quote in it breaks every audit line the same way, and "lower
80
- # risk" is not "cannot happen" for a file the operator edits by hand.
81
- local ws="\${INTUTIC_WORKSPACE_ID}"
82
- ws="\${ws//\\\\/\\\\\\\\}"; ws="\${ws//\\"/\\\\\\"}"; ws="\${ws//[\$'\\x01'-\$'\\x1f']/ }"
83
- local sid="\$SESSION_ID"
84
- sid="\${sid//\\\\/\\\\\\\\}"; sid="\${sid//\\"/\\\\\\"}"
85
- sid="\${sid//\$'\\n'/ }"; sid="\${sid//\$'\\r'/ }"
86
- local ts; ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
87
- # incidentId = sha1(timestamp + toolName + workspaceId).slice(0,16)
88
- local incident_id; incident_id="$(printf '%s' "\${ts}\${tool}\${INTUTIC_WORKSPACE_ID}" | sha1sum 2>/dev/null | cut -c1-16 || echo "$(date +%s)")"
89
- local entry="{\\"event\\":\\"\${verdict}\\",\\"toolName\\":\\"\${tool}\\",\\"reason\\":\\"\${reason}\\",\\"workspaceId\\":\\"\${ws}\\",\\"harnessType\\":\\"pi\\",\\"incidentId\\":\\"\${incident_id}\\",\\"timestamp\\":\\"\${ts}\\"\${sid:+,\\"sessionId\\":\\"\${sid}\\"}}"
90
- # Path B: reliable file append (sync-daemon drains on FSEvents change)
91
- printf '%s\\n' "\$entry" >> "\$HOOK_EVENTS_LOG" 2>/dev/null || true
92
- # Path A: fire-and-forget HTTP POST (near-real-time dashboard, non-blocking)
93
- if [ -n "\$INTUTIC_API_KEY" ]; then
94
- curl -s -o /dev/null --max-time 3 -X POST \\
95
- -H "Content-Type: application/json" \\
96
- -H "Authorization: Bearer \$INTUTIC_API_KEY" \\
97
- -d "{\\"events\\":[\$entry]}" \\
98
- "\${INTUTIC_HOST}/api/v1/hook-events" & disown 2>/dev/null || true
99
- fi
98
+ let _intuticSessionId = '';
99
+ function logEvent(verdict, toolName, reason) {
100
+ try {
101
+ const ts = new Date().toISOString();
102
+ const incidentId = crypto.createHash('sha1').update(ts + toolName + _intuticWsId).digest('hex').slice(0, 16);
103
+ // The event's id: random, made once here, and resent with the line it is
104
+ // written into, so the control plane processes the event once.
105
+ const eventId = crypto.randomBytes(16).toString('hex');
106
+ const entry = JSON.stringify({
107
+ event: verdict,
108
+ toolName, reason: reason || '',
109
+ workspaceId: _intuticWsId,
110
+ harnessType: 'pi',
111
+ timestamp: ts,
112
+ incidentId,
113
+ eventId,
114
+ ...(_intuticSessionId ? { sessionId: _intuticSessionId } : {}),
115
+ }) + '\\n';
116
+ const logPath = ${JSON.stringify(hookEventsLog)};
117
+ try { fs.mkdirSync(path.dirname(logPath), { recursive: true }); } catch {}
118
+ fs.appendFileSync(logPath, entry, { flag: 'a' });
119
+ if (_intuticKey) {
120
+ try {
121
+ const body = JSON.stringify({ events: [JSON.parse(entry)] });
122
+ const urlObj = new URL('/api/v1/hook-events', _intuticHost);
123
+ const isHttps = urlObj.protocol === 'https:';
124
+ const mod = isHttps ? https : require('http');
125
+ const req = mod.request({ hostname: urlObj.hostname, port: urlObj.port || (isHttps ? 443 : 80), path: urlObj.pathname, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body), 'Authorization': 'Bearer ' + _intuticKey } });
126
+ req.on('error', () => { /* fire-and-forget */ });
127
+ req.write(body); req.end();
128
+ } catch { /* never crash the hook */ }
129
+ }
130
+ } catch { /* never crash the hook */ }
100
131
  }
101
132
 
102
- ${emitShellGate({ harness: "pi" })}
103
- log_event "tool_allowed" "$TOOL_NAME" ""
104
- exit 0
105
- `;
106
- }
107
- // ─── Pi hooks.json merge ──────────────────────────────────────────────────────
108
133
  /**
109
- * Build the 4 canonical Pi PreToolUse hook matchers pointing at the given
110
- * hook script path. The wildcard `.*` matcher catches all tools not matched
111
- * by the more specific matchers above it.
134
+ * One tool call. Returns to allow; throws '[Intutic Governance] …' to refuse.
135
+ * Input that is not an object is refused outright: the gate reads paths and
136
+ * commands out of it, and a shape it cannot read is not one it can allow.
112
137
  */
113
- function buildPiHookMatchers(hookScriptPath) {
114
- return [
115
- { matcher: 'Bash', hooks: [{ type: 'command', command: hookScriptPath }] },
116
- { matcher: 'Edit', hooks: [{ type: 'command', command: hookScriptPath }] },
117
- { matcher: 'Write', hooks: [{ type: 'command', command: hookScriptPath }] },
118
- { matcher: '.*', hooks: [{ type: 'command', command: hookScriptPath }] },
119
- ];
138
+ function intuticEvaluate(event, ctx) {
139
+ _intuticSessionId = '';
140
+ try { _intuticSessionId = String(ctx.sessionManager.getSessionId() || ''); } catch (e) {}
141
+ const tool = String((event && event.toolName) || 'tool');
142
+ const input = event && event.input;
143
+ if (!input || typeof input !== 'object' || Array.isArray(input)) {
144
+ const reason = '[Intutic Governance] BLOCKED: tool "' + tool + '" was called with input the gate cannot read (' +
145
+ (input === null ? 'null' : typeof input) + '); refusing rather than allowing a call it cannot evaluate.';
146
+ try { logEvent('tool_blocked', tool, reason); } catch (e) {}
147
+ throw new Error(reason);
148
+ }
149
+ const target = input.path || input.file_path || input.filePath || input.target || '';
150
+ const command = input.command || input.cmd || input.script || '';
151
+ intuticGate(tool, target, command, logEvent, _intuticWsId, input, _intuticSessionId);
152
+ logEvent('tool_allowed', tool, '');
120
153
  }
154
+
121
155
  /**
122
- * Merge Pi hooks.json — upsert intutic-governance entries under
123
- * `hooks.PreToolUse`. Existing entries with our command path are filtered out
124
- * then re-added so there are no duplicates.
156
+ * Fail closed: a fault inside the gate is a refusal, never an allow. The gate
157
+ * body reports a refusal on stderr for the hook processes; inside Pi that
158
+ * line would land in the middle of the terminal UI, and the reason reaches
159
+ * the user in the tool result anyway, so stderr is muted for the call. The
160
+ * evaluation is synchronous, so nothing else logs in between.
125
161
  */
126
- function mergePiHooks(existing, hookScriptPath) {
127
- const preToolUse = existing.hooks?.PreToolUse ?? [];
128
- // Filter out any existing entries that reference our hook script
129
- const filtered = preToolUse.filter((m) => !m.hooks.some((h) => h.command === hookScriptPath));
130
- return {
131
- ...existing,
132
- hooks: {
133
- ...(existing.hooks ?? {}),
134
- PreToolUse: [...filtered, ...buildPiHookMatchers(hookScriptPath)],
135
- },
136
- };
162
+ function toolCall(event, ctx) {
163
+ const consoleError = console.error;
164
+ console.error = () => {};
165
+ try {
166
+ intuticEvaluate(event, ctx);
167
+ return undefined;
168
+ } catch (err) {
169
+ let reason = String((err && err.message) || err);
170
+ if (reason.indexOf('[Intutic Governance]') !== 0) {
171
+ reason = '[Intutic Governance] BLOCKED: gate fault (failing closed): ' + reason;
172
+ try { logEvent('tool_blocked', String((event && event.toolName) || 'unknown'), reason); } catch (e) {}
173
+ }
174
+ return { block: true, reason };
175
+ } finally {
176
+ console.error = consoleError;
177
+ }
137
178
  }
138
- // ─── Pi models.json merge ─────────────────────────────────────────────────────
179
+
180
+ export default function intuticGovernance(pi) {
181
+ pi.on('tool_call', toolCall);
182
+ }
183
+ `;
184
+ }
185
+ // ─── <agent-dir>/models.json ─────────────────────────────────────────────────
139
186
  /**
140
187
  * Merge Pi models.json — point the anthropic and openai providers at the
141
188
  * proxy, each with the base URL its SDK expects (the Anthropic SDK appends
142
189
  * `/v1/messages`, the OpenAI one `/chat/completions`). Google is left alone:
143
190
  * the proxy does not serve the Gemini API, so routing it there would break it.
144
- * Every other provider and key is kept.
191
+ * Every other provider and key is kept. A provider entry may carry `baseUrl`
192
+ * alone (`ProviderConfigSchema` in `packages/coding-agent/src/core/model-config.ts`).
145
193
  */
146
194
  export function mergePiModels(existing, proxyUrl) {
147
195
  const providers = existing.providers ?? {};
@@ -163,70 +211,33 @@ export function mergePiModels(existing, proxyUrl) {
163
211
  }
164
212
  // ─── Main export ──────────────────────────────────────────────────────────────
165
213
  /**
166
- * Write the Pi governance hook script, merge hooks.json and models.json,
167
- * and write the env snippet.
214
+ * Write the Pi governance extension into `~/.pi/agent/extensions/` and merge
215
+ * the proxy routing into `~/.pi/agent/models.json`.
168
216
  *
169
- * Safe to call repeatedly — uses atomic rename so partial writes never
170
- * leave a corrupt state.
217
+ * Safe to call repeatedly: atomic renames and a fixed file name, so repeated
218
+ * syncs replace rather than stack. Pi discovers the extension by scanning the
219
+ * directory; nothing registers it.
171
220
  *
172
221
  * @param workspaceRoot - Absolute workspace root path.
173
222
  * @param proxyUrl - Intutic proxy URL for LLM provider routing.
174
223
  * @param workspaceId - Workspace ID embedded in every hook event payload.
175
224
  */
176
225
  export async function writePiHooks(workspaceRoot, proxyUrl, workspaceId = '') {
177
- // ── 1. Ensure directories ──────────────────────────────────────────────────
178
- const globalHookDir = path.join(os.homedir(), '.intutic', 'hooks');
179
- const hookEventsDir = path.join(workspaceRoot, '.intutic', 'events');
180
- const envDir = path.join(workspaceRoot, '.intutic', 'env');
181
- const piDir = path.join(os.homedir(), '.pi');
182
- await keepOriginal(PI_HOOKS_CONFIG, workspaceRoot);
183
- await keepOriginal(PI_MODELS_CONFIG, workspaceRoot);
184
- await Promise.all([
185
- fs.mkdir(globalHookDir, { recursive: true }),
186
- fs.mkdir(hookEventsDir, { recursive: true }),
187
- fs.mkdir(envDir, { recursive: true }),
188
- fs.mkdir(piDir, { recursive: true }),
189
- ]);
190
- // ── 2. Write bash hook script ──────────────────────────────────────────────
191
- const hookScriptPath = path.join(globalHookDir, 'pi-check.sh');
192
- const tmpScript = hookScriptPath + '.intutic-tmp';
193
- await fs.writeFile(tmpScript, buildPiCheckScript(proxyUrl, workspaceRoot, workspaceId), 'utf-8');
194
- await fs.rename(tmpScript, hookScriptPath);
195
- await fs.chmod(hookScriptPath, 0o755);
196
- log.info({ action: 'pi_hook_script_written', path: hookScriptPath }, 'Pi hook script written');
197
- // ── 3. Write/merge ~/.pi/hooks.json ───────────────────────────────────────
226
+ await fs.mkdir(path.join(workspaceRoot, '.intutic', 'events'), { recursive: true });
227
+ const extensionPath = path.join(os.homedir(), PI_EXTENSION_FILE);
228
+ await writeOwnedFile(extensionPath, workspaceRoot, buildPiExtension(proxyUrl, workspaceRoot, workspaceId));
229
+ log.info({ action: 'pi_extension_written', path: extensionPath }, 'Pi governance extension written');
198
230
  // A file that is not a plain JSON object is left untouched (and reported)
199
231
  // rather than replaced with only the Intutic entries.
200
- const existingHooks = await readJsonObjectForMerge(PI_HOOKS_CONFIG);
201
- if (existingHooks !== null) {
202
- const mergedHooks = mergePiHooks(existingHooks, hookScriptPath);
203
- const tmpHooks = PI_HOOKS_CONFIG + '.intutic-tmp';
204
- await fs.writeFile(tmpHooks, JSON.stringify(mergedHooks, null, 2) + '\n', 'utf-8');
205
- await fs.rename(tmpHooks, PI_HOOKS_CONFIG);
206
- }
207
- log.info({ action: 'pi_hooks_written', path: PI_HOOKS_CONFIG }, 'Pi hooks.json written');
208
- // ── 4. Write/merge ~/.pi/models.json ──────────────────────────────────────
209
- const existingModels = await readJsonObjectForMerge(PI_MODELS_CONFIG);
232
+ const modelsPath = path.join(os.homedir(), PI_AGENT_DIR, 'models.json');
233
+ const existingModels = await readJsonObjectForMerge(modelsPath);
210
234
  if (existingModels !== null) {
211
- const mergedModels = mergePiModels(existingModels, proxyUrl);
212
- const tmpModels = PI_MODELS_CONFIG + '.intutic-tmp';
213
- await fs.writeFile(tmpModels, JSON.stringify(mergedModels, null, 2) + '\n', 'utf-8');
214
- await fs.rename(tmpModels, PI_MODELS_CONFIG);
235
+ await keepOriginal(modelsPath, workspaceRoot);
236
+ await fs.mkdir(path.dirname(modelsPath), { recursive: true });
237
+ const tmp = modelsPath + '.intutic-tmp';
238
+ await fs.writeFile(tmp, JSON.stringify(mergePiModels(existingModels, proxyUrl), null, 2) + '\n', 'utf-8');
239
+ await fs.rename(tmp, modelsPath);
240
+ log.info({ action: 'pi_models_written', path: modelsPath }, 'Pi models.json written');
215
241
  }
216
- log.info({ action: 'pi_models_written', path: PI_MODELS_CONFIG }, 'Pi models.json written');
217
- // ── 5. Write env snippet ───────────────────────────────────────────────────
218
- const envSnippet = [
219
- `# Intutic pi governance env`,
220
- `INTUTIC_PI_HOOK=~/.intutic/hooks/pi-check.sh`,
221
- `INTUTIC_PI_HOOKS_CONFIG=~/.pi/hooks.json`,
222
- `INTUTIC_PI_MODELS_CONFIG=~/.pi/models.json`,
223
- `OPENAI_BASE_URL=${proxyUrl}`,
224
- `ANTHROPIC_BASE_URL=${proxyUrl}`,
225
- ].join('\n') + '\n';
226
- const envFilePath = path.join(envDir, 'pi.env');
227
- const tmpEnv = envFilePath + '.intutic-tmp';
228
- await fs.writeFile(tmpEnv, envSnippet, 'utf-8');
229
- await fs.rename(tmpEnv, envFilePath);
230
- log.info({ action: 'pi_env_written', path: envFilePath }, 'Pi env snippet written');
231
242
  }
232
243
  //# sourceMappingURL=piHooks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"piHooks.js","sourceRoot":"","sources":["../../src/harness/piHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAEvE,MAAM,GAAG,GAAG,YAAY,CAAC,eAAe,CAAC,CAAA;AAEzC,mCAAmC;AACnC,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,YAAY,CAAC,CAAA;AAEpE,oCAAoC;AACpC,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,aAAa,CAAC,CAAA;AAiCtE,iFAAiF;AAEjF,SAAS,kBAAkB,CACzB,QAAgB,EAChB,aAAqB,EACrB,WAAmB;IAEnB,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,mBAAmB,CAAC,CAAA;IACzF,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,CAAC,CAAA;IAC5E,OAAO;;;WAGE,QAAQ;eACJ,MAAM,EAAE;eACR,WAAW;;EAExB,iBAAiB;;WAER,UAAU;;YAET,UAAU;;;;;iDAK2B,WAAW;;;EAG1D,aAAa;;mBAEI,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2C9B,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;;;CAGjC,CAAA;AACD,CAAC;AAED,iFAAiF;AAEjF;;;;GAIG;AACH,SAAS,mBAAmB,CAAC,cAAsB;IACjD,OAAO;QACL,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE;QAC1E,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE;QAC1E,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE;QAC3E,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE;KACzE,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,QAAuB,EAAE,cAAsB;IACnE,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,EAAE,UAAU,IAAI,EAAE,CAAA;IAEnD,iEAAiE;IACjE,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,cAAc,CAAC,CAC1D,CAAA;IAED,OAAO;QACL,GAAG,QAAQ;QACX,KAAK,EAAE;YACL,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;YACzB,UAAU,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,mBAAmB,CAAC,cAAc,CAAC,CAAC;SAClE;KACF,CAAA;AACH,CAAC;AAED,iFAAiF;AAEjF;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,QAAwB,EAAE,QAAgB;IACtE,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAA;IAC1C,MAAM,OAAO,GAA2B;QACtC,SAAS,EAAE,gBAAgB,CAAC,QAAQ,CAAC;QACrC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC;KAChC,CAAA;IAED,MAAM,eAAe,GAA+B,EAAE,GAAG,SAAS,EAAE,CAAA;IACpE,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1D,eAAe,CAAC,QAAQ,CAAC,GAAG;YAC1B,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC9B,OAAO;SACR,CAAA;IACH,CAAC;IAED,OAAO;QACL,GAAG,QAAQ;QACX,SAAS,EAAE,eAAe;KAC3B,CAAA;AACH,CAAC;AAED,iFAAiF;AAEjF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,aAAqB,EACrB,QAAgB,EAChB,WAAW,GAAG,EAAE;IAEhB,8EAA8E;IAE9E,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IAClE,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;IACpE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,KAAK,CAAC,CAAA;IAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,CAAA;IAE5C,MAAM,YAAY,CAAC,eAAe,EAAE,aAAa,CAAC,CAAA;IAClD,MAAM,YAAY,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAA;IACnD,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC5C,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC5C,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QACrC,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KACrC,CAAC,CAAA;IAEF,8EAA8E;IAE9E,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;IAC9D,MAAM,SAAS,GAAG,cAAc,GAAG,cAAc,CAAA;IACjD,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,kBAAkB,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,CAAA;IAChG,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,cAAc,CAAC,CAAA;IAC1C,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAA;IAErC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,wBAAwB,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,wBAAwB,CAAC,CAAA;IAE9F,6EAA6E;IAE7E,0EAA0E;IAC1E,sDAAsD;IACtD,MAAM,aAAa,GAAG,MAAM,sBAAsB,CAAC,eAAe,CAAyB,CAAA;IAC3F,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,YAAY,CAAC,aAAa,EAAE,cAAc,CAAC,CAAA;QAC/D,MAAM,QAAQ,GAAG,eAAe,GAAG,cAAc,CAAA;QACjD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAA;QAClF,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAA;IAC5C,CAAC;IAED,GAAG,CAAC,IAAI,CACN,EAAE,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,eAAe,EAAE,EACrD,uBAAuB,CACxB,CAAA;IAED,6EAA6E;IAE7E,MAAM,cAAc,GAAG,MAAM,sBAAsB,CAAC,gBAAgB,CAA0B,CAAA;IAC9F,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;QAC5B,MAAM,YAAY,GAAG,aAAa,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAA;QAC5D,MAAM,SAAS,GAAG,gBAAgB,GAAG,cAAc,CAAA;QACnD,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAA;QACpF,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA;IAC9C,CAAC;IAED,GAAG,CAAC,IAAI,CACN,EAAE,MAAM,EAAE,mBAAmB,EAAE,IAAI,EAAE,gBAAgB,EAAE,EACvD,wBAAwB,CACzB,CAAA;IAED,8EAA8E;IAE9E,MAAM,UAAU,GAAG;QACjB,6BAA6B;QAC7B,8CAA8C;QAC9C,0CAA0C;QAC1C,4CAA4C;QAC5C,mBAAmB,QAAQ,EAAE;QAC7B,sBAAsB,QAAQ,EAAE;KACjC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAEnB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IAC/C,MAAM,MAAM,GAAG,WAAW,GAAG,cAAc,CAAA;IAC3C,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IAC/C,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IAEpC,GAAG,CAAC,IAAI,CACN,EAAE,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,EAAE,EAC/C,wBAAwB,CACzB,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"piHooks.js","sourceRoot":"","sources":["../../src/harness/piHooks.ts"],"names":[],"mappings":"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"}