@intutic/sync-daemon 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/brainIndexer.d.ts +51 -0
- package/dist/brainIndexer.d.ts.map +1 -0
- package/dist/brainIndexer.js +148 -0
- package/dist/brainIndexer.js.map +1 -0
- package/dist/configReader.d.ts +46 -0
- package/dist/configReader.d.ts.map +1 -0
- package/dist/configReader.js +133 -0
- package/dist/configReader.js.map +1 -0
- package/dist/configWriter.d.ts +53 -0
- package/dist/configWriter.d.ts.map +1 -0
- package/dist/configWriter.js +503 -0
- package/dist/configWriter.js.map +1 -0
- package/dist/harness/aiderConfigMerger.d.ts +27 -0
- package/dist/harness/aiderConfigMerger.d.ts.map +1 -0
- package/dist/harness/aiderConfigMerger.js +139 -0
- package/dist/harness/aiderConfigMerger.js.map +1 -0
- package/dist/harness/antigravityHooks.d.ts +43 -0
- package/dist/harness/antigravityHooks.d.ts.map +1 -0
- package/dist/harness/antigravityHooks.js +193 -0
- package/dist/harness/antigravityHooks.js.map +1 -0
- package/dist/harness/claudeCodeHooks.d.ts +59 -0
- package/dist/harness/claudeCodeHooks.d.ts.map +1 -0
- package/dist/harness/claudeCodeHooks.js +414 -0
- package/dist/harness/claudeCodeHooks.js.map +1 -0
- package/dist/harness/claudeDesktopHooks.d.ts +30 -0
- package/dist/harness/claudeDesktopHooks.d.ts.map +1 -0
- package/dist/harness/claudeDesktopHooks.js +267 -0
- package/dist/harness/claudeDesktopHooks.js.map +1 -0
- package/dist/harness/clineHooks.d.ts +23 -0
- package/dist/harness/clineHooks.d.ts.map +1 -0
- package/dist/harness/clineHooks.js +169 -0
- package/dist/harness/clineHooks.js.map +1 -0
- package/dist/harness/continueHooks.d.ts +33 -0
- package/dist/harness/continueHooks.d.ts.map +1 -0
- package/dist/harness/continueHooks.js +124 -0
- package/dist/harness/continueHooks.js.map +1 -0
- package/dist/harness/cursorHooks.d.ts +27 -0
- package/dist/harness/cursorHooks.d.ts.map +1 -0
- package/dist/harness/cursorHooks.js +221 -0
- package/dist/harness/cursorHooks.js.map +1 -0
- package/dist/harness/cursorHooksJson.d.ts +29 -0
- package/dist/harness/cursorHooksJson.d.ts.map +1 -0
- package/dist/harness/cursorHooksJson.js +130 -0
- package/dist/harness/cursorHooksJson.js.map +1 -0
- package/dist/harness/gooseHardener.d.ts +39 -0
- package/dist/harness/gooseHardener.d.ts.map +1 -0
- package/dist/harness/gooseHardener.js +152 -0
- package/dist/harness/gooseHardener.js.map +1 -0
- package/dist/harness/gooseHooks.d.ts +24 -0
- package/dist/harness/gooseHooks.d.ts.map +1 -0
- package/dist/harness/gooseHooks.js +175 -0
- package/dist/harness/gooseHooks.js.map +1 -0
- package/dist/harness/gooseHooksWriter.d.ts +27 -0
- package/dist/harness/gooseHooksWriter.d.ts.map +1 -0
- package/dist/harness/gooseHooksWriter.js +147 -0
- package/dist/harness/gooseHooksWriter.js.map +1 -0
- package/dist/harness/hermesHooks.d.ts +31 -0
- package/dist/harness/hermesHooks.d.ts.map +1 -0
- package/dist/harness/hermesHooks.js +245 -0
- package/dist/harness/hermesHooks.js.map +1 -0
- package/dist/harness/mcpAutoWrite.d.ts +35 -0
- package/dist/harness/mcpAutoWrite.d.ts.map +1 -0
- package/dist/harness/mcpAutoWrite.js +334 -0
- package/dist/harness/mcpAutoWrite.js.map +1 -0
- package/dist/harness/n8nHooks.d.ts +28 -0
- package/dist/harness/n8nHooks.d.ts.map +1 -0
- package/dist/harness/n8nHooks.js +205 -0
- package/dist/harness/n8nHooks.js.map +1 -0
- package/dist/harness/openWebuiHooks.d.ts +31 -0
- package/dist/harness/openWebuiHooks.d.ts.map +1 -0
- package/dist/harness/openWebuiHooks.js +166 -0
- package/dist/harness/openWebuiHooks.js.map +1 -0
- package/dist/harness/openclawHooks.d.ts +34 -0
- package/dist/harness/openclawHooks.d.ts.map +1 -0
- package/dist/harness/openclawHooks.js +296 -0
- package/dist/harness/openclawHooks.js.map +1 -0
- package/dist/harness/openhandsHooks.d.ts +24 -0
- package/dist/harness/openhandsHooks.d.ts.map +1 -0
- package/dist/harness/openhandsHooks.js +178 -0
- package/dist/harness/openhandsHooks.js.map +1 -0
- package/dist/harness/openhandsHooksWriter.d.ts +23 -0
- package/dist/harness/openhandsHooksWriter.d.ts.map +1 -0
- package/dist/harness/openhandsHooksWriter.js +146 -0
- package/dist/harness/openhandsHooksWriter.js.map +1 -0
- package/dist/harness/piHooks.d.ts +32 -0
- package/dist/harness/piHooks.d.ts.map +1 -0
- package/dist/harness/piHooks.js +257 -0
- package/dist/harness/piHooks.js.map +1 -0
- package/dist/harness/rooCodeHooks.d.ts +31 -0
- package/dist/harness/rooCodeHooks.d.ts.map +1 -0
- package/dist/harness/rooCodeHooks.js +300 -0
- package/dist/harness/rooCodeHooks.js.map +1 -0
- package/dist/harness/windsurfHooks.d.ts +27 -0
- package/dist/harness/windsurfHooks.d.ts.map +1 -0
- package/dist/harness/windsurfHooks.js +202 -0
- package/dist/harness/windsurfHooks.js.map +1 -0
- package/dist/hashReporter.d.ts +33 -0
- package/dist/hashReporter.d.ts.map +1 -0
- package/dist/hashReporter.js +69 -0
- package/dist/hashReporter.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/integrityStore.d.ts +43 -0
- package/dist/integrityStore.d.ts.map +1 -0
- package/dist/integrityStore.js +94 -0
- package/dist/integrityStore.js.map +1 -0
- package/dist/lib/complianceProbes.d.ts +39 -0
- package/dist/lib/complianceProbes.d.ts.map +1 -0
- package/dist/lib/complianceProbes.js +115 -0
- package/dist/lib/complianceProbes.js.map +1 -0
- package/dist/lib/processPoller.d.ts +2 -0
- package/dist/lib/processPoller.d.ts.map +1 -0
- package/dist/lib/processPoller.js +87 -0
- package/dist/lib/processPoller.js.map +1 -0
- package/dist/lib/runtimeEnv.d.ts +49 -0
- package/dist/lib/runtimeEnv.d.ts.map +1 -0
- package/dist/lib/runtimeEnv.js +70 -0
- package/dist/lib/runtimeEnv.js.map +1 -0
- package/dist/skillWriter.d.ts +24 -0
- package/dist/skillWriter.d.ts.map +1 -0
- package/dist/skillWriter.js +112 -0
- package/dist/skillWriter.js.map +1 -0
- package/dist/syncLoop.d.ts +70 -0
- package/dist/syncLoop.d.ts.map +1 -0
- package/dist/syncLoop.js +546 -0
- package/dist/syncLoop.js.map +1 -0
- package/dist/trajectoryMonitor.d.ts +126 -0
- package/dist/trajectoryMonitor.d.ts.map +1 -0
- package/dist/trajectoryMonitor.js +291 -0
- package/dist/trajectoryMonitor.js.map +1 -0
- package/dist/watcher/driftWatcher.d.ts +25 -0
- package/dist/watcher/driftWatcher.d.ts.map +1 -0
- package/dist/watcher/driftWatcher.js +72 -0
- package/dist/watcher/driftWatcher.js.map +1 -0
- package/dist/watcher/settingsGuard.d.ts +32 -0
- package/dist/watcher/settingsGuard.d.ts.map +1 -0
- package/dist/watcher/settingsGuard.js +250 -0
- package/dist/watcher/settingsGuard.js.map +1 -0
- package/dist/wsClient.d.ts +49 -0
- package/dist/wsClient.d.ts.map +1 -0
- package/dist/wsClient.js +149 -0
- package/dist/wsClient.js.map +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* runtimeEnv.ts — Runtime credential file writer.
|
|
3
|
+
*
|
|
4
|
+
* Writes `~/.intutic/env/runtime.env` on every sync cycle so that generated
|
|
5
|
+
* hook scripts can source it at invocation time instead of having credentials
|
|
6
|
+
* baked in at generation time. This means:
|
|
7
|
+
*
|
|
8
|
+
* 1. Key rotation is instant — next tool call picks up the new key.
|
|
9
|
+
* 2. The key is never embedded in a hook script file on disk.
|
|
10
|
+
* 3. The file is chmod 0600 (owner read/write only).
|
|
11
|
+
*
|
|
12
|
+
* Format (POSIX sh source-compatible):
|
|
13
|
+
*
|
|
14
|
+
* INTUTIC_HOST=https://api.intutic.ai
|
|
15
|
+
* INTUTIC_API_KEY=sk-live-...
|
|
16
|
+
* INTUTIC_WORKSPACE_ID=ws_...
|
|
17
|
+
*
|
|
18
|
+
* LLD #14 — Dual-path hook telemetry (WS-A1)
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import * as fs from 'node:fs/promises';
|
|
23
|
+
import * as path from 'node:path';
|
|
24
|
+
import * as os from 'node:os';
|
|
25
|
+
import { createLogger } from '@intutic/logger';
|
|
26
|
+
const log = createLogger('sync-runtime-env');
|
|
27
|
+
/** Default path to the runtime env file sourced by all generated hook scripts. */
|
|
28
|
+
export const DEFAULT_RUNTIME_ENV_PATH = path.join(os.homedir(), '.intutic', 'env', 'runtime.env');
|
|
29
|
+
/**
|
|
30
|
+
* Write runtime credentials to `~/.intutic/env/runtime.env`.
|
|
31
|
+
*
|
|
32
|
+
* Uses atomic rename (.tmp -> final) so hook scripts never read a partial
|
|
33
|
+
* file. Sets permissions to 0o600 (owner read/write only).
|
|
34
|
+
*
|
|
35
|
+
* Safe to call on every sync cycle — idempotent, fast (single write).
|
|
36
|
+
*/
|
|
37
|
+
export async function writeRuntimeEnv(opts) {
|
|
38
|
+
const envPath = opts.envPath ?? DEFAULT_RUNTIME_ENV_PATH;
|
|
39
|
+
const envDir = path.dirname(envPath);
|
|
40
|
+
await fs.mkdir(envDir, { recursive: true });
|
|
41
|
+
// Sanitise values: strip newlines to prevent injection into the env file
|
|
42
|
+
const host = (opts.controlPlaneUrl ?? '').replace(/[\r\n]/g, '');
|
|
43
|
+
const key = (opts.apiKey ?? '').replace(/[\r\n]/g, '');
|
|
44
|
+
const wsId = (opts.workspaceId ?? '').replace(/[\r\n]/g, '');
|
|
45
|
+
const content = [
|
|
46
|
+
`# Intutic hook runtime credentials — auto-generated. DO NOT EDIT.`,
|
|
47
|
+
`# Sourced by ~/.intutic/hooks/*.sh and parsed by ~/.intutic/hooks/*.js at invocation time.`,
|
|
48
|
+
`# To rotate your API key: update via the Intutic control plane — daemon refreshes this file automatically.`,
|
|
49
|
+
`# WS-5: INTUTIC_MCP_FAIL_OPEN (Q1), INTUTIC_MCP_PROXY_MODE (Q2), INTUTIC_BYPASS_TIER (Q3) are written on every sync.`,
|
|
50
|
+
`INTUTIC_HOST=${host}`,
|
|
51
|
+
`INTUTIC_API_KEY=${key}`,
|
|
52
|
+
`INTUTIC_WORKSPACE_ID=${wsId}`,
|
|
53
|
+
`INTUTIC_MCP_FAIL_OPEN=${(opts.mcpProxyFailBehavior ?? 'open') !== 'closed' ? 'true' : 'false'}`,
|
|
54
|
+
`INTUTIC_MCP_PROXY_MODE=${opts.mcpProxyMode ?? 'per-session'}`,
|
|
55
|
+
`INTUTIC_BYPASS_TIER=${opts.bypassEnforcementTier ?? 'rewrite'}`,
|
|
56
|
+
``,
|
|
57
|
+
`# LLM proxy routing (uncomment when Intutic Rust proxy is running on port 8080)`,
|
|
58
|
+
`# GOOSE_BASE_URL=http://127.0.0.1:8080`,
|
|
59
|
+
`# OPENAI_BASE_URL=http://127.0.0.1:8080`,
|
|
60
|
+
`# ANTHROPIC_BASE_URL=http://127.0.0.1:8080`,
|
|
61
|
+
`# LLM_BASE_URL=http://127.0.0.1:8080`,
|
|
62
|
+
``,
|
|
63
|
+
].join('\n');
|
|
64
|
+
const tmpPath = envPath + '.tmp';
|
|
65
|
+
await fs.writeFile(tmpPath, content, { encoding: 'utf-8' });
|
|
66
|
+
await fs.chmod(tmpPath, 0o600);
|
|
67
|
+
await fs.rename(tmpPath, envPath);
|
|
68
|
+
log.debug({ action: 'runtime_env_written', path: envPath }, 'Runtime env file refreshed');
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=runtimeEnv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtimeEnv.js","sourceRoot":"","sources":["../../src/lib/runtimeEnv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;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;AAE9C,MAAM,GAAG,GAAG,YAAY,CAAC,kBAAkB,CAAC,CAAA;AAE5C,kFAAkF;AAClF,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,CAAC,CAAA;AAmBjG;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAuB;IAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,wBAAwB,CAAA;IACxD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAEpC,MAAM,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE3C,yEAAyE;IACzE,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IAChE,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IACtD,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IAE5D,MAAM,OAAO,GAAG;QACd,mEAAmE;QACnE,4FAA4F;QAC5F,4GAA4G;QAC5G,sHAAsH;QACtH,gBAAgB,IAAI,EAAE;QACtB,mBAAmB,GAAG,EAAE;QACxB,wBAAwB,IAAI,EAAE;QAC9B,yBAAyB,CAAC,IAAI,CAAC,oBAAoB,IAAI,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE;QAChG,0BAA0B,IAAI,CAAC,YAAY,IAAI,aAAa,EAAE;QAC9D,uBAAuB,IAAI,CAAC,qBAAqB,IAAI,SAAS,EAAE;QAChE,EAAE;QACF,iFAAiF;QACjF,wCAAwC;QACxC,yCAAyC;QACzC,4CAA4C;QAC5C,sCAAsC;QACtC,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEZ,MAAM,OAAO,GAAG,OAAO,GAAG,MAAM,CAAA;IAChC,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;IAC3D,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC9B,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAEjC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,qBAAqB,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,4BAA4B,CAAC,CAAA;AAC3F,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skillWriter.ts — Write bundled agent skills into the workspace.
|
|
3
|
+
*
|
|
4
|
+
* Unlike SOP files, skills are static documentation for the agent: they are
|
|
5
|
+
* written only when absent (write-if-missing), never overwrite user edits,
|
|
6
|
+
* and are deliberately not tracked by the drift watcher / IntegrityStore.
|
|
7
|
+
*
|
|
8
|
+
* The skill content is embedded as a constant because the daemon runs
|
|
9
|
+
* outside the monorepo. The canonical source is
|
|
10
|
+
* `.agents/skills/intutic-rule-author/SKILL.md` in the open-core repo; a
|
|
11
|
+
* test asserts the two stay identical.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
/** Workspace-relative path the rule-author skill is written to. */
|
|
16
|
+
export declare const RULE_AUTHOR_SKILL_PATH: string;
|
|
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";
|
|
19
|
+
/**
|
|
20
|
+
* Write bundled skills into the workspace, skipping any that already exist.
|
|
21
|
+
* Returns the paths written (empty when everything was already present).
|
|
22
|
+
*/
|
|
23
|
+
export declare function writeBundledSkills(workspaceRoot: string): Promise<string[]>;
|
|
24
|
+
//# sourceMappingURL=skillWriter.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skillWriter.ts — Write bundled agent skills into the workspace.
|
|
3
|
+
*
|
|
4
|
+
* Unlike SOP files, skills are static documentation for the agent: they are
|
|
5
|
+
* written only when absent (write-if-missing), never overwrite user edits,
|
|
6
|
+
* and are deliberately not tracked by the drift watcher / IntegrityStore.
|
|
7
|
+
*
|
|
8
|
+
* The skill content is embedded as a constant because the daemon runs
|
|
9
|
+
* outside the monorepo. The canonical source is
|
|
10
|
+
* `.agents/skills/intutic-rule-author/SKILL.md` in the open-core repo; a
|
|
11
|
+
* test asserts the two stay identical.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import * as node_fs from 'node:fs/promises';
|
|
16
|
+
import * as node_path from 'node:path';
|
|
17
|
+
/** Workspace-relative path the rule-author skill is written to. */
|
|
18
|
+
export const RULE_AUTHOR_SKILL_PATH = node_path.join('.agents', 'skills', 'intutic-rule-author', 'SKILL.md');
|
|
19
|
+
/** Embedded copy of .agents/skills/intutic-rule-author/SKILL.md (canonical). */
|
|
20
|
+
export const RULE_AUTHOR_SKILL = `---
|
|
21
|
+
name: intutic-rule-author
|
|
22
|
+
description: Convert natural-language business rules into compiled WASM governance policies enforced by the local Intutic proxy — author, compile, dry-run, and install rules without a control plane.
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# 📜 Rule Author — Business Rules as Enforced WASM Policies
|
|
26
|
+
|
|
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
|
+
|
|
29
|
+
## 1. The contract your rule sees
|
|
30
|
+
|
|
31
|
+
The proxy calls \`evaluate(offset, len)\` with a JSON-serialized \`RequestContext\`:
|
|
32
|
+
|
|
33
|
+
\`\`\`jsonc
|
|
34
|
+
{
|
|
35
|
+
"session_id": "sess_x", "workspace_id": "ws_x", "virtual_key_prefix": "vk_x",
|
|
36
|
+
"model": "claude-3-5-sonnet",
|
|
37
|
+
"tools": [{ "name": "bash", "description": "run shell commands" }],
|
|
38
|
+
"tool_calls": [{ "id": "t1", "name": "bash", "arguments": {} }],
|
|
39
|
+
"estimated_input_tokens": 1200,
|
|
40
|
+
"budget_remaining_usd": 4.25,
|
|
41
|
+
"risk_tier": "Low",
|
|
42
|
+
"dlp_findings": [{ "category": "secret", "pattern_name": "aws_key", "action": "block", "offset": 0, "length": 20 }],
|
|
43
|
+
"tool_sequence": ["read_file", "bash"]
|
|
44
|
+
}
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
\`risk_tier\` is one of \`Low | Medium | High | Critical\`. Return an \`i32\` verdict: \`0\` = ALLOW, \`1\` = BLOCK, \`2\` = REDACT (treated as block).
|
|
48
|
+
|
|
49
|
+
## 2. Author
|
|
50
|
+
|
|
51
|
+
Start 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\`.
|
|
52
|
+
|
|
53
|
+
Sandbox constraints — violating them silently disables the rule (the proxy **fails open**):
|
|
54
|
+
|
|
55
|
+
- 5 ms wall-clock budget, 1,000,000 fuel, 16 MB memory.
|
|
56
|
+
- 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.
|
|
58
|
+
|
|
59
|
+
## 3. Compile
|
|
60
|
+
|
|
61
|
+
\`\`\`bash
|
|
62
|
+
intutic policy compile --src assembly/index.ts --out build/rule.wasm
|
|
63
|
+
\`\`\`
|
|
64
|
+
|
|
65
|
+
Requires AssemblyScript in the project: \`pnpm add -D assemblyscript assemblyscript-json\`.
|
|
66
|
+
|
|
67
|
+
## 4. Dry-run — required before install
|
|
68
|
+
|
|
69
|
+
Author BOTH mock contexts and verify both outcomes before installing:
|
|
70
|
+
|
|
71
|
+
\`\`\`bash
|
|
72
|
+
intutic policy test --wasm build/rule.wasm --mock should-block.json
|
|
73
|
+
intutic policy test --wasm build/rule.wasm --mock should-allow.json
|
|
74
|
+
\`\`\`
|
|
75
|
+
|
|
76
|
+
The first must report BLOCK, the second ALLOW. A rule that blocks everything is as broken as one that blocks nothing.
|
|
77
|
+
|
|
78
|
+
## 5. Install
|
|
79
|
+
|
|
80
|
+
\`\`\`bash
|
|
81
|
+
intutic policy install --wasm build/rule.wasm --name block-prod-db --priority 50
|
|
82
|
+
intutic policy list-local
|
|
83
|
+
\`\`\`
|
|
84
|
+
|
|
85
|
+
Rules 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 — no restart needed.
|
|
86
|
+
|
|
87
|
+
## 6. Guardrails
|
|
88
|
+
|
|
89
|
+
- **Never embed secrets** (API keys, tokens, passwords) in rule sources or mock contexts — \`intutic skill audit\` flags them.
|
|
90
|
+
- **Local rules cannot weaken central rules.** Verdicts merge most-restrictive-wins: a KILL from any rule — local or centrally synced — ends the request. "Allow-override" rules are no-ops by design; do not author them.
|
|
91
|
+
- Keep rule sources (\`assembly/*.ts\`, mock JSON files) in version control alongside the workspace.
|
|
92
|
+
`;
|
|
93
|
+
/**
|
|
94
|
+
* Write bundled skills into the workspace, skipping any that already exist.
|
|
95
|
+
* Returns the paths written (empty when everything was already present).
|
|
96
|
+
*/
|
|
97
|
+
export async function writeBundledSkills(workspaceRoot) {
|
|
98
|
+
const written = [];
|
|
99
|
+
const dest = node_path.join(workspaceRoot, RULE_AUTHOR_SKILL_PATH);
|
|
100
|
+
try {
|
|
101
|
+
await node_fs.access(dest);
|
|
102
|
+
return written; // present — never overwrite user edits
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// absent → write below
|
|
106
|
+
}
|
|
107
|
+
await node_fs.mkdir(node_path.dirname(dest), { recursive: true });
|
|
108
|
+
await node_fs.writeFile(dest, RULE_AUTHOR_SKILL, 'utf-8');
|
|
109
|
+
written.push(dest);
|
|
110
|
+
return written;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=skillWriter.js.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* syncLoop.ts — Core bidirectional sync loop.
|
|
3
|
+
*
|
|
4
|
+
* The sync loop is the heartbeat of the daemon. Each iteration:
|
|
5
|
+
* 1. Fetches config from the control plane (POST /api/v1/sync/config)
|
|
6
|
+
* 2. If configVersion > local → writes SOP content to harness files
|
|
7
|
+
* 3. Computes SHA-256 hashes of local config files
|
|
8
|
+
* 4. Reports hashes + status back to the control plane
|
|
9
|
+
* 5. Calls the onSync callback with the result
|
|
10
|
+
* 6. Sleeps for pollIntervalMs (AbortSignal-aware)
|
|
11
|
+
* 7. Repeats until signal.aborted
|
|
12
|
+
*
|
|
13
|
+
* Design: never crash on a single iteration failure. Errors are
|
|
14
|
+
* caught per-iteration, logged, and the loop continues.
|
|
15
|
+
*
|
|
16
|
+
* HLD §3.14 — Real-Time State Mirroring
|
|
17
|
+
* LLD #8 — Sync Daemon / CLI
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import type { HarnessType, SyncConfigPayload, WorkspaceSettings } from '@intutic/shared-types';
|
|
22
|
+
/** Configuration for the sync loop. */
|
|
23
|
+
export interface SyncLoopOptions {
|
|
24
|
+
/** Control plane base URL (e.g., `https://api.intutic.ai`). */
|
|
25
|
+
controlPlaneUrl: string;
|
|
26
|
+
/** API key for authentication (vk_* or JWT). */
|
|
27
|
+
apiKey: string;
|
|
28
|
+
/** Workspace identifier. */
|
|
29
|
+
workspaceId: string;
|
|
30
|
+
/** Absolute path to the workspace root directory. */
|
|
31
|
+
workspaceRoot: string;
|
|
32
|
+
/** Poll interval in milliseconds (default: 30000). */
|
|
33
|
+
pollIntervalMs?: number;
|
|
34
|
+
/** Enable dev mode (relaxed checks, verbose logging). */
|
|
35
|
+
devMode?: boolean;
|
|
36
|
+
/** Callback invoked after each successful sync iteration. */
|
|
37
|
+
onSync?: (result: SyncResult) => void;
|
|
38
|
+
/** AbortSignal to gracefully stop the loop. */
|
|
39
|
+
signal?: AbortSignal;
|
|
40
|
+
/** Adapter identifier for ContextGraph sync. */
|
|
41
|
+
adapterId?: string;
|
|
42
|
+
}
|
|
43
|
+
/** Result of a single sync iteration. */
|
|
44
|
+
export interface SyncResult {
|
|
45
|
+
/** Config version from the control plane. */
|
|
46
|
+
configVersion: number;
|
|
47
|
+
/** Number of harness config files written. */
|
|
48
|
+
sopsWritten: number;
|
|
49
|
+
/** Number of files with hash drift. */
|
|
50
|
+
driftCount: number;
|
|
51
|
+
/** ISO timestamp of this sync. */
|
|
52
|
+
timestamp: string;
|
|
53
|
+
/** Resolved workspace settings from the control plane. WS-5. */
|
|
54
|
+
settings?: WorkspaceSettings;
|
|
55
|
+
/** All active SOP rules. */
|
|
56
|
+
sops?: SyncConfigPayload['sops'];
|
|
57
|
+
/** Proxy URL. */
|
|
58
|
+
proxyUrl?: string;
|
|
59
|
+
/** Active harnesses. */
|
|
60
|
+
harnesses?: HarnessType[];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Start the sync loop. This function runs indefinitely until the
|
|
64
|
+
* AbortSignal is triggered or the process exits.
|
|
65
|
+
*
|
|
66
|
+
* @param options - Sync loop configuration.
|
|
67
|
+
*/
|
|
68
|
+
export declare function startSyncLoop(options: SyncLoopOptions): Promise<void>;
|
|
69
|
+
export declare function syncOfflineTraces(controlPlaneUrl: string, apiKey: string): Promise<void>;
|
|
70
|
+
//# sourceMappingURL=syncLoop.d.ts.map
|
|
@@ -0,0 +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"}
|