@fusengine/harness 0.1.62 → 0.1.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- import { a as fileSizeGuard, c as readClaudeInput, i as denyResponse, l as systemMessage, n as blockResponse, o as guard, r as contextResponse, s as informResponse, t as attachSystemMessage, u as toClaudeResponse } from "../../claude-C0xGMbeA.mjs";
1
+ import { a as fileSizeGuard, c as readClaudeInput, i as denyResponse, l as systemMessage, n as blockResponse, o as guard, r as contextResponse, s as informResponse, t as attachSystemMessage, u as toClaudeResponse } from "../../claude-CaBe4eBY.mjs";
2
2
  export { attachSystemMessage, blockResponse, contextResponse, denyResponse, fileSizeGuard, guard, informResponse, readClaudeInput, systemMessage, toClaudeResponse };
@@ -2,7 +2,7 @@ import { f as countLines } from "../../home-state-D0RLWP8J.mjs";
2
2
  import { t as evaluate } from "../../evaluate-wDDbojx6.mjs";
3
3
  import { t as formatPrompt } from "../../types-ernB1Dy3.mjs";
4
4
  import { t as parseApplyPatch } from "../../apply-patch-CIS2EZ_q.mjs";
5
- import { _ as commandToString, c as readClaudeInput, i as denyResponse, r as contextResponse } from "../../claude-C0xGMbeA.mjs";
5
+ import { c as readClaudeInput, i as denyResponse, r as contextResponse, v as commandToString } from "../../claude-CaBe4eBY.mjs";
6
6
  //#region src/adapters/codex/index.ts
7
7
  /**
8
8
  * OpenAI Codex CLI adapter (hook-mode). Codex's `PreToolUse` hook (since 2026)
@@ -1,2 +1,2 @@
1
- import { n as readHermesInput, r as toHermesResponse, t as guard } from "../../hermes-C1gt6ooE.mjs";
1
+ import { n as readHermesInput, r as toHermesResponse, t as guard } from "../../hermes-BdwBBemn.mjs";
2
2
  export { guard, readHermesInput, toHermesResponse };
@@ -81,11 +81,23 @@ function spawnCapture(cmd, args, cwd) {
81
81
  return "";
82
82
  }
83
83
  }
84
- /** Read the full process stdin as UTF-8 text (works under Node and Bun). */
84
+ /**
85
+ * Read the full process stdin as UTF-8 text (works under Node and Bun).
86
+ * Synchronous fd-0 read — never `for await (const c of process.stdin)` —
87
+ * because Bun has a confirmed Linux-only bug where merely adding a new
88
+ * top-level module import shifts stdin's internal init order and makes
89
+ * that async iterator silently yield zero bytes (oven-sh/bun#25320,
90
+ * #27849): exactly what broke every `harness hook` invocation on CI the
91
+ * moment `figures` became this package's first runtime dependency.
92
+ * `readFileSync(0)` bypasses that stream/ownership machinery entirely and
93
+ * is well-supported for piped (non-TTY) stdin under both runtimes.
94
+ */
85
95
  async function readStdin() {
86
- const chunks = [];
87
- for await (const chunk of process.stdin) chunks.push(chunk);
88
- return Buffer.concat(chunks).toString("utf8");
96
+ try {
97
+ return readFileSync(0, "utf8");
98
+ } catch {
99
+ return "";
100
+ }
89
101
  }
90
102
  /**
91
103
  * Recursively collect files under `dir` whose extension is in `exts`, skipping
@@ -214,4 +226,4 @@ function guard(input) {
214
226
  /** @deprecated use {@link guard}. Kept for back-compat. */
215
227
  const fileSizeGuard = guard;
216
228
  //#endregion
217
- export { commandToString as _, fileSizeGuard as a, readClaudeInput as c, collectFiles as d, pathExists as f, writeText as g, spawnCapture as h, denyResponse as i, systemMessage as l, sleep as m, blockResponse as n, guard as o, readText as p, contextResponse as r, informResponse as s, attachSystemMessage as t, toClaudeResponse as u };
229
+ export { writeText as _, fileSizeGuard as a, readClaudeInput as c, collectFiles as d, pathExists as f, spawnCapture as g, sleep as h, denyResponse as i, systemMessage as l, readText as m, blockResponse as n, guard as o, readStdin as p, contextResponse as r, informResponse as s, attachSystemMessage as t, toClaudeResponse as u, commandToString as v };
package/dist/cli/bin.mjs CHANGED
@@ -4,7 +4,8 @@ import { t as detectHarness } from "../harness-Cb9xR8dC.mjs";
4
4
  import { t as claudeHome } from "../home-state-D0RLWP8J.mjs";
