@fusengine/harness 0.1.77 → 0.1.79
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 +629 -1
- package/dist/{handle-BDlk2utY.mjs → handle-Dthtlp7Z.mjs} +73 -50
- package/dist/{index-DJw1OGwE.d.mts → index-BIGVNQB8.d.mts} +19 -11
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/policy/index.d.mts +1 -1
- package/dist/policy/index.mjs +1 -1
- package/dist/runtime/index.d.mts +19 -11
- package/dist/runtime/index.mjs +1 -1
- package/dist/{validate-DnLU4IHy.mjs → validate-DhOX5hDK.mjs} +76 -25
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
|
|
2
|
-
import { c as ttlLabel } from "./dotenv-Jj8aL1FL.mjs";
|
|
2
|
+
import { c as ttlLabel, t as HOME_DIR } from "./dotenv-Jj8aL1FL.mjs";
|
|
3
3
|
import { R as DEV_KEYWORDS, g as moduleAwarePath } from "./evaluate-ClfbCDiY.mjs";
|
|
4
4
|
import { d as countFrameworkCodeLines, l as PLUGINS_DIR, u as SOLID_REF } from "./home-state-BXf38Zi1.mjs";
|
|
5
5
|
import { r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-CWZegVdR.mjs";
|
|
@@ -1187,9 +1187,48 @@ function getExpertAgent(type, pluginsDirOverride) {
|
|
|
1187
1187
|
return "general-purpose";
|
|
1188
1188
|
}
|
|
1189
1189
|
//#endregion
|
|
1190
|
-
//#region src/policy/
|
|
1191
|
-
/**
|
|
1192
|
-
|
|
1190
|
+
//#region src/policy/apex-target.ts
|
|
1191
|
+
/**
|
|
1192
|
+
* Harness-target helpers for the APEX context builders. Single source of
|
|
1193
|
+
* truth for the home-dir segment / root doc name / plan-tool idiom that
|
|
1194
|
+
* differ between Claude Code and Codex (and beyond), so the builders in
|
|
1195
|
+
* `claude-md-context.ts`, `apex-task-context.ts`, and `inject-apex.ts` never
|
|
1196
|
+
* hardcode `.claude`/`CLAUDE.md`/`TaskCreate` again. Runtime `id` values flow
|
|
1197
|
+
* through the pipeline as plain `string` (see `handleHook(id: string, ...)`),
|
|
1198
|
+
* so these helpers accept `string` and narrow internally — same idiom as the
|
|
1199
|
+
* existing `HOME_DIR[id] ?? ".claude"` precedent in `cartographer/detect.ts`.
|
|
1200
|
+
*/
|
|
1201
|
+
/**
|
|
1202
|
+
* Home-dir segment for a harness target (".claude", ".codex", ...). Falls
|
|
1203
|
+
* back to ".claude" for any harness without a {@link HOME_DIR} entry.
|
|
1204
|
+
* @param id - Harness id (e.g. "claude-code", "codex").
|
|
1205
|
+
* @returns The home-dir segment, e.g. ".claude".
|
|
1206
|
+
*/
|
|
1207
|
+
function harnessHomeSegment(id) {
|
|
1208
|
+
return HOME_DIR[id] ?? ".claude";
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Root instructions doc name for a harness target: "AGENTS.md" for Codex,
|
|
1212
|
+
* "CLAUDE.md" for every other target (including the default/unknown fallback).
|
|
1213
|
+
* @param id - Harness id.
|
|
1214
|
+
* @returns The doc file name.
|
|
1215
|
+
*/
|
|
1216
|
+
function apexDocName(id) {
|
|
1217
|
+
return id === "codex" ? "AGENTS.md" : "CLAUDE.md";
|
|
1218
|
+
}
|
|
1219
|
+
/**
|
|
1220
|
+
* Native plan/track tool name for a harness target: Codex's `update_plan` vs
|
|
1221
|
+
* Claude's `TaskCreate`. Covers only the PLAN-step line — other Claude-only
|
|
1222
|
+
* tool references (`TaskList`, `TaskUpdate`) are branched inline by the
|
|
1223
|
+
* builders since their surrounding prose differs structurally, not just by token.
|
|
1224
|
+
* @param id - Harness id.
|
|
1225
|
+
* @returns The plan-tool name.
|
|
1226
|
+
*/
|
|
1227
|
+
function apexPlanTool(id) {
|
|
1228
|
+
return id === "codex" ? "update_plan" : "TaskCreate";
|
|
1229
|
+
}
|
|
1230
|
+
//#endregion
|
|
1231
|
+
//#region src/policy/detect-claude-md-project-type.ts
|
|
1193
1232
|
/**
|
|
1194
1233
|
* Detect the project type from the cwd, reproducing the legacy Python logic:
|
|
1195
1234
|
* package.json containing "next" → nextjs, else "react" → react; else
|
|
@@ -1212,31 +1251,35 @@ function detectClaudeMdProjectType(cwd) {
|
|
|
1212
1251
|
} catch {}
|
|
1213
1252
|
return "generic";
|
|
1214
1253
|
}
|
|
1254
|
+
//#endregion
|
|
1255
|
+
//#region src/policy/claude-md-context.ts
|
|
1256
|
+
/** Dev-verb regex (FR/EN) that triggers the APEX preamble (case-insensitive). */
|
|
1257
|
+
const DEV_VERBS = /(cr[ée]er|impl[ée]menter|ajouter|d[ée]velopper|construire|build|refactor|migrer|implement|create|add|develop)/i;
|
|
1215
1258
|
/**
|
|
1216
1259
|
* Build the APEX instruction preamble for a development task.
|
|
1217
1260
|
* @param projectType - Detected project type label.
|
|
1218
1261
|
* @param maxLines - SOLID per-file line ceiling.
|
|
1262
|
+
* @param id - Harness target id (defaults to "claude-code" — zero-regression default).
|
|
1219
1263
|
* @returns The APEX instruction text.
|
|
1220
1264
|
*/
|
|
1221
|
-
function buildApexInstruction(projectType, maxLines) {
|
|
1265
|
+
function buildApexInstruction(projectType, maxLines, id = "claude-code") {
|
|
1222
1266
|
const expertAgent = getExpertAgent(projectType);
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
**TRACKING FILE**: [project]/.claude/apex/task.json — create it yourself via apex-methodology Step 0 (init-tracking) if missing
|
|
1226
|
-
|
|
1227
|
-
1. **ANALYZE** (MANDATORY - 3 AGENTS IN PARALLEL):
|
|
1228
|
-
- 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.`;
|
|
1267
|
+
const seg = harnessHomeSegment(id);
|
|
1268
|
+
return `INSTRUCTION: This is a development task. Use APEX methodology:\n\n**TRACKING FILE**: [project]/${seg}/apex/task.json — create it yourself via apex-methodology Step 0 (init-tracking) if missing\n\n1. **ANALYZE** (MANDATORY - 3 AGENTS IN PARALLEL):\n - explore-codebase + research-expert + ${expertAgent} (framework expertise)\n - Project type detected: ${projectType}\n\n2. **PLAN**: Use ${apexPlanTool(id)} 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 ${seg}/apex/task.json to check documentation status before writing code.`;
|
|
1229
1269
|
}
|
|
1230
1270
|
/**
|
|
1231
|
-
* Build the UserPromptSubmit injection text: read
|
|
1271
|
+
* Build the UserPromptSubmit injection text: read the target's root
|
|
1272
|
+
* instructions doc (`~/.claude/CLAUDE.md`, `~/.codex/AGENTS.md`, ...) and,
|
|
1232
1273
|
* when the prompt matches a dev verb, prepend the APEX instruction. Returns
|
|
1233
|
-
* `null` when
|
|
1274
|
+
* `null` when the doc is absent/unreadable (the hook then emits nothing).
|
|
1234
1275
|
* @param prompt - The raw user prompt.
|
|
1235
1276
|
* @param cwd - Project root (for project-type detection).
|
|
1277
|
+
* @param id - Harness target id (defaults to "claude-code" — zero-regression default).
|
|
1236
1278
|
* @returns The injection text, or `null` to emit nothing.
|
|
1237
1279
|
*/
|
|
1238
|
-
function buildClaudeMdContext(prompt, cwd) {
|
|
1239
|
-
const
|
|
1280
|
+
function buildClaudeMdContext(prompt, cwd, id = "claude-code") {
|
|
1281
|
+
const docName = apexDocName(id);
|
|
1282
|
+
const claudeMd = join(homedir(), harnessHomeSegment(id), docName);
|
|
1240
1283
|
if (!existsSync(claudeMd)) return null;
|
|
1241
1284
|
let claudeContent;
|
|
1242
1285
|
try {
|
|
@@ -1244,8 +1287,8 @@ function buildClaudeMdContext(prompt, cwd) {
|
|
|
1244
1287
|
} catch {
|
|
1245
1288
|
return null;
|
|
1246
1289
|
}
|
|
1247
|
-
if (!DEV_VERBS.test(prompt) && !DEV_KEYWORDS.test(prompt)) return `#
|
|
1248
|
-
return `${buildApexInstruction(detectClaudeMdProjectType(cwd), resolveMaxLines())}\n\n#
|
|
1290
|
+
if (!DEV_VERBS.test(prompt) && !DEV_KEYWORDS.test(prompt)) return `# ${docName}\n${claudeContent}`;
|
|
1291
|
+
return `${buildApexInstruction(detectClaudeMdProjectType(cwd), resolveMaxLines(), id)}\n\n# ${docName}\n${claudeContent}`;
|
|
1249
1292
|
}
|
|
1250
1293
|
//#endregion
|
|
1251
1294
|
//#region src/policy/apex-task-context.ts
|
|
@@ -1282,21 +1325,29 @@ function loadApexTaskState(taskFile) {
|
|
|
1282
1325
|
* Build the APEX context string injected into a Task sub-agent prompt.
|
|
1283
1326
|
* @param state - The parsed task state.
|
|
1284
1327
|
* @param maxLines - SOLID per-file line ceiling.
|
|
1328
|
+
* @param id - Harness target id (defaults to "claude-code" — zero-regression default).
|
|
1285
1329
|
* @returns The injection text.
|
|
1286
1330
|
*/
|
|
1287
|
-
function buildApexTaskContext(state, maxLines) {
|
|
1288
|
-
|
|
1331
|
+
function buildApexTaskContext(state, maxLines, id = "claude-code") {
|
|
1332
|
+
const seg = harnessHomeSegment(id);
|
|
1333
|
+
const isCodex = id === "codex";
|
|
1334
|
+
const step3 = isCodex ? "update_plan → review the current plan" : "TaskList → see pending tasks";
|
|
1335
|
+
const step4 = isCodex ? "update_plan → mark the active step in_progress before starting" : "TaskUpdate(in_progress) → before starting";
|
|
1336
|
+
const step7 = isCodex ? "update_plan → mark the step completed when done" : "TaskUpdate(completed) → triggers auto-commit";
|
|
1337
|
+
return `⚠️ APEX MODE - Read ${seg}/apex/AGENTS.md for rules\n\nCurrent: Task #${state.id} - ${state.subject} (Phase: ${state.phase})\nDocs consulted: ${state.docs}\n\nAgent must:\n1. Read task.json → find last 3 completed tasks\n2. Read their notes in docs/ (task-{ID}-{subject}.md)\n3. ${step3}\n4. ${step4}\n5. Apply SOLID (files < ${maxLines} lines)\n6. Write notes to docs/task-{ID}-{subject}.md\n7. ${step7}`;
|
|
1289
1338
|
}
|
|
1290
1339
|
/**
|
|
1291
|
-
* Build the PreToolUse Task injection, gated on the existence of the
|
|
1292
|
-
* `.claude/apex
|
|
1340
|
+
* Build the PreToolUse Task injection, gated on the existence of the
|
|
1341
|
+
* project's target apex dir (`.claude/apex/`, `.codex/apex/`, ...). Returns
|
|
1342
|
+
* `null` when APEX is not active (no dir).
|
|
1293
1343
|
* @param projectRoot - `CLAUDE_PROJECT_DIR` or cwd.
|
|
1344
|
+
* @param id - Harness target id (defaults to "claude-code" — zero-regression default).
|
|
1294
1345
|
* @returns The injection text, or `null` to emit nothing.
|
|
1295
1346
|
*/
|
|
1296
|
-
function buildApexTaskInjection(projectRoot) {
|
|
1297
|
-
const apexDir = join(projectRoot,
|
|
1347
|
+
function buildApexTaskInjection(projectRoot, id = "claude-code") {
|
|
1348
|
+
const apexDir = join(projectRoot, harnessHomeSegment(id), "apex");
|
|
1298
1349
|
if (!existsSync(apexDir)) return null;
|
|
1299
|
-
return buildApexTaskContext(loadApexTaskState(join(apexDir, "task.json")), resolveMaxLines());
|
|
1350
|
+
return buildApexTaskContext(loadApexTaskState(join(apexDir, "task.json")), resolveMaxLines(), id);
|
|
1300
1351
|
}
|
|
1301
1352
|
//#endregion
|
|
1302
1353
|
//#region src/policy/cartographer/indicators.ts
|
|
@@ -1540,4 +1591,4 @@ function missingSeoElements(html) {
|
|
|
1540
1591
|
return missing;
|
|
1541
1592
|
}
|
|
1542
1593
|
//#endregion
|
|
1543
|
-
export {
|
|
1594
|
+
export { capVerbosity as A, usesTailwindUtilities as C, isExcludedSwiftPath as D, isExcludedJsPath as E, brainstormGate as F, docConsultedGate as I, evaluateApex as L, APEX_GATES as M, POST_AUTH_GATES as N, MAX_EXA_RESULTS as O, PRE_AUTH_GATES as P, freshnessGate as R, skillTriggerGate as S, frameworkSolidGate as T, harnessHomeSegment as _, firstHeading as a, parseField as b, EXCLUDE_DIRS as c, buildApexTaskInjection as d, loadApexTaskState as f, detectClaudeMdProjectType as g, buildClaudeMdContext as h, firstComment as i, detectCreationIntent as j, MAX_TOKENS as k, PROJECT_INDICATORS as l, buildApexInstruction as m, missingSeoElements as n, parseEnrichment as o, DEV_VERBS as p, descFromText as r, parseEntry as s, isHtmlLike as t, buildApexTaskContext as u, scanPlugin as v, SKILL_TRIGGERS as w, detectRequiredSkills as x, parseBodyDesc as y, solidReadGate as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusengine/harness",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.79",
|
|
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",
|