@fusengine/harness 0.1.33 → 0.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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-BatVYnAf.mjs → claude-3PqBGt_7.mjs} +1 -1
- package/dist/cli/bin.mjs +2 -2
- package/dist/cli/index.mjs +1 -1
- package/dist/{evaluate-9ch1K2kt.mjs → evaluate-zyxeVZPB.mjs} +44 -10
- package/dist/freshness/index.mjs +1 -1
- package/dist/{freshness-otdUpuvP.mjs → freshness-43gxYpiX.mjs} +1 -1
- package/dist/{handle-Cxgzd4pZ.mjs → handle-DMHjTY1E.mjs} +145 -30
- package/dist/{index-DmbOUJK8.d.mts → index-QzK2dv0V.d.mts} +12 -2
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +4 -4
- package/dist/{json-io-CAn72gI4.mjs → json-io-CvSumjtz.mjs} +6 -2
- package/dist/policy/index.d.mts +1 -1
- package/dist/policy/index.mjs +2 -2
- package/dist/{run-CQbtlAKa.mjs → run-CUL70W0k.mjs} +1 -1
- package/dist/runtime/index.d.mts +29 -2
- package/dist/runtime/index.mjs +2 -2
- package/dist/state/index.mjs +1 -1
- package/dist/{state-ByhLeKyD.mjs → state-BthKK4Jj.mjs} +1 -1
- package/dist/store-7j02oGjt.mjs +184 -0
- package/dist/tracking/index.d.mts +12 -2
- package/dist/tracking/index.mjs +1 -1
- package/dist/{validate-CccewDwk.mjs → validate-DLrWtaDR.mjs} +1 -1
- package/package.json +1 -1
- package/dist/store-D-ge2ZPI.mjs +0 -89
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as readClaudeInput, i as guard, n as denyResponse, o as toClaudeResponse, r as fileSizeGuard, t as contextResponse } from "../../claude-
|
|
1
|
+
import { a as readClaudeInput, i as guard, n as denyResponse, o as toClaudeResponse, r as fileSizeGuard, t as contextResponse } from "../../claude-3PqBGt_7.mjs";
|
|
2
2
|
export { contextResponse, denyResponse, fileSizeGuard, guard, readClaudeInput, toClaudeResponse };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as readClaudeInput, i as guard, n as denyResponse, t as contextResponse } from "../../claude-
|
|
1
|
+
import { a as readClaudeInput, i as guard, n as denyResponse, t as contextResponse } from "../../claude-3PqBGt_7.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-zyxeVZPB.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
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { r as resolveTtlSec } from "../ttl-BG55s6HZ.mjs";
|
|
3
3
|
import { t as detectHarness } from "../harness-C8Nxxyn_.mjs";
|
|
4
|
-
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-
|
|
4
|
+
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-CUL70W0k.mjs";
|
|
5
5
|
import { n as writeInitFile, t as initFor } from "../run-Do2JltgU.mjs";
|
|
6
|
-
import { t as handleHook } from "../handle-
|
|
6
|
+
import { t as handleHook } from "../handle-DMHjTY1E.mjs";
|
|
7
7
|
//#region src/cli/bin.ts
|
|
8
8
|
/**
|
|
9
9
|
* harness — CLI for @fusengine/harness.
|
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-CUL70W0k.mjs";
|
|
2
2
|
export { checkStaged, stagedContent, stagedFiles };
|
|
@@ -192,24 +192,58 @@ function securityGuard(ctx) {
|
|
|
192
192
|
}
|
|
193
193
|
//#endregion
|
|
194
194
|
//#region src/policy/guards/protected-path.ts
|
|
195
|
-
/** Path fragments that mark a location as internal/generated state
|
|
195
|
+
/** Path fragments that mark a location as internal/generated state. */
|
|
196
196
|
const PROTECTED_FRAGMENTS = [
|
|
197
197
|
".claude/plugins/marketplaces",
|
|
198
198
|
".claude/plugins/cache",
|
|
199
199
|
".claude/logs/00-apex",
|
|
200
200
|
".claude/fusengine-cache",
|
|
201
|
-
".git/"
|
|
201
|
+
".git/",
|
|
202
|
+
".claude/apex/",
|
|
203
|
+
"/fuse-harness/",
|
|
204
|
+
".harness/track",
|
|
205
|
+
".harness/memory/state"
|
|
202
206
|
];
|
|
203
|
-
/**
|
|
207
|
+
/** Standard block response for any protected-path violation. */
|
|
208
|
+
const BLOCK = {
|
|
209
|
+
kind: "block",
|
|
210
|
+
title: "Protected path",
|
|
211
|
+
reason: "This is internal/generated enforcement state — do not edit it directly.",
|
|
212
|
+
actions: ["Edit the source, not the generated/cache/state copy"]
|
|
213
|
+
};
|
|
214
|
+
/** Returns true if `str` contains any protected fragment. */
|
|
215
|
+
function containsProtected(str) {
|
|
216
|
+
return PROTECTED_FRAGMENTS.some((f) => str.includes(f));
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Returns true if `cmd` contains a recognisable shell write operation.
|
|
220
|
+
*
|
|
221
|
+
* Best-effort: matches `>` / `>>` redirections, `tee`, `cp`, `mv`, `dd`, `sed -i`.
|
|
222
|
+
* Obfuscated shell (base64-decoded payloads, variable indirection, process
|
|
223
|
+
* substitution) can still evade this check — residual risk, documented. The
|
|
224
|
+
* real guarantee against a forged track is the transcript-grounded freshness
|
|
225
|
+
* gate (see `freshness/agent-evidence`), not this guard.
|
|
226
|
+
*/
|
|
227
|
+
function bashHasWriteOp(cmd) {
|
|
228
|
+
return />/.test(cmd) || /\btee\b/.test(cmd) || /\bcp\b/.test(cmd) || /\bmv\b/.test(cmd) || /\bdd\b/.test(cmd) || /\bsed\s+-[a-zA-Z]*i/.test(cmd);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Blocks direct edits to internal/generated state directories.
|
|
232
|
+
*
|
|
233
|
+
* Covers:
|
|
234
|
+
* - Write / Edit tool calls whose `filePath` targets a protected fragment.
|
|
235
|
+
* - Bash commands that both reference a protected fragment *and* contain a
|
|
236
|
+
* recognisable shell write operation (best-effort; see `bashHasWriteOp`).
|
|
237
|
+
*
|
|
238
|
+
* @param ctx - The guard context (tool, filePath, command).
|
|
239
|
+
* @returns A blocking {@link Prompt}, or null to allow.
|
|
240
|
+
*/
|
|
204
241
|
function protectedPathGuard(ctx) {
|
|
205
242
|
if ((ctx.tool === "Write" || ctx.tool === "Edit") && ctx.filePath) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
reason: "This is internal/generated state — do not edit it directly.",
|
|
211
|
-
actions: ["Edit the source, not the generated/cache copy"]
|
|
212
|
-
};
|
|
243
|
+
if (containsProtected(ctx.filePath)) return BLOCK;
|
|
244
|
+
}
|
|
245
|
+
if (ctx.tool === "Bash" && ctx.command) {
|
|
246
|
+
if (containsProtected(ctx.command) && bashHasWriteOp(ctx.command)) return BLOCK;
|
|
213
247
|
}
|
|
214
248
|
return null;
|
|
215
249
|
}
|
package/dist/freshness/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "../doc-helpers-Dd_x1-tZ.mjs";
|
|
2
|
-
import { t as incrementTrivialEditCounter } from "../freshness-
|
|
2
|
+
import { t as incrementTrivialEditCounter } from "../freshness-43gxYpiX.mjs";
|
|
3
3
|
export { formatDocDeny, formatDocSatisfactionStatus, incrementTrivialEditCounter, isDocConsulted, resolveSessions };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as writeJsonFile, i as readJsonFile, n as ensureDir } from "./json-io-CvSumjtz.mjs";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
3
|
//#region src/freshness/trivial-edit-counter.ts
|
|
4
4
|
/**
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { 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 { A as evaluateApex, E as detectCreationIntent, L as requiredArchSkill, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, l as parseField, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS$1 } from "./validate-
|
|
5
|
-
import { j as detectFramework, k as countLines, n as FAIL_CLOSED, t as evaluate } from "./evaluate-
|
|
4
|
+
import { A as evaluateApex, E as detectCreationIntent, L as requiredArchSkill, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, l as parseField, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS$1 } from "./validate-DLrWtaDR.mjs";
|
|
5
|
+
import { j as detectFramework, k as countLines, n as FAIL_CLOSED, t as evaluate } from "./evaluate-zyxeVZPB.mjs";
|
|
6
6
|
import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
|
|
7
7
|
import { a as nowStamp, l as throttleMs, n as readRoots, o as readState, s as setStateField, t as addRoot } from "./registry-BkoEbdec.mjs";
|
|
8
8
|
import { a as extractText, o as loadIndex, r as cacheStore, t as cacheLookup } from "./store-PrNPm6So.mjs";
|
|
9
|
-
import {
|
|
9
|
+
import { a as writeJsonFile, i as readJsonFile, r as hashText, t as atomicWrite } from "./json-io-CvSumjtz.mjs";
|
|
10
10
|
import { t as loadRefs } from "./loader-CyAoJv2W.mjs";
|
|
11
|
-
import { a as recordAgent, c as recordRefRead, l as recordTrivialEdit, n as saveTrack, o as recordBrainstormRequired, r as agentsFresh, s as recordDoc, t as loadTrack, u as trivialCount } from "./store-
|
|
12
|
-
import { c as pathExists, d as spawnCapture, f as writeText, l as readText, n as denyResponse, s as collectFiles, t as contextResponse, u as sleep } from "./claude-
|
|
11
|
+
import { a as recordAgent, c as recordRefRead, l as recordTrivialEdit, n as saveTrack, o as recordBrainstormRequired, r as agentsFresh, s as recordDoc, t as loadTrack, u as trivialCount } from "./store-7j02oGjt.mjs";
|
|
12
|
+
import { c as pathExists, d as spawnCapture, f as writeText, l as readText, n as denyResponse, s as collectFiles, t as contextResponse, u as sleep } from "./claude-3PqBGt_7.mjs";
|
|
13
13
|
import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
14
14
|
import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
15
|
-
import { homedir
|
|
15
|
+
import { homedir } from "node:os";
|
|
16
16
|
import { createHash } from "node:crypto";
|
|
17
17
|
import { mkdir, rmdir } from "node:fs/promises";
|
|
18
18
|
import { execFileSync } from "node:child_process";
|
|
@@ -169,9 +169,54 @@ function normalizeEvent(id, payload) {
|
|
|
169
169
|
}
|
|
170
170
|
//#endregion
|
|
171
171
|
//#region src/runtime/paths.ts
|
|
172
|
-
/**
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
/**
|
|
173
|
+
* @module paths
|
|
174
|
+
* Runtime path helpers — per-project, out-of-tree harness state.
|
|
175
|
+
*
|
|
176
|
+
* Default base: ~/.claude/fuse-harness/state/<projectHash>/
|
|
177
|
+
* where projectHash = 8-char MD5 of CLAUDE_PROJECT_DIR (or cwd).
|
|
178
|
+
* Persistent and not world-writable (unlike /tmp), and OUTSIDE the repo so the
|
|
179
|
+
* agent has no "legitimate" reason to write it (the protected-path guard denies
|
|
180
|
+
* it, and the gate verifies freshness from the transcript, not this file).
|
|
181
|
+
*
|
|
182
|
+
* @packageDocumentation
|
|
183
|
+
*/
|
|
184
|
+
/** Resolve the project root from the environment or fall back to cwd. */
|
|
185
|
+
function resolveProjectDir() {
|
|
186
|
+
return process.env["CLAUDE_PROJECT_DIR"] ?? process.cwd();
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Compute a stable 8-char hex hash for a project directory path.
|
|
190
|
+
* Delegates to `hashText` (MD5, non-cryptographic — used as a stable dir key only).
|
|
191
|
+
*
|
|
192
|
+
* @param projectDir - Absolute path to the project root; defaults to CLAUDE_PROJECT_DIR/cwd.
|
|
193
|
+
* @returns 8-char lowercase hex string.
|
|
194
|
+
*/
|
|
195
|
+
function projectHash$1(projectDir) {
|
|
196
|
+
return hashText(projectDir ?? resolveProjectDir());
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Canonical base directory for per-project harness state.
|
|
200
|
+
* Resolves to: ~/.claude/fuse-harness/state/<projectHash>/
|
|
201
|
+
*
|
|
202
|
+
* @param projectDir - Optional override for hashing; defaults to CLAUDE_PROJECT_DIR/cwd.
|
|
203
|
+
* @returns Absolute directory path (not yet created on disk).
|
|
204
|
+
*/
|
|
205
|
+
function defaultStateDir(projectDir) {
|
|
206
|
+
return join(homedir(), ".claude", "fuse-harness", "state", projectHash$1(projectDir));
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Absolute path to a session's track JSON file.
|
|
210
|
+
*
|
|
211
|
+
* The session identifier is sanitised to `[A-Za-z0-9_-]` before use in the filename.
|
|
212
|
+
*
|
|
213
|
+
* @param sessionId - Claude session identifier (raw value accepted; sanitised internally).
|
|
214
|
+
* @param baseDir - Override the base directory. Omit in production; pass an explicit
|
|
215
|
+
* temp path in unit tests to avoid touching $HOME.
|
|
216
|
+
* @returns Absolute path, e.g. ~/.claude/fuse-harness/state/a1b2c3d4/track-abc123.json
|
|
217
|
+
*/
|
|
218
|
+
function trackFile(sessionId, baseDir) {
|
|
219
|
+
return join(baseDir ?? defaultStateDir(), `track-${sessionId.replace(/[^A-Za-z0-9_-]/g, "_") || "default"}.json`);
|
|
175
220
|
}
|
|
176
221
|
//#endregion
|
|
177
222
|
//#region src/runtime/record.ts
|
|
@@ -3235,6 +3280,90 @@ function postEditContext(scope, event, now) {
|
|
|
3235
3280
|
return trackSessionChanges(event.sessionId, event.filePath, void 0, now) || postEditTypescript(event.filePath);
|
|
3236
3281
|
}
|
|
3237
3282
|
//#endregion
|
|
3283
|
+
//#region src/runtime/gate-helpers.ts
|
|
3284
|
+
/**
|
|
3285
|
+
* Code-only line count of the existing on-disk file (undefined if
|
|
3286
|
+
* absent/unreadable). Uses {@link countLines} (skips blank/comment lines) so a
|
|
3287
|
+
* partial Edit judges the full file by the SAME metric as the incoming snippet —
|
|
3288
|
+
* a raw `split("\n").length` would over-count JSDoc/blank lines (and add a
|
|
3289
|
+
* trailing-newline off-by-one), falsely blocking well-documented files.
|
|
3290
|
+
* @param path - Absolute path of the file being edited (or undefined).
|
|
3291
|
+
* @returns Code-only line count, or undefined when the file is absent/unreadable.
|
|
3292
|
+
*/
|
|
3293
|
+
function existingLineCount(path) {
|
|
3294
|
+
if (!path) return void 0;
|
|
3295
|
+
try {
|
|
3296
|
+
return existsSync(path) ? countLines(readFileSync(path, "utf8")) : void 0;
|
|
3297
|
+
} catch {
|
|
3298
|
+
return;
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
//#endregion
|
|
3302
|
+
//#region src/freshness/agent-evidence.ts
|
|
3303
|
+
/**
|
|
3304
|
+
* Platform-authored transcript evidence for APEX agent freshness.
|
|
3305
|
+
* Parses the Claude Code session JSONL transcript to find genuine Task
|
|
3306
|
+
* tool_use entries — forging this requires writing into the transcript file
|
|
3307
|
+
* which the Claude Code platform controls, unlike the self-recorded track.
|
|
3308
|
+
*/
|
|
3309
|
+
/** Parse a raw `timestamp` field to epoch ms; `undefined` when absent or invalid. */
|
|
3310
|
+
function parseTs(raw) {
|
|
3311
|
+
if (raw === void 0) return void 0;
|
|
3312
|
+
if (typeof raw === "number") return raw;
|
|
3313
|
+
const ms = Date.parse(raw);
|
|
3314
|
+
return Number.isFinite(ms) ? ms : void 0;
|
|
3315
|
+
}
|
|
3316
|
+
/**
|
|
3317
|
+
* Return `true` ONLY when, for EVERY name in `names`, the Claude Code
|
|
3318
|
+
* transcript at `transcriptPath` contains a genuine `tool_use` of the `Task`
|
|
3319
|
+
* tool whose `subagent_type` (or `name`) input field matches, with the entry
|
|
3320
|
+
* timestamp within `windowMs` of `now`.
|
|
3321
|
+
*
|
|
3322
|
+
* **Timestamp note:** when a transcript entry carries no `timestamp` field it
|
|
3323
|
+
* is counted as within-window (we cannot prove staleness). This is
|
|
3324
|
+
* intentionally lenient to stay robust across transcript-format evolution; the
|
|
3325
|
+
* tamper-resistance guarantee derives from the platform authoring the file —
|
|
3326
|
+
* not from the timestamp alone.
|
|
3327
|
+
*
|
|
3328
|
+
* @param transcriptPath - Absolute path to the session `.jsonl` transcript
|
|
3329
|
+
* (hook payload field: `transcript_path`). Returns `false` when `undefined`.
|
|
3330
|
+
* @param names - Required agent `subagent_type` values — ALL must appear.
|
|
3331
|
+
* @param windowMs - Freshness window in milliseconds.
|
|
3332
|
+
* @param now - Current epoch ms (pass `Date.now()` at the call-site).
|
|
3333
|
+
* @returns `true` when ALL agents have real, within-window transcript evidence.
|
|
3334
|
+
*/
|
|
3335
|
+
function agentsRanFromTranscript(transcriptPath, names, windowMs, now) {
|
|
3336
|
+
if (!transcriptPath || names.length === 0) return false;
|
|
3337
|
+
let text;
|
|
3338
|
+
try {
|
|
3339
|
+
text = readText(transcriptPath);
|
|
3340
|
+
} catch {
|
|
3341
|
+
return false;
|
|
3342
|
+
}
|
|
3343
|
+
const cutoff = now - windowMs;
|
|
3344
|
+
const found = /* @__PURE__ */ new Set();
|
|
3345
|
+
for (const line of text.split("\n")) {
|
|
3346
|
+
if (!line.trim()) continue;
|
|
3347
|
+
let entry;
|
|
3348
|
+
try {
|
|
3349
|
+
entry = JSON.parse(line);
|
|
3350
|
+
} catch {
|
|
3351
|
+
continue;
|
|
3352
|
+
}
|
|
3353
|
+
const ts = parseTs(entry.timestamp);
|
|
3354
|
+
if (ts !== void 0 && ts <= cutoff) continue;
|
|
3355
|
+
const content = entry.message?.content;
|
|
3356
|
+
if (!Array.isArray(content)) continue;
|
|
3357
|
+
for (const block of content) {
|
|
3358
|
+
if (block?.type !== "tool_use" || block.name !== "Task") continue;
|
|
3359
|
+
const agent = block.input?.subagent_type ?? block.input?.name;
|
|
3360
|
+
if (typeof agent === "string" && names.includes(agent)) found.add(agent);
|
|
3361
|
+
}
|
|
3362
|
+
if (found.size === names.length) return true;
|
|
3363
|
+
}
|
|
3364
|
+
return names.every((n) => found.has(n));
|
|
3365
|
+
}
|
|
3366
|
+
//#endregion
|
|
3238
3367
|
//#region src/runtime/dry-patterns.ts
|
|
3239
3368
|
/** Short identifiers never worth a duplication check (control flow, tiny names). */
|
|
3240
3369
|
const DRY_KEYWORDS = /* @__PURE__ */ new Set([
|
|
@@ -3570,22 +3699,6 @@ const DEFAULT_WINDOW_MS = 12e4;
|
|
|
3570
3699
|
/** Trivial edits allowed within the window before the full APEX gates apply. */
|
|
3571
3700
|
const TRIVIAL_BUDGET = 4;
|
|
3572
3701
|
/**
|
|
3573
|
-
* Code-only line count of the existing on-disk file (undefined if
|
|
3574
|
-
* absent/unreadable). Uses {@link countLines} (skips blank/comment lines) to
|
|
3575
|
-
* mirror the Python `count_code_lines(get_full_file_content(...))`, so a partial
|
|
3576
|
-
* Edit judges the full file by the SAME metric as the incoming snippet — a raw
|
|
3577
|
-
* `split("\n").length` would over-count JSDoc/blank lines (and add a
|
|
3578
|
-
* trailing-newline off-by-one), falsely blocking well-documented files.
|
|
3579
|
-
*/
|
|
3580
|
-
function existingLineCount(path) {
|
|
3581
|
-
if (!path) return void 0;
|
|
3582
|
-
try {
|
|
3583
|
-
return existsSync(path) ? countLines(readFileSync(path, "utf8")) : void 0;
|
|
3584
|
-
} catch {
|
|
3585
|
-
return;
|
|
3586
|
-
}
|
|
3587
|
-
}
|
|
3588
|
-
/**
|
|
3589
3702
|
* Full gate: the stateless guards (file-size, git, security...) first, then a
|
|
3590
3703
|
* trivial-edit fast path, then the stateful APEX gates fed from the session
|
|
3591
3704
|
* track. Returns the first blocking prompt, or null to allow.
|
|
@@ -3620,6 +3733,7 @@ async function gate(input) {
|
|
|
3620
3733
|
await saveTrack(input.trackFile, recordTrivialEdit(track, input.now, window, input.now));
|
|
3621
3734
|
return null;
|
|
3622
3735
|
}
|
|
3736
|
+
const freshnessFor = (names) => input.transcriptPath ? agentsRanFromTranscript(input.transcriptPath, names, window, input.now) : agentsFresh(track, names, window, input.now);
|
|
3623
3737
|
const ctx = {
|
|
3624
3738
|
sessionId: input.sessionId,
|
|
3625
3739
|
framework: input.framework,
|
|
@@ -3628,9 +3742,9 @@ async function gate(input) {
|
|
|
3628
3742
|
authorizations: track.authorizations,
|
|
3629
3743
|
refs: input.refs,
|
|
3630
3744
|
refsRead: track.refsRead,
|
|
3631
|
-
agentsFresh:
|
|
3745
|
+
agentsFresh: freshnessFor([...REQUIRED_AGENTS]),
|
|
3632
3746
|
brainstormRequired: track.brainstormRequired,
|
|
3633
|
-
brainstormFresh:
|
|
3747
|
+
brainstormFresh: freshnessFor(["brainstorming"])
|
|
3634
3748
|
};
|
|
3635
3749
|
try {
|
|
3636
3750
|
const apex = evaluateApex(ctx);
|
|
@@ -3693,7 +3807,8 @@ async function handlePre(ctx) {
|
|
|
3693
3807
|
agentType: event.agentType,
|
|
3694
3808
|
windowMs: opts.windowMs,
|
|
3695
3809
|
now: opts.now,
|
|
3696
|
-
trackFile: file
|
|
3810
|
+
trackFile: file,
|
|
3811
|
+
transcriptPath: typeof payload.transcript_path === "string" ? payload.transcript_path : void 0
|
|
3697
3812
|
});
|
|
3698
3813
|
return prompt ? {
|
|
3699
3814
|
stdout: respond(id, prompt),
|
|
@@ -3718,7 +3833,7 @@ function rawEventName(payload) {
|
|
|
3718
3833
|
async function handleHook(id, payload, opts) {
|
|
3719
3834
|
const event = normalizeEvent(id, payload);
|
|
3720
3835
|
const layout = projectLayout(opts.cwd);
|
|
3721
|
-
const file = trackFile(event.sessionId,
|
|
3836
|
+
const file = trackFile(event.sessionId, defaultStateDir(opts.cwd));
|
|
3722
3837
|
const mcpDir = layout.cacheDir;
|
|
3723
3838
|
const framework = detectFramework(event.filePath ?? "", event.content ?? "");
|
|
3724
3839
|
if (designLifecycle(payload, mcpDir, opts.cwd, String(opts.now), opts.now)) return {
|
|
@@ -3788,4 +3903,4 @@ async function handleHook(id, payload, opts) {
|
|
|
3788
3903
|
});
|
|
3789
3904
|
}
|
|
3790
3905
|
//#endregion
|
|
3791
|
-
export { detectSolidProfile as $, dispatchLessons as A,
|
|
3906
|
+
export { detectSolidProfile as $, dispatchLessons as A, mcpPreIntercept as At, mergeLines as B, securityStateDir as C, defaultStateDir as Ct, dispatchLifecycle as D, MCP_TTL_MS as Dt, trackEnrichment as E, normalizeEvent as Et, writePluginMap as F, trackSessionChanges as G, getFileDesc as H, generateProjectMap as I, saveApexState as J, validateRulesLoaded as K, isProject as L, lessonsStateFileFor as M, activityFor as Mt, cartoSessionStart as N, aipilotPostToolUse as O, isMcpTool as Ot, generateEcosystemMap as P, subagentCacheContext as Q, writeTree as R, saveSecurityState as S, recordActivity as St, todayUtc as T, trackFile as Tt, listChildren as U, countFiles as V, postEditTypescript as W, validateTeammateOutput as X, logToolFailure as Y, trackAgentMemory as Z, trackWatchResearch as _, sessionStatePath as _t, TRIVIAL_BUDGET as a, pruneEmptyDirs as at, isoUtc as b, taskContext as bt, detectDuplication as c, trimLogFile as ct, lifecycleStdout as d, projectContext as dt, solidDetectStart as et, postEditContext as f, claudeHome as ft, postTrackingSideEffects as g, saveSessionState as gt, securityAdvisory as h, sanitizeSessionId as ht, REQUIRED_AGENTS as i, sessionStartCore as it, lessonsFileFor as j, queryOf as jt, dispatchAipilot as k, mcpPostStore as kt, dryGate as l, devContext as lt, seoPostToolUseResponse as m, loadSessionState as mt, handlePre as n, readRules as nt, gate as o, purgeTtlTree as ot, seoPostToolUse as p, fusengineCache as pt, cleanupSession as q, DEFAULT_WINDOW_MS as r, runSessionStartCleanups as rt, preCommitGate as s, removeOldFiles as st, handleHook as t, injectRules as tt, extractSymbols as u, gitContext as ut, trackMcpResearch as v, sessionsDir as vt, securityStatePath as w, projectHash$1 as wt, loadSecurityState as x, respond as xt, trackSkillRead as y, promptSubmitContext as yt, loadEnriched as z };
|
|
@@ -170,9 +170,19 @@ declare const ASK_PATTERNS: RegExp[];
|
|
|
170
170
|
declare function securityGuard(ctx: GuardContext): Prompt | null;
|
|
171
171
|
//#endregion
|
|
172
172
|
//#region src/policy/guards/protected-path.d.ts
|
|
173
|
-
/** Path fragments that mark a location as internal/generated state
|
|
173
|
+
/** Path fragments that mark a location as internal/generated state. */
|
|
174
174
|
declare const PROTECTED_FRAGMENTS: readonly string[];
|
|
175
|
-
/**
|
|
175
|
+
/**
|
|
176
|
+
* Blocks direct edits to internal/generated state directories.
|
|
177
|
+
*
|
|
178
|
+
* Covers:
|
|
179
|
+
* - Write / Edit tool calls whose `filePath` targets a protected fragment.
|
|
180
|
+
* - Bash commands that both reference a protected fragment *and* contain a
|
|
181
|
+
* recognisable shell write operation (best-effort; see `bashHasWriteOp`).
|
|
182
|
+
*
|
|
183
|
+
* @param ctx - The guard context (tool, filePath, command).
|
|
184
|
+
* @returns A blocking {@link Prompt}, or null to allow.
|
|
185
|
+
*/
|
|
176
186
|
declare function protectedPathGuard(ctx: GuardContext): Prompt | null;
|
|
177
187
|
//#endregion
|
|
178
188
|
//#region src/policy/guards/bash-write.d.ts
|
package/dist/index.d.mts
CHANGED
|
@@ -5,7 +5,7 @@ import { a as detectHarness, i as HarnessVia, n as HarnessInfo, o as detectMode,
|
|
|
5
5
|
import { a as isDocConsulted, i as formatDocSatisfactionStatus, n as DocSatisfactionStatus, o as resolveSessions, r as formatDocDeny, t as AuthEntry } from "./doc-helpers-CG1nuf-c.mjs";
|
|
6
6
|
import { t as incrementTrivialEditCounter } from "./index-BOBXQ91y.mjs";
|
|
7
7
|
import { a as compactJson, i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./index-BEMumjOw.mjs";
|
|
8
|
-
import { $ as APEX_GATES, A as GUARDS, B as TS_DECL_RE, C as SKILL_TRIGGERS, Ct as detectProjectType, D as capVerbosity, E as MAX_TOKENS, F as GO_DECL_RE, G as bashWriteGuard, H as ASK_WRITERS, I as JAVA_DECL_RE, J as ASK_PATTERNS, K as PROTECTED_FRAGMENTS, L as PHP_DECL_RE, M as registerGuard, N as runGuards, O as detectCreationIntent, P as installGuard, Q as GuardContext, R as PY_MODEL_RE, S as skillTriggerGate, St as detectModularArchitecture, T as MAX_EXA_RESULTS, Tt as requiredArchSkill, U as CODE_MUTATORS, V as interfaceSeparationGuard, W as CODE_REDIRECT, X as securityGuard, Y as CRITICAL_PATTERNS, Z as Guard, _ as DEV_VERBS, _t as evaluateFileSize, a as firstHeading, at as freshnessGate, b as detectClaudeMdProjectType, bt as ModularArchitecture, c as parseEntry, ct as PolicyResult, d as EXCLUDE_DIRS, dt as GIT_BLOCKED, et as ApexContext, f as PROJECT_INDICATORS, ft as PROJECT_INSTALL, g as loadApexTaskState, gt as countLines, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as evaluateApex, j as clearUserGuards, k as FAIL_CLOSED, l as parseBodyDesc, lt as evaluate, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as brainstormGate, o as TreeEntry, ot as solidReadGate, p as ApexTaskState, pt as SYSTEM_INSTALL, q as protectedPathGuard, r as descFromText, rt as docConsultedGate, s as parseEnrichment, st as PolicyContext, t as isHtmlLike, tt as ApexGate, u as parseField, ut as GIT_ASK, v as buildApexInstruction, vt as detectFramework, w as frameworkSolidGate, wt as isApexCommand, x as detectRequiredSkills, xt as ProjectType, y as buildClaudeMdContext, yt as DEV_KEYWORDS, z as SWIFT_PROTO_RE } from "./index-
|
|
8
|
+
import { $ as APEX_GATES, A as GUARDS, B as TS_DECL_RE, C as SKILL_TRIGGERS, Ct as detectProjectType, D as capVerbosity, E as MAX_TOKENS, F as GO_DECL_RE, G as bashWriteGuard, H as ASK_WRITERS, I as JAVA_DECL_RE, J as ASK_PATTERNS, K as PROTECTED_FRAGMENTS, L as PHP_DECL_RE, M as registerGuard, N as runGuards, O as detectCreationIntent, P as installGuard, Q as GuardContext, R as PY_MODEL_RE, S as skillTriggerGate, St as detectModularArchitecture, T as MAX_EXA_RESULTS, Tt as requiredArchSkill, U as CODE_MUTATORS, V as interfaceSeparationGuard, W as CODE_REDIRECT, X as securityGuard, Y as CRITICAL_PATTERNS, Z as Guard, _ as DEV_VERBS, _t as evaluateFileSize, a as firstHeading, at as freshnessGate, b as detectClaudeMdProjectType, bt as ModularArchitecture, c as parseEntry, ct as PolicyResult, d as EXCLUDE_DIRS, dt as GIT_BLOCKED, et as ApexContext, f as PROJECT_INDICATORS, ft as PROJECT_INSTALL, g as loadApexTaskState, gt as countLines, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as evaluateApex, j as clearUserGuards, k as FAIL_CLOSED, l as parseBodyDesc, lt as evaluate, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as brainstormGate, o as TreeEntry, ot as solidReadGate, p as ApexTaskState, pt as SYSTEM_INSTALL, q as protectedPathGuard, r as descFromText, rt as docConsultedGate, s as parseEnrichment, st as PolicyContext, t as isHtmlLike, tt as ApexGate, u as parseField, ut as GIT_ASK, v as buildApexInstruction, vt as detectFramework, w as frameworkSolidGate, wt as isApexCommand, x as detectRequiredSkills, xt as ProjectType, y as buildClaudeMdContext, yt as DEV_KEYWORDS, z as SWIFT_PROTO_RE } from "./index-QzK2dv0V.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-DL8MxjuP.mjs";
|
package/dist/index.mjs
CHANGED
|
@@ -4,16 +4,16 @@ 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 evaluateApex, C as MAX_EXA_RESULTS, D as APEX_GATES, E as detectCreationIntent, F as detectProjectType, I as isApexCommand, L as requiredArchSkill, M as solidReadGate, N as DEV_KEYWORDS, O as brainstormGate, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, a as firstHeading, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, f as buildApexTaskContext, g as buildApexInstruction, h as DEV_VERBS, i as firstComment, j as freshnessGate, k as docConsultedGate, l as parseField, m as loadApexTaskState, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS, v as detectClaudeMdProjectType, w as MAX_TOKENS, x as SKILL_TRIGGERS, y as detectRequiredSkills } from "./validate-
|
|
8
|
-
import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, 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 bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "./evaluate-
|
|
7
|
+
import { A as evaluateApex, C as MAX_EXA_RESULTS, D as APEX_GATES, E as detectCreationIntent, F as detectProjectType, I as isApexCommand, L as requiredArchSkill, M as solidReadGate, N as DEV_KEYWORDS, O as brainstormGate, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, a as firstHeading, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, f as buildApexTaskContext, g as buildApexInstruction, h as DEV_VERBS, i as firstComment, j as freshnessGate, k as docConsultedGate, l as parseField, m as loadApexTaskState, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS, v as detectClaudeMdProjectType, w as MAX_TOKENS, x as SKILL_TRIGGERS, y as detectRequiredSkills } from "./validate-DLrWtaDR.mjs";
|
|
8
|
+
import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, 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 bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "./evaluate-zyxeVZPB.mjs";
|
|
9
9
|
import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-Dd_x1-tZ.mjs";
|
|
10
10
|
import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-D8cVrI-s.mjs";
|
|
11
11
|
import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
|
|
12
12
|
import { a as nowStamp, c as stateFileFor, i as lessonsFileFor, l as throttleMs, n as readRoots, o as readState, r as registryFile, s as setStateField, t as addRoot, u as ensureMemoryGitignore } from "./registry-BkoEbdec.mjs";
|
|
13
13
|
import { n as jaccardSimilar, r as queryHash, t as compactMarkdown } from "./cache-C9z9LclL.mjs";
|
|
14
14
|
import { a as extractText, i as mcpCacheKey, n as cachePath, o as loadIndex, r as cacheStore, s as summarizeIndex, t as cacheLookup } from "./store-PrNPm6So.mjs";
|
|
15
|
-
import { t as incrementTrivialEditCounter } from "./freshness-
|
|
15
|
+
import { t as incrementTrivialEditCounter } from "./freshness-43gxYpiX.mjs";
|
|
16
16
|
import { n as toRefMeta, t as loadRefs } from "./loader-CyAoJv2W.mjs";
|
|
17
|
-
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-
|
|
17
|
+
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-BthKK4Jj.mjs";
|
|
18
18
|
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";
|
|
19
19
|
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, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GRADIENT_BLOCKS, GUARDS, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_LINES_ENV_KEY, MAX_TOKENS, PHP_DECL_RE, PROGRESS_BAR_DEFAULTS, PROGRESS_CHARS, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, SKILL_TRIGGERS, STATE_GITIGNORE, STATE_ROOT, SWIFT_PROTO_RE, SYSTEM_INSTALL, TIME_INTERVALS, TS_DECL_RE, TTL_ENV_KEY, acquireLock, addRoot, apexStateDir, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, cacheLookup, cachePath, cacheStore, capVerbosity, clearUserGuards, colors, compactJson, compactMarkdown, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectHarness, detectMode, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, ensureMemoryGitignore, ensureStateDir, 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, jaccardSimilar, lessonsFileFor, loadApexTaskState, loadIndex, loadRefs, loadState, matchPatterns, mcpCacheKey, missingSeoElements, modeFor, nowStamp, parseBodyDesc, parseEnrichment, parseEntry, parseEnvInt, parseField, parseFrontmatter, progressiveColor, projectLayout, projectRoot, projectRootOrNull, protectedPathGuard, queryHash, readRoots, readState, registerGuard, registryFile, requiredArchSkill, resolveMaxLines, resolveSessions, resolveTtlSec, routeReferences, runGuards, saveState, scoreReferences, securityGuard, setStateField, skillTriggerGate, solidReadGate, splitTarget, stateFileFor, stateFilePath, summarizeIndex, taskComplete, taskCreate, taskStart, throttleMs, toRefMeta, ttlLabel, walkUpFor };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as compactJson } from "./compact-json-DK2nX-MK.mjs";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
3
|
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
5
5
|
import { mkdir } from "node:fs/promises";
|
|
6
6
|
//#region src/util/json-io.ts
|
|
7
7
|
/** Atomically write `data` to `path` (temp + rename, 0o600). Cross-FS safe on macOS/Linux. */
|
|
@@ -36,5 +36,9 @@ async function readJsonFile(path) {
|
|
|
36
36
|
async function writeJsonFile(path, data, compact = false) {
|
|
37
37
|
atomicWrite(path, compact ? compactJson(data) : JSON.stringify(data, null, 2));
|
|
38
38
|
}
|
|
39
|
+
/** 8-char MD5 of text (cache key; non-cryptographic). Portable Node+Bun. */
|
|
40
|
+
function hashText(text) {
|
|
41
|
+
return createHash("md5").update(text).digest("hex").slice(0, 8);
|
|
42
|
+
}
|
|
39
43
|
//#endregion
|
|
40
|
-
export { writeJsonFile as i, ensureDir as n,
|
|
44
|
+
export { writeJsonFile as a, readJsonFile as i, ensureDir as n, hashText as r, atomicWrite as t };
|
package/dist/policy/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as APEX_GATES, A as GUARDS, B as TS_DECL_RE, C as SKILL_TRIGGERS, Ct as detectProjectType, D as capVerbosity, E as MAX_TOKENS, F as GO_DECL_RE, G as bashWriteGuard, H as ASK_WRITERS, I as JAVA_DECL_RE, J as ASK_PATTERNS, K as PROTECTED_FRAGMENTS, L as PHP_DECL_RE, M as registerGuard, N as runGuards, O as detectCreationIntent, P as installGuard, Q as GuardContext, R as PY_MODEL_RE, S as skillTriggerGate, St as detectModularArchitecture, T as MAX_EXA_RESULTS, Tt as requiredArchSkill, U as CODE_MUTATORS, V as interfaceSeparationGuard, W as CODE_REDIRECT, X as securityGuard, Y as CRITICAL_PATTERNS, Z as Guard, _ as DEV_VERBS, _t as evaluateFileSize, a as firstHeading, at as freshnessGate, b as detectClaudeMdProjectType, bt as ModularArchitecture, c as parseEntry, ct as PolicyResult, d as EXCLUDE_DIRS, dt as GIT_BLOCKED, et as ApexContext, f as PROJECT_INDICATORS, ft as PROJECT_INSTALL, g as loadApexTaskState, gt as countLines, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as evaluateApex, j as clearUserGuards, k as FAIL_CLOSED, l as parseBodyDesc, lt as evaluate, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as brainstormGate, o as TreeEntry, ot as solidReadGate, p as ApexTaskState, pt as SYSTEM_INSTALL, q as protectedPathGuard, r as descFromText, rt as docConsultedGate, s as parseEnrichment, st as PolicyContext, t as isHtmlLike, tt as ApexGate, u as parseField, ut as GIT_ASK, v as buildApexInstruction, vt as detectFramework, w as frameworkSolidGate, wt as isApexCommand, x as detectRequiredSkills, xt as ProjectType, y as buildClaudeMdContext, yt as DEV_KEYWORDS, z as SWIFT_PROTO_RE } from "../index-
|
|
1
|
+
import { $ as APEX_GATES, A as GUARDS, B as TS_DECL_RE, C as SKILL_TRIGGERS, Ct as detectProjectType, D as capVerbosity, E as MAX_TOKENS, F as GO_DECL_RE, G as bashWriteGuard, H as ASK_WRITERS, I as JAVA_DECL_RE, J as ASK_PATTERNS, K as PROTECTED_FRAGMENTS, L as PHP_DECL_RE, M as registerGuard, N as runGuards, O as detectCreationIntent, P as installGuard, Q as GuardContext, R as PY_MODEL_RE, S as skillTriggerGate, St as detectModularArchitecture, T as MAX_EXA_RESULTS, Tt as requiredArchSkill, U as CODE_MUTATORS, V as interfaceSeparationGuard, W as CODE_REDIRECT, X as securityGuard, Y as CRITICAL_PATTERNS, Z as Guard, _ as DEV_VERBS, _t as evaluateFileSize, a as firstHeading, at as freshnessGate, b as detectClaudeMdProjectType, bt as ModularArchitecture, c as parseEntry, ct as PolicyResult, d as EXCLUDE_DIRS, dt as GIT_BLOCKED, et as ApexContext, f as PROJECT_INDICATORS, ft as PROJECT_INSTALL, g as loadApexTaskState, gt as countLines, h as buildApexTaskInjection, ht as FileSizeVerdict, i as firstComment, it as evaluateApex, j as clearUserGuards, k as FAIL_CLOSED, l as parseBodyDesc, lt as evaluate, m as buildApexTaskContext, mt as matchPatterns, n as missingSeoElements, nt as brainstormGate, o as TreeEntry, ot as solidReadGate, p as ApexTaskState, pt as SYSTEM_INSTALL, q as protectedPathGuard, r as descFromText, rt as docConsultedGate, s as parseEnrichment, st as PolicyContext, t as isHtmlLike, tt as ApexGate, u as parseField, ut as GIT_ASK, v as buildApexInstruction, vt as detectFramework, w as frameworkSolidGate, wt as isApexCommand, x as detectRequiredSkills, xt as ProjectType, y as buildClaudeMdContext, yt as DEV_KEYWORDS, z as SWIFT_PROTO_RE } from "../index-QzK2dv0V.mjs";
|
|
2
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, FileSizeVerdict, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, Guard, GuardContext, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_TOKENS, ModularArchitecture, PHP_DECL_RE, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, PolicyContext, PolicyResult, ProjectType, SKILL_TRIGGERS, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, TreeEntry, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, isHtmlLike, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate };
|
package/dist/policy/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as evaluateApex, C as MAX_EXA_RESULTS, D as APEX_GATES, E as detectCreationIntent, F as detectProjectType, I as isApexCommand, L as requiredArchSkill, M as solidReadGate, N as DEV_KEYWORDS, O as brainstormGate, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, a as firstHeading, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, f as buildApexTaskContext, g as buildApexInstruction, h as DEV_VERBS, i as firstComment, j as freshnessGate, k as docConsultedGate, l as parseField, m as loadApexTaskState, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS, v as detectClaudeMdProjectType, w as MAX_TOKENS, x as SKILL_TRIGGERS, y as detectRequiredSkills } from "../validate-
|
|
2
|
-
import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, 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 bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "../evaluate-
|
|
1
|
+
import { A as evaluateApex, C as MAX_EXA_RESULTS, D as APEX_GATES, E as detectCreationIntent, F as detectProjectType, I as isApexCommand, L as requiredArchSkill, M as solidReadGate, N as DEV_KEYWORDS, O as brainstormGate, P as detectModularArchitecture, S as frameworkSolidGate, T as capVerbosity, _ as buildClaudeMdContext, a as firstHeading, b as skillTriggerGate, c as parseBodyDesc, d as PROJECT_INDICATORS, f as buildApexTaskContext, g as buildApexInstruction, h as DEV_VERBS, i as firstComment, j as freshnessGate, k as docConsultedGate, l as parseField, m as loadApexTaskState, n as missingSeoElements, o as parseEnrichment, p as buildApexTaskInjection, r as descFromText, s as parseEntry, t as isHtmlLike, u as EXCLUDE_DIRS, v as detectClaudeMdProjectType, w as MAX_TOKENS, x as SKILL_TRIGGERS, y as detectRequiredSkills } from "../validate-DLrWtaDR.mjs";
|
|
2
|
+
import { A as evaluateFileSize, C as securityGuard, D as SYSTEM_INSTALL, E as PROJECT_INSTALL, O as matchPatterns, S as CRITICAL_PATTERNS, T as GIT_BLOCKED, _ as CODE_REDIRECT, a as registerGuard, b as protectedPathGuard, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as CODE_MUTATORS, h as ASK_WRITERS, i as clearUserGuards, j as detectFramework, k as countLines, 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 bashWriteGuard, w as GIT_ASK, x as ASK_PATTERNS, y as PROTECTED_FRAGMENTS } from "../evaluate-zyxeVZPB.mjs";
|
|
3
3
|
import "../policy-la_KkjCS.mjs";
|
|
4
4
|
export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_TOKENS, PHP_DECL_RE, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PY_MODEL_RE, SKILL_TRIGGERS, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, isHtmlLike, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate };
|
|
@@ -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-zyxeVZPB.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
|
@@ -3,7 +3,32 @@ import { t as RefMeta } from "../types-CY5qT2X1.mjs";
|
|
|
3
3
|
import { t as AgentQuality } from "../session-state-DxNkIBZ2.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/runtime/paths.d.ts
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Compute a stable 8-char hex hash for a project directory path.
|
|
8
|
+
* Delegates to `hashText` (MD5, non-cryptographic — used as a stable dir key only).
|
|
9
|
+
*
|
|
10
|
+
* @param projectDir - Absolute path to the project root; defaults to CLAUDE_PROJECT_DIR/cwd.
|
|
11
|
+
* @returns 8-char lowercase hex string.
|
|
12
|
+
*/
|
|
13
|
+
declare function projectHash(projectDir?: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Canonical base directory for per-project harness state.
|
|
16
|
+
* Resolves to: ~/.claude/fuse-harness/state/<projectHash>/
|
|
17
|
+
*
|
|
18
|
+
* @param projectDir - Optional override for hashing; defaults to CLAUDE_PROJECT_DIR/cwd.
|
|
19
|
+
* @returns Absolute directory path (not yet created on disk).
|
|
20
|
+
*/
|
|
21
|
+
declare function defaultStateDir(projectDir?: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Absolute path to a session's track JSON file.
|
|
24
|
+
*
|
|
25
|
+
* The session identifier is sanitised to `[A-Za-z0-9_-]` before use in the filename.
|
|
26
|
+
*
|
|
27
|
+
* @param sessionId - Claude session identifier (raw value accepted; sanitised internally).
|
|
28
|
+
* @param baseDir - Override the base directory. Omit in production; pass an explicit
|
|
29
|
+
* temp path in unit tests to avoid touching $HOME.
|
|
30
|
+
* @returns Absolute path, e.g. ~/.claude/fuse-harness/state/a1b2c3d4/track-abc123.json
|
|
31
|
+
*/
|
|
7
32
|
declare function trackFile(sessionId: string, baseDir?: string): string;
|
|
8
33
|
//#endregion
|
|
9
34
|
//#region src/runtime/storage.d.ts
|
|
@@ -69,6 +94,8 @@ interface GateInput {
|
|
|
69
94
|
windowMs?: number;
|
|
70
95
|
isReplaceAll?: boolean;
|
|
71
96
|
agentType?: string;
|
|
97
|
+
/** Absolute path to the session transcript (Claude `transcript_path`) for evidence-based freshness. */
|
|
98
|
+
transcriptPath?: string;
|
|
72
99
|
}
|
|
73
100
|
//#endregion
|
|
74
101
|
//#region src/runtime/gate.d.ts
|
|
@@ -678,4 +705,4 @@ interface PreContext {
|
|
|
678
705
|
*/
|
|
679
706
|
declare function handlePre(ctx: PreContext): Promise<HandleOutcome>;
|
|
680
707
|
//#endregion
|
|
681
|
-
export { Activity, DEFAULT_WINDOW_MS, DuplicationVerdict, type GateInput, HandleOptions, HandleOutcome, LifecycleInput, MCP_TTL_MS, McpIntercept, NormalizedEvent, PluginScope, PreContext, REQUIRED_AGENTS, SolidProfile, TRIVIAL_BUDGET, ToolEvent, activityFor, aipilotPostToolUse, cartoSessionStart, claudeHome, cleanupSession, countFiles, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dryGate, extractSymbols, fusengineCache, gate, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lessonsFileFor, lessonsStateFileFor, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateTeammateOutput, writePluginMap, writeTree };
|
|
708
|
+
export { Activity, DEFAULT_WINDOW_MS, DuplicationVerdict, type GateInput, HandleOptions, HandleOutcome, LifecycleInput, MCP_TTL_MS, McpIntercept, NormalizedEvent, PluginScope, PreContext, REQUIRED_AGENTS, SolidProfile, TRIVIAL_BUDGET, ToolEvent, activityFor, aipilotPostToolUse, cartoSessionStart, claudeHome, cleanupSession, countFiles, defaultStateDir, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dryGate, extractSymbols, fusengineCache, gate, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, 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, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateTeammateOutput, writePluginMap, writeTree };
|
package/dist/runtime/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as projectLayout } from "../layout-C0jaaCQC.mjs";
|
|
2
|
-
import { $ as detectSolidProfile, A as dispatchLessons, At as
|
|
2
|
+
import { $ as detectSolidProfile, A as dispatchLessons, At as mcpPreIntercept, B as mergeLines, C as securityStateDir, Ct as defaultStateDir, D as dispatchLifecycle, Dt as MCP_TTL_MS, E as trackEnrichment, Et as normalizeEvent, F as writePluginMap, G as trackSessionChanges, H as getFileDesc, I as generateProjectMap, J as saveApexState, K as validateRulesLoaded, L as isProject, M as lessonsStateFileFor, Mt as activityFor, N as cartoSessionStart, O as aipilotPostToolUse, Ot as isMcpTool, P as generateEcosystemMap, Q as subagentCacheContext, R as writeTree, S as saveSecurityState, St as recordActivity, T as todayUtc, Tt as trackFile, U as listChildren, V as countFiles, W as postEditTypescript, X as validateTeammateOutput, Y as logToolFailure, Z as trackAgentMemory, _ as trackWatchResearch, _t as sessionStatePath, a as TRIVIAL_BUDGET, at as pruneEmptyDirs, b as isoUtc, bt as taskContext, c as detectDuplication, ct as trimLogFile, d as lifecycleStdout, dt as projectContext, et as solidDetectStart, f as postEditContext, ft as claudeHome, g as postTrackingSideEffects, gt as saveSessionState, h as securityAdvisory, ht as sanitizeSessionId, i as REQUIRED_AGENTS, it as sessionStartCore, j as lessonsFileFor, jt as queryOf, k as dispatchAipilot, kt as mcpPostStore, l as dryGate, lt as devContext, m as seoPostToolUseResponse, mt as loadSessionState, n as handlePre, nt as readRules, o as gate, ot as purgeTtlTree, p as seoPostToolUse, pt as fusengineCache, q as cleanupSession, r as DEFAULT_WINDOW_MS, rt as runSessionStartCleanups, s as preCommitGate, st as removeOldFiles, t as handleHook, tt as injectRules, u as extractSymbols, ut as gitContext, v as trackMcpResearch, vt as sessionsDir, w as securityStatePath, wt as projectHash, x as loadSecurityState, xt as respond, y as trackSkillRead, yt as promptSubmitContext, z as loadEnriched } from "../handle-DMHjTY1E.mjs";
|
|
3
3
|
//#region src/runtime/storage.ts
|
|
4
4
|
/**
|
|
5
5
|
* The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
|
|
@@ -9,4 +9,4 @@ function harnessStateDir(root) {
|
|
|
9
9
|
return projectLayout(root).stateDir;
|
|
10
10
|
}
|
|
11
11
|
//#endregion
|
|
12
|
-
export { DEFAULT_WINDOW_MS, MCP_TTL_MS, REQUIRED_AGENTS, TRIVIAL_BUDGET, activityFor, aipilotPostToolUse, cartoSessionStart, claudeHome, cleanupSession, countFiles, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dryGate, extractSymbols, fusengineCache, gate, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, lessonsFileFor, lessonsStateFileFor, lifecycleStdout, listChildren, loadEnriched, loadSecurityState, loadSessionState, logToolFailure, mcpPostStore, mcpPreIntercept, mergeLines, normalizeEvent, postEditContext, postEditTypescript, postTrackingSideEffects, preCommitGate, projectContext, promptSubmitContext, pruneEmptyDirs, purgeTtlTree, queryOf, readRules, recordActivity, removeOldFiles, respond, runSessionStartCleanups, sanitizeSessionId, saveApexState, saveSecurityState, saveSessionState, securityAdvisory, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateTeammateOutput, writePluginMap, writeTree };
|
|
12
|
+
export { DEFAULT_WINDOW_MS, MCP_TTL_MS, REQUIRED_AGENTS, TRIVIAL_BUDGET, activityFor, aipilotPostToolUse, cartoSessionStart, claudeHome, cleanupSession, countFiles, defaultStateDir, detectDuplication, detectSolidProfile, devContext, dispatchAipilot, dispatchLessons, dispatchLifecycle, dryGate, extractSymbols, fusengineCache, gate, generateEcosystemMap, generateProjectMap, getFileDesc, gitContext, handleHook, handlePre, harnessStateDir, injectRules, isMcpTool, isProject, isoUtc, 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, securityStateDir, securityStatePath, seoPostToolUse, seoPostToolUseResponse, sessionStartCore, sessionStatePath, sessionsDir, solidDetectStart, subagentCacheContext, taskContext, todayUtc, trackAgentMemory, trackEnrichment, trackFile, trackMcpResearch, trackSessionChanges, trackSkillRead, trackWatchResearch, trimLogFile, validateRulesLoaded, validateTeammateOutput, writePluginMap, writeTree };
|
package/dist/state/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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-
|
|
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-BthKK4Jj.mjs";
|
|
2
2
|
export { acquireLock, apexStateDir, ensureStateDir, loadState, saveState, stateFilePath, taskComplete, taskCreate, taskStart };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as writeJsonFile, i as readJsonFile, n as ensureDir } from "./json-io-CvSumjtz.mjs";
|
|
2
2
|
import { mkdir, rmdir } from "node:fs/promises";
|
|
3
3
|
//#region src/state/lock.ts
|
|
4
4
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { a as writeJsonFile, i as readJsonFile } from "./json-io-CvSumjtz.mjs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { createHmac, randomBytes } from "node:crypto";
|
|
6
|
+
//#region src/tracking/session-state.ts
|
|
7
|
+
/** A fresh, empty track. */
|
|
8
|
+
function emptyTrack() {
|
|
9
|
+
return {
|
|
10
|
+
authorizations: {},
|
|
11
|
+
refsRead: [],
|
|
12
|
+
agents: [],
|
|
13
|
+
trivialEdits: []
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Record a doc consultation (Context7/Exa) for a framework in this session. Immutable. */
|
|
17
|
+
function recordDoc(track, framework, sessionId, source) {
|
|
18
|
+
const prev = track.authorizations[framework] ?? {};
|
|
19
|
+
const sessions = new Set(prev.doc_sessions ?? []);
|
|
20
|
+
sessions.add(sessionId);
|
|
21
|
+
const sources = new Set(prev.sources ?? (prev.source ? [prev.source] : []));
|
|
22
|
+
sources.add(source);
|
|
23
|
+
return {
|
|
24
|
+
...track,
|
|
25
|
+
authorizations: {
|
|
26
|
+
...track.authorizations,
|
|
27
|
+
[framework]: {
|
|
28
|
+
...prev,
|
|
29
|
+
doc_sessions: [...sessions],
|
|
30
|
+
sources: [...sources]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Record that a SOLID reference file was read (deduped). Immutable. */
|
|
36
|
+
function recordRefRead(track, path) {
|
|
37
|
+
return track.refsRead.includes(path) ? track : {
|
|
38
|
+
...track,
|
|
39
|
+
refsRead: [...track.refsRead, path]
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Record an agent/tool call with a timestamp + optional quality. Immutable. */
|
|
43
|
+
function recordAgent(track, name, ts, quality) {
|
|
44
|
+
const entry = quality ? {
|
|
45
|
+
name,
|
|
46
|
+
ts,
|
|
47
|
+
quality
|
|
48
|
+
} : {
|
|
49
|
+
name,
|
|
50
|
+
ts
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
...track,
|
|
54
|
+
agents: [...track.agents, entry]
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** True when ALL of `names` ran within `windowMs` with non-insufficient quality. */
|
|
58
|
+
function agentsFresh(track, names, windowMs, now) {
|
|
59
|
+
const cutoff = now - windowMs;
|
|
60
|
+
return names.every((n) => track.agents.some((a) => a.name === n && a.ts > cutoff && a.quality !== "insufficient"));
|
|
61
|
+
}
|
|
62
|
+
/** Record a trivial edit timestamp (sliding window; old evicted). Immutable. */
|
|
63
|
+
function recordTrivialEdit(track, ts, windowMs, now) {
|
|
64
|
+
const cutoff = now - windowMs;
|
|
65
|
+
return {
|
|
66
|
+
...track,
|
|
67
|
+
trivialEdits: [...(track.trivialEdits ?? []).filter((t) => t > cutoff), ts]
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** Count trivial edits within the sliding window. */
|
|
71
|
+
function trivialCount(track, windowMs, now) {
|
|
72
|
+
const cutoff = now - windowMs;
|
|
73
|
+
return (track.trivialEdits ?? []).filter((t) => t > cutoff).length;
|
|
74
|
+
}
|
|
75
|
+
/** Set the brainstorm-required flag (from creation-intent detection). Immutable. */
|
|
76
|
+
function recordBrainstormRequired(track, required) {
|
|
77
|
+
return {
|
|
78
|
+
...track,
|
|
79
|
+
brainstormRequired: required
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/tracking/integrity.ts
|
|
84
|
+
/**
|
|
85
|
+
* @module integrity
|
|
86
|
+
* HMAC-SHA256 tamper-evident wrapping for {@link SessionTrack}.
|
|
87
|
+
*
|
|
88
|
+
* Failure policy: ONLY a MAC mismatch causes fail-closed (returns null).
|
|
89
|
+
* The nonce is included in the signed payload and written to disk for advisory
|
|
90
|
+
* diagnostics, but is NOT checked during verification — concurrent hook
|
|
91
|
+
* invocations (PostToolUse, SubagentStop, …) legitimately load the same
|
|
92
|
+
* envelope after the nonce watermark advances; a monotonic check would trigger
|
|
93
|
+
* spurious fail-closed behaviour mid-session.
|
|
94
|
+
*
|
|
95
|
+
* The machine key is readable by the same agent process, so this deters naive
|
|
96
|
+
* out-of-band tampering — not a determined re-sign. Item B (transcript-grounded
|
|
97
|
+
* freshness) is the primary guarantee.
|
|
98
|
+
* @packageDocumentation
|
|
99
|
+
*/
|
|
100
|
+
const HARNESS_DIR = join(homedir(), ".claude", "fuse-harness");
|
|
101
|
+
const KEY_PATH = join(HARNESS_DIR, ".key");
|
|
102
|
+
const NONCE_PATH = join(HARNESS_DIR, ".nonce");
|
|
103
|
+
/** Load (or create on first use) the per-machine HMAC key stored at mode 0600. */
|
|
104
|
+
function loadOrCreateKey() {
|
|
105
|
+
mkdirSync(HARNESS_DIR, { recursive: true });
|
|
106
|
+
if (!existsSync(KEY_PATH)) {
|
|
107
|
+
const key = randomBytes(32).toString("hex");
|
|
108
|
+
writeFileSync(KEY_PATH, key, {
|
|
109
|
+
encoding: "utf8",
|
|
110
|
+
mode: 384
|
|
111
|
+
});
|
|
112
|
+
return key;
|
|
113
|
+
}
|
|
114
|
+
return readFileSync(KEY_PATH, "utf8").trim();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Persist the last-seen nonce for advisory diagnostics (mode 0600).
|
|
118
|
+
* Never read during {@link verifyTrack} — see module JSDoc for rationale.
|
|
119
|
+
*/
|
|
120
|
+
function writeLastNonce(nonce) {
|
|
121
|
+
mkdirSync(HARNESS_DIR, { recursive: true });
|
|
122
|
+
writeFileSync(NONCE_PATH, String(nonce), {
|
|
123
|
+
encoding: "utf8",
|
|
124
|
+
mode: 384
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/** Compute HMAC-SHA256 over the canonical message `"${nonce}:${data}"`. */
|
|
128
|
+
function computeMac(key, data, nonce) {
|
|
129
|
+
return createHmac("sha256", key).update(`${nonce}:${data}`).digest("hex");
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Sign a {@link SessionTrack} into a tamper-evident envelope. The nonce
|
|
133
|
+
* (`Date.now()`) is embedded in the MAC to bind the timestamp to the payload.
|
|
134
|
+
*/
|
|
135
|
+
function signTrack(track) {
|
|
136
|
+
const key = loadOrCreateKey();
|
|
137
|
+
const data = JSON.stringify(track);
|
|
138
|
+
const nonce = Date.now();
|
|
139
|
+
return {
|
|
140
|
+
data,
|
|
141
|
+
nonce,
|
|
142
|
+
mac: computeMac(key, data, nonce)
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Verify a {@link TrackEnvelope}. Returns the parsed {@link SessionTrack} on
|
|
147
|
+
* success, or `null` ONLY on MAC mismatch / parse failure (fail-closed on
|
|
148
|
+
* tampering). The nonce is NOT checked — see module JSDoc.
|
|
149
|
+
*/
|
|
150
|
+
function verifyTrack(envelope) {
|
|
151
|
+
try {
|
|
152
|
+
const key = loadOrCreateKey();
|
|
153
|
+
if (envelope.mac !== computeMac(key, envelope.data, envelope.nonce)) return null;
|
|
154
|
+
return JSON.parse(envelope.data);
|
|
155
|
+
} catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/tracking/store.ts
|
|
161
|
+
/**
|
|
162
|
+
* Load and verify a session track from a signed envelope file.
|
|
163
|
+
*
|
|
164
|
+
* Returns {@link emptyTrack} (fail closed) when the file is absent, corrupt, or
|
|
165
|
+
* fails MAC validation — so the gates re-require real agents rather than trust a
|
|
166
|
+
* forged track. Only a MAC mismatch triggers fail-closed; the nonce is advisory
|
|
167
|
+
* and is never checked during load.
|
|
168
|
+
*/
|
|
169
|
+
async function loadTrack(file) {
|
|
170
|
+
const envelope = await readJsonFile(file);
|
|
171
|
+
if (!envelope) return emptyTrack();
|
|
172
|
+
return verifyTrack(envelope) ?? emptyTrack();
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Sign and persist a session track as a tamper-evident envelope, then write the
|
|
176
|
+
* advisory nonce watermark.
|
|
177
|
+
*/
|
|
178
|
+
async function saveTrack(file, track) {
|
|
179
|
+
const envelope = signTrack(track);
|
|
180
|
+
await writeJsonFile(file, envelope);
|
|
181
|
+
writeLastNonce(envelope.nonce);
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
184
|
+
export { recordAgent as a, recordRefRead as c, emptyTrack as i, recordTrivialEdit as l, saveTrack as n, recordBrainstormRequired as o, agentsFresh as r, recordDoc as s, loadTrack as t, trivialCount as u };
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { a as recordAgent, c as recordRefRead, i as emptyTrack, l as recordTrivialEdit, n as SessionTrack, o as recordBrainstormRequired, r as agentsFresh, s as recordDoc, t as AgentQuality, u as trivialCount } from "../session-state-DxNkIBZ2.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/tracking/store.d.ts
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Load and verify a session track from a signed envelope file.
|
|
6
|
+
*
|
|
7
|
+
* Returns {@link emptyTrack} (fail closed) when the file is absent, corrupt, or
|
|
8
|
+
* fails MAC validation — so the gates re-require real agents rather than trust a
|
|
9
|
+
* forged track. Only a MAC mismatch triggers fail-closed; the nonce is advisory
|
|
10
|
+
* and is never checked during load.
|
|
11
|
+
*/
|
|
5
12
|
declare function loadTrack(file: string): Promise<SessionTrack>;
|
|
6
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Sign and persist a session track as a tamper-evident envelope, then write the
|
|
15
|
+
* advisory nonce watermark.
|
|
16
|
+
*/
|
|
7
17
|
declare function saveTrack(file: string, track: SessionTrack): Promise<void>;
|
|
8
18
|
//#endregion
|
|
9
19
|
export { AgentQuality, SessionTrack, agentsFresh, emptyTrack, loadTrack, recordAgent, recordBrainstormRequired, recordDoc, recordRefRead, recordTrivialEdit, saveTrack, trivialCount };
|
package/dist/tracking/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as recordAgent, c as recordRefRead, i as emptyTrack, l as recordTrivialEdit, n as saveTrack, o as recordBrainstormRequired, r as agentsFresh, s as recordDoc, t as loadTrack, u as trivialCount } from "../store-
|
|
1
|
+
import { a as recordAgent, c as recordRefRead, i as emptyTrack, l as recordTrivialEdit, n as saveTrack, o as recordBrainstormRequired, r as agentsFresh, s as recordDoc, t as loadTrack, u as trivialCount } from "../store-7j02oGjt.mjs";
|
|
2
2
|
export { agentsFresh, emptyTrack, loadTrack, recordAgent, recordBrainstormRequired, recordDoc, recordRefRead, recordTrivialEdit, saveTrack, trivialCount };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
|
|
2
|
-
import { k as countLines } from "./evaluate-
|
|
2
|
+
import { k as countLines } from "./evaluate-zyxeVZPB.mjs";
|
|
3
3
|
import { r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-Dd_x1-tZ.mjs";
|
|
4
4
|
import { t as routeReferences } from "./router-D8cVrI-s.mjs";
|
|
5
5
|
import { join } from "node:path";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusengine/harness",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
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",
|
package/dist/store-D-ge2ZPI.mjs
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { i as writeJsonFile, r as readJsonFile } from "./json-io-CAn72gI4.mjs";
|
|
2
|
-
//#region src/tracking/session-state.ts
|
|
3
|
-
/** A fresh, empty track. */
|
|
4
|
-
function emptyTrack() {
|
|
5
|
-
return {
|
|
6
|
-
authorizations: {},
|
|
7
|
-
refsRead: [],
|
|
8
|
-
agents: [],
|
|
9
|
-
trivialEdits: []
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
/** Record a doc consultation (Context7/Exa) for a framework in this session. Immutable. */
|
|
13
|
-
function recordDoc(track, framework, sessionId, source) {
|
|
14
|
-
const prev = track.authorizations[framework] ?? {};
|
|
15
|
-
const sessions = new Set(prev.doc_sessions ?? []);
|
|
16
|
-
sessions.add(sessionId);
|
|
17
|
-
const sources = new Set(prev.sources ?? (prev.source ? [prev.source] : []));
|
|
18
|
-
sources.add(source);
|
|
19
|
-
return {
|
|
20
|
-
...track,
|
|
21
|
-
authorizations: {
|
|
22
|
-
...track.authorizations,
|
|
23
|
-
[framework]: {
|
|
24
|
-
...prev,
|
|
25
|
-
doc_sessions: [...sessions],
|
|
26
|
-
sources: [...sources]
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
/** Record that a SOLID reference file was read (deduped). Immutable. */
|
|
32
|
-
function recordRefRead(track, path) {
|
|
33
|
-
return track.refsRead.includes(path) ? track : {
|
|
34
|
-
...track,
|
|
35
|
-
refsRead: [...track.refsRead, path]
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
/** Record an agent/tool call with a timestamp + optional quality. Immutable. */
|
|
39
|
-
function recordAgent(track, name, ts, quality) {
|
|
40
|
-
const entry = quality ? {
|
|
41
|
-
name,
|
|
42
|
-
ts,
|
|
43
|
-
quality
|
|
44
|
-
} : {
|
|
45
|
-
name,
|
|
46
|
-
ts
|
|
47
|
-
};
|
|
48
|
-
return {
|
|
49
|
-
...track,
|
|
50
|
-
agents: [...track.agents, entry]
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
/** True when ALL of `names` ran within `windowMs` with non-insufficient quality. */
|
|
54
|
-
function agentsFresh(track, names, windowMs, now) {
|
|
55
|
-
const cutoff = now - windowMs;
|
|
56
|
-
return names.every((n) => track.agents.some((a) => a.name === n && a.ts > cutoff && a.quality !== "insufficient"));
|
|
57
|
-
}
|
|
58
|
-
/** Record a trivial edit timestamp (sliding window; old evicted). Immutable. */
|
|
59
|
-
function recordTrivialEdit(track, ts, windowMs, now) {
|
|
60
|
-
const cutoff = now - windowMs;
|
|
61
|
-
return {
|
|
62
|
-
...track,
|
|
63
|
-
trivialEdits: [...(track.trivialEdits ?? []).filter((t) => t > cutoff), ts]
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
/** Count trivial edits within the sliding window. */
|
|
67
|
-
function trivialCount(track, windowMs, now) {
|
|
68
|
-
const cutoff = now - windowMs;
|
|
69
|
-
return (track.trivialEdits ?? []).filter((t) => t > cutoff).length;
|
|
70
|
-
}
|
|
71
|
-
/** Set the brainstorm-required flag (from creation-intent detection). Immutable. */
|
|
72
|
-
function recordBrainstormRequired(track, required) {
|
|
73
|
-
return {
|
|
74
|
-
...track,
|
|
75
|
-
brainstormRequired: required
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
//#endregion
|
|
79
|
-
//#region src/tracking/store.ts
|
|
80
|
-
/** Load a session track from a file (an empty track if absent/corrupt). */
|
|
81
|
-
async function loadTrack(file) {
|
|
82
|
-
return await readJsonFile(file) ?? emptyTrack();
|
|
83
|
-
}
|
|
84
|
-
/** Persist a session track. */
|
|
85
|
-
async function saveTrack(file, track) {
|
|
86
|
-
await writeJsonFile(file, track);
|
|
87
|
-
}
|
|
88
|
-
//#endregion
|
|
89
|
-
export { recordAgent as a, recordRefRead as c, emptyTrack as i, recordTrivialEdit as l, saveTrack as n, recordBrainstormRequired as o, agentsFresh as r, recordDoc as s, loadTrack as t, trivialCount as u };
|