@fusengine/harness 0.1.66 → 0.1.68

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 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-Cu6rPxUZ.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-BmchLlp7.mjs";
2
2
  export { attachSystemMessage, blockResponse, contextResponse, denyResponse, fileSizeGuard, guard, informResponse, readClaudeInput, systemMessage, toClaudeResponse };
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "../../evaluate-CxgYAODk.mjs";
1
+ import { t as evaluate } from "../../evaluate-CRZ_Hq33.mjs";
2
2
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/cline/index.ts
4
4
  /**
@@ -1,8 +1,8 @@
1
1
  import { f as countLines } from "../../home-state-D0RLWP8J.mjs";
2
- import { t as evaluate } from "../../evaluate-CxgYAODk.mjs";
2
+ import { t as evaluate } from "../../evaluate-CRZ_Hq33.mjs";
3
3
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
4
4
  import { n as parseApplyPatch, t as isBypassPermissions } from "../../permission-mode-BN3MNgbm.mjs";
5
- import { c as readClaudeInput, i as denyResponse, r as contextResponse, s as informResponse, v as commandToString } from "../../claude-Cu6rPxUZ.mjs";
5
+ import { c as readClaudeInput, i as denyResponse, r as contextResponse, s as informResponse, v as commandToString } from "../../claude-BmchLlp7.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)
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "../../evaluate-CxgYAODk.mjs";
1
+ import { t as evaluate } from "../../evaluate-CRZ_Hq33.mjs";
2
2
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/cursor/index.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "../../evaluate-CxgYAODk.mjs";
1
+ import { t as evaluate } from "../../evaluate-CRZ_Hq33.mjs";
2
2
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/gemini/index.ts
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { n as readHermesInput, r as toHermesResponse, t as guard } from "../../hermes-BpD0nlyR.mjs";
1
+ import { n as readHermesInput, r as toHermesResponse, t as guard } from "../../hermes-dbvFJRuY.mjs";
2
2
  export { guard, readHermesInput, toHermesResponse };
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "./evaluate-CxgYAODk.mjs";
1
+ import { t as evaluate } from "./evaluate-CRZ_Hq33.mjs";
2
2
  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";
package/dist/cli/bin.mjs CHANGED
@@ -2,10 +2,10 @@
2
2
  import { r as loadDotenv, s as resolveTtlSec } from "../dotenv-Jj8aL1FL.mjs";
3
3
  import { t as detectHarness } from "../harness-Cb9xR8dC.mjs";
4
4
  import { t as claudeHome } from "../home-state-D0RLWP8J.mjs";
5
- import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-BfJytXnW.mjs";
5
+ import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-BJH3Wx_b.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-BBlvYhek.mjs";
8
- import { p as readStdin$1 } from "../claude-Cu6rPxUZ.mjs";
7
+ import { J as runningVersion, Lt as todayUtc, Y as versionBanner, q as runDoctor, t as handleHook } from "../handle-D8rvbAfw.mjs";
8
+ import { p as readStdin$1 } from "../claude-BmchLlp7.mjs";
9
9
  import { delimiter, join } from "node:path";
10
10
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
11
11
  import { homedir } from "node:os";
@@ -1,2 +1,2 @@
1
- import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-BfJytXnW.mjs";
1
+ import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-BJH3Wx_b.mjs";
2
2
  export { checkStaged, stagedContent, stagedFiles };
@@ -1,3 +1,4 @@
1
+ import { r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
1
2
  import { f as countLines, p as evaluateFileSize, r as fusengineCache, t as claudeHome } from "./home-state-D0RLWP8J.mjs";
2
3
  import { dirname, join, normalize } from "node:path";
3
4
  import { existsSync } from "node:fs";
@@ -146,6 +147,53 @@ function resolveSolidRefFramework(filePath) {
146
147
  return "generic";
147
148
  }
148
149
  //#endregion
150
+ //#region src/policy/edit-outcome.ts
151
+ /**
152
+ * Count non-overlapping literal occurrences of `needle` in `haystack`. An
153
+ * empty `needle` returns 0 — treated as "not found" by callers, since Edit's
154
+ * `old_string` is never legitimately empty and an empty needle has no
155
+ * well-defined occurrence count.
156
+ * @param haystack - The on-disk file content to search.
157
+ * @param needle - The literal substring to count.
158
+ */
159
+ function countOccurrences(haystack, needle) {
160
+ if (needle === "") return 0;
161
+ let count = 0;
162
+ let from = 0;
163
+ for (;;) {
164
+ const at = haystack.indexOf(needle, from);
165
+ if (at === -1) break;
166
+ count++;
167
+ from = at + needle.length;
168
+ }
169
+ return count;
170
+ }
171
+ /**
172
+ * Compute the line count an Edit would PRODUCE, before it lands on disk —
173
+ * `existingLines − countLines(old_string) + countLines(new_string)`, scaled
174
+ * by how many `old_string` occurrences are actually replaced (1 normally, or
175
+ * every occurrence under `replace_all`). Pure arithmetic on the literal
176
+ * strings — no regex/fuzzy matching, matching the real Edit tool's own
177
+ * exact-substring semantics.
178
+ *
179
+ * Returns `null` (fail-closed — caller must fall back to judging the stale
180
+ * on-disk count alone) when `old_string` is missing/empty, or does not occur
181
+ * in `existingContent` at all: an Edit whose `old_string` doesn't match the
182
+ * real file is stale or adversarial, never a case to special-case an allow for.
183
+ * @param existingContent - Full on-disk content of the file being edited.
184
+ * @param oldString - The Edit's `old_string` (tool_input, unmodified).
185
+ * @param newString - The Edit's `new_string` (tool_input, unmodified).
186
+ * @param replaceAll - The Edit's `replace_all` flag.
187
+ */
188
+ function computeEditResultLines(existingContent, oldString, newString, replaceAll) {
189
+ if (!oldString) return null;
190
+ const occurrences = countOccurrences(existingContent, oldString);
191
+ if (occurrences === 0) return null;
192
+ const times = replaceAll ? occurrences : 1;
193
+ const delta = countLines(newString) - countLines(oldString);
194
+ return countLines(existingContent) + delta * times;
195
+ }
196
+ //#endregion
149
197
  //#region src/policy/guards/security.ts
