@fusengine/harness 0.1.10 → 0.1.11

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.
@@ -30,8 +30,16 @@ const freshnessGate = (ctx) => ctx.agentsFresh === false ? {
30
30
  reason: `Run explore-codebase and research-expert (within the freshness window) before editing ${ctx.framework}.`,
31
31
  actions: ["Launch the explore-codebase agent", "Launch the research-expert agent"]
32
32
  } : null;
33
- /** Default APEX gate chain (freshness, then docs, then SOLID refs). */
33
+ /** Gate: brainstorming must precede creating new files when flagged. */
34
+ const brainstormGate = (ctx) => ctx.brainstormRequired && ctx.brainstormFresh === false ? {
35
+ kind: "block",
36
+ title: "APEX: brainstorm first",
37
+ reason: `Creation intent detected — brainstorm before creating new ${ctx.framework} files.`,
38
+ actions: ["Launch the brainstorming agent"]
39
+ } : null;
40
+ /** Default APEX gate chain (brainstorm, freshness, docs, SOLID refs). */
34
41
  const APEX_GATES = [
42
+ brainstormGate,
35
43
  freshnessGate,
36
44
  docConsultedGate,
37
45
  solidReadGate
@@ -44,4 +52,4 @@ function evaluateApex(ctx, gates = APEX_GATES) {
44
52
  return gates.reduce((hit, gate) => hit ?? gate(ctx), null);
45
53
  }
46
54
  //#endregion
47
- export { solidReadGate as a, freshnessGate as i, docConsultedGate as n, evaluateApex as r, APEX_GATES as t };
55
+ export { freshnessGate as a, evaluateApex as i, brainstormGate as n, solidReadGate as o, docConsultedGate as r, APEX_GATES as t };
package/dist/cli/bin.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { t as detectHarness } from "../harness-C8Nxxyn_.mjs";
3
3
  import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-D2na7Z2Z.mjs";
4
4
  import { n as writeInitFile, t as initFor } from "../run-Cdp2Ef9B.mjs";
5
- import { t as handleHook } from "../handle-BUyS6NU6.mjs";
5
+ import { t as handleHook } from "../handle-Cr0YQYz-.mjs";
6
6
  //#region src/cli/bin.ts
7
7
  /**
8
8
  * harness — CLI for @fusengine/harness.
@@ -1,8 +1,8 @@
1
1
  import { O as detectFramework, t as evaluate } from "./evaluate-DkTgwHNh.mjs";
2
- import { r as evaluateApex } from "./apex-gGrHzvM2.mjs";
2
+ import { i as evaluateApex } from "./apex-BcJSE-VL.mjs";
3
3
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
4
4
  import { t as loadRefs } from "./loader-BephwI8n.mjs";
5
- import { a as recordAgent, n as saveTrack, o as recordDoc, r as agentsFresh, s as recordRefRead, t as loadTrack } from "./store-BWvwnnf6.mjs";
5
+ import { a as recordAgent, c as recordRefRead, l as recordTrivialEdit, n as saveTrack, r as agentsFresh, s as recordDoc, t as loadTrack, u as trivialCount } from "./store-gtbP-Bv9.mjs";
6
6
  import { join } from "node:path";
7
7
  import { tmpdir } from "node:os";
8
8
  //#region src/runtime/activity.ts
@@ -49,10 +49,12 @@ function activityFor(event) {
49
49
  const REQUIRED_AGENTS = ["explore-codebase", "research-expert"];
50
50
  /** Default freshness window for {@link REQUIRED_AGENTS} (4 min, the APEX TTL). */
51
51
  const DEFAULT_WINDOW_MS = 24e4;
52
+ /** Trivial edits allowed within the window before the full APEX gates apply. */
53
+ const TRIVIAL_BUDGET = 4;
52
54
  /**
53
- * Full gate: the stateless guards (file-size, git) first, then the stateful
54
- * APEX gates fed from the session track. Returns the first blocking prompt, or
55
- * null to allow. APEX gates apply only to code edits (a `filePath`).
55
+ * Full gate: the stateless guards (file-size, git, security...) first, then a
56
+ * trivial-edit fast path, then the stateful APEX gates fed from the session
57
+ * track. Returns the first blocking prompt, or null to allow.
56
58
  */
57
59
  async function gate(input) {
58
60
  const quick = evaluate({
@@ -63,7 +65,13 @@ async function gate(input) {
63
65
  });
64
66
  if (quick.decision !== "allow" && quick.prompt) return quick.prompt;
65
67
  if (!input.filePath) return null;
68
+ const window = input.windowMs ?? 24e4;
66
69
  const track = await loadTrack(input.trackFile);
70
+ const lineCount = input.content === void 0 ? Number.POSITIVE_INFINITY : input.content.split("\n").length;
71
+ if (!input.isReplaceAll && lineCount < 5 && trivialCount(track, window, input.now) < 4) {
72
+ await saveTrack(input.trackFile, recordTrivialEdit(track, input.now, window, input.now));
73
+ return null;
74
+ }
67
75
  return evaluateApex({
68
76
  sessionId: input.sessionId,
69
77
  framework: input.framework,
@@ -72,7 +80,9 @@ async function gate(input) {
72
80
  authorizations: track.authorizations,
73
81
  refs: input.refs,
74
82
  refsRead: track.refsRead,
75
- agentsFresh: agentsFresh(track, [...REQUIRED_AGENTS], input.windowMs ?? 24e4, input.now)
83
+ agentsFresh: agentsFresh(track, [...REQUIRED_AGENTS], window, input.now),
84
+ brainstormRequired: track.brainstormRequired,
85
+ brainstormFresh: agentsFresh(track, ["brainstorming"], window, input.now)
76
86
  });
77
87
  }
78
88
  //#endregion
@@ -211,6 +221,7 @@ async function handleHook(id, payload, opts) {
211
221
  content: event.content,
212
222
  command: event.command,
213
223
  refs: opts.refsDir ? await loadRefs(opts.refsDir) : void 0,
224
+ isReplaceAll: event.input.replace_all === true,
214
225
  now: opts.now,
215
226
  trackFile: file
216
227
  });
@@ -223,4 +234,4 @@ async function handleHook(id, payload, opts) {
223
234
  };
224
235
  }
225
236
  //#endregion
226
- export { trackFile as a, REQUIRED_AGENTS as c, recordActivity as i, gate as l, harnessTrackDir as n, normalizeEvent as o, respond as r, DEFAULT_WINDOW_MS as s, handleHook as t, activityFor as u };
237
+ export { trackFile as a, REQUIRED_AGENTS as c, activityFor as d, recordActivity as i, TRIVIAL_BUDGET as l, harnessTrackDir as n, normalizeEvent as o, respond as r, DEFAULT_WINDOW_MS as s, handleHook as t, gate as u };
@@ -98,6 +98,10 @@ interface ApexContext {
98
98
  refsRead?: string[];
99
99
  /** Whether the required prior agents (explore + research) ran within the freshness window. */
100
100
  agentsFresh?: boolean;
101
+ /** Whether brainstorming is required for this edit (creation intent on a new file). */
102
+ brainstormRequired?: boolean;
103
+ /** Whether the brainstorming agent ran within the window. */
104
+ brainstormFresh?: boolean;
101
105
  }
102
106
  /** A single APEX gate: returns a blocking {@link Prompt}, or null to pass. */
103
107
  type ApexGate = (ctx: ApexContext) => Prompt | null;
@@ -107,7 +111,9 @@ declare const docConsultedGate: ApexGate;
107
111
  declare const solidReadGate: ApexGate;
108
112
  /** Gate: the required prior agents (explore + research) must have run within the window. */
109
113
  declare const freshnessGate: ApexGate;
110
- /** Default APEX gate chain (freshness, then docs, then SOLID refs). */
114
+ /** Gate: brainstorming must precede creating new files when flagged. */
115
+ declare const brainstormGate: ApexGate;
116
+ /** Default APEX gate chain (brainstorm, freshness, docs, SOLID refs). */
111
117
  declare const APEX_GATES: ReadonlyArray<ApexGate>;
112
118
  /**
113
119
  * Run the APEX gates (chain-of-responsibility): the first failing gate's prompt
@@ -184,4 +190,12 @@ declare const GUARDS: ReadonlyArray<Guard>;
184
190
  /** Run the guard chain; the first firing guard's Prompt wins, else null. */
185
191
  declare function runGuards(ctx: GuardContext): Prompt | null;
186
192
  //#endregion
187
- export { PolicyResult as A, detectFramework as B, ApexContext as C, freshnessGate as D, evaluateApex as E, SYSTEM_INSTALL as F, ProjectType as H, matchPatterns as I, FileSizeVerdict as L, GIT_ASK as M, GIT_BLOCKED as N, solidReadGate as O, PROJECT_INSTALL as P, countLines as R, APEX_GATES as S, docConsultedGate as T, detectProjectType as U, DEV_KEYWORDS as V, isApexCommand as W, ASK_PATTERNS as _, installGuard as a, Guard as b, SWIFT_PROTO_RE as c, ASK_WRITERS as d, CODE_MUTATORS as f, protectedPathGuard as g, PROTECTED_FRAGMENTS as h, SYSTEM_INSTALL_RE as i, evaluate as j, PolicyContext as k, TS_DECL_RE as l, bashWriteGuard as m, runGuards as n, PHP_DECL_RE as o, CODE_REDIRECT as p, PROJECT_INSTALL_RE as r, PY_MODEL_RE as s, GUARDS as t, interfaceSeparationGuard as u, CRITICAL_PATTERNS as v, ApexGate as w, GuardContext as x, securityGuard as y, evaluateFileSize as z };
193
+ //#region src/policy/creation-intent.d.ts
194
+ /**
195
+ * True when a prompt expresses creation intent (a new feature/component) and is
196
+ * not a fix/refactor — the signal that brainstorming should precede creation.
197
+ * The harness calls this on UserPromptSubmit, then `recordBrainstormRequired`.
198
+ */
199
+ declare function detectCreationIntent(prompt: string): boolean;
200
+ //#endregion
201
+ export { solidReadGate as A, countLines as B, APEX_GATES as C, docConsultedGate as D, brainstormGate as E, GIT_BLOCKED as F, detectProjectType as G, detectFramework as H, PROJECT_INSTALL as I, isApexCommand as K, SYSTEM_INSTALL as L, PolicyResult as M, evaluate as N, evaluateApex as O, GIT_ASK as P, matchPatterns as R, GuardContext as S, ApexGate as T, DEV_KEYWORDS as U, evaluateFileSize as V, ProjectType as W, protectedPathGuard as _, SYSTEM_INSTALL_RE as a, securityGuard as b, PY_MODEL_RE as c, interfaceSeparationGuard as d, ASK_WRITERS as f, PROTECTED_FRAGMENTS as g, bashWriteGuard as h, PROJECT_INSTALL_RE as i, PolicyContext as j, freshnessGate as k, SWIFT_PROTO_RE as l, CODE_REDIRECT as m, GUARDS as n, installGuard as o, CODE_MUTATORS as p, runGuards as r, PHP_DECL_RE as s, detectCreationIntent as t, TS_DECL_RE as u, ASK_PATTERNS as v, ApexContext as w, Guard as x, CRITICAL_PATTERNS as y, FileSizeVerdict as z };
package/dist/index.d.mts CHANGED
@@ -5,10 +5,10 @@ import { a as detectHarness, i as HarnessVia, n as HarnessInfo, o as detectMode,
5
5
  import { a as isDocConsulted, i as formatDocSatisfactionStatus, n as DocSatisfactionStatus, o as resolveSessions, r as formatDocDeny, t as AuthEntry } from "./doc-helpers-CG1nuf-c.mjs";
6
6
  import { t as incrementTrivialEditCounter } from "./index-BOBXQ91y.mjs";
7
7
  import { i as compactJson, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./index-C1vLIMwN.mjs";
8
- import { A as PolicyResult, B as detectFramework, C as ApexContext, D as freshnessGate, E as evaluateApex, F as SYSTEM_INSTALL, H as ProjectType, I as matchPatterns, L as FileSizeVerdict, M as GIT_ASK, N as GIT_BLOCKED, O as solidReadGate, P as PROJECT_INSTALL, R as countLines, S as APEX_GATES, T as docConsultedGate, U as detectProjectType, V as DEV_KEYWORDS, W as isApexCommand, _ as ASK_PATTERNS, a as installGuard, b as Guard, c as SWIFT_PROTO_RE, d as ASK_WRITERS, f as CODE_MUTATORS, g as protectedPathGuard, h as PROTECTED_FRAGMENTS, i as SYSTEM_INSTALL_RE, j as evaluate, k as PolicyContext, l as TS_DECL_RE, m as bashWriteGuard, n as runGuards, o as PHP_DECL_RE, p as CODE_REDIRECT, r as PROJECT_INSTALL_RE, s as PY_MODEL_RE, t as GUARDS, u as interfaceSeparationGuard, v as CRITICAL_PATTERNS, w as ApexGate, x as GuardContext, y as securityGuard, z as evaluateFileSize } from "./index-uEteukGR.mjs";
8
+ import { A as solidReadGate, B as countLines, C as APEX_GATES, D as docConsultedGate, E as brainstormGate, F as GIT_BLOCKED, G as detectProjectType, H as detectFramework, I as PROJECT_INSTALL, K as isApexCommand, L as SYSTEM_INSTALL, M as PolicyResult, N as evaluate, O as evaluateApex, P as GIT_ASK, R as matchPatterns, S as GuardContext, T as ApexGate, U as DEV_KEYWORDS, V as evaluateFileSize, W as ProjectType, _ as protectedPathGuard, a as SYSTEM_INSTALL_RE, b as securityGuard, c as PY_MODEL_RE, d as interfaceSeparationGuard, f as ASK_WRITERS, g as PROTECTED_FRAGMENTS, h as bashWriteGuard, i as PROJECT_INSTALL_RE, j as PolicyContext, k as freshnessGate, l as SWIFT_PROTO_RE, m as CODE_REDIRECT, n as GUARDS, o as installGuard, p as CODE_MUTATORS, r as runGuards, s as PHP_DECL_RE, t as detectCreationIntent, u as TS_DECL_RE, v as ASK_PATTERNS, w as ApexContext, x as Guard, y as CRITICAL_PATTERNS, z as FileSizeVerdict } from "./index-CGFPvQ69.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 setStateField, i as registryFile, l as stateFileFor, n as addRoot, o as nowStamp, r as readRoots, s as readState, t as ensureMemoryGitignore, u as throttleMs } from "./index-BEM-mQMC.mjs";
11
11
  import { a as globToRe, i as scoreReferences, n as toRefMeta, o as parseFrontmatter, r as routeReferences, t as loadRefs } from "./index-hL_r6tlc.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
- 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, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GRADIENT_BLOCKS, GUARDS, Guard, GuardContext, HarnessId, HarnessInfo, HarnessMode, HarnessVia, IndexSummary, MAX_LINES_ENV_KEY, PHP_DECL_RE, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, PROJECT_INSTALL_RE, PROTECTED_FRAGMENTS, PY_MODEL_RE, Palette, PolicyContext, PolicyResult, ProgressBarOptions, ProjectType, Prompt, PromptKind, RefMeta, ReminderState, RouteResult, SWIFT_PROTO_RE, SYSTEM_INSTALL, SYSTEM_INSTALL_RE, ScoredRef, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, bashWriteGuard, colors, compactJson, compactMarkdown, countLines, 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, loadIndex, loadRefs, loadState, matchPatterns, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, saveState, scoreReferences, securityGuard, setStateField, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, toRefMeta, ttlLabel };
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, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GRADIENT_BLOCKS, GUARDS, Guard, GuardContext, HarnessId, HarnessInfo, HarnessMode, HarnessVia, IndexSummary, MAX_LINES_ENV_KEY, PHP_DECL_RE, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, PROJECT_INSTALL_RE, PROTECTED_FRAGMENTS, PY_MODEL_RE, Palette, PolicyContext, PolicyResult, ProgressBarOptions, ProjectType, Prompt, PromptKind, RefMeta, ReminderState, RouteResult, SWIFT_PROTO_RE, SYSTEM_INSTALL, SYSTEM_INSTALL_RE, ScoredRef, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, bashWriteGuard, brainstormGate, 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, loadIndex, loadRefs, loadState, matchPatterns, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, 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
@@ -3,11 +3,11 @@ import { i as ttlLabel, n as TTL_ENV_KEY, r as resolveTtlSec, t as DEFAULT_TTL_S
3
3
  import { t as compactJson } from "./compact-json-DK2nX-MK.mjs";
4
4
  import { n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-C4ks_q1G.mjs";
5
5
  import { n as detectMode, r as modeFor, t as detectHarness } from "./harness-C8Nxxyn_.mjs";
6
- import { n as detectProjectType, r as isApexCommand, t as DEV_KEYWORDS } from "./policy-C_pXmeNB.mjs";
6
+ import { i as isApexCommand, n as DEV_KEYWORDS, r as detectProjectType, t as detectCreationIntent } from "./policy-Djmqxow2.mjs";
7
7
  import { C as PROJECT_INSTALL, D as evaluateFileSize, E as countLines, O as detectFramework, S as GIT_BLOCKED, T as matchPatterns, _ as protectedPathGuard, a as SYSTEM_INSTALL_RE, b as securityGuard, c as PY_MODEL_RE, d as interfaceSeparationGuard, f as ASK_WRITERS, g as PROTECTED_FRAGMENTS, h as bashWriteGuard, i as PROJECT_INSTALL_RE, l as SWIFT_PROTO_RE, m as CODE_REDIRECT, n as GUARDS, o as installGuard, p as CODE_MUTATORS, r as runGuards, s as PHP_DECL_RE, t as evaluate, u as TS_DECL_RE, v as ASK_PATTERNS, w as SYSTEM_INSTALL, x as GIT_ASK, y as CRITICAL_PATTERNS } from "./evaluate-DkTgwHNh.mjs";
8
8
  import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-Dd_x1-tZ.mjs";
9
9
  import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-Dj3AfgBE.mjs";
10
- import { a as solidReadGate, i as freshnessGate, n as docConsultedGate, r as evaluateApex, t as APEX_GATES } from "./apex-gGrHzvM2.mjs";
10
+ import { a as freshnessGate, i as evaluateApex, n as brainstormGate, o as solidReadGate, r as docConsultedGate, t as APEX_GATES } from "./apex-BcJSE-VL.mjs";
11
11
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
12
12
  import { a as readState, c as throttleMs, i as nowStamp, l as ensureMemoryGitignore, n as readRoots, o as setStateField, r as registryFile, s as stateFileFor, t as addRoot } from "./memory-BVNt4Ary.mjs";
13
13
  import { a as jaccardSimilar, i as compactMarkdown, n as loadIndex, o as queryHash, r as summarizeIndex, t as extractText } from "./cache-DbPSJ9bC.mjs";
@@ -15,4 +15,4 @@ import { t as incrementTrivialEditCounter } from "./freshness-BK9Xg6oG.mjs";
15
15
  import { n as toRefMeta, t as loadRefs } from "./loader-BephwI8n.mjs";
16
16
  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-Bc4wdnCG.mjs";
17
17
  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";
18
- export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, COLOR_THRESHOLDS, CRITICAL_PATTERNS, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, GRADIENT_BLOCKS, GUARDS, MAX_LINES_ENV_KEY, PHP_DECL_RE, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, PROJECT_INSTALL_RE, PROTECTED_FRAGMENTS, PY_MODEL_RE, SWIFT_PROTO_RE, SYSTEM_INSTALL, SYSTEM_INSTALL_RE, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, bashWriteGuard, colors, compactJson, compactMarkdown, countLines, 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, loadIndex, loadRefs, loadState, matchPatterns, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, saveState, scoreReferences, securityGuard, setStateField, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, toRefMeta, ttlLabel };
18
+ export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, COLOR_THRESHOLDS, CRITICAL_PATTERNS, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, GRADIENT_BLOCKS, GUARDS, MAX_LINES_ENV_KEY, PHP_DECL_RE, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, PROJECT_INSTALL_RE, PROTECTED_FRAGMENTS, PY_MODEL_RE, SWIFT_PROTO_RE, SYSTEM_INSTALL, SYSTEM_INSTALL_RE, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, bashWriteGuard, brainstormGate, 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, loadIndex, loadRefs, loadState, matchPatterns, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, saveState, scoreReferences, securityGuard, setStateField, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, toRefMeta, ttlLabel };
@@ -1,2 +1,2 @@
1
- import { A as PolicyResult, B as detectFramework, C as ApexContext, D as freshnessGate, E as evaluateApex, F as SYSTEM_INSTALL, H as ProjectType, I as matchPatterns, L as FileSizeVerdict, M as GIT_ASK, N as GIT_BLOCKED, O as solidReadGate, P as PROJECT_INSTALL, R as countLines, S as APEX_GATES, T as docConsultedGate, U as detectProjectType, V as DEV_KEYWORDS, W as isApexCommand, _ as ASK_PATTERNS, a as installGuard, b as Guard, c as SWIFT_PROTO_RE, d as ASK_WRITERS, f as CODE_MUTATORS, g as protectedPathGuard, h as PROTECTED_FRAGMENTS, i as SYSTEM_INSTALL_RE, j as evaluate, k as PolicyContext, l as TS_DECL_RE, m as bashWriteGuard, n as runGuards, o as PHP_DECL_RE, p as CODE_REDIRECT, r as PROJECT_INSTALL_RE, s as PY_MODEL_RE, t as GUARDS, u as interfaceSeparationGuard, v as CRITICAL_PATTERNS, w as ApexGate, x as GuardContext, y as securityGuard, z as evaluateFileSize } from "../index-uEteukGR.mjs";
2
- export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, ApexContext, ApexGate, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GUARDS, Guard, GuardContext, PHP_DECL_RE, PROJECT_INSTALL, PROJECT_INSTALL_RE, PROTECTED_FRAGMENTS, PY_MODEL_RE, PolicyContext, PolicyResult, ProjectType, SWIFT_PROTO_RE, SYSTEM_INSTALL, SYSTEM_INSTALL_RE, TS_DECL_RE, bashWriteGuard, countLines, detectFramework, detectProjectType, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, matchPatterns, protectedPathGuard, runGuards, securityGuard, solidReadGate };
1
+ import { A as solidReadGate, B as countLines, C as APEX_GATES, D as docConsultedGate, E as brainstormGate, F as GIT_BLOCKED, G as detectProjectType, H as detectFramework, I as PROJECT_INSTALL, K as isApexCommand, L as SYSTEM_INSTALL, M as PolicyResult, N as evaluate, O as evaluateApex, P as GIT_ASK, R as matchPatterns, S as GuardContext, T as ApexGate, U as DEV_KEYWORDS, V as evaluateFileSize, W as ProjectType, _ as protectedPathGuard, a as SYSTEM_INSTALL_RE, b as securityGuard, c as PY_MODEL_RE, d as interfaceSeparationGuard, f as ASK_WRITERS, g as PROTECTED_FRAGMENTS, h as bashWriteGuard, i as PROJECT_INSTALL_RE, j as PolicyContext, k as freshnessGate, l as SWIFT_PROTO_RE, m as CODE_REDIRECT, n as GUARDS, o as installGuard, p as CODE_MUTATORS, r as runGuards, s as PHP_DECL_RE, t as detectCreationIntent, u as TS_DECL_RE, v as ASK_PATTERNS, w as ApexContext, x as Guard, y as CRITICAL_PATTERNS, z as FileSizeVerdict } from "../index-CGFPvQ69.mjs";
2
+ export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, ApexContext, ApexGate, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GUARDS, Guard, GuardContext, PHP_DECL_RE, PROJECT_INSTALL, PROJECT_INSTALL_RE, PROTECTED_FRAGMENTS, PY_MODEL_RE, PolicyContext, PolicyResult, ProjectType, SWIFT_PROTO_RE, SYSTEM_INSTALL, SYSTEM_INSTALL_RE, TS_DECL_RE, bashWriteGuard, brainstormGate, countLines, detectCreationIntent, detectFramework, detectProjectType, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, matchPatterns, protectedPathGuard, runGuards, securityGuard, solidReadGate };
@@ -1,4 +1,4 @@
1
- import { n as detectProjectType, r as isApexCommand, t as DEV_KEYWORDS } from "../policy-C_pXmeNB.mjs";
1
+ import { i as isApexCommand, n as DEV_KEYWORDS, r as detectProjectType, t as detectCreationIntent } from "../policy-Djmqxow2.mjs";
2
2
  import { C as PROJECT_INSTALL, D as evaluateFileSize, E as countLines, O as detectFramework, S as GIT_BLOCKED, T as matchPatterns, _ as protectedPathGuard, a as SYSTEM_INSTALL_RE, b as securityGuard, c as PY_MODEL_RE, d as interfaceSeparationGuard, f as ASK_WRITERS, g as PROTECTED_FRAGMENTS, h as bashWriteGuard, i as PROJECT_INSTALL_RE, l as SWIFT_PROTO_RE, m as CODE_REDIRECT, n as GUARDS, o as installGuard, p as CODE_MUTATORS, r as runGuards, s as PHP_DECL_RE, t as evaluate, u as TS_DECL_RE, v as ASK_PATTERNS, w as SYSTEM_INSTALL, x as GIT_ASK, y as CRITICAL_PATTERNS } from "../evaluate-DkTgwHNh.mjs";
