@fusengine/harness 0.1.3 → 0.1.4

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.
@@ -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,7 +3,7 @@ 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 { a as solidReadGate, c as isApexCommand, i as freshnessGate, n as docConsultedGate, o as DEV_KEYWORDS, r as evaluateApex, s as detectProjectType, t as APEX_GATES } from "./policy-C4zmyZR-.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";
@@ -13,4 +13,4 @@ import { a as jaccardSimilar, i as compactMarkdown, n as loadIndex, o as queryHa
13
13
  import { t as incrementTrivialEditCounter } from "./freshness-BK9Xg6oG.mjs";
14
14
  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
15
  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 };
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, 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,3 @@
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 { a as solidReadGate, c as isApexCommand, i as freshnessGate, n as docConsultedGate, o as DEV_KEYWORDS, r as evaluateApex, s as detectProjectType, t as APEX_GATES } from "../policy-C4zmyZR-.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
+ export { APEX_GATES, DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, PROJECT_INSTALL, SYSTEM_INSTALL, countLines, detectFramework, detectProjectType, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, freshnessGate, isApexCommand, matchPatterns, solidReadGate };
@@ -55,8 +55,19 @@ const solidReadGate = (ctx) => {
55
55
  actions: missing
56
56
  };
57
57
  };
58
- /** Default APEX gate chain. */
59
- const APEX_GATES = [docConsultedGate, solidReadGate];
58
+ /** Gate: the required prior agents (explore + research) must have run within the window. */
59
+ const freshnessGate = (ctx) => ctx.agentsFresh === false ? {
60
+ kind: "block",
61
+ title: "APEX: explore + research required",
62
+ reason: `Run explore-codebase and research-expert (within the freshness window) before editing ${ctx.framework}.`,
63
+ actions: ["Launch the explore-codebase agent", "Launch the research-expert agent"]
64
+ } : null;
65
+ /** Default APEX gate chain (freshness, then docs, then SOLID refs). */
66
+ const APEX_GATES = [
67
+ freshnessGate,
68
+ docConsultedGate,
69
+ solidReadGate
70
+ ];
60
71
  /**
61
72
  * Run the APEX gates (chain-of-responsibility): the first failing gate's prompt
62
73
  * wins; null means every gate passed (allow).
@@ -65,4 +76,4 @@ function evaluateApex(ctx, gates = APEX_GATES) {
65
76
  return gates.reduce((hit, gate) => hit ?? gate(ctx), null);
66
77
  }
67
78
  //#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 };
79
+ export { solidReadGate as a, isApexCommand as c, freshnessGate as i, docConsultedGate as n, DEV_KEYWORDS as o, evaluateApex as r, detectProjectType as s, APEX_GATES 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,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 { 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.4",
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,7 @@
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" },
26
27
  "./adapters/claude": { "bun": "./src/adapters/claude/index.ts", "types": "./dist/adapters/claude/index.d.mts", "import": "./dist/adapters/claude/index.mjs" },
27
28
  "./adapters/codex": { "bun": "./src/adapters/codex/index.ts", "types": "./dist/adapters/codex/index.d.mts", "import": "./dist/adapters/codex/index.mjs" },
28
29
  "./adapters/cursor": { "bun": "./src/adapters/cursor/index.ts", "types": "./dist/adapters/cursor/index.d.mts", "import": "./dist/adapters/cursor/index.mjs" },
@@ -35,7 +36,7 @@
35
36
  "scripts": {
36
37
  "test": "bun test",
37
38
  "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",
39
+ "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/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
40
  "prepublishOnly": "bun test && tsc --noEmit && bun run build"
40
41
  },
41
42
  "publishConfig": {