@fusengine/harness 0.1.70 → 0.1.72

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.
@@ -1,2 +1,2 @@
1
- import { a as fileSizeGuard, c as readClaudeInput, i as denyResponse, l as systemMessage, n as blockResponse, o as guard, r as contextResponse, s as informResponse, t as attachSystemMessage, u as toClaudeResponse } from "../../claude-CHpb1U0A.mjs";
1
+ import { a as fileSizeGuard, c as readClaudeInput, i as denyResponse, l as systemMessage, n as blockResponse, o as guard, r as contextResponse, s as informResponse, t as attachSystemMessage, u as toClaudeResponse } from "../../claude-Z0pN-dqc.mjs";
2
2
  export { attachSystemMessage, blockResponse, contextResponse, denyResponse, fileSizeGuard, guard, informResponse, readClaudeInput, systemMessage, toClaudeResponse };
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "../../evaluate-Dx6q1kmQ.mjs";
1
+ import { t as evaluate } from "../../evaluate-DlM9ckLB.mjs";
2
2
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/cline/index.ts
4
4
  /**
@@ -1,8 +1,8 @@
1
+ import { t as evaluate } from "../../evaluate-DlM9ckLB.mjs";
1
2
  import { f as countLines } from "../../home-state-D0RLWP8J.mjs";
2
- import { t as evaluate } from "../../evaluate-Dx6q1kmQ.mjs";
3
3
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
4
4
  import { n as parseApplyPatch, t as isBypassPermissions } from "../../permission-mode-BN3MNgbm.mjs";
5
- import { c as readClaudeInput, i as denyResponse, r as contextResponse, s as informResponse, v as commandToString } from "../../claude-CHpb1U0A.mjs";
5
+ import { c as readClaudeInput, i as denyResponse, r as contextResponse, s as informResponse, v as commandToString } from "../../claude-Z0pN-dqc.mjs";
6
6
  //#region src/adapters/codex/index.ts
7
7
  /**
8
8
  * OpenAI Codex CLI adapter (hook-mode). Codex's `PreToolUse` hook (since 2026)
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "../../evaluate-Dx6q1kmQ.mjs";
1
+ import { t as evaluate } from "../../evaluate-DlM9ckLB.mjs";
2
2
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/cursor/index.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "../../evaluate-Dx6q1kmQ.mjs";
1
+ import { t as evaluate } from "../../evaluate-DlM9ckLB.mjs";
2
2
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
3
3
  //#region src/adapters/gemini/index.ts
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { n as readHermesInput, r as toHermesResponse, t as guard } from "../../hermes-CddsFoPN.mjs";
1
+ import { n as readHermesInput, r as toHermesResponse, t as guard } from "../../hermes-B8QmMtSK.mjs";
2
2
  export { guard, readHermesInput, toHermesResponse };
@@ -1,4 +1,4 @@
1
- import { t as evaluate } from "./evaluate-Dx6q1kmQ.mjs";
1
+ import { t as evaluate } from "./evaluate-DlM9ckLB.mjs";
2
2
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
package/dist/cli/bin.mjs CHANGED
@@ -2,10 +2,10 @@
2
2
  import { r as loadDotenv, s as resolveTtlSec } from "../dotenv-Jj8aL1FL.mjs";
3
3
  import { t as detectHarness } from "../harness-Cb9xR8dC.mjs";
4
4
  import { t as claudeHome } from "../home-state-D0RLWP8J.mjs";
5
- import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-B9Br7SEr.mjs";
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-ClfFahJs.mjs";
8
- import { p as readStdin$1 } from "../claude-CHpb1U0A.mjs";
7
+ import { $ as runningVersion, Q as runDoctor, Z as notify, et as versionBanner, t as handleHook, zt as todayUtc } from "../handle-Cw1H21Eg.mjs";
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";
11
11
  import { homedir } from "node:os";
@@ -1,2 +1,2 @@
1
- import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-B9Br7SEr.mjs";
1
+ import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-B4BqxlXH.mjs";
2
2
  export { checkStaged, stagedContent, stagedFiles };
@@ -1,8 +1,206 @@
1
1
  import { r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
2
2
  import { f as countLines, p as evaluateFileSize, r as fusengineCache, t as claudeHome } from "./home-state-D0RLWP8J.mjs";
3
- import { dirname, join, normalize } from "node:path";
4
- import { existsSync } from "node:fs";
3
+ import { dirname, join, normalize, resolve } from "node:path";
4
+ import { existsSync, readFileSync } from "node:fs";
5
5
  import { homedir } from "node:os";
6
+ //#region src/policy/detect-project.ts
7
+ /** Keywords that signal a development task (APEX trigger). */
8
+ const DEV_KEYWORDS = /\b(implement|create|build|fix|add|refactor|develop|feature|bug|update|modify|change|write|code)\b/i;
9
+ /** True when the prompt invokes the /apex command. */
10
+ function isApexCommand(prompt) {
11
+ return /(?:^|\s)\/apex|\/fuse-ai-pilot:apex/i.test(prompt);
12
+ }
13
+ /**
14
+ * Detect a project-internal modular architecture (a sub-architecture the
15
+ * framework-level {@link detectProjectType} doesn't capture): Fusengine's
16
+ * FuseCore (Laravel) or a `modules/`-based Next.js layout.
17
+ */
18
+ function detectModularArchitecture(dir) {
19
+ const has = (f) => existsSync(join(dir, f));
20
+ if (has("FuseCore") && has("artisan")) return "fusecore";
21
+ if (has("modules") && (has("next.config.js") || has("next.config.ts") || has("next.config.mjs"))) return "nextjs-modular";
22
+ return null;
23
+ }
24
+ /**
25
+ * Resolve the skill a detected modular architecture forces.
26
+ *
27
+ * Ports the Python `check-nextjs-skill.py` / `check-laravel-skill.py` gates:
28
+ * when the project is detected on disk as a modular architecture, a specific
29
+ * skill is required ('solid-nextjs' for nextjs-modular, 'fusecore' for
30
+ * fusecore). Returns `null` when no modular architecture is detected.
31
+ *
32
+ * @param cwd - Project root directory to scan.
33
+ * @returns The forced skill name, or `null` when none applies.
34
+ */
35
+ function requiredArchSkill(cwd) {
36
+ switch (detectModularArchitecture(cwd)) {
37
+ case "nextjs-modular": return "solid-nextjs";
38
+ case "fusecore": return "fusecore";
39
+ default: return null;
40
+ }
41
+ }
42
+ /** Config file names that mark a project as using Tailwind (v3 JS config or legacy). */
43
+ const TAILWIND_CONFIG_FILES = [
44
+ "tailwind.config.js",
45
+ "tailwind.config.ts",
46
+ "tailwind.config.mjs",
47
+ "tailwind.config.cjs"
48
+ ];
49
+ /** True when `package.json` lists `tailwindcss` as a dep (Tailwind v4 CSS-first, no config file). */
50
+ function hasTailwindDependency(dir) {
51
+ const pkgPath = join(dir, "package.json");
52
+ if (!existsSync(pkgPath)) return false;
53
+ try {
54
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
55
+ return "tailwindcss" in {
56
+ ...pkg.dependencies,
57
+ ...pkg.devDependencies
58
+ };
59
+ } catch {
60
+ return false;
61
+ }
62
+ }
63
+ /** Detect the project type by scanning config files in `dir`. */
64
+ function detectProjectType(dir) {
65
+ const has = (f) => existsSync(join(dir, f));
66
+ if (has("next.config.js") || has("next.config.ts") || has("next.config.mjs")) return "nextjs";
67
+ if (has("nuxt.config.ts") || has("nuxt.config.js")) return "nuxt";
68
+ if (has("angular.json")) return "angular";
69
+ if (has("svelte.config.js") || has("svelte.config.ts")) return "svelte";
70
+ if (has("vite.config.ts") && has("src/App.vue")) return "vue";
71
+ if (has("vite.config.ts") || has("vite.config.js")) return "react";
72
+ if (TAILWIND_CONFIG_FILES.some(has) || hasTailwindDependency(dir)) return "tailwind";
73
+ if (has("composer.json") && has("artisan")) return "laravel";
74
+ if (has("Gemfile") && has("config/routes.rb")) return "rails";
75
+ if (has("requirements.txt") || has("pyproject.toml") || has("setup.py")) return has("manage.py") ? "django" : "python";
76
+ if (has("go.mod")) return "go";
77
+ if (has("Cargo.toml")) return "rust";
78
+ if (has("Package.swift")) return "swift";
79
+ if (has("pom.xml") || has("build.gradle") || has("build.gradle.kts")) return "java";
80
+ if (has("build.sbt")) return "scala";
81
+ if (has("mix.exs")) return "elixir";
82
+ if (has("Gemfile")) return "ruby";
83
+ return "generic";
84
+ }
85
+ //#endregion
86
+ //#region src/policy/nearest-manifest.ts
87
+ /** Manifest filenames that anchor a project root (any one marks the dir). */
88
+ const MANIFESTS = [
89
+ "package.json",
90
+ "composer.json",
91
+ "Package.swift",
92
+ "Cargo.toml",
93
+ "go.mod",
94
+ "pyproject.toml"
95
+ ];
96
+ /**
97
+ * Walk up from `startDir` to the NEAREST ancestor holding any manifest file.
98
+ * Unlike {@link projectRootOrNull} (which prefers the `.git` boundary and would
99
+ * skip a nested `scripts/package.json`), this returns the closest manifest dir,
100
+ * so an inner monorepo package wins over the repo root.
101
+ * @param startDir - Directory to begin the walk-up from.
102
+ * @returns The nearest manifest directory, or `null` at the filesystem root.
103
+ */
104
+ function nearestManifestDir(startDir) {
105
+ let current = resolve(startDir);
106
+ for (;;) {
107
+ if (MANIFESTS.some((m) => existsSync(join(current, m)))) return current;
108
+ const parent = dirname(current);
109
+ if (parent === current) return null;
110
+ current = parent;
111
+ }
112
+ }
113
+ /**
114
+ * Read the REAL capabilities of the project rooted at `dir`: JS-framework deps
115
+ * from `package.json` (which {@link detectProjectType} does NOT scan), plus the
116
+ * non-JS/config signals detectProjectType already covers (laravel/swift/
117
+ * tailwind) — reused, not duplicated. Fail-open: any parse error yields whatever
118
+ * was gathered so far, never throws.
119
+ * @param dir - A manifest directory (from {@link nearestManifestDir}), or null.
120
+ * @returns The set of detected capabilities (empty when `dir` is null).
121
+ */
122
+ function projectCaps(dir) {
123
+ const caps = /* @__PURE__ */ new Set();
124
+ if (!dir) return caps;
125
+ try {
126
+ const pkgPath = join(dir, "package.json");
127
+ if (existsSync(pkgPath)) {
128
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
129
+ const deps = {
130
+ ...pkg.dependencies,
131
+ ...pkg.devDependencies
132
+ };
133
+ if ("react" in deps || "react-dom" in deps) caps.add("react");
134
+ if ("next" in deps) caps.add("nextjs");
135
+ if ("vue" in deps) caps.add("vue");
136
+ if ("svelte" in deps) caps.add("svelte");
137
+ if ("@angular/core" in deps) caps.add("angular");
138
+ if ("nuxt" in deps) caps.add("nuxt");
139
+ if ("tailwindcss" in deps) caps.add("tailwind");
140
+ }
141
+ const type = detectProjectType(dir);
142
+ if (type === "laravel") caps.add("laravel");
143
+ if (type === "swift") caps.add("swift");
144
+ if (type === "tailwind") caps.add("tailwind");
145
+ } catch {}
146
+ return caps;
147
+ }
148
+ //#endregion
149
+ //#region src/policy/detect-framework.ts
150
+ /** react markers in a plain .ts/.js file (avoids TS-generic false positives). */
151
+ const REACT_CONTENT = /from ['"]react['"]|\buse(State|Effect|Context|Ref|Memo|Callback|Reducer|LayoutEffect)\b|className=/;
152
+ /** next.js markers in content. */
153
+ const NEXT_CONTENT = /use client|use server|NextRequest|NextResponse|from ['"]next|getServerSideProps|getStaticProps/;
154
+ /** next.js route-file conventions. */
155
+ const NEXT_ROUTE = /(page|layout|loading|error|route|middleware)\.(ts|tsx|js|jsx)$/;
156
+ /** Derive the raw signal an extension + content carry (no filesystem access). */
157
+ function fileSignal(filePath, content) {
158
+ if (/\.swift$/.test(filePath)) return { definitive: "swift" };
159
+ if (/\.php$/.test(filePath)) return { definitive: "laravel" };
160
+ if (/\.java$/.test(filePath)) return { definitive: "java" };
161
+ if (/\.go$/.test(filePath)) return { definitive: "go" };
162
+ if (/\.rb$/.test(filePath)) return { definitive: "ruby" };
163
+ if (/\.rs$/.test(filePath)) return { definitive: "rust" };
164
+ if (/\.css$/.test(filePath) || /@tailwind|@apply/.test(content)) return { definitive: "tailwind" };
165
+ const isNext = NEXT_ROUTE.test(filePath) || NEXT_CONTENT.test(content);
166
+ if (/\.(tsx|jsx)$/.test(filePath)) return { jsHint: isNext ? "nextjs" : "react" };
167
+ if (/\.(ts|js)$/.test(filePath)) {
168
+ if (isNext) return { jsHint: "nextjs" };
169
+ if (REACT_CONTENT.test(content)) return { jsHint: "react" };
170
+ }
171
+ return {};
172
+ }
173
+ /** Reconcile the JS signal against the project's REAL capabilities. */
174
+ function reconcile(caps, hint) {
175
+ const nextCap = caps.has("nextjs");
176
+ const reactCap = caps.has("react") || nextCap;
177
+ if (hint === "nextjs") return nextCap ? "nextjs" : reactCap ? "react" : "generic";
178
+ return reactCap ? "react" : "generic";
179
+ }
180
+ /**
181
+ * Detect a file's framework as the intersection of the REAL project (its nearest
182
+ * manifest's capabilities) and the file's own extension/content signal. A
183
+ * backend `.ts` in a react project is `generic` (no react signal) — fixing the
184
+ * old extension-only default that flagged every `.ts` as react. Fail-open: any
185
+ * error yields `"generic"`, never throws. Return values stay within the existing
186
+ * union ("react" | "nextjs" | "laravel" | "swift" | "tailwind" | "java" | "go" |
187
+ * "ruby" | "rust" | "generic") — no new labels.
188
+ * @param filePath - Path of the file being written/edited.
189
+ * @param content - Its (incoming) content, for JS content signals.
190
+ * @param cwd - Root to resolve a relative `filePath` against (default cwd).
191
+ * @returns A framework label from the existing union.
192
+ */
193
+ function detectFramework(filePath, content, cwd = process.cwd()) {
194
+ try {
195
+ const sig = fileSignal(filePath, content);
196
+ if (sig.definitive) return sig.definitive;
197
+ if (!sig.jsHint) return "generic";
198
+ return reconcile(projectCaps(nearestManifestDir(dirname(resolve(cwd, filePath)))), sig.jsHint);
199
+ } catch {
200
+ return "generic";
201
+ }
202
+ }
203
+ //#endregion
6
204
  //#region src/policy/patterns.ts
7
205
  /**
8
206
  * Guard pattern data, ported verbatim from the fusengine git/install guards.
@@ -124,27 +322,19 @@ function isFileSizeScoped(filePath) {
124
322
  return FILE_SIZE_CODE_EXT.test(filePath);
125
323
  }
126
324
  /**
127
- * Resolve the SOLID_REF framework key for a file — parity with Python
128
- * `enforce-file-size.py::get_solid_ref()` (NOT `detectFramework()`, which backs
129
- * the unrelated require-solid-read pipeline and keys off filename/content
130
- * heuristics that script never checks). Matches Python exactly:
131
- * - ts/tsx/js/jsx: "nextjs" only when `next.config.js`/`next.config.ts` sits in
132
- * the SAME directory as the file (Python's literal `os.path.dirname(fp)`
133
- * check, not a project-root search) else "react".
134
- * - vue/svelte/py/go/rs/java/cpp/c/rb/kt/dart/astro: "generic" (Python's
135
- * `SOLID_MAP.get(ext, 'generic/')` fallback none of these are map keys).
136
- * - php: "laravel"; swift: "swift".
325
+ * Resolve the SOLID_REF framework key for a file — now project-real via
326
+ * {@link detectFramework} (nearest-manifest caps ∩ file signal), NOT the old
327
+ * extension-only default that mislabeled every `.ts` as react (the "twin bug" of
328
+ * the require-solid-read pipeline; it only escaped when `next.config` sat in the
329
+ * SAME dir). A backend `.ts` in a react project — or any `.ts` in this generic
330
+ * Bun repo now resolves to "generic". Content is unavailable at this call site
331
+ * (evaluate.ts:59 passes only the path), so `.tsx`/`.jsx` still resolve via caps
332
+ * while `.ts`/`.js` lacking a content signal fall to "generic". Return values
333
+ * stay in the existing union; fail-open to "generic".
137
334
  * @param filePath - Absolute path of the file being written/edited.
138
335
  */
139
336
  function resolveSolidRefFramework(filePath) {
140
- const ext = filePath.includes(".") ? filePath.slice(filePath.lastIndexOf(".") + 1) : "";
141
- if (ext === "ts" || ext === "tsx" || ext === "js" || ext === "jsx") {
142
- const dir = dirname(filePath);
143
- return ["next.config.js", "next.config.ts"].some((c) => existsSync(join(dir, c))) ? "nextjs" : "react";
144
- }
145
- if (ext === "php") return "laravel";
146
- if (ext === "swift") return "swift";
147
- return "generic";
337
+ return detectFramework(filePath, "");
148
338
  }
149
339
  //#endregion
150
340
  //#region src/policy/edit-outcome.ts
@@ -967,4 +1157,4 @@ function evaluate(ctx) {
967
1157
  };
968
1158
  }
969
1159
  //#endregion
970
- export { PROJECT_INSTALL as A, PROTECTED_GIT_RE as C, securityGuard as D, CRITICAL_PATTERNS as E, SYSTEM_INSTALL as M, isRalphMode as N, GIT_ASK as O, matchPatterns as P, PROTECTED_FRAGMENTS as S, ASK_PATTERNS as T, CODE_MUTATORS as _, registerGuard as a, SAFE_PREFIXES as b, GO_DECL_RE as c, PY_MODEL_RE as d, SWIFT_PROTO_RE as f, ASK_WRITERS as g, bashWriteGuard as h, clearUserGuards as i, RALPH_SAFE as j, GIT_BLOCKED as k, JAVA_DECL_RE as l, interfaceSeparationGuard as m, FAIL_CLOSED as n, runGuards as o, TS_DECL_RE as p, GUARDS as r, installGuard as s, evaluate as t, PHP_DECL_RE as u, CODE_REDIRECT as v, protectedPathGuard as w, SESSION_STATE_FRAGMENT as x, FILE_REDIRECT as y };
1160
+ export { PROJECT_INSTALL as A, requiredArchSkill as B, PROTECTED_GIT_RE as C, securityGuard as D, CRITICAL_PATTERNS as E, detectFramework as F, DEV_KEYWORDS as I, detectModularArchitecture as L, SYSTEM_INSTALL as M, isRalphMode as N, GIT_ASK as O, matchPatterns as P, detectProjectType as R, PROTECTED_FRAGMENTS as S, ASK_PATTERNS as T, CODE_MUTATORS as _, registerGuard as a, SAFE_PREFIXES as b, GO_DECL_RE as c, PY_MODEL_RE as d, SWIFT_PROTO_RE as f, ASK_WRITERS as g, bashWriteGuard as h, clearUserGuards as i, RALPH_SAFE as j, GIT_BLOCKED as k, JAVA_DECL_RE as l, interfaceSeparationGuard as m, FAIL_CLOSED as n, runGuards as o, TS_DECL_RE as p, GUARDS as r, installGuard as s, evaluate as t, PHP_DECL_RE as u, CODE_REDIRECT as v, protectedPathGuard as w, SESSION_STATE_FRAGMENT as x, FILE_REDIRECT as y, isApexCommand as z };
@@ -2,11 +2,11 @@ import { a as parseEnvInt, i as splitTarget, r as resolveMaxLines } from "./limi
2
2
  import { s as resolveTtlSec } from "./dotenv-Jj8aL1FL.mjs";
3
3
  import { r as projectLayout } from "./layout-C0jaaCQC.mjs";
4
4
  import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
5
- import { A as detectCreationIntent, E as isExcludedSwiftPath, F as docConsultedGate, H as detectProjectType$1, I as evaluateApex, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, S as usesTailwindUtilities, T as isExcludedJsPath, V as detectModularArchitecture, W as requiredArchSkill, _ as scanPlugin, c as EXCLUDE_DIRS$1, d as buildApexTaskInjection, h as buildClaudeMdContext, k as capVerbosity, l as PROJECT_INDICATORS, n as missingSeoElements, o as parseEnrichment, r as descFromText, s as parseEntry, t as isHtmlLike, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "./validate-DnOqIZD_.mjs";
5
+ import { B as requiredArchSkill, F as detectFramework, L as detectModularArchitecture, R as detectProjectType$1, n as FAIL_CLOSED, t as evaluate } from "./evaluate-DlM9ckLB.mjs";
6
6
  import { a as sanitizeSessionId, c as sessionsDir, d as countFrameworkCodeLines, f as countLines, i as loadSessionState, l as PLUGINS_DIR, n as fuseHarnessHome, o as saveSessionState, r as fusengineCache, t as claudeHome } from "./home-state-D0RLWP8J.mjs";
7
- import { n as FAIL_CLOSED, t as evaluate } from "./evaluate-Dx6q1kmQ.mjs";
8
7
  import { a as writeJsonFile, i as readJsonFile, r as hashText, t as atomicWrite } from "./json-io-DisYd2fb.mjs";
9
8
  import { r as isDocConsulted } from "./doc-helpers-CWZegVdR.mjs";
9
+ import { A as detectCreationIntent, E as isExcludedSwiftPath, F as docConsultedGate, I as evaluateApex, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, S as usesTailwindUtilities, T as isExcludedJsPath, _ as scanPlugin, c as EXCLUDE_DIRS$1, d as buildApexTaskInjection, h as buildClaudeMdContext, k as capVerbosity, l as PROJECT_INDICATORS, n as missingSeoElements, o as parseEnrichment, r as descFromText, s as parseEntry, t as isHtmlLike, w as frameworkSolidGate, x as skillTriggerGate, y as parseField } from "./validate-RzxKWIFC.mjs";
10
10
  import { n as findMarketplacePlugins, r as readPluginMeta, t as resolveSkillPath } from "./skill-path-DhItkBzk.mjs";
11
11
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
12
12
  import { a as nowStamp, l as throttleMs, n as readRoots, o as readState, s as setStateField, t as addRoot } from "./registry-CymilZiZ.mjs";
@@ -14,8 +14,8 @@ import { d as loadIndex, i as cacheLookupMeta, n as webfetchCacheWrite, o as cac
14
14
  import { t as loadRefs } from "./loader-AGz4nK7d.mjs";
15
15
  import { a as writeLastNonce, c as recordAgent, d as recordRefRead, f as recordTarget, h as apexAuthorizationGate, i as verifyTrack, l as recordBrainstormRequired, m as trivialCount, n as saveTrack, o as agentsFresh, p as recordTrivialEdit, r as signTrack, s as emptyTrack, t as loadTrack, u as recordDoc } from "./store-CQ4roWrU.mjs";
16
16
  import { n as parseApplyPatch, t as isBypassPermissions } from "./permission-mode-BN3MNgbm.mjs";
17
- import { _ as writeText, d as collectFiles, f as pathExists, g as spawnCapture, h as sleep, i as denyResponse, l as systemMessage, m as readText, n as blockResponse, r as contextResponse, s as informResponse, t as attachSystemMessage, v as commandToString } from "./claude-CHpb1U0A.mjs";
18
- import { r as toHermesResponse } from "./hermes-CddsFoPN.mjs";
17
+ import { _ as writeText, d as collectFiles, f as pathExists, g as spawnCapture, h as sleep, i as denyResponse, l as systemMessage, m as readText, n as blockResponse, r as contextResponse, s as informResponse, t as attachSystemMessage, v as commandToString } from "./claude-Z0pN-dqc.mjs";
18
+ import { r as toHermesResponse } from "./hermes-B8QmMtSK.mjs";
19
19
  import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
20
20
  import { appendFileSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, rmdirSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
21
21
  import { homedir } from "node:os";
@@ -790,16 +790,18 @@ function readRules(rulesDir) {
790
790
  return parts.join("\n\n");
791
791
  }
792
792
  /**
793
- * Build the rules injection for claude-rules (SessionStart + UserPromptSubmit):
794
- * read `<pluginRoot>/rules/*.md` and emit as `additionalContext`, or "" when no
795
- * rules. Ports `claude-rules/scripts/inject-rules.py` (which always tags the
796
- * output `hookEventName: "SessionStart"`, even on UserPromptSubmit).
793
+ * Build the rules injection for claude-rules (SessionStart, UserPromptSubmit,
794
+ * SubagentStart): read `<pluginRoot>/rules/*.md` and emit as `additionalContext`,
795
+ * or "" when no rules. Tags the output with the *actual* `hookEventName` — the
796
+ * spec requires it to match the firing event (a hardcoded "SessionStart" is
797
+ * non-conforming and may be dropped on UserPromptSubmit/SubagentStart).
797
798
  * @param pluginRoot - `CLAUDE_PLUGIN_ROOT` of the claude-rules plugin.
799
+ * @param event - The firing hook event name (e.g. "SessionStart").
798
800
  * @returns The native hook stdout (possibly empty).
799
801
  */
800
- function injectRules(pluginRoot) {
802
+ function injectRules(pluginRoot, event) {
801
803
  const content = readRules(join(pluginRoot, "rules"));
802
- return content ? contextResponse("SessionStart", content) : "";
804
+ return content ? contextResponse(event, content) : "";
803
805
  }
804
806
  //#endregion
805
807
  //#region src/runtime/lifecycle/solid-detect.ts
@@ -5313,7 +5315,7 @@ async function aipilotPostToolUse(payload, cwd) {
5313
5315
  /** SessionStart handler keyed on plugin scope. */
5314
5316
  function sessionStart(input) {
5315
5317
  if (input.scope === "solid") return solidDetectStart();
5316
- if (input.scope === "rules") return injectRules(process.env.CLAUDE_PLUGIN_ROOT ?? input.cwd);
5318
+ if (input.scope === "rules") return injectRules(process.env.CLAUDE_PLUGIN_ROOT ?? input.cwd, input.event);
5317
5319
  if (input.scope === "carto") return cartoSessionStart(input.cwd, input.now);
5318
5320
  if (input.scope === "lessons") return dispatchLessons("SessionStart", input.payload, input.cwd, input.now);
5319
5321
  const core = sessionStartCore(input.cwd, void 0, input.now);
@@ -5329,9 +5331,9 @@ function sessionStart(input) {
5329
5331
  function dispatchLifecycle(input) {
5330
5332
  switch (input.event) {
5331
5333
  case "SessionStart": return sessionStart(input);
5332
- case "UserPromptSubmit": return input.scope === "rules" ? injectRules(process.env.CLAUDE_PLUGIN_ROOT ?? input.cwd) : null;
5334
+ case "UserPromptSubmit": return input.scope === "rules" ? injectRules(process.env.CLAUDE_PLUGIN_ROOT ?? input.cwd, input.event) : null;
5333
5335
  case "SubagentStart":
5334
- if (input.scope === "rules") return injectRules(process.env.CLAUDE_PLUGIN_ROOT ?? input.cwd);
5336
+ if (input.scope === "rules") return injectRules(process.env.CLAUDE_PLUGIN_ROOT ?? input.cwd, input.event);
5335
5337
  if (input.scope === "aipilot") return "";
5336
5338
  if (input.scope === "lessons") return dispatchLessons("SubagentStart", input.payload, input.cwd, input.now);
5337
5339
  return subagentCacheContext(input.payload.session_id);
@@ -8916,7 +8918,7 @@ async function handleHook(id, payload, opts) {
8916
8918
  const layout = projectLayout(opts.cwd);
8917
8919
  const file = trackFile(event.sessionId, defaultStateDir(opts.cwd));
8918
8920
  const mcpDir = layout.cacheDir;
8919
- const framework = detectFramework(event.filePath ?? "", event.content ?? "");
8921
+ const framework = detectFramework(event.filePath ?? "", event.content ?? "", opts.cwd);
8920
8922
  if ((id === "claude-code" || id === "codex") && designLifecycle(payload, mcpDir, opts.cwd, String(opts.now), opts.now)) return {
8921
8923
  stdout: "",
8922
8924
  exit: 0
@@ -1,6 +1,6 @@
1
- import { t as evaluate } from "./evaluate-Dx6q1kmQ.mjs";
1
+ import { t as evaluate } from "./evaluate-DlM9ckLB.mjs";
2
2
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
3
- import { c as readClaudeInput, v as commandToString } from "./claude-CHpb1U0A.mjs";
3
+ import { c as readClaudeInput, v as commandToString } from "./claude-Z0pN-dqc.mjs";
4
4
  //#region src/adapters/hermes/index.ts
5
5
  /**
6
6
  * Hermes Agent adapter (hook-mode). Nous Research's hermes-agent (2026) pipes a
@@ -32,11 +32,19 @@ declare function detectProjectType(dir: string): ProjectType;
32
32
  //#endregion
33
33
  //#region src/policy/detect-framework.d.ts
34
34
  /**
35
- * Detect the framework from a file path extension + content patterns.
36
- * Aligned with the fusengine require-solid-read detection (distinct from
37
- * {@link detectProjectType}, which scans config files on disk).
38
- */
39
- declare function detectFramework(filePath: string, content: string): string;
35
+ * Detect a file's framework as the intersection of the REAL project (its nearest
36
+ * manifest's capabilities) and the file's own extension/content signal. A
37
+ * backend `.ts` in a react project is `generic` (no react signal) — fixing the
38
+ * old extension-only default that flagged every `.ts` as react. Fail-open: any
39
+ * error yields `"generic"`, never throws. Return values stay within the existing
40
+ * union ("react" | "nextjs" | "laravel" | "swift" | "tailwind" | "java" | "go" |
41
+ * "ruby" | "rust" | "generic") — no new labels.
42
+ * @param filePath - Path of the file being written/edited.
43
+ * @param content - Its (incoming) content, for JS content signals.
44
+ * @param cwd - Root to resolve a relative `filePath` against (default cwd).
45
+ * @returns A framework label from the existing union.
46
+ */
47
+ declare function detectFramework(filePath: string, content: string, cwd?: string): string;
40
48
  //#endregion
41
49
  //#region src/policy/file-size.d.ts
42
50
  /**
package/dist/index.d.mts CHANGED
@@ -5,7 +5,7 @@ import { a as HarnessInfo, i as HarnessId, n as detectMode, o as HarnessMode, r
5
5
  import { a as isDocConsulted, i as formatDocSatisfactionStatus, n as DocSatisfactionStatus, o as resolveSessions, r as formatDocDeny, t as AuthEntry } from "./doc-helpers-CEKzGg2u.mjs";
6
6
  import { t as incrementTrivialEditCounter } from "./index-BOBXQ91y.mjs";
7
7
  import { a as compactJson, i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./index-BEMumjOw.mjs";
8
- import { $ as ASK_PATTERNS, A as FAIL_CLOSED, B as SWIFT_PROTO_RE, C as usesTailwindUtilities, Ct as ModularArchitecture, D as MAX_TOKENS, Dt as isApexCommand, E as MAX_EXA_RESULTS, Et as detectProjectType, F as installGuard, G as CODE_MUTATORS, H as interfaceSeparationGuard, I as GO_DECL_RE, J as SAFE_PREFIXES, K as CODE_REDIRECT, L as JAVA_DECL_RE, M as clearUserGuards, N as registerGuard, O as capVerbosity, Ot as requiredArchSkill, P as runGuards, Q as protectedPathGuard, R as PHP_DECL_RE, S as skillTriggerGate, St as DEV_KEYWORDS, T as frameworkSolidGate, Tt as detectModularArchitecture, U as bashWriteGuard, V as TS_DECL_RE, W as ASK_WRITERS, X as PROTECTED_FRAGMENTS, Y as SESSION_STATE_FRAGMENT, Z as PROTECTED_GIT_RE, _ as DEV_VERBS, _t as SOLID_REF, a as firstHeading, at as evaluate, b as detectClaudeMdProjectType, bt as evaluateFileSize, c as parseEntry, ct as GIT_ASK, d as EXCLUDE_DIRS, dt as RALPH_SAFE, et as CRITICAL_PATTERNS, f as PROJECT_INDICATORS, ft as SYSTEM_INSTALL, g as loadApexTaskState, gt as PLUGINS_DIR, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as GuardContext, j as GUARDS, k as detectCreationIntent, l as parseBodyDesc, lt as GIT_BLOCKED, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as securityGuard, o as TreeEntry, ot as PolicyContext, p as ApexTaskState, pt as isRalphMode, q as FILE_REDIRECT, r as descFromText, rt as Guard, s as parseEnrichment, st as PolicyResult, t as isHtmlLike, tt as LabeledPattern, u as parseField, ut as PROJECT_INSTALL, v as buildApexInstruction, vt as countFrameworkCodeLines, w as SKILL_TRIGGERS, wt as ProjectType, x as detectRequiredSkills, xt as detectFramework, y as buildClaudeMdContext, yt as countLines, z as PY_MODEL_RE } from "./index-DzOJraAT.mjs";
8
+ import { $ as ASK_PATTERNS, A as FAIL_CLOSED, B as SWIFT_PROTO_RE, C as usesTailwindUtilities, Ct as ModularArchitecture, D as MAX_TOKENS, Dt as isApexCommand, E as MAX_EXA_RESULTS, Et as detectProjectType, F as installGuard, G as CODE_MUTATORS, H as interfaceSeparationGuard, I as GO_DECL_RE, J as SAFE_PREFIXES, K as CODE_REDIRECT, L as JAVA_DECL_RE, M as clearUserGuards, N as registerGuard, O as capVerbosity, Ot as requiredArchSkill, P as runGuards, Q as protectedPathGuard, R as PHP_DECL_RE, S as skillTriggerGate, St as DEV_KEYWORDS, T as frameworkSolidGate, Tt as detectModularArchitecture, U as bashWriteGuard, V as TS_DECL_RE, W as ASK_WRITERS, X as PROTECTED_FRAGMENTS, Y as SESSION_STATE_FRAGMENT, Z as PROTECTED_GIT_RE, _ as DEV_VERBS, _t as SOLID_REF, a as firstHeading, at as evaluate, b as detectClaudeMdProjectType, bt as evaluateFileSize, c as parseEntry, ct as GIT_ASK, d as EXCLUDE_DIRS, dt as RALPH_SAFE, et as CRITICAL_PATTERNS, f as PROJECT_INDICATORS, ft as SYSTEM_INSTALL, g as loadApexTaskState, gt as PLUGINS_DIR, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as GuardContext, j as GUARDS, k as detectCreationIntent, l as parseBodyDesc, lt as GIT_BLOCKED, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as securityGuard, o as TreeEntry, ot as PolicyContext, p as ApexTaskState, pt as isRalphMode, q as FILE_REDIRECT, r as descFromText, rt as Guard, s as parseEnrichment, st as PolicyResult, t as isHtmlLike, tt as LabeledPattern, u as parseField, ut as PROJECT_INSTALL, v as buildApexInstruction, vt as countFrameworkCodeLines, w as SKILL_TRIGGERS, wt as ProjectType, x as detectRequiredSkills, xt as detectFramework, y as buildClaudeMdContext, yt as countLines, z as PY_MODEL_RE } from "./index-eNTFpuby.mjs";
9
9
  import { n as RouteResult, r as ScoredRef, t as RefMeta } from "./types-CY5qT2X1.mjs";
10
10
  import { a as PRE_AUTH_GATES, c as evaluateApex, i as POST_AUTH_GATES, l as freshnessGate, n as ApexContext, o as brainstormGate, r as ApexGate, s as docConsultedGate, t as APEX_GATES, u as solidReadGate } from "./apex-Wdi1nq_w.mjs";
11
11
  import { a as ReminderState, c as readState, d as throttleMs, i as registryFile, l as setStateField, n as addRoot, o as lessonsFileFor, r as readRoots, s as nowStamp, t as ensureMemoryGitignore, u as stateFileFor } from "./index-DLYhervv.mjs";
package/dist/index.mjs CHANGED
@@ -4,11 +4,11 @@ import { n as STATE_ROOT, r as projectLayout, t as STATE_GITIGNORE } from "./lay
4
4
  import { t as compactJson } from "./compact-json-DK2nX-MK.mjs";
5
5
  import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
6
6
  import { n as detectMode, r as modeFor, t as detectHarness } from "./harness-Cb9xR8dC.mjs";
7
- import { A as detectCreationIntent, B as DEV_KEYWORDS, C as SKILL_TRIGGERS, D as MAX_EXA_RESULTS, F as docConsultedGate, H as detectProjectType, I as evaluateApex, L as freshnessGate, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, O as MAX_TOKENS, P as brainstormGate, R as solidReadGate, S as usesTailwindUtilities, U as isApexCommand, V as detectModularArchitecture, W as requiredArchSkill, a as firstHeading, b as detectRequiredSkills, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as APEX_GATES, k as capVerbosity, l as PROJECT_INDICATORS, m as buildApexInstruction, n as missingSeoElements, o as parseEnrichment, p as DEV_VERBS, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, v as parseBodyDesc, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "./validate-DnOqIZD_.mjs";
7
+ import { A as PROJECT_INSTALL, B as requiredArchSkill, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, F as detectFramework, I as DEV_KEYWORDS, L as detectModularArchitecture, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, R as detectProjectType, S as PROTECTED_FRAGMENTS, T as ASK_PATTERNS, _ as CODE_MUTATORS, a as registerGuard, b as SAFE_PREFIXES, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as ASK_WRITERS, h as bashWriteGuard, i as clearUserGuards, j as RALPH_SAFE, k as GIT_BLOCKED, 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 CODE_REDIRECT, w as protectedPathGuard, x as SESSION_STATE_FRAGMENT, y as FILE_REDIRECT, z as isApexCommand } from "./evaluate-DlM9ckLB.mjs";
8
8
  import { d as countFrameworkCodeLines, f as countLines, l as PLUGINS_DIR, p as evaluateFileSize, u as SOLID_REF } from "./home-state-D0RLWP8J.mjs";
9
- import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, S as PROTECTED_FRAGMENTS, T as ASK_PATTERNS, _ as CODE_MUTATORS, a as registerGuard, b as SAFE_PREFIXES, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as ASK_WRITERS, h as bashWriteGuard, i as clearUserGuards, j as RALPH_SAFE, k as GIT_BLOCKED, 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 CODE_REDIRECT, w as protectedPathGuard, x as SESSION_STATE_FRAGMENT, y as FILE_REDIRECT } from "./evaluate-Dx6q1kmQ.mjs";
10
9
  import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-CWZegVdR.mjs";
11
10
  import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-PKVNBHge.mjs";
11
+ import { A as detectCreationIntent, C as SKILL_TRIGGERS, D as MAX_EXA_RESULTS, F as docConsultedGate, I as evaluateApex, L as freshnessGate, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, O as MAX_TOKENS, P as brainstormGate, R as solidReadGate, S as usesTailwindUtilities, a as firstHeading, b as detectRequiredSkills, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as APEX_GATES, k as capVerbosity, l as PROJECT_INDICATORS, m as buildApexInstruction, n as missingSeoElements, o as parseEnrichment, p as DEV_VERBS, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, v as parseBodyDesc, w as frameworkSolidGate, x as skillTriggerGate, y as parseField } from "./validate-RzxKWIFC.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-CymilZiZ.mjs";
14
14
  import { a as cacheLookupSubstring, c as cacheStore, d as loadIndex, f as summarizeIndex, h as queryHash, i as cacheLookupMeta, l as mcpCacheKey, m as jaccardSimilar, n as webfetchCacheWrite, o as cacheLookupSubstringMeta, p as compactMarkdown, r as cacheLookup, s as cachePath, t as mcpCacheWrite, u as extractText } from "./mcp-store-BkBDmuxN.mjs";
@@ -1,3 +1,3 @@
1
- import { $ as ASK_PATTERNS, A as FAIL_CLOSED, B as SWIFT_PROTO_RE, C as usesTailwindUtilities, Ct as ModularArchitecture, D as MAX_TOKENS, Dt as isApexCommand, E as MAX_EXA_RESULTS, Et as detectProjectType, F as installGuard, G as CODE_MUTATORS, H as interfaceSeparationGuard, I as GO_DECL_RE, J as SAFE_PREFIXES, K as CODE_REDIRECT, L as JAVA_DECL_RE, M as clearUserGuards, N as registerGuard, O as capVerbosity, Ot as requiredArchSkill, P as runGuards, Q as protectedPathGuard, R as PHP_DECL_RE, S as skillTriggerGate, St as DEV_KEYWORDS, T as frameworkSolidGate, Tt as detectModularArchitecture, U as bashWriteGuard, V as TS_DECL_RE, W as ASK_WRITERS, X as PROTECTED_FRAGMENTS, Y as SESSION_STATE_FRAGMENT, Z as PROTECTED_GIT_RE, _ as DEV_VERBS, _t as SOLID_REF, a as firstHeading, at as evaluate, b as detectClaudeMdProjectType, bt as evaluateFileSize, c as parseEntry, ct as GIT_ASK, d as EXCLUDE_DIRS, dt as RALPH_SAFE, et as CRITICAL_PATTERNS, f as PROJECT_INDICATORS, ft as SYSTEM_INSTALL, g as loadApexTaskState, gt as PLUGINS_DIR, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as GuardContext, j as GUARDS, k as detectCreationIntent, l as parseBodyDesc, lt as GIT_BLOCKED, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as securityGuard, o as TreeEntry, ot as PolicyContext, p as ApexTaskState, pt as isRalphMode, q as FILE_REDIRECT, r as descFromText, rt as Guard, s as parseEnrichment, st as PolicyResult, t as isHtmlLike, tt as LabeledPattern, u as parseField, ut as PROJECT_INSTALL, v as buildApexInstruction, vt as countFrameworkCodeLines, w as SKILL_TRIGGERS, wt as ProjectType, x as detectRequiredSkills, xt as detectFramework, y as buildClaudeMdContext, yt as countLines, z as PY_MODEL_RE } from "../index-DzOJraAT.mjs";
1
+ import { $ as ASK_PATTERNS, A as FAIL_CLOSED, B as SWIFT_PROTO_RE, C as usesTailwindUtilities, Ct as ModularArchitecture, D as MAX_TOKENS, Dt as isApexCommand, E as MAX_EXA_RESULTS, Et as detectProjectType, F as installGuard, G as CODE_MUTATORS, H as interfaceSeparationGuard, I as GO_DECL_RE, J as SAFE_PREFIXES, K as CODE_REDIRECT, L as JAVA_DECL_RE, M as clearUserGuards, N as registerGuard, O as capVerbosity, Ot as requiredArchSkill, P as runGuards, Q as protectedPathGuard, R as PHP_DECL_RE, S as skillTriggerGate, St as DEV_KEYWORDS, T as frameworkSolidGate, Tt as detectModularArchitecture, U as bashWriteGuard, V as TS_DECL_RE, W as ASK_WRITERS, X as PROTECTED_FRAGMENTS, Y as SESSION_STATE_FRAGMENT, Z as PROTECTED_GIT_RE, _ as DEV_VERBS, _t as SOLID_REF, a as firstHeading, at as evaluate, b as detectClaudeMdProjectType, bt as evaluateFileSize, c as parseEntry, ct as GIT_ASK, d as EXCLUDE_DIRS, dt as RALPH_SAFE, et as CRITICAL_PATTERNS, f as PROJECT_INDICATORS, ft as SYSTEM_INSTALL, g as loadApexTaskState, gt as PLUGINS_DIR, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as GuardContext, j as GUARDS, k as detectCreationIntent, l as parseBodyDesc, lt as GIT_BLOCKED, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as securityGuard, o as TreeEntry, ot as PolicyContext, p as ApexTaskState, pt as isRalphMode, q as FILE_REDIRECT, r as descFromText, rt as Guard, s as parseEnrichment, st as PolicyResult, t as isHtmlLike, tt as LabeledPattern, u as parseField, ut as PROJECT_INSTALL, v as buildApexInstruction, vt as countFrameworkCodeLines, w as SKILL_TRIGGERS, wt as ProjectType, x as detectRequiredSkills, xt as detectFramework, y as buildClaudeMdContext, yt as countLines, z as PY_MODEL_RE } from "../index-eNTFpuby.mjs";
2
2
  import { a as PRE_AUTH_GATES, c as evaluateApex, i as POST_AUTH_GATES, l as freshnessGate, n as ApexContext, o as brainstormGate, r as ApexGate, s as docConsultedGate, t as APEX_GATES, u as solidReadGate } from "../apex-Wdi1nq_w.mjs";
3
3
  export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, ApexContext, ApexGate, ApexTaskState, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, FILE_REDIRECT, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, Guard, GuardContext, JAVA_DECL_RE, LabeledPattern, MAX_EXA_RESULTS, MAX_TOKENS, ModularArchitecture, PHP_DECL_RE, PLUGINS_DIR, POST_AUTH_GATES, PRE_AUTH_GATES, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PROTECTED_GIT_RE, PY_MODEL_RE, type PolicyContext, type PolicyResult, ProjectType, RALPH_SAFE, SAFE_PREFIXES, SESSION_STATE_FRAGMENT, SKILL_TRIGGERS, SOLID_REF, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, TreeEntry, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countFrameworkCodeLines, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, isHtmlLike, isRalphMode, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate, usesTailwindUtilities };
@@ -1,5 +1,5 @@
1
- import { A as detectCreationIntent, B as DEV_KEYWORDS, C as SKILL_TRIGGERS, D as MAX_EXA_RESULTS, F as docConsultedGate, H as detectProjectType, I as evaluateApex, L as freshnessGate, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, O as MAX_TOKENS, P as brainstormGate, R as solidReadGate, S as usesTailwindUtilities, U as isApexCommand, V as detectModularArchitecture, W as requiredArchSkill, a as firstHeading, b as detectRequiredSkills, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as APEX_GATES, k as capVerbosity, l as PROJECT_INDICATORS, m as buildApexInstruction, n as missingSeoElements, o as parseEnrichment, p as DEV_VERBS, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, v as parseBodyDesc, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "../validate-DnOqIZD_.mjs";
1
+ import { A as PROJECT_INSTALL, B as requiredArchSkill, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, F as detectFramework, I as DEV_KEYWORDS, L as detectModularArchitecture, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, R as detectProjectType, S as PROTECTED_FRAGMENTS, T as ASK_PATTERNS, _ as CODE_MUTATORS, a as registerGuard, b as SAFE_PREFIXES, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as ASK_WRITERS, h as bashWriteGuard, i as clearUserGuards, j as RALPH_SAFE, k as GIT_BLOCKED, 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 CODE_REDIRECT, w as protectedPathGuard, x as SESSION_STATE_FRAGMENT, y as FILE_REDIRECT, z as isApexCommand } from "../evaluate-DlM9ckLB.mjs";
2
2
  import { d as countFrameworkCodeLines, f as countLines, l as PLUGINS_DIR, p as evaluateFileSize, u as SOLID_REF } from "../home-state-D0RLWP8J.mjs";
3
- import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, S as PROTECTED_FRAGMENTS, T as ASK_PATTERNS, _ as CODE_MUTATORS, a as registerGuard, b as SAFE_PREFIXES, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as ASK_WRITERS, h as bashWriteGuard, i as clearUserGuards, j as RALPH_SAFE, k as GIT_BLOCKED, 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 CODE_REDIRECT, w as protectedPathGuard, x as SESSION_STATE_FRAGMENT, y as FILE_REDIRECT } from "../evaluate-Dx6q1kmQ.mjs";
3
+ import { A as detectCreationIntent, C as SKILL_TRIGGERS, D as MAX_EXA_RESULTS, F as docConsultedGate, I as evaluateApex, L as freshnessGate, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, O as MAX_TOKENS, P as brainstormGate, R as solidReadGate, S as usesTailwindUtilities, a as firstHeading, b as detectRequiredSkills, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as APEX_GATES, k as capVerbosity, l as PROJECT_INDICATORS, m as buildApexInstruction, n as missingSeoElements, o as parseEnrichment, p as DEV_VERBS, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, v as parseBodyDesc, w as frameworkSolidGate, x as skillTriggerGate, y as parseField } from "../validate-RzxKWIFC.mjs";
4
4
  import "../policy-la_KkjCS.mjs";
5
5
  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, PLUGINS_DIR, POST_AUTH_GATES, PRE_AUTH_GATES, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PROTECTED_GIT_RE, PY_MODEL_RE, RALPH_SAFE, SAFE_PREFIXES, SESSION_STATE_FRAGMENT, SKILL_TRIGGERS, SOLID_REF, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countFrameworkCodeLines, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, isHtmlLike, isRalphMode, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate, usesTailwindUtilities };
@@ -1,5 +1,5 @@
1
1
  import { t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
2
- import { t as evaluate } from "./evaluate-Dx6q1kmQ.mjs";
2
+ import { t as evaluate } from "./evaluate-DlM9ckLB.mjs";
3
3
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
4
4
  import { execSync } from "node:child_process";
5
5
  //#region src/cli/run.ts
@@ -352,14 +352,16 @@ declare function sessionStartCore(cwd: string, home?: string, now?: number): str
352
352
  /** Read & concatenate all `*.md` files (sorted) under `rulesDir`. */
353
353
  declare function readRules(rulesDir: string): string;
354
354
  /**
355
- * Build the rules injection for claude-rules (SessionStart + UserPromptSubmit):
356
- * read `<pluginRoot>/rules/*.md` and emit as `additionalContext`, or "" when no
357
- * rules. Ports `claude-rules/scripts/inject-rules.py` (which always tags the
358
- * output `hookEventName: "SessionStart"`, even on UserPromptSubmit).
355
+ * Build the rules injection for claude-rules (SessionStart, UserPromptSubmit,
356
+ * SubagentStart): read `<pluginRoot>/rules/*.md` and emit as `additionalContext`,
357
+ * or "" when no rules. Tags the output with the *actual* `hookEventName` — the
358
+ * spec requires it to match the firing event (a hardcoded "SessionStart" is
359
+ * non-conforming and may be dropped on UserPromptSubmit/SubagentStart).
359
360
  * @param pluginRoot - `CLAUDE_PLUGIN_ROOT` of the claude-rules plugin.
361
+ * @param event - The firing hook event name (e.g. "SessionStart").
360
362
  * @returns The native hook stdout (possibly empty).
361
363
  */
362
- declare function injectRules(pluginRoot: string): string;
364
+ declare function injectRules(pluginRoot: string, event: string): string;
363
365
  //#endregion
364
366
  //#region src/runtime/lifecycle/solid-detect.d.ts
365
367
  /** A SOLID project profile: type label, per-file line limit, interface dir. */
@@ -820,7 +822,7 @@ declare function lifecycleStdout(payload: Record<string, unknown>, cwd: string,
820
822
  */
821
823
  declare function postEditContext(scope: PluginScope, event: NormalizedEvent, now: number): Promise<string>;
822
824
  //#endregion
823
- //#region src/runtime/handle.d.ts
825
+ //#region src/runtime/handle-types.d.ts
824
826
  /** Options for {@link handleHook} (caller supplies the clock + project root). */
825
827
  interface HandleOptions {
826
828
  now: number;
@@ -837,6 +839,8 @@ interface HandleOutcome {
837
839
  stdout: string;
838
840
  exit: number;
839
841
  }
842
+ //#endregion
843
+ //#region src/runtime/handle.d.ts
840
844
  /**
841
845
  * The full hook handler: on a PRE event it gates the tool-use (stateless guards
842
846
  * then APEX gates from the session track) and returns the native response; on a
@@ -863,4 +867,4 @@ interface PreContext {
863
867
  */
864
868
  declare function handlePre(ctx: PreContext): Promise<HandleOutcome>;
865
869
  //#endregion
866
- export { Activity, DEFAULT_WINDOW_MS, DuplicationVerdict, type GateInput, HandleOptions, HandleOutcome, LifecycleInput, MCP_TTL_MS, McpIntercept, NormalizedEvent, NormalizedFile, PluginScope, PreContext, REQUIRED_AGENTS, SolidProfile, TRIVIAL_BUDGET, ToolEvent, WEBFETCH_TTL_MS, activityFor, aipilotPostToolUse, cacheQueryOf, cartoSessionStart, checkFileSize, claudeHome, claudeMdKey, cleanupSession, countFiles, countLoc, defaultStateDir, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dispatchMemory, dryGate, extractSymbols, fuseHarnessHome, fusengineCache, gate, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lessonsArchiveFileFor, lessonsFileFor, lessonsStateFileFor, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, projectHash, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityAdvisoryForPatch, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateSolidGate, validateTailwind, validateTeammateOutput, writePluginMap, writeTree };
870
+ export { Activity, DEFAULT_WINDOW_MS, DuplicationVerdict, type GateInput, type HandleOptions, type HandleOutcome, LifecycleInput, MCP_TTL_MS, McpIntercept, NormalizedEvent, NormalizedFile, PluginScope, PreContext, REQUIRED_AGENTS, SolidProfile, TRIVIAL_BUDGET, ToolEvent, WEBFETCH_TTL_MS, activityFor, aipilotPostToolUse, cacheQueryOf, cartoSessionStart, checkFileSize, claudeHome, claudeMdKey, cleanupSession, countFiles, countLoc, defaultStateDir, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dispatchMemory, dryGate, extractSymbols, fuseHarnessHome, fusengineCache, gate, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lessonsArchiveFileFor, lessonsFileFor, lessonsStateFileFor, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, projectHash, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityAdvisoryForPatch, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateSolidGate, validateTailwind, validateTeammateOutput, writePluginMap, writeTree };
@@ -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-ClfFahJs.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-Cw1H21Eg.mjs";
4
4
  //#region src/runtime/storage.ts
5
5
  /**
6
6
  * The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
@@ -1,5 +1,6 @@
1
1
  import { r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
2
2
  import { c as ttlLabel } from "./dotenv-Jj8aL1FL.mjs";
3
+ import { I as DEV_KEYWORDS } from "./evaluate-DlM9ckLB.mjs";
3
4
  import { d as countFrameworkCodeLines, l as PLUGINS_DIR, u as SOLID_REF } from "./home-state-D0RLWP8J.mjs";
4
5
  import { r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-CWZegVdR.mjs";
5
6
  import { t as routeReferences } from "./router-PKVNBHge.mjs";
@@ -7,107 +8,6 @@ import { n as findMarketplacePlugins, r as readPluginMeta, t as resolveSkillPath
7
8
  import { extname, join } from "node:path";
8
9
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
9
10
  import { homedir } from "node:os";
10
- //#region src/policy/detect-project.ts
11
- /** Keywords that signal a development task (APEX trigger). */
12
- const DEV_KEYWORDS = /\b(implement|create|build|fix|add|refactor|develop|feature|bug|update|modify|change|write|code)\b/i;
13
- /** True when the prompt invokes the /apex command. */
14
- function isApexCommand(prompt) {
15
- return /(?:^|\s)\/apex|\/fuse-ai-pilot:apex/i.test(prompt);
16
- }
17
- /**
18
- * Detect a project-internal modular architecture (a sub-architecture the
19
- * framework-level {@link detectProjectType} doesn't capture): Fusengine's
20
- * FuseCore (Laravel) or a `modules/`-based Next.js layout.
21
- */
22
- function detectModularArchitecture(dir) {
23
- const has = (f) => existsSync(join(dir, f));
24
- if (has("FuseCore") && has("artisan")) return "fusecore";
25
- if (has("modules") && (has("next.config.js") || has("next.config.ts") || has("next.config.mjs"))) return "nextjs-modular";
26
- return null;
27
- }
28
- /**
29
- * Resolve the skill a detected modular architecture forces.
30
- *
31
- * Ports the Python `check-nextjs-skill.py` / `check-laravel-skill.py` gates:
32
- * when the project is detected on disk as a modular architecture, a specific
33
- * skill is required ('solid-nextjs' for nextjs-modular, 'fusecore' for
34
- * fusecore). Returns `null` when no modular architecture is detected.
35
- *
36
- * @param cwd - Project root directory to scan.
37
- * @returns The forced skill name, or `null` when none applies.
38
- */
39
- function requiredArchSkill(cwd) {
40
- switch (detectModularArchitecture(cwd)) {
41
- case "nextjs-modular": return "solid-nextjs";
42
- case "fusecore": return "fusecore";
43
- default: return null;
44
- }
45
- }
46
- /** Config file names that mark a project as using Tailwind (v3 JS config or legacy). */
47
- const TAILWIND_CONFIG_FILES = [
48
- "tailwind.config.js",
49
- "tailwind.config.ts",
50
- "tailwind.config.mjs",
51
- "tailwind.config.cjs"
52
- ];
53
- /** True when `package.json` lists `tailwindcss` as a dep (Tailwind v4 CSS-first, no config file). */
54
- function hasTailwindDependency(dir) {
55
- const pkgPath = join(dir, "package.json");
56
- if (!existsSync(pkgPath)) return false;
57
- try {
58
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
59
- return "tailwindcss" in {
60
- ...pkg.dependencies,
61
- ...pkg.devDependencies
62
- };
63
- } catch {
64
- return false;
65
- }
66
- }
67
- /** Detect the project type by scanning config files in `dir`. */
68
- function detectProjectType(dir) {
69
- const has = (f) => existsSync(join(dir, f));
70
- if (has("next.config.js") || has("next.config.ts") || has("next.config.mjs")) return "nextjs";
71
- if (has("nuxt.config.ts") || has("nuxt.config.js")) return "nuxt";
72
- if (has("angular.json")) return "angular";
73
- if (has("svelte.config.js") || has("svelte.config.ts")) return "svelte";
74
- if (has("vite.config.ts") && has("src/App.vue")) return "vue";
75
- if (has("vite.config.ts") || has("vite.config.js")) return "react";
76
- if (TAILWIND_CONFIG_FILES.some(has) || hasTailwindDependency(dir)) return "tailwind";
77
- if (has("composer.json") && has("artisan")) return "laravel";
78
- if (has("Gemfile") && has("config/routes.rb")) return "rails";
79
- if (has("requirements.txt") || has("pyproject.toml") || has("setup.py")) return has("manage.py") ? "django" : "python";
80
- if (has("go.mod")) return "go";
81
- if (has("Cargo.toml")) return "rust";
82
- if (has("Package.swift")) return "swift";
83
- if (has("pom.xml") || has("build.gradle") || has("build.gradle.kts")) return "java";
84
- if (has("build.sbt")) return "scala";
85
- if (has("mix.exs")) return "elixir";
86
- if (has("Gemfile")) return "ruby";
87
- return "generic";
88
- }
89
- //#endregion
90
- //#region src/policy/detect-framework.ts
91
- /**
92
- * Detect the framework from a file path extension + content patterns.
93
- * Aligned with the fusengine require-solid-read detection (distinct from
94
- * {@link detectProjectType}, which scans config files on disk).
95
- */
96
- function detectFramework(filePath, content) {
97
- if (/\.(tsx?|jsx?|vue|svelte)$/.test(filePath) || /from ['"]react|useState|className=/.test(content)) {
98
- if (/(page|layout|loading|error|route|middleware)\.(ts|tsx)$/.test(filePath) || /use client|use server|NextRequest|NextResponse|from ['"]next|getServerSideProps|getStaticProps/.test(content)) return "nextjs";
99
- return "react";
100
- }
101
- if (/\.swift$/.test(filePath)) return "swift";
102
- if (/\.php$/.test(filePath)) return "laravel";
103
- if (/\.java$/.test(filePath)) return "java";
104
- if (/\.go$/.test(filePath)) return "go";
105
- if (/\.rb$/.test(filePath)) return "ruby";
106
- if (/\.rs$/.test(filePath)) return "rust";
107
- if (/\.css$/.test(filePath) || /@tailwind|@apply/.test(content)) return "tailwind";
108
- return "generic";
109
- }
110
- //#endregion
111
11
  //#region src/refs/ref-key.ts
112
12
  /**
113
13
  * Path shapes {@link discoverRefs}'s `skillParents` treats as legitimate skill
@@ -1523,4 +1423,4 @@ function missingSeoElements(html) {
1523
1423
  return missing;
1524
1424
  }
1525
1425
  //#endregion
1526
- export { detectCreationIntent as A, DEV_KEYWORDS as B, SKILL_TRIGGERS as C, MAX_EXA_RESULTS as D, isExcludedSwiftPath as E, docConsultedGate as F, detectProjectType as H, evaluateApex as I, freshnessGate as L, POST_AUTH_GATES as M, PRE_AUTH_GATES as N, MAX_TOKENS as O, brainstormGate as P, solidReadGate as R, usesTailwindUtilities as S, isExcludedJsPath as T, isApexCommand as U, detectModularArchitecture as V, requiredArchSkill as W, scanPlugin as _, firstHeading as a, detectRequiredSkills as b, EXCLUDE_DIRS as c, buildApexTaskInjection as d, loadApexTaskState as f, detectClaudeMdProjectType as g, buildClaudeMdContext as h, firstComment as i, APEX_GATES as j, capVerbosity as k, PROJECT_INDICATORS as l, buildApexInstruction as m, missingSeoElements as n, parseEnrichment as o, DEV_VERBS as p, descFromText as r, parseEntry as s, isHtmlLike as t, buildApexTaskContext as u, parseBodyDesc as v, frameworkSolidGate as w, skillTriggerGate as x, parseField as y, detectFramework as z };
1426
+ export { detectCreationIntent as A, SKILL_TRIGGERS as C, MAX_EXA_RESULTS as D, isExcludedSwiftPath as E, docConsultedGate as F, evaluateApex as I, freshnessGate as L, POST_AUTH_GATES as M, PRE_AUTH_GATES as N, MAX_TOKENS as O, brainstormGate as P, solidReadGate as R, usesTailwindUtilities as S, isExcludedJsPath as T, scanPlugin as _, firstHeading as a, detectRequiredSkills as b, EXCLUDE_DIRS as c, buildApexTaskInjection as d, loadApexTaskState as f, detectClaudeMdProjectType as g, buildClaudeMdContext as h, firstComment as i, APEX_GATES as j, capVerbosity as k, PROJECT_INDICATORS as l, buildApexInstruction as m, missingSeoElements as n, parseEnrichment as o, DEV_VERBS as p, descFromText as r, parseEntry as s, isHtmlLike as t, buildApexTaskContext as u, parseBodyDesc as v, frameworkSolidGate as w, skillTriggerGate as x, parseField as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusengine/harness",
3
- "version": "0.1.70",
3
+ "version": "0.1.72",
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",