@fusengine/harness 0.1.2 → 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.
- package/dist/{freshness-DzGoBKKj.mjs → doc-helpers-Dd_x1-tZ.mjs} +1 -23
- package/dist/freshness/index.mjs +2 -1
- package/dist/freshness-BK9Xg6oG.mjs +23 -0
- package/dist/{index-D7MkQNdc.d.mts → index-BbJucvaG.d.mts} +39 -1
- package/dist/{index-DqNKW8Ki.d.mts → index-C2Lz-cwJ.d.mts} +3 -26
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +5 -4
- package/dist/policy/index.d.mts +2 -2
- package/dist/policy/index.mjs +2 -2
- package/dist/policy-C4zmyZR-.mjs +79 -0
- package/dist/refs/index.d.mts +2 -1
- package/dist/refs/index.mjs +2 -1
- package/dist/refs-la_KkjCS.mjs +1 -0
- package/dist/tracking/index.d.mts +30 -0
- package/dist/tracking/index.mjs +63 -0
- package/dist/types-CY5qT2X1.d.mts +26 -0
- package/package.json +3 -2
- package/dist/policy-C_pXmeNB.mjs +0 -33
- /package/dist/{refs-Dj3AfgBE.mjs → router-Dj3AfgBE.mjs} +0 -0
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { n as readJsonFile, r as writeJsonFile, t as ensureDir } from "./json-io-RH82El2J.mjs";
|
|
2
|
-
import { dirname } from "node:path";
|
|
3
1
|
//#region src/freshness/doc-helpers.ts
|
|
4
2
|
/** Resolve the sessions array from an auth entry (legacy fallback). */
|
|
5
3
|
function resolveSessions(auth) {
|
|
@@ -41,24 +39,4 @@ function formatDocDeny(framework) {
|
|
|
41
39
|
].join("\n");
|
|
42
40
|
}
|
|
43
41
|
//#endregion
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Increment a session's trivial-edit counter, evicting timestamps older than
|
|
47
|
-
* `windowMs`. Decoupled + injectable `now` for testability.
|
|
48
|
-
* @param filePath - session state file path
|
|
49
|
-
* @param windowMs - sliding window in ms
|
|
50
|
-
* @param now - current epoch ms (defaults to `Date.now()`)
|
|
51
|
-
* @returns number of trivial edits within the window (including this one)
|
|
52
|
-
*/
|
|
53
|
-
async function incrementTrivialEditCounter(filePath, windowMs, now = Date.now()) {
|
|
54
|
-
await ensureDir(dirname(filePath));
|
|
55
|
-
const state = await readJsonFile(filePath) ?? {};
|
|
56
|
-
const cutoff = now - windowMs;
|
|
57
|
-
const edits = (state.trivial_edits ?? []).filter((ts) => ts > cutoff);
|
|
58
|
-
edits.push(now);
|
|
59
|
-
state.trivial_edits = edits;
|
|
60
|
-
await writeJsonFile(filePath, state);
|
|
61
|
-
return edits.length;
|
|
62
|
-
}
|
|
63
|
-
//#endregion
|
|
64
|
-
export { resolveSessions as a, isDocConsulted as i, formatDocDeny as n, formatDocSatisfactionStatus as r, incrementTrivialEditCounter as t };
|
|
42
|
+
export { resolveSessions as i, formatDocSatisfactionStatus as n, isDocConsulted as r, formatDocDeny as t };
|
package/dist/freshness/index.mjs
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "../doc-helpers-Dd_x1-tZ.mjs";
|
|
2
|
+
import { t as incrementTrivialEditCounter } from "../freshness-BK9Xg6oG.mjs";
|
|
2
3
|
export { formatDocDeny, formatDocSatisfactionStatus, incrementTrivialEditCounter, isDocConsulted, resolveSessions };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { n as readJsonFile, r as writeJsonFile, t as ensureDir } from "./json-io-RH82El2J.mjs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
//#region src/freshness/trivial-edit-counter.ts
|
|
4
|
+
/**
|
|
5
|
+
* Increment a session's trivial-edit counter, evicting timestamps older than
|
|
6
|
+
* `windowMs`. Decoupled + injectable `now` for testability.
|
|
7
|
+
* @param filePath - session state file path
|
|
8
|
+
* @param windowMs - sliding window in ms
|
|
9
|
+
* @param now - current epoch ms (defaults to `Date.now()`)
|
|
10
|
+
* @returns number of trivial edits within the window (including this one)
|
|
11
|
+
*/
|
|
12
|
+
async function incrementTrivialEditCounter(filePath, windowMs, now = Date.now()) {
|
|
13
|
+
await ensureDir(dirname(filePath));
|
|
14
|
+
const state = await readJsonFile(filePath) ?? {};
|
|
15
|
+
const cutoff = now - windowMs;
|
|
16
|
+
const edits = (state.trivial_edits ?? []).filter((ts) => ts > cutoff);
|
|
17
|
+
edits.push(now);
|
|
18
|
+
state.trivial_edits = edits;
|
|
19
|
+
await writeJsonFile(filePath, state);
|
|
20
|
+
return edits.length;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { incrementTrivialEditCounter as t };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { t as Prompt } from "./types-D56jSgD9.mjs";
|
|
2
|
+
import { t as AuthEntry } from "./doc-helpers-CG1nuf-c.mjs";
|
|
3
|
+
import { t as RefMeta } from "./types-CY5qT2X1.mjs";
|
|
2
4
|
|
|
3
5
|
//#region src/policy/detect-project.d.ts
|
|
4
6
|
/** Project types detected from filesystem indicators. */
|
|
@@ -77,4 +79,40 @@ interface PolicyResult {
|
|
|
77
79
|
*/
|
|
78
80
|
declare function evaluate(ctx: PolicyContext): PolicyResult;
|
|
79
81
|
//#endregion
|
|
80
|
-
|
|
82
|
+
//#region src/policy/apex.d.ts
|
|
83
|
+
/**
|
|
84
|
+
* Session context for the stateful APEX gates. The harness adapter supplies this
|
|
85
|
+
* (the package owns the gate LOGIC; recording the session activity is the
|
|
86
|
+
* adapter's tracking layer).
|
|
87
|
+
*/
|
|
88
|
+
interface ApexContext {
|
|
89
|
+
sessionId: string;
|
|
90
|
+
framework: string;
|
|
91
|
+
filePath: string;
|
|
92
|
+
content: string;
|
|
93
|
+
/** Doc-consultation authorizations from session state (Context7/Exa). */
|
|
94
|
+
authorizations?: Record<string, AuthEntry>;
|
|
95
|
+
/** Available SOLID references for the framework's skill. */
|
|
96
|
+
refs?: RefMeta[];
|
|
97
|
+
/** Absolute paths of SOLID refs already read this session. */
|
|
98
|
+
refsRead?: string[];
|
|
99
|
+
/** Whether the required prior agents (explore + research) ran within the freshness window. */
|
|
100
|
+
agentsFresh?: boolean;
|
|
101
|
+
}
|
|
102
|
+
/** A single APEX gate: returns a blocking {@link Prompt}, or null to pass. */
|
|
103
|
+
type ApexGate = (ctx: ApexContext) => Prompt | null;
|
|
104
|
+
/** Gate: Context7 + Exa must have been consulted this session. */
|
|
105
|
+
declare const docConsultedGate: ApexGate;
|
|
106
|
+
/** Gate: the routed SOLID references for this edit must have been read. */
|
|
107
|
+
declare const solidReadGate: ApexGate;
|
|
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). */
|
|
111
|
+
declare const APEX_GATES: ReadonlyArray<ApexGate>;
|
|
112
|
+
/**
|
|
113
|
+
* Run the APEX gates (chain-of-responsibility): the first failing gate's prompt
|
|
114
|
+
* wins; null means every gate passed (allow).
|
|
115
|
+
*/
|
|
116
|
+
declare function evaluateApex(ctx: ApexContext, gates?: ReadonlyArray<ApexGate>): Prompt | null;
|
|
117
|
+
//#endregion
|
|
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 };
|
|
@@ -1,28 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
interface RefMeta {
|
|
4
|
-
name: string;
|
|
5
|
-
description: string;
|
|
6
|
-
keywords: string;
|
|
7
|
-
priority: string;
|
|
8
|
-
related: string;
|
|
9
|
-
appliesTo: string;
|
|
10
|
-
triggerOnEdit: string;
|
|
11
|
-
level: string;
|
|
12
|
-
filePath: string;
|
|
13
|
-
}
|
|
14
|
-
/** A reference with its computed routing score. */
|
|
15
|
-
interface ScoredRef {
|
|
16
|
-
meta: RefMeta;
|
|
17
|
-
score: number;
|
|
18
|
-
}
|
|
19
|
-
/** Routing result with categorized references. */
|
|
20
|
-
interface RouteResult {
|
|
21
|
-
required: ScoredRef[];
|
|
22
|
-
optional: ScoredRef[];
|
|
23
|
-
skillPath: string;
|
|
24
|
-
}
|
|
25
|
-
//#endregion
|
|
1
|
+
import { n as RouteResult, r as ScoredRef, t as RefMeta } from "./types-CY5qT2X1.mjs";
|
|
2
|
+
|
|
26
3
|
//#region src/refs/frontmatter.d.ts
|
|
27
4
|
/** Extract frontmatter key/value pairs from markdown content (quotes stripped). */
|
|
28
5
|
declare function parseFrontmatter(content: string): Record<string, string>;
|
|
@@ -41,4 +18,4 @@ declare function scoreReferences(refs: RefMeta[], filePath: string, content: str
|
|
|
41
18
|
*/
|
|
42
19
|
declare function routeReferences(refs: RefMeta[], filePath: string, content: string, skillPath?: string): RouteResult | null;
|
|
43
20
|
//#endregion
|
|
44
|
-
export {
|
|
21
|
+
export { parseFrontmatter as i, scoreReferences as n, globToRe as r, routeReferences as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -5,9 +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
|
|
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
|
+
import { n as RouteResult, r as ScoredRef, t as RefMeta } from "./types-CY5qT2X1.mjs";
|
|
9
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";
|
|
10
|
-
import {
|
|
11
|
+
import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./index-C2Lz-cwJ.mjs";
|
|
11
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";
|
|
12
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";
|
|
13
|
-
export { 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, ensureMemoryGitignore, ensureStateDir, evaluate, 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, 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,13 +3,14 @@ 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
|
|
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
|
+
import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-Dd_x1-tZ.mjs";
|
|
9
|
+
import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-Dj3AfgBE.mjs";
|
|
8
10
|
import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
|
|
9
11
|
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";
|
|
10
12
|
import { a as jaccardSimilar, i as compactMarkdown, n as loadIndex, o as queryHash, r as summarizeIndex, t as extractText } from "./cache-DbPSJ9bC.mjs";
|
|
11
|
-
import {
|
|
12
|
-
import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./refs-Dj3AfgBE.mjs";
|
|
13
|
+
import { t as incrementTrivialEditCounter } from "./freshness-BK9Xg6oG.mjs";
|
|
13
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";
|
|
14
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";
|
|
15
|
-
export { 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, ensureMemoryGitignore, ensureStateDir, evaluate, 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, 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 };
|
package/dist/policy/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { DEV_KEYWORDS, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, PROJECT_INSTALL, PolicyContext, PolicyResult, ProjectType, SYSTEM_INSTALL, countLines, detectFramework, detectProjectType, evaluate, evaluateFileSize, isApexCommand, matchPatterns };
|
|
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,3 @@
|
|
|
1
|
-
import { n as
|
|
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 { DEV_KEYWORDS, GIT_ASK, GIT_BLOCKED, PROJECT_INSTALL, SYSTEM_INSTALL, countLines, detectFramework, detectProjectType, evaluate, evaluateFileSize, isApexCommand, matchPatterns };
|
|
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 };
|
|
@@ -0,0 +1,79 @@
|
|
|
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
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
//#region src/policy/detect-project.ts
|
|
6
|
+
/** Keywords that signal a development task (APEX trigger). */
|
|
7
|
+
const DEV_KEYWORDS = /\b(implement|create|build|fix|add|refactor|develop|feature|bug|update|modify|change|write|code)\b/i;
|
|
8
|
+
/** True when the prompt invokes the /apex command. */
|
|
9
|
+
function isApexCommand(prompt) {
|
|
10
|
+
return /(?:^|\s)\/apex|\/fuse-ai-pilot:apex/i.test(prompt);
|
|
11
|
+
}
|
|
12
|
+
/** Detect the project type by scanning config files in `dir`. */
|
|
13
|
+
function detectProjectType(dir) {
|
|
14
|
+
const has = (f) => existsSync(join(dir, f));
|
|
15
|
+
if (has("next.config.js") || has("next.config.ts") || has("next.config.mjs")) return "nextjs";
|
|
16
|
+
if (has("nuxt.config.ts") || has("nuxt.config.js")) return "nuxt";
|
|
17
|
+
if (has("angular.json")) return "angular";
|
|
18
|
+
if (has("svelte.config.js") || has("svelte.config.ts")) return "svelte";
|
|
19
|
+
if (has("vite.config.ts") && has("src/App.vue")) return "vue";
|
|
20
|
+
if (has("vite.config.ts") || has("vite.config.js")) return "react";
|
|
21
|
+
if (has("tailwind.config.js") || has("tailwind.config.ts")) return "tailwind";
|
|
22
|
+
if (has("composer.json") && has("artisan")) return "laravel";
|
|
23
|
+
if (has("Gemfile") && has("config/routes.rb")) return "rails";
|
|
24
|
+
if (has("requirements.txt") || has("pyproject.toml") || has("setup.py")) return has("manage.py") ? "django" : "python";
|
|
25
|
+
if (has("go.mod")) return "go";
|
|
26
|
+
if (has("Cargo.toml")) return "rust";
|
|
27
|
+
if (has("Package.swift")) return "swift";
|
|
28
|
+
if (has("pom.xml") || has("build.gradle") || has("build.gradle.kts")) return "java";
|
|
29
|
+
if (has("build.sbt")) return "scala";
|
|
30
|
+
if (has("mix.exs")) return "elixir";
|
|
31
|
+
if (has("Gemfile")) return "ruby";
|
|
32
|
+
return "generic";
|
|
33
|
+
}
|
|
34
|
+
//#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
|
+
/** 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
|
+
];
|
|
71
|
+
/**
|
|
72
|
+
* Run the APEX gates (chain-of-responsibility): the first failing gate's prompt
|
|
73
|
+
* wins; null means every gate passed (allow).
|
|
74
|
+
*/
|
|
75
|
+
function evaluateApex(ctx, gates = APEX_GATES) {
|
|
76
|
+
return gates.reduce((hit, gate) => hit ?? gate(ctx), null);
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
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 };
|
package/dist/refs/index.d.mts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as RouteResult, r as ScoredRef, t as RefMeta } from "../types-CY5qT2X1.mjs";
|
|
2
|
+
import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "../index-C2Lz-cwJ.mjs";
|
|
2
3
|
export { RefMeta, RouteResult, ScoredRef, globToRe, parseFrontmatter, routeReferences, scoreReferences };
|
package/dist/refs/index.mjs
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "../
|
|
1
|
+
import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "../router-Dj3AfgBE.mjs";
|
|
2
|
+
import "../refs-la_KkjCS.mjs";
|
|
2
3
|
export { globToRe, parseFrontmatter, routeReferences, scoreReferences };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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 };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/refs/types.d.ts
|
|
2
|
+
/** Parsed frontmatter metadata from a reference .md file. */
|
|
3
|
+
interface RefMeta {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
keywords: string;
|
|
7
|
+
priority: string;
|
|
8
|
+
related: string;
|
|
9
|
+
appliesTo: string;
|
|
10
|
+
triggerOnEdit: string;
|
|
11
|
+
level: string;
|
|
12
|
+
filePath: string;
|
|
13
|
+
}
|
|
14
|
+
/** A reference with its computed routing score. */
|
|
15
|
+
interface ScoredRef {
|
|
16
|
+
meta: RefMeta;
|
|
17
|
+
score: number;
|
|
18
|
+
}
|
|
19
|
+
/** Routing result with categorized references. */
|
|
20
|
+
interface RouteResult {
|
|
21
|
+
required: ScoredRef[];
|
|
22
|
+
optional: ScoredRef[];
|
|
23
|
+
skillPath: string;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { RouteResult as n, ScoredRef as r, RefMeta as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusengine/harness",
|
|
3
|
-
"version": "0.1.
|
|
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": {
|
package/dist/policy-C_pXmeNB.mjs
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
//#region src/policy/detect-project.ts
|
|
4
|
-
/** Keywords that signal a development task (APEX trigger). */
|
|
5
|
-
const DEV_KEYWORDS = /\b(implement|create|build|fix|add|refactor|develop|feature|bug|update|modify|change|write|code)\b/i;
|
|
6
|
-
/** True when the prompt invokes the /apex command. */
|
|
7
|
-
function isApexCommand(prompt) {
|
|
8
|
-
return /(?:^|\s)\/apex|\/fuse-ai-pilot:apex/i.test(prompt);
|
|
9
|
-
}
|
|
10
|
-
/** Detect the project type by scanning config files in `dir`. */
|
|
11
|
-
function detectProjectType(dir) {
|
|
12
|
-
const has = (f) => existsSync(join(dir, f));
|
|
13
|
-
if (has("next.config.js") || has("next.config.ts") || has("next.config.mjs")) return "nextjs";
|
|
14
|
-
if (has("nuxt.config.ts") || has("nuxt.config.js")) return "nuxt";
|
|
15
|
-
if (has("angular.json")) return "angular";
|
|
16
|
-
if (has("svelte.config.js") || has("svelte.config.ts")) return "svelte";
|
|
17
|
-
if (has("vite.config.ts") && has("src/App.vue")) return "vue";
|
|
18
|
-
if (has("vite.config.ts") || has("vite.config.js")) return "react";
|
|
19
|
-
if (has("tailwind.config.js") || has("tailwind.config.ts")) return "tailwind";
|
|
20
|
-
if (has("composer.json") && has("artisan")) return "laravel";
|
|
21
|
-
if (has("Gemfile") && has("config/routes.rb")) return "rails";
|
|
22
|
-
if (has("requirements.txt") || has("pyproject.toml") || has("setup.py")) return has("manage.py") ? "django" : "python";
|
|
23
|
-
if (has("go.mod")) return "go";
|
|
24
|
-
if (has("Cargo.toml")) return "rust";
|
|
25
|
-
if (has("Package.swift")) return "swift";
|
|
26
|
-
if (has("pom.xml") || has("build.gradle") || has("build.gradle.kts")) return "java";
|
|
27
|
-
if (has("build.sbt")) return "scala";
|
|
28
|
-
if (has("mix.exs")) return "elixir";
|
|
29
|
-
if (has("Gemfile")) return "ruby";
|
|
30
|
-
return "generic";
|
|
31
|
-
}
|
|
32
|
-
//#endregion
|
|
33
|
-
export { detectProjectType as n, isApexCommand as r, DEV_KEYWORDS as t };
|
|
File without changes
|