150
198
  /** Critical patterns that must always be blocked — parity `security_rules.py`'s cumulated violation names. */
151
199
  const CRITICAL_PATTERNS = [
@@ -870,10 +918,17 @@ function evaluate(ctx) {
870
918
  };
871
919
  if (ctx.filePath && isFileSizeScoped(ctx.filePath) && ctx.agentType !== "Explore" && ctx.agentType !== "Plan") {
872
920
  const incoming = ctx.content !== void 0 ? countLines(ctx.content) : 0;
873
- const lines = ctx.tool === "Edit" ? Math.max(incoming, ctx.existingLines ?? 0) : incoming || (ctx.existingLines ?? 0);
921
+ const existing = ctx.existingLines ?? 0;
922
+ const max = ctx.maxLines ?? resolveMaxLines();
923
+ const editResult = ctx.tool === "Edit" && ctx.existingContent !== void 0 && ctx.content !== void 0 ? computeEditResultLines(ctx.existingContent, ctx.oldString, ctx.content, ctx.isReplaceAll === true) : null;
924
+ if (editResult !== null && (editResult <= max || editResult < existing)) return {
925
+ decision: "allow",
926
+ message: null
927
+ };
928
+ const lines = ctx.tool === "Edit" ? editResult ?? Math.max(incoming, existing) : incoming || existing;
874
929
  const framework = resolveSolidRefFramework(ctx.filePath);
875
930
  const displayLines = ctx.tool === "Write" ? ctx.existingLines ?? lines : lines;
876
- const verdict = evaluateFileSize(lines, ctx.maxLines, ctx.filePath, framework, displayLines);
931
+ const verdict = evaluateFileSize(lines, max, ctx.filePath, framework, displayLines);
877
932
  if (lines > 0 && !verdict.ok) return {
878
933
  decision: "deny",
879
934
  message: verdict.message,
@@ -4,7 +4,7 @@ import { r as projectLayout } from "./layout-C0jaaCQC.mjs";
4
4
  import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
5
5
  import { A as detectCreationIntent, E as isExcludedSwiftPath, F as docConsultedGate, H as detectProjectType$1, I as evaluateApex, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, S as usesTailwindUtilities, T as isExcludedJsPath, V as detectModularArchitecture, W as requiredArchSkill, _ as scanPlugin, c as EXCLUDE_DIRS$1, d as buildApexTaskInjection, h as buildClaudeMdContext, k as capVerbosity, l as PROJECT_INDICATORS, n as missingSeoElements, o as parseEnrichment, r as descFromText, s as parseEntry, t as isHtmlLike, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "./validate-DnOqIZD_.mjs";
6
6
  import { a as sanitizeSessionId, c as sessionsDir, d as countFrameworkCodeLines, f as countLines, i as loadSessionState, l as PLUGINS_DIR, n as fuseHarnessHome, o as saveSessionState, r as fusengineCache, t as claudeHome } from "./home-state-D0RLWP8J.mjs";
7
- import { n as FAIL_CLOSED, t as evaluate } from "./evaluate-CxgYAODk.mjs";
7
+ import { n as FAIL_CLOSED, t as evaluate } from "./evaluate-CRZ_Hq33.mjs";
8
8
  import { a as writeJsonFile, i as readJsonFile, r as hashText, t as atomicWrite } from "./json-io-DisYd2fb.mjs";
9
9
  import { r as isDocConsulted } from "./doc-helpers-CWZegVdR.mjs";
10
10
  import { n as findMarketplacePlugins, r as readPluginMeta, t as resolveSkillPath } from "./skill-path-DhItkBzk.mjs";
@@ -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 { n as parseApplyPatch, t as isBypassPermissions } from "./permission-mode-BN3MNgbm.mjs";
17
- import { _ as writeText, d as collectFiles, f as pathExists, g as spawnCapture, h as sleep, i as denyResponse, l as systemMessage, m as readText, n as blockResponse, r as contextResponse, s as informResponse, t as attachSystemMessage, v as commandToString } from "./claude-Cu6rPxUZ.mjs";
18
- import { r as toHermesResponse } from "./hermes-BpD0nlyR.mjs";
17
+ import { _ as writeText, d as collectFiles, f as pathExists, g as spawnCapture, h as sleep, i as denyResponse, l as systemMessage, m as readText, n as blockResponse, r as contextResponse, s as informResponse, t as attachSystemMessage, v as commandToString } from "./claude-BmchLlp7.mjs";
18
+ import { r as toHermesResponse } from "./hermes-dbvFJRuY.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";
@@ -113,6 +113,7 @@ function normalizeEvent(id, payload) {
113
113
  ...base,
114
114
  filePath: str(input.file_path) ?? str(input.path) ?? str(payload.file_path),
115
115
  content: str(input.content) ?? str(input.new_string),
116
+ oldString: str(input.old_string),
116
117
  command: commandToString(input.command) ?? commandToString(payload.command)
117
118
  };
118
119
  }
@@ -5864,7 +5865,8 @@ function existingLineCounts(path) {
5864
5865
  const content = readFileSync(path, "utf8");
5865
5866
  return {
5866
5867
  raw: countLines(content),
5867
- code: countFrameworkCodeLines(content)
5868
+ code: countFrameworkCodeLines(content),
5869
+ content
5868
5870
  };
5869
5871
  } catch {
5870
5872
  return {};
@@ -6805,7 +6807,7 @@ async function runGates(input) {
6805
6807
  if (precommit) return precommit;
6806
6808
  const protectedDeny = protectedPathGate(input.tool, input.filePath);
6807
6809
  if (protectedDeny) return protectedDeny;
6808
- const { raw: existingLines, code: existingCodeLines } = existingLineCounts(input.filePath);
6810
+ const { raw: existingLines, code: existingCodeLines, content: existingContent } = existingLineCounts(input.filePath);
6809
6811
  let quick;
6810
6812
  try {
6811
6813
  quick = evaluate({
@@ -6815,6 +6817,9 @@ async function runGates(input) {
6815
6817
  command: input.command,
6816
6818
  agentType: input.agentType,
6817
6819
  existingLines,
6820
+ existingContent,
6821
+ oldString: input.oldString,
6822
+ isReplaceAll: input.isReplaceAll,
6818
6823
  neverApproval: input.neverApproval
6819
6824
  });
6820
6825
  } catch {
@@ -7704,6 +7709,7 @@ async function handlePre(ctx) {
7704
7709
  cwd: opts.cwd,
7705
7710
  refs: opts.refsDir ? await loadRefs(opts.refsDir) : void 0,
7706
7711
  isReplaceAll: event.input.replace_all === true,
7712
+ oldString: event.oldString,
7707
7713
  agentType: event.agentType,
7708
7714
  agentId: typeof payload.agent_id === "string" ? payload.agent_id : void 0,
7709
7715
  windowMs: opts.windowMs,
@@ -7885,6 +7891,92 @@ function activityFor(event) {
7885
7891
  return out;
7886
7892
  }
7887
7893
  //#endregion
7894
+ //#region src/freshness/codex-spawn-evidence.ts
7895
+ /**
7896
+ * Codex multi_agent_v2 `spawn_agent` -> session evidence bridge. Codex's custom
7897
+ * agents (fusengine multi_agent_v2, e.g. sniper/explore-codebase) are launched
7898
+ * via a `spawn_agent` TOOL CALL inside the SAME session -- Codex has no
7899
+ * SubagentStart/SubagentStop lifecycle for them, so the existing Claude-side
7900
+ * evidence paths (agent-evidence-record.ts `classifyAgentEvidence`, the
7901
+ * SubagentStop harvest) never observe them; the harness only ever saw a
7902
+ * generic tool call. This module credits the SAME session track
7903
+ * ({@link recordAgent}, read back by `agent-evidence-record.ts`
7904
+ * `agentsFreshInTrack`) straight from that PostToolUse `spawn_agent` call.
7905
+ *
7906
+ * SOURCE (openai/codex@44918ea1, tag rust-v0.144.1 -- verified upstream,
7907
+ * not re-checked here): the hook `tool_name` is `"spawn_agent"` normally, or
7908
+ * the SEPARATOR-LESS namespace-prefixed `{namespace}spawn_agent` when the
7909
+ * `namespace_tools` capability provider is active (e.g.
7910
+ * `"fusengine_agentsspawn_agent"`, `"collaborationspawn_agent"`). Detection is
7911
+ * `tool_name === "spawn_agent" || tool_name.endsWith("spawn_agent")` -- a tool
7912
+ * that merely CONTAINS the substring without being an exact/suffix match
7913
+ * (`"spawn_agentX"`, `"myspawn_agent_tool"`) is correctly rejected.
7914
+ * `tool_input.agent_type` carries the spawned agent's type only when Codex's
7915
+ * `hide_spawn_agent_metadata=false`; treat it as always-optional.
7916
+ *
7917
+ * INVARIANT (multi-harness parity): every entry point here is gated on
7918
+ * `id === "codex"` FIRST -- claude-code/cursor/cline/gemini-cli/hermes always
7919
+ * take the early return, touching neither the track nor disk. Byte-identical
7920
+ * elsewhere by construction.
7921
+ */
7922
+ /**
7923
+ * True when `tool` is Codex's `spawn_agent` primitive, bare or
7924
+ * namespace-prefixed (no separator). Rejects any tool that merely contains
7925
+ * the substring elsewhere in its name.
7926
+ * @param tool - Raw/normalized `tool_name` from the hook payload.
7927
+ */
7928
+ function isCodexSpawnAgentTool(tool) {
7929
+ return tool === "spawn_agent" || tool.endsWith("spawn_agent");
7930
+ }
7931
+ /**
7932
+ * Extract the spawned agent's type from a `spawn_agent` `tool_input`, or
7933
+ * `undefined` when absent/blank (`hide_spawn_agent_metadata=true`, or a
7934
+ * future Codex build omitting it) -- never throws.
7935
+ * @param input - Raw `tool_input` payload (harness `event.input`).
7936
+ */
7937
+ function codexSpawnAgentType(input) {
7938
+ const v = input?.agent_type;
7939
+ return typeof v === "string" && v.trim() !== "" ? v.trim() : void 0;
7940
+ }
7941
+ /**
7942
+ * Pure classifier + folder: credit a Codex `spawn_agent` call into
7943
+ * `track.agents` under the SAME `subagent-<name>` convention the Claude-side
7944
+ * explore/research evidence uses -- so an `agent_type` that happens to match
7945
+ * a `REQUIRED_AGENTS` name (e.g. `"explore-codebase"`) is picked up by
7946
+ * `agentsFreshInTrack`'s substring match exactly like genuine Claude
7947
+ * Task/Agent evidence. Immutable: returns `track` UNCHANGED (same reference)
7948
+ * for any other harness `id`, any non-spawn tool, or a missing `agent_type`.
7949
+ * @param id - Harness id (only `"codex"` ever credits).
7950
+ * @param tool - Normalized event tool name (raw `tool_name`).
7951
+ * @param input - Raw `tool_input` payload.
7952
+ * @param track - The current session track.
7953
+ * @param ts - Epoch-ms timestamp of the tool call.
7954
+ * @returns The credited track, or `track` itself when nothing was credited.
7955
+ */
7956
+ function creditCodexSpawnAgent(id, tool, input, track, ts) {
7957
+ if (id !== "codex" || !isCodexSpawnAgentTool(tool)) return track;
7958
+ const agentType = codexSpawnAgentType(input);
7959
+ if (!agentType) return track;
7960
+ return recordAgent(track, `subagent-${agentType}`, ts, "sufficient");
7961
+ }
7962
+ /**
7963
+ * I/O wiring for {@link creditCodexSpawnAgent}: load the session track, fold
7964
+ * in the credit, and persist only when something actually changed (skips a
7965
+ * write for the strict no-op cases). Mirrors `agent-evidence-record.ts`
7966
+ * `recordAgentEvidence`'s async load/save shape.
7967
+ * @param file - Session track file path (same one the freshness gate reads).
7968
+ * @param id - Harness id (only `"codex"` ever credits).
7969
+ * @param tool - Normalized event tool name (raw `tool_name`).
7970
+ * @param input - Raw `tool_input` payload.
7971
+ * @param ts - Epoch-ms timestamp of the tool call.
7972
+ */
7973
+ async function recordCodexSpawnEvidence(file, id, tool, input, ts) {
7974
+ if (id !== "codex" || !isCodexSpawnAgentTool(tool)) return;
7975
+ const track = await loadTrack(file);
7976
+ const next = creditCodexSpawnAgent(id, tool, input, track, ts);
7977
+ if (next !== track) await saveTrack(file, next);
7978
+ }
7979
+ //#endregion
7888
7980
  //#region src/runtime/handle-post.ts
7889
7981
  /**
7890
7982
  * Run the PostToolUse pipeline: store the MCP response, emit a design warning,
@@ -7909,6 +8001,7 @@ async function handlePost(ctx) {
7909
8001
  for (const activity of activities) await recordActivity(file, activity);
7910
8002
  const evidence = classifyAgentEvidence(event.tool, event.input, response);
7911
8003
  if (evidence) await recordAgentEvidence(file, evidence, opts.now, typeof payload.agent_id === "string" ? payload.agent_id : void 0);
8004
+ await recordCodexSpawnEvidence(file, id, event.tool, event.input, opts.now);
7912
8005
  if (event.tool === "Bash" && event.command) {
7913
8006
  const r = payload.tool_result ?? response;
7914
8007
  const out = `${typeof r?.stdout === "string" ? r.stdout : ""}\n${typeof r?.stderr === "string" ? r.stderr : ""}`;
@@ -1,6 +1,6 @@
1
- import { t as evaluate } from "./evaluate-CxgYAODk.mjs";
1
+ import { t as evaluate } from "./evaluate-CRZ_Hq33.mjs";
2
2
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
3
- import { c as readClaudeInput, v as commandToString } from "./claude-Cu6rPxUZ.mjs";
3
+ import { c as readClaudeInput, v as commandToString } from "./claude-BmchLlp7.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
@@ -131,6 +131,12 @@ interface PolicyContext {
131
131
  agentType?: string;
132
132
  /** Line count of the existing on-disk file (so an Edit on an oversized file blocks). */
133
133
  existingLines?: number;
134
+ /** Edit only: full on-disk content, read once by the runtime (runtime/gate-helpers.ts::existingLineCounts) — lets evaluate() compute the exact post-edit line count instead of judging the stale pre-edit count alone. Undefined when unreadable/missing (fail-closed to the existingLines-only behavior). */
135
+ existingContent?: string;
136
+ /** Edit only: the tool_input.old_string being replaced (runtime/normalize.ts). Undefined for Write (no such field) — fail-closed. */
137
+ oldString?: string;
138
+ /** Edit only: the tool_input.replace_all flag — every occurrence of old_string is replaced, not just the first. */
139
+ isReplaceAll?: boolean;
134
140
  /** Codex-only, populated by handle-pre.ts from the resolved `permission_mode` of an `approval_policy=never` session (adapters/codex/permission-mode.ts) — auto-approve gate, wired through evaluate.ts's anti-chaining check. */
135
141
  neverApproval?: boolean;
136
142
  }
package/dist/index.d.mts CHANGED
@@ -5,7 +5,7 @@ import { a as HarnessInfo, i as HarnessId, n as detectMode, o as HarnessMode, r
5
5
  import { a as isDocConsulted, i as formatDocSatisfactionStatus, n as DocSatisfactionStatus, o as resolveSessions, r as formatDocDeny, t as AuthEntry } from "./doc-helpers-CEKzGg2u.mjs";
6
6
  import { t as incrementTrivialEditCounter } from "./index-BOBXQ91y.mjs";
7
7
  import { a as compactJson, i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./index-BEMumjOw.mjs";
8
- import { $ as ASK_PATTERNS, A as FAIL_CLOSED, B as SWIFT_PROTO_RE, C as usesTailwindUtilities, Ct as ModularArchitecture, D as MAX_TOKENS, Dt as isApexCommand, E as MAX_EXA_RESULTS, Et as detectProjectType, F as installGuard, G as CODE_MUTATORS, H as interfaceSeparationGuard, I as GO_DECL_RE, J as SAFE_PREFIXES, K as CODE_REDIRECT, L as JAVA_DECL_RE, M as clearUserGuards, N as registerGuard, O as capVerbosity, Ot as requiredArchSkill, P as runGuards, Q as protectedPathGuard, R as PHP_DECL_RE, S as skillTriggerGate, St as DEV_KEYWORDS, T as frameworkSolidGate, Tt as detectModularArchitecture, U as bashWriteGuard, V as TS_DECL_RE, W as ASK_WRITERS, X as PROTECTED_FRAGMENTS, Y as SESSION_STATE_FRAGMENT, Z as PROTECTED_GIT_RE, _ as DEV_VERBS, _t as SOLID_REF, a as firstHeading, at as evaluate, b as detectClaudeMdProjectType, bt as evaluateFileSize, c as parseEntry, ct as GIT_ASK, d as EXCLUDE_DIRS, dt as RALPH_SAFE, et as CRITICAL_PATTERNS, f as PROJECT_INDICATORS, ft as SYSTEM_INSTALL, g as loadApexTaskState, gt as PLUGINS_DIR, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as GuardContext, j as GUARDS, k as detectCreationIntent, l as parseBodyDesc, lt as GIT_BLOCKED, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as securityGuard, o as TreeEntry, ot as PolicyContext, p as ApexTaskState, pt as isRalphMode, q as FILE_REDIRECT, r as descFromText, rt as Guard, s as parseEnrichment, st as PolicyResult, t as isHtmlLike, tt as LabeledPattern, u as parseField, ut as PROJECT_INSTALL, v as buildApexInstruction, vt as countFrameworkCodeLines, w as SKILL_TRIGGERS, wt as ProjectType, x as detectRequiredSkills, xt as detectFramework, y as buildClaudeMdContext, yt as countLines, z as PY_MODEL_RE } from "./index-CU3oHxOe.mjs";
8
+ import { $ as ASK_PATTERNS, A as FAIL_CLOSED, B as SWIFT_PROTO_RE, C as usesTailwindUtilities, Ct as ModularArchitecture, D as MAX_TOKENS, Dt as isApexCommand, E as MAX_EXA_RESULTS, Et as detectProjectType, F as installGuard, G as CODE_MUTATORS, H as interfaceSeparationGuard, I as GO_DECL_RE, J as SAFE_PREFIXES, K as CODE_REDIRECT, L as JAVA_DECL_RE, M as clearUserGuards, N as registerGuard, O as capVerbosity, Ot as requiredArchSkill, P as runGuards, Q as protectedPathGuard, R as PHP_DECL_RE, S as skillTriggerGate, St as DEV_KEYWORDS, T as frameworkSolidGate, Tt as detectModularArchitecture, U as bashWriteGuard, V as TS_DECL_RE, W as ASK_WRITERS, X as PROTECTED_FRAGMENTS, Y as SESSION_STATE_FRAGMENT, Z as PROTECTED_GIT_RE, _ as DEV_VERBS, _t as SOLID_REF, a as firstHeading, at as evaluate, b as detectClaudeMdProjectType, bt as evaluateFileSize, c as parseEntry, ct as GIT_ASK, d as EXCLUDE_DIRS, dt as RALPH_SAFE, et as CRITICAL_PATTERNS, f as PROJECT_INDICATORS, ft as SYSTEM_INSTALL, g as loadApexTaskState, gt as PLUGINS_DIR, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as GuardContext, j as GUARDS, k as detectCreationIntent, l as parseBodyDesc, lt as GIT_BLOCKED, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as securityGuard, o as TreeEntry, ot as PolicyContext, p as ApexTaskState, pt as isRalphMode, q as FILE_REDIRECT, r as descFromText, rt as Guard, s as parseEnrichment, st as PolicyResult, t as isHtmlLike, tt as LabeledPattern, u as parseField, ut as PROJECT_INSTALL, v as buildApexInstruction, vt as countFrameworkCodeLines, w as SKILL_TRIGGERS, wt as ProjectType, x as detectRequiredSkills, xt as detectFramework, y as buildClaudeMdContext, yt as countLines, z as PY_MODEL_RE } from "./index-DzOJraAT.mjs";
9
9
  import { n as RouteResult, r as ScoredRef, t as RefMeta } from "./types-CY5qT2X1.mjs";
10
10
  import { a as PRE_AUTH_GATES, c as evaluateApex, i as POST_AUTH_GATES, l as freshnessGate, n as ApexContext, o as brainstormGate, r as ApexGate, s as docConsultedGate, t as APEX_GATES, u as solidReadGate } from "./apex-Wdi1nq_w.mjs";
11
11
  import { a as ReminderState, c as readState, d as throttleMs, i as registryFile, l as setStateField, n as addRoot, o as lessonsFileFor, r as readRoots, s as nowStamp, t as ensureMemoryGitignore, u as stateFileFor } from "./index-DLYhervv.mjs";
package/dist/index.mjs CHANGED
@@ -6,7 +6,7 @@ import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFi
6
6
  import { n as detectMode, r as modeFor, t as detectHarness } from "./harness-Cb9xR8dC.mjs";
7
7
  import { A as detectCreationIntent, B as DEV_KEYWORDS, C as SKILL_TRIGGERS, D as MAX_EXA_RESULTS, F as docConsultedGate, H as detectProjectType, I as evaluateApex, L as freshnessGate, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, O as MAX_TOKENS, P as brainstormGate, R as solidReadGate, S as usesTailwindUtilities, U as isApexCommand, V as detectModularArchitecture, W as requiredArchSkill, a as firstHeading, b as detectRequiredSkills, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as APEX_GATES, k as capVerbosity, l as PROJECT_INDICATORS, m as buildApexInstruction, n as missingSeoElements, o as parseEnrichment, p as DEV_VERBS, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, v as parseBodyDesc, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "./validate-DnOqIZD_.mjs";
8
8
  import { d as countFrameworkCodeLines, f as countLines, l as PLUGINS_DIR, p as evaluateFileSize, u as SOLID_REF } from "./home-state-D0RLWP8J.mjs";
9
- import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, S as PROTECTED_FRAGMENTS, T as ASK_PATTERNS, _ as CODE_MUTATORS, a as registerGuard, b as SAFE_PREFIXES, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as ASK_WRITERS, h as bashWriteGuard, i as clearUserGuards, j as RALPH_SAFE, k as GIT_BLOCKED, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as CODE_REDIRECT, w as protectedPathGuard, x as SESSION_STATE_FRAGMENT, y as FILE_REDIRECT } from "./evaluate-CxgYAODk.mjs";
9
+ import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, S as PROTECTED_FRAGMENTS, T as ASK_PATTERNS, _ as CODE_MUTATORS, a as registerGuard, b as SAFE_PREFIXES, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as ASK_WRITERS, h as bashWriteGuard, i as clearUserGuards, j as RALPH_SAFE, k as GIT_BLOCKED, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as CODE_REDIRECT, w as protectedPathGuard, x as SESSION_STATE_FRAGMENT, y as FILE_REDIRECT } from "./evaluate-CRZ_Hq33.mjs";
10
10
  import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-CWZegVdR.mjs";
11
11
  import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-PKVNBHge.mjs";
12
12
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
@@ -1,3 +1,3 @@
1
- import { $ as ASK_PATTERNS, A as FAIL_CLOSED, B as SWIFT_PROTO_RE, C as usesTailwindUtilities, Ct as ModularArchitecture, D as MAX_TOKENS, Dt as isApexCommand, E as MAX_EXA_RESULTS, Et as detectProjectType, F as installGuard, G as CODE_MUTATORS, H as interfaceSeparationGuard, I as GO_DECL_RE, J as SAFE_PREFIXES, K as CODE_REDIRECT, L as JAVA_DECL_RE, M as clearUserGuards, N as registerGuard, O as capVerbosity, Ot as requiredArchSkill, P as runGuards, Q as protectedPathGuard, R as PHP_DECL_RE, S as skillTriggerGate, St as DEV_KEYWORDS, T as frameworkSolidGate, Tt as detectModularArchitecture, U as bashWriteGuard, V as TS_DECL_RE, W as ASK_WRITERS, X as PROTECTED_FRAGMENTS, Y as SESSION_STATE_FRAGMENT, Z as PROTECTED_GIT_RE, _ as DEV_VERBS, _t as SOLID_REF, a as firstHeading, at as evaluate, b as detectClaudeMdProjectType, bt as evaluateFileSize, c as parseEntry, ct as GIT_ASK, d as EXCLUDE_DIRS, dt as RALPH_SAFE, et as CRITICAL_PATTERNS, f as PROJECT_INDICATORS, ft as SYSTEM_INSTALL, g as loadApexTaskState, gt as PLUGINS_DIR, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as GuardContext, j as GUARDS, k as detectCreationIntent, l as parseBodyDesc, lt as GIT_BLOCKED, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as securityGuard, o as TreeEntry, ot as PolicyContext, p as ApexTaskState, pt as isRalphMode, q as FILE_REDIRECT, r as descFromText, rt as Guard, s as parseEnrichment, st as PolicyResult, t as isHtmlLike, tt as LabeledPattern, u as parseField, ut as PROJECT_INSTALL, v as buildApexInstruction, vt as countFrameworkCodeLines, w as SKILL_TRIGGERS, wt as ProjectType, x as detectRequiredSkills, xt as detectFramework, y as buildClaudeMdContext, yt as countLines, z as PY_MODEL_RE } from "../index-CU3oHxOe.mjs";
1
+ import { $ as ASK_PATTERNS, A as FAIL_CLOSED, B as SWIFT_PROTO_RE, C as usesTailwindUtilities, Ct as ModularArchitecture, D as MAX_TOKENS, Dt as isApexCommand, E as MAX_EXA_RESULTS, Et as detectProjectType, F as installGuard, G as CODE_MUTATORS, H as interfaceSeparationGuard, I as GO_DECL_RE, J as SAFE_PREFIXES, K as CODE_REDIRECT, L as JAVA_DECL_RE, M as clearUserGuards, N as registerGuard, O as capVerbosity, Ot as requiredArchSkill, P as runGuards, Q as protectedPathGuard, R as PHP_DECL_RE, S as skillTriggerGate, St as DEV_KEYWORDS, T as frameworkSolidGate, Tt as detectModularArchitecture, U as bashWriteGuard, V as TS_DECL_RE, W as ASK_WRITERS, X as PROTECTED_FRAGMENTS, Y as SESSION_STATE_FRAGMENT, Z as PROTECTED_GIT_RE, _ as DEV_VERBS, _t as SOLID_REF, a as firstHeading, at as evaluate, b as detectClaudeMdProjectType, bt as evaluateFileSize, c as parseEntry, ct as GIT_ASK, d as EXCLUDE_DIRS, dt as RALPH_SAFE, et as CRITICAL_PATTERNS, f as PROJECT_INDICATORS, ft as SYSTEM_INSTALL, g as loadApexTaskState, gt as PLUGINS_DIR, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as GuardContext, j as GUARDS, k as detectCreationIntent, l as parseBodyDesc, lt as GIT_BLOCKED, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as securityGuard, o as TreeEntry, ot as PolicyContext, p as ApexTaskState, pt as isRalphMode, q as FILE_REDIRECT, r as descFromText, rt as Guard, s as parseEnrichment, st as PolicyResult, t as isHtmlLike, tt as LabeledPattern, u as parseField, ut as PROJECT_INSTALL, v as buildApexInstruction, vt as countFrameworkCodeLines, w as SKILL_TRIGGERS, wt as ProjectType, x as detectRequiredSkills, xt as detectFramework, y as buildClaudeMdContext, yt as countLines, z as PY_MODEL_RE } from "../index-DzOJraAT.mjs";
2
2
  import { a as PRE_AUTH_GATES, c as evaluateApex, i as POST_AUTH_GATES, l as freshnessGate, n as ApexContext, o as brainstormGate, r as ApexGate, s as docConsultedGate, t as APEX_GATES, u as solidReadGate } from "../apex-Wdi1nq_w.mjs";
3
3
  export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, ApexContext, ApexGate, ApexTaskState, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, FILE_REDIRECT, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, Guard, GuardContext, JAVA_DECL_RE, LabeledPattern, MAX_EXA_RESULTS, MAX_TOKENS, ModularArchitecture, PHP_DECL_RE, PLUGINS_DIR, POST_AUTH_GATES, PRE_AUTH_GATES, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PROTECTED_GIT_RE, PY_MODEL_RE, type PolicyContext, type PolicyResult, ProjectType, RALPH_SAFE, SAFE_PREFIXES, SESSION_STATE_FRAGMENT, SKILL_TRIGGERS, SOLID_REF, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, TreeEntry, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countFrameworkCodeLines, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, isHtmlLike, isRalphMode, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate, usesTailwindUtilities };
@@ -1,5 +1,5 @@
1
1
  import { A as detectCreationIntent, B as DEV_KEYWORDS, C as SKILL_TRIGGERS, D as MAX_EXA_RESULTS, F as docConsultedGate, H as detectProjectType, I as evaluateApex, L as freshnessGate, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, O as MAX_TOKENS, P as brainstormGate, R as solidReadGate, S as usesTailwindUtilities, U as isApexCommand, V as detectModularArchitecture, W as requiredArchSkill, a as firstHeading, b as detectRequiredSkills, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as APEX_GATES, k as capVerbosity, l as PROJECT_INDICATORS, m as buildApexInstruction, n as missingSeoElements, o as parseEnrichment, p as DEV_VERBS, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, v as parseBodyDesc, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "../validate-DnOqIZD_.mjs";
2
2
  import { d as countFrameworkCodeLines, f as countLines, l as PLUGINS_DIR, p as evaluateFileSize, u as SOLID_REF } from "../home-state-D0RLWP8J.mjs";
3
- import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, S as PROTECTED_FRAGMENTS, T as ASK_PATTERNS, _ as CODE_MUTATORS, a as registerGuard, b as SAFE_PREFIXES, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as ASK_WRITERS, h as bashWriteGuard, i as clearUserGuards, j as RALPH_SAFE, k as GIT_BLOCKED, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as CODE_REDIRECT, w as protectedPathGuard, x as SESSION_STATE_FRAGMENT, y as FILE_REDIRECT } from "../evaluate-CxgYAODk.mjs";
3
+ import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, S as PROTECTED_FRAGMENTS, T as ASK_PATTERNS, _ as CODE_MUTATORS, a as registerGuard, b as SAFE_PREFIXES, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as ASK_WRITERS, h as bashWriteGuard, i as clearUserGuards, j as RALPH_SAFE, k as GIT_BLOCKED, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as CODE_REDIRECT, w as protectedPathGuard, x as SESSION_STATE_FRAGMENT, y as FILE_REDIRECT } from "../evaluate-CRZ_Hq33.mjs";
4
4
  import "../policy-la_KkjCS.mjs";
5
5
  export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, FILE_REDIRECT, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_TOKENS, PHP_DECL_RE, PLUGINS_DIR, POST_AUTH_GATES, PRE_AUTH_GATES, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PROTECTED_GIT_RE, PY_MODEL_RE, RALPH_SAFE, SAFE_PREFIXES, SESSION_STATE_FRAGMENT, SKILL_TRIGGERS, SOLID_REF, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countFrameworkCodeLines, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, isHtmlLike, isRalphMode, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate, usesTailwindUtilities };
@@ -1,5 +1,5 @@
1
1
  import { t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
2
- import { t as evaluate } from "./evaluate-CxgYAODk.mjs";
2
+ import { t as evaluate } from "./evaluate-CRZ_Hq33.mjs";
3
3
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
4
4
  import { execSync } from "node:child_process";
5
5
  //#region src/cli/run.ts
@@ -97,6 +97,8 @@ interface GateInput {
97
97
  trackFile: string;
98
98
  windowMs?: number;
99
99
  isReplaceAll?: boolean;
100
+ /** Edit only: the tool_input.old_string being replaced (runtime/normalize.ts) — threaded to evaluate()'s file-size gate so it can compute the post-edit outcome (policy/edit-outcome.ts) instead of judging the stale on-disk count alone. */
101
+ oldString?: string;
100
102
  agentType?: string;
101
103
  /** Claude `agent_id` when the tool-use comes from a subagent (parity require-apex-agents.py:41 — subagents inherit the lead's brainstorm decision). */
102
104
  agentId?: string;
@@ -166,6 +168,8 @@ interface NormalizedEvent {
166
168
  sessionId: string;
167
169
  filePath?: string;
168
170
  content?: string;
171
+ /** Edit only: the tool_input.old_string being replaced — lets the file-size gate (policy/evaluate.ts + policy/edit-outcome.ts) compute the post-edit outcome instead of judging the stale on-disk count alone. Undefined for Write (no such field) and for cline/apply_patch (parsed separately, no equivalent field). */
172
+ oldString?: string;
169
173
  command?: string;
170
174
  /** Subagent type, if the tool-use came from one (Explore/Plan are file-size-exempt). */
171
175
  agentType?: string;
@@ -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-BBlvYhek.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-D8rvbAfw.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.66",
3
+ "version": "0.1.68",
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",