@intutic/sync-daemon 1.9.0 → 1.10.1

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 (200) hide show
  1. package/README.md +2 -2
  2. package/dist/agentReporter.d.ts +205 -0
  3. package/dist/agentReporter.d.ts.map +1 -0
  4. package/dist/agentReporter.js +394 -0
  5. package/dist/agentReporter.js.map +1 -0
  6. package/dist/configReader.d.ts +39 -2
  7. package/dist/configReader.d.ts.map +1 -1
  8. package/dist/configReader.js +56 -2
  9. package/dist/configReader.js.map +1 -1
  10. package/dist/configWriter.d.ts +51 -1
  11. package/dist/configWriter.d.ts.map +1 -1
  12. package/dist/configWriter.js +490 -63
  13. package/dist/configWriter.js.map +1 -1
  14. package/dist/harness/antigravityHooks.d.ts.map +1 -1
  15. package/dist/harness/antigravityHooks.js +33 -55
  16. package/dist/harness/antigravityHooks.js.map +1 -1
  17. package/dist/harness/claudeCodeHooks.d.ts +47 -13
  18. package/dist/harness/claudeCodeHooks.d.ts.map +1 -1
  19. package/dist/harness/claudeCodeHooks.js +323 -55
  20. package/dist/harness/claudeCodeHooks.js.map +1 -1
  21. package/dist/harness/claudeDesktopHooks.d.ts.map +1 -1
  22. package/dist/harness/claudeDesktopHooks.js +35 -48
  23. package/dist/harness/claudeDesktopHooks.js.map +1 -1
  24. package/dist/harness/clineHooks.d.ts.map +1 -1
  25. package/dist/harness/clineHooks.js +42 -34
  26. package/dist/harness/clineHooks.js.map +1 -1
  27. package/dist/harness/codexHooks.d.ts +36 -0
  28. package/dist/harness/codexHooks.d.ts.map +1 -0
  29. package/dist/harness/codexHooks.js +227 -0
  30. package/dist/harness/codexHooks.js.map +1 -0
  31. package/dist/harness/continueHooks.d.ts +45 -5
  32. package/dist/harness/continueHooks.d.ts.map +1 -1
  33. package/dist/harness/continueHooks.js +225 -5
  34. package/dist/harness/continueHooks.js.map +1 -1
  35. package/dist/harness/cursorHooks.d.ts +31 -0
  36. package/dist/harness/cursorHooks.d.ts.map +1 -1
  37. package/dist/harness/cursorHooks.js +78 -49
  38. package/dist/harness/cursorHooks.js.map +1 -1
  39. package/dist/harness/dshHooks.d.ts +198 -0
  40. package/dist/harness/dshHooks.d.ts.map +1 -0
  41. package/dist/harness/dshHooks.js +569 -0
  42. package/dist/harness/dshHooks.js.map +1 -0
  43. package/dist/harness/gateBody.d.ts +422 -0
  44. package/dist/harness/gateBody.d.ts.map +1 -0
  45. package/dist/harness/gateBody.js +1816 -0
  46. package/dist/harness/gateBody.js.map +1 -0
  47. package/dist/harness/gateKind.d.ts +164 -0
  48. package/dist/harness/gateKind.d.ts.map +1 -0
  49. package/dist/harness/gateKind.js +143 -0
  50. package/dist/harness/gateKind.js.map +1 -0
  51. package/dist/harness/githubCopilotHooks.d.ts +54 -0
  52. package/dist/harness/githubCopilotHooks.d.ts.map +1 -0
  53. package/dist/harness/githubCopilotHooks.js +218 -0
  54. package/dist/harness/githubCopilotHooks.js.map +1 -0
  55. package/dist/harness/gooseHooks.d.ts.map +1 -1
  56. package/dist/harness/gooseHooks.js +67 -37
  57. package/dist/harness/gooseHooks.js.map +1 -1
  58. package/dist/harness/grokHooks.d.ts +77 -0
  59. package/dist/harness/grokHooks.d.ts.map +1 -0
  60. package/dist/harness/grokHooks.js +350 -0
  61. package/dist/harness/grokHooks.js.map +1 -0
  62. package/dist/harness/hermesHooks.d.ts.map +1 -1
  63. package/dist/harness/hermesHooks.js +26 -55
  64. package/dist/harness/hermesHooks.js.map +1 -1
  65. package/dist/harness/holdRedaction.d.ts +69 -0
  66. package/dist/harness/holdRedaction.d.ts.map +1 -0
  67. package/dist/harness/holdRedaction.js +211 -0
  68. package/dist/harness/holdRedaction.js.map +1 -0
  69. package/dist/harness/jetbrainsXmlConfig.d.ts +51 -0
  70. package/dist/harness/jetbrainsXmlConfig.d.ts.map +1 -0
  71. package/dist/harness/jetbrainsXmlConfig.js +151 -0
  72. package/dist/harness/jetbrainsXmlConfig.js.map +1 -0
  73. package/dist/harness/mcpAutoWrite.d.ts +100 -3
  74. package/dist/harness/mcpAutoWrite.d.ts.map +1 -1
  75. package/dist/harness/mcpAutoWrite.js +712 -90
  76. package/dist/harness/mcpAutoWrite.js.map +1 -1
  77. package/dist/harness/museHooks.d.ts +53 -0
  78. package/dist/harness/museHooks.d.ts.map +1 -0
  79. package/dist/harness/museHooks.js +273 -0
  80. package/dist/harness/museHooks.js.map +1 -0
  81. package/dist/harness/n8nHooks.d.ts +25 -9
  82. package/dist/harness/n8nHooks.d.ts.map +1 -1
  83. package/dist/harness/n8nHooks.js +174 -9
  84. package/dist/harness/n8nHooks.js.map +1 -1
  85. package/dist/harness/openCodeHooks.d.ts +93 -0
  86. package/dist/harness/openCodeHooks.d.ts.map +1 -0
  87. package/dist/harness/openCodeHooks.js +248 -0
  88. package/dist/harness/openCodeHooks.js.map +1 -0
  89. package/dist/harness/openWebuiHooks.d.ts.map +1 -1
  90. package/dist/harness/openWebuiHooks.js +56 -11
  91. package/dist/harness/openWebuiHooks.js.map +1 -1
  92. package/dist/harness/openclawHooks.d.ts.map +1 -1
  93. package/dist/harness/openclawHooks.js +30 -54
  94. package/dist/harness/openclawHooks.js.map +1 -1
  95. package/dist/harness/openhandsHooks.d.ts.map +1 -1
  96. package/dist/harness/openhandsHooks.js +35 -41
  97. package/dist/harness/openhandsHooks.js.map +1 -1
  98. package/dist/harness/piHooks.d.ts.map +1 -1
  99. package/dist/harness/piHooks.js +31 -58
  100. package/dist/harness/piHooks.js.map +1 -1
  101. package/dist/harness/protectedPaths.d.ts +353 -0
  102. package/dist/harness/protectedPaths.d.ts.map +1 -0
  103. package/dist/harness/protectedPaths.js +805 -0
  104. package/dist/harness/protectedPaths.js.map +1 -0
  105. package/dist/harness/rooCodeHooks.d.ts.map +1 -1
  106. package/dist/harness/rooCodeHooks.js +34 -48
  107. package/dist/harness/rooCodeHooks.js.map +1 -1
  108. package/dist/harness/windsurfHooks.d.ts +72 -0
  109. package/dist/harness/windsurfHooks.d.ts.map +1 -1
  110. package/dist/harness/windsurfHooks.js +172 -58
  111. package/dist/harness/windsurfHooks.js.map +1 -1
  112. package/dist/harness/windsurfJetBrainsProxy.d.ts +78 -0
  113. package/dist/harness/windsurfJetBrainsProxy.d.ts.map +1 -0
  114. package/dist/harness/windsurfJetBrainsProxy.js +159 -0
  115. package/dist/harness/windsurfJetBrainsProxy.js.map +1 -0
  116. package/dist/hashReporter.js +1 -1
  117. package/dist/hashReporter.js.map +1 -1
  118. package/dist/index.d.ts +12 -6
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +14 -6
  121. package/dist/index.js.map +1 -1
  122. package/dist/integrityStore.d.ts +0 -8
  123. package/dist/integrityStore.d.ts.map +1 -1
  124. package/dist/integrityStore.js +6 -29
  125. package/dist/integrityStore.js.map +1 -1
  126. package/dist/lib/approvedBypasses.d.ts +76 -0
  127. package/dist/lib/approvedBypasses.d.ts.map +1 -0
  128. package/dist/lib/approvedBypasses.js +140 -0
  129. package/dist/lib/approvedBypasses.js.map +1 -0
  130. package/dist/lib/complianceProbes.d.ts.map +1 -1
  131. package/dist/lib/complianceProbes.js +5 -0
  132. package/dist/lib/complianceProbes.js.map +1 -1
  133. package/dist/lib/decisionsDigest.d.ts +99 -0
  134. package/dist/lib/decisionsDigest.d.ts.map +1 -0
  135. package/dist/lib/decisionsDigest.js +199 -0
  136. package/dist/lib/decisionsDigest.js.map +1 -0
  137. package/dist/lib/egressPolicy.d.ts +69 -0
  138. package/dist/lib/egressPolicy.d.ts.map +1 -0
  139. package/dist/lib/egressPolicy.js +126 -0
  140. package/dist/lib/egressPolicy.js.map +1 -0
  141. package/dist/lib/gitWorktrees.d.ts +140 -0
  142. package/dist/lib/gitWorktrees.d.ts.map +1 -0
  143. package/dist/lib/gitWorktrees.js +191 -0
  144. package/dist/lib/gitWorktrees.js.map +1 -0
  145. package/dist/lib/policySnapshot.d.ts +224 -0
  146. package/dist/lib/policySnapshot.d.ts.map +1 -0
  147. package/dist/lib/policySnapshot.js +637 -0
  148. package/dist/lib/policySnapshot.js.map +1 -0
  149. package/dist/lib/processPoller.d.ts +44 -0
  150. package/dist/lib/processPoller.d.ts.map +1 -1
  151. package/dist/lib/processPoller.js +176 -1
  152. package/dist/lib/processPoller.js.map +1 -1
  153. package/dist/lib/runtimeEnv.d.ts +8 -0
  154. package/dist/lib/runtimeEnv.d.ts.map +1 -1
  155. package/dist/lib/runtimeEnv.js +3 -0
  156. package/dist/lib/runtimeEnv.js.map +1 -1
  157. package/dist/localTrajectoryHeuristics.d.ts +51 -0
  158. package/dist/localTrajectoryHeuristics.d.ts.map +1 -0
  159. package/dist/localTrajectoryHeuristics.js +90 -0
  160. package/dist/localTrajectoryHeuristics.js.map +1 -0
  161. package/dist/sessionReporter.d.ts +70 -0
  162. package/dist/sessionReporter.d.ts.map +1 -0
  163. package/dist/sessionReporter.js +140 -0
  164. package/dist/sessionReporter.js.map +1 -0
  165. package/dist/skillWriter.d.ts +1 -1
  166. package/dist/skillWriter.d.ts.map +1 -1
  167. package/dist/skillWriter.js +6 -3
  168. package/dist/skillWriter.js.map +1 -1
  169. package/dist/syncLoop.d.ts +105 -3
  170. package/dist/syncLoop.d.ts.map +1 -1
  171. package/dist/syncLoop.js +397 -65
  172. package/dist/syncLoop.js.map +1 -1
  173. package/dist/trajectoryMonitor.d.ts +2 -0
  174. package/dist/trajectoryMonitor.d.ts.map +1 -1
  175. package/dist/trajectoryMonitor.js +57 -0
  176. package/dist/trajectoryMonitor.js.map +1 -1
  177. package/dist/watcher/driftWatcher.d.ts.map +1 -1
  178. package/dist/watcher/driftWatcher.js +12 -3
  179. package/dist/watcher/driftWatcher.js.map +1 -1
  180. package/dist/watcher/settingsGuard.d.ts +23 -0
  181. package/dist/watcher/settingsGuard.d.ts.map +1 -1
  182. package/dist/watcher/settingsGuard.js +202 -17
  183. package/dist/watcher/settingsGuard.js.map +1 -1
  184. package/package.json +37 -6
  185. package/dist/brainIndexer.d.ts +0 -51
  186. package/dist/brainIndexer.d.ts.map +0 -1
  187. package/dist/brainIndexer.js +0 -148
  188. package/dist/brainIndexer.js.map +0 -1
  189. package/dist/harness/cursorHooksJson.d.ts +0 -29
  190. package/dist/harness/cursorHooksJson.d.ts.map +0 -1
  191. package/dist/harness/cursorHooksJson.js +0 -130
  192. package/dist/harness/cursorHooksJson.js.map +0 -1
  193. package/dist/harness/gooseHooksWriter.d.ts +0 -27
  194. package/dist/harness/gooseHooksWriter.d.ts.map +0 -1
  195. package/dist/harness/gooseHooksWriter.js +0 -147
  196. package/dist/harness/gooseHooksWriter.js.map +0 -1
  197. package/dist/harness/openhandsHooksWriter.d.ts +0 -23
  198. package/dist/harness/openhandsHooksWriter.d.ts.map +0 -1
  199. package/dist/harness/openhandsHooksWriter.js +0 -146
  200. package/dist/harness/openhandsHooksWriter.js.map +0 -1
