@fusengine/harness 0.1.60 → 0.1.61

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.
@@ -1,2 +1,2 @@
1
- import { a as denyResponse, c as informResponse, d as toClaudeResponse, i as contextResponse, l as readClaudeInput, n as attachSystemMessage, o as fileSizeGuard, r as blockResponse, s as guard, t as ClaudeHookInput, u as systemMessage } from "../../index-DZCLmSoO.mjs";
1
+ import { a as denyResponse, c as informResponse, d as toClaudeResponse, i as contextResponse, l as readClaudeInput, n as attachSystemMessage, o as fileSizeGuard, r as blockResponse, s as guard, t as ClaudeHookInput, u as systemMessage } from "../../index-ce2J1bHC.mjs";
2
2
  export { ClaudeHookInput, attachSystemMessage, blockResponse, contextResponse, denyResponse, fileSizeGuard, guard, informResponse, readClaudeInput, systemMessage, toClaudeResponse };
@@ -1,2 +1,2 @@
1
- import { a as fileSizeGuard, c as readClaudeInput, i as denyResponse, l as systemMessage, n as blockResponse, o as guard, r as contextResponse, s as informResponse, t as attachSystemMessage, u as toClaudeResponse } from "../../claude-k1SG-ROm.mjs";
1
+ import { a as fileSizeGuard, c as readClaudeInput, i as denyResponse, l as systemMessage, n as blockResponse, o as guard, r as contextResponse, s as informResponse, t as attachSystemMessage, u as toClaudeResponse } from "../../claude-BJER7Mbj.mjs";
2
2
  export { attachSystemMessage, blockResponse, contextResponse, denyResponse, fileSizeGuard, guard, informResponse, readClaudeInput, systemMessage, toClaudeResponse };
@@ -1,5 +1,5 @@
1
1
  import { t as Prompt } from "../../types-DVbIl9md.mjs";
2
- import { a as denyResponse, i as contextResponse, l as readClaudeInput, t as ClaudeHookInput } from "../../index-DZCLmSoO.mjs";
2
+ import { a as denyResponse, i as contextResponse, l as readClaudeInput, t as ClaudeHookInput } from "../../index-ce2J1bHC.mjs";
3
3
 
4
4
  //#region src/adapters/codex/index.d.ts
5
5
  /** Render a portable {@link Prompt} as a Codex hook response, `ask` → explicit deny. */
@@ -2,7 +2,7 @@ import { f as countLines } from "../../home-state-D0RLWP8J.mjs";
2
2
  import { t as evaluate } from "../../evaluate-PuyQPU36.mjs";
3
3
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
4
4
  import { t as parseApplyPatch } from "../../apply-patch-CIS2EZ_q.mjs";
5
- import { c as readClaudeInput, i as denyResponse, r as contextResponse } from "../../claude-k1SG-ROm.mjs";
5
+ import { _ as commandToString, c as readClaudeInput, i as denyResponse, r as contextResponse } from "../../claude-BJER7Mbj.mjs";
6
6
  //#region src/adapters/codex/index.ts
7
7
  /**
8
8
  * OpenAI Codex CLI adapter (hook-mode). Codex's `PreToolUse` hook (since 2026)
@@ -49,7 +49,7 @@ function resolvePrompt(input) {
49
49
  tool: input.tool_name ?? "Write",
50
50
  filePath: i?.file_path,
51
51
  content: i?.content ?? i?.new_string,
52
- command: i?.command
52
+ command: commandToString(i?.command)
53
53
  });
54
54
  return r.decision === "allow" || !r.prompt ? null : r.prompt;
55
55
  }
@@ -59,7 +59,7 @@ function resolvePrompt(input) {
59
59
  * into per-file checks; every other tool routes through the portable policy.
60
60
  */
61
61
  function guard(input) {
62
- const prompt = input.tool_name === "apply_patch" ? applyPatchPrompt(input.tool_input?.command ?? "") : resolvePrompt(input);
62
+ const prompt = input.tool_name === "apply_patch" ? applyPatchPrompt(commandToString(input.tool_input?.command) ?? "") : resolvePrompt(input);
63
63
  return prompt ? toCodexResponse(prompt) : null;
64
64
  }
65
65
  //#endregion
@@ -15,7 +15,7 @@ interface HermesHookInput {
15
15
  path?: string;
16
16
  file_path?: string;
17
17
  content?: string;
18
- command?: string;
18
+ command?: string | string[];
19
19
  };
20
20
  session_id?: string;
21
21
  cwd?: string;
@@ -1,2 +1,2 @@
1
- import { n as readHermesInput, r as toHermesResponse, t as guard } from "../../hermes-DQ0XFn7u.mjs";
1
+ import { n as readHermesInput, r as toHermesResponse, t as guard } from "../../hermes-DKPzVwI7.mjs";
2
2
  export { guard, readHermesInput, toHermesResponse };