3
- import { a as solidReadGate, i as freshnessGate, n as docConsultedGate, r as evaluateApex, t as APEX_GATES } from "../apex-gGrHzvM2.mjs";
4
- export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, GUARDS, PHP_DECL_RE, PROJECT_INSTALL, PROJECT_INSTALL_RE, PROTECTED_FRAGMENTS, PY_MODEL_RE, SWIFT_PROTO_RE, SYSTEM_INSTALL, SYSTEM_INSTALL_RE, TS_DECL_RE, bashWriteGuard, countLines, detectFramework, detectProjectType, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, matchPatterns, protectedPathGuard, runGuards, securityGuard, solidReadGate };
3
+ import { a as freshnessGate, i as evaluateApex, n as brainstormGate, o as solidReadGate, r as docConsultedGate, t as APEX_GATES } from "../apex-BcJSE-VL.mjs";
4
+ export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, GUARDS, PHP_DECL_RE, PROJECT_INSTALL, PROJECT_INSTALL_RE, PROTECTED_FRAGMENTS, PY_MODEL_RE, SWIFT_PROTO_RE, SYSTEM_INSTALL, SYSTEM_INSTALL_RE, TS_DECL_RE, bashWriteGuard, brainstormGate, countLines, detectCreationIntent, detectFramework, detectProjectType, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, matchPatterns, protectedPathGuard, runGuards, securityGuard, solidReadGate };
@@ -30,4 +30,16 @@ function detectProjectType(dir) {
30
30
  return "generic";
31
31
  }
