@fusengine/harness 0.1.66 → 0.1.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/bin.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { t as detectHarness } from "../harness-Cb9xR8dC.mjs";
|
|
|
4
4
|
import { t as claudeHome } from "../home-state-D0RLWP8J.mjs";
|
|
5
5
|
import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-BfJytXnW.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-
|
|
7
|
+
import { J as runningVersion, Lt as todayUtc, Y as versionBanner, q as runDoctor, t as handleHook } from "../handle-CU5UdAei.mjs";
|
|
8
8
|
import { p as readStdin$1 } from "../claude-Cu6rPxUZ.mjs";
|
|
9
9
|
import { delimiter, join } from "node:path";
|
|
10
10
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
@@ -7885,6 +7885,92 @@ function activityFor(event) {
|
|
|
7885
7885
|
return out;
|
|
7886
7886
|
}
|
|
7887
7887
|
//#endregion
|
|
7888
|
+
//#region src/freshness/codex-spawn-evidence.ts
|
|
7889
|
+
/**
|
|
7890
|
+
* Codex multi_agent_v2 `spawn_agent` -> session evidence bridge. Codex's custom
|
|
7891
|
+
* agents (fusengine multi_agent_v2, e.g. sniper/explore-codebase) are launched
|
|
7892
|
+
* via a `spawn_agent` TOOL CALL inside the SAME session -- Codex has no
|
|
7893
|
+
* SubagentStart/SubagentStop lifecycle for them, so the existing Claude-side
|
|
7894
|
+
* evidence paths (agent-evidence-record.ts `classifyAgentEvidence`, the
|
|
7895
|
+
* SubagentStop harvest) never observe them; the harness only ever saw a
|
|
7896
|
+
* generic tool call. This module credits the SAME session track
|
|
7897
|
+
* ({@link recordAgent}, read back by `agent-evidence-record.ts`
|
|
7898
|
+
* `agentsFreshInTrack`) straight from that PostToolUse `spawn_agent` call.
|
|
7899
|
+
*
|
|
7900
|
+
* SOURCE (openai/codex@44918ea1, tag rust-v0.144.1 -- verified upstream,
|
|
7901
|
+
* not re-checked here): the hook `tool_name` is `"spawn_agent"` normally, or
|
|
7902
|
+
* the SEPARATOR-LESS namespace-prefixed `{namespace}spawn_agent` when the
|
|
7903
|
+
* `namespace_tools` capability provider is active (e.g.
|
|
7904
|
+
* `"fusengine_agentsspawn_agent"`, `"collaborationspawn_agent"`). Detection is
|
|
7905
|
+
* `tool_name === "spawn_agent" || tool_name.endsWith("spawn_agent")` -- a tool
|
|
7906
|
+
* that merely CONTAINS the substring without being an exact/suffix match
|
|
7907
|
+
* (`"spawn_agentX"`, `"myspawn_agent_tool"`) is correctly rejected.
|
|
7908
|
+
* `tool_input.agent_type` carries the spawned agent's type only when Codex's
|
|
7909
|
+
* `hide_spawn_agent_metadata=false`; treat it as always-optional.
|
|
7910
|
+
*
|
|
7911
|
+
* INVARIANT (multi-harness parity): every entry point here is gated on
|
|
7912
|
+
* `id === "codex"` FIRST -- claude-code/cursor/cline/gemini-cli/hermes always
|
|
7913
|
+
* take the early return, touching neither the track nor disk. Byte-identical
|
|
7914
|
+
* elsewhere by construction.
|
|
7915
|
+
*/
|
|
7916
|
+
/**
|
|
7917
|
+
* True when `tool` is Codex's `spawn_agent` primitive, bare or
|
|
7918
|
+
* namespace-prefixed (no separator). Rejects any tool that merely contains
|
|
7919
|
+
* the substring elsewhere in its name.
|
|
7920
|
+
* @param tool - Raw/normalized `tool_name` from the hook payload.
|
|
7921
|
+
*/
|
|
7922
|
+
function isCodexSpawnAgentTool(tool) {
|
|
7923
|
+
return tool === "spawn_agent" || tool.endsWith("spawn_agent");
|
|
7924
|
+
}
|
|
7925
|
+
/**
|
|
7926
|
+
* Extract the spawned agent's type from a `spawn_agent` `tool_input`, or
|
|
7927
|
+
* `undefined` when absent/blank (`hide_spawn_agent_metadata=true`, or a
|
|
7928
|
+
* future Codex build omitting it) -- never throws.
|
|
7929
|
+
* @param input - Raw `tool_input` payload (harness `event.input`).
|
|
7930
|
+
*/
|
|
7931
|
+
function codexSpawnAgentType(input) {
|
|
7932
|
+
const v = input?.agent_type;
|
|
7933
|
+
return typeof v === "string" && v.trim() !== "" ? v.trim() : void 0;
|
|
7934
|
+
}
|
|
7935
|
+
/**
|
|
7936
|
+
* Pure classifier + folder: credit a Codex `spawn_agent` call into
|
|
7937
|
+
* `track.agents` under the SAME `subagent-<name>` convention the Claude-side
|
|
7938
|
+
* explore/research evidence uses -- so an `agent_type` that happens to match
|
|
7939
|
+
* a `REQUIRED_AGENTS` name (e.g. `"explore-codebase"`) is picked up by
|
|
7940
|
+
* `agentsFreshInTrack`'s substring match exactly like genuine Claude
|
|
7941
|
+
* Task/Agent evidence. Immutable: returns `track` UNCHANGED (same reference)
|
|
7942
|
+
* for any other harness `id`, any non-spawn tool, or a missing `agent_type`.
|
|
7943
|
+
* @param id - Harness id (only `"codex"` ever credits).
|
|
7944
|
+
* @param tool - Normalized event tool name (raw `tool_name`).
|
|
7945
|
+
* @param input - Raw `tool_input` payload.
|
|
7946
|
+
* @param track - The current session track.
|
|
7947
|
+
* @param ts - Epoch-ms timestamp of the tool call.
|
|
7948
|
+
* @returns The credited track, or `track` itself when nothing was credited.
|
|
7949
|
+
*/
|
|
7950
|
+
function creditCodexSpawnAgent(id, tool, input, track, ts) {
|
|
7951
|
+
if (id !== "codex" || !isCodexSpawnAgentTool(tool)) return track;
|
|
7952
|
+
const agentType = codexSpawnAgentType(input);
|
|
7953
|
+
if (!agentType) return track;
|
|
7954
|
+
return recordAgent(track, `subagent-${agentType}`, ts, "sufficient");
|
|
7955
|
+
}
|
|
7956
|
+
/**
|
|
7957
|
+
* I/O wiring for {@link creditCodexSpawnAgent}: load the session track, fold
|
|
7958
|
+
* in the credit, and persist only when something actually changed (skips a
|
|
7959
|
+
* write for the strict no-op cases). Mirrors `agent-evidence-record.ts`
|
|
7960
|
+
* `recordAgentEvidence`'s async load/save shape.
|
|
7961
|
+
* @param file - Session track file path (same one the freshness gate reads).
|
|
7962
|
+
* @param id - Harness id (only `"codex"` ever credits).
|
|
7963
|
+
* @param tool - Normalized event tool name (raw `tool_name`).
|
|
7964
|
+
* @param input - Raw `tool_input` payload.
|
|
7965
|
+
* @param ts - Epoch-ms timestamp of the tool call.
|
|
7966
|
+
*/
|
|
7967
|
+
async function recordCodexSpawnEvidence(file, id, tool, input, ts) {
|
|
7968
|
+
if (id !== "codex" || !isCodexSpawnAgentTool(tool)) return;
|
|
7969
|
+
const track = await loadTrack(file);
|
|
7970
|
+
const next = creditCodexSpawnAgent(id, tool, input, track, ts);
|
|
7971
|
+
if (next !== track) await saveTrack(file, next);
|
|
7972
|
+
}
|
|
7973
|
+
//#endregion
|
|
7888
7974
|
//#region src/runtime/handle-post.ts
|
|
7889
7975
|
/**
|
|
7890
7976
|
* Run the PostToolUse pipeline: store the MCP response, emit a design warning,
|
|
@@ -7909,6 +7995,7 @@ async function handlePost(ctx) {
|
|
|
7909
7995
|
for (const activity of activities) await recordActivity(file, activity);
|
|
7910
7996
|
const evidence = classifyAgentEvidence(event.tool, event.input, response);
|
|
7911
7997
|
if (evidence) await recordAgentEvidence(file, evidence, opts.now, typeof payload.agent_id === "string" ? payload.agent_id : void 0);
|
|
7998
|
+
await recordCodexSpawnEvidence(file, id, event.tool, event.input, opts.now);
|
|
7912
7999
|
if (event.tool === "Bash" && event.command) {
|
|
7913
8000
|
const r = payload.tool_result ?? response;
|
|
7914
8001
|
const out = `${typeof r?.stdout === "string" ? r.stdout : ""}\n${typeof r?.stderr === "string" ? r.stderr : ""}`;
|
package/dist/runtime/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as projectLayout } from "../layout-C0jaaCQC.mjs";
|
|
2
2
|
import { a as sanitizeSessionId, c as sessionsDir, i as loadSessionState, n as fuseHarnessHome, o as saveSessionState, r as fusengineCache, s as sessionStatePath, t as claudeHome } from "../home-state-D0RLWP8J.mjs";
|
|
3
|
-
import { $ 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-
|
|
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-CU5UdAei.mjs";
|
|
4
4
|
//#region src/runtime/storage.ts
|
|
5
5
|
/**
|
|
6
6
|
* The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusengine/harness",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.67",
|
|
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",
|