@fusengine/harness 0.1.40 → 0.1.41
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/README.md +7 -4
- package/dist/cli/bin.mjs +67 -4
- package/dist/{doc-helpers-B4XYL1v8.mjs → doc-helpers-BhzDmJ18.mjs} +2 -2
- package/dist/freshness/index.mjs +1 -1
- package/dist/{handle-gYSq5znf.mjs → handle-VhWQxvyN.mjs} +30 -15
- package/dist/index.mjs +2 -2
- package/dist/policy/index.mjs +1 -1
- package/dist/runtime/index.d.mts +1 -1
- package/dist/runtime/index.mjs +1 -1
- package/dist/{validate-BCRqp9XG.mjs → validate-B3wkqEoN.mjs} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,7 +26,9 @@ bun add @fusengine/harness # Bun reads the TS source directly — no build
|
|
|
26
26
|
```sh
|
|
27
27
|
cd your-project
|
|
28
28
|
harness init # detects the harness, writes its pre+post hooks
|
|
29
|
-
|
|
29
|
+
# The SOLID-read gate auto-activates from discovered skills (default marketplace: fusengine-plugins).
|
|
30
|
+
export FUSE_HARNESS_MARKETPLACES=fusengine-plugins # (optional) which marketplaces to auto-scan
|
|
31
|
+
export FUSE_HARNESS_REFS=.claude/skills # (optional) explicit refs dir, overrides auto-discovery
|
|
30
32
|
```
|
|
31
33
|
|
|
32
34
|
That's it. `init` writes the wiring file for the detected harness
|
|
@@ -65,8 +67,8 @@ Ten portable guards + the APEX gate chain, all evaluated before a tool runs:
|
|
|
65
67
|
| interface-separation | top-level interface/type/protocol in a component/controller |
|
|
66
68
|
| protected-path | edits to `.claude/plugins\|logs\|cache`, `.git/` |
|
|
67
69
|
| APEX freshness | `explore-codebase` + `research-expert` not run within the window |
|
|
68
|
-
| APEX doc-consulted | Context7
|
|
69
|
-
| APEX solid-read | required SOLID refs (
|
|
70
|
+
| APEX doc-consulted | no doc source (Context7 / Exa / fuse-browser / WebSearch / WebFetch) consulted this session |
|
|
71
|
+
| APEX solid-read | required SOLID refs (auto-discovered, or `FUSE_HARNESS_REFS`) not read |
|
|
70
72
|
| brainstorm | creating a new file without brainstorming (when flagged) |
|
|
71
73
|
| MCP verbosity / cache | caps exa `numResults`; serves a fresh cached MCP/WebFetch result |
|
|
72
74
|
|
|
@@ -78,7 +80,8 @@ through per window without the full APEX gates.
|
|
|
78
80
|
| Var | Effect |
|
|
79
81
|
|---|---|
|
|
80
82
|
| `FUSE_SOLID_MAX_LINES` | SOLID file-size limit (default `100`). |
|
|
81
|
-
| `FUSE_HARNESS_REFS` |
|
|
83
|
+
| `FUSE_HARNESS_REFS` | Explicit `path.delimiter`-list of `.md` SOLID-reference dirs → activates `solidReadGate`. Overrides auto-discovery. |
|
|
84
|
+
| `FUSE_HARNESS_MARKETPLACES` | Comma-list of marketplace names whose `solid-*` skill refs are auto-discovered when `FUSE_HARNESS_REFS` is unset (default `fusengine-plugins`; an absent marketplace contributes nothing). Standalone `.claude`/`.codex`/`.cursor`/`.agents` skills are always scanned. |
|
|
82
85
|
| `FUSE_ENFORCE_TTL_SEC` | APEX freshness window in seconds. |
|
|
83
86
|
| `FUSE_LESSONS_THROTTLE_MIN` | Lessons-injection throttle (memory module). |
|
|
84
87
|
|
package/dist/cli/bin.mjs
CHANGED
|
@@ -4,9 +4,9 @@ import { r as loadDotenv } from "../dotenv-DGyLln7U.mjs";
|
|
|
4
4
|
import { t as detectHarness } from "../harness-C8Nxxyn_.mjs";
|
|
5
5
|
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-D-Ydrw3D.mjs";
|
|
6
6
|
import { n as writeInitFile, t as initFor } from "../run-Do2JltgU.mjs";
|
|
7
|
-
import { Ot as todayUtc, kt as claudeHome, t as handleHook } from "../handle-
|
|
8
|
-
import { join } from "node:path";
|
|
9
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { Ot as todayUtc, kt as claudeHome, t as handleHook } from "../handle-VhWQxvyN.mjs";
|
|
8
|
+
import { delimiter, join } from "node:path";
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
//#region src/changelog/fetch.ts
|
|
12
12
|
/**
|
|
@@ -76,6 +76,67 @@ async function scanChangelog(now = Date.now(), home = homedir()) {
|
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
//#endregion
|
|
79
|
+
//#region src/refs/discover.ts
|
|
80
|
+
/** Immediate subdirectory names of `p`, or `[]` when it is missing/inaccessible. */
|
|
81
|
+
function subdirs(p) {
|
|
82
|
+
try {
|
|
83
|
+
return readdirSync(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
84
|
+
} catch {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Every `skills/` parent dir across the Open-Agent-Skills layouts
|
|
90
|
+
* (agentskills.io) of Claude Code, Codex and Cursor: the standalone skill roots
|
|
91
|
+
* (`<base>/{.claude,.codex,.cursor,.agents}/skills` + `/etc/codex/skills`) plus
|
|
92
|
+
* installed-plugin roots (`<plugin>/skills` under the Claude marketplace and the
|
|
93
|
+
* Claude/Codex version caches). Shallow `readdir` only — no deep walk — so it is
|
|
94
|
+
* cheap enough to run on every hook.
|
|
95
|
+
*/
|
|
96
|
+
function skillParents(home, cwd, marketplaces) {
|
|
97
|
+
const out = [];
|
|
98
|
+
for (const base of [cwd, home]) for (const tool of [
|
|
99
|
+
".claude",
|
|
100
|
+
".codex",
|
|
101
|
+
".cursor",
|
|
102
|
+
".agents"
|
|
103
|
+
]) out.push(join(base, tool, "skills"));
|
|
104
|
+
out.push(join("/etc", "codex", "skills"));
|
|
105
|
+
const mktRoot = join(home, ".claude", "plugins", "marketplaces");
|
|
106
|
+
for (const mkt of subdirs(mktRoot)) {
|
|
107
|
+
if (!marketplaces.includes(mkt)) continue;
|
|
108
|
+
const pluginsDir = join(mktRoot, mkt, "plugins");
|
|
109
|
+
for (const plugin of subdirs(pluginsDir)) out.push(join(pluginsDir, plugin, "skills"));
|
|
110
|
+
}
|
|
111
|
+
for (const cacheRoot of [join(home, ".claude", "plugins", "cache"), join(home, ".codex", "plugins", "cache")]) for (const mkt of subdirs(cacheRoot)) {
|
|
112
|
+
if (!marketplaces.includes(mkt)) continue;
|
|
113
|
+
for (const plugin of subdirs(join(cacheRoot, mkt))) for (const ver of subdirs(join(cacheRoot, mkt, plugin))) out.push(join(cacheRoot, mkt, plugin, ver, "skills"));
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Auto-discover SOLID reference dirs (`<skill>/references` for every `solid-*`
|
|
119
|
+
* skill) across the Claude/Codex/Cursor skill layouts — the fallback used when
|
|
120
|
+
* `FUSE_HARNESS_REFS` is unset. Deduped by skill name (first source wins, so a
|
|
121
|
+
* marketplace skill shadows its version-cache copy). Returns a path-delimiter
|
|
122
|
+
* list, or `""` when none is found — with no refs the SOLID-read gate stays off.
|
|
123
|
+
* @param home - User home dir (`os.homedir()`).
|
|
124
|
+
* @param cwd - Current project dir (`process.cwd()`).
|
|
125
|
+
* @param marketplaces - Allowlist of marketplace names to scan (env
|
|
126
|
+
* `FUSE_HARNESS_MARKETPLACES`, default `["fusengine-plugins"]`); a marketplace
|
|
127
|
+
* absent from disk simply contributes nothing. Standalone
|
|
128
|
+
* `.claude`/`.codex`/`.cursor`/`.agents` skill roots are always scanned.
|
|
129
|
+
* @returns A `path.delimiter`-joined list of `references` dirs, or `""`.
|
|
130
|
+
*/
|
|
131
|
+
function discoverRefs(home, cwd, marketplaces) {
|
|
132
|
+
const bySkill = /* @__PURE__ */ new Map();
|
|
133
|
+
for (const parent of skillParents(home, cwd, marketplaces)) for (const skill of subdirs(parent)) {
|
|
134
|
+
if (!skill.startsWith("solid-") || bySkill.has(skill)) continue;
|
|
135
|
+
if (subdirs(join(parent, skill)).includes("references")) bySkill.set(skill, join(parent, skill, "references"));
|
|
136
|
+
}
|
|
137
|
+
return [...bySkill.values()].join(delimiter);
|
|
138
|
+
}
|
|
139
|
+
//#endregion
|
|
79
140
|
//#region src/cli/bin.ts
|
|
80
141
|
/**
|
|
81
142
|
* harness — CLI for @fusengine/harness.
|
|
@@ -112,10 +173,12 @@ if (cmd === "hook") {
|
|
|
112
173
|
"seo",
|
|
113
174
|
"memory"
|
|
114
175
|
])).has(scopeArg) ? scopeArg : "core";
|
|
176
|
+
const marketplaces = (process.env.FUSE_HARNESS_MARKETPLACES ?? "fusengine-plugins").split(",").map((s) => s.trim()).filter(Boolean);
|
|
177
|
+
const refsDir = process.env.FUSE_HARNESS_REFS || discoverRefs(homedir(), process.cwd(), marketplaces) || void 0;
|
|
115
178
|
const outcome = await handleHook(id, await readStdin(), {
|
|
116
179
|
now: Date.now(),
|
|
117
180
|
cwd: process.cwd(),
|
|
118
|
-
refsDir
|
|
181
|
+
refsDir,
|
|
119
182
|
windowMs: resolveTtlSec(process.env) * 1e3,
|
|
120
183
|
scope
|
|
121
184
|
});
|
|
@@ -13,7 +13,7 @@ function evaluateDoc(auths) {
|
|
|
13
13
|
const readPaths = auths.flatMap((a) => a.read_paths ?? []);
|
|
14
14
|
const liveC7 = sources.some((s) => /context7/i.test(s));
|
|
15
15
|
const liveExa = sources.some((s) => /exa/i.test(s));
|
|
16
|
-
const liveWeb = sources.some((s) => /web(search|fetch)/i.test(s));
|
|
16
|
+
const liveWeb = sources.some((s) => /web(search|fetch)|fuse-browser/i.test(s));
|
|
17
17
|
const cacheC7 = readPaths.some((p) => /\/context\/mcp\/context7-/.test(p));
|
|
18
18
|
const cacheExa = readPaths.some((p) => /\/context\/mcp\/(exa-search|exa-code-context)-/.test(p));
|
|
19
19
|
return {
|
|
@@ -36,7 +36,7 @@ function formatDocSatisfactionStatus(authorizations, sessionId) {
|
|
|
36
36
|
function formatDocDeny(framework) {
|
|
37
37
|
return [
|
|
38
38
|
`APEX: Online documentation not consulted for ${framework}!`,
|
|
39
|
-
"Use ANY ONE of: mcp__context7__query-docs, mcp__exa__web_search_exa, WebSearch, or WebFetch.",
|
|
39
|
+
"Use ANY ONE of: mcp__context7__query-docs, mcp__exa__web_search_exa (or — if Exa is down — mcp__fuse-browser__browser_fetch / browser_crawl / browser_serp_batch), WebSearch, or WebFetch.",
|
|
40
40
|
"This check is once per session — after consulting one source, Write/Edit will be allowed."
|
|
41
41
|
].join("\n");
|
|
42
42
|
}
|
package/dist/freshness/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "../doc-helpers-
|
|
1
|
+
import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "../doc-helpers-BhzDmJ18.mjs";
|
|
2
2
|
import { t as incrementTrivialEditCounter } from "../freshness-43gxYpiX.mjs";
|
|
3
3
|
export { formatDocDeny, formatDocSatisfactionStatus, incrementTrivialEditCounter, isDocConsulted, resolveSessions };
|
|
@@ -3,9 +3,9 @@ import { r as projectLayout } from "./layout-C0jaaCQC.mjs";
|
|
|
3
3
|
import { t as HOME_DIR } from "./dotenv-DGyLln7U.mjs";
|
|
4
4
|
import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
|
|
5
5
|
import { t as detectHarness } from "./harness-C8Nxxyn_.mjs";
|
|
6
|
-
import { A as evaluateApex, E as detectCreationIntent, L as requiredArchSkill, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, l as parseField, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS$1 } from "./validate-
|
|
6
|
+
import { A as evaluateApex, E as detectCreationIntent, L as requiredArchSkill, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, l as parseField, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS$1 } from "./validate-B3wkqEoN.mjs";
|
|
7
7
|
import { N as detectFramework, j as countLines, n as FAIL_CLOSED, t as evaluate } from "./evaluate-B1n1ti0N.mjs";
|
|
8
|
-
import { r as isDocConsulted } from "./doc-helpers-
|
|
8
|
+
import { r as isDocConsulted } from "./doc-helpers-BhzDmJ18.mjs";
|
|
9
9
|
import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
|
|
10
10
|
import { a as nowStamp, l as throttleMs, n as readRoots, o as readState, s as setStateField, t as addRoot } from "./registry-BkoEbdec.mjs";
|
|
11
11
|
import { c as extractText, i as cacheLookupSubstring, l as loadIndex, n as webfetchCacheWrite, r as cacheLookup, t as mcpCacheWrite } from "./mcp-store-CDUVqtJ0.mjs";
|
|
@@ -206,6 +206,20 @@ function agentActivity(name, ts, quality) {
|
|
|
206
206
|
};
|
|
207
207
|
}
|
|
208
208
|
/**
|
|
209
|
+
* The documentation source a tool satisfies for the doc-consultation gate, or
|
|
210
|
+
* undefined. Context7/Exa are the primary sources; fuse-browser is the fallback
|
|
211
|
+
* when Exa is down (`browser_fetch`/`browser_crawl`/`browser_serp_batch`); the
|
|
212
|
+
* built-in WebSearch/WebFetch also count.
|
|
213
|
+
* @param tool - The harness tool name.
|
|
214
|
+
*/
|
|
215
|
+
function docSourceOf$1(tool) {
|
|
216
|
+
if (/context7/i.test(tool)) return "context7";
|
|
217
|
+
if (/exa/i.test(tool)) return "exa";
|
|
218
|
+
if (/browser_(fetch|crawl|serp)/i.test(tool)) return "fuse-browser";
|
|
219
|
+
if (tool === "WebSearch") return "websearch";
|
|
220
|
+
if (tool === "WebFetch") return "webfetch";
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
209
223
|
* Map a live tool-use to the activity to record, or null when nothing is
|
|
210
224
|
* tracked. Works across harnesses — tool names are globally distinct:
|
|
211
225
|
* - MCP doc calls (`context7` / `exa`, any separator) → `doc`
|
|
@@ -215,30 +229,31 @@ function agentActivity(name, ts, quality) {
|
|
|
215
229
|
* - a read tool opening a `.md` reference → `ref`
|
|
216
230
|
*/
|
|
217
231
|
function activityFor(event) {
|
|
218
|
-
|
|
232
|
+
const out = [];
|
|
233
|
+
const docSource = docSourceOf$1(event.tool);
|
|
234
|
+
if (docSource) out.push({
|
|
219
235
|
kind: "doc",
|
|
220
236
|
framework: event.framework,
|
|
221
237
|
sessionId: event.sessionId,
|
|
222
|
-
source:
|
|
223
|
-
};
|
|
238
|
+
source: docSource
|
|
239
|
+
});
|
|
224
240
|
if (event.tool === "Task" || event.tool === "Agent") {
|
|
225
241
|
const name = String(event.input?.subagent_type ?? event.input?.name ?? "").split(":").pop() ?? "";
|
|
226
|
-
if (
|
|
227
|
-
return
|
|
242
|
+
if (name) out.push(agentActivity(name, event.now, qualityFor(event.responseLength, AGENT_QUALITY_MIN)));
|
|
243
|
+
return out;
|
|
228
244
|
}
|
|
229
245
|
const hit = classifyExplore(event.tool, event.input);
|
|
230
246
|
if (hit) {
|
|
231
247
|
const quality = hit.cacheHit ? "sufficient" : qualityFor(event.responseLength, EXPLORE_QUALITY_MIN);
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
if (READ_TOOLS.has(event.tool)) {
|
|
248
|
+
out.push(agentActivity(hit.phase, event.now, quality));
|
|
249
|
+
} else if (READ_TOOLS.has(event.tool)) {
|
|
235
250
|
const path = String(event.input?.file_path ?? event.input?.path ?? "");
|
|
236
|
-
if (path.endsWith(".md"))
|
|
251
|
+
if (path.endsWith(".md")) out.push({
|
|
237
252
|
kind: "ref",
|
|
238
253
|
path
|
|
239
|
-
};
|
|
254
|
+
});
|
|
240
255
|
}
|
|
241
|
-
return
|
|
256
|
+
return out;
|
|
242
257
|
}
|
|
243
258
|
//#endregion
|
|
244
259
|
//#region src/runtime/mcp-key.ts
|
|
@@ -4571,7 +4586,7 @@ async function handleHook(id, payload, opts) {
|
|
|
4571
4586
|
const response = payload.tool_response ?? payload.tool_output;
|
|
4572
4587
|
mcpPostStore(event.tool, event.input, response, mcpDir);
|
|
4573
4588
|
const designWarn = designGate(payload, event, mcpDir, opts.cwd);
|
|
4574
|
-
const
|
|
4589
|
+
const activities = activityFor({
|
|
4575
4590
|
tool: event.tool,
|
|
4576
4591
|
input: event.input,
|
|
4577
4592
|
sessionId: event.sessionId,
|
|
@@ -4579,7 +4594,7 @@ async function handleHook(id, payload, opts) {
|
|
|
4579
4594
|
now: opts.now,
|
|
4580
4595
|
responseLength: extractText(response).length
|
|
4581
4596
|
});
|
|
4582
|
-
|
|
4597
|
+
for (const activity of activities) await recordActivity(file, activity);
|
|
4583
4598
|
postTrackingSideEffects(opts.scope ?? "core", event, event.input, opts.now, payload, opts.cwd);
|
|
4584
4599
|
const seoDeny = opts.scope === "seo" ? seoPostToolUseResponse(payload) : null;
|
|
4585
4600
|
if (seoDeny) return {
|
package/dist/index.mjs
CHANGED
|
@@ -5,9 +5,9 @@ import { i as parseEnvFile, n as envCandidates, r as loadDotenv, t as HOME_DIR }
|
|
|
5
5
|
import { t as compactJson } from "./compact-json-DK2nX-MK.mjs";
|
|
6
6
|
import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
|
|
7
7
|
import { n as detectMode, r as modeFor, t as detectHarness } from "./harness-C8Nxxyn_.mjs";
|
|
8
|
-
import { A as evaluateApex, C as MAX_EXA_RESULTS, D as APEX_GATES, E as detectCreationIntent, F as detectProjectType, I as isApexCommand, L as requiredArchSkill, M as solidReadGate, N as DEV_KEYWORDS, O as brainstormGate, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, a as firstHeading, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, f as buildApexTaskContext, g as buildApexInstruction, h as DEV_VERBS, i as firstComment, j as freshnessGate, k as docConsultedGate, l as parseField, m as loadApexTaskState, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS, v as detectClaudeMdProjectType, w as MAX_TOKENS, x as SKILL_TRIGGERS, y as detectRequiredSkills } from "./validate-
|
|
8
|
+
import { A as evaluateApex, C as MAX_EXA_RESULTS, D as APEX_GATES, E as detectCreationIntent, F as detectProjectType, I as isApexCommand, L as requiredArchSkill, M as solidReadGate, N as DEV_KEYWORDS, O as brainstormGate, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, a as firstHeading, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, f as buildApexTaskContext, g as buildApexInstruction, h as DEV_VERBS, i as firstComment, j as freshnessGate, k as docConsultedGate, l as parseField, m as loadApexTaskState, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS, v as detectClaudeMdProjectType, w as MAX_TOKENS, x as SKILL_TRIGGERS, y as detectRequiredSkills } from "./validate-B3wkqEoN.mjs";
|
|
9
9
|
import { A as matchPatterns, C as ASK_PATTERNS, D as GIT_BLOCKED, E as GIT_ASK, M as evaluateFileSize, N as detectFramework, O as PROJECT_INSTALL, S as protectedPathGuard, T as securityGuard, _ as CODE_REDIRECT, a as registerGuard, b as PROTECTED_FRAGMENTS, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as countLines, k as SYSTEM_INSTALL, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as FILE_REDIRECT, w as CRITICAL_PATTERNS, x as PROTECTED_GIT_RE, y as bashWriteGuard } from "./evaluate-B1n1ti0N.mjs";
|
|
10
|
-
import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-
|
|
10
|
+
import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-BhzDmJ18.mjs";
|
|
11
11
|
import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-BfX0hJg8.mjs";
|
|
12
12
|
import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
|
|
13
13
|
import { a as nowStamp, c as stateFileFor, i as lessonsFileFor, l as throttleMs, n as readRoots, o as readState, r as registryFile, s as setStateField, t as addRoot, u as ensureMemoryGitignore } from "./registry-BkoEbdec.mjs";
|
package/dist/policy/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as evaluateApex, C as MAX_EXA_RESULTS, D as APEX_GATES, E as detectCreationIntent, F as detectProjectType, I as isApexCommand, L as requiredArchSkill, M as solidReadGate, N as DEV_KEYWORDS, O as brainstormGate, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, a as firstHeading, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, f as buildApexTaskContext, g as buildApexInstruction, h as DEV_VERBS, i as firstComment, j as freshnessGate, k as docConsultedGate, l as parseField, m as loadApexTaskState, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS, v as detectClaudeMdProjectType, w as MAX_TOKENS, x as SKILL_TRIGGERS, y as detectRequiredSkills } from "../validate-
|
|
1
|
+
import { A as evaluateApex, C as MAX_EXA_RESULTS, D as APEX_GATES, E as detectCreationIntent, F as detectProjectType, I as isApexCommand, L as requiredArchSkill, M as solidReadGate, N as DEV_KEYWORDS, O as brainstormGate, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, a as firstHeading, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, f as buildApexTaskContext, g as buildApexInstruction, h as DEV_VERBS, i as firstComment, j as freshnessGate, k as docConsultedGate, l as parseField, m as loadApexTaskState, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS, v as detectClaudeMdProjectType, w as MAX_TOKENS, x as SKILL_TRIGGERS, y as detectRequiredSkills } from "../validate-B3wkqEoN.mjs";
|
|
2
2
|
import { A as matchPatterns, C as ASK_PATTERNS, D as GIT_BLOCKED, E as GIT_ASK, M as evaluateFileSize, N as detectFramework, O as PROJECT_INSTALL, S as protectedPathGuard, T as securityGuard, _ as CODE_REDIRECT, a as registerGuard, b as PROTECTED_FRAGMENTS, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as countLines, k as SYSTEM_INSTALL, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as FILE_REDIRECT, w as CRITICAL_PATTERNS, x as PROTECTED_GIT_RE, y as bashWriteGuard } from "../evaluate-B1n1ti0N.mjs";
|
|
3
3
|
import "../policy-la_KkjCS.mjs";
|
|
4
4
|
export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, FILE_REDIRECT, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_TOKENS, PHP_DECL_RE, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PROTECTED_GIT_RE, PY_MODEL_RE, SKILL_TRIGGERS, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, isHtmlLike, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate };
|
package/dist/runtime/index.d.mts
CHANGED
|
@@ -78,7 +78,7 @@ interface ToolEvent {
|
|
|
78
78
|
* → `agent` credited to the matching REQUIRED_AGENTS phase
|
|
79
79
|
* - a read tool opening a `.md` reference → `ref`
|
|
80
80
|
*/
|
|
81
|
-
declare function activityFor(event: ToolEvent): Activity
|
|
81
|
+
declare function activityFor(event: ToolEvent): Activity[];
|
|
82
82
|
//#endregion
|
|
83
83
|
//#region src/runtime/gate-input.d.ts
|
|
84
84
|
/** A tool-use to gate, plus the session pointers needed for the stateful gates. */
|
package/dist/runtime/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as projectLayout } from "../layout-C0jaaCQC.mjs";
|
|
2
|
-
import { $ as sessionStartCore, A as writePluginMap, At as fusengineCache, B as trackSessionChanges, C as aipilotPostToolUse, Ct as isoUtc, D as lessonsStateFileFor, Dt as securityStatePath, E as lessonsFileFor, Et as securityStateDir, F as mergeLines, Ft as sessionsDir, G as validateTeammateOutput, H as cleanupSession, I as countFiles, J as detectSolidProfile, K as trackAgentMemory, L as getFileDesc, M as isProject, Mt as sanitizeSessionId, N as writeTree, Nt as saveSessionState, O as cartoSessionStart, Ot as todayUtc, P as loadEnriched, Pt as sessionStatePath, Q as runSessionStartCleanups, R as listChildren, S as dispatchLifecycle, St as activityFor, T as dispatchLessons, Tt as saveSecurityState, U as saveApexState, V as validateRulesLoaded, W as logToolFailure, X as injectRules, Y as solidDetectStart, Z as readRules, _ as postTrackingSideEffects, _t as MCP_TTL_MS, a as TRIVIAL_BUDGET, at as gitContext, b as trackSkillRead, bt as isMcpTool, c as detectDuplication, ct as taskContext, d as lifecycleStdout, dt as defaultStateDir, et as pruneEmptyDirs, f as postEditContext, ft as projectHash, g as securityAdvisory, gt as mcpPreIntercept, h as dispatchMemory, ht as mcpPostStore, i as REQUIRED_AGENTS, it as devContext, j as generateProjectMap, jt as loadSessionState, k as generateEcosystemMap, kt as claudeHome, l as dryGate, lt as respond, m as seoPostToolUseResponse, mt as normalizeEvent, n as handlePre, nt as removeOldFiles, o as gate, ot as projectContext, p as seoPostToolUse, pt as trackFile, q as subagentCacheContext, r as DEFAULT_WINDOW_MS, rt as trimLogFile, s as preCommitGate, st as promptSubmitContext, t as handleHook, tt as purgeTtlTree, u as extractSymbols, ut as recordActivity, v as trackWatchResearch, vt as WEBFETCH_TTL_MS, w as dispatchAipilot, wt as loadSecurityState, x as trackEnrichment, xt as queryOf, y as trackMcpResearch, yt as cacheQueryOf, z as postEditTypescript } from "../handle-
|
|
2
|
+
import { $ as sessionStartCore, A as writePluginMap, At as fusengineCache, B as trackSessionChanges, C as aipilotPostToolUse, Ct as isoUtc, D as lessonsStateFileFor, Dt as securityStatePath, E as lessonsFileFor, Et as securityStateDir, F as mergeLines, Ft as sessionsDir, G as validateTeammateOutput, H as cleanupSession, I as countFiles, J as detectSolidProfile, K as trackAgentMemory, L as getFileDesc, M as isProject, Mt as sanitizeSessionId, N as writeTree, Nt as saveSessionState, O as cartoSessionStart, Ot as todayUtc, P as loadEnriched, Pt as sessionStatePath, Q as runSessionStartCleanups, R as listChildren, S as dispatchLifecycle, St as activityFor, T as dispatchLessons, Tt as saveSecurityState, U as saveApexState, V as validateRulesLoaded, W as logToolFailure, X as injectRules, Y as solidDetectStart, Z as readRules, _ as postTrackingSideEffects, _t as MCP_TTL_MS, a as TRIVIAL_BUDGET, at as gitContext, b as trackSkillRead, bt as isMcpTool, c as detectDuplication, ct as taskContext, d as lifecycleStdout, dt as defaultStateDir, et as pruneEmptyDirs, f as postEditContext, ft as projectHash, g as securityAdvisory, gt as mcpPreIntercept, h as dispatchMemory, ht as mcpPostStore, i as REQUIRED_AGENTS, it as devContext, j as generateProjectMap, jt as loadSessionState, k as generateEcosystemMap, kt as claudeHome, l as dryGate, lt as respond, m as seoPostToolUseResponse, mt as normalizeEvent, n as handlePre, nt as removeOldFiles, o as gate, ot as projectContext, p as seoPostToolUse, pt as trackFile, q as subagentCacheContext, r as DEFAULT_WINDOW_MS, rt as trimLogFile, s as preCommitGate, st as promptSubmitContext, t as handleHook, tt as purgeTtlTree, u as extractSymbols, ut as recordActivity, v as trackWatchResearch, vt as WEBFETCH_TTL_MS, w as dispatchAipilot, wt as loadSecurityState, x as trackEnrichment, xt as queryOf, y as trackMcpResearch, yt as cacheQueryOf, z as postEditTypescript } from "../handle-VhWQxvyN.mjs";
|
|
3
3
|
//#region src/runtime/storage.ts
|
|
4
4
|
/**
|
|
5
5
|
* The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
|
|
2
2
|
import { j as countLines } from "./evaluate-B1n1ti0N.mjs";
|
|
3
|
-
import { r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-
|
|
3
|
+
import { r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-BhzDmJ18.mjs";
|
|
4
4
|
import { t as routeReferences } from "./router-BfX0hJg8.mjs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusengine/harness",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.41",
|
|
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",
|