32
32
  //#endregion
33
- export { detectProjectType as n, isApexCommand as r, DEV_KEYWORDS as t };
33
+ //#region src/policy/creation-intent.ts
34
+ const CREATE_RE = /\b(?:create|implement|add|build|new|feature|component|generate|make|develop|scaffold)\b/i;
35
+ const SKIP_RE = /\b(?:fix|bug|debug|update|refactor|rename|move|delete|remove|commit|push|edit|modify|change)\b/i;
36
+ /**
37
+ * True when a prompt expresses creation intent (a new feature/component) and is
38
+ * not a fix/refactor — the signal that brainstorming should precede creation.
39
+ * The harness calls this on UserPromptSubmit, then `recordBrainstormRequired`.
40
+ */
41
+ function detectCreationIntent(prompt) {
42
+ return CREATE_RE.test(prompt) && !SKIP_RE.test(prompt);
43
+ }
44
+ //#endregion
45
+ export { isApexCommand as i, DEV_KEYWORDS as n, detectProjectType as r, detectCreationIntent as t };
@@ -56,6 +56,8 @@ declare function activityFor(event: ToolEvent): Activity | null;
56
56
  declare const REQUIRED_AGENTS: ReadonlyArray<string>;
57
57
  /** Default freshness window for {@link REQUIRED_AGENTS} (4 min, the APEX TTL). */