5
5
  import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-kVHXFVug.mjs";
6
6
  import { n as writeInitFile, t as initFor } from "../run-Do2JltgU.mjs";
7
- import { J as runningVersion, Lt as todayUtc, Y as versionBanner, q as runDoctor, t as handleHook } from "../handle-C2-HU8PS.mjs";
7
+ import { J as runningVersion, Lt as todayUtc, Y as versionBanner, q as runDoctor, t as handleHook } from "../handle-DE-753Mr.mjs";
8
+ import { p as readStdin$1 } from "../claude-CaBe4eBY.mjs";
8
9
  import { delimiter, join } from "node:path";
9
10
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
10
11
  import { homedir } from "node:os";
@@ -361,15 +362,19 @@ function discoverRefs(home, cwd, marketplaces) {
361
362
  * harness hook <id> runtime: read a hook payload on stdin, route to the adapter, print the response
362
363
  * harness changelog fetch + diff the Claude Code changelog, print a JSON summary (changelog-watcher)
363
364
  */
365
+ const hookDebug = process.env.FUSE_HARNESS_DEBUG === "1";
366
+ function traceHook(label, data) {
367
+ if (hookDebug) process.stderr.write(`[hook-debug] ${label}: ${typeof data === "string" ? data : JSON.stringify(data)}\n`);
368
+ }
364
369
  async function readStdin() {
365
- const chunks = [];
366
- for await (const c of process.stdin) chunks.push(c);
367
- const text = Buffer.concat(chunks).toString("utf8").trim();
370
+ const text = (await readStdin$1()).trim();
371
+ traceHook("stdin-text-length", text.length);
368
372
  if (!text) return {};
369
373
  try {
370
374
  const parsed = JSON.parse(text);
371
375
  return typeof parsed === "object" && parsed !== null ? parsed : {};
372
- } catch {
376
+ } catch (e) {
377
+ traceHook("stdin-parse-error", e instanceof Error ? e.message : String(e));
373
378
  return {};
374
379
  }
375
380
  }
@@ -399,13 +404,27 @@ if (cmd === "--version" || cmd === "-v") {
399
404
  ])).has(scopeArg) ? scopeArg : "core";
400
405
  const marketplaces = (process.env.FUSE_HARNESS_MARKETPLACES ?? "fusengine-plugins").split(",").map((s) => s.trim()).filter(Boolean);
401
406
  const refsDir = process.env.FUSE_HARNESS_REFS || discoverRefs(homedir(), process.cwd(), marketplaces) || void 0;
