@fusengine/harness 0.1.45 → 0.1.47
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 +4 -0
- package/dist/adapters/claude/index.mjs +1 -1
- package/dist/adapters/cline/index.mjs +1 -1
- package/dist/adapters/codex/index.mjs +1 -1
- package/dist/adapters/cursor/index.mjs +1 -1
- package/dist/adapters/gemini/index.mjs +1 -1
- package/dist/{claude-DLh0fHWM.mjs → claude-U1KTaRG4.mjs} +1 -1
- package/dist/cli/bin.mjs +2 -2
- package/dist/cli/index.mjs +1 -1
- package/dist/{evaluate-d7Pp8XJH.mjs → evaluate-qYC5xClb.mjs} +52 -13
- package/dist/{handle-DJaaD2BT.mjs → handle-DUlUbhyF.mjs} +158 -28
- package/dist/{index-CVhw7eA0.d.mts → index-l9Xvxrx7.d.mts} +23 -3
- package/dist/index.d.mts +2 -3
- package/dist/index.mjs +3 -4
- package/dist/policy/index.d.mts +2 -2
- package/dist/policy/index.mjs +3 -3
- package/dist/{run-DLXtA5DH.mjs → run-CaqeQFYp.mjs} +1 -1
- package/dist/runtime/index.d.mts +2 -0
- package/dist/runtime/index.mjs +1 -1
- package/dist/{validate-DcQaKzau.mjs → validate-DVV4nRfr.mjs} +13 -7
- package/package.json +2 -7
- package/dist/index-BA-SqNR7.d.mts +0 -59
- package/dist/state/index.d.mts +0 -2
- package/dist/state/index.mjs +0 -2
- package/dist/state-9lWvvWk8.mjs +0 -104
package/README.md
CHANGED
|
@@ -116,6 +116,8 @@ Ten portable guards + the APEX gate chain, all evaluated before a tool runs:
|
|
|
116
116
|
| APEX freshness | `explore-codebase` + `research-expert` not run within the window |
|
|
117
117
|
| APEX doc-consulted | no doc source (Context7 / Exa / fuse-browser / WebSearch / WebFetch) consulted this session |
|
|
118
118
|
| APEX solid-read | required SOLID refs (auto-discovered, or `FUSE_HARNESS_REFS`) not read |
|
|
119
|
+
| framework sub-skill | framework / shadcn / Tailwind code whose required skill (`skills/<name>/`) wasn't read this session |
|
|
120
|
+
| Gemini MCP (opt-in) | hand-written Tailwind UI without a `mcp__gemini-design__*` call — only when `FUSE_ENFORCE_GEMINI_MCP` is set |
|
|
119
121
|
| brainstorm | creating a new file without brainstorming (when flagged) |
|
|
120
122
|
| MCP verbosity / cache | caps exa `numResults`; serves a fresh cached MCP/WebFetch result |
|
|
121
123
|
|
|
@@ -131,6 +133,8 @@ through per window without the full APEX gates.
|
|
|
131
133
|
| `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. |
|
|
132
134
|
| `FUSE_ENFORCE_TTL_SEC` | APEX freshness window in seconds. |
|
|
133
135
|
| `FUSE_LESSONS_THROTTLE_MIN` | Lessons-injection throttle (memory module). |
|
|
136
|
+
| `FUSE_ENFORCE_GEMINI_MCP` | **Opt-in (default off).** `1`/`true` blocks hand-written Tailwind UI (`.tsx/.jsx/.vue/.svelte`, ≥3 utility classes) until a `mcp__gemini-design__*` call is made this session. Read fresh per call. |
|
|
137
|
+
| `RALPH_MODE` | **Opt-in (default off).** `1`/`true` enables autonomous "Ralph" mode: exempts the safe git commands (`add`/`commit`/`checkout -b`/`status`/`diff`/`log`) from the confirmation ASK and auto-approves project installs. Destructive git (force-push, `reset --hard`) and system installs still gate. |
|
|
134
138
|
|
|
135
139
|
## Library usage
|
|
136
140
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as guard, c as toClaudeResponse, i as fileSizeGuard, n as contextResponse, o as readClaudeInput, r as denyResponse, s as systemMessage, t as blockResponse } from "../../claude-
|
|
1
|
+
import { a as guard, c as toClaudeResponse, i as fileSizeGuard, n as contextResponse, o as readClaudeInput, r as denyResponse, s as systemMessage, t as blockResponse } from "../../claude-U1KTaRG4.mjs";
|
|
2
2
|
export { blockResponse, contextResponse, denyResponse, fileSizeGuard, guard, readClaudeInput, systemMessage, toClaudeResponse };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as guard, n as contextResponse, o as readClaudeInput, r as denyResponse } from "../../claude-
|
|
1
|
+
import { a as guard, n as contextResponse, o as readClaudeInput, r as denyResponse } from "../../claude-U1KTaRG4.mjs";
|
|
2
2
|
export { contextResponse, denyResponse, guard, readClaudeInput as readCodexInput };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as evaluate } from "./evaluate-
|
|
1
|
+
import { t as evaluate } from "./evaluate-qYC5xClb.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,9 +2,9 @@
|
|
|
2
2
|
import { r as loadDotenv, s as resolveTtlSec } from "../dotenv-B9nM4cuQ.mjs";
|
|
3
3
|
import { t as detectHarness } from "../harness-C8Nxxyn_.mjs";
|
|
4
4
|
import { t as claudeHome } from "../home-state-mKZxP4oZ.mjs";
|
|
5
|
-
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-
|
|
5
|
+
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-CaqeQFYp.mjs";
|
|
6
6
|
import { n as writeInitFile, t as initFor } from "../run-Do2JltgU.mjs";
|
|
7
|
-
import { Mt as todayUtc, t as handleHook } from "../handle-
|
|
7
|
+
import { Mt as todayUtc, t as handleHook } from "../handle-DUlUbhyF.mjs";
|
|
8
8
|
import { delimiter, dirname, join } from "node:path";
|
|
9
9
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
10
10
|
import { homedir } from "node:os";
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-
|
|
1
|
+
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-CaqeQFYp.mjs";
|
|
2
2
|
export { checkStaged, stagedContent, stagedFiles };
|
|
@@ -147,6 +147,27 @@ const PROJECT_INSTALL = [
|
|
|
147
147
|
function matchPatterns(cmd, patterns) {
|
|
148
148
|
return patterns.some((re) => re.test(cmd));
|
|
149
149
|
}
|
|
150
|
+
/** Git commands exempt from confirmation when Ralph mode is on (parity git-guard.py RALPH_SAFE). */
|
|
151
|
+
const RALPH_SAFE = [
|
|
152
|
+
"git add",
|
|
153
|
+
"git commit",
|
|
154
|
+
"git checkout -b",
|
|
155
|
+
"git branch --show-current",
|
|
156
|
+
"git status",
|
|
157
|
+
"git diff",
|
|
158
|
+
"git log"
|
|
159
|
+
];
|
|
160
|
+
/**
|
|
161
|
+
* OPT-IN autonomous "Ralph" mode: OFF unless `RALPH_MODE` is `1`/`true`, read
|
|
162
|
+
* fresh on each call. Only the env var activates it — the Python source also
|
|
163
|
+
* auto-enabled on a `.claude/ralph/prd.json` file or a `feature/*` branch, but
|
|
164
|
+
* those silent activations are dropped here: a mode that removes git/install
|
|
165
|
+
* confirmations must never turn on implicitly (owner: default OFF, env opt-in).
|
|
166
|
+
*/
|
|
167
|
+
function isRalphMode() {
|
|
168
|
+
const v = process.env.RALPH_MODE;
|
|
169
|
+
return v === "1" || v === "true";
|
|
170
|
+
}
|
|
150
171
|
//#endregion
|
|
151
172
|
//#region src/policy/file-size-scope.ts
|
|
152
173
|
/**
|
|
@@ -302,23 +323,32 @@ function stripHeredoc(cmd) {
|
|
|
302
323
|
}
|
|
303
324
|
return out;
|
|
304
325
|
}
|
|
305
|
-
/**
|
|
326
|
+
/**
|
|
327
|
+
* Guards against dangerous Bash commands. Parity `security_rules.validate_command`
|
|
328
|
+
* + `security-guard.py`: ACCUMULATE every matched violation, then deny when any
|
|
329
|
+
* critical matched else ask, joining all violation labels in the reason. The
|
|
330
|
+
* generic `rm` ask is exempt when the command targets a trash location (parity
|
|
331
|
+
* `not re.search('trash', cmd)`).
|
|
332
|
+
*/
|
|
306
333
|
function securityGuard(ctx) {
|
|
307
334
|
if (ctx.tool !== "Bash" || !ctx.command) return null;
|
|
308
335
|
const cmd = stripHeredoc(ctx.command);
|
|
309
|
-
|
|
336
|
+
const hasTrash = /trash/i.test(cmd);
|
|
337
|
+
const critical = CRITICAL_PATTERNS.filter(({ re }) => re.test(cmd)).map((p) => p.label);
|
|
338
|
+
const ask = ASK_PATTERNS.filter(({ re, label }) => re.test(cmd) && !(hasTrash && label.startsWith("DELETE: 'rm'"))).map((p) => p.label);
|
|
339
|
+
if (critical.length === 0 && ask.length === 0) return null;
|
|
340
|
+
if (critical.length > 0) return {
|
|
310
341
|
kind: "block",
|
|
311
342
|
title: "Dangerous command",
|
|
312
|
-
reason: `${
|
|
343
|
+
reason: `${[...critical, ...ask].join(", ")}.`,
|
|
313
344
|
actions: ["Remove the destructive command", "Scope the operation to a specific safe path"]
|
|
314
345
|
};
|
|
315
|
-
|
|
346
|
+
return {
|
|
316
347
|
kind: "ask",
|
|
317
348
|
title: "Dangerous command",
|
|
318
|
-
reason: `${
|
|
349
|
+
reason: `${ask.join(", ")}.`,
|
|
319
350
|
actions: ["Confirm this command is intended", "Run with least privilege"]
|
|
320
351
|
};
|
|
321
|
-
return null;
|
|
322
352
|
}
|
|
323
353
|
//#endregion
|
|
324
354
|
//#region src/policy/guards/protected-path.ts
|
|
@@ -611,7 +641,7 @@ function bashWriteGuard(ctx) {
|
|
|
611
641
|
/** TS/JS component files: top-level `interface`/`type Foo`. */
|
|
612
642
|
const TS_DECL_RE = /^\s*(export\s+)?(interface|type)\s+[A-Z]/m;
|
|
613
643
|
/** Python view models: class subclassing a schema/protocol base. */
|
|
614
|
-
const PY_MODEL_RE = /^\s*class\s+\w+\((BaseModel|TypedDict|Protocol)\
|
|
644
|
+
const PY_MODEL_RE = /^\s*class\s+\w+\s*\([^)]*\b(?:BaseModel|TypedDict|Protocol)\b/m;
|
|
615
645
|
/**
|
|
616
646
|
* PHP controllers: top-level `interface`, `abstract class`, or a concrete
|
|
617
647
|
* `class …Interface/DTO/Request`. Union of the TS-only `abstract class` rule
|
|
@@ -662,16 +692,23 @@ function interfaceSeparationGuard(ctx) {
|
|
|
662
692
|
}
|
|
663
693
|
//#endregion
|
|
664
694
|
//#region src/policy/guards/install.ts
|
|
665
|
-
/**
|
|
695
|
+
/**
|
|
696
|
+
* Asks for confirmation before a dependency or system package install. In Ralph
|
|
697
|
+
* mode (opt-in `RALPH_MODE`) a PROJECT install is auto-approved for autonomous
|
|
698
|
+
* runs (parity install-guard.py:52), but a SYSTEM install always asks.
|
|
699
|
+
*/
|
|
666
700
|
function installGuard(ctx) {
|
|
667
701
|
if (ctx.tool !== "Bash" || !ctx.command) return null;
|
|
668
|
-
|
|
702
|
+
const isSystem = matchPatterns(ctx.command, SYSTEM_INSTALL);
|
|
703
|
+
const isProject = matchPatterns(ctx.command, PROJECT_INSTALL);
|
|
704
|
+
if (!isSystem && !isProject) return null;
|
|
705
|
+
if (!isSystem && isProject && isRalphMode()) return null;
|
|
706
|
+
return {
|
|
669
707
|
kind: "ask",
|
|
670
708
|
title: "Dependency install",
|
|
671
709
|
reason: `This command installs packages: ${ctx.command.trim()}`,
|
|
672
710
|
actions: ["Confirm this install is intended"]
|
|
673
711
|
};
|
|
674
|
-
return null;
|
|
675
712
|
}
|
|
676
713
|
//#endregion
|
|
677
714
|
//#region src/policy/guards/index.ts
|
|
@@ -730,7 +767,9 @@ function evaluate(ctx) {
|
|
|
730
767
|
message: guard.reason,
|
|
731
768
|
prompt: guard
|
|
732
769
|
};
|
|
733
|
-
|
|
770
|
+
const cmd = ctx.command;
|
|
771
|
+
const ralphSafe = !!cmd && isRalphMode() && RALPH_SAFE.some((s) => cmd.startsWith(s));
|
|
772
|
+
if (!ralphSafe && ctx.command && matchPatterns(ctx.command, GIT_BLOCKED)) {
|
|
734
773
|
const reason = `Destructive git command: ${ctx.command}`;
|
|
735
774
|
return {
|
|
736
775
|
decision: "deny",
|
|
@@ -743,7 +782,7 @@ function evaluate(ctx) {
|
|
|
743
782
|
}
|
|
744
783
|
};
|
|
745
784
|
}
|
|
746
|
-
if (ctx.command && matchPatterns(ctx.command, GIT_ASK)) return {
|
|
785
|
+
if (!ralphSafe && ctx.command && matchPatterns(ctx.command, GIT_ASK)) return {
|
|
747
786
|
decision: "deny",
|
|
748
787
|
message: `Git operation requires confirmation: ${ctx.command}`,
|
|
749
788
|
prompt: {
|
|
@@ -781,4 +820,4 @@ function evaluate(ctx) {
|
|
|
781
820
|
};
|
|
782
821
|
}
|
|
783
822
|
//#endregion
|
|
784
|
-
export { PROJECT_INSTALL as A, PROTECTED_GIT_RE as C, securityGuard as D, CRITICAL_PATTERNS as E,
|
|
823
|
+
export { PROJECT_INSTALL as A, PROTECTED_GIT_RE as C, securityGuard as D, CRITICAL_PATTERNS as E, PLUGINS_DIR as F, SOLID_REF as I, countFrameworkCodeLines as L, SYSTEM_INSTALL as M, isRalphMode as N, GIT_ASK as O, matchPatterns as P, countLines 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, evaluateFileSize as z };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { a as parseEnvInt, i as splitTarget, r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
|
|
2
2
|
import { r as projectLayout } from "./layout-C0jaaCQC.mjs";
|
|
3
3
|
import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { F as
|
|
4
|
+
import { B as detectFramework, C as resolveSkillPath, D as frameworkSolidGate, G as requiredArchSkill, H as detectModularArchitecture, I as docConsultedGate, L as evaluateApex, M as capVerbosity, N as detectCreationIntent, O as isExcludedJsPath, S as usesTailwindUtilities, T as readPluginMeta, U as detectProjectType$1, _ as scanPlugin, c as EXCLUDE_DIRS$1, d as buildApexTaskInjection, h as buildClaudeMdContext, k as isExcludedSwiftPath, l as PROJECT_INDICATORS, n as missingSeoElements, o as parseEnrichment, r as descFromText, s as parseEntry, t as isHtmlLike, w as findMarketplacePlugins, x as skillTriggerGate, y as parseField } from "./validate-DVV4nRfr.mjs";
|
|
5
|
+
import { F as PLUGINS_DIR, L as countFrameworkCodeLines, R as countLines, n as FAIL_CLOSED, t as evaluate } from "./evaluate-qYC5xClb.mjs";
|
|
6
6
|
import { a as writeJsonFile, i as readJsonFile, r as hashText, t as atomicWrite } from "./json-io-DisYd2fb.mjs";
|
|
7
7
|
import { a as sanitizeSessionId, c as sessionsDir, i as loadSessionState, n as fuseHarnessHome, o as saveSessionState, r as fusengineCache, t as claudeHome } from "./home-state-mKZxP4oZ.mjs";
|
|
8
8
|
import { r as isDocConsulted } from "./doc-helpers-CWZegVdR.mjs";
|
|
@@ -11,7 +11,7 @@ import { a as nowStamp, l as throttleMs, n as readRoots, o as readState, s as se
|
|
|
11
11
|
import { d as loadIndex, i as cacheLookupMeta, n as webfetchCacheWrite, o as cacheLookupSubstringMeta, t as mcpCacheWrite, u as extractText } from "./mcp-store-BkBDmuxN.mjs";
|
|
12
12
|
import { t as loadRefs } from "./loader-AGz4nK7d.mjs";
|
|
13
13
|
import { c as recordDoc, d as trivialCount, i as agentsFresh, l as recordRefRead, n as saveTrack, o as recordAgent, r as verifyTrack, s as recordBrainstormRequired, t as loadTrack, u as recordTrivialEdit } from "./store-CNjFenWe.mjs";
|
|
14
|
-
import { d as readText, f as sleep, l as collectFiles, m as writeText, n as contextResponse, p as spawnCapture, r as denyResponse, s as systemMessage, t as blockResponse, u as pathExists } from "./claude-
|
|
14
|
+
import { d as readText, f as sleep, l as collectFiles, m as writeText, n as contextResponse, p as spawnCapture, r as denyResponse, s as systemMessage, t as blockResponse, u as pathExists } from "./claude-U1KTaRG4.mjs";
|
|
15
15
|
import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
16
16
|
import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
17
17
|
import { homedir } from "node:os";
|
|
@@ -3537,7 +3537,7 @@ const EXEMPT_PATTERNS = [
|
|
|
3537
3537
|
/\.claude-plugin\//,
|
|
3538
3538
|
/CHANGELOG\.md$/,
|
|
3539
3539
|
/marketplace\.json$/,
|
|
3540
|
-
/\/\.claude\/(apex|memory|logs)\//,
|
|
3540
|
+
/\/\.claude\/(apex|memory|logs|fusengine-cache)\//,
|
|
3541
3541
|
/\/\.fuse-harness\//
|
|
3542
3542
|
];
|
|
3543
3543
|
/**
|
|
@@ -3849,11 +3849,12 @@ function nextModular(filePath, content, cwd) {
|
|
|
3849
3849
|
}
|
|
3850
3850
|
/** Laravel FuseCore architecture: `app/` domain ban + module.json + cross-module `use` rules. */
|
|
3851
3851
|
function fusecore(filePath, content, cwd) {
|
|
3852
|
-
for (const b of PHP_BLOCKED_IN_APP) if (filePath.includes(b)) return block$1(`BLOCKED: FuseCore
|
|
3852
|
+
for (const b of PHP_BLOCKED_IN_APP) if (filePath.includes(b)) return block$1(`BLOCKED: FuseCore project. Code in '${b.replace(/^\/|\/$/g, "")}' FORBIDDEN. Move to '${b.replaceAll("/app/", "/FuseCore/{Module}/App/").replace(/^\/|\/$/g, "")}'.`);
|
|
3853
3853
|
const mod = filePath.match(/\/FuseCore\/([A-Za-z]+)\//);
|
|
3854
3854
|
if (!mod) return null;
|
|
3855
3855
|
const name = mod[1] ?? "";
|
|
3856
|
-
|
|
3856
|
+
const mj = join(cwd, "FuseCore", name, "module.json");
|
|
3857
|
+
if (!existsSync(mj)) return block$1(`BLOCKED: Module '${name}' missing module.json. Create ${mj} first.`);
|
|
3857
3858
|
for (const m of content.matchAll(/use\s+FuseCore\\(\w+)\\/g)) {
|
|
3858
3859
|
const imported = m[1] ?? "";
|
|
3859
3860
|
if (name === "Core") {
|
|
@@ -3873,6 +3874,19 @@ function modularGate(tool, filePath, content, cwd) {
|
|
|
3873
3874
|
}
|
|
3874
3875
|
//#endregion
|
|
3875
3876
|
//#region src/runtime/framework-skill-gate.ts
|
|
3877
|
+
/** PHP paths the Laravel skill check skips — broader than the SOLID vendor-only exclude (parity check-laravel-skill.py `/(vendor|storage|bootstrap/cache)/`). */
|
|
3878
|
+
const PHP_SKILL_EXCLUDE_RE = /\/(vendor|storage|bootstrap\/cache)\//;
|
|
3879
|
+
/**
|
|
3880
|
+
* Whether the sub-skill gate should skip this path — parity with the early return
|
|
3881
|
+
* in check-*-skill.py (build/vendor artifacts never require a sub-skill).
|
|
3882
|
+
* @param framework - the detected framework ("laravel" | "swift" | JS otherwise).
|
|
3883
|
+
* @param filePath - the file being written.
|
|
3884
|
+
*/
|
|
3885
|
+
function skillGateExcluded(framework, filePath) {
|
|
3886
|
+
if (framework === "laravel") return PHP_SKILL_EXCLUDE_RE.test(filePath);
|
|
3887
|
+
if (framework === "swift") return isExcludedSwiftPath(filePath);
|
|
3888
|
+
return isExcludedJsPath(filePath);
|
|
3889
|
+
}
|
|
3876
3890
|
/**
|
|
3877
3891
|
* Effective line count for the SOLID size check. On an Edit, `content` is only
|
|
3878
3892
|
* the `new_string` snippet, so for Next.js — mirroring the base file-size guard
|
|
@@ -3912,6 +3926,7 @@ function frameworkSkillGate(input, refsRead, existingCodeLines) {
|
|
|
3912
3926
|
const content = input.content ?? "";
|
|
3913
3927
|
const solid = frameworkSolidGate(input.filePath, content, effectiveLines(input.tool, input.framework, content, existingCodeLines));
|
|
3914
3928
|
if (solid) return solid;
|
|
3929
|
+
if (skillGateExcluded(input.framework, input.filePath)) return null;
|
|
3915
3930
|
const forced = input.cwd ? requiredArchSkill(input.cwd) : null;
|
|
3916
3931
|
return skillTriggerGate(input.framework, content, refsRead, forced, input.cwd, input.filePath);
|
|
3917
3932
|
}
|
|
@@ -3979,6 +3994,122 @@ function shadcnSkillGate(tool, filePath, content, ev) {
|
|
|
3979
3994
|
});
|
|
3980
3995
|
}
|
|
3981
3996
|
//#endregion
|
|
3997
|
+
//#region src/policy/tailwind-skill-gate.ts
|
|
3998
|
+
/** Vendored/build paths exempt (parity check-tailwind-skill.py `/(node_modules|dist|build)/`). */
|
|
3999
|
+
const TW_EXCLUDE_RE = /(^|\/)(node_modules|dist|build)\//;
|
|
4000
|
+
/** A read reference proving a base Tailwind skill was consulted (Phase 1). */
|
|
4001
|
+
const TW_BASE_SKILL_RE = /skills\/(tailwindcss-v4|tailwindcss-utilities)\//;
|
|
4002
|
+
/**
|
|
4003
|
+
* True when this Write/Edit is a `.tsx`/`.jsx` file carrying Tailwind utility
|
|
4004
|
+
* classes, outside vendored dirs — the trigger condition of Phase 1.
|
|
4005
|
+
* @param tool - the tool name.
|
|
4006
|
+
* @param filePath - the file being written.
|
|
4007
|
+
* @param content - the written content.
|
|
4008
|
+
*/
|
|
4009
|
+
function isTailwindWrite(tool, filePath, content) {
|
|
4010
|
+
if (tool !== "Write" && tool !== "Edit") return false;
|
|
4011
|
+
if (TW_EXCLUDE_RE.test(filePath)) return false;
|
|
4012
|
+
return usesTailwindUtilities(filePath, content);
|
|
4013
|
+
}
|
|
4014
|
+
/** True when `tailwindcss-v4` or `tailwindcss-utilities` was read this session (Phase 1 base skill). */
|
|
4015
|
+
function tailwindBaseSkillRead(refsRead) {
|
|
4016
|
+
return refsRead.some((p) => TW_BASE_SKILL_RE.test(p));
|
|
4017
|
+
}
|
|
4018
|
+
/**
|
|
4019
|
+
* Gate a Tailwind-scoped write: block until a base Tailwind skill is read
|
|
4020
|
+
* (parity check-tailwind-skill.py Phase 1). Returns `null` when out of scope
|
|
4021
|
+
* or already satisfied.
|
|
4022
|
+
* @param tool - the tool name.
|
|
4023
|
+
* @param filePath - the file being written.
|
|
4024
|
+
* @param content - the written content.
|
|
4025
|
+
* @param refsRead - in-session read reference paths.
|
|
4026
|
+
*/
|
|
4027
|
+
function tailwindSkillGate(tool, filePath, content, refsRead) {
|
|
4028
|
+
if (!isTailwindWrite(tool, filePath, content)) return null;
|
|
4029
|
+
if (tailwindBaseSkillRead(refsRead)) return null;
|
|
4030
|
+
return {
|
|
4031
|
+
kind: "block",
|
|
4032
|
+
title: "Tailwind CSS skill",
|
|
4033
|
+
reason: "BLOCKED: Tailwind skill not consulted. Read tailwindcss-v4/SKILL.md or tailwindcss-utilities/SKILL.md, or use mcp__context7__query-docs (topic: tailwindcss), then retry.",
|
|
4034
|
+
actions: [`Read ${resolveSkillPath("tailwindcss-v4")} or ${resolveSkillPath("tailwindcss-utilities")}`]
|
|
4035
|
+
};
|
|
4036
|
+
}
|
|
4037
|
+
//#endregion
|
|
4038
|
+
//#region src/policy/gemini-mcp-gate.ts
|
|
4039
|
+
/** UI file extensions the gate polices (parity enforce-gemini-mcp.py UI_EXT). */
|
|
4040
|
+
const UI_EXT_RE = /\.(tsx|jsx|vue|svelte)$/;
|
|
4041
|
+
/** Paths exempt from the gate (parity EXEMPT_DIRS). */
|
|
4042
|
+
const GEMINI_EXEMPT_RE = /(node_modules|dist|build|\.next|\.claude)\//;
|
|
4043
|
+
/** A live `mcp__gemini-design__*` call recorded this session proves consultation. */
|
|
4044
|
+
const GEMINI_MCP_SOURCE_RE = /gemini-mcp/i;
|
|
4045
|
+
/** Tailwind utility patterns (parity TAILWIND_PATTERNS). */
|
|
4046
|
+
const TW_PATTERNS = [
|
|
4047
|
+
/\bflex\b/,
|
|
4048
|
+
/\bgrid\b/,
|
|
4049
|
+
/\bp-\d/,
|
|
4050
|
+
/\bpx-\d/,
|
|
4051
|
+
/\bpy-\d/,
|
|
4052
|
+
/\bm-\d/,
|
|
4053
|
+
/\bmx-\d/,
|
|
4054
|
+
/\bmy-\d/,
|
|
4055
|
+
/\bmt-\d/,
|
|
4056
|
+
/\bmb-\d/,
|
|
4057
|
+
/\bbg-\w+/,
|
|
4058
|
+
/\btext-\w+/,
|
|
4059
|
+
/\brounded/,
|
|
4060
|
+
/\bshadow/,
|
|
4061
|
+
/\bborder\b/,
|
|
4062
|
+
/\bgap-\d/,
|
|
4063
|
+
/\bw-\w+/,
|
|
4064
|
+
/\bh-\w+/,
|
|
4065
|
+
/\bjustify-\w+/,
|
|
4066
|
+
/\bitems-\w+/,
|
|
4067
|
+
/\bspace-\w+-\d/
|
|
4068
|
+
];
|
|
4069
|
+
/** Min distinct Tailwind patterns before the gate fires (parity MIN_TAILWIND_CLASSES). */
|
|
4070
|
+
const MIN_TW = 3;
|
|
4071
|
+
/** Min newlines an Edit's new_string must have to be gated (parity MIN_LINES_FOR_EDIT). */
|
|
4072
|
+
const MIN_LINES_EDIT = 2;
|
|
4073
|
+
/** OPT-IN: off unless `FUSE_ENFORCE_GEMINI_MCP` is `1`/`true`. Read fresh each call (dynamic). */
|
|
4074
|
+
function geminiMcpEnforced() {
|
|
4075
|
+
const v = process.env.FUSE_ENFORCE_GEMINI_MCP;
|
|
4076
|
+
return v === "1" || v === "true";
|
|
4077
|
+
}
|
|
4078
|
+
/** Count distinct Tailwind utility patterns present in `content` (parity count_tailwind_classes). */
|
|
4079
|
+
function countTailwindClasses(content) {
|
|
4080
|
+
return TW_PATTERNS.reduce((n, re) => re.test(content) ? n + 1 : n, 0);
|
|
4081
|
+
}
|
|
4082
|
+
/** True when a `mcp__gemini-design__*` call was recorded this session (parity gemini_was_called). */
|
|
4083
|
+
function geminiMcpConsulted(authorizations, sessionId) {
|
|
4084
|
+
if (!authorizations) return false;
|
|
4085
|
+
return Object.values(authorizations).some((a) => a.doc_sessions?.includes(sessionId) && (a.sources ?? (a.source ? [a.source] : [])).some((s) => GEMINI_MCP_SOURCE_RE.test(s)));
|
|
4086
|
+
}
|
|
4087
|
+
/**
|
|
4088
|
+
* Gate a UI write when `FUSE_ENFORCE_GEMINI_MCP` is on: block hand-written
|
|
4089
|
+
* Tailwind (>= 3 classes) in a `.tsx/.jsx/.vue/.svelte` file unless a Gemini
|
|
4090
|
+
* Design MCP call was made this session. Returns `null` when disabled (default),
|
|
4091
|
+
* out of scope, or already satisfied.
|
|
4092
|
+
* @param tool - the tool name.
|
|
4093
|
+
* @param filePath - the file being written.
|
|
4094
|
+
* @param content - the written content (new_string on Edit).
|
|
4095
|
+
* @param ev - session evidence (authorizations + sessionId).
|
|
4096
|
+
*/
|
|
4097
|
+
function geminiMcpGate(tool, filePath, content, ev) {
|
|
4098
|
+
if (!geminiMcpEnforced()) return null;
|
|
4099
|
+
if (tool !== "Write" && tool !== "Edit") return null;
|
|
4100
|
+
if (!filePath || !UI_EXT_RE.test(filePath) || GEMINI_EXEMPT_RE.test(filePath)) return null;
|
|
4101
|
+
if (!content) return null;
|
|
4102
|
+
if (tool === "Edit" && (content.match(/\n/g)?.length ?? 0) < MIN_LINES_EDIT) return null;
|
|
4103
|
+
if (countTailwindClasses(content) < MIN_TW) return null;
|
|
4104
|
+
if (geminiMcpConsulted(ev.authorizations, ev.sessionId)) return null;
|
|
4105
|
+
return {
|
|
4106
|
+
kind: "block",
|
|
4107
|
+
title: "Gemini Design MCP",
|
|
4108
|
+
reason: "BLOCKED: UI code with Tailwind detected but Gemini Design MCP not used. Use mcp__gemini-design__create_frontend, modify_frontend, or snippet_frontend BEFORE writing UI code manually.",
|
|
4109
|
+
actions: ["Call mcp__gemini-design__create_frontend / modify_frontend / snippet_frontend, then retry"]
|
|
4110
|
+
};
|
|
4111
|
+
}
|
|
4112
|
+
//#endregion
|
|
3982
4113
|
//#region src/freshness/explore-tools.ts
|
|
3983
4114
|
/** Native exploration tools (parity `apex_constants.EXPLORE_TOOLS`). */
|
|
3984
4115
|
const EXPLORE_TOOLS = /* @__PURE__ */ new Set(["Glob", "Grep"]);
|
|
@@ -4160,7 +4291,7 @@ async function apexScopedGate(input, track, window) {
|
|
|
4160
4291
|
agentsFresh: freshnessFor([...REQUIRED_AGENTS]),
|
|
4161
4292
|
missingAgents: REQUIRED_AGENTS.filter((name) => !freshnessFor([name])),
|
|
4162
4293
|
windowMs: window,
|
|
4163
|
-
brainstormRequired: input.tool === "Edit" ? false : track.brainstormRequired,
|
|
4294
|
+
brainstormRequired: input.tool === "Edit" || input.agentId ? false : track.brainstormRequired,
|
|
4164
4295
|
brainstormFresh: freshnessFor(["brainstorming"], Number.MAX_SAFE_INTEGER)
|
|
4165
4296
|
};
|
|
4166
4297
|
try {
|
|
@@ -4221,6 +4352,15 @@ async function gate(input) {
|
|
|
4221
4352
|
});
|
|
4222
4353
|
if (shadcnBlock) return shadcnBlock;
|
|
4223
4354
|
}
|
|
4355
|
+
if (isTailwindWrite(input.tool, filePath, input.content ?? "")) {
|
|
4356
|
+
const twBlock = tailwindSkillGate(input.tool, filePath, input.content ?? "", track.refsRead);
|
|
4357
|
+
if (twBlock) return twBlock;
|
|
4358
|
+
}
|
|
4359
|
+
const geminiBlock = geminiMcpGate(input.tool, filePath, input.content ?? "", {
|
|
4360
|
+
authorizations: track.authorizations,
|
|
4361
|
+
sessionId: input.sessionId
|
|
4362
|
+
});
|
|
4363
|
+
if (geminiBlock) return geminiBlock;
|
|
4224
4364
|
if (isApexScoped(input.filePath)) {
|
|
4225
4365
|
const apex = await apexScopedGate(input, track, window);
|
|
4226
4366
|
if (apex) return apex;
|
|
@@ -4646,25 +4786,6 @@ function htmlCssOnlyGate(filePath) {
|
|
|
4646
4786
|
function stateFileGate(filePath) {
|
|
4647
4787
|
return filePath.includes(".design-state-") ? deny("BLOCKED: .design-state files are READ-ONLY for you. Hooks update them automatically as you progress. Do NOT try to modify them — it will not unblock you. Follow the pipeline: Phase 0→1→2→3→4→5→6 in order.") : null;
|
|
4648
4788
|
}
|
|
4649
|
-
/**
|
|
4650
|
-
* Ports browser_helpers.is_exempt: design-system.md is NOT exempt (it must meet
|
|
4651
|
-
* the quota); other `.md` files and vendored dirs ARE exempt from the check.
|
|
4652
|
-
*/
|
|
4653
|
-
function screenshotExempt(filePath) {
|
|
4654
|
-
if (filePath.endsWith("design-system.md")) return false;
|
|
4655
|
-
return filePath.endsWith(".md") || EXEMPT_DIRS.some((d) => filePath.includes(d));
|
|
4656
|
-
}
|
|
4657
|
-
/**
|
|
4658
|
-
* Block ANY non-exempt write (html/css/design-system.md) until the per-mode
|
|
4659
|
-
* screenshot quota is met. Ports check-browser-browsing.py's "Browse N sites
|
|
4660
|
-
* BEFORE writing" deny for the active design agent.
|
|
4661
|
-
*/
|
|
4662
|
-
function preScreenshotWriteGate(filePath, state) {
|
|
4663
|
-
if (screenshotExempt(filePath)) return null;
|
|
4664
|
-
const needed = MIN_SCREENSHOTS[state.mode];
|
|
4665
|
-
if (state.screenshotsCount < needed) return deny(`BLOCKED: ${state.screenshotsCount}/${needed} fuse-browser screenshots for mode '${state.mode}'. Browse ${needed - state.screenshotsCount} more site(s) BEFORE writing. Read design-inspiration.md, then browser_open + browser_navigate + browser_screenshot.`);
|
|
4666
|
-
return null;
|
|
4667
|
-
}
|
|
4668
4789
|
/** Return the requirements missing from a design-system.md (empty = valid). */
|
|
4669
4790
|
function validateDesignSystem(content) {
|
|
4670
4791
|
const missing = [];
|
|
@@ -4759,7 +4880,7 @@ function designGate(payload, event, cacheDir, cwd) {
|
|
|
4759
4880
|
}
|
|
4760
4881
|
if (event.tool === "Write" || event.tool === "Edit") {
|
|
4761
4882
|
const fp = event.filePath ?? "";
|
|
4762
|
-
const base = stateFileGate(fp) ?? htmlCssOnlyGate(fp) ??
|
|
4883
|
+
const base = stateFileGate(fp) ?? htmlCssOnlyGate(fp) ?? designSystemWriteGate(fp, state);
|
|
4763
4884
|
if (base) return base;
|
|
4764
4885
|
if (geminiEnabled() && state.geminiCalls === 0 && /\.(html|css)$/.test(fp)) return {
|
|
4765
4886
|
kind: "block",
|
|
@@ -4775,7 +4896,14 @@ function designGate(payload, event, cacheDir, cwd) {
|
|
|
4775
4896
|
if (!geminiEnabled()) return null;
|
|
4776
4897
|
const block = geminiCreateGate(state);
|
|
4777
4898
|
if (block) return block;
|
|
4778
|
-
const
|
|
4899
|
+
const ds = findDesignSystem(cwd);
|
|
4900
|
+
if (ds === "") return {
|
|
4901
|
+
kind: "block",
|
|
4902
|
+
title: "Design pipeline",
|
|
4903
|
+
reason: "BLOCKED: design-system.md not found. RECOVERY: 1) Read the identity templates 2) Read design-inspiration.md 3) Browse 4 reference sites 4) Write design-system.md, then retry create_frontend.",
|
|
4904
|
+
actions: ["Create design-system.md via the pipeline, then retry create_frontend"]
|
|
4905
|
+
};
|
|
4906
|
+
const missing = validateDesignSystem(ds);
|
|
4779
4907
|
if (missing.length) return {
|
|
4780
4908
|
kind: "block",
|
|
4781
4909
|
title: "Design pipeline",
|
|
@@ -4844,6 +4972,7 @@ async function handlePre(ctx) {
|
|
|
4844
4972
|
refs: opts.refsDir ? await loadRefs(opts.refsDir) : void 0,
|
|
4845
4973
|
isReplaceAll: event.input.replace_all === true,
|
|
4846
4974
|
agentType: event.agentType,
|
|
4975
|
+
agentId: typeof payload.agent_id === "string" ? payload.agent_id : void 0,
|
|
4847
4976
|
windowMs: opts.windowMs,
|
|
4848
4977
|
now: opts.now,
|
|
4849
4978
|
trackFile: file,
|
|
@@ -4900,6 +5029,7 @@ function docSourceOf(tool) {
|
|
|
4900
5029
|
if (tool === "WebSearch") return "websearch";
|
|
4901
5030
|
if (tool === "WebFetch") return "webfetch";
|
|
4902
5031
|
if (/^mcp__shadcn__/i.test(tool)) return "shadcn-mcp";
|
|
5032
|
+
if (/^mcp__gemini-design__/i.test(tool)) return "gemini-mcp";
|
|
4903
5033
|
}
|
|
4904
5034
|
/**
|
|
4905
5035
|
* Map a live tool-use to the activity to record, or null when nothing is
|
|
@@ -113,6 +113,16 @@ declare const SYSTEM_INSTALL: ReadonlyArray<RegExp>;
|
|
|
113
113
|
declare const PROJECT_INSTALL: ReadonlyArray<RegExp>;
|
|
114
114
|
/** True when `cmd` matches any pattern in `patterns`. */
|
|
115
115
|
declare function matchPatterns(cmd: string, patterns: ReadonlyArray<RegExp>): boolean;
|
|
116
|
+
/** Git commands exempt from confirmation when Ralph mode is on (parity git-guard.py RALPH_SAFE). */
|
|
117
|
+
declare const RALPH_SAFE: ReadonlyArray<string>;
|
|
118
|
+
/**
|
|
119
|
+
* OPT-IN autonomous "Ralph" mode: OFF unless `RALPH_MODE` is `1`/`true`, read
|
|
120
|
+
* fresh on each call. Only the env var activates it — the Python source also
|
|
121
|
+
* auto-enabled on a `.claude/ralph/prd.json` file or a `feature/*` branch, but
|
|
122
|
+
* those silent activations are dropped here: a mode that removes git/install
|
|
123
|
+
* confirmations must never turn on implicitly (owner: default OFF, env opt-in).
|
|
124
|
+
*/
|
|
125
|
+
declare function isRalphMode(): boolean;
|
|
116
126
|
//#endregion
|
|
117
127
|
//#region src/policy/interfaces/types.d.ts
|
|
118
128
|
/** Harness-agnostic input to {@link evaluate}. */
|
|
@@ -214,7 +224,13 @@ interface LabeledPattern {
|
|
|
214
224
|
declare const CRITICAL_PATTERNS: LabeledPattern[];
|
|
215
225
|
/** Patterns that warrant explicit confirmation before running — parity `security_rules.py`'s ask-level violation names. */
|
|
216
226
|
declare const ASK_PATTERNS: LabeledPattern[];
|
|
217
|
-
/**
|
|
227
|
+
/**
|
|
228
|
+
* Guards against dangerous Bash commands. Parity `security_rules.validate_command`
|
|
229
|
+
* + `security-guard.py`: ACCUMULATE every matched violation, then deny when any
|
|
230
|
+
* critical matched else ask, joining all violation labels in the reason. The
|
|
231
|
+
* generic `rm` ask is exempt when the command targets a trash location (parity
|
|
232
|
+
* `not re.search('trash', cmd)`).
|
|
233
|
+
*/
|
|
218
234
|
declare function securityGuard(ctx: GuardContext): Prompt | null;
|
|
219
235
|
//#endregion
|
|
220
236
|
//#region src/policy/guards/protected-path.d.ts
|
|
@@ -323,7 +339,11 @@ declare const JAVA_DECL_RE: RegExp;
|
|
|
323
339
|
declare function interfaceSeparationGuard(ctx: GuardContext): Prompt | null;
|
|
324
340
|
//#endregion
|
|
325
341
|
//#region src/policy/guards/install.d.ts
|
|
326
|
-
/**
|
|
342
|
+
/**
|
|
343
|
+
* Asks for confirmation before a dependency or system package install. In Ralph
|
|
344
|
+
* mode (opt-in `RALPH_MODE`) a PROJECT install is auto-approved for autonomous
|
|
345
|
+
* runs (parity install-guard.py:52), but a SYSTEM install always asks.
|
|
346
|
+
*/
|
|
327
347
|
declare function installGuard(ctx: GuardContext): Prompt | null;
|
|
328
348
|
//#endregion
|
|
329
349
|
//#region src/policy/guards/index.d.ts
|
|
@@ -571,4 +591,4 @@ declare function isHtmlLike(path: string): boolean;
|
|
|
571
591
|
*/
|
|
572
592
|
declare function missingSeoElements(html: string): string[];
|
|
573
593
|
//#endregion
|
|
574
|
-
export { ASK_PATTERNS as $, FAIL_CLOSED as A,
|
|
594
|
+
export { ASK_PATTERNS as $, FAIL_CLOSED as A, DEV_KEYWORDS as At, SWIFT_PROTO_RE as B, usesTailwindUtilities as C, FileSizeVerdict as Ct, MAX_TOKENS as D, countLines as Dt, MAX_EXA_RESULTS as E, countFrameworkCodeLines as Et, installGuard as F, isApexCommand as Ft, CODE_MUTATORS as G, interfaceSeparationGuard as H, GO_DECL_RE as I, requiredArchSkill as It, SAFE_PREFIXES as J, CODE_REDIRECT as K, JAVA_DECL_RE as L, clearUserGuards as M, ProjectType as Mt, registerGuard as N, detectModularArchitecture as Nt, capVerbosity as O, evaluateFileSize as Ot, runGuards as P, detectProjectType as Pt, protectedPathGuard as Q, PHP_DECL_RE as R, skillTriggerGate as S, matchPatterns as St, frameworkSolidGate as T, SOLID_REF as Tt, bashWriteGuard as U, TS_DECL_RE as V, ASK_WRITERS as W, PROTECTED_FRAGMENTS as X, SESSION_STATE_FRAGMENT as Y, PROTECTED_GIT_RE as Z, DEV_VERBS as _, GIT_BLOCKED as _t, firstHeading as a, APEX_GATES as at, detectClaudeMdProjectType as b, SYSTEM_INSTALL as bt, parseEntry as c, brainstormGate as ct, EXCLUDE_DIRS as d, freshnessGate as dt, CRITICAL_PATTERNS as et, PROJECT_INDICATORS as f, solidReadGate as ft, loadApexTaskState as g, GIT_ASK as gt, buildApexTaskInjection as h, PolicyResult as ht, firstComment as i, GuardContext as it, GUARDS as j, ModularArchitecture as jt, detectCreationIntent as k, detectFramework as kt, parseBodyDesc as l, docConsultedGate as lt, buildApexTaskContext as m, PolicyContext as mt, missingSeoElements as n, securityGuard as nt, TreeEntry as o, ApexContext as ot, ApexTaskState as p, evaluate as pt, FILE_REDIRECT as q, descFromText as r, Guard as rt, parseEnrichment as s, ApexGate as st, isHtmlLike as t, LabeledPattern as tt, parseField as u, evaluateApex as ut, buildApexInstruction as v, PROJECT_INSTALL as vt, SKILL_TRIGGERS as w, PLUGINS_DIR as wt, detectRequiredSkills as x, isRalphMode as xt, buildClaudeMdContext as y, RALPH_SAFE as yt, PY_MODEL_RE as z };
|
package/dist/index.d.mts
CHANGED
|
@@ -5,10 +5,9 @@ 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-BNfYWvYv.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, At as
|
|
8
|
+
import { $ as ASK_PATTERNS, A as FAIL_CLOSED, At as DEV_KEYWORDS, B as SWIFT_PROTO_RE, C as usesTailwindUtilities, Ct as FileSizeVerdict, D as MAX_TOKENS, Dt as countLines, E as MAX_EXA_RESULTS, Et as countFrameworkCodeLines, F as installGuard, Ft as isApexCommand, G as CODE_MUTATORS, H as interfaceSeparationGuard, I as GO_DECL_RE, It as requiredArchSkill, J as SAFE_PREFIXES, K as CODE_REDIRECT, L as JAVA_DECL_RE, M as clearUserGuards, Mt as ProjectType, N as registerGuard, Nt as detectModularArchitecture, O as capVerbosity, Ot as evaluateFileSize, P as runGuards, Pt as detectProjectType, Q as protectedPathGuard, R as PHP_DECL_RE, S as skillTriggerGate, St as matchPatterns, T as frameworkSolidGate, Tt as SOLID_REF, 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 GIT_BLOCKED, a as firstHeading, at as APEX_GATES, b as detectClaudeMdProjectType, bt as SYSTEM_INSTALL, c as parseEntry, ct as brainstormGate, d as EXCLUDE_DIRS, dt as freshnessGate, et as CRITICAL_PATTERNS, f as PROJECT_INDICATORS, ft as solidReadGate, g as loadApexTaskState, gt as GIT_ASK, h as buildApexTaskInjection, ht as PolicyResult, i as firstComment, it as GuardContext, j as GUARDS, jt as ModularArchitecture, k as detectCreationIntent, kt as detectFramework, l as parseBodyDesc, lt as docConsultedGate, m as buildApexTaskContext, mt as PolicyContext, n as missingSeoElements, nt as securityGuard, o as TreeEntry, ot as ApexContext, p as ApexTaskState, pt as evaluate, q as FILE_REDIRECT, r as descFromText, rt as Guard, s as parseEnrichment, st as ApexGate, t as isHtmlLike, tt as LabeledPattern, u as parseField, ut as evaluateApex, v as buildApexInstruction, vt as PROJECT_INSTALL, w as SKILL_TRIGGERS, wt as PLUGINS_DIR, x as detectRequiredSkills, xt as isRalphMode, y as buildClaudeMdContext, yt as RALPH_SAFE, z as PY_MODEL_RE } from "./index-l9Xvxrx7.mjs";
|
|
9
9
|
import { n as RouteResult, r as ScoredRef, t as RefMeta } from "./types-CY5qT2X1.mjs";
|
|
10
10
|
import { a as ReminderState, c as 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";
|
|
11
11
|
import { a as globToRe, i as scoreReferences, n as toRefMeta, o as parseFrontmatter, r as routeReferences, t as loadRefs } from "./index-mmRF3KNp.mjs";
|
|
12
|
-
import { a as taskStart, c as ensureStateDir, d as stateFilePath, f as acquireLock, i as taskCreate, l as loadState, n as ApexTaskFile, o as ApexState, r as taskComplete, s as apexStateDir, t as ApexTask, u as saveState } from "./index-BA-SqNR7.mjs";
|
|
13
12
|
import { _ as TIME_INTERVALS, a as formatCost, c as formatTokens, d as colors, f as progressiveColor, g as PROGRESS_CHARS, h as PROGRESS_BAR_DEFAULTS, i as formatBasename, l as ColorFn, m as GRADIENT_BLOCKS, n as generateGradientBar, o as formatPath, p as COLOR_THRESHOLDS, r as generateProgressBar, s as formatTimeLeft, t as ProgressBarOptions, u as Palette } from "./index-BWK8slRi.mjs";
|
|
14
|
-
export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, ApexContext, ApexGate,
|
|
13
|
+
export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, ApexContext, ApexGate, ApexTaskState, AuthEntry, CODE_MUTATORS, CODE_REDIRECT, COLOR_THRESHOLDS, CRITICAL_PATTERNS, CacheHit, ColorFn, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, DEV_VERBS, DocSatisfactionStatus, EXCLUDE_DIRS, FAIL_CLOSED, FILE_REDIRECT, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GRADIENT_BLOCKS, GUARDS, Guard, GuardContext, HOME_DIR, type HarnessId, type HarnessInfo, type HarnessMode, type HarnessVia, IndexSummary, JAVA_DECL_RE, LabeledPattern, MAX_EXA_RESULTS, MAX_LINES_ENV_KEY, MAX_TOKENS, ModularArchitecture, PHP_DECL_RE, PLUGINS_DIR, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PROTECTED_GIT_RE, PY_MODEL_RE, Palette, type PolicyContext, type PolicyResult, ProgressBarOptions, ProjectLayout, ProjectType, Prompt, PromptKind, RALPH_SAFE, RefMeta, ReminderState, RouteResult, SAFE_PREFIXES, SESSION_STATE_FRAGMENT, SKILL_TRIGGERS, SOLID_REF, STATE_GITIGNORE, STATE_ROOT, SWIFT_PROTO_RE, SYSTEM_INSTALL, ScoredRef, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, TreeEntry, addRoot, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, cacheLookup, cacheLookupMeta, cacheLookupSubstring, cacheLookupSubstringMeta, cachePath, cacheStore, capVerbosity, clearUserGuards, colors, compactJson, compactMarkdown, countFrameworkCodeLines, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectHarness, detectMode, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, ensureMemoryGitignore, envCandidates, evaluate, evaluateApex, evaluateFileSize, extractText, firstComment, firstHeading, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, frameworkSolidGate, freshnessGate, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, installGuard, interfaceSeparationGuard, isApexCommand, isCodeFile, isDocConsulted, isHtmlLike, isRalphMode, jaccardSimilar, lessonsFileFor, loadApexTaskState, loadDotenv, loadIndex, loadRefs, matchPatterns, mcpCacheKey, mcpCacheWrite, missingSeoElements, modeFor, nowStamp, parseBodyDesc, parseEnrichment, parseEntry, parseEnvFile, parseEnvInt, parseField, parseFrontmatter, progressiveColor, projectLayout, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registerGuard, registryFile, requiredArchSkill, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, scoreReferences, securityGuard, setStateField, skillTriggerGate, solidReadGate, splitTarget, stateFileFor, summarizeIndex, throttleMs, toRefMeta, ttlLabel, usesTailwindUtilities, walkUpFor, webfetchCacheWrite };
|
package/dist/index.mjs
CHANGED
|
@@ -4,8 +4,8 @@ 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-C8Nxxyn_.mjs";
|
|
7
|
-
import { A as
|
|
8
|
-
import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, F as
|
|
7
|
+
import { A as MAX_EXA_RESULTS, B as detectFramework, D as frameworkSolidGate, E as SKILL_TRIGGERS, F as brainstormGate, G as requiredArchSkill, H as detectModularArchitecture, I as docConsultedGate, L as evaluateApex, M as capVerbosity, N as detectCreationIntent, P as APEX_GATES, R as freshnessGate, S as usesTailwindUtilities, U as detectProjectType, V as DEV_KEYWORDS, W as isApexCommand, 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 MAX_TOKENS, 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, x as skillTriggerGate, y as parseField, z as solidReadGate } from "./validate-DVV4nRfr.mjs";
|
|
8
|
+
import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, F as PLUGINS_DIR, I as SOLID_REF, L as countFrameworkCodeLines, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, R as countLines, 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 evaluateFileSize } from "./evaluate-qYC5xClb.mjs";
|
|
9
9
|
import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-CWZegVdR.mjs";
|
|
10
10
|
import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-PKVNBHge.mjs";
|
|
11
11
|
import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
|
|
@@ -13,6 +13,5 @@ import { a as nowStamp, c as stateFileFor, i as lessonsFileFor, l as throttleMs,
|
|
|
13
13
|
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";
|
|
14
14
|
import { t as incrementTrivialEditCounter } from "./freshness-BV3PQkDB.mjs";
|
|
15
15
|
import { n as toRefMeta, t as loadRefs } from "./loader-AGz4nK7d.mjs";
|
|
16
|
-
import { a as ensureStateDir, c as stateFilePath, i as apexStateDir, l as acquireLock, n as taskCreate, o as loadState, r as taskStart, s as saveState, t as taskComplete } from "./state-9lWvvWk8.mjs";
|
|
17
16
|
import { a as formatPath, c as colors, d as GRADIENT_BLOCKS, f as PROGRESS_BAR_DEFAULTS, i as formatCost, l as progressiveColor, m as TIME_INTERVALS, n as generateProgressBar, o as formatTimeLeft, p as PROGRESS_CHARS, r as formatBasename, s as formatTokens, t as generateGradientBar, u as COLOR_THRESHOLDS } from "./statusline-D87eUNXl.mjs";
|
|
18
|
-
export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, COLOR_THRESHOLDS, CRITICAL_PATTERNS, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, FILE_REDIRECT, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GRADIENT_BLOCKS, GUARDS, HOME_DIR, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_LINES_ENV_KEY, MAX_TOKENS, PHP_DECL_RE, PLUGINS_DIR, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PROTECTED_GIT_RE, PY_MODEL_RE, SAFE_PREFIXES, SESSION_STATE_FRAGMENT, SKILL_TRIGGERS, SOLID_REF, STATE_GITIGNORE, STATE_ROOT, SWIFT_PROTO_RE, SYSTEM_INSTALL, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY,
|
|
17
|
+
export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, COLOR_THRESHOLDS, CRITICAL_PATTERNS, DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, FILE_REDIRECT, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GRADIENT_BLOCKS, GUARDS, HOME_DIR, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_LINES_ENV_KEY, MAX_TOKENS, PHP_DECL_RE, PLUGINS_DIR, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PROTECTED_GIT_RE, PY_MODEL_RE, RALPH_SAFE, SAFE_PREFIXES, SESSION_STATE_FRAGMENT, SKILL_TRIGGERS, SOLID_REF, STATE_GITIGNORE, STATE_ROOT, SWIFT_PROTO_RE, SYSTEM_INSTALL, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, addRoot, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, cacheLookup, cacheLookupMeta, cacheLookupSubstring, cacheLookupSubstringMeta, cachePath, cacheStore, capVerbosity, clearUserGuards, colors, compactJson, compactMarkdown, countFrameworkCodeLines, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectHarness, detectMode, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, ensureMemoryGitignore, envCandidates, evaluate, evaluateApex, evaluateFileSize, extractText, firstComment, firstHeading, formatBasename, formatCost, formatDocDeny, formatDocSatisfactionStatus, formatPath, formatPrompt, formatTimeLeft, formatTokens, frameworkSolidGate, freshnessGate, generateGradientBar, generateProgressBar, globToRe, incrementTrivialEditCounter, installGuard, interfaceSeparationGuard, isApexCommand, isCodeFile, isDocConsulted, isHtmlLike, isRalphMode, jaccardSimilar, lessonsFileFor, loadApexTaskState, loadDotenv, loadIndex, loadRefs, matchPatterns, mcpCacheKey, mcpCacheWrite, missingSeoElements, modeFor, nowStamp, parseBodyDesc, parseEnrichment, parseEntry, parseEnvFile, parseEnvInt, parseField, parseFrontmatter, progressiveColor, projectLayout, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registerGuard, registryFile, requiredArchSkill, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, scoreReferences, securityGuard, setStateField, skillTriggerGate, solidReadGate, splitTarget, stateFileFor, summarizeIndex, throttleMs, toRefMeta, ttlLabel, usesTailwindUtilities, walkUpFor, webfetchCacheWrite };
|
package/dist/policy/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as ASK_PATTERNS, A as FAIL_CLOSED, At as
|
|
2
|
-
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, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PROTECTED_GIT_RE, PY_MODEL_RE, type PolicyContext, type PolicyResult, ProjectType, 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, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate, usesTailwindUtilities };
|
|
1
|
+
import { $ as ASK_PATTERNS, A as FAIL_CLOSED, At as DEV_KEYWORDS, B as SWIFT_PROTO_RE, C as usesTailwindUtilities, Ct as FileSizeVerdict, D as MAX_TOKENS, Dt as countLines, E as MAX_EXA_RESULTS, Et as countFrameworkCodeLines, F as installGuard, Ft as isApexCommand, G as CODE_MUTATORS, H as interfaceSeparationGuard, I as GO_DECL_RE, It as requiredArchSkill, J as SAFE_PREFIXES, K as CODE_REDIRECT, L as JAVA_DECL_RE, M as clearUserGuards, Mt as ProjectType, N as registerGuard, Nt as detectModularArchitecture, O as capVerbosity, Ot as evaluateFileSize, P as runGuards, Pt as detectProjectType, Q as protectedPathGuard, R as PHP_DECL_RE, S as skillTriggerGate, St as matchPatterns, T as frameworkSolidGate, Tt as SOLID_REF, 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 GIT_BLOCKED, a as firstHeading, at as APEX_GATES, b as detectClaudeMdProjectType, bt as SYSTEM_INSTALL, c as parseEntry, ct as brainstormGate, d as EXCLUDE_DIRS, dt as freshnessGate, et as CRITICAL_PATTERNS, f as PROJECT_INDICATORS, ft as solidReadGate, g as loadApexTaskState, gt as GIT_ASK, h as buildApexTaskInjection, ht as PolicyResult, i as firstComment, it as GuardContext, j as GUARDS, jt as ModularArchitecture, k as detectCreationIntent, kt as detectFramework, l as parseBodyDesc, lt as docConsultedGate, m as buildApexTaskContext, mt as PolicyContext, n as missingSeoElements, nt as securityGuard, o as TreeEntry, ot as ApexContext, p as ApexTaskState, pt as evaluate, q as FILE_REDIRECT, r as descFromText, rt as Guard, s as parseEnrichment, st as ApexGate, t as isHtmlLike, tt as LabeledPattern, u as parseField, ut as evaluateApex, v as buildApexInstruction, vt as PROJECT_INSTALL, w as SKILL_TRIGGERS, wt as PLUGINS_DIR, x as detectRequiredSkills, xt as isRalphMode, y as buildClaudeMdContext, yt as RALPH_SAFE, z as PY_MODEL_RE } from "../index-l9Xvxrx7.mjs";
|
|
2
|
+
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, 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 };
|
package/dist/policy/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, F as
|
|
1
|
+
import { A as MAX_EXA_RESULTS, B as detectFramework, D as frameworkSolidGate, E as SKILL_TRIGGERS, F as brainstormGate, G as requiredArchSkill, H as detectModularArchitecture, I as docConsultedGate, L as evaluateApex, M as capVerbosity, N as detectCreationIntent, P as APEX_GATES, R as freshnessGate, S as usesTailwindUtilities, U as detectProjectType, V as DEV_KEYWORDS, W as isApexCommand, 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 MAX_TOKENS, 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, x as skillTriggerGate, y as parseField, z as solidReadGate } from "../validate-DVV4nRfr.mjs";
|
|
2
|
+
import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, F as PLUGINS_DIR, I as SOLID_REF, L as countFrameworkCodeLines, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, R as countLines, 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 evaluateFileSize } from "../evaluate-qYC5xClb.mjs";
|
|
3
3
|
import "../policy-la_KkjCS.mjs";
|
|
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, PLUGINS_DIR, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PROTECTED_GIT_RE, PY_MODEL_RE, 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, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate, usesTailwindUtilities };
|
|
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, PLUGINS_DIR, 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-
|
|
2
|
+
import { t as evaluate } from "./evaluate-qYC5xClb.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
|
package/dist/runtime/index.d.mts
CHANGED
|
@@ -96,6 +96,8 @@ interface GateInput {
|
|
|
96
96
|
windowMs?: number;
|
|
97
97
|
isReplaceAll?: boolean;
|
|
98
98
|
agentType?: string;
|
|
99
|
+
/** Claude `agent_id` when the tool-use comes from a subagent (parity require-apex-agents.py:41 — subagents inherit the lead's brainstorm decision). */
|
|
100
|
+
agentId?: string;
|
|
99
101
|
/** Absolute path to the session transcript (Claude `transcript_path`) for evidence-based freshness. */
|
|
100
102
|
transcriptPath?: string;
|
|
101
103
|
}
|
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-mKZxP4oZ.mjs";
|
|
3
|
-
import { $ as saveApexState, A as trackSkillRead, At as securityStateDir, B as writePluginMap, C as seoPostToolUse, Ct as defaultStateDir, D as postTrackingSideEffects, Dt as isoUtc, E as securityAdvisory, Et as normalizeEvent, F as dispatchLessons, G as mergeLines, H as isProject, I as lessonsFileFor, J as listChildren, K as countFiles, L as lessonsStateFileFor, M as dispatchLifecycle, Mt as todayUtc, N as aipilotPostToolUse, O as trackWatchResearch, Ot as loadSecurityState, P as dispatchAipilot, Q as cleanupSession, R as cartoSessionStart, S as postEditContext, St as taskContext, T as dispatchMemory, Tt as trackFile, U as writeTree, V as generateProjectMap, W as loadEnriched, X as trackSessionChanges, Y as postEditTypescript, Z as validateRulesLoaded, _ as preCommitGate, _t as trimLogFile, a as recordActivity, at as validateSolidGate, b as extractSymbols, bt as projectContext, c as MCP_TTL_MS, ct as detectSolidProfile, d as isMcpTool, dt as readRules, et as logToolFailure, f as queryOf, ft as runSessionStartCleanups, g as gate, gt as removeOldFiles, h as TRIVIAL_BUDGET, ht as purgeTtlTree, i as respond, it as validateTailwind, j as trackEnrichment, jt as securityStatePath, k as trackMcpResearch, kt as saveSecurityState, l as WEBFETCH_TTL_MS, lt as solidDetectStart, m as REQUIRED_AGENTS, mt as pruneEmptyDirs, n as activityFor, nt as trackAgentMemory, o as mcpPostStore, ot as checkFileSize, p as DEFAULT_WINDOW_MS, pt as sessionStartCore, q as getFileDesc, r as handlePre, rt as subagentCacheContext, s as mcpPreIntercept, st as countLoc, t as handleHook, tt as validateTeammateOutput, u as cacheQueryOf, ut as injectRules, v as detectDuplication, vt as devContext, w as seoPostToolUseResponse, wt as projectHash, x as lifecycleStdout, xt as promptSubmitContext, y as dryGate, yt as gitContext, z as generateEcosystemMap } from "../handle-
|
|
3
|
+
import { $ as saveApexState, A as trackSkillRead, At as securityStateDir, B as writePluginMap, C as seoPostToolUse, Ct as defaultStateDir, D as postTrackingSideEffects, Dt as isoUtc, E as securityAdvisory, Et as normalizeEvent, F as dispatchLessons, G as mergeLines, H as isProject, I as lessonsFileFor, J as listChildren, K as countFiles, L as lessonsStateFileFor, M as dispatchLifecycle, Mt as todayUtc, N as aipilotPostToolUse, O as trackWatchResearch, Ot as loadSecurityState, P as dispatchAipilot, Q as cleanupSession, R as cartoSessionStart, S as postEditContext, St as taskContext, T as dispatchMemory, Tt as trackFile, U as writeTree, V as generateProjectMap, W as loadEnriched, X as trackSessionChanges, Y as postEditTypescript, Z as validateRulesLoaded, _ as preCommitGate, _t as trimLogFile, a as recordActivity, at as validateSolidGate, b as extractSymbols, bt as projectContext, c as MCP_TTL_MS, ct as detectSolidProfile, d as isMcpTool, dt as readRules, et as logToolFailure, f as queryOf, ft as runSessionStartCleanups, g as gate, gt as removeOldFiles, h as TRIVIAL_BUDGET, ht as purgeTtlTree, i as respond, it as validateTailwind, j as trackEnrichment, jt as securityStatePath, k as trackMcpResearch, kt as saveSecurityState, l as WEBFETCH_TTL_MS, lt as solidDetectStart, m as REQUIRED_AGENTS, mt as pruneEmptyDirs, n as activityFor, nt as trackAgentMemory, o as mcpPostStore, ot as checkFileSize, p as DEFAULT_WINDOW_MS, pt as sessionStartCore, q as getFileDesc, r as handlePre, rt as subagentCacheContext, s as mcpPreIntercept, st as countLoc, t as handleHook, tt as validateTeammateOutput, u as cacheQueryOf, ut as injectRules, v as detectDuplication, vt as devContext, w as seoPostToolUseResponse, wt as projectHash, x as lifecycleStdout, xt as promptSubmitContext, y as dryGate, yt as gitContext, z as generateEcosystemMap } from "../handle-DUlUbhyF.mjs";
|
|
4
4
|
//#region src/runtime/storage.ts
|
|
5
5
|
/**
|
|
6
6
|
* The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
|
|
2
2
|
import { c as ttlLabel, t as HOME_DIR } from "./dotenv-B9nM4cuQ.mjs";
|
|
3
3
|
import { t as detectHarness } from "./harness-C8Nxxyn_.mjs";
|
|
4
|
-
import { F as
|
|
4
|
+
import { F as PLUGINS_DIR, I as SOLID_REF, L as countFrameworkCodeLines } from "./evaluate-qYC5xClb.mjs";
|
|
5
5
|
import { r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-CWZegVdR.mjs";
|
|
6
6
|
import { t as routeReferences } from "./router-PKVNBHge.mjs";
|
|
7
7
|
import { extname, join } from "node:path";
|
|
@@ -95,7 +95,7 @@ function detectProjectType(dir) {
|
|
|
95
95
|
*/
|
|
96
96
|
function detectFramework(filePath, content) {
|
|
97
97
|
if (/\.(tsx?|jsx?|vue|svelte)$/.test(filePath) || /from ['"]react|useState|className=/.test(content)) {
|
|
98
|
-
if (/(page|layout|loading|error|route)\.(ts|tsx)$/.test(filePath) || /use client|use server/.test(content)) return "nextjs";
|
|
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
99
|
return "react";
|
|
100
100
|
}
|
|
101
101
|
if (/\.swift$/.test(filePath)) return "swift";
|
|
@@ -124,7 +124,7 @@ const solidReadGate = (ctx) => {
|
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
const read = new Set(ctx.refsRead ?? []);
|
|
127
|
-
const missing = routed.required.map((r) => r.meta.filePath).filter((p) => !read.has(p));
|
|
127
|
+
const missing = !!routed.skillPath && read.has(routed.skillPath) ? [] : routed.required.map((r) => r.meta.filePath).filter((p) => !read.has(p));
|
|
128
128
|
if (missing.length === 0) return null;
|
|
129
129
|
const optional = routed.optional.map((r) => r.meta.filePath);
|
|
130
130
|
const reason = [
|
|
@@ -232,8 +232,8 @@ function capVerbosity(tool, input) {
|
|
|
232
232
|
}
|
|
233
233
|
//#endregion
|
|
234
234
|
//#region src/policy/framework-solid-exclude.ts
|
|
235
|
-
/** Build
|
|
236
|
-
const JS_EXCLUDE_RE = /(node_modules|dist|build|\.next)/;
|
|
235
|
+
/** Build/dep paths excluded from React/Next.js SOLID gating — segment-anchored (parity `r"/(node_modules|dist|build|\.next)/"`), NOT a bare substring, so `distance.ts`/`rebuild/` stay gated. */
|
|
236
|
+
const JS_EXCLUDE_RE = /(^|\/)(node_modules|dist|build|\.next)(\/|$)/;
|
|
237
237
|
/** Vendored dependency paths excluded from Laravel/PHP SOLID gating. */
|
|
238
238
|
const PHP_EXCLUDE_RE = /\/vendor\//;
|
|
239
239
|
/** Derived/build artifact paths excluded from Swift SOLID gating. */
|
|
@@ -945,6 +945,12 @@ function usesTailwindUtilities(filePath, content) {
|
|
|
945
945
|
* @returns a `block` Prompt naming the missing sub-skills, or `null` when satisfied.
|
|
946
946
|
*/
|
|
947
947
|
function skillTriggerGate(framework, content, refsRead, forcedSkill, cwd, filePath) {
|
|
948
|
+
if (forcedSkill === "fusecore" && !refsRead.some((r) => r.includes("skills/fusecore/"))) return {
|
|
949
|
+
kind: "block",
|
|
950
|
+
title: "FuseCore skill not consulted",
|
|
951
|
+
reason: "BLOCKED: FuseCore project detected. Read the FuseCore skill before writing code in FuseCore modules.",
|
|
952
|
+
actions: [`Read ${resolveSkillPath("fusecore")}`]
|
|
953
|
+
};
|
|
948
954
|
let required = detectRequiredSkills(framework, content);
|
|
949
955
|
if (framework !== "tailwind" && filePath && usesTailwindUtilities(filePath, content)) required = [...required, ...detectRequiredSkills("tailwind", content)];
|
|
950
956
|
if (forcedSkill && !required.includes(forcedSkill)) required.push(forcedSkill);
|
|
@@ -1243,7 +1249,7 @@ function buildClaudeMdContext(prompt, cwd) {
|
|
|
1243
1249
|
} catch {
|
|
1244
1250
|
return null;
|
|
1245
1251
|
}
|
|
1246
|
-
if (!DEV_VERBS.test(prompt)) return `# CLAUDE.md\n${claudeContent}`;
|
|
1252
|
+
if (!DEV_VERBS.test(prompt) && !DEV_KEYWORDS.test(prompt)) return `# CLAUDE.md\n${claudeContent}`;
|
|
1247
1253
|
return `${buildApexInstruction(detectClaudeMdProjectType(cwd), resolveMaxLines())}\n\n# CLAUDE.md\n${claudeContent}`;
|
|
1248
1254
|
}
|
|
1249
1255
|
//#endregion
|
|
@@ -1539,4 +1545,4 @@ function missingSeoElements(html) {
|
|
|
1539
1545
|
return missing;
|
|
1540
1546
|
}
|
|
1541
1547
|
//#endregion
|
|
1542
|
-
export {
|
|
1548
|
+
export { MAX_EXA_RESULTS as A, detectFramework as B, resolveSkillPath as C, frameworkSolidGate as D, SKILL_TRIGGERS as E, brainstormGate as F, requiredArchSkill as G, detectModularArchitecture as H, docConsultedGate as I, evaluateApex as L, capVerbosity as M, detectCreationIntent as N, isExcludedJsPath as O, APEX_GATES as P, freshnessGate as R, usesTailwindUtilities as S, readPluginMeta as T, detectProjectType as U, DEV_KEYWORDS as V, isApexCommand 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, MAX_TOKENS as j, isExcludedSwiftPath 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, findMarketplacePlugins as w, skillTriggerGate as x, parseField as y, solidReadGate as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusengine/harness",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.47",
|
|
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",
|
|
@@ -59,11 +59,6 @@
|
|
|
59
59
|
"types": "./dist/refs/index.d.mts",
|
|
60
60
|
"import": "./dist/refs/index.mjs"
|
|
61
61
|
},
|
|
62
|
-
"./state": {
|
|
63
|
-
"bun": "./src/state/index.ts",
|
|
64
|
-
"types": "./dist/state/index.d.mts",
|
|
65
|
-
"import": "./dist/state/index.mjs"
|
|
66
|
-
},
|
|
67
62
|
"./statusline": {
|
|
68
63
|
"bun": "./src/statusline/index.ts",
|
|
69
64
|
"types": "./dist/statusline/index.d.mts",
|
|
@@ -132,7 +127,7 @@
|
|
|
132
127
|
"test": "bun test",
|
|
133
128
|
"typecheck": "tsc --noEmit",
|
|
134
129
|
"docs:api": "typedoc",
|
|
135
|
-
"build": "tsdown src/index.ts src/config/index.ts src/util/index.ts src/detect/index.ts src/policy/index.ts src/prompt/index.ts src/memory/index.ts src/cache/index.ts src/freshness/index.ts src/refs/index.ts src/
|
|
130
|
+
"build": "tsdown src/index.ts src/config/index.ts src/util/index.ts src/detect/index.ts src/policy/index.ts src/prompt/index.ts src/memory/index.ts src/cache/index.ts src/freshness/index.ts src/refs/index.ts src/statusline/index.ts src/cli/index.ts src/cli/bin.ts src/init/index.ts src/tracking/index.ts src/runtime/index.ts src/adapters/claude/index.ts src/adapters/codex/index.ts src/adapters/cursor/index.ts src/adapters/cline/index.ts src/adapters/gemini/index.ts --dts --format esm --clean --out-dir dist",
|
|
136
131
|
"prepublishOnly": "bun test && tsc --noEmit && bun run build"
|
|
137
132
|
},
|
|
138
133
|
"publishConfig": {
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { t as AuthEntry } from "./doc-helpers-BNfYWvYv.mjs";
|
|
2
|
-
|
|
3
|
-
//#region src/state/lock.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Acquire a directory-based lock (atomic `mkdir`, EEXIST = already held) with a timeout.
|
|
6
|
-
* @returns a release function, or null if the lock could not be acquired in time.
|
|
7
|
-
*/
|
|
8
|
-
declare function acquireLock(lockDir: string, timeoutMs?: number): Promise<(() => Promise<void>) | null>;
|
|
9
|
-
//#endregion
|
|
10
|
-
//#region src/state/apex-state.d.ts
|
|
11
|
-
declare const DEFAULT_STATE: {
|
|
12
|
-
$schema: string;
|
|
13
|
-
description: string;
|
|
14
|
-
target: Record<string, string>;
|
|
15
|
-
authorizations: Record<string, AuthEntry & {
|
|
16
|
-
doc_consulted?: string;
|
|
17
|
-
}>;
|
|
18
|
-
};
|
|
19
|
-
/** APEX state shape. */
|
|
20
|
-
type ApexState = typeof DEFAULT_STATE;
|
|
21
|
-
/** APEX state directory under a home dir. */
|
|
22
|
-
declare function apexStateDir(home?: string): string;
|
|
23
|
-
/** Daily state file path: `<home>/.claude/logs/00-apex/<YYYY-MM-DD>-state.json`. */
|
|
24
|
-
declare function stateFilePath(home?: string, today?: string): string;
|
|
25
|
-
/** Ensure the state directory exists and return its path. */
|
|
26
|
-
declare function ensureStateDir(home?: string): Promise<string>;
|
|
27
|
-
/** Load APEX state, or a fresh default. */
|
|
28
|
-
declare function loadState(path: string): Promise<ApexState>;
|
|
29
|
-
/** Save APEX state. */
|
|
30
|
-
declare function saveState(path: string, state: ApexState): Promise<void>;
|
|
31
|
-
//#endregion
|
|
32
|
-
//#region src/state/task-helpers.d.ts
|
|
33
|
-
/** A task entry in task.json. */
|
|
34
|
-
interface ApexTask {
|
|
35
|
-
subject: string;
|
|
36
|
-
description: string;
|
|
37
|
-
status: string;
|
|
38
|
-
phase: string;
|
|
39
|
-
started_at?: string;
|
|
40
|
-
completed_at?: string;
|
|
41
|
-
created_at?: string;
|
|
42
|
-
doc_consulted: Record<string, unknown>;
|
|
43
|
-
files_modified: string[];
|
|
44
|
-
blockedBy?: string[];
|
|
45
|
-
}
|
|
46
|
-
/** Structure of `.claude/apex/task.json`. */
|
|
47
|
-
interface ApexTaskFile {
|
|
48
|
-
current_task: string;
|
|
49
|
-
created_at: string;
|
|
50
|
-
tasks: Record<string, ApexTask>;
|
|
51
|
-
}
|
|
52
|
-
/** Add a new pending task. */
|
|
53
|
-
declare function taskCreate(file: string, id: string, subject: string, desc: string): Promise<void>;
|
|
54
|
-
/** Mark a task in_progress (creating a stub if absent). */
|
|
55
|
-
declare function taskStart(file: string, id: string, subject?: string, desc?: string, blocked?: string): Promise<void>;
|
|
56
|
-
/** Mark a task completed. */
|
|
57
|
-
declare function taskComplete(file: string, id: string): Promise<void>;
|
|
58
|
-
//#endregion
|
|
59
|
-
export { taskStart as a, ensureStateDir as c, stateFilePath as d, acquireLock as f, taskCreate as i, loadState as l, ApexTaskFile as n, ApexState as o, taskComplete as r, apexStateDir as s, ApexTask as t, saveState as u };
|
package/dist/state/index.d.mts
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { a as taskStart, c as ensureStateDir, d as stateFilePath, f as acquireLock, i as taskCreate, l as loadState, n as ApexTaskFile, o as ApexState, r as taskComplete, s as apexStateDir, t as ApexTask, u as saveState } from "../index-BA-SqNR7.mjs";
|
|
2
|
-
export { ApexState, ApexTask, ApexTaskFile, acquireLock, apexStateDir, ensureStateDir, loadState, saveState, stateFilePath, taskComplete, taskCreate, taskStart };
|
package/dist/state/index.mjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { a as ensureStateDir, c as stateFilePath, i as apexStateDir, l as acquireLock, n as taskCreate, o as loadState, r as taskStart, s as saveState, t as taskComplete } from "../state-9lWvvWk8.mjs";
|
|
2
|
-
export { acquireLock, apexStateDir, ensureStateDir, loadState, saveState, stateFilePath, taskComplete, taskCreate, taskStart };
|
package/dist/state-9lWvvWk8.mjs
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { a as writeJsonFile, i as readJsonFile, n as ensureDir } from "./json-io-DisYd2fb.mjs";
|
|
2
|
-
import { mkdir, rmdir } from "node:fs/promises";
|
|
3
|
-
//#region src/state/lock.ts
|
|
4
|
-
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
5
|
-
/**
|
|
6
|
-
* Acquire a directory-based lock (atomic `mkdir`, EEXIST = already held) with a timeout.
|
|
7
|
-
* @returns a release function, or null if the lock could not be acquired in time.
|
|
8
|
-
*/
|
|
9
|
-
async function acquireLock(lockDir, timeoutMs = 5e3) {
|
|
10
|
-
const start = Date.now();
|
|
11
|
-
while (Date.now() - start < timeoutMs) try {
|
|
12
|
-
await mkdir(lockDir, { recursive: false });
|
|
13
|
-
return async () => {
|
|
14
|
-
try {
|
|
15
|
-
await rmdir(lockDir);
|
|
16
|
-
} catch {}
|
|
17
|
-
};
|
|
18
|
-
} catch {
|
|
19
|
-
await sleep(100);
|
|
20
|
-
}
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
//#endregion
|
|
24
|
-
//#region src/state/apex-state.ts
|
|
25
|
-
const DEFAULT_STATE = {
|
|
26
|
-
$schema: "apex-state-v1",
|
|
27
|
-
description: "APEX/SOLID state - sessions[] + 2min expiry",
|
|
28
|
-
target: {},
|
|
29
|
-
authorizations: {}
|
|
30
|
-
};
|
|
31
|
-
/** APEX state directory under a home dir. */
|
|
32
|
-
function apexStateDir(home = process.env.HOME ?? "") {
|
|
33
|
-
return `${home}/.claude/logs/00-apex`;
|
|
34
|
-
}
|
|
35
|
-
/** Daily state file path: `<home>/.claude/logs/00-apex/<YYYY-MM-DD>-state.json`. */
|
|
36
|
-
function stateFilePath(home = process.env.HOME ?? "", today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)) {
|
|
37
|
-
return `${apexStateDir(home)}/${today}-state.json`;
|
|
38
|
-
}
|
|
39
|
-
/** Ensure the state directory exists and return its path. */
|
|
40
|
-
async function ensureStateDir(home) {
|
|
41
|
-
const dir = apexStateDir(home);
|
|
42
|
-
await ensureDir(dir);
|
|
43
|
-
return dir;
|
|
44
|
-
}
|
|
45
|
-
/** Load APEX state, or a fresh default. */
|
|
46
|
-
async function loadState(path) {
|
|
47
|
-
return await readJsonFile(path) ?? { ...DEFAULT_STATE };
|
|
48
|
-
}
|
|
49
|
-
/** Save APEX state. */
|
|
50
|
-
async function saveState(path, state) {
|
|
51
|
-
await writeJsonFile(path, state);
|
|
52
|
-
}
|
|
53
|
-
//#endregion
|
|
54
|
-
//#region src/state/task-helpers.ts
|
|
55
|
-
/** Add a new pending task. */
|
|
56
|
-
async function taskCreate(file, id, subject, desc) {
|
|
57
|
-
const data = await readJsonFile(file);
|
|
58
|
-
if (!data) return;
|
|
59
|
-
data.tasks[id] = {
|
|
60
|
-
subject,
|
|
61
|
-
description: desc,
|
|
62
|
-
status: "pending",
|
|
63
|
-
phase: "pending",
|
|
64
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
65
|
-
doc_consulted: {},
|
|
66
|
-
files_modified: [],
|
|
67
|
-
blockedBy: []
|
|
68
|
-
};
|
|
69
|
-
await writeJsonFile(file, data);
|
|
70
|
-
}
|
|
71
|
-
/** Mark a task in_progress (creating a stub if absent). */
|
|
72
|
-
async function taskStart(file, id, subject, desc, blocked) {
|
|
73
|
-
const data = await readJsonFile(file);
|
|
74
|
-
if (!data) return;
|
|
75
|
-
const task = data.tasks[id] ?? {
|
|
76
|
-
subject: "",
|
|
77
|
-
description: "",
|
|
78
|
-
status: "in_progress",
|
|
79
|
-
phase: "analyze",
|
|
80
|
-
doc_consulted: {},
|
|
81
|
-
files_modified: []
|
|
82
|
-
};
|
|
83
|
-
data.tasks[id] = task;
|
|
84
|
-
data.current_task = id;
|
|
85
|
-
task.status = "in_progress";
|
|
86
|
-
task.phase = "analyze";
|
|
87
|
-
task.started_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
88
|
-
if (subject) task.subject = subject;
|
|
89
|
-
if (desc) task.description = desc;
|
|
90
|
-
if (blocked) task.blockedBy = blocked.split(",");
|
|
91
|
-
await writeJsonFile(file, data);
|
|
92
|
-
}
|
|
93
|
-
/** Mark a task completed. */
|
|
94
|
-
async function taskComplete(file, id) {
|
|
95
|
-
const data = await readJsonFile(file);
|
|
96
|
-
const task = data?.tasks[id];
|
|
97
|
-
if (!data || !task) return;
|
|
98
|
-
task.status = "completed";
|
|
99
|
-
task.phase = "completed";
|
|
100
|
-
task.completed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
101
|
-
await writeJsonFile(file, data);
|
|
102
|
-
}
|
|
103
|
-
//#endregion
|
|
104
|
-
export { ensureStateDir as a, stateFilePath as c, apexStateDir as i, acquireLock as l, taskCreate as n, loadState as o, taskStart as r, saveState as s, taskComplete as t };
|