58
58
  declare const DEFAULT_WINDOW_MS = 24e4;
59
+ /** Trivial edits allowed within the window before the full APEX gates apply. */
60
+ declare const TRIVIAL_BUDGET = 4;
59
61
  /** A tool-use to gate, plus the session pointers needed for the stateful gates. */
60
62
  interface GateInput {
61
63
  sessionId: string;
@@ -68,11 +70,12 @@ interface GateInput {
68
70
  now: number;
69
71
  trackFile: string;
70
72
  windowMs?: number;
73
+ isReplaceAll?: boolean;
71
74
  }
72
75
  /**
73
- * Full gate: the stateless guards (file-size, git) first, then the stateful
74
- * APEX gates fed from the session track. Returns the first blocking prompt, or
75
- * null to allow. APEX gates apply only to code edits (a `filePath`).
76
+ * Full gate: the stateless guards (file-size, git, security...) first, then a
77
+ * trivial-edit fast path, then the stateful APEX gates fed from the session
78
+ * track. Returns the first blocking prompt, or null to allow.
76
79
  */
77
80
  declare function gate(input: GateInput): Promise<Prompt | null>;
78
81
  //#endregion
@@ -123,4 +126,4 @@ interface HandleOutcome {
123
126
  */
124
127
  declare function handleHook(id: string, payload: Record<string, unknown>, opts: HandleOptions): Promise<HandleOutcome>;
125
128
  //#endregion
126
- export { Activity, DEFAULT_WINDOW_MS, GateInput, HandleOptions, HandleOutcome, NormalizedEvent, REQUIRED_AGENTS, ToolEvent, activityFor, gate, handleHook, harnessTrackDir, normalizeEvent, recordActivity, respond, trackFile };
129
+ export { Activity, DEFAULT_WINDOW_MS, GateInput, HandleOptions, HandleOutcome, NormalizedEvent, REQUIRED_AGENTS, TRIVIAL_BUDGET, ToolEvent, activityFor, gate, handleHook, harnessTrackDir, normalizeEvent, recordActivity, respond, trackFile };
@@ -1,2 +1,2 @@
1
- import { a as trackFile, c as REQUIRED_AGENTS, i as recordActivity, l as gate, n as harnessTrackDir, o as normalizeEvent, r as respond, s as DEFAULT_WINDOW_MS, t as handleHook, u as activityFor } from "../handle-BUyS6NU6.mjs";
2
- export { DEFAULT_WINDOW_MS, REQUIRED_AGENTS, activityFor, gate, handleHook, harnessTrackDir, normalizeEvent, recordActivity, respond, trackFile };
1
+ import { a as trackFile, c as REQUIRED_AGENTS, d as activityFor, i as recordActivity, l as TRIVIAL_BUDGET, n as harnessTrackDir, o as normalizeEvent, r as respond, s as DEFAULT_WINDOW_MS, t as handleHook, u as gate } from "../handle-Cr0YQYz-.mjs";
2
+ export { DEFAULT_WINDOW_MS, REQUIRED_AGENTS, TRIVIAL_BUDGET, activityFor, gate, handleHook, harnessTrackDir, normalizeEvent, recordActivity, respond, trackFile };
@@ -5,7 +5,8 @@ function emptyTrack() {
5
5
  return {
6
6
  authorizations: {},
7
7
  refsRead: [],
8
- agents: []
8
+ agents: [],
9
+ trivialEdits: []
9
10
  };
10
11
  }
11
12
  /** Record a doc consultation (Context7/Exa) for a framework in this session. Immutable. */
@@ -34,20 +35,45 @@ function recordRefRead(track, path) {
34
35
  refsRead: [...track.refsRead, path]
35
36
  };
36
37
  }
37
- /** Record an agent/tool call with a timestamp. Immutable. */
38
- function recordAgent(track, name, ts) {
38
+ /** Record an agent/tool call with a timestamp + optional quality. Immutable. */
39
+ function recordAgent(track, name, ts, quality) {
40
+ const entry = quality ? {
41
+ name,
42
+ ts,
43
+ quality
44
+ } : {
45
+ name,
46
+ ts
47
+ };
39
48
  return {
40
49
  ...track,
41
- agents: [...track.agents, {
42
- name,
43
- ts
44
- }]
50
+ agents: [...track.agents, entry]
45
51
  };
46
52
  }
47
- /** True when ALL of `names` were called within `windowMs` before `now`. */
53
+ /** True when ALL of `names` ran within `windowMs` with non-insufficient quality. */
48
54
  function agentsFresh(track, names, windowMs, now) {
49
55
  const cutoff = now - windowMs;
50
- return names.every((n) => track.agents.some((a) => a.name === n && a.ts > cutoff));
56
+ return names.every((n) => track.agents.some((a) => a.name === n && a.ts > cutoff && a.quality !== "insufficient"));
57
+ }
58
+ /** Record a trivial edit timestamp (sliding window; old evicted). Immutable. */
59
+ function recordTrivialEdit(track, ts, windowMs, now) {
60
+ const cutoff = now - windowMs;
61
+ return {
62
+ ...track,
63
+ trivialEdits: [...(track.trivialEdits ?? []).filter((t) => t > cutoff), ts]
64
+ };
65
+ }
66
+ /** Count trivial edits within the sliding window. */
67
+ function trivialCount(track, windowMs, now) {
68
+ const cutoff = now - windowMs;
69
+ return (track.trivialEdits ?? []).filter((t) => t > cutoff).length;
70
+ }
71
+ /** Set the brainstorm-required flag (from creation-intent detection). Immutable. */
72
+ function recordBrainstormRequired(track, required) {
73
+ return {
74
+ ...track,
75
+ brainstormRequired: required
76
+ };
51
77
  }
52
78
  //#endregion
53
79
  //#region src/tracking/store.ts
@@ -60,4 +86,4 @@ async function saveTrack(file, track) {
60
86
  await writeJsonFile(file, track);
61
87
  }
62
88
  //#endregion
63
- export { recordAgent as a, emptyTrack as i, saveTrack as n, recordDoc as o, agentsFresh as r, recordRefRead as s, loadTrack as t };
89
+ export { recordAgent as a, recordRefRead as c, emptyTrack as i, recordTrivialEdit as l, saveTrack as n, recordBrainstormRequired as o, agentsFresh as r, recordDoc as s, loadTrack as t, trivialCount as u };
@@ -1,6 +1,8 @@
1
1
  import { t as AuthEntry } from "../doc-helpers-CG1nuf-c.mjs";
2
2
 
3
3
  //#region src/tracking/session-state.d.ts
4
+ /** Quality of a recorded agent call (the freshness gate ignores insufficient ones). */
5
+ type AgentQuality = "sufficient" | "insufficient";
4
6
  /** Recorded session activity that feeds the APEX gates. */
5
7
  interface SessionTrack {
6
8
  authorizations: Record<string, AuthEntry>;
@@ -8,7 +10,10 @@ interface SessionTrack {
8
10
  agents: {
9
11
  name: string;
10
12
  ts: number;
13
+ quality?: AgentQuality;
11
14
  }[];
15
+ trivialEdits: number[];
16
+ brainstormRequired?: boolean;
12
17
  }
13
18
  /** A fresh, empty track. */
14
19
  declare function emptyTrack(): SessionTrack;
@@ -16,10 +21,16 @@ declare function emptyTrack(): SessionTrack;
16
21
  declare function recordDoc(track: SessionTrack, framework: string, sessionId: string, source: string): SessionTrack;
17
22
  /** Record that a SOLID reference file was read (deduped). Immutable. */
18
23
  declare function recordRefRead(track: SessionTrack, path: string): SessionTrack;
19
- /** Record an agent/tool call with a timestamp. Immutable. */
20
- declare function recordAgent(track: SessionTrack, name: string, ts: number): SessionTrack;
21
- /** True when ALL of `names` were called within `windowMs` before `now`. */
24
+ /** Record an agent/tool call with a timestamp + optional quality. Immutable. */
25
+ declare function recordAgent(track: SessionTrack, name: string, ts: number, quality?: AgentQuality): SessionTrack;
26
+ /** True when ALL of `names` ran within `windowMs` with non-insufficient quality. */
22
27
  declare function agentsFresh(track: SessionTrack, names: string[], windowMs: number, now: number): boolean;
28
+ /** Record a trivial edit timestamp (sliding window; old evicted). Immutable. */
29
+ declare function recordTrivialEdit(track: SessionTrack, ts: number, windowMs: number, now: number): SessionTrack;
30
+ /** Count trivial edits within the sliding window. */
31
+ declare function trivialCount(track: SessionTrack, windowMs: number, now: number): number;
32
+ /** Set the brainstorm-required flag (from creation-intent detection). Immutable. */
33
+ declare function recordBrainstormRequired(track: SessionTrack, required: boolean): SessionTrack;
23
34
  //#endregion
24
35
  //#region src/tracking/store.d.ts
25
36
  /** Load a session track from a file (an empty track if absent/corrupt). */
@@ -27,4 +38,4 @@ declare function loadTrack(file: string): Promise<SessionTrack>;
27
38
  /** Persist a session track. */
28
39
  declare function saveTrack(file: string, track: SessionTrack): Promise<void>;
29
40
  //#endregion
30
- export { SessionTrack, agentsFresh, emptyTrack, loadTrack, recordAgent, recordDoc, recordRefRead, saveTrack };
41
+ export { AgentQuality, SessionTrack, agentsFresh, emptyTrack, loadTrack, recordAgent, recordBrainstormRequired, recordDoc, recordRefRead, recordTrivialEdit, saveTrack, trivialCount };
@@ -1,2 +1,2 @@
1
- import { a as recordAgent, i as emptyTrack, n as saveTrack, o as recordDoc, r as agentsFresh, s as recordRefRead, t as loadTrack } from "../store-BWvwnnf6.mjs";
2
- export { agentsFresh, emptyTrack, loadTrack, recordAgent, recordDoc, recordRefRead, saveTrack };
1
+ import { a as recordAgent, c as recordRefRead, i as emptyTrack, l as recordTrivialEdit, n as saveTrack, o as recordBrainstormRequired, r as agentsFresh, s as recordDoc, t as loadTrack, u as trivialCount } from "../store-gtbP-Bv9.mjs";
2
+ export { agentsFresh, emptyTrack, loadTrack, recordAgent, recordBrainstormRequired, recordDoc, recordRefRead, recordTrivialEdit, saveTrack, trivialCount };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusengine/harness",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
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",