@@ -0,0 +1,140 @@
1
+ /**
2
+ * sessionReporter.ts — turn harness detection into real control-plane
3
+ * sessions.
4
+ *
5
+ * The full-fidelity session path (POST /api/v1/sessions — branch/commit
6
+ * capture and the Jira/Linear/GitHub task-context cascade) had no production
7
+ * caller: sessions only ever existed as synthetic `ssp_` rows minted
8
+ * server-side. The daemon knows everything the route wants — workspace root,
9
+ * harness, git branch and commit — so it reports them once per harness per
10
+ * daemon run when the harness is first detected.
11
+ *
12
+ * WHICH row it reports them onto (TD-231, Wave 5.6): when a local proxy is
13
+ * reachable, the caller passes that process's `proxyInstanceId` and the
14
+ * control plane puts the context on the proxy's OWN row — the
15
+ * `ssp_<ws>_<harness>_<instance>` session it derives for that process's
16
+ * traces, so the branch, the task and the cost sit on one row (AI intensity
17
+ * reads them together) and the hook gate's blocks resolve to the same row.
18
+ * That row's lifecycle stays the control plane's 30-minute idle rule; the
19
+ * daemon never ends it, because an externally started proxy keeps serving
20
+ * after the daemon stops and an ended row would vanish from Active Sessions
21
+ * and from the hook gate's resolver while traces still attach to it. A
22
+ * respawned proxy has a new instance id, so it gets a new row on the next
23
+ * iteration. Without an instance id (no local proxy, or a shared gateway —
24
+ * `fetchLocalProxyInstanceId` refuses a `gw_` id) the daemon opens a `ses_`
25
+ * STANDARD row as before and ends it on shutdown
26
+ * (PATCH /api/v1/sessions/:id/end).
27
+ *
28
+ * Dedupe lives here (module state keyed workspace+harness+instance), so
29
+ * callers — `startSyncLoop`'s iteration as well as the CLI's inline connect
30
+ * loop — can call `startHarnessSession` every iteration and only the first
31
+ * one POSTs. Git context is captured once per key, not on a branch switch.
32
+ * Everything is best-effort: a dead control plane costs a warning, never the
33
+ * sync loop.
34
+ *
35
+ * @module
36
+ */
37
+ import { execFile } from 'node:child_process';
38
+ import { promisify } from 'node:util';
39
+ import { newIso } from '@intutic/id';
40
+ const execFileP = promisify(execFile);
41
+ /**
42
+ * sessionIds this daemon run opened AND owns the lifecycle of — the `ses_`
43
+ * rows `endAllOpenSessions` ends. Keyed `${workspaceId}:${harness}:`.
44
+ */
45
+ const openSessions = new Map();
46
+ /**
47
+ * Proxy rows this run registered context onto, keyed
48
+ * `${workspaceId}:${harness}:${proxyInstanceId}`. Dedupe only — never ended.
49
+ */
50
+ const registeredProxyRows = new Map();
51
+ /** Keys with a POST in flight or already attempted (success or not) — one try per run. */
52
+ const attempted = new Set();
53
+ /** Best-effort git context from the workspace root. */
54
+ export async function readGitInfo(workspaceRoot) {
55
+ const git = async (...args) => {
56
+ try {
57
+ const { stdout } = await execFileP('git', args, { cwd: workspaceRoot, timeout: 3_000 });
58
+ const out = stdout.trim();
59
+ return out.length > 0 ? out : undefined;
60
+ }
61
+ catch {
62
+ return undefined;
63
+ }
64
+ };
65
+ const [branchName, commitHash, commitMessage] = await Promise.all([
66
+ git('rev-parse', '--abbrev-ref', 'HEAD'),
67
+ git('rev-parse', 'HEAD'),
68
+ git('log', '-1', '--format=%s'),
69
+ ]);
70
+ return { branchName, commitHash, commitMessage };
71
+ }
72
+ /**
73
+ * Report a harness session once per run — onto the local proxy's own row when
74
+ * `proxyInstanceId` is given (see the module doc), else as a new `ses_` row.
75
+ * Returns the sessionId when one is known (new or previously created).
76
+ */
77
+ export async function startHarnessSession(opts) {
78
+ const key = `${opts.workspaceId}:${opts.harnessType}:${opts.proxyInstanceId ?? ''}`;
79
+ const existing = opts.proxyInstanceId ? registeredProxyRows.get(key) : openSessions.get(key);
80
+ if (existing)
81
+ return existing;
82
+ if (attempted.has(key))
83
+ return null;
84
+ attempted.add(key);
85
+ try {
86
+ const git = await readGitInfo(opts.workspaceRoot);
87
+ const res = await fetch(`${opts.controlPlaneUrl}/api/v1/sessions`, {
88
+ method: 'POST',
89
+ headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${opts.apiKey}` },
90
+ body: JSON.stringify({
91
+ workspaceId: opts.workspaceId,
92
+ harnessType: opts.harnessType,
93
+ ...(opts.agentRole ? { agentRole: opts.agentRole } : {}),
94
+ ...(opts.proxyInstanceId ? { proxyInstanceId: opts.proxyInstanceId } : {}),
95
+ ...git,
96
+ reportedAt: newIso(),
97
+ }),
98
+ signal: AbortSignal.timeout(15_000),
99
+ });
100
+ if (!res.ok) {
101
+ console.warn(`[sync-daemon] startHarnessSession failed for ${opts.harnessType}: ${res.status}`);
102
+ return null;
103
+ }
104
+ const body = (await res.json());
105
+ if (body.sessionId) {
106
+ ;
107
+ (opts.proxyInstanceId ? registeredProxyRows : openSessions).set(key, body.sessionId);
108
+ return body.sessionId;
109
+ }
110
+ return null;
111
+ }
112
+ catch (err) {
113
+ console.warn(`[sync-daemon] startHarnessSession error for ${opts.harnessType}:`, err instanceof Error ? err.message : err);
114
+ return null;
115
+ }
116
+ }
117
+ /**
118
+ * End every `ses_` session this run opened. Called from shutdown paths. Proxy
119
+ * rows registered through `proxyInstanceId` are forgotten, not ended — the
120
+ * module doc says why.
121
+ */
122
+ export async function endAllOpenSessions(controlPlaneUrl, apiKey) {
123
+ const entries = [...openSessions.entries()];
124
+ openSessions.clear();
125
+ registeredProxyRows.clear();
126
+ attempted.clear();
127
+ await Promise.allSettled(entries.map(async ([, sessionId]) => {
128
+ try {
129
+ await fetch(`${controlPlaneUrl}/api/v1/sessions/${sessionId}/end`, {
130
+ method: 'PATCH',
131
+ headers: { Authorization: `Bearer ${apiKey}` },
132
+ signal: AbortSignal.timeout(5_000),
133
+ });
134
+ }
135
+ catch {
136
+ // shutdown is not the time to retry
137
+ }
138
+ }));
139
+ }
140
+ //# sourceMappingURL=sessionReporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionReporter.js","sourceRoot":"","sources":["../src/sessionReporter.ts"],"names":[],"mappings":"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"}
@@ -15,7 +15,7 @@
15
15
  /** Workspace-relative path the rule-author skill is written to. */
16
16
  export declare const RULE_AUTHOR_SKILL_PATH: string;
17
17
  /** Embedded copy of .agents/skills/intutic-rule-author/SKILL.md (canonical). */
18
- export declare const RULE_AUTHOR_SKILL = "---\nname: intutic-rule-author\ndescription: Convert natural-language business rules into compiled WASM governance policies enforced by the local Intutic proxy \u2014 author, compile, dry-run, and install rules without a control plane.\n---\n\n# \uD83D\uDCDC Rule Author \u2014 Business Rules as Enforced WASM Policies\n\nUse this skill whenever the user states a rule that AI agent traffic must obey \u2014 \"block any agent call that touches the prod database\", \"kill requests once the session budget drops below $1\", \"never allow shell tool calls containing rm -rf\". You convert the rule into an AssemblyScript policy, compile it to WebAssembly, dry-run it against mock contexts, and install it into the local Intutic proxy. The proxy hot-loads it within ~5 seconds and enforces it on every intercepted LLM request.\n\n## 1. The contract your rule sees\n\nThe proxy calls `evaluate(offset, len)` with a JSON-serialized `RequestContext`:\n\n```jsonc\n{\n \"session_id\": \"sess_x\", \"workspace_id\": \"ws_x\", \"virtual_key_prefix\": \"vk_x\",\n \"model\": \"claude-3-5-sonnet\",\n \"tools\": [{ \"name\": \"bash\", \"description\": \"run shell commands\" }],\n \"tool_calls\": [{ \"id\": \"t1\", \"name\": \"bash\", \"arguments\": {} }],\n \"estimated_input_tokens\": 1200,\n \"budget_remaining_usd\": 4.25,\n \"risk_tier\": \"Low\",\n \"dlp_findings\": [{ \"category\": \"secret\", \"pattern_name\": \"aws_key\", \"action\": \"block\", \"offset\": 0, \"length\": 20 }],\n \"tool_sequence\": [\"read_file\", \"bash\"]\n}\n```\n\n`risk_tier` is one of `Low | Medium | High | Critical`. Return an `i32` verdict: `0` = ALLOW, `1` = BLOCK, `2` = REDACT (treated as block).\n\n## 2. Author\n\nStart from the `@intutic/wasm-sdk` template (`packages/wasm-sdk/` in the open-core repo). Add one function per business rule and call it from `runRules()` in `assembly/index.ts`.\n\nSandbox constraints \u2014 violating them silently disables the rule (the proxy **fails open**):\n\n- 5 ms wall-clock budget, 1,000,000 fuel, 16 MB memory.\n- Keep logic simple: no unbounded loops over `arguments`, no recursion, no I/O (none exists in the sandbox).\n- Host imports are limited to `env.log_info`, `env.trace`, `env.abort`, `env.seed`, and the `onnx_rules.runOnnxInference` stub.\n\n## 3. Compile\n\n```bash\nintutic policy compile --src assembly/index.ts --out build/rule.wasm\n```\n\nRequires AssemblyScript in the project: `pnpm add -D assemblyscript assemblyscript-json`.\n\n## 4. Dry-run \u2014 required before install\n\nAuthor BOTH mock contexts and verify both outcomes before installing:\n\n```bash\nintutic policy test --wasm build/rule.wasm --mock should-block.json\nintutic policy test --wasm build/rule.wasm --mock should-allow.json\n```\n\nThe first must report BLOCK, the second ALLOW. A rule that blocks everything is as broken as one that blocks nothing.\n\n## 5. Install\n\n```bash\nintutic policy install --wasm build/rule.wasm --name block-prod-db --priority 50\nintutic policy list-local\n```\n\nRules install to `~/.intutic/wasm/` as `NN_name.wasm` (lower `NN` runs first; default 100). The proxy picks up changes within ~5 s on the next request \u2014 no restart needed.\n\n## 6. Guardrails\n\n- **Never embed secrets** (API keys, tokens, passwords) in rule sources or mock contexts \u2014 `intutic skill audit` flags them.\n- **Local rules cannot weaken central rules.** Verdicts merge most-restrictive-wins: a KILL from any rule \u2014 local or centrally synced \u2014 ends the request. \"Allow-override\" rules are no-ops by design; do not author them.\n- Keep rule sources (`assembly/*.ts`, mock JSON files) in version control alongside the workspace.\n";
18
+ export declare const RULE_AUTHOR_SKILL = "---\nname: intutic-rule-author\ndescription: Convert natural-language business rules into compiled WASM governance policies enforced by the local Intutic proxy \u2014 author, compile, dry-run, and install rules without a control plane.\n---\n\n# \uD83D\uDCDC Rule Author \u2014 Business Rules as Enforced WASM Policies\n\nUse this skill whenever the user states a rule that AI agent traffic must obey \u2014 \"block any agent call that touches the prod database\", \"kill requests once the session budget drops below $1\", \"never allow shell tool calls containing rm -rf\". You convert the rule into an AssemblyScript policy, compile it to WebAssembly, dry-run it against mock contexts, and install it into the local Intutic proxy. The proxy hot-loads it within ~5 seconds and enforces it on every intercepted LLM request.\n\n**The other way you get here is `/fix`.** That proxy command scores the workspace's governance posture and, when it finds no custom policy, recommends: *\"Add a WASM rule under `~/.intutic/wasm` to codify a custom guardrail.\"* When that recommendation is the prompt, the rule to author is the gap `/fix` found \u2014 ask the user which specific behaviour they want blocked rather than writing a generic rule, then run `/fix` again after installing to confirm the posture score moved. If it did not, the rule is not loading: check `intutic policy list-local` and the sandbox constraints in \u00A72, since a rule that violates them is silently disabled.\n\n## 1. The contract your rule sees\n\nThe proxy calls `evaluate(offset, len)` with a JSON-serialized `RequestContext`:\n\n```jsonc\n{\n \"session_id\": \"sess_x\", \"workspace_id\": \"ws_x\", \"virtual_key_prefix\": \"vk_x\",\n \"model\": \"claude-3-5-sonnet\",\n \"tools\": [{ \"name\": \"bash\", \"description\": \"run shell commands\" }],\n \"tool_calls\": [{ \"id\": \"t1\", \"name\": \"bash\", \"arguments\": {} }],\n \"estimated_input_tokens\": 1200,\n \"budget_remaining_usd\": 4.25,\n \"risk_tier\": \"Low\",\n \"dlp_findings\": [{ \"category\": \"secret\", \"pattern_name\": \"aws_access_key\", \"action\": \"redact\", \"offset\": 0, \"length\": 20 }],\n \"tool_sequence\": [\"read_file\", \"bash\"]\n}\n```\n\n`risk_tier` is one of `Low | Medium | High | Critical`. Return an `i32` verdict: `0` = ALLOW, `1` = BLOCK, `3` = REASK (refuse this attempt, tell the agent why, let it retry). `2` is deprecated \u2014 the guest never receives the request body, so redaction was never expressible; the proxy maps it to a block. Prefer `3` over `1` for any finding that is a pattern match, because pattern matches produce false positives.\n\n## 2. Author\n\nStart from the `@intutic/wasm-sdk` template (`packages/wasm-sdk/` in the open-core repo). Add one function per business rule and call it from `runRules()` in `assembly/index.ts`.\n\nSandbox constraints \u2014 violating them silently disables the rule (the proxy **fails open**):\n\n- 5 ms wall-clock budget, 1,000,000 fuel, 16 MB memory.\n- Keep logic simple: no unbounded loops over `arguments`, no recursion, no I/O (none exists in the sandbox).\n- Host imports are limited to `env.log_info`, `env.trace`, `env.abort` and `env.read_referenced_file` (reads the bytes of a file the host already resolved before the sandbox existed \u2014 not a filesystem import, and it cannot be used to browse). A rule importing anything else cannot link, so it is refused at `intutic policy install` and refused again when the proxy loads it.\n- **`Math.random()` is unavailable.** AssemblyScript compiles it to an `env.seed` import the proxy does not provide. This list previously named `env.seed`, and a rule using randomness installed clean and then failed to link on every request \u2014 enforcing nothing, silently. Beyond the missing import, a verdict that samples is not a verdict: the same request would get different answers, and the audit trail would not explain either.\n\n## 3. Compile\n\n```bash\nintutic policy compile --src assembly/index.ts --out build/rule.wasm\n```\n\nRequires AssemblyScript in the project: `pnpm add -D assemblyscript assemblyscript-json`.\n\n## 4. Dry-run \u2014 required before install\n\nAuthor BOTH mock contexts and verify both outcomes before installing:\n\n```bash\nintutic policy test --wasm build/rule.wasm --mock should-block.json\nintutic policy test --wasm build/rule.wasm --mock should-allow.json\n```\n\nThe first must report BLOCK, the second ALLOW. A rule that blocks everything is as broken as one that blocks nothing.\n\n## 5. Install\n\n```bash\nintutic policy install --wasm build/rule.wasm --name block-prod-db --priority 50\nintutic policy list-local\n```\n\nRules install to `~/.intutic/wasm/` as `NN_name.wasm` (lower `NN` runs first; default 100). The proxy picks up changes within ~5 s on the next request \u2014 no restart needed.\n\n## 6. Guardrails\n\n- **Never embed secrets** (API keys, tokens, passwords) in rule sources or mock contexts \u2014 `intutic skill audit` flags them.\n- **Local rules cannot weaken central rules.** Verdicts merge most-restrictive-wins: a KILL from any rule \u2014 local or centrally synced \u2014 ends the request. \"Allow-override\" rules are no-ops by design; do not author them.\n- Keep rule sources (`assembly/*.ts`, mock JSON files) in version control alongside the workspace.\n";
19
19
  /**
20
20
  * Write bundled skills into the workspace, skipping any that already exist.
21
21
  * Returns the paths written (empty when everything was already present).
@@ -1 +1 @@
1
- {"version":3,"file":"skillWriter.d.ts","sourceRoot":"","sources":["../src/skillWriter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,mEAAmE;AACnE,eAAO,MAAM,sBAAsB,QAKlC,CAAA;AAED,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,wmHAwE7B,CAAA;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAejF"}
1
+ {"version":3,"file":"skillWriter.d.ts","sourceRoot":"","sources":["../src/skillWriter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,mEAAmE;AACnE,eAAO,MAAM,sBAAsB,QAKlC,CAAA;AAED,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,0sKA2E7B,CAAA;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAejF"}
@@ -26,6 +26,8 @@ description: Convert natural-language business rules into compiled WASM governan
26
26
 
27
27
  Use this skill whenever the user states a rule that AI agent traffic must obey — "block any agent call that touches the prod database", "kill requests once the session budget drops below $1", "never allow shell tool calls containing rm -rf". You convert the rule into an AssemblyScript policy, compile it to WebAssembly, dry-run it against mock contexts, and install it into the local Intutic proxy. The proxy hot-loads it within ~5 seconds and enforces it on every intercepted LLM request.
28
28
 
29
+ **The other way you get here is \`/fix\`.** That proxy command scores the workspace's governance posture and, when it finds no custom policy, recommends: *"Add a WASM rule under \`~/.intutic/wasm\` to codify a custom guardrail."* When that recommendation is the prompt, the rule to author is the gap \`/fix\` found — ask the user which specific behaviour they want blocked rather than writing a generic rule, then run \`/fix\` again after installing to confirm the posture score moved. If it did not, the rule is not loading: check \`intutic policy list-local\` and the sandbox constraints in §2, since a rule that violates them is silently disabled.
30
+
29
31
  ## 1. The contract your rule sees
30
32
 
31
33
  The proxy calls \`evaluate(offset, len)\` with a JSON-serialized \`RequestContext\`:
@@ -39,12 +41,12 @@ The proxy calls \`evaluate(offset, len)\` with a JSON-serialized \`RequestContex
39
41
  "estimated_input_tokens": 1200,
40
42
  "budget_remaining_usd": 4.25,
41
43
  "risk_tier": "Low",
42
- "dlp_findings": [{ "category": "secret", "pattern_name": "aws_key", "action": "block", "offset": 0, "length": 20 }],
44
+ "dlp_findings": [{ "category": "secret", "pattern_name": "aws_access_key", "action": "redact", "offset": 0, "length": 20 }],
43
45
  "tool_sequence": ["read_file", "bash"]
44
46
  }
45
47
  \`\`\`
46
48
 
47
- \`risk_tier\` is one of \`Low | Medium | High | Critical\`. Return an \`i32\` verdict: \`0\` = ALLOW, \`1\` = BLOCK, \`2\` = REDACT (treated as block).
49
+ \`risk_tier\` is one of \`Low | Medium | High | Critical\`. Return an \`i32\` verdict: \`0\` = ALLOW, \`1\` = BLOCK, \`3\` = REASK (refuse this attempt, tell the agent why, let it retry). \`2\` is deprecated — the guest never receives the request body, so redaction was never expressible; the proxy maps it to a block. Prefer \`3\` over \`1\` for any finding that is a pattern match, because pattern matches produce false positives.
48
50
 
49
51
  ## 2. Author
50
52
 
@@ -54,7 +56,8 @@ Sandbox constraints — violating them silently disables the rule (the proxy **f
54
56
 
55
57
  - 5 ms wall-clock budget, 1,000,000 fuel, 16 MB memory.
56
58
  - Keep logic simple: no unbounded loops over \`arguments\`, no recursion, no I/O (none exists in the sandbox).
57
- - Host imports are limited to \`env.log_info\`, \`env.trace\`, \`env.abort\`, \`env.seed\`, and the \`onnx_rules.runOnnxInference\` stub.
59
+ - Host imports are limited to \`env.log_info\`, \`env.trace\`, \`env.abort\` and \`env.read_referenced_file\` (reads the bytes of a file the host already resolved before the sandbox existed — not a filesystem import, and it cannot be used to browse). A rule importing anything else cannot link, so it is refused at \`intutic policy install\` and refused again when the proxy loads it.
60
+ - **\`Math.random()\` is unavailable.** AssemblyScript compiles it to an \`env.seed\` import the proxy does not provide. This list previously named \`env.seed\`, and a rule using randomness installed clean and then failed to link on every request — enforcing nothing, silently. Beyond the missing import, a verdict that samples is not a verdict: the same request would get different answers, and the audit trail would not explain either.
58
61
 
59
62
  ## 3. Compile
60
63
 
@@ -1 +1 @@
1
- {"version":3,"file":"skillWriter.js","sourceRoot":"","sources":["../src/skillWriter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,SAAS,MAAM,WAAW,CAAA;AAEtC,mEAAmE;AACnE,MAAM,CAAC,MAAM,sBAAsB,GAAG,SAAS,CAAC,IAAI,CAClD,SAAS,EACT,QAAQ,EACR,qBAAqB,EACrB,UAAU,CACX,CAAA;AAED,gFAAgF;AAChF,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwEhC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,aAAqB;IAC5D,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAA;IAElE,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAC1B,OAAO,OAAO,CAAA,CAAC,uCAAuC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;IAED,MAAM,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACjE,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAA;IACzD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAClB,OAAO,OAAO,CAAA;AAChB,CAAC"}
1
+ {"version":3,"file":"skillWriter.js","sourceRoot":"","sources":["../src/skillWriter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,SAAS,MAAM,WAAW,CAAA;AAEtC,mEAAmE;AACnE,MAAM,CAAC,MAAM,sBAAsB,GAAG,SAAS,CAAC,IAAI,CAClD,SAAS,EACT,QAAQ,EACR,qBAAqB,EACrB,UAAU,CACX,CAAA;AAED,gFAAgF;AAChF,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2EhC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,aAAqB;IAC5D,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAA;IAElE,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAC1B,OAAO,OAAO,CAAA,CAAC,uCAAuC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;IAED,MAAM,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACjE,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAA;IACzD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAClB,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -18,7 +18,47 @@
18
18
  *
19
19
  * @module
20
20
  */
21
- import type { HarnessType, SyncConfigPayload, WorkspaceSettings } from '@intutic/shared-types';
21
+ import type { HarnessType, SyncConfigPayload, WorkspaceSettings, SyncSopEntry } from '@intutic/shared-types';
22
+ import { type GovernanceCoverageInputs } from './configReader.js';
23
+ import { type AgentReport } from './agentReporter.js';
24
+ /**
25
+ * Turns a non-clean `scanSkillContent` result — already computed as part of
26
+ * `collectAgentReport`'s `facets.skills` — into a `skill_flagged` hook event
27
+ * (TD-358).
28
+ *
29
+ * Deliberately reuses the report the daemon already built for this cycle
30
+ * rather than re-scanning: `agentReporter.ts`'s `collectSkills` runs
31
+ * `scanSkillContent` on every `.agents/skills/**\/SKILL.md` as part of
32
+ * building `facets.skills` already, so this only turns a result the daemon
33
+ * already has into a visible signal — it does not add a second scan pass.
34
+ *
35
+ * Appends directly to `.intutic/events/hook-events.jsonl`, the SAME file
36
+ * every emitted PreToolUse gate's `log_event`/`logEvent` writes to and the
37
+ * SAME mechanism `onDriftDetected` below already uses for `config_tamper` —
38
+ * not a new event pipeline. `drainHookEvents` (`claudeCodeHooks.ts`) picks
39
+ * this line up on its next pass exactly like a gate-written one, because it
40
+ * only ever reads the file; it does not care who appended a given line.
41
+ *
42
+ * Report-only, per `scanSkillContent`'s own doc comment on the unmeasured
43
+ * false-positive rate against real, benign skill markdown: this NEVER
44
+ * blocks, mutates, or removes a skill. `hookEvents.ts`'s
45
+ * `HookEventSchema.event` enum (control plane) counts `skill_flagged`
46
+ * exactly like `tool_flagged` — advisory telemetry, not an incident.
47
+ *
48
+ * A failure to append is caught and warned, never thrown: a governance
49
+ * telemetry write must not be able to abort the sync cycle it rides in on.
50
+ */
51
+ export declare function emitSkillFlaggedEvents(opts: {
52
+ workspaceRoot: string;
53
+ workspaceId: string;
54
+ harnessType: HarnessType;
55
+ skills: AgentReport['facets']['skills'];
56
+ /** Skills already emitted in this cycle, keyed `source:name`, mutated in
57
+ * place. A skill is not harness-specific, and the caller invokes this
58
+ * once per harness in the workspace — without a shared set, a workspace
59
+ * with two active harnesses would double-emit every flagged skill. */
60
+ alreadyEmitted: Set<string>;
61
+ }): void;
22
62
  /** Configuration for the sync loop. */
23
63
  export interface SyncLoopOptions {
24
64
  /** Control plane base URL (e.g., `https://api.intutic.ai`). */
@@ -37,8 +77,6 @@ export interface SyncLoopOptions {
37
77
  onSync?: (result: SyncResult) => void;
38
78
  /** AbortSignal to gracefully stop the loop. */
39
79
  signal?: AbortSignal;
40
- /** Adapter identifier for ContextGraph sync. */
41
- adapterId?: string;
42
80
  }
43
81
  /** Result of a single sync iteration. */
44
82
  export interface SyncResult {
@@ -58,6 +96,15 @@ export interface SyncResult {
58
96
  proxyUrl?: string;
59
97
  /** Active harnesses. */
60
98
  harnesses?: HarnessType[];
99
+ /**
100
+ * This cycle's per-harness governance-coverage enforcement signals, derived
101
+ * from the same `collectAgentReport` facets step 5b already computes for
102
+ * `POST /api/v1/agents/report` — see that step's inline derivation for the
103
+ * mapping. Consumed by the outer loop's config-capture step to fire
104
+ * `POST /api/v1/governance-coverage/snapshot` once per harness whose rules
105
+ * file content actually changed this cycle.
106
+ */
107
+ harnessGovernanceInputs?: Partial<Record<HarnessType, GovernanceCoverageInputs>>;
61
108
  }
62
109
  /**
63
110
  * Start the sync loop. This function runs indefinitely until the
@@ -65,6 +112,61 @@ export interface SyncResult {
65
112
  *
66
113
  * @param options - Sync loop configuration.
67
114
  */
115
+ /** The credentials every gate-side refresh takes. */
116
+ export interface GateCacheRefreshOptions {
117
+ controlPlaneUrl: string;
118
+ apiKey: string;
119
+ workspaceId: string;
120
+ /** See {@link PolicySnapshotOptions.localHoldTokens}. */
121
+ localHoldTokens?: readonly string[];
122
+ }
123
+ /**
124
+ * The `review_before:` tokens the snapshot compiles into hold rules: from the
125
+ * synced SOPs' front matter and JSON blocks, the workspace settings, and the
126
+ * local `.intutic/sops`. The same parse the Claude Code writer runs for its
127
+ * pattern blacklist, so the two cannot disagree about what is held.
128
+ */
129
+ export declare function localHoldTokensFor(workspaceRoot: string, sops: SyncSopEntry[], settings: Record<string, unknown> | undefined, harnesses?: HarnessType[]): Promise<string[]>;
130
+ /**
131
+ * Refresh the three gate-side caches every hook reads: the policy snapshot
132
+ * (`~/.intutic/hooks/policy-snapshot.rules`), the approved review-hold
133
+ * bypasses and the central egress policy. Called on EVERY sync cycle by both
134
+ * loops — this one and `intutic connect`'s — never only when the config
135
+ * version moved: policy changes without the version changing, and before
136
+ * this helper existed `connect` refreshed once at startup and never again, so
137
+ * a guardrail promoted mid-session reached a connected machine only on
138
+ * restart (TD-488). None of the three throw; the return says which of them
139
+ * landed.
140
+ */
141
+ export declare function refreshGateCaches(opts: GateCacheRefreshOptions): Promise<{
142
+ snapshot: boolean;
143
+ bypasses: boolean;
144
+ egress: boolean;
145
+ }>;
68
146
  export declare function startSyncLoop(options: SyncLoopOptions): Promise<void>;
147
+ export interface IterationContext {
148
+ controlPlaneUrl: string;
149
+ apiKey: string;
150
+ workspaceId: string;
151
+ workspaceRoot: string;
152
+ onSync?: (result: SyncResult) => void;
153
+ }
154
+ /**
155
+ * Execute a single sync iteration:
156
+ * 1. Fetch config from control plane
157
+ * 2. Write config files if version is newer
158
+ * 3. Compute file hashes
159
+ * 4. Report status back to control plane
160
+ * 5. Update local integrity store
161
+ * 6. Call onSync callback
162
+ *
163
+ * Exported (in addition to being used internally by `startSyncLoop`'s
164
+ * polling loop) as a test seam — it is the unit that exercises exactly one
165
+ * cycle's worth of work, including the injectMcpServer call (step 3c),
166
+ * without the surrounding while-loop's extra one-time/Nth-iteration network
167
+ * calls (policy snapshot, approved bypasses, egress policy, compliance
168
+ * probes, drift watcher, decisions digest, config capture).
169
+ */
170
+ export declare function runSyncIteration(ctx: IterationContext): Promise<SyncResult>;
69
171
  export declare function syncOfflineTraces(controlPlaneUrl: string, apiKey: string): Promise<void>;
70
172
  //# sourceMappingURL=syncLoop.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"syncLoop.d.ts","sourceRoot":"","sources":["../src/syncLoop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EAEjB,iBAAiB,EAClB,MAAM,uBAAuB,CAAA;AAe9B,uCAAuC;AACvC,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,eAAe,EAAE,MAAM,CAAA;IACvB,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAA;IACd,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,qDAAqD;IACrD,aAAa,EAAE,MAAM,CAAA;IACrB,sDAAsD;IACtD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAA;IACrC,+CAA+C;IAC/C,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,yCAAyC;AACzC,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,aAAa,EAAE,MAAM,CAAA;IACrB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAA;IACnB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,4BAA4B;IAC5B,IAAI,CAAC,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAA;IAChC,iBAAiB;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wBAAwB;IACxB,SAAS,CAAC,EAAE,WAAW,EAAE,CAAA;CAC1B;AAQD;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAyN3E;AAkTD,wBAAsB,iBAAiB,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqE9F"}
1
+ {"version":3,"file":"syncLoop.d.ts","sourceRoot":"","sources":["../src/syncLoop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EAEjB,iBAAiB,EACjB,YAAY,EACb,MAAM,uBAAuB,CAAA;AAqB9B,OAAO,EAAgD,KAAK,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AAS/G,OAAO,EAA8D,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAqBjH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,WAAW,CAAA;IACxB,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAA;IACvC;;;2EAGuE;IACvE,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAC5B,GAAG,IAAI,CA+BP;AAID,uCAAuC;AACvC,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,eAAe,EAAE,MAAM,CAAA;IACvB,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAA;IACd,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,qDAAqD;IACrD,aAAa,EAAE,MAAM,CAAA;IACrB,sDAAsD;IACtD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAA;IACrC,+CAA+C;IAC/C,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,yCAAyC;AACzC,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,aAAa,EAAE,MAAM,CAAA;IACrB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAA;IACnB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,4BAA4B;IAC5B,IAAI,CAAC,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAA;IAChC,iBAAiB;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wBAAwB;IACxB,SAAS,CAAC,EAAE,WAAW,EAAE,CAAA;IACzB;;;;;;;OAOG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,wBAAwB,CAAC,CAAC,CAAA;CACjF;AA6BD;;;;;GAKG;AACH,qDAAqD;AACrD,MAAM,WAAW,uBAAuB;IACtC,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,yDAAyD;IACzD,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,YAAY,EAAE,EACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC7C,SAAS,GAAE,WAAW,EAAO,GAC5B,OAAO,CAAC,MAAM,EAAE,CAAC,CAGnB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CAKpE;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA8R3E;AAID,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CA4PjF;AAwKD,wBAAsB,iBAAiB,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqE9F"}