@fusengine/harness 0.1.25 → 0.1.27

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 readClaudeInput, i as guard, n as denyResponse, o as toClaudeResponse, r as fileSizeGuard, t as contextResponse } from "../../claude-c2Sskvb6.mjs";
1
+ import { a as readClaudeInput, i as guard, n as denyResponse, o as toClaudeResponse, r as fileSizeGuard, t as contextResponse } from "../../claude-CeNVUGku.mjs";
2
2
  export { contextResponse, denyResponse, fileSizeGuard, guard, readClaudeInput, toClaudeResponse };
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "../../evaluate-CreJy519.mjs";
1
+ import { t as evaluate } from "../../evaluate-BIK60lOR.mjs";
2
2
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/cline/index.ts
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { a as readClaudeInput, i as guard, n as denyResponse, t as contextResponse } from "../../claude-c2Sskvb6.mjs";
1
+ import { a as readClaudeInput, i as guard, n as denyResponse, t as contextResponse } from "../../claude-CeNVUGku.mjs";
2
2
  export { contextResponse, denyResponse, guard, readClaudeInput as readCodexInput };
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "../../evaluate-CreJy519.mjs";
1
+ import { t as evaluate } from "../../evaluate-BIK60lOR.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-CreJy519.mjs";
1
+ import { t as evaluate } from "../../evaluate-BIK60lOR.mjs";
2
2
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/gemini/index.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "./evaluate-CreJy519.mjs";
1
+ import { t as evaluate } from "./evaluate-BIK60lOR.mjs";
2
2
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/claude/index.ts
4
4
  /**
package/dist/cli/bin.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { r as resolveTtlSec } from "../ttl-BG55s6HZ.mjs";
3
3
  import { t as detectHarness } from "../harness-C8Nxxyn_.mjs";
4
- import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-0LTLAbmo.mjs";
4
+ import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-BdcSLer0.mjs";
5
5
  import { n as writeInitFile, t as initFor } from "../run-D91N4ul1.mjs";
6
- import { t as handleHook } from "../handle-lX8yNCj3.mjs";
6
+ import { t as handleHook } from "../handle-BJ2xdeA-.mjs";
7
7
  //#region src/cli/bin.ts
8
8
  /**
9
9
  * harness — CLI for @fusengine/harness.
@@ -1,2 +1,2 @@
1
- import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-0LTLAbmo.mjs";
1
+ import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-BdcSLer0.mjs";
2
2
  export { checkStaged, stagedContent, stagedFiles };
@@ -118,7 +118,7 @@ const CRITICAL_PATTERNS = [
118
118
  /\b(?:curl|wget)\b[^|]*\|\s*(?:sudo\s+)?(?:ba|z|da|k)?sh\b/,
119
119
  /\bchmod\s+(?:-[a-zA-Z]+\s+)*777\s+\//,
120
120
  /\bmkfs(?:\.[a-z0-9]+)?\b/,
121
- /\bdd\b[^\n]*\bif=\/dev\/zero\b[^\n]*\bof=\/dev\//,
121
+ /\bdd\b[^\n]*\bof=\/dev\/(?:disk|sd|hd|nvme|mmcblk|vd)/i,
122
122
  /\bshred\b/,
123
123
  /\bfdisk\b/,
124
124
  /\bdiskutil\s+(?:erase|partitionDisk)/i,
@@ -136,12 +136,17 @@ const ASK_PATTERNS = [
136
136
  /\bdoas\s/,
137
137
  /\bpasswd\b/,
138
138
  /\brm\s/,
139
- /\bunlink\s/
139
+ /\bunlink\s/,
140
+ /\bdel\s/
140
141
  ];
142
+ /** Strip heredoc bodies so their content isn't matched as a command (false positives). */
143
+ function stripHeredoc(cmd) {
144
+ return cmd.replace(/<<-?\s*['"]?(\w+)['"]?[\s\S]*?\n[ \t]*\1\b/g, " ");
145
+ }
141
146
  /** Guards against dangerous Bash commands (critical → block, sensitive → ask). */
142
147
  function securityGuard(ctx) {
143
148
  if (ctx.tool !== "Bash" || !ctx.command) return null;
144
- const cmd = ctx.command;
149
+ const cmd = stripHeredoc(ctx.command);
145
150
  for (const re of CRITICAL_PATTERNS) if (re.test(cmd)) return {
146
151
  kind: "block",
147
152
  title: "Dangerous command",
@@ -1,9 +1,9 @@
1
1
  import { r as projectLayout } from "./layout-C0jaaCQC.mjs";
2
- import { j as detectFramework, n as FAIL_CLOSED, t as evaluate } from "./evaluate-CreJy519.mjs";
3
- import { c as evaluateApex, i as detectCreationIntent, r as capVerbosity } from "./verbosity-BnGJPq6y.mjs";
2
+ import { j as detectFramework, n as FAIL_CLOSED, t as evaluate } from "./evaluate-BIK60lOR.mjs";
3
+ import { c as evaluateApex, i as detectCreationIntent, r as capVerbosity } from "./verbosity-CXpf3aQQ.mjs";
4
4
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
5
5
  import { a as extractText, r as cacheStore, t as cacheLookup } from "./store-DeIsfMg5.mjs";
6
- import { t as loadRefs } from "./loader-CR3MT6Sn.mjs";
6
+ import { t as loadRefs } from "./loader-CyAoJv2W.mjs";
7
7
  import { a as recordAgent, c as recordRefRead, l as recordTrivialEdit, n as saveTrack, o as recordBrainstormRequired, r as agentsFresh, s as recordDoc, t as loadTrack, u as trivialCount } from "./store-BnHpq2ZB.mjs";
8
8
  import { join } from "node:path";
9
9
  import { existsSync, readFileSync } from "node:fs";
@@ -28,6 +28,6 @@ declare function toRefMeta(fm: Record<string, string>, filePath: string): RefMet
28
28
  * {@link RefMeta}. The content is entirely the consumer's — point this at any
29
29
  * refs dir (`FUSE_HARNESS_REFS`). Returns an empty list when the dir is absent.
30
30
  */
31
- declare function loadRefs(dir: string): Promise<RefMeta[]>;
31
+ declare function loadRefs(dirs: string): Promise<RefMeta[]>;
32
32
  //#endregion
33
33
  export { globToRe as a, scoreReferences as i, toRefMeta as n, parseFrontmatter as o, routeReferences as r, loadRefs as t };
package/dist/index.d.mts CHANGED
@@ -8,7 +8,7 @@ import { i as compactJson, n as projectRoot, r as projectRootOrNull, t as isCode
8
8
  import { A as ApexContext, B as GIT_ASK, C as protectedPathGuard, D as Guard, E as securityGuard, F as freshnessGate, G as FileSizeVerdict, H as PROJECT_INSTALL, I as solidReadGate, J as detectFramework, K as countLines, L as PolicyContext, M as brainstormGate, N as docConsultedGate, O as GuardContext, P as evaluateApex, Q as isApexCommand, R as PolicyResult, S as PROTECTED_FRAGMENTS, T as CRITICAL_PATTERNS, U as SYSTEM_INSTALL, V as GIT_BLOCKED, W as matchPatterns, X as ProjectType, Y as DEV_KEYWORDS, Z as detectProjectType, _ as interfaceSeparationGuard, a as FAIL_CLOSED, b as CODE_REDIRECT, c as registerGuard, d as GO_DECL_RE, f as JAVA_DECL_RE, g as TS_DECL_RE, h as SWIFT_PROTO_RE, i as detectCreationIntent, j as ApexGate, k as APEX_GATES, l as runGuards, m as PY_MODEL_RE, n as MAX_TOKENS, o as GUARDS, p as PHP_DECL_RE, q as evaluateFileSize, r as capVerbosity, s as clearUserGuards, t as MAX_EXA_RESULTS, u as installGuard, v as ASK_WRITERS, w as ASK_PATTERNS, x as bashWriteGuard, y as CODE_MUTATORS, z as evaluate } from "./index-DNAzITvw.mjs";
9
9
  import { n as RouteResult, r as ScoredRef, t as RefMeta } from "./types-CY5qT2X1.mjs";
10
10
  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";
11
- import { a as globToRe, i as scoreReferences, n as toRefMeta, o as parseFrontmatter, r as routeReferences, t as loadRefs } from "./index-BD1ZRv-H.mjs";
11
+ import { a as globToRe, i as scoreReferences, n as toRefMeta, o as parseFrontmatter, r as routeReferences, t as loadRefs } from "./index-DL8MxjuP.mjs";
12
12
  import { a as taskStart, c as ensureStateDir, d as stateFilePath, f as acquireLock, i as taskCreate, l as loadState, n as ApexTaskFile, o as ApexState, r as taskComplete, s as apexStateDir, t as ApexTask, u as saveState } from "./index-CPoF_hLP.mjs";
13
13
  import { _ as TIME_INTERVALS, a as formatCost, c as formatTokens, d as colors, f as progressiveColor, g as PROGRESS_CHARS, h as PROGRESS_BAR_DEFAULTS, i as formatBasename, l as ColorFn, m as GRADIENT_BLOCKS, n as generateGradientBar, o as formatPath, p as COLOR_THRESHOLDS, r as generateProgressBar, s as formatTimeLeft, t as ProgressBarOptions, u as Palette } from "./index-BWK8slRi.mjs";
14
14
  export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, ApexContext, ApexGate, ApexState, ApexTask, ApexTaskFile, AuthEntry, CODE_MUTATORS, CODE_REDIRECT, COLOR_THRESHOLDS, CRITICAL_PATTERNS, ColorFn, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, DocSatisfactionStatus, FAIL_CLOSED, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GRADIENT_BLOCKS, GUARDS, Guard, GuardContext, HarnessId, HarnessInfo, HarnessMode, HarnessVia, IndexSummary, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_LINES_ENV_KEY, MAX_TOKENS, PHP_DECL_RE, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, Palette, PolicyContext, PolicyResult, ProgressBarOptions, ProjectLayout, ProjectType, Prompt, PromptKind, RefMeta, ReminderState, RouteResult, STATE_GITIGNORE, STATE_ROOT, SWIFT_PROTO_RE, SYSTEM_INSTALL, ScoredRef, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, bashWriteGuard, brainstormGate, cacheLookup, cachePath, cacheStore, capVerbosity, clearUserGuards, colors, compactJson, compactMarkdown, countLines, detectCreationIntent, detectFramework, detectHarness, detectMode, detectProjectType, docConsultedGate, ensureMemoryGitignore, ensureStateDir, evaluate, evaluateApex, evaluateFileSize, extractText, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, freshnessGate, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, installGuard, interfaceSeparationGuard, isApexCommand, isCodeFile, isDocConsulted, jaccardSimilar, lessonsFileFor, loadIndex, loadRefs, loadState, matchPatterns, mcpCacheKey, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectLayout, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registerGuard, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, saveState, scoreReferences, securityGuard, setStateField, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, toRefMeta, ttlLabel };
package/dist/index.mjs CHANGED
@@ -5,16 +5,16 @@ import { t as compactJson } from "./compact-json-DK2nX-MK.mjs";
5
5
  import { n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-ff0_poWU.mjs";
6
6
  import { n as detectMode, r as modeFor, t as detectHarness } from "./harness-C8Nxxyn_.mjs";
7
7
  import { n as detectProjectType, r as isApexCommand, t as DEV_KEYWORDS } from "./policy-EuVJ_5hS.mjs";
8
- import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, 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 bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "./evaluate-CreJy519.mjs";
8
+ import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, 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 bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "./evaluate-BIK60lOR.mjs";
9
9
  import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-Dd_x1-tZ.mjs";
10
- import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-BxA7TgnX.mjs";
11
- import { a as APEX_GATES, c as evaluateApex, i as detectCreationIntent, l as freshnessGate, n as MAX_TOKENS, o as brainstormGate, r as capVerbosity, s as docConsultedGate, t as MAX_EXA_RESULTS, u as solidReadGate } from "./verbosity-BnGJPq6y.mjs";
10
+ import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-D8cVrI-s.mjs";
11
+ import { a as APEX_GATES, c as evaluateApex, i as detectCreationIntent, l as freshnessGate, n as MAX_TOKENS, o as brainstormGate, r as capVerbosity, s as docConsultedGate, t as MAX_EXA_RESULTS, u as solidReadGate } from "./verbosity-CXpf3aQQ.mjs";
12
12
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
13
13
  import { a as nowStamp, c as stateFileFor, i as lessonsFileFor, l as throttleMs, n as readRoots, o as readState, r as registryFile, s as setStateField, t as addRoot, u as ensureMemoryGitignore } from "./memory-BkoEbdec.mjs";
14
14
  import { a as queryHash, i as jaccardSimilar, n as summarizeIndex, r as compactMarkdown, t as loadIndex } from "./cache-BzbX-ztL.mjs";
15
15
  import { a as extractText, i as mcpCacheKey, n as cachePath, r as cacheStore, t as cacheLookup } from "./store-DeIsfMg5.mjs";
16
16
  import { t as incrementTrivialEditCounter } from "./freshness-CezohJHo.mjs";
17
- import { n as toRefMeta, t as loadRefs } from "./loader-CR3MT6Sn.mjs";
17
+ import { n as toRefMeta, t as loadRefs } from "./loader-CyAoJv2W.mjs";
18
18
  import { a as ensureStateDir, c as stateFilePath, i as apexStateDir, l as acquireLock, n as taskCreate, o as loadState, r as taskStart, s as saveState, t as taskComplete } from "./state-Cs0Y0MG_.mjs";
19
19
  import { a as formatPath, c as colors, d as GRADIENT_BLOCKS, f as PROGRESS_BAR_DEFAULTS, i as formatCost, l as progressiveColor, m as TIME_INTERVALS, n as generateProgressBar, o as formatTimeLeft, p as PROGRESS_CHARS, r as formatBasename, s as formatTokens, t as generateGradientBar, u as COLOR_THRESHOLDS } from "./statusline-D87eUNXl.mjs";
20
20
  export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, COLOR_THRESHOLDS, CRITICAL_PATTERNS, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, FAIL_CLOSED, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GRADIENT_BLOCKS, GUARDS, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_LINES_ENV_KEY, MAX_TOKENS, PHP_DECL_RE, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, STATE_GITIGNORE, STATE_ROOT, SWIFT_PROTO_RE, SYSTEM_INSTALL, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, bashWriteGuard, brainstormGate, cacheLookup, cachePath, cacheStore, capVerbosity, clearUserGuards, colors, compactJson, compactMarkdown, countLines, detectCreationIntent, detectFramework, detectHarness, detectMode, detectProjectType, docConsultedGate, ensureMemoryGitignore, ensureStateDir, evaluate, evaluateApex, evaluateFileSize, extractText, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, freshnessGate, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, installGuard, interfaceSeparationGuard, isApexCommand, isCodeFile, isDocConsulted, jaccardSimilar, lessonsFileFor, loadIndex, loadRefs, loadState, matchPatterns, mcpCacheKey, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectLayout, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registerGuard, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, saveState, scoreReferences, securityGuard, setStateField, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, toRefMeta, ttlLabel };
@@ -0,0 +1,63 @@
1
+ import { i as parseFrontmatter } from "./router-D8cVrI-s.mjs";
2
+ import { delimiter, join } from "node:path";
3
+ import { readFile, readdir } from "node:fs/promises";
4
+ //#region src/refs/loader.ts
5
+ function pick(fm, ...keys) {
6
+ for (const k of keys) {
7
+ const v = fm[k];
8
+ if (v) return v;
9
+ }
10
+ return "";
11
+ }
12
+ const SOLID_SLUGS = /* @__PURE__ */ new Set([
13
+ "single-responsibility",
14
+ "open-closed",
15
+ "liskov-substitution",
16
+ "interface-segregation",
17
+ "dependency-inversion",
18
+ "solid-principles"
19
+ ]);
20
+ /** Infer a ref's level from its path when the frontmatter omits it (templates/→template, SOLID slug→principle). */
21
+ function inferLevel(filePath) {
22
+ if (filePath.includes("/templates/")) return "template";
23
+ const stem = (filePath.split("/").pop() ?? "").replace(/\.md$/, "");
24
+ return SOLID_SLUGS.has(stem) ? "principle" : "architecture";
25
+ }
26
+ /** Build a {@link RefMeta} from parsed frontmatter, tolerant of kebab/camel keys. */
27
+ function toRefMeta(fm, filePath) {
28
+ return {
29
+ name: pick(fm, "name") || filePath,
30
+ description: pick(fm, "description"),
31
+ keywords: pick(fm, "keywords"),
32
+ priority: pick(fm, "priority"),
33
+ related: pick(fm, "related"),
34
+ appliesTo: pick(fm, "appliesTo", "applies-to", "applies_to"),
35
+ triggerOnEdit: pick(fm, "triggerOnEdit", "trigger-on-edit", "trigger_on_edit"),
36
+ level: pick(fm, "level") || inferLevel(filePath),
37
+ filePath
38
+ };
39
+ }
40
+ /**
41
+ * Scan a directory recursively for `.md` reference files and parse each into a
42
+ * {@link RefMeta}. The content is entirely the consumer's — point this at any
43
+ * refs dir (`FUSE_HARNESS_REFS`). Returns an empty list when the dir is absent.
44
+ */
45
+ async function loadRefs(dirs) {
46
+ const refs = [];
47
+ for (const dir of dirs.split(delimiter).filter(Boolean)) {
48
+ let entries;
49
+ try {
50
+ entries = await readdir(dir, { recursive: true });
51
+ } catch {
52
+ continue;
53
+ }
54
+ for (const rel of entries) {
55
+ if (!rel.endsWith(".md")) continue;
56
+ const filePath = join(dir, rel);
57
+ refs.push(toRefMeta(parseFrontmatter(await readFile(filePath, "utf8")), filePath));
58
+ }
59
+ }
60
+ return refs;
61
+ }
62
+ //#endregion
63
+ export { toRefMeta as n, loadRefs as t };
@@ -1,4 +1,4 @@
1
1
  import { n as detectProjectType, r as isApexCommand, t as DEV_KEYWORDS } from "../policy-EuVJ_5hS.mjs";
2
- import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, 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 bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "../evaluate-CreJy519.mjs";
3
- import { a as APEX_GATES, c as evaluateApex, i as detectCreationIntent, l as freshnessGate, n as MAX_TOKENS, o as brainstormGate, r as capVerbosity, s as docConsultedGate, t as MAX_EXA_RESULTS, u as solidReadGate } from "../verbosity-BnGJPq6y.mjs";
2
+ import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, 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 bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "../evaluate-BIK60lOR.mjs";
3
+ import { a as APEX_GATES, c as evaluateApex, i as detectCreationIntent, l as freshnessGate, n as MAX_TOKENS, o as brainstormGate, r as capVerbosity, s as docConsultedGate, t as MAX_EXA_RESULTS, u as solidReadGate } from "../verbosity-CXpf3aQQ.mjs";
4
4
  export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, FAIL_CLOSED, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_TOKENS, PHP_DECL_RE, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, bashWriteGuard, brainstormGate, capVerbosity, clearUserGuards, countLines, detectCreationIntent, detectFramework, detectProjectType, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, matchPatterns, protectedPathGuard, registerGuard, runGuards, securityGuard, solidReadGate };
@@ -1,3 +1,3 @@
1
1
  import { n as RouteResult, r as ScoredRef, t as RefMeta } from "../types-CY5qT2X1.mjs";
2
- import { a as globToRe, i as scoreReferences, n as toRefMeta, o as parseFrontmatter, r as routeReferences, t as loadRefs } from "../index-BD1ZRv-H.mjs";
2
+ import { a as globToRe, i as scoreReferences, n as toRefMeta, o as parseFrontmatter, r as routeReferences, t as loadRefs } from "../index-DL8MxjuP.mjs";
3
3
  export { RefMeta, RouteResult, ScoredRef, globToRe, loadRefs, parseFrontmatter, routeReferences, scoreReferences, toRefMeta };
@@ -1,4 +1,4 @@
1
- import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "../router-BxA7TgnX.mjs";
2
- import { n as toRefMeta, t as loadRefs } from "../loader-CR3MT6Sn.mjs";
1
+ import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "../router-D8cVrI-s.mjs";
2
+ import { n as toRefMeta, t as loadRefs } from "../loader-CyAoJv2W.mjs";
3
3
  import "../refs-la_KkjCS.mjs";
4
4
  export { globToRe, loadRefs, parseFrontmatter, routeReferences, scoreReferences, toRefMeta };
@@ -37,9 +37,12 @@ function scoreReferences(refs, filePath, content) {
37
37
  if (meta.triggerOnEdit) {
38
38
  for (const frag of meta.triggerOnEdit.split(", ")) if (filePath.includes(frag.trim())) score += 5;
39
39
  }
40
- if (meta.keywords) for (const kw of meta.keywords.split(", ")) {
41
- const k = kw.trim();
42
- if (k && (filePath.includes(k) || content.includes(k))) score += 1;
40
+ if (meta.keywords) {
41
+ const hay = `${filePath} ${content}`.toLowerCase();
42
+ for (const kw of meta.keywords.split(", ")) {
43
+ const k = kw.trim().toLowerCase();
44
+ if (k && hay.includes(k)) score += 1;
45
+ }
43
46
  }
44
47
  if (score > 0) scored.push({
45
48
  meta,
@@ -1,5 +1,5 @@
1
1
  import { t as isCodeFile } from "./project-root-ff0_poWU.mjs";
2
- import { t as evaluate } from "./evaluate-CreJy519.mjs";
2
+ import { t as evaluate } from "./evaluate-BIK60lOR.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
@@ -1,5 +1,5 @@
1
1
  import { r as projectLayout } from "../layout-C0jaaCQC.mjs";
2
- import { a as normalizeEvent, c as mcpPostStore, d as DEFAULT_WINDOW_MS, f as REQUIRED_AGENTS, h as activityFor, i as trackFile, l as mcpPreIntercept, m as gate, n as respond, o as MCP_TTL_MS, p as TRIVIAL_BUDGET, r as recordActivity, s as isMcpTool, t as handleHook, u as queryOf } from "../handle-lX8yNCj3.mjs";
2
+ import { a as normalizeEvent, c as mcpPostStore, d as DEFAULT_WINDOW_MS, f as REQUIRED_AGENTS, h as activityFor, i as trackFile, l as mcpPreIntercept, m as gate, n as respond, o as MCP_TTL_MS, p as TRIVIAL_BUDGET, r as recordActivity, s as isMcpTool, t as handleHook, u as queryOf } from "../handle-BJ2xdeA-.mjs";
3
3
  //#region src/runtime/storage.ts
4
4
  /**
5
5
  * The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
@@ -1,5 +1,5 @@
1
1
  import { r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-Dd_x1-tZ.mjs";
2
- import { t as routeReferences } from "./router-BxA7TgnX.mjs";
2
+ import { t as routeReferences } from "./router-D8cVrI-s.mjs";
3
3
  //#region src/policy/apex.ts
4
4
  /** Gate: Context7 + Exa must have been consulted this session. */
5
5
  const docConsultedGate = (ctx) => isDocConsulted(ctx.authorizations, ctx.sessionId) ? null : {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusengine/harness",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
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",
@@ -1,47 +0,0 @@
1
- import { i as parseFrontmatter } from "./router-BxA7TgnX.mjs";
2
- import { join } from "node:path";
3
- import { readFile, readdir } from "node:fs/promises";
4
- //#region src/refs/loader.ts
5
- function pick(fm, ...keys) {
6
- for (const k of keys) {
7
- const v = fm[k];
8
- if (v) return v;
9
- }
10
- return "";
11
- }
12
- /** Build a {@link RefMeta} from parsed frontmatter, tolerant of kebab/camel keys. */
13
- function toRefMeta(fm, filePath) {
14
- return {
15
- name: pick(fm, "name") || filePath,
16
- description: pick(fm, "description"),
17
- keywords: pick(fm, "keywords"),
18
- priority: pick(fm, "priority"),
19
- related: pick(fm, "related"),
20
- appliesTo: pick(fm, "appliesTo", "applies-to", "applies_to"),
21
- triggerOnEdit: pick(fm, "triggerOnEdit", "trigger-on-edit", "trigger_on_edit"),
22
- level: pick(fm, "level"),
23
- filePath
24
- };
25
- }
26
- /**
27
- * Scan a directory recursively for `.md` reference files and parse each into a
28
- * {@link RefMeta}. The content is entirely the consumer's — point this at any
29
- * refs dir (`FUSE_HARNESS_REFS`). Returns an empty list when the dir is absent.
30
- */
31
- async function loadRefs(dir) {
32
- let entries;
33
- try {
34
- entries = await readdir(dir, { recursive: true });
35
- } catch {
36
- return [];
37
- }
38
- const refs = [];
39
- for (const rel of entries) {
40
- if (!rel.endsWith(".md")) continue;
41
- const filePath = join(dir, rel);
42
- refs.push(toRefMeta(parseFrontmatter(await readFile(filePath, "utf8")), filePath));
43
- }
44
- return refs;
45
- }
46
- //#endregion
47
- export { toRefMeta as n, loadRefs as t };