@smeltjs/core 0.2.0 → 0.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.
- package/README.md +3 -3
- package/dist/apply.d.ts.map +1 -1
- package/dist/apply.js.map +1 -1
- package/dist/cache/prefix.d.ts.map +1 -1
- package/dist/cache/prefix.js.map +1 -1
- package/dist/cli/args.d.ts +16 -70
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +18 -338
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/bin.d.ts.map +1 -1
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/config.d.ts +40 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +55 -1
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/hooks.d.ts +33 -38
- package/dist/cli/hooks.d.ts.map +1 -1
- package/dist/cli/hooks.js +140 -485
- package/dist/cli/hooks.js.map +1 -1
- package/dist/cli/init.d.ts +30 -15
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +167 -38
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/report.d.ts.map +1 -1
- package/dist/cli/report.js +2 -2
- package/dist/cli/report.js.map +1 -1
- package/dist/cli/run.d.ts +25 -88
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +32 -341
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/shell.d.ts +106 -0
- package/dist/cli/shell.d.ts.map +1 -0
- package/dist/cli/shell.js +100 -0
- package/dist/cli/shell.js.map +1 -0
- package/dist/cli/subcommands/flags.d.ts +141 -0
- package/dist/cli/subcommands/flags.d.ts.map +1 -0
- package/dist/cli/subcommands/flags.js +208 -0
- package/dist/cli/subcommands/flags.js.map +1 -0
- package/dist/cli/subcommands/hooks.d.ts +18 -0
- package/dist/cli/subcommands/hooks.d.ts.map +1 -0
- package/dist/cli/subcommands/hooks.js +64 -0
- package/dist/cli/subcommands/hooks.js.map +1 -0
- package/dist/cli/subcommands/init.d.ts +19 -0
- package/dist/cli/subcommands/init.d.ts.map +1 -0
- package/dist/cli/subcommands/init.js +44 -0
- package/dist/cli/subcommands/init.js.map +1 -0
- package/dist/cli/subcommands/map.d.ts +75 -0
- package/dist/cli/subcommands/map.d.ts.map +1 -0
- package/dist/cli/subcommands/map.js +132 -0
- package/dist/cli/subcommands/map.js.map +1 -0
- package/dist/cli/subcommands/registry.d.ts +80 -0
- package/dist/cli/subcommands/registry.d.ts.map +1 -0
- package/dist/cli/subcommands/registry.js +138 -0
- package/dist/cli/subcommands/registry.js.map +1 -0
- package/dist/cli/subcommands/retrieve.d.ts +74 -0
- package/dist/cli/subcommands/retrieve.d.ts.map +1 -0
- package/dist/cli/subcommands/retrieve.js +84 -0
- package/dist/cli/subcommands/retrieve.js.map +1 -0
- package/dist/cli/subcommands/smelt.d.ts +107 -0
- package/dist/cli/subcommands/smelt.d.ts.map +1 -0
- package/dist/cli/subcommands/smelt.js +304 -0
- package/dist/cli/subcommands/smelt.js.map +1 -0
- package/dist/cli/subcommands/stats.d.ts +43 -0
- package/dist/cli/subcommands/stats.d.ts.map +1 -0
- package/dist/cli/subcommands/stats.js +62 -0
- package/dist/cli/subcommands/stats.js.map +1 -0
- package/dist/cli/subcommands/subcommand.d.ts +113 -0
- package/dist/cli/subcommands/subcommand.d.ts.map +1 -0
- package/dist/cli/subcommands/subcommand.js +3 -0
- package/dist/cli/subcommands/subcommand.js.map +1 -0
- package/dist/cli/usage.d.ts +3 -0
- package/dist/cli/usage.d.ts.map +1 -0
- package/dist/cli/usage.js +95 -0
- package/dist/cli/usage.js.map +1 -0
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js.map +1 -1
- package/dist/errors.d.ts +21 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +33 -1
- package/dist/errors.js.map +1 -1
- package/dist/harness/aider.d.ts +10 -0
- package/dist/harness/aider.d.ts.map +1 -0
- package/dist/harness/aider.js +21 -0
- package/dist/harness/aider.js.map +1 -0
- package/dist/harness/claude-code.d.ts +3 -0
- package/dist/harness/claude-code.d.ts.map +1 -0
- package/dist/harness/claude-code.js +68 -0
- package/dist/harness/claude-code.js.map +1 -0
- package/dist/harness/cline.d.ts +3 -0
- package/dist/harness/cline.d.ts.map +1 -0
- package/dist/harness/cline.js +54 -0
- package/dist/harness/cline.js.map +1 -0
- package/dist/harness/codex.d.ts +3 -0
- package/dist/harness/codex.d.ts.map +1 -0
- package/dist/harness/codex.js +91 -0
- package/dist/harness/codex.js.map +1 -0
- package/dist/harness/cursor.d.ts +3 -0
- package/dist/harness/cursor.d.ts.map +1 -0
- package/dist/harness/cursor.js +54 -0
- package/dist/harness/cursor.js.map +1 -0
- package/dist/harness/gemini.d.ts +3 -0
- package/dist/harness/gemini.d.ts.map +1 -0
- package/dist/harness/gemini.js +59 -0
- package/dist/harness/gemini.js.map +1 -0
- package/dist/harness/grok.d.ts +3 -0
- package/dist/harness/grok.d.ts.map +1 -0
- package/dist/harness/grok.js +46 -0
- package/dist/harness/grok.js.map +1 -0
- package/dist/harness/hermes.d.ts +3 -0
- package/dist/harness/hermes.d.ts.map +1 -0
- package/dist/harness/hermes.js +71 -0
- package/dist/harness/hermes.js.map +1 -0
- package/dist/harness/kilocode.d.ts +3 -0
- package/dist/harness/kilocode.d.ts.map +1 -0
- package/dist/harness/kilocode.js +35 -0
- package/dist/harness/kilocode.js.map +1 -0
- package/dist/harness/opencode.d.ts +3 -0
- package/dist/harness/opencode.d.ts.map +1 -0
- package/dist/harness/opencode.js +97 -0
- package/dist/harness/opencode.js.map +1 -0
- package/dist/harness/paths.d.ts +17 -0
- package/dist/harness/paths.d.ts.map +1 -0
- package/dist/harness/paths.js +45 -0
- package/dist/harness/paths.js.map +1 -0
- package/dist/harness/profile.d.ts +184 -0
- package/dist/harness/profile.d.ts.map +1 -0
- package/dist/harness/profile.js +26 -0
- package/dist/harness/profile.js.map +1 -0
- package/dist/harness/registry.d.ts +51 -0
- package/dist/harness/registry.d.ts.map +1 -0
- package/dist/harness/registry.js +87 -0
- package/dist/harness/registry.js.map +1 -0
- package/dist/harness/snippet.d.ts +19 -0
- package/dist/harness/snippet.d.ts.map +1 -0
- package/dist/harness/snippet.js +41 -0
- package/dist/harness/snippet.js.map +1 -0
- package/dist/hash.d.ts.map +1 -1
- package/dist/hash.js.map +1 -1
- package/dist/hooks/guard-core.d.ts +14 -14
- package/dist/hooks/guard-core.d.ts.map +1 -1
- package/dist/hooks/guard-core.js +15 -37
- package/dist/hooks/guard-core.js.map +1 -1
- package/dist/hooks/shim.d.ts +95 -4
- package/dist/hooks/shim.d.ts.map +1 -1
- package/dist/hooks/shim.js +87 -2
- package/dist/hooks/shim.js.map +1 -1
- package/dist/hooks/shims/claude-code.d.ts +5 -18
- package/dist/hooks/shims/claude-code.d.ts.map +1 -1
- package/dist/hooks/shims/claude-code.js +9 -56
- package/dist/hooks/shims/claude-code.js.map +1 -1
- package/dist/hooks/shims/cline.d.ts +5 -12
- package/dist/hooks/shims/cline.d.ts.map +1 -1
- package/dist/hooks/shims/cline.js +9 -34
- package/dist/hooks/shims/cline.js.map +1 -1
- package/dist/hooks/shims/codex.d.ts +5 -18
- package/dist/hooks/shims/codex.d.ts.map +1 -1
- package/dist/hooks/shims/codex.js +9 -51
- package/dist/hooks/shims/codex.js.map +1 -1
- package/dist/hooks/shims/cursor.d.ts +5 -14
- package/dist/hooks/shims/cursor.d.ts.map +1 -1
- package/dist/hooks/shims/cursor.js +9 -42
- package/dist/hooks/shims/cursor.js.map +1 -1
- package/dist/hooks/shims/gemini.d.ts +5 -18
- package/dist/hooks/shims/gemini.d.ts.map +1 -1
- package/dist/hooks/shims/gemini.js +9 -48
- package/dist/hooks/shims/gemini.js.map +1 -1
- package/dist/hooks/shims/grok.d.ts +5 -13
- package/dist/hooks/shims/grok.d.ts.map +1 -1
- package/dist/hooks/shims/grok.js +9 -32
- package/dist/hooks/shims/grok.js.map +1 -1
- package/dist/hooks/shims/hermes.d.ts +5 -17
- package/dist/hooks/shims/hermes.d.ts.map +1 -1
- package/dist/hooks/shims/hermes.js +9 -45
- package/dist/hooks/shims/hermes.js.map +1 -1
- package/dist/index.d.ts +33 -76
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -67
- package/dist/index.js.map +1 -1
- package/dist/lang/bash.d.ts.map +1 -1
- package/dist/lang/bash.js.map +1 -1
- package/dist/lang/c.d.ts.map +1 -1
- package/dist/lang/c.js.map +1 -1
- package/dist/lang/c_sharp.d.ts.map +1 -1
- package/dist/lang/c_sharp.js.map +1 -1
- package/dist/lang/cpp.d.ts.map +1 -1
- package/dist/lang/cpp.js.map +1 -1
- package/dist/lang/go.d.ts.map +1 -1
- package/dist/lang/go.js.map +1 -1
- package/dist/lang/java.d.ts.map +1 -1
- package/dist/lang/java.js.map +1 -1
- package/dist/lang/javascript.d.ts.map +1 -1
- package/dist/lang/javascript.js.map +1 -1
- package/dist/lang/kotlin.d.ts.map +1 -1
- package/dist/lang/kotlin.js.map +1 -1
- package/dist/lang/php.d.ts.map +1 -1
- package/dist/lang/php.js.map +1 -1
- package/dist/lang/profile.d.ts.map +1 -1
- package/dist/lang/profile.js.map +1 -1
- package/dist/lang/python.d.ts.map +1 -1
- package/dist/lang/python.js.map +1 -1
- package/dist/lang/registry.d.ts.map +1 -1
- package/dist/lang/registry.js.map +1 -1
- package/dist/lang/ruby.d.ts.map +1 -1
- package/dist/lang/ruby.js.map +1 -1
- package/dist/lang/rust.d.ts.map +1 -1
- package/dist/lang/rust.js.map +1 -1
- package/dist/lang/swift.d.ts.map +1 -1
- package/dist/lang/swift.js.map +1 -1
- package/dist/lang/tsx.d.ts.map +1 -1
- package/dist/lang/tsx.js.map +1 -1
- package/dist/lang/typescript.d.ts.map +1 -1
- package/dist/lang/typescript.js.map +1 -1
- package/dist/net/policy.d.ts +18 -1
- package/dist/net/policy.d.ts.map +1 -1
- package/dist/net/policy.js +6 -4
- package/dist/net/policy.js.map +1 -1
- package/dist/ops/index.d.ts +39 -0
- package/dist/ops/index.d.ts.map +1 -0
- package/dist/ops/index.js +37 -0
- package/dist/ops/index.js.map +1 -0
- package/dist/ops/inputs.d.ts +170 -0
- package/dist/ops/inputs.d.ts.map +1 -0
- package/dist/ops/inputs.js +142 -0
- package/dist/ops/inputs.js.map +1 -0
- package/dist/ops/verbs.d.ts +136 -0
- package/dist/ops/verbs.d.ts.map +1 -0
- package/dist/ops/verbs.js +76 -0
- package/dist/ops/verbs.js.map +1 -0
- package/dist/plan/auto.d.ts +69 -0
- package/dist/plan/auto.d.ts.map +1 -0
- package/dist/plan/auto.js +70 -0
- package/dist/plan/auto.js.map +1 -0
- package/dist/plan/budget.d.ts +21 -0
- package/dist/plan/budget.d.ts.map +1 -0
- package/dist/plan/budget.js +26 -0
- package/dist/plan/budget.js.map +1 -0
- package/dist/plan/grammar.d.ts +14 -0
- package/dist/plan/grammar.d.ts.map +1 -1
- package/dist/plan/grammar.js +47 -6
- package/dist/plan/grammar.js.map +1 -1
- package/dist/plan/lexical.d.ts.map +1 -1
- package/dist/plan/lexical.js +1 -7
- package/dist/plan/lexical.js.map +1 -1
- package/dist/plan/planners.d.ts +35 -2
- package/dist/plan/planners.d.ts.map +1 -1
- package/dist/plan/planners.js +35 -2
- package/dist/plan/planners.js.map +1 -1
- package/dist/plan/structural.d.ts +19 -5
- package/dist/plan/structural.d.ts.map +1 -1
- package/dist/plan/structural.js +180 -33
- package/dist/plan/structural.js.map +1 -1
- package/dist/repomap/cache.d.ts +48 -0
- package/dist/repomap/cache.d.ts.map +1 -1
- package/dist/repomap/cache.js +112 -13
- package/dist/repomap/cache.js.map +1 -1
- package/dist/repomap/io.d.ts +24 -0
- package/dist/repomap/io.d.ts.map +1 -0
- package/dist/repomap/io.js +34 -0
- package/dist/repomap/io.js.map +1 -0
- package/dist/repomap/map.d.ts +69 -6
- package/dist/repomap/map.d.ts.map +1 -1
- package/dist/repomap/map.js +104 -22
- package/dist/repomap/map.js.map +1 -1
- package/dist/repomap/rank.d.ts +26 -2
- package/dist/repomap/rank.d.ts.map +1 -1
- package/dist/repomap/rank.js +20 -0
- package/dist/repomap/rank.js.map +1 -1
- package/dist/repomap/reader.d.ts +73 -0
- package/dist/repomap/reader.d.ts.map +1 -0
- package/dist/repomap/reader.js +30 -0
- package/dist/repomap/reader.js.map +1 -0
- package/dist/repomap/tags.d.ts.map +1 -1
- package/dist/repomap/tags.js.map +1 -1
- package/dist/retrieve.d.ts +8 -0
- package/dist/retrieve.d.ts.map +1 -1
- package/dist/retrieve.js +12 -1
- package/dist/retrieve.js.map +1 -1
- package/dist/smelter.d.ts +79 -0
- package/dist/smelter.d.ts.map +1 -0
- package/dist/smelter.js +65 -0
- package/dist/smelter.js.map +1 -0
- package/dist/stages.d.ts.map +1 -1
- package/dist/stages.js +2 -2
- package/dist/stages.js.map +1 -1
- package/dist/stats.d.ts +2 -1
- package/dist/stats.d.ts.map +1 -1
- package/dist/stats.js +2 -1
- package/dist/stats.js.map +1 -1
- package/dist/store-dir.d.ts +43 -4
- package/dist/store-dir.d.ts.map +1 -1
- package/dist/store-dir.js +48 -5
- package/dist/store-dir.js.map +1 -1
- package/dist/store.d.ts +6 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +6 -0
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +35 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-c_sharp.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-go.wasm +0 -0
- package/grammars/tree-sitter-java.wasm +0 -0
- package/grammars/tree-sitter-javascript.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-php.wasm +0 -0
- package/grammars/tree-sitter-python.wasm +0 -0
- package/grammars/tree-sitter-ruby.wasm +0 -0
- package/grammars/tree-sitter-rust.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/grammars/tree-sitter-tsx.wasm +0 -0
- package/grammars/tree-sitter-typescript.wasm +0 -0
- package/package.json +11 -11
- package/dist/cli/resolve.d.ts +0 -103
- package/dist/cli/resolve.d.ts.map +0 -1
- package/dist/cli/resolve.js +0 -106
- package/dist/cli/resolve.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/harness/codex.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,KAAK,GAAsB;IAC/B,SAAS,EAAE,CAAC,MAAM,CAAC;IACnB,SAAS,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,CAAC,WAAW,CAAC;IAC3B,aAAa,EAAE,CAAC,YAAY,CAAC;IAC7B,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACjB,kBAAkB,EAAE;YAClB,aAAa,EAAE,YAAY;YAC3B,kBAAkB,EAAE,MAAM;YAC1B,wBAAwB,EAAE,MAAM;SACjC;KACF,CAAC;IACF,OAAO,EAAE;QACP,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;YACtC,kBAAkB,EAAE;gBAClB,aAAa,EAAE,YAAY;gBAC3B,kBAAkB,EAAE,OAAO;gBAC3B,wBAAwB,EAAE,YAAY;gBACtC,YAAY,EAAE,KAAK;aACpB;SACF,CAAC;QACF,QAAQ,EAAE,QAAQ;KACnB;CACF,CAAC;AAEF,kFAAkF;AAClF,SAAS,oBAAoB;IAC3B,OAAO,GAAG,kBAAkB;;;;;EAK5B,gBAAgB;CACjB,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAA0B;IAC1C,EAAE,EAAE,OAAO;IACX,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,UAAU;IAChB,MAAM,EAAE,CAAC,QAAQ,CAAC;IAClB,UAAU,EAAE,CAAC,QAAQ,CAAC;IACtB,eAAe,EAAE,WAAW;IAC5B,YAAY,EAAE,SAAS;IACvB,OAAO,EAAE;QACP,wIAAwI;KACzI;IACD,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE;QACP;YACE,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,mBAAmB;YACzB,KAAK,EAAE,YAAY;YACnB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;YAC1B,KAAK,EAAE,cAAc;YACrB,SAAS,EAAE,IAAI;SAChB;QACD;YACE,IAAI,EAAE,cAAc;YACpB,IAAI,EAAE,oBAAoB;YAC1B,KAAK,EAAE,oBAAoB;YAC3B,KAAK,EAAE,kBAAkB;YACzB,GAAG,EAAE,gBAAgB;YACrB,QAAQ,EAAE;gBACR,QAAQ,EAAE,YAAY;gBACtB,GAAG,EAAE,oEAAoE;aAC1E;SACF;KACF;CACF,CAAC","sourcesContent":["import type { HarnessHookSchema } from '../hooks/shim.ts';\n\nimport type { ShimmedHarnessProfile } from './profile.ts';\nimport { SNIPPET_END_HASH, SNIPPET_START_HASH } from './snippet.ts';\n\n/**\n * Codex CLI — VERIFIED tier. Schema, install and removal, end to end.\n *\n * Codex's experimental hooks (`features.hooks`, rust-v0.114.0+, on by default from\n * 0.150.1) deliberately mirror Claude Code's schema — the survey is\n * docs/research/2026-09-02-agent-enforcement.md § 3, primary source\n * <https://developers.openai.com/codex/hooks>:\n *\n * - stdin: `{ tool_name, tool_input }`; shell input arrives as `tool_name: \"Bash\"`,\n * `tool_input.command`.\n * - deny: `hookSpecificOutput.permissionDecision: \"deny\"` + reason (or exit 2).\n * - rewrite: `permissionDecision: \"allow\"` with `updatedInput` — for Bash,\n * `updatedInput` **must include a string `command` field**, which the shared splice\n * always does.\n *\n * Two documented differences from Claude Code, both honoured here:\n * `permissionDecision: \"ask\"` is NOT supported (a parse error — the tool proceeds),\n * and this schema never emits it; project-layer hooks only run once the project is\n * trusted, which the installer's output says out loud, and which the `[features]`\n * block below is what enables.\n */\nconst HOOKS: HarnessHookSchema = {\n readTools: ['Read'],\n bashTools: ['Bash', 'shell'],\n toolNameKeys: ['tool_name'],\n toolInputKeys: ['tool_input'],\n deny: (reason) => ({\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'deny',\n permissionDecisionReason: reason,\n },\n }),\n rewrite: {\n document: ({ input, announcement }) => ({\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'allow',\n permissionDecisionReason: announcement,\n updatedInput: input,\n },\n }),\n announce: 'reason',\n },\n};\n\n/** The Codex `config.toml` block: enables the hooks feature, marker-bracketed. */\nfunction codexConfigTomlBlock(): string {\n return `${SNIPPET_START_HASH}\n# Enables Codex's hooks feature so .codex/hooks.json is honored. Project-level hooks\n# run only once this project is trusted. Written by \\`smelt hooks install\\`.\n[features]\nhooks = true\n${SNIPPET_END_HASH}\n`;\n}\n\nexport const codex: ShimmedHarnessProfile = {\n id: 'codex',\n name: 'Codex CLI',\n tier: 'verified',\n detect: ['.codex'],\n detectHome: ['.codex'],\n instructionFile: 'AGENTS.md',\n instructions: 'snippet',\n caveats: [\n 'project-level Codex hooks run only once the project is trusted (features.hooks; see docs/research/2026-09-02-agent-enforcement.md § 3)',\n ],\n hooks: HOOKS,\n install: [\n {\n kind: 'json-hooks',\n file: '.codex/hooks.json',\n event: 'PreToolUse',\n matchers: ['Read', 'Bash'],\n entry: 'command-list',\n lifecycle: true,\n },\n {\n kind: 'marker-block',\n file: '.codex/config.toml',\n block: codexConfigTomlBlock,\n start: SNIPPET_START_HASH,\n end: SNIPPET_END_HASH,\n skipWhen: {\n contains: '[features]',\n why: 'already has a [features] table — add `hooks = true` to it yourself',\n },\n },\n ],\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/harness/cursor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAkC1D,eAAO,MAAM,MAAM,EAAE,qBAqBpB,CAAC","sourcesContent":["import type { HarnessHookSchema } from '../hooks/shim.ts';\n\nimport type { ShimmedHarnessProfile } from './profile.ts';\n\n/**\n * Cursor — EXPERIMENTAL tier. Schema, install and removal, end to end.\n *\n * Schema mapped from the capability matrix\n * (docs/research/2026-09-02-harness-capability-matrix.md, Cursor row; primary source\n * <https://cursor.com/docs/agent/hooks>), not yet smoke-tested against the real binary.\n *\n * - event: `preToolUse` (the broad hook — unlike `beforeShellExecution`, it supports\n * input rewrite), fired for every tool, so the hook file carries one matcher-less\n * entry; stdin `{ tool_name, tool_input }`, and the settings file is versioned\n * (`\"version\": 1`).\n * - deny: `{ \"permission\": \"deny\", \"agentMessage\": … }` — `agentMessage` reaches the\n * model, `userMessage` the human; the guard's steering text goes to the model.\n * - rewrite: `{ \"permission\": \"allow\", \"updated_input\": { … } }` (snake_case, the\n * whole input object), with no message field — announced on stderr instead.\n *\n * Cursor has no static permission-config file — gating is entirely hook code — so this\n * shim plus the instruction file is the whole enforcement story there.\n */\nconst HOOKS: HarnessHookSchema = {\n readTools: ['read_file', 'Read', 'ReadFile'],\n bashTools: ['run_terminal_cmd', 'Shell', 'Bash', 'shell'],\n toolNameKeys: ['tool_name'],\n toolInputKeys: ['tool_input'],\n deny: (reason) => ({ permission: 'deny', agentMessage: reason }),\n rewrite: {\n document: ({ input }) => ({ permission: 'allow', updated_input: input }),\n // The allow/updated_input shape carries no message field — announce on stderr.\n announce: 'stderr',\n },\n};\n\nexport const cursor: ShimmedHarnessProfile = {\n id: 'cursor',\n name: 'Cursor',\n tier: 'experimental',\n detect: ['.cursor'],\n detectHome: ['.cursor'],\n instructionFile: 'AGENTS.md',\n instructions: 'snippet',\n caveats: ['Cursor has no static permission config — gating is entirely hook code'],\n hooks: HOOKS,\n install: [\n {\n kind: 'json-hooks',\n file: '.cursor/hooks.json',\n event: 'preToolUse',\n matchers: [undefined],\n entry: 'bare-command',\n lifecycle: false,\n shape: { version: 1 },\n },\n ],\n};\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor — EXPERIMENTAL tier. Schema, install and removal, end to end.
|
|
3
|
+
*
|
|
4
|
+
* Schema mapped from the capability matrix
|
|
5
|
+
* (docs/research/2026-09-02-harness-capability-matrix.md, Cursor row; primary source
|
|
6
|
+
* <https://cursor.com/docs/agent/hooks>), not yet smoke-tested against the real binary.
|
|
7
|
+
*
|
|
8
|
+
* - event: `preToolUse` (the broad hook — unlike `beforeShellExecution`, it supports
|
|
9
|
+
* input rewrite), fired for every tool, so the hook file carries one matcher-less
|
|
10
|
+
* entry; stdin `{ tool_name, tool_input }`, and the settings file is versioned
|
|
11
|
+
* (`"version": 1`).
|
|
12
|
+
* - deny: `{ "permission": "deny", "agentMessage": … }` — `agentMessage` reaches the
|
|
13
|
+
* model, `userMessage` the human; the guard's steering text goes to the model.
|
|
14
|
+
* - rewrite: `{ "permission": "allow", "updated_input": { … } }` (snake_case, the
|
|
15
|
+
* whole input object), with no message field — announced on stderr instead.
|
|
16
|
+
*
|
|
17
|
+
* Cursor has no static permission-config file — gating is entirely hook code — so this
|
|
18
|
+
* shim plus the instruction file is the whole enforcement story there.
|
|
19
|
+
*/
|
|
20
|
+
const HOOKS = {
|
|
21
|
+
readTools: ['read_file', 'Read', 'ReadFile'],
|
|
22
|
+
bashTools: ['run_terminal_cmd', 'Shell', 'Bash', 'shell'],
|
|
23
|
+
toolNameKeys: ['tool_name'],
|
|
24
|
+
toolInputKeys: ['tool_input'],
|
|
25
|
+
deny: (reason) => ({ permission: 'deny', agentMessage: reason }),
|
|
26
|
+
rewrite: {
|
|
27
|
+
document: ({ input }) => ({ permission: 'allow', updated_input: input }),
|
|
28
|
+
// The allow/updated_input shape carries no message field — announce on stderr.
|
|
29
|
+
announce: 'stderr',
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
export const cursor = {
|
|
33
|
+
id: 'cursor',
|
|
34
|
+
name: 'Cursor',
|
|
35
|
+
tier: 'experimental',
|
|
36
|
+
detect: ['.cursor'],
|
|
37
|
+
detectHome: ['.cursor'],
|
|
38
|
+
instructionFile: 'AGENTS.md',
|
|
39
|
+
instructions: 'snippet',
|
|
40
|
+
caveats: ['Cursor has no static permission config — gating is entirely hook code'],
|
|
41
|
+
hooks: HOOKS,
|
|
42
|
+
install: [
|
|
43
|
+
{
|
|
44
|
+
kind: 'json-hooks',
|
|
45
|
+
file: '.cursor/hooks.json',
|
|
46
|
+
event: 'preToolUse',
|
|
47
|
+
matchers: [undefined],
|
|
48
|
+
entry: 'bare-command',
|
|
49
|
+
lifecycle: false,
|
|
50
|
+
shape: { version: 1 },
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/harness/cursor.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,KAAK,GAAsB;IAC/B,SAAS,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC;IAC5C,SAAS,EAAE,CAAC,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC;IACzD,YAAY,EAAE,CAAC,WAAW,CAAC;IAC3B,aAAa,EAAE,CAAC,YAAY,CAAC;IAC7B,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;IAChE,OAAO,EAAE;QACP,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;QACxE,+EAA+E;QAC/E,QAAQ,EAAE,QAAQ;KACnB;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAA0B;IAC3C,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,cAAc;IACpB,MAAM,EAAE,CAAC,SAAS,CAAC;IACnB,UAAU,EAAE,CAAC,SAAS,CAAC;IACvB,eAAe,EAAE,WAAW;IAC5B,YAAY,EAAE,SAAS;IACvB,OAAO,EAAE,CAAC,uEAAuE,CAAC;IAClF,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE;QACP;YACE,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,oBAAoB;YAC1B,KAAK,EAAE,YAAY;YACnB,QAAQ,EAAE,CAAC,SAAS,CAAC;YACrB,KAAK,EAAE,cAAc;YACrB,SAAS,EAAE,KAAK;YAChB,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;SACtB;KACF;CACF,CAAC","sourcesContent":["import type { HarnessHookSchema } from '../hooks/shim.ts';\n\nimport type { ShimmedHarnessProfile } from './profile.ts';\n\n/**\n * Cursor — EXPERIMENTAL tier. Schema, install and removal, end to end.\n *\n * Schema mapped from the capability matrix\n * (docs/research/2026-09-02-harness-capability-matrix.md, Cursor row; primary source\n * <https://cursor.com/docs/agent/hooks>), not yet smoke-tested against the real binary.\n *\n * - event: `preToolUse` (the broad hook — unlike `beforeShellExecution`, it supports\n * input rewrite), fired for every tool, so the hook file carries one matcher-less\n * entry; stdin `{ tool_name, tool_input }`, and the settings file is versioned\n * (`\"version\": 1`).\n * - deny: `{ \"permission\": \"deny\", \"agentMessage\": … }` — `agentMessage` reaches the\n * model, `userMessage` the human; the guard's steering text goes to the model.\n * - rewrite: `{ \"permission\": \"allow\", \"updated_input\": { … } }` (snake_case, the\n * whole input object), with no message field — announced on stderr instead.\n *\n * Cursor has no static permission-config file — gating is entirely hook code — so this\n * shim plus the instruction file is the whole enforcement story there.\n */\nconst HOOKS: HarnessHookSchema = {\n readTools: ['read_file', 'Read', 'ReadFile'],\n bashTools: ['run_terminal_cmd', 'Shell', 'Bash', 'shell'],\n toolNameKeys: ['tool_name'],\n toolInputKeys: ['tool_input'],\n deny: (reason) => ({ permission: 'deny', agentMessage: reason }),\n rewrite: {\n document: ({ input }) => ({ permission: 'allow', updated_input: input }),\n // The allow/updated_input shape carries no message field — announce on stderr.\n announce: 'stderr',\n },\n};\n\nexport const cursor: ShimmedHarnessProfile = {\n id: 'cursor',\n name: 'Cursor',\n tier: 'experimental',\n detect: ['.cursor'],\n detectHome: ['.cursor'],\n instructionFile: 'AGENTS.md',\n instructions: 'snippet',\n caveats: ['Cursor has no static permission config — gating is entirely hook code'],\n hooks: HOOKS,\n install: [\n {\n kind: 'json-hooks',\n file: '.cursor/hooks.json',\n event: 'preToolUse',\n matchers: [undefined],\n entry: 'bare-command',\n lifecycle: false,\n shape: { version: 1 },\n },\n ],\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/harness/gemini.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAsC1D,eAAO,MAAM,MAAM,EAAE,qBAsBpB,CAAC","sourcesContent":["import type { HarnessHookSchema } from '../hooks/shim.ts';\n\nimport type { ShimmedHarnessProfile } from './profile.ts';\n\n/**\n * Gemini CLI — EXPERIMENTAL tier. Schema, install and removal, end to end.\n *\n * The schema below is mapped from the capability matrix\n * (docs/research/2026-09-02-harness-capability-matrix.md, Gemini CLI row; primary\n * source <https://geminicli.com/docs/hooks/reference/>), and the field names were\n * additionally checked 2026-09-02 against the shipped `@google/gemini-cli` 0.58.0\n * bundle (installed headlessly for the shim's verification pass): the BeforeTool stdin\n * payload is `{ tool_name, tool_input }`, `read_file` takes `file_path` with\n * `start_line`/`end_line` windows, the shell tool is `run_shell_command` with\n * `command`, denial is `{ \"decision\": \"deny\", \"reason\": … }`, and\n * `hookSpecificOutput.tool_input` substitutes the input. What has NOT run is a live\n * end-to-end session (needs credentials this environment does not have), so the tier\n * stays experimental — treat surprises as shim bugs and please report them.\n *\n * Carried caveat from the matrix: Gemini's policy engine has an open bug where an\n * `allow` policy is ignored in non-interactive runs\n * (<https://github.com/google-gemini/gemini-cli/issues/20469>) — this preset uses\n * hooks, not the policy engine, but non-interactive behaviour is the least-tested\n * corner; verify before relying on it in CI.\n */\nconst HOOKS: HarnessHookSchema = {\n readTools: ['read_file', 'ReadFile', 'Read'],\n bashTools: ['run_shell_command', 'Shell', 'Bash'],\n toolNameKeys: ['tool_name'],\n toolInputKeys: ['tool_input'],\n deny: (reason) => ({ decision: 'deny', reason }),\n rewrite: {\n document: ({ input }) => ({\n hookSpecificOutput: { hookEventName: 'BeforeTool', tool_input: input },\n }),\n // The BeforeTool rewrite shape carries no reason field — announce on stderr.\n announce: 'stderr',\n },\n};\n\nexport const gemini: ShimmedHarnessProfile = {\n id: 'gemini',\n name: 'Gemini CLI',\n tier: 'experimental',\n detect: ['.gemini'],\n detectHome: ['.gemini'],\n instructionFile: 'GEMINI.md',\n instructions: 'snippet',\n caveats: [\n 'Gemini policy-engine allow rules are ignored in non-interactive runs (google-gemini/gemini-cli#20469) — verify hook behaviour in CI before relying on it',\n ],\n hooks: HOOKS,\n install: [\n {\n kind: 'json-hooks',\n file: '.gemini/settings.json',\n event: 'BeforeTool',\n matchers: ['read_file', 'run_shell_command'],\n entry: 'command-list',\n lifecycle: false,\n },\n ],\n};\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini CLI — EXPERIMENTAL tier. Schema, install and removal, end to end.
|
|
3
|
+
*
|
|
4
|
+
* The schema below is mapped from the capability matrix
|
|
5
|
+
* (docs/research/2026-09-02-harness-capability-matrix.md, Gemini CLI row; primary
|
|
6
|
+
* source <https://geminicli.com/docs/hooks/reference/>), and the field names were
|
|
7
|
+
* additionally checked 2026-09-02 against the shipped `@google/gemini-cli` 0.58.0
|
|
8
|
+
* bundle (installed headlessly for the shim's verification pass): the BeforeTool stdin
|
|
9
|
+
* payload is `{ tool_name, tool_input }`, `read_file` takes `file_path` with
|
|
10
|
+
* `start_line`/`end_line` windows, the shell tool is `run_shell_command` with
|
|
11
|
+
* `command`, denial is `{ "decision": "deny", "reason": … }`, and
|
|
12
|
+
* `hookSpecificOutput.tool_input` substitutes the input. What has NOT run is a live
|
|
13
|
+
* end-to-end session (needs credentials this environment does not have), so the tier
|
|
14
|
+
* stays experimental — treat surprises as shim bugs and please report them.
|
|
15
|
+
*
|
|
16
|
+
* Carried caveat from the matrix: Gemini's policy engine has an open bug where an
|
|
17
|
+
* `allow` policy is ignored in non-interactive runs
|
|
18
|
+
* (<https://github.com/google-gemini/gemini-cli/issues/20469>) — this preset uses
|
|
19
|
+
* hooks, not the policy engine, but non-interactive behaviour is the least-tested
|
|
20
|
+
* corner; verify before relying on it in CI.
|
|
21
|
+
*/
|
|
22
|
+
const HOOKS = {
|
|
23
|
+
readTools: ['read_file', 'ReadFile', 'Read'],
|
|
24
|
+
bashTools: ['run_shell_command', 'Shell', 'Bash'],
|
|
25
|
+
toolNameKeys: ['tool_name'],
|
|
26
|
+
toolInputKeys: ['tool_input'],
|
|
27
|
+
deny: (reason) => ({ decision: 'deny', reason }),
|
|
28
|
+
rewrite: {
|
|
29
|
+
document: ({ input }) => ({
|
|
30
|
+
hookSpecificOutput: { hookEventName: 'BeforeTool', tool_input: input },
|
|
31
|
+
}),
|
|
32
|
+
// The BeforeTool rewrite shape carries no reason field — announce on stderr.
|
|
33
|
+
announce: 'stderr',
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
export const gemini = {
|
|
37
|
+
id: 'gemini',
|
|
38
|
+
name: 'Gemini CLI',
|
|
39
|
+
tier: 'experimental',
|
|
40
|
+
detect: ['.gemini'],
|
|
41
|
+
detectHome: ['.gemini'],
|
|
42
|
+
instructionFile: 'GEMINI.md',
|
|
43
|
+
instructions: 'snippet',
|
|
44
|
+
caveats: [
|
|
45
|
+
'Gemini policy-engine allow rules are ignored in non-interactive runs (google-gemini/gemini-cli#20469) — verify hook behaviour in CI before relying on it',
|
|
46
|
+
],
|
|
47
|
+
hooks: HOOKS,
|
|
48
|
+
install: [
|
|
49
|
+
{
|
|
50
|
+
kind: 'json-hooks',
|
|
51
|
+
file: '.gemini/settings.json',
|
|
52
|
+
event: 'BeforeTool',
|
|
53
|
+
matchers: ['read_file', 'run_shell_command'],
|
|
54
|
+
entry: 'command-list',
|
|
55
|
+
lifecycle: false,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=gemini.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/harness/gemini.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,KAAK,GAAsB;IAC/B,SAAS,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,MAAM,CAAC;IAC5C,SAAS,EAAE,CAAC,mBAAmB,EAAE,OAAO,EAAE,MAAM,CAAC;IACjD,YAAY,EAAE,CAAC,WAAW,CAAC;IAC3B,aAAa,EAAE,CAAC,YAAY,CAAC;IAC7B,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAChD,OAAO,EAAE;QACP,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;YACxB,kBAAkB,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE;SACvE,CAAC;QACF,6EAA6E;QAC7E,QAAQ,EAAE,QAAQ;KACnB;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAA0B;IAC3C,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,cAAc;IACpB,MAAM,EAAE,CAAC,SAAS,CAAC;IACnB,UAAU,EAAE,CAAC,SAAS,CAAC;IACvB,eAAe,EAAE,WAAW;IAC5B,YAAY,EAAE,SAAS;IACvB,OAAO,EAAE;QACP,0JAA0J;KAC3J;IACD,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE;QACP;YACE,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,uBAAuB;YAC7B,KAAK,EAAE,YAAY;YACnB,QAAQ,EAAE,CAAC,WAAW,EAAE,mBAAmB,CAAC;YAC5C,KAAK,EAAE,cAAc;YACrB,SAAS,EAAE,KAAK;SACjB;KACF;CACF,CAAC","sourcesContent":["import type { HarnessHookSchema } from '../hooks/shim.ts';\n\nimport type { ShimmedHarnessProfile } from './profile.ts';\n\n/**\n * Gemini CLI — EXPERIMENTAL tier. Schema, install and removal, end to end.\n *\n * The schema below is mapped from the capability matrix\n * (docs/research/2026-09-02-harness-capability-matrix.md, Gemini CLI row; primary\n * source <https://geminicli.com/docs/hooks/reference/>), and the field names were\n * additionally checked 2026-09-02 against the shipped `@google/gemini-cli` 0.58.0\n * bundle (installed headlessly for the shim's verification pass): the BeforeTool stdin\n * payload is `{ tool_name, tool_input }`, `read_file` takes `file_path` with\n * `start_line`/`end_line` windows, the shell tool is `run_shell_command` with\n * `command`, denial is `{ \"decision\": \"deny\", \"reason\": … }`, and\n * `hookSpecificOutput.tool_input` substitutes the input. What has NOT run is a live\n * end-to-end session (needs credentials this environment does not have), so the tier\n * stays experimental — treat surprises as shim bugs and please report them.\n *\n * Carried caveat from the matrix: Gemini's policy engine has an open bug where an\n * `allow` policy is ignored in non-interactive runs\n * (<https://github.com/google-gemini/gemini-cli/issues/20469>) — this preset uses\n * hooks, not the policy engine, but non-interactive behaviour is the least-tested\n * corner; verify before relying on it in CI.\n */\nconst HOOKS: HarnessHookSchema = {\n readTools: ['read_file', 'ReadFile', 'Read'],\n bashTools: ['run_shell_command', 'Shell', 'Bash'],\n toolNameKeys: ['tool_name'],\n toolInputKeys: ['tool_input'],\n deny: (reason) => ({ decision: 'deny', reason }),\n rewrite: {\n document: ({ input }) => ({\n hookSpecificOutput: { hookEventName: 'BeforeTool', tool_input: input },\n }),\n // The BeforeTool rewrite shape carries no reason field — announce on stderr.\n announce: 'stderr',\n },\n};\n\nexport const gemini: ShimmedHarnessProfile = {\n id: 'gemini',\n name: 'Gemini CLI',\n tier: 'experimental',\n detect: ['.gemini'],\n detectHome: ['.gemini'],\n instructionFile: 'GEMINI.md',\n instructions: 'snippet',\n caveats: [\n 'Gemini policy-engine allow rules are ignored in non-interactive runs (google-gemini/gemini-cli#20469) — verify hook behaviour in CI before relying on it',\n ],\n hooks: HOOKS,\n install: [\n {\n kind: 'json-hooks',\n file: '.gemini/settings.json',\n event: 'BeforeTool',\n matchers: ['read_file', 'run_shell_command'],\n entry: 'command-list',\n lifecycle: false,\n },\n ],\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grok.d.ts","sourceRoot":"","sources":["../../src/harness/grok.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AA2B1D,eAAO,MAAM,IAAI,EAAE,qBAoBlB,CAAC","sourcesContent":["import type { HarnessHookSchema } from '../hooks/shim.ts';\n\nimport type { ShimmedHarnessProfile } from './profile.ts';\n\n/**\n * Grok CLI — EXPERIMENTAL tier. Schema, install and removal, end to end.\n *\n * Schema mapped from the capability matrix\n * (docs/research/2026-09-02-harness-capability-matrix.md, Grok CLI row; primary source\n * <https://docs.x.ai/build/features/hooks>), not yet smoke-tested against the real\n * binary. Note the matrix's provenance warning: the official CLI is\n * `xai-org/grok-build` (binary `grok`) — `superagent-ai/grok-cli` is a third-party\n * clone with a different hook surface.\n *\n * - event: `PreToolUse`; stdin `{ tool_name, tool_input }` (Claude-Code-like tool\n * names).\n * - deny: `{ \"decision\": \"deny\", \"reason\": … }` or exit 2. **Deny-only**: the input\n * is read-only to hooks, so there is no `rewrite` here — under\n * `hooks.enforcement: \"rewrite\"` this harness falls back to the deny, whose reason\n * still carries the exact replacement pipeline.\n */\nconst HOOKS: HarnessHookSchema = {\n readTools: ['Read', 'read_file', 'ReadFile'],\n bashTools: ['Bash', 'shell', 'run_shell_command'],\n toolNameKeys: ['tool_name'],\n toolInputKeys: ['tool_input'],\n deny: (reason) => ({ decision: 'deny', reason }),\n};\n\nexport const grok: ShimmedHarnessProfile = {\n id: 'grok',\n name: 'Grok CLI',\n tier: 'experimental',\n detect: ['.grok'],\n detectHome: ['.grok'],\n instructionFile: 'AGENTS.md',\n instructions: 'snippet',\n caveats: ['deny-only hooks: input rewrite is not supported, so rewrite mode falls back to deny'],\n hooks: HOOKS,\n install: [\n {\n kind: 'json-hooks',\n file: '.grok/hooks.json',\n event: 'PreToolUse',\n matchers: ['Read', 'Bash'],\n entry: 'command-list',\n lifecycle: false,\n },\n ],\n};\n"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grok CLI — EXPERIMENTAL tier. Schema, install and removal, end to end.
|
|
3
|
+
*
|
|
4
|
+
* Schema mapped from the capability matrix
|
|
5
|
+
* (docs/research/2026-09-02-harness-capability-matrix.md, Grok CLI row; primary source
|
|
6
|
+
* <https://docs.x.ai/build/features/hooks>), not yet smoke-tested against the real
|
|
7
|
+
* binary. Note the matrix's provenance warning: the official CLI is
|
|
8
|
+
* `xai-org/grok-build` (binary `grok`) — `superagent-ai/grok-cli` is a third-party
|
|
9
|
+
* clone with a different hook surface.
|
|
10
|
+
*
|
|
11
|
+
* - event: `PreToolUse`; stdin `{ tool_name, tool_input }` (Claude-Code-like tool
|
|
12
|
+
* names).
|
|
13
|
+
* - deny: `{ "decision": "deny", "reason": … }` or exit 2. **Deny-only**: the input
|
|
14
|
+
* is read-only to hooks, so there is no `rewrite` here — under
|
|
15
|
+
* `hooks.enforcement: "rewrite"` this harness falls back to the deny, whose reason
|
|
16
|
+
* still carries the exact replacement pipeline.
|
|
17
|
+
*/
|
|
18
|
+
const HOOKS = {
|
|
19
|
+
readTools: ['Read', 'read_file', 'ReadFile'],
|
|
20
|
+
bashTools: ['Bash', 'shell', 'run_shell_command'],
|
|
21
|
+
toolNameKeys: ['tool_name'],
|
|
22
|
+
toolInputKeys: ['tool_input'],
|
|
23
|
+
deny: (reason) => ({ decision: 'deny', reason }),
|
|
24
|
+
};
|
|
25
|
+
export const grok = {
|
|
26
|
+
id: 'grok',
|
|
27
|
+
name: 'Grok CLI',
|
|
28
|
+
tier: 'experimental',
|
|
29
|
+
detect: ['.grok'],
|
|
30
|
+
detectHome: ['.grok'],
|
|
31
|
+
instructionFile: 'AGENTS.md',
|
|
32
|
+
instructions: 'snippet',
|
|
33
|
+
caveats: ['deny-only hooks: input rewrite is not supported, so rewrite mode falls back to deny'],
|
|
34
|
+
hooks: HOOKS,
|
|
35
|
+
install: [
|
|
36
|
+
{
|
|
37
|
+
kind: 'json-hooks',
|
|
38
|
+
file: '.grok/hooks.json',
|
|
39
|
+
event: 'PreToolUse',
|
|
40
|
+
matchers: ['Read', 'Bash'],
|
|
41
|
+
entry: 'command-list',
|
|
42
|
+
lifecycle: false,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=grok.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grok.js","sourceRoot":"","sources":["../../src/harness/grok.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,KAAK,GAAsB;IAC/B,SAAS,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC;IAC5C,SAAS,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,mBAAmB,CAAC;IACjD,YAAY,EAAE,CAAC,WAAW,CAAC;IAC3B,aAAa,EAAE,CAAC,YAAY,CAAC;IAC7B,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;CACjD,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAA0B;IACzC,EAAE,EAAE,MAAM;IACV,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,cAAc;IACpB,MAAM,EAAE,CAAC,OAAO,CAAC;IACjB,UAAU,EAAE,CAAC,OAAO,CAAC;IACrB,eAAe,EAAE,WAAW;IAC5B,YAAY,EAAE,SAAS;IACvB,OAAO,EAAE,CAAC,qFAAqF,CAAC;IAChG,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE;QACP;YACE,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,kBAAkB;YACxB,KAAK,EAAE,YAAY;YACnB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;YAC1B,KAAK,EAAE,cAAc;YACrB,SAAS,EAAE,KAAK;SACjB;KACF;CACF,CAAC","sourcesContent":["import type { HarnessHookSchema } from '../hooks/shim.ts';\n\nimport type { ShimmedHarnessProfile } from './profile.ts';\n\n/**\n * Grok CLI — EXPERIMENTAL tier. Schema, install and removal, end to end.\n *\n * Schema mapped from the capability matrix\n * (docs/research/2026-09-02-harness-capability-matrix.md, Grok CLI row; primary source\n * <https://docs.x.ai/build/features/hooks>), not yet smoke-tested against the real\n * binary. Note the matrix's provenance warning: the official CLI is\n * `xai-org/grok-build` (binary `grok`) — `superagent-ai/grok-cli` is a third-party\n * clone with a different hook surface.\n *\n * - event: `PreToolUse`; stdin `{ tool_name, tool_input }` (Claude-Code-like tool\n * names).\n * - deny: `{ \"decision\": \"deny\", \"reason\": … }` or exit 2. **Deny-only**: the input\n * is read-only to hooks, so there is no `rewrite` here — under\n * `hooks.enforcement: \"rewrite\"` this harness falls back to the deny, whose reason\n * still carries the exact replacement pipeline.\n */\nconst HOOKS: HarnessHookSchema = {\n readTools: ['Read', 'read_file', 'ReadFile'],\n bashTools: ['Bash', 'shell', 'run_shell_command'],\n toolNameKeys: ['tool_name'],\n toolInputKeys: ['tool_input'],\n deny: (reason) => ({ decision: 'deny', reason }),\n};\n\nexport const grok: ShimmedHarnessProfile = {\n id: 'grok',\n name: 'Grok CLI',\n tier: 'experimental',\n detect: ['.grok'],\n detectHome: ['.grok'],\n instructionFile: 'AGENTS.md',\n instructions: 'snippet',\n caveats: ['deny-only hooks: input rewrite is not supported, so rewrite mode falls back to deny'],\n hooks: HOOKS,\n install: [\n {\n kind: 'json-hooks',\n file: '.grok/hooks.json',\n event: 'PreToolUse',\n matchers: ['Read', 'Bash'],\n entry: 'command-list',\n lifecycle: false,\n },\n ],\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes.d.ts","sourceRoot":"","sources":["../../src/harness/hermes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAyB,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAmDjF,eAAO,MAAM,MAAM,EAAE,qBAqBpB,CAAC","sourcesContent":["import type { HarnessHookSchema } from '../hooks/shim.ts';\n\nimport { nodeCommand, shimScriptPath } from './paths.ts';\nimport type { HarnessInstallContext, ShimmedHarnessProfile } from './profile.ts';\nimport { SNIPPET_END_HASH, SNIPPET_START_HASH } from './snippet.ts';\n\n/**\n * Hermes Agent — EXPERIMENTAL tier. Schema, install and removal, end to end.\n *\n * Schema mapped from the capability matrix\n * (docs/research/2026-09-02-harness-capability-matrix.md, Hermes Agent row; primary\n * source <https://hermes-agent.nousresearch.com/docs/user-guide/features/hooks>), not\n * yet smoke-tested against the real binary.\n *\n * - event: `pre_tool_call`; stdin carries the tool name and its arguments\n * (`tool_name` + `args`, with `tool_input` accepted as a fallback spelling).\n * - deny: `{ \"action\": \"block\", \"reason\": … }`.\n * - rewrite: `{ \"action\": \"modify\", \"args\": { … } }` — a **shallow merge** into the\n * tool's arguments, so this schema sends only the `command` key and the harness\n * keeps the rest. The modify document has **no reason field**, so the substitution\n * is announced on stderr — a rewrite must never be silent.\n *\n * Carried caveat from the matrix: Hermes has a known bypass where memory tools ignore\n * `disabled_toolsets` (<https://github.com/NousResearch/hermes-agent/issues/46171>) —\n * tool gating there is leaky at the edges, so treat this hook as best-effort steering,\n * not a boundary.\n */\nconst HOOKS: HarnessHookSchema = {\n readTools: ['read_file', 'Read', 'ReadFile'],\n bashTools: ['execute_command', 'terminal', 'bash', 'Bash', 'shell'],\n toolNameKeys: ['tool_name'],\n toolInputKeys: ['args', 'tool_input'],\n deny: (reason) => ({ action: 'block', reason }),\n rewrite: {\n // A shallow merge: only the key that changed travels, never the spliced whole.\n document: ({ suggestion }) => ({ action: 'modify', args: { command: suggestion } }),\n announce: 'stderr',\n },\n};\n\n/** Hermes hook config, as a mergeable snippet — their config is a home-level YAML. */\nfunction hermesHooksYaml(ctx: HarnessInstallContext): string {\n return `${SNIPPET_START_HASH}\n# Hermes Agent hook config for the smelt guard. EXPERIMENTAL tier: schema mapped from\n# the capability matrix (docs/research/2026-09-02-harness-capability-matrix.md, Hermes\n# row), not yet smoke-tested against the real binary. If Hermes does not read this\n# file directly, merge the \\`hooks:\\` section into ~/.hermes/config.yaml.\nhooks:\n pre_tool_call:\n - command: ${nodeCommand(ctx.cwd, shimScriptPath(hermes))}\n${SNIPPET_END_HASH}\n`;\n}\n\nexport const hermes: ShimmedHarnessProfile = {\n id: 'hermes',\n name: 'Hermes Agent',\n tier: 'experimental',\n detect: ['.hermes', '.hermes.md'],\n detectHome: ['.hermes'],\n instructionFile: 'AGENTS.md',\n instructions: 'snippet',\n caveats: [\n 'Hermes memory tools bypass disabled_toolsets (NousResearch/hermes-agent#46171) — treat tool gating there as leaky',\n 'hook config may need merging into ~/.hermes/config.yaml by hand; the written file says how',\n ],\n hooks: HOOKS,\n install: [\n {\n kind: 'own-file',\n file: '.hermes/hooks.yaml',\n content: hermesHooksYaml,\n guardOnly: true,\n },\n ],\n};\n"]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { nodeCommand, shimScriptPath } from './paths.js';
|
|
2
|
+
import { SNIPPET_END_HASH, SNIPPET_START_HASH } from './snippet.js';
|
|
3
|
+
/**
|
|
4
|
+
* Hermes Agent — EXPERIMENTAL tier. Schema, install and removal, end to end.
|
|
5
|
+
*
|
|
6
|
+
* Schema mapped from the capability matrix
|
|
7
|
+
* (docs/research/2026-09-02-harness-capability-matrix.md, Hermes Agent row; primary
|
|
8
|
+
* source <https://hermes-agent.nousresearch.com/docs/user-guide/features/hooks>), not
|
|
9
|
+
* yet smoke-tested against the real binary.
|
|
10
|
+
*
|
|
11
|
+
* - event: `pre_tool_call`; stdin carries the tool name and its arguments
|
|
12
|
+
* (`tool_name` + `args`, with `tool_input` accepted as a fallback spelling).
|
|
13
|
+
* - deny: `{ "action": "block", "reason": … }`.
|
|
14
|
+
* - rewrite: `{ "action": "modify", "args": { … } }` — a **shallow merge** into the
|
|
15
|
+
* tool's arguments, so this schema sends only the `command` key and the harness
|
|
16
|
+
* keeps the rest. The modify document has **no reason field**, so the substitution
|
|
17
|
+
* is announced on stderr — a rewrite must never be silent.
|
|
18
|
+
*
|
|
19
|
+
* Carried caveat from the matrix: Hermes has a known bypass where memory tools ignore
|
|
20
|
+
* `disabled_toolsets` (<https://github.com/NousResearch/hermes-agent/issues/46171>) —
|
|
21
|
+
* tool gating there is leaky at the edges, so treat this hook as best-effort steering,
|
|
22
|
+
* not a boundary.
|
|
23
|
+
*/
|
|
24
|
+
const HOOKS = {
|
|
25
|
+
readTools: ['read_file', 'Read', 'ReadFile'],
|
|
26
|
+
bashTools: ['execute_command', 'terminal', 'bash', 'Bash', 'shell'],
|
|
27
|
+
toolNameKeys: ['tool_name'],
|
|
28
|
+
toolInputKeys: ['args', 'tool_input'],
|
|
29
|
+
deny: (reason) => ({ action: 'block', reason }),
|
|
30
|
+
rewrite: {
|
|
31
|
+
// A shallow merge: only the key that changed travels, never the spliced whole.
|
|
32
|
+
document: ({ suggestion }) => ({ action: 'modify', args: { command: suggestion } }),
|
|
33
|
+
announce: 'stderr',
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
/** Hermes hook config, as a mergeable snippet — their config is a home-level YAML. */
|
|
37
|
+
function hermesHooksYaml(ctx) {
|
|
38
|
+
return `${SNIPPET_START_HASH}
|
|
39
|
+
# Hermes Agent hook config for the smelt guard. EXPERIMENTAL tier: schema mapped from
|
|
40
|
+
# the capability matrix (docs/research/2026-09-02-harness-capability-matrix.md, Hermes
|
|
41
|
+
# row), not yet smoke-tested against the real binary. If Hermes does not read this
|
|
42
|
+
# file directly, merge the \`hooks:\` section into ~/.hermes/config.yaml.
|
|
43
|
+
hooks:
|
|
44
|
+
pre_tool_call:
|
|
45
|
+
- command: ${nodeCommand(ctx.cwd, shimScriptPath(hermes))}
|
|
46
|
+
${SNIPPET_END_HASH}
|
|
47
|
+
`;
|
|
48
|
+
}
|
|
49
|
+
export const hermes = {
|
|
50
|
+
id: 'hermes',
|
|
51
|
+
name: 'Hermes Agent',
|
|
52
|
+
tier: 'experimental',
|
|
53
|
+
detect: ['.hermes', '.hermes.md'],
|
|
54
|
+
detectHome: ['.hermes'],
|
|
55
|
+
instructionFile: 'AGENTS.md',
|
|
56
|
+
instructions: 'snippet',
|
|
57
|
+
caveats: [
|
|
58
|
+
'Hermes memory tools bypass disabled_toolsets (NousResearch/hermes-agent#46171) — treat tool gating there as leaky',
|
|
59
|
+
'hook config may need merging into ~/.hermes/config.yaml by hand; the written file says how',
|
|
60
|
+
],
|
|
61
|
+
hooks: HOOKS,
|
|
62
|
+
install: [
|
|
63
|
+
{
|
|
64
|
+
kind: 'own-file',
|
|
65
|
+
file: '.hermes/hooks.yaml',
|
|
66
|
+
content: hermesHooksYaml,
|
|
67
|
+
guardOnly: true,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=hermes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes.js","sourceRoot":"","sources":["../../src/harness/hermes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,KAAK,GAAsB;IAC/B,SAAS,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC;IAC5C,SAAS,EAAE,CAAC,iBAAiB,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;IACnE,YAAY,EAAE,CAAC,WAAW,CAAC;IAC3B,aAAa,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC;IACrC,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAC/C,OAAO,EAAE;QACP,+EAA+E;QAC/E,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC;QACnF,QAAQ,EAAE,QAAQ;KACnB;CACF,CAAC;AAEF,sFAAsF;AACtF,SAAS,eAAe,CAAC,GAA0B;IACjD,OAAO,GAAG,kBAAkB;;;;;;;iBAOb,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;EAC3D,gBAAgB;CACjB,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAA0B;IAC3C,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,cAAc;IACpB,IAAI,EAAE,cAAc;IACpB,MAAM,EAAE,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,UAAU,EAAE,CAAC,SAAS,CAAC;IACvB,eAAe,EAAE,WAAW;IAC5B,YAAY,EAAE,SAAS;IACvB,OAAO,EAAE;QACP,mHAAmH;QACnH,4FAA4F;KAC7F;IACD,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE;QACP;YACE,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,oBAAoB;YAC1B,OAAO,EAAE,eAAe;YACxB,SAAS,EAAE,IAAI;SAChB;KACF;CACF,CAAC","sourcesContent":["import type { HarnessHookSchema } from '../hooks/shim.ts';\n\nimport { nodeCommand, shimScriptPath } from './paths.ts';\nimport type { HarnessInstallContext, ShimmedHarnessProfile } from './profile.ts';\nimport { SNIPPET_END_HASH, SNIPPET_START_HASH } from './snippet.ts';\n\n/**\n * Hermes Agent — EXPERIMENTAL tier. Schema, install and removal, end to end.\n *\n * Schema mapped from the capability matrix\n * (docs/research/2026-09-02-harness-capability-matrix.md, Hermes Agent row; primary\n * source <https://hermes-agent.nousresearch.com/docs/user-guide/features/hooks>), not\n * yet smoke-tested against the real binary.\n *\n * - event: `pre_tool_call`; stdin carries the tool name and its arguments\n * (`tool_name` + `args`, with `tool_input` accepted as a fallback spelling).\n * - deny: `{ \"action\": \"block\", \"reason\": … }`.\n * - rewrite: `{ \"action\": \"modify\", \"args\": { … } }` — a **shallow merge** into the\n * tool's arguments, so this schema sends only the `command` key and the harness\n * keeps the rest. The modify document has **no reason field**, so the substitution\n * is announced on stderr — a rewrite must never be silent.\n *\n * Carried caveat from the matrix: Hermes has a known bypass where memory tools ignore\n * `disabled_toolsets` (<https://github.com/NousResearch/hermes-agent/issues/46171>) —\n * tool gating there is leaky at the edges, so treat this hook as best-effort steering,\n * not a boundary.\n */\nconst HOOKS: HarnessHookSchema = {\n readTools: ['read_file', 'Read', 'ReadFile'],\n bashTools: ['execute_command', 'terminal', 'bash', 'Bash', 'shell'],\n toolNameKeys: ['tool_name'],\n toolInputKeys: ['args', 'tool_input'],\n deny: (reason) => ({ action: 'block', reason }),\n rewrite: {\n // A shallow merge: only the key that changed travels, never the spliced whole.\n document: ({ suggestion }) => ({ action: 'modify', args: { command: suggestion } }),\n announce: 'stderr',\n },\n};\n\n/** Hermes hook config, as a mergeable snippet — their config is a home-level YAML. */\nfunction hermesHooksYaml(ctx: HarnessInstallContext): string {\n return `${SNIPPET_START_HASH}\n# Hermes Agent hook config for the smelt guard. EXPERIMENTAL tier: schema mapped from\n# the capability matrix (docs/research/2026-09-02-harness-capability-matrix.md, Hermes\n# row), not yet smoke-tested against the real binary. If Hermes does not read this\n# file directly, merge the \\`hooks:\\` section into ~/.hermes/config.yaml.\nhooks:\n pre_tool_call:\n - command: ${nodeCommand(ctx.cwd, shimScriptPath(hermes))}\n${SNIPPET_END_HASH}\n`;\n}\n\nexport const hermes: ShimmedHarnessProfile = {\n id: 'hermes',\n name: 'Hermes Agent',\n tier: 'experimental',\n detect: ['.hermes', '.hermes.md'],\n detectHome: ['.hermes'],\n instructionFile: 'AGENTS.md',\n instructions: 'snippet',\n caveats: [\n 'Hermes memory tools bypass disabled_toolsets (NousResearch/hermes-agent#46171) — treat tool gating there as leaky',\n 'hook config may need merging into ~/.hermes/config.yaml by hand; the written file says how',\n ],\n hooks: HOOKS,\n install: [\n {\n kind: 'own-file',\n file: '.hermes/hooks.yaml',\n content: hermesHooksYaml,\n guardOnly: true,\n },\n ],\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kilocode.d.ts","sourceRoot":"","sources":["../../src/harness/kilocode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAyB,cAAc,EAAE,MAAM,cAAc,CAAC;AAwB1E,eAAO,MAAM,QAAQ,EAAE,cAYtB,CAAC","sourcesContent":["import type { HarnessInstallContext, HarnessProfile } from './profile.ts';\nimport { instructionSnippet } from './snippet.ts';\n\n/**\n * KiloCode — ADVISORY tier. Instructions only, and honest about it.\n *\n * No first-class hook API (Kilo-Org/kilocode#5827), so nothing here is enforced: what\n * ships is a rules file this harness owns whole — the shared snippet plus the two\n * manual enforcement legs the snippet has no room for. `remove` deletes it.\n */\nfunction kilocodeRulesSource(ctx: HarnessInstallContext): string {\n return `${instructionSnippet(ctx.thresholdBytes, ctx.budgetBytes)}\n<!-- smelt:hooks v1 advisory notes -->\n\nKiloCode has no first-class hook API (Kilo-Org/kilocode#5827), so nothing above is\nenforced — it is advisory. Two manual legs make it harder to bypass:\n\n1. Permissions: in your KiloCode per-tool permission config, set raw-read/execute\n tools to \"ask\" so oversized reads surface for review instead of passing silently.\n2. MCP: expose smelt through an MCP server and prefer its tools; a resident server\n also keeps smelt's grammar cache warm across calls.\n`;\n}\n\nexport const kilocode: HarnessProfile = {\n id: 'kilocode',\n name: 'KiloCode',\n tier: 'advisory',\n detect: ['.kilocode'],\n detectHome: ['.config/kilo'],\n instructionFile: '.kilocode/rules/smelt.md',\n instructions: kilocodeRulesSource,\n caveats: [\n 'no first-class hooks (Kilo-Org/kilocode#5827): enforcement is permissions config + MCP, both manual',\n ],\n install: [],\n};\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { instructionSnippet } from './snippet.js';
|
|
2
|
+
/**
|
|
3
|
+
* KiloCode — ADVISORY tier. Instructions only, and honest about it.
|
|
4
|
+
*
|
|
5
|
+
* No first-class hook API (Kilo-Org/kilocode#5827), so nothing here is enforced: what
|
|
6
|
+
* ships is a rules file this harness owns whole — the shared snippet plus the two
|
|
7
|
+
* manual enforcement legs the snippet has no room for. `remove` deletes it.
|
|
8
|
+
*/
|
|
9
|
+
function kilocodeRulesSource(ctx) {
|
|
10
|
+
return `${instructionSnippet(ctx.thresholdBytes, ctx.budgetBytes)}
|
|
11
|
+
<!-- smelt:hooks v1 advisory notes -->
|
|
12
|
+
|
|
13
|
+
KiloCode has no first-class hook API (Kilo-Org/kilocode#5827), so nothing above is
|
|
14
|
+
enforced — it is advisory. Two manual legs make it harder to bypass:
|
|
15
|
+
|
|
16
|
+
1. Permissions: in your KiloCode per-tool permission config, set raw-read/execute
|
|
17
|
+
tools to "ask" so oversized reads surface for review instead of passing silently.
|
|
18
|
+
2. MCP: expose smelt through an MCP server and prefer its tools; a resident server
|
|
19
|
+
also keeps smelt's grammar cache warm across calls.
|
|
20
|
+
`;
|
|
21
|
+
}
|
|
22
|
+
export const kilocode = {
|
|
23
|
+
id: 'kilocode',
|
|
24
|
+
name: 'KiloCode',
|
|
25
|
+
tier: 'advisory',
|
|
26
|
+
detect: ['.kilocode'],
|
|
27
|
+
detectHome: ['.config/kilo'],
|
|
28
|
+
instructionFile: '.kilocode/rules/smelt.md',
|
|
29
|
+
instructions: kilocodeRulesSource,
|
|
30
|
+
caveats: [
|
|
31
|
+
'no first-class hooks (Kilo-Org/kilocode#5827): enforcement is permissions config + MCP, both manual',
|
|
32
|
+
],
|
|
33
|
+
install: [],
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=kilocode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kilocode.js","sourceRoot":"","sources":["../../src/harness/kilocode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD;;;;;;GAMG;AACH,SAAS,mBAAmB,CAAC,GAA0B;IACrD,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,WAAW,CAAC;;;;;;;;;;CAUlE,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAmB;IACtC,EAAE,EAAE,UAAU;IACd,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,MAAM,EAAE,CAAC,WAAW,CAAC;IACrB,UAAU,EAAE,CAAC,cAAc,CAAC;IAC5B,eAAe,EAAE,0BAA0B;IAC3C,YAAY,EAAE,mBAAmB;IACjC,OAAO,EAAE;QACP,qGAAqG;KACtG;IACD,OAAO,EAAE,EAAE;CACZ,CAAC","sourcesContent":["import type { HarnessInstallContext, HarnessProfile } from './profile.ts';\nimport { instructionSnippet } from './snippet.ts';\n\n/**\n * KiloCode — ADVISORY tier. Instructions only, and honest about it.\n *\n * No first-class hook API (Kilo-Org/kilocode#5827), so nothing here is enforced: what\n * ships is a rules file this harness owns whole — the shared snippet plus the two\n * manual enforcement legs the snippet has no room for. `remove` deletes it.\n */\nfunction kilocodeRulesSource(ctx: HarnessInstallContext): string {\n return `${instructionSnippet(ctx.thresholdBytes, ctx.budgetBytes)}\n<!-- smelt:hooks v1 advisory notes -->\n\nKiloCode has no first-class hook API (Kilo-Org/kilocode#5827), so nothing above is\nenforced — it is advisory. Two manual legs make it harder to bypass:\n\n1. Permissions: in your KiloCode per-tool permission config, set raw-read/execute\n tools to \"ask\" so oversized reads surface for review instead of passing silently.\n2. MCP: expose smelt through an MCP server and prefer its tools; a resident server\n also keeps smelt's grammar cache warm across calls.\n`;\n}\n\nexport const kilocode: HarnessProfile = {\n id: 'kilocode',\n name: 'KiloCode',\n tier: 'advisory',\n detect: ['.kilocode'],\n detectHome: ['.config/kilo'],\n instructionFile: '.kilocode/rules/smelt.md',\n instructions: kilocodeRulesSource,\n caveats: [\n 'no first-class hooks (Kilo-Org/kilocode#5827): enforcement is permissions config + MCP, both manual',\n ],\n install: [],\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../src/harness/opencode.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAyB,cAAc,EAAE,MAAM,cAAc,CAAC;AA6E1E,eAAO,MAAM,QAAQ,EAAE,cAmBtB,CAAC","sourcesContent":["import {\n DENIED_WITHOUT_REASON,\n REWRITE_ANNOUNCEMENT_JOIN,\n REWRITE_ANNOUNCEMENT_OPENING,\n} from '../hooks/shim.ts';\n\nimport { guardCoreScriptPath, portablePath } from './paths.ts';\nimport type { HarnessInstallContext, HarnessProfile } from './profile.ts';\n\n/**\n * opencode — EXPERIMENTAL tier. Install and removal, end to end.\n *\n * The one harness with no shim script: its hook API is a JavaScript plugin, not a\n * stdin schema, so what the installer writes *is* the adapter. The plugin imports the\n * built guard core directly (the same module every shim calls) and maps\n * `tool.execute.before` onto it, so all policy still lives in exactly one place.\n *\n * Its two announcements — the rewrite sentence and the reasonless deny — are spliced\n * in from `hooks/shim.ts`'s constants rather than hand-typed into the template, where\n * nothing could see them drift from what the shims print.\n */\nfunction opencodePluginSource(ctx: HarnessInstallContext): string {\n const guardCore = portablePath(ctx.cwd, guardCoreScriptPath());\n return `// smelt:hooks v1 — opencode plugin shim. EXPERIMENTAL tier: mapped from the\n// capability matrix (docs/research/2026-09-02-harness-capability-matrix.md, opencode\n// row; https://opencode.ai/docs/plugins/). This template's deny/pass/window paths\n// were exercised directly against the built guard core (verified\n// 2026-09-02), but a live opencode session has not been smoke-tested — that needs\n// provider credentials. Caveat carried from the matrix: MCP tools can bypass plugin\n// hooks (sst/opencode#2319) — this guard sees built-in tools only.\n//\n// Thin adapter: maps tool.execute.before onto the smelt guard core (zero\n// dependencies), which owns every decision. Deny mode throws (opencode surfaces the\n// reason to the model); rewrite mode substitutes the faithful replacement command —\n// announced on stderr, because the plugin API has no reason channel on a rewrite\n// and a substitution must never be silent. Both announcements below are spliced in\n// from the shims' own constants, so this copy cannot drift from theirs.\nimport { pathToFileURL } from 'node:url';\n\nconst GUARD_CORE = ${JSON.stringify(guardCore)};\nconst core = await import(pathToFileURL(GUARD_CORE).href);\n\nexport const SmeltGuard = async () => ({\n 'tool.execute.before': async (input, output) => {\n const tool = input?.tool;\n const args = output?.args ?? {};\n let request;\n if (tool === 'read' && typeof args.filePath === 'string') {\n request = {\n tool: 'Read',\n input: {\n path: args.filePath,\n offsetLimited: args.offset !== undefined || args.limit !== undefined,\n },\n };\n } else if (tool === 'bash' && typeof args.command === 'string') {\n request = { tool: 'Bash', input: { command: args.command } };\n } else {\n return;\n }\n const warn = (text) => process.stderr.write(text + '\\\\n');\n const settings = core.readGuardSettings(process.cwd(), warn);\n const decision = core.decide(request, settings, process.cwd());\n if (decision.action !== 'deny') return;\n if (\n settings.enforcement === 'rewrite' &&\n request.tool === 'Bash' &&\n decision.suggestion !== undefined\n ) {\n warn(\n ${JSON.stringify(REWRITE_ANNOUNCEMENT_OPENING)} +\n decision.suggestion +\n ${JSON.stringify(REWRITE_ANNOUNCEMENT_JOIN)} +\n (decision.reason ?? ''),\n );\n output.args.command = decision.suggestion;\n return;\n }\n throw new Error(decision.reason ?? ${JSON.stringify(DENIED_WITHOUT_REASON)});\n },\n});\n`;\n}\n\nexport const opencode: HarnessProfile = {\n id: 'opencode',\n name: 'opencode',\n tier: 'experimental',\n detect: ['.opencode', 'opencode.json'],\n detectHome: ['.config/opencode'],\n instructionFile: 'AGENTS.md',\n instructions: 'snippet',\n caveats: [\n 'MCP tools can bypass opencode plugin hooks (sst/opencode#2319) — the guard sees built-in tools only',\n ],\n install: [\n {\n kind: 'own-file',\n file: '.opencode/plugin/smelt-guard.js',\n content: opencodePluginSource,\n guardOnly: true,\n },\n ],\n};\n"]}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { DENIED_WITHOUT_REASON, REWRITE_ANNOUNCEMENT_JOIN, REWRITE_ANNOUNCEMENT_OPENING, } from '../hooks/shim.js';
|
|
2
|
+
import { guardCoreScriptPath, portablePath } from './paths.js';
|
|
3
|
+
/**
|
|
4
|
+
* opencode — EXPERIMENTAL tier. Install and removal, end to end.
|
|
5
|
+
*
|
|
6
|
+
* The one harness with no shim script: its hook API is a JavaScript plugin, not a
|
|
7
|
+
* stdin schema, so what the installer writes *is* the adapter. The plugin imports the
|
|
8
|
+
* built guard core directly (the same module every shim calls) and maps
|
|
9
|
+
* `tool.execute.before` onto it, so all policy still lives in exactly one place.
|
|
10
|
+
*
|
|
11
|
+
* Its two announcements — the rewrite sentence and the reasonless deny — are spliced
|
|
12
|
+
* in from `hooks/shim.ts`'s constants rather than hand-typed into the template, where
|
|
13
|
+
* nothing could see them drift from what the shims print.
|
|
14
|
+
*/
|
|
15
|
+
function opencodePluginSource(ctx) {
|
|
16
|
+
const guardCore = portablePath(ctx.cwd, guardCoreScriptPath());
|
|
17
|
+
return `// smelt:hooks v1 — opencode plugin shim. EXPERIMENTAL tier: mapped from the
|
|
18
|
+
// capability matrix (docs/research/2026-09-02-harness-capability-matrix.md, opencode
|
|
19
|
+
// row; https://opencode.ai/docs/plugins/). This template's deny/pass/window paths
|
|
20
|
+
// were exercised directly against the built guard core (verified
|
|
21
|
+
// 2026-09-02), but a live opencode session has not been smoke-tested — that needs
|
|
22
|
+
// provider credentials. Caveat carried from the matrix: MCP tools can bypass plugin
|
|
23
|
+
// hooks (sst/opencode#2319) — this guard sees built-in tools only.
|
|
24
|
+
//
|
|
25
|
+
// Thin adapter: maps tool.execute.before onto the smelt guard core (zero
|
|
26
|
+
// dependencies), which owns every decision. Deny mode throws (opencode surfaces the
|
|
27
|
+
// reason to the model); rewrite mode substitutes the faithful replacement command —
|
|
28
|
+
// announced on stderr, because the plugin API has no reason channel on a rewrite
|
|
29
|
+
// and a substitution must never be silent. Both announcements below are spliced in
|
|
30
|
+
// from the shims' own constants, so this copy cannot drift from theirs.
|
|
31
|
+
import { pathToFileURL } from 'node:url';
|
|
32
|
+
|
|
33
|
+
const GUARD_CORE = ${JSON.stringify(guardCore)};
|
|
34
|
+
const core = await import(pathToFileURL(GUARD_CORE).href);
|
|
35
|
+
|
|
36
|
+
export const SmeltGuard = async () => ({
|
|
37
|
+
'tool.execute.before': async (input, output) => {
|
|
38
|
+
const tool = input?.tool;
|
|
39
|
+
const args = output?.args ?? {};
|
|
40
|
+
let request;
|
|
41
|
+
if (tool === 'read' && typeof args.filePath === 'string') {
|
|
42
|
+
request = {
|
|
43
|
+
tool: 'Read',
|
|
44
|
+
input: {
|
|
45
|
+
path: args.filePath,
|
|
46
|
+
offsetLimited: args.offset !== undefined || args.limit !== undefined,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
} else if (tool === 'bash' && typeof args.command === 'string') {
|
|
50
|
+
request = { tool: 'Bash', input: { command: args.command } };
|
|
51
|
+
} else {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const warn = (text) => process.stderr.write(text + '\\n');
|
|
55
|
+
const settings = core.readGuardSettings(process.cwd(), warn);
|
|
56
|
+
const decision = core.decide(request, settings, process.cwd());
|
|
57
|
+
if (decision.action !== 'deny') return;
|
|
58
|
+
if (
|
|
59
|
+
settings.enforcement === 'rewrite' &&
|
|
60
|
+
request.tool === 'Bash' &&
|
|
61
|
+
decision.suggestion !== undefined
|
|
62
|
+
) {
|
|
63
|
+
warn(
|
|
64
|
+
${JSON.stringify(REWRITE_ANNOUNCEMENT_OPENING)} +
|
|
65
|
+
decision.suggestion +
|
|
66
|
+
${JSON.stringify(REWRITE_ANNOUNCEMENT_JOIN)} +
|
|
67
|
+
(decision.reason ?? ''),
|
|
68
|
+
);
|
|
69
|
+
output.args.command = decision.suggestion;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
throw new Error(decision.reason ?? ${JSON.stringify(DENIED_WITHOUT_REASON)});
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
`;
|
|
76
|
+
}
|
|
77
|
+
export const opencode = {
|
|
78
|
+
id: 'opencode',
|
|
79
|
+
name: 'opencode',
|
|
80
|
+
tier: 'experimental',
|
|
81
|
+
detect: ['.opencode', 'opencode.json'],
|
|
82
|
+
detectHome: ['.config/opencode'],
|
|
83
|
+
instructionFile: 'AGENTS.md',
|
|
84
|
+
instructions: 'snippet',
|
|
85
|
+
caveats: [
|
|
86
|
+
'MCP tools can bypass opencode plugin hooks (sst/opencode#2319) — the guard sees built-in tools only',
|
|
87
|
+
],
|
|
88
|
+
install: [
|
|
89
|
+
{
|
|
90
|
+
kind: 'own-file',
|
|
91
|
+
file: '.opencode/plugin/smelt-guard.js',
|
|
92
|
+
content: opencodePluginSource,
|
|
93
|
+
guardOnly: true,
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/harness/opencode.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/D;;;;;;;;;;;GAWG;AACH,SAAS,oBAAoB,CAAC,GAA0B;IACtD,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC/D,OAAO;;;;;;;;;;;;;;;;qBAgBY,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA+BpC,IAAI,CAAC,SAAS,CAAC,4BAA4B,CAAC;;YAE1C,IAAI,CAAC,SAAS,CAAC,yBAAyB,CAAC;;;;;;yCAMZ,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC;;;CAG7E,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAmB;IACtC,EAAE,EAAE,UAAU;IACd,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,cAAc;IACpB,MAAM,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC;IACtC,UAAU,EAAE,CAAC,kBAAkB,CAAC;IAChC,eAAe,EAAE,WAAW;IAC5B,YAAY,EAAE,SAAS;IACvB,OAAO,EAAE;QACP,qGAAqG;KACtG;IACD,OAAO,EAAE;QACP;YACE,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,iCAAiC;YACvC,OAAO,EAAE,oBAAoB;YAC7B,SAAS,EAAE,IAAI;SAChB;KACF;CACF,CAAC","sourcesContent":["import {\n DENIED_WITHOUT_REASON,\n REWRITE_ANNOUNCEMENT_JOIN,\n REWRITE_ANNOUNCEMENT_OPENING,\n} from '../hooks/shim.ts';\n\nimport { guardCoreScriptPath, portablePath } from './paths.ts';\nimport type { HarnessInstallContext, HarnessProfile } from './profile.ts';\n\n/**\n * opencode — EXPERIMENTAL tier. Install and removal, end to end.\n *\n * The one harness with no shim script: its hook API is a JavaScript plugin, not a\n * stdin schema, so what the installer writes *is* the adapter. The plugin imports the\n * built guard core directly (the same module every shim calls) and maps\n * `tool.execute.before` onto it, so all policy still lives in exactly one place.\n *\n * Its two announcements — the rewrite sentence and the reasonless deny — are spliced\n * in from `hooks/shim.ts`'s constants rather than hand-typed into the template, where\n * nothing could see them drift from what the shims print.\n */\nfunction opencodePluginSource(ctx: HarnessInstallContext): string {\n const guardCore = portablePath(ctx.cwd, guardCoreScriptPath());\n return `// smelt:hooks v1 — opencode plugin shim. EXPERIMENTAL tier: mapped from the\n// capability matrix (docs/research/2026-09-02-harness-capability-matrix.md, opencode\n// row; https://opencode.ai/docs/plugins/). This template's deny/pass/window paths\n// were exercised directly against the built guard core (verified\n// 2026-09-02), but a live opencode session has not been smoke-tested — that needs\n// provider credentials. Caveat carried from the matrix: MCP tools can bypass plugin\n// hooks (sst/opencode#2319) — this guard sees built-in tools only.\n//\n// Thin adapter: maps tool.execute.before onto the smelt guard core (zero\n// dependencies), which owns every decision. Deny mode throws (opencode surfaces the\n// reason to the model); rewrite mode substitutes the faithful replacement command —\n// announced on stderr, because the plugin API has no reason channel on a rewrite\n// and a substitution must never be silent. Both announcements below are spliced in\n// from the shims' own constants, so this copy cannot drift from theirs.\nimport { pathToFileURL } from 'node:url';\n\nconst GUARD_CORE = ${JSON.stringify(guardCore)};\nconst core = await import(pathToFileURL(GUARD_CORE).href);\n\nexport const SmeltGuard = async () => ({\n 'tool.execute.before': async (input, output) => {\n const tool = input?.tool;\n const args = output?.args ?? {};\n let request;\n if (tool === 'read' && typeof args.filePath === 'string') {\n request = {\n tool: 'Read',\n input: {\n path: args.filePath,\n offsetLimited: args.offset !== undefined || args.limit !== undefined,\n },\n };\n } else if (tool === 'bash' && typeof args.command === 'string') {\n request = { tool: 'Bash', input: { command: args.command } };\n } else {\n return;\n }\n const warn = (text) => process.stderr.write(text + '\\\\n');\n const settings = core.readGuardSettings(process.cwd(), warn);\n const decision = core.decide(request, settings, process.cwd());\n if (decision.action !== 'deny') return;\n if (\n settings.enforcement === 'rewrite' &&\n request.tool === 'Bash' &&\n decision.suggestion !== undefined\n ) {\n warn(\n ${JSON.stringify(REWRITE_ANNOUNCEMENT_OPENING)} +\n decision.suggestion +\n ${JSON.stringify(REWRITE_ANNOUNCEMENT_JOIN)} +\n (decision.reason ?? ''),\n );\n output.args.command = decision.suggestion;\n return;\n }\n throw new Error(decision.reason ?? ${JSON.stringify(DENIED_WITHOUT_REASON)});\n },\n});\n`;\n}\n\nexport const opencode: HarnessProfile = {\n id: 'opencode',\n name: 'opencode',\n tier: 'experimental',\n detect: ['.opencode', 'opencode.json'],\n detectHome: ['.config/opencode'],\n instructionFile: 'AGENTS.md',\n instructions: 'snippet',\n caveats: [\n 'MCP tools can bypass opencode plugin hooks (sst/opencode#2319) — the guard sees built-in tools only',\n ],\n install: [\n {\n kind: 'own-file',\n file: '.opencode/plugin/smelt-guard.js',\n content: opencodePluginSource,\n guardOnly: true,\n },\n ],\n};\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ShimmedHarnessProfile } from './profile.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The shim script a harness's hook command runs. Takes a profile rather than an id,
|
|
4
|
+
* because only a profile that carries a hook schema (or a hand-written adapter) has a
|
|
5
|
+
* shim script on disk: a path for a harness that ships none would name a file the
|
|
6
|
+
* build never produced.
|
|
7
|
+
*/
|
|
8
|
+
export declare function shimScriptPath(profile: ShimmedHarnessProfile): string;
|
|
9
|
+
/** The guard core as a module: what the opencode plugin imports at hook time. */
|
|
10
|
+
export declare function guardCoreScriptPath(): string;
|
|
11
|
+
/** The `smelt` binary — quoted into the stats and map hook commands. */
|
|
12
|
+
export declare function smeltBinPath(): string;
|
|
13
|
+
/** Inside the project, a project-relative path travels with the repo; outside, absolute. */
|
|
14
|
+
export declare function portablePath(cwd: string, absolute: string): string;
|
|
15
|
+
/** `node "<script>"` — how every harness config invokes something of smelt's. */
|
|
16
|
+
export declare function nodeCommand(cwd: string, script: string, args?: string): string;
|
|
17
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/harness/paths.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAoB1D;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAErE;AAED,iFAAiF;AACjF,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,wEAAwE;AACxE,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGlE;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,MAAM,CAE1E","sourcesContent":["import { dirname, isAbsolute, join, relative, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { ShimmedHarnessProfile } from './profile.ts';\n\n/**\n * Where the scripts a harness config points at actually live, and how a profile names\n * one. Path facts only — nothing here reads or writes a file.\n */\n\n/**\n * The `dist` directory of this installed package — where the shipped guard core and\n * shim scripts live. Computed from this module's own location, which is\n * `<pkg>/dist/harness/` in every real run (the CLI executes from `dist`); under the\n * test runner it is `<pkg>/src/harness/`, and the substitution still points at `dist`,\n * which is where the scripts will exist once built — the paths are written into config\n * files for *node* to execute, never imported.\n */\nfunction packageDistDir(): string {\n const here = dirname(fileURLToPath(import.meta.url)); // <pkg>/(dist|src)/harness\n return join(dirname(dirname(here)), 'dist');\n}\n\n/**\n * The shim script a harness's hook command runs. Takes a profile rather than an id,\n * because only a profile that carries a hook schema (or a hand-written adapter) has a\n * shim script on disk: a path for a harness that ships none would name a file the\n * build never produced.\n */\nexport function shimScriptPath(profile: ShimmedHarnessProfile): string {\n return join(packageDistDir(), 'hooks', 'shims', `${profile.id}.js`);\n}\n\n/** The guard core as a module: what the opencode plugin imports at hook time. */\nexport function guardCoreScriptPath(): string {\n return join(packageDistDir(), 'hooks', 'guard-core.js');\n}\n\n/** The `smelt` binary — quoted into the stats and map hook commands. */\nexport function smeltBinPath(): string {\n return join(packageDistDir(), 'cli', 'bin.js');\n}\n\n/** Inside the project, a project-relative path travels with the repo; outside, absolute. */\nexport function portablePath(cwd: string, absolute: string): string {\n const rel = relative(cwd, absolute);\n return rel.startsWith('..') || isAbsolute(rel) ? absolute : rel.split(sep).join('/');\n}\n\n/** `node \"<script>\"` — how every harness config invokes something of smelt's. */\nexport function nodeCommand(cwd: string, script: string, args = ''): string {\n return `node \"${portablePath(cwd, script)}\"${args === '' ? '' : ` ${args}`}`;\n}\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { dirname, isAbsolute, join, relative, sep } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
/**
|
|
4
|
+
* Where the scripts a harness config points at actually live, and how a profile names
|
|
5
|
+
* one. Path facts only — nothing here reads or writes a file.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* The `dist` directory of this installed package — where the shipped guard core and
|
|
9
|
+
* shim scripts live. Computed from this module's own location, which is
|
|
10
|
+
* `<pkg>/dist/harness/` in every real run (the CLI executes from `dist`); under the
|
|
11
|
+
* test runner it is `<pkg>/src/harness/`, and the substitution still points at `dist`,
|
|
12
|
+
* which is where the scripts will exist once built — the paths are written into config
|
|
13
|
+
* files for *node* to execute, never imported.
|
|
14
|
+
*/
|
|
15
|
+
function packageDistDir() {
|
|
16
|
+
const here = dirname(fileURLToPath(import.meta.url)); // <pkg>/(dist|src)/harness
|
|
17
|
+
return join(dirname(dirname(here)), 'dist');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The shim script a harness's hook command runs. Takes a profile rather than an id,
|
|
21
|
+
* because only a profile that carries a hook schema (or a hand-written adapter) has a
|
|
22
|
+
* shim script on disk: a path for a harness that ships none would name a file the
|
|
23
|
+
* build never produced.
|
|
24
|
+
*/
|
|
25
|
+
export function shimScriptPath(profile) {
|
|
26
|
+
return join(packageDistDir(), 'hooks', 'shims', `${profile.id}.js`);
|
|
27
|
+
}
|
|
28
|
+
/** The guard core as a module: what the opencode plugin imports at hook time. */
|
|
29
|
+
export function guardCoreScriptPath() {
|
|
30
|
+
return join(packageDistDir(), 'hooks', 'guard-core.js');
|
|
31
|
+
}
|
|
32
|
+
/** The `smelt` binary — quoted into the stats and map hook commands. */
|
|
33
|
+
export function smeltBinPath() {
|
|
34
|
+
return join(packageDistDir(), 'cli', 'bin.js');
|
|
35
|
+
}
|
|
36
|
+
/** Inside the project, a project-relative path travels with the repo; outside, absolute. */
|
|
37
|
+
export function portablePath(cwd, absolute) {
|
|
38
|
+
const rel = relative(cwd, absolute);
|
|
39
|
+
return rel.startsWith('..') || isAbsolute(rel) ? absolute : rel.split(sep).join('/');
|
|
40
|
+
}
|
|
41
|
+
/** `node "<script>"` — how every harness config invokes something of smelt's. */
|
|
42
|
+
export function nodeCommand(cwd, script, args = '') {
|
|
43
|
+
return `node "${portablePath(cwd, script)}"${args === '' ? '' : ` ${args}`}`;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=paths.js.map
|