@fusengine/harness 0.1.91 → 0.1.92
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/cursor/index.mjs +1 -1
- package/dist/cli/bin.mjs +2 -2
- package/dist/{handle-C43gA-Pr.mjs → handle-BF1dZFjY.mjs} +542 -59
- package/dist/{normalize-BjG6unTj.mjs → normalize-Dy8g9Ybl.mjs} +83 -3
- package/dist/runtime/index.d.mts +10 -0
- package/dist/runtime/index.mjs +1 -1
- package/package.json +1 -1
- package/src/adapters/cursor/context-budget.ts +144 -0
- package/src/adapters/cursor/context-limit.ts +115 -0
- package/src/adapters/cursor/context.ts +21 -2
- package/src/adapters/cursor/interfaces/context-budget.ts +25 -0
- package/src/adapters/cursor/native-response.ts +10 -129
- package/src/adapters/cursor/native-schemas.ts +161 -0
- package/src/adapters/cursor/normalize.ts +65 -0
- package/src/adapters/cursor/plugin-root.ts +103 -0
- package/src/adapters/cursor/respond.ts +94 -47
- package/src/runtime/handle.ts +87 -6
- package/src/runtime/lifecycle/aipilot/dispatch-aipilot.ts +7 -1
- package/src/runtime/lifecycle/failure-lesson.ts +6 -2
- package/src/runtime/lifecycle/rules-root.ts +18 -2
|
@@ -90,7 +90,13 @@ export async function dispatchAipilot(event: string, payload: Record<string, unk
|
|
|
90
90
|
if (event === "SubagentStop") return onSubagentStop(payload, cwd, home, id);
|
|
91
91
|
// Stop too: Codex emits no SessionEnd, so its ai-pilot hooks.json wires Stop here as the sole analytics-flush trigger — reusing the SessionEnd handler verbatim (codex-plugins/docs/reference/hooks.md).
|
|
92
92
|
if (event === "SessionEnd" || event === "Stop") { await cacheAnalyticsSave(home, now); return ""; }
|
|
93
|
-
|
|
93
|
+
// "BeforeMCPExecution" is a Cursor-only lifecycle literal (produced solely
|
|
94
|
+
// by cursorEventContract in adapters/cursor/events.ts); asyncScopeStdout
|
|
95
|
+
// forwards every non-Cursor id's `hook_event_name` RAW and unvalidated, so
|
|
96
|
+
// gating on the literal alone would let a claude-code/codex payload that
|
|
97
|
+
// happens to carry this exact string reach docCacheGate — the guard must
|
|
98
|
+
// be structural (`id === "cursor"`), never event-name-only.
|
|
99
|
+
if (event === "PreToolUse" || (id === "cursor" && event === "BeforeMCPExecution")) return docCacheGate(payload, cwd, now, home, id);
|
|
94
100
|
return null;
|
|
95
101
|
}
|
|
96
102
|
|
|
@@ -5,8 +5,12 @@
|
|
|
5
5
|
* matches the failure message — reusing the PreToolUse {@link lessonFor} index and
|
|
6
6
|
* its cooldown (idempotent under the ~11-process fan-out). Fail-open throughout.
|
|
7
7
|
*
|
|
8
|
-
* Claude-Code-only
|
|
9
|
-
*
|
|
8
|
+
* Claude-Code-only in the sense that no equivalent `PostToolUseFailure` hook
|
|
9
|
+
* exists on Codex or Hermes — but Cursor's own `postToolUseFailure` DOES
|
|
10
|
+
* arrive here too, via `lifecycle-bridge.ts`'s `lifecycleStdout` translating
|
|
11
|
+
* the wire event name and forwarding to `dispatchLifecycle`'s
|
|
12
|
+
* `"PostToolUseFailure"` case (see `handle.ts`'s `cursorRawPayloadProjection`
|
|
13
|
+
* for how `data.tool_name` below arrives already canonicalized on Cursor).
|
|
10
14
|
* @packageDocumentation
|
|
11
15
|
*/
|
|
12
16
|
import { homedir } from "node:os";
|
|
@@ -2,8 +2,15 @@
|
|
|
2
2
|
* Dynamic rules-plugin root resolution. The historical `CLAUDE_PLUGIN_ROOT ??
|
|
3
3
|
* cwd` chain only worked when the harness exported the plugin root — Kimi
|
|
4
4
|
* injects `KIMI_PLUGIN_ROOT` instead, and a bare cwd fallback never held a
|
|
5
|
-
* `rules/` dir.
|
|
6
|
-
*
|
|
5
|
+
* `rules/` dir.
|
|
6
|
+
*
|
|
7
|
+
* `id === "cursor"` is resolved by a SEPARATE branch (`resolveCursorPluginRoot`)
|
|
8
|
+
* before any of the below, because Cursor's env contract differs from the
|
|
9
|
+
* other harnesses (see `../../adapters/cursor/plugin-root.ts`) — it is never
|
|
10
|
+
* folded into the shared switch. For every other id, resolution order (first
|
|
11
|
+
* hit wins, unchanged):
|
|
12
|
+
* 1. `CLAUDE_PLUGIN_ROOT` (read for ALL non-cursor ids, historical quirk —
|
|
13
|
+
* frozen by non-regression tests, do not "fix" without an explicit ask);
|
|
7
14
|
* 2. `KIMI_PLUGIN_ROOT` (kimi plugin-declared hooks);
|
|
8
15
|
* 3. Per-harness install probe (claude marketplace, codex versioned cache,
|
|
9
16
|
* kimi managed plugins) — first `<plugin>/rules` dir whose plugin folder
|
|
@@ -14,6 +21,7 @@ import { existsSync, readdirSync } from "node:fs";
|
|
|
14
21
|
import { homedir } from "node:os";
|
|
15
22
|
import { join } from "node:path";
|
|
16
23
|
import { maxSemver } from "../../util/semver";
|
|
24
|
+
import { resolveCursorPluginRoot } from "../../adapters/cursor/plugin-root";
|
|
17
25
|
|
|
18
26
|
/** Immediate child dir names of `dir`, or [] when unreadable. */
|
|
19
27
|
function children(dir: string): string[] {
|
|
@@ -72,6 +80,14 @@ export function resolveRulesRoot(
|
|
|
72
80
|
cwd: string,
|
|
73
81
|
env: Record<string, string | undefined> = process.env,
|
|
74
82
|
): string {
|
|
83
|
+
if (id === "cursor") {
|
|
84
|
+
const result = resolveCursorPluginRoot(env, cwd);
|
|
85
|
+
if (result.root) return result.root;
|
|
86
|
+
process.stderr.write(
|
|
87
|
+
`[fuse-harness] cursor: no plugin root proven (checked: ${result.checked.join("; ")}); rules root falls back to ${cwd}\n`,
|
|
88
|
+
);
|
|
89
|
+
return cwd;
|
|
90
|
+
}
|
|
75
91
|
if (env.CLAUDE_PLUGIN_ROOT) return env.CLAUDE_PLUGIN_ROOT;
|
|
76
92
|
if (env.KIMI_PLUGIN_ROOT) return env.KIMI_PLUGIN_ROOT;
|
|
77
93
|
const home = env.HOME ?? homedir();
|