@fusengine/harness 0.1.72 → 0.1.73
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/cli/bin.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { t as detectHarness } from "../harness-Cb9xR8dC.mjs";
|
|
|
4
4
|
import { t as claudeHome } from "../home-state-D0RLWP8J.mjs";
|
|
5
5
|
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-B4BqxlXH.mjs";
|
|
6
6
|
import { n as writeInitFile, t as initFor } from "../run-Do2JltgU.mjs";
|
|
7
|
-
import { $ as runningVersion, Q as runDoctor, Z as notify, et as versionBanner, t as handleHook, zt as todayUtc } from "../handle-
|
|
7
|
+
import { $ as runningVersion, Q as runDoctor, Z as notify, et as versionBanner, t as handleHook, zt as todayUtc } from "../handle-BcUrrK0Q.mjs";
|
|
8
8
|
import { p as readStdin$1 } from "../claude-Z0pN-dqc.mjs";
|
|
9
9
|
import { delimiter, join } from "node:path";
|
|
10
10
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
@@ -227,7 +227,7 @@ function recordValidDesignSystem(state) {
|
|
|
227
227
|
*/
|
|
228
228
|
function recordRead(state, filePath) {
|
|
229
229
|
const next = { ...state };
|
|
230
|
-
if (filePath.includes("
|
|
230
|
+
if (filePath.includes("design-system/SKILL.md")) {
|
|
231
231
|
next.currentPhase = Math.max(state.currentPhase, 1);
|
|
232
232
|
next.phasesCompleted = [.../* @__PURE__ */ new Set([...state.phasesCompleted, "identity"])];
|
|
233
233
|
}
|
|
@@ -7345,8 +7345,8 @@ function runDesignChecks(content) {
|
|
|
7345
7345
|
/** Domain skill triggers (ported 1:1 from `design_skill_triggers.py`). */
|
|
7346
7346
|
const SKILL_TRIGGERS = [
|
|
7347
7347
|
{
|
|
7348
|
-
skill: "
|
|
7349
|
-
readFragment: "
|
|
7348
|
+
skill: "design-web",
|
|
7349
|
+
readFragment: "design-web",
|
|
7350
7350
|
patterns: [
|
|
7351
7351
|
/className\s*=\s*["{]/i,
|
|
7352
7352
|
/<(div|section|main|header|footer|nav|aside)\s/i,
|
|
@@ -7359,8 +7359,8 @@ const SKILL_TRIGGERS = [
|
|
|
7359
7359
|
]
|
|
7360
7360
|
},
|
|
7361
7361
|
{
|
|
7362
|
-
skill: "
|
|
7363
|
-
readFragment: "
|
|
7362
|
+
skill: "design-system",
|
|
7363
|
+
readFragment: "design-system",
|
|
7364
7364
|
patterns: [
|
|
7365
7365
|
/--(\w+-)+color:|:root\s*\{|@theme\b/i,
|
|
7366
7366
|
/design.?system|token|palette|typography.?scale/i,
|
|
@@ -7374,8 +7374,8 @@ const SKILL_TRIGGERS = [
|
|
|
7374
7374
|
]
|
|
7375
7375
|
},
|
|
7376
7376
|
{
|
|
7377
|
-
skill: "
|
|
7378
|
-
readFragment: "
|
|
7377
|
+
skill: "design-motion",
|
|
7378
|
+
readFragment: "design-motion",
|
|
7379
7379
|
patterns: [
|
|
7380
7380
|
/motion\.|framer-motion|animate|variants/i,
|
|
7381
7381
|
/whileHover|whileTap|AnimatePresence|transition/i,
|
|
@@ -7390,8 +7390,8 @@ const SKILL_TRIGGERS = [
|
|
|
7390
7390
|
]
|
|
7391
7391
|
},
|
|
7392
7392
|
{
|
|
7393
|
-
skill: "
|
|
7394
|
-
readFragment: "design-
|
|
7393
|
+
skill: "design-review",
|
|
7394
|
+
readFragment: "design-review",
|
|
7395
7395
|
patterns: [/aria-|role=|sr-only|tabIndex|alt=/i, /WCAG|a11y|contrast|screen.?reader/i]
|
|
7396
7396
|
}
|
|
7397
7397
|
];
|
|
@@ -7410,7 +7410,7 @@ const UI_PATH_RE = /(components|ui|styles|page|layout|content|view|feature|secti
|
|
|
7410
7410
|
/** Tailwind utility usage in JSX `className` (ports the Python `has_jsx_tailwind`). */
|
|
7411
7411
|
const TAILWIND_RE = /className\s*=.*(?:flex|grid|p-|m-|bg-|text-|rounded|shadow|border|gap-|w-|h-)/;
|
|
7412
7412
|
/** A read reference path that counts as "a design skill was consulted". */
|
|
7413
|
-
const DESIGN_SKILL_RE = /skills\/(
|
|
7413
|
+
const DESIGN_SKILL_RE = /skills\/(design-method|design-system|design-web|design-webapp|design-motion|design-review|ux-copy|design-ios|design-android)/i;
|
|
7414
7414
|
/** True when this Write/Edit targets a UI file in a UI-ish path or with Tailwind classes. */
|
|
7415
7415
|
function isUiWrite(tool, filePath, content) {
|
|
7416
7416
|
if (tool !== "Write" && tool !== "Edit") return false;
|
|
@@ -7437,7 +7437,7 @@ const block = (reason, action) => ({
|
|
|
7437
7437
|
*/
|
|
7438
7438
|
function uiDesignSkillGate(tool, filePath, content, ev) {
|
|
7439
7439
|
if (!isUiWrite(tool, filePath, content)) return null;
|
|
7440
|
-
if (!designSkillRead(ev.refsRead)) return block("BLOCKED: design skill not consulted before writing UI. Read a design SKILL.md (
|
|
7440
|
+
if (!designSkillRead(ev.refsRead)) return block("BLOCKED: design skill not consulted before writing UI. Read a design SKILL.md (design-system, design-web, or design-motion), then retry.", "Read a design skill reference, then retry");
|
|
7441
7441
|
const missing = missingDomainSkills(content, ev.refsRead);
|
|
7442
7442
|
if (missing.length) return block(`BLOCKED: code uses ${missing.join(", ")} but the matching design skill(s) were not consulted. Read the SKILL.md for: ${missing.join(", ")}, then retry.`, `Read design skill(s): ${missing.join(", ")}, then retry`);
|
|
7443
7443
|
if (!ev.docConsulted) return block("BLOCKED: no documentation consulted. Use BOTH mcp__context7__query-docs AND mcp__exa__web_search_exa, or a web fallback alone (WebSearch/WebFetch). Gemini is NOT required.", "Consult Context7+Exa, or web docs alone (Gemini not required), then retry");
|
|
@@ -7615,7 +7615,7 @@ const KNOWN_DOMAINS = [
|
|
|
7615
7615
|
/** Gate writing design-system.md: requires phase >= 2 and the per-mode screenshot quota. */
|
|
7616
7616
|
function designSystemWriteGate(filePath, state) {
|
|
7617
7617
|
if (!filePath.endsWith("design-system.md")) return null;
|
|
7618
|
-
if (state.currentPhase < 2) return deny(`BLOCKED: Cannot write design-system.md at phase ${state.currentPhase}. RECOVERY: 1) Read identity templates from skills/
|
|
7618
|
+
if (state.currentPhase < 2) return deny(`BLOCKED: Cannot write design-system.md at phase ${state.currentPhase}. RECOVERY: 1) Read identity templates from skills/design-system/ 2) Read design-inspiration.md 3) Browse and screenshot sites 4) Then write design-system.md`);
|
|
7619
7619
|
const needed = MIN_SCREENSHOTS[state.mode];
|
|
7620
7620
|
if (state.screenshotsCount < needed) return deny(`BLOCKED: ${state.screenshotsCount}/${needed} screenshots for mode '${state.mode}'. RECOVERY: 1) Take ${needed - state.screenshotsCount} more fuse-browser screenshots 2) Use browser_open + browser_navigate + browser_screenshot fullPage:true 3) Then write design-system.md`);
|
|
7621
7621
|
return null;
|
|
@@ -7628,8 +7628,8 @@ function geminiCreateGate(state) {
|
|
|
7628
7628
|
}
|
|
7629
7629
|
/** Gate fuse-browser navigate: phase >= 1, inspiration read, URL in the catalog. */
|
|
7630
7630
|
function browserNavigateGate(state, url) {
|
|
7631
|
-
if (state.currentPhase < 1) return deny(`BLOCKED: Phase 0 not done. READ: ${SKILLS}/
|
|
7632
|
-
if (!state.inspirationRead) return deny(`BLOCKED: Read inspiration catalog first. READ: ${SKILLS}/
|
|
7631
|
+
if (state.currentPhase < 1) return deny(`BLOCKED: Phase 0 not done. READ: ${SKILLS}/design-system/SKILL.md first.`);
|
|
7632
|
+
if (!state.inspirationRead) return deny(`BLOCKED: Read inspiration catalog first. READ: ${SKILLS}/design-web/references/design-inspiration.md + design-inspiration-urls.md`);
|
|
7633
7633
|
if (url && !KNOWN_DOMAINS.some((d) => url.includes(d))) return deny(`BLOCKED: '${url}' not in catalog. Use URLs from design-inspiration-urls.md. Domains: ${KNOWN_DOMAINS.join(", ")}`);
|
|
7634
7634
|
return null;
|
|
7635
7635
|
}
|
package/dist/runtime/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as projectLayout } from "../layout-C0jaaCQC.mjs";
|
|
2
2
|
import { a as sanitizeSessionId, c as sessionsDir, i as loadSessionState, n as fuseHarnessHome, o as saveSessionState, r as fusengineCache, s as sessionStatePath, t as claudeHome } from "../home-state-D0RLWP8J.mjs";
|
|
3
|
-
import { A as trackMcpResearch, At as defaultStateDir, B as generateProjectMap, C as seoPostToolUse, Ct as trimLogFile, D as securityAdvisoryForPatch, Dt as claudeMdKey, E as securityAdvisory, Et as projectContext, F as dispatchAipilot, Ft as loadSecurityState, G as countFiles, H as writeTree, I as dispatchLessons, It as saveSecurityState, J as lessonsArchiveFileFor, K as getFileDesc, L as cartoSessionStart, Lt as securityStateDir, M as trackEnrichment, Mt as trackFile, N as dispatchLifecycle, Nt as normalizeEvent, O as postTrackingSideEffects, Ot as promptSubmitContext, P as aipilotPostToolUse, Pt as isoUtc, R as generateEcosystemMap, Rt as securityStatePath, S as postEditContext, St as removeOldFiles, T as dispatchMemory, Tt as gitContext, U as loadEnriched, V as isProject, W as mergeLines, X as lessonsStateFileFor, Y as lessonsFileFor, _ as preCommitGate, _t as readRules, a as recordActivity, at as saveApexState, b as extractSymbols, bt as pruneEmptyDirs, c as MCP_TTL_MS, ct as trackAgentMemory, d as isMcpTool, dt as validateSolidGate, f as queryOf, ft as checkFileSize, g as gate, gt as injectRules, h as TRIVIAL_BUDGET, ht as solidDetectStart, i as respond, it as cleanupSession, j as trackSkillRead, jt as projectHash, k as trackWatchResearch, kt as taskContext, l as WEBFETCH_TTL_MS, lt as subagentCacheContext, m as REQUIRED_AGENTS, mt as detectSolidProfile, n as activityFor, nt as trackSessionChanges, o as mcpPostStore, ot as logToolFailure, p as DEFAULT_WINDOW_MS, pt as countLoc, q as listChildren, r as handlePre, rt as validateRulesLoaded, s as mcpPreIntercept, st as validateTeammateOutput, t as handleHook, tt as postEditTypescript, u as cacheQueryOf, ut as validateTailwind, v as detectDuplication, vt as runSessionStartCleanups, w as seoPostToolUseResponse, wt as devContext, x as lifecycleStdout, xt as purgeTtlTree, y as dryGate, yt as sessionStartCore, z as writePluginMap, zt as todayUtc } from "../handle-
|
|
3
|
+
import { A as trackMcpResearch, At as defaultStateDir, B as generateProjectMap, C as seoPostToolUse, Ct as trimLogFile, D as securityAdvisoryForPatch, Dt as claudeMdKey, E as securityAdvisory, Et as projectContext, F as dispatchAipilot, Ft as loadSecurityState, G as countFiles, H as writeTree, I as dispatchLessons, It as saveSecurityState, J as lessonsArchiveFileFor, K as getFileDesc, L as cartoSessionStart, Lt as securityStateDir, M as trackEnrichment, Mt as trackFile, N as dispatchLifecycle, Nt as normalizeEvent, O as postTrackingSideEffects, Ot as promptSubmitContext, P as aipilotPostToolUse, Pt as isoUtc, R as generateEcosystemMap, Rt as securityStatePath, S as postEditContext, St as removeOldFiles, T as dispatchMemory, Tt as gitContext, U as loadEnriched, V as isProject, W as mergeLines, X as lessonsStateFileFor, Y as lessonsFileFor, _ as preCommitGate, _t as readRules, a as recordActivity, at as saveApexState, b as extractSymbols, bt as pruneEmptyDirs, c as MCP_TTL_MS, ct as trackAgentMemory, d as isMcpTool, dt as validateSolidGate, f as queryOf, ft as checkFileSize, g as gate, gt as injectRules, h as TRIVIAL_BUDGET, ht as solidDetectStart, i as respond, it as cleanupSession, j as trackSkillRead, jt as projectHash, k as trackWatchResearch, kt as taskContext, l as WEBFETCH_TTL_MS, lt as subagentCacheContext, m as REQUIRED_AGENTS, mt as detectSolidProfile, n as activityFor, nt as trackSessionChanges, o as mcpPostStore, ot as logToolFailure, p as DEFAULT_WINDOW_MS, pt as countLoc, q as listChildren, r as handlePre, rt as validateRulesLoaded, s as mcpPreIntercept, st as validateTeammateOutput, t as handleHook, tt as postEditTypescript, u as cacheQueryOf, ut as validateTailwind, v as detectDuplication, vt as runSessionStartCleanups, w as seoPostToolUseResponse, wt as devContext, x as lifecycleStdout, xt as purgeTtlTree, y as dryGate, yt as sessionStartCore, z as writePluginMap, zt as todayUtc } from "../handle-BcUrrK0Q.mjs";
|
|
4
4
|
//#region src/runtime/storage.ts
|
|
5
5
|
/**
|
|
6
6
|
* The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusengine/harness",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.73",
|
|
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",
|