@@ -3,6 +3,47 @@ import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
5
5
  import { spawnSync } from "node:child_process";
6
+ //#region src/runtime/command-string.ts
7
+ /** Shell basenames whose `-c`-style argv carries the real script in argv[2]. */
8
+ const SHELLS = /* @__PURE__ */ new Set([
9
+ "bash",
10
+ "sh",
11
+ "zsh",
12
+ "dash"
13
+ ]);
14
+ /** True when `arg` is (a path to) a POSIX shell we know wraps a `-c` script. */
15
+ function isShell(arg) {
16
+ if (arg === void 0) return false;
17
+ const base = arg.slice(arg.lastIndexOf("/") + 1);
18
+ return SHELLS.has(base);
19
+ }
20
+ /** True for a shell command flag (`-c`, `-lc`, `-ic`, …) — anything ending in `c`. */
21
+ function isCommandFlag(arg) {
22
+ return arg !== void 0 && /^-[a-z]*c$/.test(arg);
23
+ }
24
+ /**
25
+ * Coerce a hook payload's `command` field to the shell string the guard chain
26
+ * expects. Harnesses disagree on the wire shape: Claude Code, Cursor, and Hermes
27
+ * send a plain string, but Codex CLI sends an argv ARRAY
28
+ * (`["bash", "-lc", "git commit -m x"]`). A naive `typeof === "string"` check
29
+ * dropped the array to `undefined`, blinding every `ctx.command` guard
30
+ * (destructive-git, mutators, install…) into a silent fail-open. This restores
31
+ * the script so the array and string payloads reach an identical verdict.
32
+ *
33
+ * @param v - Raw `command` value off the payload (string, argv array, or other).
34
+ * @returns A string as-is; a `[shell, -c|-lc, script]` argv reduced to its
35
+ * script; any other all-string array joined with spaces; and `undefined` for
36
+ * empty arrays, arrays holding non-strings, or any other type.
37
+ */
38
+ function commandToString(v) {
39
+ if (typeof v === "string") return v;
40
+ if (!Array.isArray(v)) return void 0;
41
+ if (v.length === 0 || !v.every((e) => typeof e === "string")) return void 0;
42
+ const argv = v;
43
+ if (argv.length >= 3 && isShell(argv[0]) && isCommandFlag(argv[1])) return argv[2];
44
+ return argv.join(" ");
45
+ }
46
+ //#endregion
6
47
  //#region src/util/runtime-io.ts
7
48
  /**
8
49
  * Cross-runtime I/O helpers (Node + Bun). The published CLI ships a `node`
@@ -165,7 +206,7 @@ function guard(input) {
165
206
  tool: input.tool_name ?? "Write",
166
207
  filePath: input.tool_input?.file_path,
167
208
  content: input.tool_input?.content ?? input.tool_input?.new_string,
168
- command: input.tool_input?.command
209
+ command: commandToString(input.tool_input?.command)
169
210
  });
170
211
  if (result.decision === "allow" || !result.prompt) return null;
171
212
  return toClaudeResponse(input.hook_event_name ?? "PreToolUse", result.prompt);
@@ -173,4 +214,4 @@ function guard(input) {
173
214
  /** @deprecated use {@link guard}. Kept for back-compat. */
174
215
  const fileSizeGuard = guard;
175
216
  //#endregion
176
- export { fileSizeGuard as a, readClaudeInput as c, collectFiles as d, pathExists as f, writeText as g, spawnCapture as h, denyResponse as i, systemMessage as l, sleep as m, blockResponse as n, guard as o, readText as p, contextResponse as r, informResponse as s, attachSystemMessage as t, toClaudeResponse as u };
217
+ export { commandToString as _, fileSizeGuard as a, readClaudeInput as c, collectFiles as d, pathExists as f, writeText as g, spawnCapture as h, denyResponse as i, systemMessage as l, sleep as m, blockResponse as n, guard as o, readText as p, contextResponse as r, informResponse as s, attachSystemMessage as t, toClaudeResponse as u };
package/dist/cli/bin.mjs CHANGED
@@ -4,7 +4,7 @@ import { t as detectHarness } from "../harness-Cb9xR8dC.mjs";
4
4
  import { t as claudeHome } from "../home-state-D0RLWP8J.mjs";
5
5
  import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-CvqZrZUR.mjs";
6
6
  import { n as writeInitFile, t as initFor } from "../run-Do2JltgU.mjs";
