@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.
- package/dist/apex-gGrHzvM2.mjs +47 -0
- package/dist/{index-BXBWKbL8.d.mts → index-BbJucvaG.d.mts} +6 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +3 -2
- package/dist/policy/index.d.mts +2 -2
- package/dist/policy/index.mjs +3 -2
- package/dist/{policy-DMpyaPZ_.mjs → policy-C_pXmeNB.mjs} +1 -36
- package/dist/runtime/index.d.mts +51 -0
- package/dist/runtime/index.mjs +51 -0
- package/dist/store-BWvwnnf6.mjs +63 -0
- package/dist/tracking/index.d.mts +30 -0
- package/dist/tracking/index.mjs +2 -0
- package/package.json +4 -2
|
@@ -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
|
-
/**
|
|
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,
|
|
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 {
|
|
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 {
|
|
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 };
|
package/dist/policy/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
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 };
|
package/dist/policy/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusengine/harness",
|
|
3
|
-
"version": "0.1.
|
|
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": {
|