@fusengine/harness 0.1.3 → 0.1.5

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.
@@ -0,0 +1,47 @@
1
+ import { r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-Dd_x1-tZ.mjs";
2
+ import { t as routeReferences } from "./router-Dj3AfgBE.mjs";
3
+ //#region src/policy/apex.ts
4
+ /** Gate: Context7 + Exa must have been consulted this session. */
5
+ const docConsultedGate = (ctx) => isDocConsulted(ctx.authorizations, ctx.sessionId) ? null : {
6
+ kind: "block",
7
+ title: "APEX: documentation not consulted",
8
+ reason: formatDocDeny(ctx.framework),
9
+ actions: ["Call mcp__context7__query-docs", "Call mcp__exa__web_search_exa"]
10
+ };
11
+ /** Gate: the routed SOLID references for this edit must have been read. */
12
+ const solidReadGate = (ctx) => {
13
+ if (!ctx.refs?.length) return null;
14
+ const routed = routeReferences(ctx.refs, ctx.filePath, ctx.content);
15
+ if (!routed) return null;
16
+ const read = new Set(ctx.refsRead ?? []);
17
+ const missing = routed.required.map((r) => r.meta.filePath).filter((p) => !read.has(p));
18
+ if (missing.length === 0) return null;
19
+ return {
20
+ kind: "block",
21
+ title: `APEX: read SOLID references for ${ctx.framework}`,
22
+ reason: `Read these before editing ${ctx.filePath}:`,
23
+ actions: missing
24
+ };
25
+ };
26
+ /** Gate: the required prior agents (explore + research) must have run within the window. */
27
+ const freshnessGate = (ctx) => ctx.agentsFresh === false ? {
28
+ kind: "block",
29
+ title: "APEX: explore + research required",
30
+ reason: `Run explore-codebase and research-expert (within the freshness window) before editing ${ctx.framework}.`,
31
+ actions: ["Launch the explore-codebase agent", "Launch the research-expert agent"]
32
+ } : null;
33
+ /** Default APEX gate chain (freshness, then docs, then SOLID refs). */
34
+ const APEX_GATES = [
35
+ freshnessGate,
36
+ docConsultedGate,
37
+ solidReadGate
38
+ ];
39
+ /**
40
+ * Run the APEX gates (chain-of-responsibility): the first failing gate's prompt
41
+ * wins; null means every gate passed (allow).
42
+ */
43
+ function evaluateApex(ctx, gates = APEX_GATES) {
44
+ return gates.reduce((hit, gate) => hit ?? gate(ctx), null);
45
+ }
46
+ //#endregion
47
+ export { solidReadGate as a, freshnessGate as i, docConsultedGate as n, evaluateApex as r, APEX_GATES as t };
@@ -96,6 +96,8 @@ interface ApexContext {
96
96
  refs?: RefMeta[];
97
97
  /** Absolute paths of SOLID refs already read this session. */
98
98
  refsRead?: string[];
99
+ /** Whether the required prior agents (explore + research) ran within the freshness window. */
100
+ agentsFresh?: boolean;
99
101
  }
100
102
  /** A single APEX gate: returns a blocking {@link Prompt}, or null to pass. */
101
103
  type ApexGate = (ctx: ApexContext) => Prompt | null;
@@ -103,7 +105,9 @@ type ApexGate = (ctx: ApexContext) => Prompt | null;
103
105
  declare const docConsultedGate: ApexGate;
104
106
  /** Gate: the routed SOLID references for this edit must have been read. */
105
107
  declare const solidReadGate: ApexGate;
106
- /** Default APEX gate chain. */
108
+ /** Gate: the required prior agents (explore + research) must have run within the window. */
109
+ declare const freshnessGate: ApexGate;
110
+ /** Default APEX gate chain (freshness, then docs, then SOLID refs). */
107
111
  declare const APEX_GATES: ReadonlyArray<ApexGate>;
108
112
  /**
109
113
  * Run the APEX gates (chain-of-responsibility): the first failing gate's prompt
@@ -111,4 +115,4 @@ declare const APEX_GATES: ReadonlyArray<ApexGate>;
111
115
  */
112
116
  declare function evaluateApex(ctx: ApexContext, gates?: ReadonlyArray<ApexGate>): Prompt | null;
113
117
  //#endregion
114
- export { isApexCommand as S, evaluateFileSize as _, evaluateApex as a, ProjectType as b, PolicyResult as c, GIT_BLOCKED as d, PROJECT_INSTALL as f, countLines as g, FileSizeVerdict as h, docConsultedGate as i, evaluate as l, matchPatterns as m, ApexContext as n, solidReadGate as o, SYSTEM_INSTALL as p, ApexGate as r, PolicyContext as s, APEX_GATES as t, GIT_ASK as u, detectFramework as v, detectProjectType as x, DEV_KEYWORDS as y };
118
+ export { isApexCommand as C, detectProjectType as S, countLines as _, evaluateApex as a, DEV_KEYWORDS as b, PolicyContext as c, GIT_ASK as d, GIT_BLOCKED as f, FileSizeVerdict as g, matchPatterns as h, docConsultedGate as i, PolicyResult as l, SYSTEM_INSTALL as m, ApexContext as n, freshnessGate as o, PROJECT_INSTALL as p, ApexGate as r, solidReadGate as s, APEX_GATES as t, evaluate as u, evaluateFileSize as v, ProjectType as x, detectFramework as y };
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 { S as isApexCommand, _ as evaluateFileSize, a as evaluateApex, b as ProjectType, c as PolicyResult, d as GIT_BLOCKED, f as PROJECT_INSTALL, g as countLines, h as FileSizeVerdict, i as docConsultedGate, l as evaluate, m as matchPatterns, n as ApexContext, o as solidReadGate, p as SYSTEM_INSTALL, r as ApexGate, s as PolicyContext, t as APEX_GATES, u as GIT_ASK, v as detectFramework, x as detectProjectType, y as DEV_KEYWORDS } from "./index-BXBWKbL8.mjs";
8
+ import { C as isApexCommand, S as detectProjectType, _ as countLines, a as evaluateApex, b as DEV_KEYWORDS, c as PolicyContext, d as GIT_ASK, f as GIT_BLOCKED, g as FileSizeVerdict, h as matchPatterns, i as docConsultedGate, l as PolicyResult, m as SYSTEM_INSTALL, n as ApexContext, o as freshnessGate, p as PROJECT_INSTALL, r as ApexGate, s as solidReadGate, t as APEX_GATES, u as evaluate, v as evaluateFileSize, x as ProjectType, y as detectFramework } from "./index-BbJucvaG.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 { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./index-C2Lz-cwJ.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, ApexContext, ApexGate, ApexState, ApexTask, ApexTaskFile, AuthEntry, COLOR_THRESHOLDS, ColorFn, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, DocSatisfactionStatus, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GRADIENT_BLOCKS, HarnessId, HarnessInfo, HarnessMode, HarnessVia, IndexSummary, MAX_LINES_ENV_KEY, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, Palette, PolicyContext, PolicyResult, ProgressBarOptions, ProjectType, Prompt, PromptKind, RefMeta, ReminderState, RouteResult, SYSTEM_INSTALL, ScoredRef, TIME_INTERVALS, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, colors, compactJson, compactMarkdown, countLines, detectFramework, detectHarness, detectMode, detectProjectType, docConsultedGate, ensureMemoryGitignore, ensureStateDir, evaluate, evaluateApex, evaluateFileSize, extractText, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, isApexCommand, isCodeFile, isDocConsulted, jaccardSimilar, loadIndex, loadState, matchPatterns, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectRoot, projectRootOrNull, queryHash, readRoots, readState, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, saveState, scoreReferences, setStateField, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, ttlLabel };
14
+ export { APEX_GATES, ApexContext, ApexGate, ApexState, ApexTask, ApexTaskFile, AuthEntry, COLOR_THRESHOLDS, ColorFn, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, DocSatisfactionStatus, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GRADIENT_BLOCKS, HarnessId, HarnessInfo, HarnessMode, HarnessVia, IndexSummary, MAX_LINES_ENV_KEY, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, Palette, PolicyContext, PolicyResult, ProgressBarOptions, ProjectType, Prompt, PromptKind, RefMeta, ReminderState, RouteResult, SYSTEM_INSTALL, ScoredRef, TIME_INTERVALS, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, 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, isApexCommand, isCodeFile, isDocConsulted, jaccardSimilar, loadIndex, loadState, matchPatterns, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectRoot, projectRootOrNull, queryHash, readRoots, readState, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, saveState, scoreReferences, setStateField, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, ttlLabel };
package/dist/index.mjs CHANGED
@@ -3,14 +3,15 @@ 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 { a as DEV_KEYWORDS, i as solidReadGate, n as docConsultedGate, o as detectProjectType, r as evaluateApex, s as isApexCommand, t as APEX_GATES } from "./policy-DMpyaPZ_.mjs";
6
+ import { n as detectProjectType, r as isApexCommand, t as DEV_KEYWORDS } from "./policy-C_pXmeNB.mjs";
7
7
  import { a as SYSTEM_INSTALL, c as evaluateFileSize, i as PROJECT_INSTALL, l as detectFramework, n as GIT_ASK, o as matchPatterns, r as GIT_BLOCKED, s as countLines, t as evaluate } from "./evaluate-CsYyUucy.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
11
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
11
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";
12
13
  import { a as jaccardSimilar, i as compactMarkdown, n as loadIndex, o as queryHash, r as summarizeIndex, t as extractText } from "./cache-DbPSJ9bC.mjs";
13
14
  import { t as incrementTrivialEditCounter } from "./freshness-BK9Xg6oG.mjs";
14
15
  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";
15
16
  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";
16
- export { APEX_GATES, COLOR_THRESHOLDS, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, GRADIENT_BLOCKS, MAX_LINES_ENV_KEY, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, SYSTEM_INSTALL, TIME_INTERVALS, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, colors, compactJson, compactMarkdown, countLines, detectFramework, detectHarness, detectMode, detectProjectType, docConsultedGate, ensureMemoryGitignore, ensureStateDir, evaluate, evaluateApex, evaluateFileSize, extractText, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, isApexCommand, isCodeFile, isDocConsulted, jaccardSimilar, loadIndex, loadState, matchPatterns, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectRoot, projectRootOrNull, queryHash, readRoots, readState, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, saveState, scoreReferences, setStateField, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, ttlLabel };
17
+ export { APEX_GATES, COLOR_THRESHOLDS, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, GRADIENT_BLOCKS, MAX_LINES_ENV_KEY, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INSTALL, SYSTEM_INSTALL, TIME_INTERVALS, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, 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, isApexCommand, isCodeFile, isDocConsulted, jaccardSimilar, loadIndex, loadState, matchPatterns, modeFor, nowStamp, parseEnvInt, parseFrontmatter, progressiveColor, projectRoot, projectRootOrNull, queryHash, readRoots, readState, registryFile, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, saveState, scoreReferences, setStateField, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, ttlLabel };
@@ -1,2 +1,2 @@
1
- import { S as isApexCommand, _ as evaluateFileSize, a as evaluateApex, b as ProjectType, c as PolicyResult, d as GIT_BLOCKED, f as PROJECT_INSTALL, g as countLines, h as FileSizeVerdict, i as docConsultedGate, l as evaluate, m as matchPatterns, n as ApexContext, o as solidReadGate, p as SYSTEM_INSTALL, r as ApexGate, s as PolicyContext, t as APEX_GATES, u as GIT_ASK, v as detectFramework, x as detectProjectType, y as DEV_KEYWORDS } from "../index-BXBWKbL8.mjs";
2
- export { APEX_GATES, ApexContext, ApexGate, DEV_KEYWORDS, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, PROJECT_INSTALL, PolicyContext, PolicyResult, ProjectType, SYSTEM_INSTALL, countLines, detectFramework, detectProjectType, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, isApexCommand, matchPatterns, solidReadGate };
1
+ import { C as isApexCommand, S as detectProjectType, _ as countLines, a as evaluateApex, b as DEV_KEYWORDS, c as PolicyContext, d as GIT_ASK, f as GIT_BLOCKED, g as FileSizeVerdict, h as matchPatterns, i as docConsultedGate, l as PolicyResult, m as SYSTEM_INSTALL, n as ApexContext, o as freshnessGate, p as PROJECT_INSTALL, r as ApexGate, s as solidReadGate, t as APEX_GATES, u as evaluate, v as evaluateFileSize, x as ProjectType, y as detectFramework } from "../index-BbJucvaG.mjs";
2
+ export { APEX_GATES, ApexContext, ApexGate, DEV_KEYWORDS, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, PROJECT_INSTALL, PolicyContext, PolicyResult, ProjectType, SYSTEM_INSTALL, countLines, detectFramework, detectProjectType, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, freshnessGate, isApexCommand, matchPatterns, solidReadGate };
@@ -1,3 +1,4 @@
1
- import { a as DEV_KEYWORDS, i as solidReadGate, n as docConsultedGate, o as detectProjectType, r as evaluateApex, s as isApexCommand, t as APEX_GATES } from "../policy-DMpyaPZ_.mjs";
1
+ import { n as detectProjectType, r as isApexCommand, t as DEV_KEYWORDS } from "../policy-C_pXmeNB.mjs";
2
2
  import { a as SYSTEM_INSTALL, c as evaluateFileSize, i as PROJECT_INSTALL, l as detectFramework, n as GIT_ASK, o as matchPatterns, r as GIT_BLOCKED, s as countLines, t as evaluate } from "../evaluate-CsYyUucy.mjs";
3
- export { APEX_GATES, DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, PROJECT_INSTALL, SYSTEM_INSTALL, countLines, detectFramework, detectProjectType, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, isApexCommand, matchPatterns, solidReadGate };
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, DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, PROJECT_INSTALL, SYSTEM_INSTALL, countLines, detectFramework, detectProjectType, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, freshnessGate, isApexCommand, matchPatterns, solidReadGate };
@@ -1,5 +1,3 @@
1
- import { r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-Dd_x1-tZ.mjs";
2
- import { t as routeReferences } from "./router-Dj3AfgBE.mjs";
3
1
  import { existsSync } from "node:fs";
4
2
  import { join } from "node:path";
5
3
  //#region src/policy/detect-project.ts
@@ -32,37 +30,4 @@ function detectProjectType(dir) {
32
30
  return "generic";
33
31
  }
34
32
  //#endregion
35
- //#region src/policy/apex.ts
36
- /** Gate: Context7 + Exa must have been consulted this session. */
37
- const docConsultedGate = (ctx) => isDocConsulted(ctx.authorizations, ctx.sessionId) ? null : {
38
- kind: "block",
39
- title: "APEX: documentation not consulted",
40
- reason: formatDocDeny(ctx.framework),
41
- actions: ["Call mcp__context7__query-docs", "Call mcp__exa__web_search_exa"]
42
- };
43
- /** Gate: the routed SOLID references for this edit must have been read. */
44
- const solidReadGate = (ctx) => {
45
- if (!ctx.refs?.length) return null;
46
- const routed = routeReferences(ctx.refs, ctx.filePath, ctx.content);
47
- if (!routed) return null;
48
- const read = new Set(ctx.refsRead ?? []);
49
- const missing = routed.required.map((r) => r.meta.filePath).filter((p) => !read.has(p));
50
- if (missing.length === 0) return null;
51
- return {
52
- kind: "block",
53
- title: `APEX: read SOLID references for ${ctx.framework}`,
54
- reason: `Read these before editing ${ctx.filePath}:`,
55
- actions: missing
56
- };
57
- };
58
- /** Default APEX gate chain. */
59
- const APEX_GATES = [docConsultedGate, solidReadGate];
60
- /**
61
- * Run the APEX gates (chain-of-responsibility): the first failing gate's prompt
62
- * wins; null means every gate passed (allow).
63
- */
64
- function evaluateApex(ctx, gates = APEX_GATES) {
65
- return gates.reduce((hit, gate) => hit ?? gate(ctx), null);
66
- }
67
- //#endregion
68
- export { DEV_KEYWORDS as a, solidReadGate as i, docConsultedGate as n, detectProjectType as o, evaluateApex as r, isApexCommand as s, APEX_GATES as t };
33
+ export { detectProjectType as n, isApexCommand as r, DEV_KEYWORDS as t };
@@ -0,0 +1,51 @@
1
+ import { t as Prompt } from "../types-D56jSgD9.mjs";
2
+ import { t as RefMeta } from "../types-CY5qT2X1.mjs";
3
+
4
+ //#region src/runtime/paths.d.ts
5
+ /** Path to a session's track file (under a per-tool base dir). */
6
+ declare function trackFile(sessionId: string, baseDir?: string): string;
7
+ //#endregion
8
+ //#region src/runtime/record.d.ts
9
+ /** A unit of session activity to record (discriminated union on `kind`). */
10
+ type Activity = {
11
+ kind: "agent";
12
+ name: string;
13
+ ts: number;
14
+ } | {
15
+ kind: "doc";
16
+ framework: string;
17
+ sessionId: string;
18
+ source: string;
19
+ } | {
20
+ kind: "ref";
21
+ path: string;
22
+ };
23
+ /** Apply an activity to a session's track and persist it (PostToolUse path). */
24
+ declare function recordActivity(file: string, activity: Activity): Promise<void>;
25
+ //#endregion
26
+ //#region src/runtime/gate.d.ts
27
+ /** Prior agents the freshness gate requires before a code edit. */
28
+ declare const REQUIRED_AGENTS: ReadonlyArray<string>;
29
+ /** Default freshness window for {@link REQUIRED_AGENTS} (4 min, the APEX TTL). */
30
+ declare const DEFAULT_WINDOW_MS = 24e4;
31
+ /** A tool-use to gate, plus the session pointers needed for the stateful gates. */
32
+ interface GateInput {
33
+ sessionId: string;
34
+ framework: string;
35
+ tool: string;
36
+ filePath?: string;
37
+ content?: string;
38
+ command?: string;
39
+ refs?: RefMeta[];
40
+ now: number;
41
+ trackFile: string;
42
+ windowMs?: number;
43
+ }
44
+ /**
45
+ * Full gate: the stateless guards (file-size, git) first, then the stateful
46
+ * APEX gates fed from the session track. Returns the first blocking prompt, or
47
+ * null to allow. APEX gates apply only to code edits (a `filePath`).
48
+ */
49
+ declare function gate(input: GateInput): Promise<Prompt | null>;
50
+ //#endregion
51
+ export { Activity, DEFAULT_WINDOW_MS, GateInput, REQUIRED_AGENTS, gate, recordActivity, trackFile };
@@ -0,0 +1,51 @@
1
+ import { t as evaluate } from "../evaluate-CsYyUucy.mjs";
2
+ import { r as evaluateApex } from "../apex-gGrHzvM2.mjs";
3
+ import { a as recordAgent, n as saveTrack, o as recordDoc, r as agentsFresh, s as recordRefRead, t as loadTrack } from "../store-BWvwnnf6.mjs";
4
+ import { join } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+ //#region src/runtime/paths.ts
7
+ /** Path to a session's track file (under a per-tool base dir). */
8
+ function trackFile(sessionId, baseDir = join(tmpdir(), "fuse-harness")) {
9
+ return join(baseDir, `track-${sessionId.replace(/[^A-Za-z0-9_-]/g, "_") || "default"}.json`);
10
+ }
11
+ //#endregion
12
+ //#region src/runtime/record.ts
13
+ /** Apply an activity to a session's track and persist it (PostToolUse path). */
14
+ async function recordActivity(file, activity) {
15
+ const track = await loadTrack(file);
16
+ await saveTrack(file, activity.kind === "agent" ? recordAgent(track, activity.name, activity.ts) : activity.kind === "doc" ? recordDoc(track, activity.framework, activity.sessionId, activity.source) : recordRefRead(track, activity.path));
17
+ }
18
+ //#endregion
19
+ //#region src/runtime/gate.ts
20
+ /** Prior agents the freshness gate requires before a code edit. */
21
+ const REQUIRED_AGENTS = ["explore-codebase", "research-expert"];
22
+ /** Default freshness window for {@link REQUIRED_AGENTS} (4 min, the APEX TTL). */
23
+ const DEFAULT_WINDOW_MS = 24e4;
24
+ /**
25
+ * Full gate: the stateless guards (file-size, git) first, then the stateful
26
+ * APEX gates fed from the session track. Returns the first blocking prompt, or
27
+ * null to allow. APEX gates apply only to code edits (a `filePath`).
28
+ */
29
+ async function gate(input) {
30
+ const quick = evaluate({
31
+ tool: input.tool,
32
+ filePath: input.filePath,
33
+ content: input.content,
34
+ command: input.command
35
+ });
36
+ if (quick.decision !== "allow" && quick.prompt) return quick.prompt;
37
+ if (!input.filePath) return null;
38
+ const track = await loadTrack(input.trackFile);
39
+ return evaluateApex({
40
+ sessionId: input.sessionId,
41
+ framework: input.framework,
42
+ filePath: input.filePath,
43
+ content: input.content ?? "",
44
+ authorizations: track.authorizations,
45
+ refs: input.refs,
46
+ refsRead: track.refsRead,
47
+ agentsFresh: agentsFresh(track, [...REQUIRED_AGENTS], input.windowMs ?? 24e4, input.now)
48
+ });
49
+ }
50
+ //#endregion
51
+ export { DEFAULT_WINDOW_MS, REQUIRED_AGENTS, gate, recordActivity, trackFile };
@@ -0,0 +1,63 @@
1
+ import { n as readJsonFile, r as writeJsonFile } from "./json-io-RH82El2J.mjs";
2
+ //#region src/tracking/session-state.ts
3
+ /** A fresh, empty track. */
4
+ function emptyTrack() {
5
+ return {
6
+ authorizations: {},
7
+ refsRead: [],
8
+ agents: []
9
+ };
10
+ }
11
+ /** Record a doc consultation (Context7/Exa) for a framework in this session. Immutable. */
12
+ function recordDoc(track, framework, sessionId, source) {
13
+ const prev = track.authorizations[framework] ?? {};
14
+ const sessions = new Set(prev.doc_sessions ?? []);
15
+ sessions.add(sessionId);
16
+ const sources = new Set(prev.sources ?? (prev.source ? [prev.source] : []));
17
+ sources.add(source);
18
+ return {
19
+ ...track,
20
+ authorizations: {
21
+ ...track.authorizations,
22
+ [framework]: {
23
+ ...prev,
24
+ doc_sessions: [...sessions],
25
+ sources: [...sources]
26
+ }
27
+ }
28
+ };
29
+ }
30
+ /** Record that a SOLID reference file was read (deduped). Immutable. */
31
+ function recordRefRead(track, path) {
32
+ return track.refsRead.includes(path) ? track : {
33
+ ...track,
34
+ refsRead: [...track.refsRead, path]
35
+ };
36
+ }
37
+ /** Record an agent/tool call with a timestamp. Immutable. */
38
+ function recordAgent(track, name, ts) {
39
+ return {
40
+ ...track,
41
+ agents: [...track.agents, {
42
+ name,
43
+ ts
44
+ }]
45
+ };
46
+ }
47
+ /** True when ALL of `names` were called within `windowMs` before `now`. */
48
+ function agentsFresh(track, names, windowMs, now) {
49
+ const cutoff = now - windowMs;
50
+ return names.every((n) => track.agents.some((a) => a.name === n && a.ts > cutoff));
51
+ }
52
+ //#endregion
53
+ //#region src/tracking/store.ts
54
+ /** Load a session track from a file (an empty track if absent/corrupt). */
55
+ async function loadTrack(file) {
56
+ return await readJsonFile(file) ?? emptyTrack();
57
+ }
58
+ /** Persist a session track. */
59
+ async function saveTrack(file, track) {
60
+ await writeJsonFile(file, track);
61
+ }
62
+ //#endregion
63
+ export { recordAgent as a, emptyTrack as i, saveTrack as n, recordDoc as o, agentsFresh as r, recordRefRead as s, loadTrack as t };
@@ -0,0 +1,30 @@
1
+ import { t as AuthEntry } from "../doc-helpers-CG1nuf-c.mjs";
2
+
3
+ //#region src/tracking/session-state.d.ts
4
+ /** Recorded session activity that feeds the APEX gates. */
5
+ interface SessionTrack {
6
+ authorizations: Record<string, AuthEntry>;
7
+ refsRead: string[];
8
+ agents: {
9
+ name: string;
10
+ ts: number;
11
+ }[];
12
+ }
13
+ /** A fresh, empty track. */
14
+ declare function emptyTrack(): SessionTrack;
15
+ /** Record a doc consultation (Context7/Exa) for a framework in this session. Immutable. */
16
+ declare function recordDoc(track: SessionTrack, framework: string, sessionId: string, source: string): SessionTrack;
17
+ /** Record that a SOLID reference file was read (deduped). Immutable. */
18
+ 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`. */
22
+ declare function agentsFresh(track: SessionTrack, names: string[], windowMs: number, now: number): boolean;
23
+ //#endregion
24
+ //#region src/tracking/store.d.ts
25
+ /** Load a session track from a file (an empty track if absent/corrupt). */
26
+ declare function loadTrack(file: string): Promise<SessionTrack>;
27
+ /** Persist a session track. */
28
+ declare function saveTrack(file: string, track: SessionTrack): Promise<void>;
29
+ //#endregion
30
+ export { SessionTrack, agentsFresh, emptyTrack, loadTrack, recordAgent, recordDoc, recordRefRead, saveTrack };
@@ -0,0 +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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusengine/harness",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
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",
@@ -23,6 +23,8 @@
23
23
  "./statusline": { "bun": "./src/statusline/index.ts", "types": "./dist/statusline/index.d.mts", "import": "./dist/statusline/index.mjs" },
24
24
  "./cli": { "bun": "./src/cli/index.ts", "types": "./dist/cli/index.d.mts", "import": "./dist/cli/index.mjs" },
25
25
  "./init": { "bun": "./src/init/index.ts", "types": "./dist/init/index.d.mts", "import": "./dist/init/index.mjs" },
26
+ "./tracking": { "bun": "./src/tracking/index.ts", "types": "./dist/tracking/index.d.mts", "import": "./dist/tracking/index.mjs" },
27
+ "./runtime": { "bun": "./src/runtime/index.ts", "types": "./dist/runtime/index.d.mts", "import": "./dist/runtime/index.mjs" },
26
28
  "./adapters/claude": { "bun": "./src/adapters/claude/index.ts", "types": "./dist/adapters/claude/index.d.mts", "import": "./dist/adapters/claude/index.mjs" },
27
29
  "./adapters/codex": { "bun": "./src/adapters/codex/index.ts", "types": "./dist/adapters/codex/index.d.mts", "import": "./dist/adapters/codex/index.mjs" },
28
30
  "./adapters/cursor": { "bun": "./src/adapters/cursor/index.ts", "types": "./dist/adapters/cursor/index.d.mts", "import": "./dist/adapters/cursor/index.mjs" },
@@ -35,7 +37,7 @@
35
37
  "scripts": {
36
38
  "test": "bun test",
37
39
  "typecheck": "tsc --noEmit",
38
- "build": "tsdown src/index.ts src/config/index.ts src/util/index.ts src/detect/index.ts src/policy/index.ts src/prompt/index.ts src/memory/index.ts src/cache/index.ts src/freshness/index.ts src/refs/index.ts src/state/index.ts src/statusline/index.ts src/cli/index.ts src/cli/bin.ts src/init/index.ts src/adapters/claude/index.ts src/adapters/codex/index.ts src/adapters/cursor/index.ts src/adapters/cline/index.ts src/adapters/gemini/index.ts --dts --format esm --clean --out-dir dist",
40
+ "build": "tsdown src/index.ts src/config/index.ts src/util/index.ts src/detect/index.ts src/policy/index.ts src/prompt/index.ts src/memory/index.ts src/cache/index.ts src/freshness/index.ts src/refs/index.ts src/state/index.ts src/statusline/index.ts src/cli/index.ts src/cli/bin.ts src/init/index.ts src/tracking/index.ts src/runtime/index.ts src/adapters/claude/index.ts src/adapters/codex/index.ts src/adapters/cursor/index.ts src/adapters/cline/index.ts src/adapters/gemini/index.ts --dts --format esm --clean --out-dir dist",
39
41
  "prepublishOnly": "bun test && tsc --noEmit && bun run build"
40
42
  },
41
43
  "publishConfig": {