7
- import { J as runningVersion, Lt as todayUtc, Y as versionBanner, q as runDoctor, t as handleHook } from "../handle-DveqiDmL.mjs";
7
+ import { J as runningVersion, Lt as todayUtc, Y as versionBanner, q as runDoctor, t as handleHook } from "../handle-DJovWDAy.mjs";
8
8
  import { delimiter, join } from "node:path";
9
9
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
10
10
  import { homedir } from "node:os";
@@ -14,8 +14,8 @@ import { d as loadIndex, i as cacheLookupMeta, n as webfetchCacheWrite, o as cac
14
14
  import { t as loadRefs } from "./loader-AGz4nK7d.mjs";
15
15
  import { a as writeLastNonce, c as recordAgent, d as recordRefRead, f as recordTarget, h as apexAuthorizationGate, i as verifyTrack, l as recordBrainstormRequired, m as trivialCount, n as saveTrack, o as agentsFresh, p as recordTrivialEdit, r as signTrack, s as emptyTrack, t as loadTrack, u as recordDoc } from "./store-CQ4roWrU.mjs";
16
16
  import { t as parseApplyPatch } from "./apply-patch-CIS2EZ_q.mjs";
17
- import { d as collectFiles, f as pathExists, g as writeText, h as spawnCapture, i as denyResponse, l as systemMessage, m as sleep, n as blockResponse, p as readText, r as contextResponse, s as informResponse, t as attachSystemMessage } from "./claude-k1SG-ROm.mjs";
18
- import { r as toHermesResponse } from "./hermes-DQ0XFn7u.mjs";
17
+ import { _ as commandToString, d as collectFiles, f as pathExists, g as writeText, h as spawnCapture, i as denyResponse, l as systemMessage, m as sleep, n as blockResponse, p as readText, r as contextResponse, s as informResponse, t as attachSystemMessage } from "./claude-BJER7Mbj.mjs";
18
+ import { r as toHermesResponse } from "./hermes-DKPzVwI7.mjs";
19
19
  import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
20
20
  import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
21
21
  import { homedir } from "node:os";
@@ -111,7 +111,7 @@ function normalizeEvent(id, payload) {
111
111
  ...base,
112
112
  filePath: str(input.file_path) ?? str(input.path) ?? str(payload.file_path),
113
113
  content: str(input.content) ?? str(input.new_string),
114
- command: str(input.command) ?? str(payload.command)
114
+ command: commandToString(input.command) ?? commandToString(payload.command)
115
115
  };
116
116
  }
117
117
  //#endregion
@@ -1,6 +1,6 @@
1
1
  import { t as evaluate } from "./evaluate-PuyQPU36.mjs";
2
2
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
3
- import { c as readClaudeInput } from "./claude-k1SG-ROm.mjs";
3
+ import { _ as commandToString, c as readClaudeInput } from "./claude-BJER7Mbj.mjs";
4
4
  //#region src/adapters/hermes/index.ts