402
- const outcome = await handleHook(id, await readStdin(), {
403
- now: Date.now(),
404
- cwd: process.cwd(),
405
- refsDir,
406
- windowMs: resolveTtlSec(process.env) * 1e3,
407
+ traceHook("args", {
408
+ id,
407
409
  scope
408
410
  });
411
+ let outcome;
412
+ try {
413
+ outcome = await handleHook(id, await readStdin(), {
414
+ now: Date.now(),
415
+ cwd: process.cwd(),
416
+ refsDir,
417
+ windowMs: resolveTtlSec(process.env) * 1e3,
418
+ scope
419
+ });
420
+ } catch (e) {
421
+ traceHook("handleHook-threw", e instanceof Error ? `${e.message}\n${e.stack}` : String(e));
422
+ throw e;
423
+ }
424
+ traceHook("outcome", {
425
+ stdoutLength: outcome.stdout.length,
426
+ exit: outcome.exit
427
+ });
409
428
  if (outcome.stdout) process.stdout.write(outcome.stdout);
410
429
  process.exit(outcome.exit);
411
430
  } else if (cmd === "init") {
@@ -2,7 +2,7 @@ import { a as parseEnvInt, i as splitTarget, r as resolveMaxLines } from "./limi
2
2
  import { s as resolveTtlSec } from "./dotenv-Jj8aL1FL.mjs";
3
3
  import { r as projectLayout } from "./layout-C0jaaCQC.mjs";
4
4
  import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
5
- import { A as detectCreationIntent, E as isExcludedSwiftPath, F as docConsultedGate, H as detectProjectType$1, I as evaluateApex, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, S as usesTailwindUtilities, T as isExcludedJsPath, V as detectModularArchitecture, W as requiredArchSkill, _ as scanPlugin, c as EXCLUDE_DIRS$1, d as buildApexTaskInjection, h as buildClaudeMdContext, k as capVerbosity, l as PROJECT_INDICATORS, n as missingSeoElements, o as parseEnrichment, r as descFromText, s as parseEntry, t as isHtmlLike, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "./validate-CjpoH2bf.mjs";
5
+ import { A as detectCreationIntent, E as isExcludedSwiftPath, F as docConsultedGate, H as detectProjectType$1, I as evaluateApex, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, S as usesTailwindUtilities, T as isExcludedJsPath, V as detectModularArchitecture, W as requiredArchSkill, _ as scanPlugin, c as EXCLUDE_DIRS$1, d as buildApexTaskInjection, h as buildClaudeMdContext, k as capVerbosity, l as PROJECT_INDICATORS, n as missingSeoElements, o as parseEnrichment, r as descFromText, s as parseEntry, t as isHtmlLike, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "./validate-DnOqIZD_.mjs";
6
6
  import { a as sanitizeSessionId, c as sessionsDir, d as countFrameworkCodeLines, f as countLines, i as loadSessionState, l as PLUGINS_DIR, n as fuseHarnessHome, o as saveSessionState, r as fusengineCache, t as claudeHome } from "./home-state-D0RLWP8J.mjs";
7
7
  import { n as FAIL_CLOSED, t as evaluate } from "./evaluate-wDDbojx6.mjs";
8
8
  import { a as writeJsonFile, i as readJsonFile, r as hashText, t as atomicWrite } from "./json-io-DisYd2fb.mjs";
@@ -14,8 +14,8 @@ import { d as loadIndex, i as cacheLookupMeta, n as webfetchCacheWrite, o as cac
14
14
  import { t as loadRefs } from "./loader-AGz4nK7d.mjs";
15
15
  import { a as writeLastNonce, c as recordAgent, d as recordRefRead, f as recordTarget, h as apexAuthorizationGate, i as verifyTrack, l as recordBrainstormRequired, m as trivialCount, n as saveTrack, o as agentsFresh, p as recordTrivialEdit, r as signTrack, s as emptyTrack, t as loadTrack, u as recordDoc } from "./store-CQ4roWrU.mjs";
16
16
  import { t as parseApplyPatch } from "./apply-patch-CIS2EZ_q.mjs";
17
- import { _ as commandToString, d as collectFiles, f as pathExists, g as writeText, h as spawnCapture, i as denyResponse, l as systemMessage, m as sleep, n as blockResponse, p as readText, r as contextResponse, s as informResponse, t as attachSystemMessage } from "./claude-C0xGMbeA.mjs";
18
- import { r as toHermesResponse } from "./hermes-C1gt6ooE.mjs";
17
+ import { _ as writeText, d as collectFiles, f as pathExists, g as spawnCapture, h as sleep, i as denyResponse, l as systemMessage, m as readText, n as blockResponse, r as contextResponse, s as informResponse, t as attachSystemMessage, v as commandToString } from "./claude-CaBe4eBY.mjs";
18
+ import { r as toHermesResponse } from "./hermes-BdwBBemn.mjs";
19
19
  import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
20
20
  import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
21
21
  import { homedir } from "node:os";
@@ -23,6 +23,7 @@ import { mkdir, rmdir } from "node:fs/promises";
23
23
  import { createHash } from "node:crypto";
24
24
  import { execFileSync, execSync } from "node:child_process";
25
25
  import { fileURLToPath } from "node:url";
26
+ import figures from "figures";
26
27
  //#region src/runtime/lifecycle/security/skill-state.ts
27
28
  /**
28
29
  * Shared security-tracker state: per-UTC-day JSON under
@@ -3951,7 +3952,11 @@ ${agents}
3951
3952
  ### 5. Research Before Code
3952
3953
  - Use Context7/Exa for docs | Write notes to .claude/apex/docs/
3953
3954
 
3954
- ### 6. When Done
3955
+ ### 6. Before Done (NEVER skip)
3956
+ - eLicit: self-review with a NAMED elicitation technique; fix findings first
3957
+ - Verify: run/functional-check your changes (references⇔declarations)
3958
+
3959
+ ### 7. When Done
3955
3960
  - TaskUpdate(taskId, status: completed) triggers auto-commit${cartographerContext()}`));
3956
3961
  }
3957
3962
  /** 16-char hex SHA-256 of `text` (project hash / doc topic key). */
@@ -5166,6 +5171,7 @@ function dispatchLifecycle(input) {
5166
5171
  case "SessionStart": return sessionStart(input);
5167
5172
  case "UserPromptSubmit": return input.scope === "rules" ? injectRules(process.env.CLAUDE_PLUGIN_ROOT ?? input.cwd) : null;
5168
5173
  case "SubagentStart":
5174
+ if (input.scope === "rules") return injectRules(process.env.CLAUDE_PLUGIN_ROOT ?? input.cwd);
5169
5175
  if (input.scope === "aipilot") return "";
5170
5176
  if (input.scope === "lessons") return dispatchLessons("SubagentStart", input.payload, input.cwd, input.now);
5171
5177
  return subagentCacheContext(input.payload.session_id);
@@ -7048,6 +7054,56 @@ function respond(id, prompt) {
7048
7054
  }
7049
7055
  }
7050
7056
  //#endregion
7057
+ //#region src/runtime/deny-notice.ts
7058
+ /**
7059
+ * @module deny-notice
7060
+ * Attach a user-visible notice to a deny/ask hook response — the owner-reported
7061
+ * gap where `permissionDecision: deny/ask` (the agent-only channel) left the
7062
+ * human staring at a silent terminal. Mirrors {@link module:notices}'s
7063
+ * compliance notices but for the BLOCKING outcomes those never covered.
7064
+ * @packageDocumentation
7065
+ */
7066
+ /**
7067
+ * The human-facing line for a block/ask outcome: the gate's own
7068
+ * {@link Prompt.userMessage} when it set one, else a generic symbol + title —
7069
+ * text-presentation Unicode only (`figures.cross`/`?`), never emoji: terminal-safe,
7070
+ * single-cell width, with the Windows fallbacks `figures` already resolves, matching
7071
+ * the existing notice family (`notices.ts`'s `✓`/`⚠`, left untouched by this module).
7072
+ * Null for `inform` ({@link module:respond}'s own `userMessage` path already
7073
+ * covers it) or when neither applies.
7074
+ */
7075
+ function denyAskNotice(prompt) {
7076
+ if (prompt.kind === "block") return prompt.userMessage ?? `${figures.cross} ${prompt.title}`;
7077
+ if (prompt.kind === "ask") return prompt.userMessage ?? `? ${prompt.title}`;
7078
+ return null;
7079
+ }
7080
+ /**
7081
+ * Attach {@link denyAskNotice} onto an already-rendered deny/ask `stdout`, for
7082
+ * the harnesses whose human channel is `systemMessage` (claude-code/codex —
7083
+ * `permissionDecision`/`permissionDecisionReason` stay byte-intact, only the
7084
+ * top-level field is added). Every other harness passes `stdout` through
7085
+ * unchanged: Cursor already emits `user_message` natively (respond.ts), Hermes
7086
+ * and cline have no human channel. Deduped via {@link onceExclusive} against
7087
+ * the ~11 sibling-plugin fan-out for one real event (same window as the
7088
+ * sniper reminder / compliance notices).
7089
+ * @param id - Harness id (`ctx.id` from `PreContext`).
7090
+ * @param stdout - The rendered hook response (from {@link module:respond.respond}).
7091
+ * @param prompt - The {@link Prompt} that produced `stdout`.
7092
+ * @param sessionId - Current session id (dedup scope).
7093
+ * @param dir - State-dir for the dedup marker (per-project state dir).
7094
+ * @param now - Event clock (tests pass a fake one).
7095
+ */
7096
+ function withDenyNotice(id, stdout, prompt, sessionId, dir, now) {
7097
+ if (id !== "claude-code" && id !== "codex") return stdout;
7098
+ const notice = denyAskNotice(prompt);
7099
+ if (!notice) return stdout;
7100
+ if (!onceExclusive(`deny-notice:${sessionId}:${prompt.title}`, 2e3, {
7101
+ now,
7102
+ dir
7103
+ })) return stdout;
7104
+ return attachSystemMessage(stdout, notice);
7105
+ }
7106
+ //#endregion
7051
7107
  //#region src/policy/design/content-checks.ts
7052
7108
  /** Accessibility warnings: icon buttons need aria-label, images need alt. */
7053
7109
  function checkAccessibility(content) {
@@ -7613,7 +7669,7 @@ async function handlePre(ctx) {
7613
7669
  }
7614
7670
  const designBlock = designGate(payload, event, mcpDir, opts.cwd);
7615
7671
  if (designBlock) return {
7616
- stdout: respond(id, designBlock),
7672
+ stdout: withDenyNotice(id, respond(id, designBlock), designBlock, event.sessionId, dirname(file), opts.now),
7617
7673
  exit: 0
7618
7674
  };
7619
7675
  if (opts.scope === "security") return {
@@ -7634,7 +7690,7 @@ async function handlePre(ctx) {
7634
7690
  if (event.files && event.files.length > 0) {
7635
7691
  const patchPrompt = applyPatchGate(event.files, opts.cwd);
7636
7692
  if (patchPrompt) return {
7637
- stdout: respond(id, patchPrompt),
7693
+ stdout: withDenyNotice(id, respond(id, patchPrompt), patchPrompt, event.sessionId, dirname(file), opts.now),
7638
7694
  exit: 0
7639
7695
  };
7640
7696
  }
@@ -7656,7 +7712,7 @@ async function handlePre(ctx) {
7656
7712
  transcriptPath: typeof payload.transcript_path === "string" ? payload.transcript_path : void 0
7657
7713
  });
7658
7714
  if (prompt) return {
7659
- stdout: respond(id, prompt),
7715
+ stdout: withDenyNotice(id, respond(id, prompt), prompt, event.sessionId, dirname(file), opts.now),
7660
7716
  exit: 0
7661
7717
  };
7662
7718
  return allowOutcome(id, event, payload, mcpDir, opts.cwd, {
@@ -1,6 +1,6 @@
1
1
  import { t as evaluate } from "./evaluate-wDDbojx6.mjs";
2
2
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
3
- import { _ as commandToString, c as readClaudeInput } from "./claude-C0xGMbeA.mjs";
3
+ import { c as readClaudeInput, v as commandToString } from "./claude-CaBe4eBY.mjs";
4
4
  //#region src/adapters/hermes/index.ts
5
5
  /**
6
6
  * Hermes Agent adapter (hook-mode). Nous Research's hermes-agent (2026) pipes a
package/dist/index.mjs CHANGED
@@ -4,7 +4,7 @@ import { n as STATE_ROOT, r as projectLayout, t as STATE_GITIGNORE } from "./lay
4
4
  import { t as compactJson } from "./compact-json-DK2nX-MK.mjs";
5
5
  import { i as walkUpFor, n as projectRoot, r as projectRootOrNull, t as isCodeFile } from "./project-root-3kk7gCOp.mjs";
6
6
  import { n as detectMode, r as modeFor, t as detectHarness } from "./harness-Cb9xR8dC.mjs";
7
- import { A as detectCreationIntent, B as DEV_KEYWORDS, C as SKILL_TRIGGERS, D as MAX_EXA_RESULTS, F as docConsultedGate, H as detectProjectType, I as evaluateApex, L as freshnessGate, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, O as MAX_TOKENS, P as brainstormGate, R as solidReadGate, S as usesTailwindUtilities, U as isApexCommand, V as detectModularArchitecture, W as requiredArchSkill, a as firstHeading, b as detectRequiredSkills, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as APEX_GATES, k as capVerbosity, l as PROJECT_INDICATORS, m as buildApexInstruction, n as missingSeoElements, o as parseEnrichment, p as DEV_VERBS, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, v as parseBodyDesc, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "./validate-CjpoH2bf.mjs";
7
+ import { A as detectCreationIntent, B as DEV_KEYWORDS, C as SKILL_TRIGGERS, D as MAX_EXA_RESULTS, F as docConsultedGate, H as detectProjectType, I as evaluateApex, L as freshnessGate, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, O as MAX_TOKENS, P as brainstormGate, R as solidReadGate, S as usesTailwindUtilities, U as isApexCommand, V as detectModularArchitecture, W as requiredArchSkill, a as firstHeading, b as detectRequiredSkills, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as APEX_GATES, k as capVerbosity, l as PROJECT_INDICATORS, m as buildApexInstruction, n as missingSeoElements, o as parseEnrichment, p as DEV_VERBS, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, v as parseBodyDesc, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "./validate-DnOqIZD_.mjs";
8
8
  import { d as countFrameworkCodeLines, f as countLines, l as PLUGINS_DIR, p as evaluateFileSize, u as SOLID_REF } from "./home-state-D0RLWP8J.mjs";
9
9
  import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, S as PROTECTED_FRAGMENTS, T as ASK_PATTERNS, _ as CODE_MUTATORS, a as registerGuard, b as SAFE_PREFIXES, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as ASK_WRITERS, h as bashWriteGuard, i as clearUserGuards, j as RALPH_SAFE, k as GIT_BLOCKED, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as CODE_REDIRECT, w as protectedPathGuard, x as SESSION_STATE_FRAGMENT, y as FILE_REDIRECT } from "./evaluate-wDDbojx6.mjs";
10
10
  import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-CWZegVdR.mjs";
@@ -1,4 +1,4 @@
1
- import { A as detectCreationIntent, B as DEV_KEYWORDS, C as SKILL_TRIGGERS, D as MAX_EXA_RESULTS, F as docConsultedGate, H as detectProjectType, I as evaluateApex, L as freshnessGate, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, O as MAX_TOKENS, P as brainstormGate, R as solidReadGate, S as usesTailwindUtilities, U as isApexCommand, V as detectModularArchitecture, W as requiredArchSkill, a as firstHeading, b as detectRequiredSkills, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as APEX_GATES, k as capVerbosity, l as PROJECT_INDICATORS, m as buildApexInstruction, n as missingSeoElements, o as parseEnrichment, p as DEV_VERBS, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, v as parseBodyDesc, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "../validate-CjpoH2bf.mjs";
1
+ import { A as detectCreationIntent, B as DEV_KEYWORDS, C as SKILL_TRIGGERS, D as MAX_EXA_RESULTS, F as docConsultedGate, H as detectProjectType, I as evaluateApex, L as freshnessGate, M as POST_AUTH_GATES, N as PRE_AUTH_GATES, O as MAX_TOKENS, P as brainstormGate, R as solidReadGate, S as usesTailwindUtilities, U as isApexCommand, V as detectModularArchitecture, W as requiredArchSkill, a as firstHeading, b as detectRequiredSkills, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as APEX_GATES, k as capVerbosity, l as PROJECT_INDICATORS, m as buildApexInstruction, n as missingSeoElements, o as parseEnrichment, p as DEV_VERBS, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, v as parseBodyDesc, w as frameworkSolidGate, x as skillTriggerGate, y as parseField, z as detectFramework } from "../validate-DnOqIZD_.mjs";
2
2
  import { d as countFrameworkCodeLines, f as countLines, l as PLUGINS_DIR, p as evaluateFileSize, u as SOLID_REF } from "../home-state-D0RLWP8J.mjs";
3
3
  import { A as PROJECT_INSTALL, C as PROTECTED_GIT_RE, D as securityGuard, E as CRITICAL_PATTERNS, M as SYSTEM_INSTALL, N as isRalphMode, O as GIT_ASK, P as matchPatterns, S as PROTECTED_FRAGMENTS, T as ASK_PATTERNS, _ as CODE_MUTATORS, a as registerGuard, b as SAFE_PREFIXES, c as GO_DECL_RE, d as PY_MODEL_RE, f as SWIFT_PROTO_RE, g as ASK_WRITERS, h as bashWriteGuard, i as clearUserGuards, j as RALPH_SAFE, k as GIT_BLOCKED, l as JAVA_DECL_RE, m as interfaceSeparationGuard, n as FAIL_CLOSED, o as runGuards, p as TS_DECL_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as CODE_REDIRECT, w as protectedPathGuard, x as SESSION_STATE_FRAGMENT, y as FILE_REDIRECT } from "../evaluate-wDDbojx6.mjs";
4
4
  import "../policy-la_KkjCS.mjs";
@@ -1,6 +1,6 @@
1
1
  import { r as projectLayout } from "../layout-C0jaaCQC.mjs";
2
2
  import { a as sanitizeSessionId, c as sessionsDir, i as loadSessionState, n as fuseHarnessHome, o as saveSessionState, r as fusengineCache, s as sessionStatePath, t as claudeHome } from "../home-state-D0RLWP8J.mjs";
3
- import { $ as postEditTypescript, A as trackSkillRead, At as trackFile, B as isProject, C as seoPostToolUse, Ct as gitContext, D as postTrackingSideEffects, Dt as taskContext, E as securityAdvisory, Et as promptSubmitContext, F as dispatchLessons, Ft as securityStateDir, G as getFileDesc, H as loadEnriched, I as cartoSessionStart, It as securityStatePath, K as listChildren, L as generateEcosystemMap, Lt as todayUtc, M as dispatchLifecycle, Mt as isoUtc, N as aipilotPostToolUse, Nt as loadSecurityState, O as trackWatchResearch, Ot as defaultStateDir, P as dispatchAipilot, Pt as saveSecurityState, Q as lessonsStateFileFor, R as writePluginMap, S as postEditContext, St as devContext, T as dispatchMemory, Tt as claudeMdKey, U as mergeLines, V as writeTree, W as countFiles, X as lessonsArchiveFileFor, Z as lessonsFileFor, _ as preCommitGate, _t as sessionStartCore, a as recordActivity, at as validateTeammateOutput, b as extractSymbols, bt as removeOldFiles, c as MCP_TTL_MS, ct as validateTailwind, d as isMcpTool, dt as countLoc, et as trackSessionChanges, f as queryOf, ft as detectSolidProfile, g as gate, gt as runSessionStartCleanups, h as TRIVIAL_BUDGET, ht as readRules, i as respond, it as logToolFailure, j as trackEnrichment, jt as normalizeEvent, k as trackMcpResearch, kt as projectHash, l as WEBFETCH_TTL_MS, lt as validateSolidGate, m as REQUIRED_AGENTS, mt as injectRules, n as activityFor, nt as cleanupSession, o as mcpPostStore, ot as trackAgentMemory, p as DEFAULT_WINDOW_MS, pt as solidDetectStart, r as handlePre, rt as saveApexState, s as mcpPreIntercept, st as subagentCacheContext, t as handleHook, tt as validateRulesLoaded, u as cacheQueryOf, ut as checkFileSize, v as detectDuplication, vt as pruneEmptyDirs, w as seoPostToolUseResponse, wt as projectContext, x as lifecycleStdout, xt as trimLogFile, y as dryGate, yt as purgeTtlTree, z as generateProjectMap } from "../handle-C2-HU8PS.mjs";
3
+ import { $ as postEditTypescript, A as trackSkillRead, At as trackFile, B as isProject, C as seoPostToolUse, Ct as gitContext, D as postTrackingSideEffects, Dt as taskContext, E as securityAdvisory, Et as promptSubmitContext, F as dispatchLessons, Ft as securityStateDir, G as getFileDesc, H as loadEnriched, I as cartoSessionStart, It as securityStatePath, K as listChildren, L as generateEcosystemMap, Lt as todayUtc, M as dispatchLifecycle, Mt as isoUtc, N as aipilotPostToolUse, Nt as loadSecurityState, O as trackWatchResearch, Ot as defaultStateDir, P as dispatchAipilot, Pt as saveSecurityState, Q as lessonsStateFileFor, R as writePluginMap, S as postEditContext, St as devContext, T as dispatchMemory, Tt as claudeMdKey, U as mergeLines, V as writeTree, W as countFiles, X as lessonsArchiveFileFor, Z as lessonsFileFor, _ as preCommitGate, _t as sessionStartCore, a as recordActivity, at as validateTeammateOutput, b as extractSymbols, bt as removeOldFiles, c as MCP_TTL_MS, ct as validateTailwind, d as isMcpTool, dt as countLoc, et as trackSessionChanges, f as queryOf, ft as detectSolidProfile, g as gate, gt as runSessionStartCleanups, h as TRIVIAL_BUDGET, ht as readRules, i as respond, it as logToolFailure, j as trackEnrichment, jt as normalizeEvent, k as trackMcpResearch, kt as projectHash, l as WEBFETCH_TTL_MS, lt as validateSolidGate, m as REQUIRED_AGENTS, mt as injectRules, n as activityFor, nt as cleanupSession, o as mcpPostStore, ot as trackAgentMemory, p as DEFAULT_WINDOW_MS, pt as solidDetectStart, r as handlePre, rt as saveApexState, s as mcpPreIntercept, st as subagentCacheContext, t as handleHook, tt as validateRulesLoaded, u as cacheQueryOf, ut as checkFileSize, v as detectDuplication, vt as pruneEmptyDirs, w as seoPostToolUseResponse, wt as projectContext, x as lifecycleStdout, xt as trimLogFile, y as dryGate, yt as purgeTtlTree, z as generateProjectMap } from "../handle-DE-753Mr.mjs";
4
4
  //#region src/runtime/storage.ts
5
5
  /**
6
6
  * The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
@@ -1205,10 +1205,10 @@ function buildApexInstruction(projectType, maxLines) {
1205
1205
  const expertAgent = getExpertAgent(projectType);
1206
1206
  return `INSTRUCTION: This is a development task. Use APEX methodology:
1207
1207
 
1208
- **TRACKING FILE**: [project]/.claude/apex/task.json (created by the /apex command)
1208
+ **TRACKING FILE**: [project]/.claude/apex/task.json create it yourself via apex-methodology Step 0 (init-tracking) if missing
1209
1209
 
1210
1210
  1. **ANALYZE** (MANDATORY - 3 AGENTS IN PARALLEL):
1211
- - explore-codebase + research-expert + ${expertAgent} (framework expertise)\n - Project type detected: ${projectType}\n\n2. **PLAN**: Use TaskCreate to break down tasks (<${maxLines} lines per file)\n\n3. **EXECUTE**: ${expertAgent}, follow SOLID principles, split at ${maxLines - 10} lines\n\n4. **EXAMINE**: Run sniper agent after ANY modification\n\n**IMPORTANT**: Read .claude/apex/task.json to check documentation status before writing code.`;
1211
+ - explore-codebase + research-expert + ${expertAgent} (framework expertise)\n - Project type detected: ${projectType}\n\n2. **PLAN**: Use TaskCreate to break down tasks (<${maxLines} lines per file)\n\n3. **EXECUTE**: ${expertAgent}, follow SOLID principles, split at ${maxLines - 10} lines\n\n4. **eLICIT**: self-review with NAMED elicitation techniques (apex ref 03.5-elicit) — fix findings BEFORE validation\n\n5. **VERIFY**: functional check — run it, confirm references⇔declarations consistency\n\n6. **eXAMINE**: Run sniper agent after ANY modification\n\n**GATE**: eLicit + Verify BEFORE sniper — NEVER skip.\n\n**IMPORTANT**: Read .claude/apex/task.json to check documentation status before writing code.`;
1212
1212
  }
1213
1213
  /**
1214
1214
  * Build the UserPromptSubmit injection text: read `~/.claude/CLAUDE.md` and,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusengine/harness",
3
- "version": "0.1.62",
3
+ "version": "0.1.64",
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",
@@ -152,5 +152,8 @@
152
152
  "tsdown": "^0.22.3",
153
153
  "typedoc": "^0.28.19",
154
154
  "typescript": "^6.0.3"
155
+ },
156
+ "dependencies": {
157
+ "figures": "^6.1.0"
155
158
  }
156
159
  }