5
5
  /**
6
6
  * Hermes Agent adapter (hook-mode). Nous Research's hermes-agent (2026) pipes a
@@ -45,7 +45,7 @@ function guard(input) {
45
45
  tool: input.tool_name ?? "write_file",
46
46
  filePath: t?.path ?? t?.file_path,
47
47
  content: t?.content,
48
- command: t?.command
48
+ command: commandToString(t?.command)
49
49
  });
50
50
  if (r.decision === "allow" || !r.prompt) return null;
51
51
  return toHermesResponse(r.prompt);
@@ -9,7 +9,7 @@ interface ClaudeHookInput {
9
9
  file_path?: string;
10
10
  content?: string;
11
11
  new_string?: string;
12
- command?: string;
12
+ command?: string | string[];
13
13
  };
14
14
  cwd?: string;
15
15
  }
@@ -1,6 +1,6 @@
1
1
  import { r as projectLayout } from "../layout-C0jaaCQC.mjs";
2
2
  import { a as sanitizeSessionId, c as sessionsDir, i as loadSessionState, n as fuseHarnessHome, o as saveSessionState, r as fusengineCache, s as sessionStatePath, t as claudeHome } from "../home-state-D0RLWP8J.mjs";
3
- import { $ as postEditTypescript, A as trackSkillRead, At as trackFile, B as isProject, C as seoPostToolUse, Ct as gitContext, D as postTrackingSideEffects, Dt as taskContext, E as securityAdvisory, Et as promptSubmitContext, F as dispatchLessons, Ft as securityStateDir, G as getFileDesc, H as loadEnriched, I as cartoSessionStart, It as securityStatePath, K as listChildren, L as generateEcosystemMap, Lt as todayUtc, M as dispatchLifecycle, Mt as isoUtc, N as aipilotPostToolUse, Nt as loadSecurityState, O as trackWatchResearch, Ot as defaultStateDir, P as dispatchAipilot, Pt as saveSecurityState, Q as lessonsStateFileFor, R as writePluginMap, S as postEditContext, St as devContext, T as dispatchMemory, Tt as claudeMdKey, U as mergeLines, V as writeTree, W as countFiles, X as lessonsArchiveFileFor, Z as lessonsFileFor, _ as preCommitGate, _t as sessionStartCore, a as recordActivity, at as validateTeammateOutput, b as extractSymbols, bt as removeOldFiles, c as MCP_TTL_MS, ct as validateTailwind, d as isMcpTool, dt as countLoc, et as trackSessionChanges, f as queryOf, ft as detectSolidProfile, g as gate, gt as runSessionStartCleanups, h as TRIVIAL_BUDGET, ht as readRules, i as respond, it as logToolFailure, j as trackEnrichment, jt as normalizeEvent, k as trackMcpResearch, kt as projectHash, l as WEBFETCH_TTL_MS, lt as validateSolidGate, m as REQUIRED_AGENTS, mt as injectRules, n as activityFor, nt as cleanupSession, o as mcpPostStore, ot as trackAgentMemory, p as DEFAULT_WINDOW_MS, pt as solidDetectStart, r as handlePre, rt as saveApexState, s as mcpPreIntercept, st as subagentCacheContext, t as handleHook, tt as validateRulesLoaded, u as cacheQueryOf, ut as checkFileSize, v as detectDuplication, vt as pruneEmptyDirs, w as seoPostToolUseResponse, wt as projectContext, x as lifecycleStdout, xt as trimLogFile, y as dryGate, yt as purgeTtlTree, z as generateProjectMap } from "../handle-DveqiDmL.mjs";
3
+ import { $ as postEditTypescript, A as trackSkillRead, At as trackFile, B as isProject, C as seoPostToolUse, Ct as gitContext, D as postTrackingSideEffects, Dt as taskContext, E as securityAdvisory, Et as promptSubmitContext, F as dispatchLessons, Ft as securityStateDir, G as getFileDesc, H as loadEnriched, I as cartoSessionStart, It as securityStatePath, K as listChildren, L as generateEcosystemMap, Lt as todayUtc, M as dispatchLifecycle, Mt as isoUtc, N as aipilotPostToolUse, Nt as loadSecurityState, O as trackWatchResearch, Ot as defaultStateDir, P as dispatchAipilot, Pt as saveSecurityState, Q as lessonsStateFileFor, R as writePluginMap, S as postEditContext, St as devContext, T as dispatchMemory, Tt as claudeMdKey, U as mergeLines, V as writeTree, W as countFiles, X as lessonsArchiveFileFor, Z as lessonsFileFor, _ as preCommitGate, _t as sessionStartCore, a as recordActivity, at as validateTeammateOutput, b as extractSymbols, bt as removeOldFiles, c as MCP_TTL_MS, ct as validateTailwind, d as isMcpTool, dt as countLoc, et as trackSessionChanges, f as queryOf, ft as detectSolidProfile, g as gate, gt as runSessionStartCleanups, h as TRIVIAL_BUDGET, ht as readRules, i as respond, it as logToolFailure, j as trackEnrichment, jt as normalizeEvent, k as trackMcpResearch, kt as projectHash, l as WEBFETCH_TTL_MS, lt as validateSolidGate, m as REQUIRED_AGENTS, mt as injectRules, n as activityFor, nt as cleanupSession, o as mcpPostStore, ot as trackAgentMemory, p as DEFAULT_WINDOW_MS, pt as solidDetectStart, r as handlePre, rt as saveApexState, s as mcpPreIntercept, st as subagentCacheContext, t as handleHook, tt as validateRulesLoaded, u as cacheQueryOf, ut as checkFileSize, v as detectDuplication, vt as pruneEmptyDirs, w as seoPostToolUseResponse, wt as projectContext, x as lifecycleStdout, xt as trimLogFile, y as dryGate, yt as purgeTtlTree, z as generateProjectMap } from "../handle-DJovWDAy.mjs";
4
4
  //#region src/runtime/storage.ts
5
5
  /**
6
6
  * The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusengine/harness",
3
- "version": "0.1.60",
3
+ "version": "0.1.61",
4
4
  "description": "Harness-agnostic toolkit for AI coding agents: runtime harness detection (Claude Code, Codex, Cursor, Cline, Gemini, Aider...), pure policy core (env config, project/framework detection, SOLID/file-size limits, APEX freshness, guard patterns, portable prompts), cache, project memory, ref routing, state/locks, statusline, per-harness adapters (Claude/Cursor/Cline/Gemini) and a cli-mode harness-check binary. Bun-native, with a built dist for Node + bundlers.",
5
5
  "type": "module",
6
6
  "module": "src/index.ts",