@fusengine/harness 0.1.79 → 0.1.80

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/README.md CHANGED
@@ -130,6 +130,7 @@ also works elsewhere.
130
130
  | **gemini-cli** | `BeforeTool` denies via `{decision:"deny",reason}` (`gemini/index.ts:22-36`) | none | Thin stateless adapter — no session track, no APEX gates wired through it. |
131
131
  | **cline** | `PreToolUse` only; block → `{cancel:true}`, non-block → `contextModification` (`cline/index.ts:24-36`) | none | Same as gemini-cli: stateless guard only. |
132
132
  | **hermes** | `pre_tool_call` proven: reuses the Claude stdin reader, blocks via `{decision:"block",reason}` (`hermes/index.ts:12-36`) | untested — no lifecycle dispatch wired for Hermes in this repo | `ask`/`inform` degrade to non-blocking `{context}` — Hermes "has no interactive ask state" (`hermes/index.ts:27-28`). |
133
+ | **kimi** | `PreToolUse` denies via the camelCase JSON channel `{"hookSpecificOutput":{"permissionDecision":"deny","permissionDecisionReason":"…"}}` on stdout at **exit 0** (verified live against kimi-code v0.27.0 — exit 2 with stderr = reason also blocks, but is not required) — only `deny` is documented. `ask` is **downgraded to deny** prefixed `[downgraded from ask — Kimi Code has no interactive approval]`; `inform` rides plain stdout text at exit 0, never wrapped in JSON. Blocking events: `UserPromptSubmit`, `PreToolUse`, `Stop` (`kimi/index.ts`). | Observation only: `PostToolUse`, `PostToolUseFailure`, `PermissionRequest`, `PermissionResult`, `SessionStart`, `SessionEnd`, `SubagentStart`, `SubagentStop`, `StopFailure`, `Interrupt`, `PreCompact`, `PostCompact`, `Notification` — Kimi delivers them but **ignores any response**, so no verdict can be returned from them. | A **hook** cannot request approval — Kimi's `ask` lives in a parallel, hook-unreachable system (`[[permission.rules]] decision = "ask"` in `config.toml`), hence the ask→deny downgrade. Hooks are configured **only** in the global `~/.kimi-code/config.toml` (no project-local hooks file), so `harness init` writes no kimi wiring — copy the TOML snippet from [docs/adapters.md](docs/adapters.md#kimi-code--manual-wiring), and emit **no field** beyond `event`/`matcher`/`command`/`timeout` or the whole config fails to load. **Fail-open by design**: any exit code other than 0/2, a timeout, or a crash lets the call through. Stdin payload is snake_case and carries only `hook_event_name`, `session_id`, `cwd`, `tool_name`, `tool_input.command` and an undocumented `tool_call_id` (unused here) — no `transcript_path`, no `permission_mode`, no `tool_response`. Verified live against kimi-code v0.27.0 for `PreToolUse`/`Bash`; validate hand-written config with `kimi doctor`. Instructions file is `AGENTS.md`, not `CLAUDE.md`. |
133
134
 
134
135
  ## What it enforces
135
136
 
@@ -191,6 +192,14 @@ Features shipped since 0.1.44, each with its own test:
191
192
  version + drift vs. npm, `.claude/BOARD.md`, and the one-shot summary, each
192
193
  collector isolated so one failure can't blank the rest
193
194
  (`src/runtime/lifecycle/snapshot/index.ts`, `test/snapshot.test.ts`).
195
+ - **Target-aware root-doc injection** — `SessionStart` and `UserPromptSubmit`
196
+ inject the target's own root instructions doc, not a hardcoded `CLAUDE.md`:
197
+ `apexDocName(id)` + `harnessHomeSegment(id)` (`src/policy/apex-target.ts`)
198
+ resolve `AGENTS.md` under `.codex`/`.kimi-code` for Codex/Kimi, `CLAUDE.md`
199
+ under `.claude` for every other target (byte-identical to the pre-target-aware
200
+ default). The `systemMessage` label follows suit (`"AGENTS.md injected"`
201
+ under Codex/Kimi) (`src/runtime/lifecycle/session-start.ts`,
202
+ `src/runtime/inject-context.ts`).
194
203
  - **Injection budget cap** — harness-produced context fragments (lessons,
195
204
  snapshot, APEX task context) are capped at ~8000 chars each; owner-authored
196
205
  content (CLAUDE.md/rules) is never capped
@@ -202,7 +211,11 @@ Features shipped since 0.1.44, each with its own test:
202
211
  carrying `tool_input.agent_type` is recorded as `subagent-<agent_type>` in the
203
212
  same SessionTrack as Claude Task evidence, so a Codex explore-codebase/sniper
204
213
  satisfies the APEX freshness gates exactly like a Claude subagent
205
- (`src/tracking/session-state.ts`, sim scenario 32b).
214
+ (`src/tracking/session-state.ts`, sim scenario 32b). Recognized
215
+ agent-launcher tools across targets: `Task` (Claude), `Agent`/`AgentSwarm`
216
+ (Kimi Code) — each credits its `subagent_type`/`agent_type` toward the same
217
+ freshness evidence (`src/runtime/activity.ts`,
218
+ `src/freshness/agent-evidence-record.ts`).
206
219
  - **File-size gate judges the real Edit outcome, not the on-disk count** — an
207
220
  Edit on a file already over `FUSE_SOLID_MAX_LINES` used to be denied
208
221
  unconditionally (the on-disk count always won); the gate now computes the
@@ -0,0 +1,79 @@
1
+ import { t as Prompt } from "../../types-DVbIl9md.mjs";
2
+
3
+ //#region src/adapters/kimi/interfaces/types.d.ts
4
+ /**
5
+ * Kimi Code CLI shell-hook wire types. Verified 2026 against
6
+ * kimi.com/code/docs/en/kimi-code-cli/customization/hooks.html (v0.27.0):
7
+ * hooks are configured in `~/.kimi-code/config.toml` under `[[hooks]]`,
8
+ * receive a snake_case JSON payload on stdin, and answer with a camelCase
9
+ * JSON envelope on stdout (a real, documented casing inconsistency).
10
+ */
11
+ /**
12
+ * `PreToolUse`/`UserPromptSubmit`/`Stop` stdin payload (subset). Same base
13
+ * wire shape as Claude Code (`hook_event_name`/`tool_name`/`tool_input`/
14
+ * `cwd`); `tool_input.command` is confirmed for `Bash` by the docs' example
15
+ * script (`payload.tool_input?.command`). Verified live against kimi-code
16
+ * v0.27.0 on `PreToolUse`/`Bash`: `tool_name` is present at top level (the
17
+ * docs never name it as a stdin key) and `tool_input.command` carries the
18
+ * shell string. The live payload also carries an UNDOCUMENTED `tool_call_id`
19
+ * (e.g. `"tool_LsTnl0gBxM62XuWvKw0GFGHs"`); the harness does not consume it,
20
+ * so it is deliberately absent from this interface. `cwd` is the
21
+ * symlink-resolved path (macOS: `/private/tmp/…` for a shell in `/tmp/…`).
22
+ */
23
+ interface KimiHookInput {
24
+ hook_event_name?: string;
25
+ tool_name?: string;
26
+ /**
27
+ * Verified against the official tool reference (`docs/en/reference/tools.md`,
28
+ * moonshotai/kimi-code) AND live against kimi-code v0.27.0: `Write` sends
29
+ * `{ path, content, mode? }`, `Edit` sends
30
+ * `{ path, old_string, new_string, replace_all? }` — the path key is `path`,
31
+ * NOT Claude's `file_path`. `file_path` is kept as a tolerated alias (read
32
+ * second) for Claude-shaped replay payloads, mirroring
33
+ * `runtime/normalize.ts` which resolves both on the CLI path.
34
+ */
35
+ tool_input?: {
36
+ path?: string;
37
+ file_path?: string;
38
+ content?: string;
39
+ new_string?: string;
40
+ command?: string | string[];
41
+ };
42
+ session_id?: string;
43
+ cwd?: string;
44
+ }
45
+ /**
46
+ * Hook stdout response. Only `"deny"` is documented for `permissionDecision`
47
+ * — no `"ask"`/`"allow"` value, and no `additionalContext` field exists on
48
+ * this envelope. Blocking events are `UserPromptSubmit`, `PreToolUse`, and
49
+ * `Stop` only; every other event's return value is ignored.
50
+ */
51
+ interface KimiResponse {
52
+ hookSpecificOutput?: {
53
+ permissionDecision?: "deny";
54
+ permissionDecisionReason?: string;
55
+ };
56
+ }
57
+ //#endregion
58
+ //#region src/adapters/kimi/index.d.ts
59
+ /** Read & parse the Kimi hook stdin payload (same wire shape as Claude for the fields we consume). */
60
+ declare function readKimiInput(): Promise<KimiHookInput>;
61
+ /**
62
+ * Render a portable {@link Prompt} as a Kimi hook response string:
63
+ * `block`/`ask` -> `{hookSpecificOutput:{permissionDecision:"deny",...}}`
64
+ * (only `"deny"` is documented; `ask` is downgraded with {@link ASK_PREFIX});
65
+ * `inform` -> raw text (Kimi appends stdout to context on exit 0 — no
66
+ * documented JSON envelope for non-blocking context injection).
67
+ * @param prompt - The portable policy prompt.
68
+ * @returns The native Kimi response string.
69
+ */
70
+ declare function toKimiResponse(prompt: Prompt): string;
71
+ /**
72
+ * Run the bundled policy over a Kimi hook payload and return the native
73
+ * response string, or null to allow (the hook then exits 0 with empty stdout).
74
+ * @param input - Parsed hook stdin payload.
75
+ * @returns Native response string, or null when the tool use is allowed.
76
+ */
77
+ declare function guard(input: KimiHookInput): string | null;
78
+ //#endregion
79
+ export { type KimiHookInput, type KimiResponse, guard, readKimiInput, toKimiResponse };
@@ -0,0 +1,2 @@
1
+ import { n as readKimiInput, r as toKimiResponse, t as guard } from "../../kimi-C7FGprQz.mjs";
2
+ export { guard, readKimiInput, toKimiResponse };
package/dist/cli/bin.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { r as loadDotenv, s as resolveTtlSec } from "../dotenv-Jj8aL1FL.mjs";
3
- import { t as detectHarness } from "../harness-Cb9xR8dC.mjs";
2
+ import { r as loadDotenv, s as resolveTtlSec } from "../dotenv-B26N_uGr.mjs";
3
+ import { t as detectHarness } from "../harness-BMuLJ9lm.mjs";
4
4
  import { t as claudeHome } from "../home-state-BXf38Zi1.mjs";
5
5
  import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-3tyTW9Ud.mjs";
6
6
  import { n as writeInitFile, t as initFor } from "../run-Do2JltgU.mjs";
7
- import { $ as runningVersion, Q as runDoctor, Z as notify, et as versionBanner, t as handleHook, zt as todayUtc } from "../handle-Dthtlp7Z.mjs";
7
+ import { $ as runningVersion, Q as runDoctor, Z as notify, et as versionBanner, t as handleHook, zt as todayUtc } from "../handle-B7YufFz9.mjs";
8
8
  import { p as readStdin$1 } from "../claude-51RSspJ1.mjs";
9
9
  import { delimiter, join } from "node:path";
10
10
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
@@ -1032,7 +1032,7 @@ function maybePlaySound(argv) {
1032
1032
  * harness changelog fetch + diff the Claude Code changelog, print a JSON summary (changelog-watcher)
1033
1033
  * harness codex-rules generate a Codex execpolicy .rules (Starlark) file from security.ts; stdout or --out <path>
1034
1034
  */
1035
- const hookDebug = process.env.FUSE_HARNESS_DEBUG === "1";
1035
+ const hookDebug = process.env.FUSE_HARNESS_DEBUG === "1" && process.env.CI === "true";
1036
1036
  function traceHook(label, data) {
1037
1037
  if (hookDebug) process.stderr.write(`[hook-debug] ${label}: ${typeof data === "string" ? data : JSON.stringify(data)}\n`);
1038
1038
  }
@@ -1,2 +1,2 @@
1
- import { _ as parseEnvInt, a as ProjectLayout, c as projectLayout, d as resolveMaxLines, f as splitTarget, g as ttlLabel, h as resolveTtlSec, i as parseEnvFile, l as DEFAULT_MAX_LINES, m as TTL_ENV_KEY, n as envCandidates, o as STATE_GITIGNORE, p as DEFAULT_TTL_SEC, r as loadDotenv, s as STATE_ROOT, t as HOME_DIR, u as MAX_LINES_ENV_KEY } from "../index-jj_EzZRv.mjs";
1
+ import { _ as parseEnvInt, a as ProjectLayout, c as projectLayout, d as resolveMaxLines, f as splitTarget, g as ttlLabel, h as resolveTtlSec, i as parseEnvFile, l as DEFAULT_MAX_LINES, m as TTL_ENV_KEY, n as envCandidates, o as STATE_GITIGNORE, p as DEFAULT_TTL_SEC, r as loadDotenv, s as STATE_ROOT, t as HOME_DIR, u as MAX_LINES_ENV_KEY } from "../index-B_VHbsaJ.mjs";
2
2
  export { DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, HOME_DIR, MAX_LINES_ENV_KEY, ProjectLayout, STATE_GITIGNORE, STATE_ROOT, TTL_ENV_KEY, envCandidates, loadDotenv, parseEnvFile, parseEnvInt, projectLayout, resolveMaxLines, resolveTtlSec, splitTarget, ttlLabel };
@@ -1,5 +1,5 @@
1
1
  import { a as parseEnvInt, i as splitTarget, n as MAX_LINES_ENV_KEY, r as resolveMaxLines, t as DEFAULT_MAX_LINES } from "../limits-CHn8AIL1.mjs";
2
- import { a as DEFAULT_TTL_SEC, c as ttlLabel, i as parseEnvFile, n as envCandidates, o as TTL_ENV_KEY, r as loadDotenv, s as resolveTtlSec, t as HOME_DIR } from "../dotenv-Jj8aL1FL.mjs";
2
+ import { a as DEFAULT_TTL_SEC, c as ttlLabel, i as parseEnvFile, n as envCandidates, o as TTL_ENV_KEY, r as loadDotenv, s as resolveTtlSec, t as HOME_DIR } from "../dotenv-B26N_uGr.mjs";
3
3
  import { n as STATE_ROOT, r as projectLayout, t as STATE_GITIGNORE } from "../layout-C0jaaCQC.mjs";
4
4
  import "../config-la_KkjCS.mjs";
5
5
  export { DEFAULT_MAX_LINES, DEFAULT_TTL_SEC, HOME_DIR, MAX_LINES_ENV_KEY, STATE_GITIGNORE, STATE_ROOT, TTL_ENV_KEY, envCandidates, loadDotenv, parseEnvFile, parseEnvInt, projectLayout, resolveMaxLines, resolveTtlSec, splitTarget, ttlLabel };
@@ -1,2 +1,2 @@
1
- import { a as HarnessInfo, i as HarnessId, n as detectMode, o as HarnessMode, r as modeFor, s as HarnessVia, t as detectHarness } from "../harness-s1Fce_dL.mjs";
1
+ import { a as HarnessInfo, i as HarnessId, n as detectMode, o as HarnessMode, r as modeFor, s as HarnessVia, t as detectHarness } from "../harness-BQ5_Wnva.mjs";
2
2
  export { type HarnessId, type HarnessInfo, type HarnessMode, type HarnessVia, detectHarness, detectMode, modeFor };
@@ -1,3 +1,3 @@
1
- import { n as detectMode, r as modeFor, t as detectHarness } from "../harness-Cb9xR8dC.mjs";
1
+ import { n as detectMode, r as modeFor, t as detectHarness } from "../harness-BMuLJ9lm.mjs";
2
2
  import "../detect-la_KkjCS.mjs";
3
3
  export { detectHarness, detectMode, modeFor };
@@ -42,7 +42,8 @@ const HOME_DIR = {
42
42
  cline: ".clinerules",
43
43
  "gemini-cli": ".gemini",
44
44
  opencode: ".opencode",
45
- hermes: ".hermes"
45
+ hermes: ".hermes",
46
+ kimi: ".kimi-code"
46
47
  };
47
48
  /** Parse a `.env` file into a key→value map (`export KEY="v"` or `KEY=v`). */
48
49
  function parseEnvFile(path) {
@@ -1,21 +1,22 @@
1
1
  import { a as parseEnvInt, i as splitTarget, r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
2
- import { s as resolveTtlSec } from "./dotenv-Jj8aL1FL.mjs";
2
+ import { s as resolveTtlSec } from "./dotenv-B26N_uGr.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
5
  import { B as detectProjectType$1, H as requiredArchSkill, L as detectFramework, n as FAIL_CLOSED, t as evaluate, z as detectModularArchitecture } from "./evaluate-ClfbCDiY.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-BXf38Zi1.mjs";
7
7
  import { a as writeJsonFile, i as readJsonFile, r as hashText, t as atomicWrite } from "./json-io-DisYd2fb.mjs";
8
8
  import { r as isDocConsulted } from "./doc-helpers-CWZegVdR.mjs";
9
- import { A as capVerbosity, C as usesTailwindUtilities, D as isExcludedSwiftPath, E as isExcludedJsPath, I as docConsultedGate, L as evaluateApex, N as POST_AUTH_GATES, P as PRE_AUTH_GATES, S as skillTriggerGate, T as frameworkSolidGate, _ as harnessHomeSegment, b as parseField, c as EXCLUDE_DIRS$1, d as buildApexTaskInjection, h as buildClaudeMdContext, j as detectCreationIntent, l as PROJECT_INDICATORS, n as missingSeoElements, o as parseEnrichment, r as descFromText, s as parseEntry, t as isHtmlLike, v as scanPlugin } from "./validate-DhOX5hDK.mjs";
10
- import { n as findMarketplacePlugins, r as readPluginMeta, t as resolveSkillPath } from "./skill-path-BO2N0XvB.mjs";
9
+ import { D as frameworkSolidGate, F as POST_AUTH_GATES, I as PRE_AUTH_GATES, M as capVerbosity, N as detectCreationIntent, O as isExcludedJsPath, R as docConsultedGate, S as parseField, T as usesTailwindUtilities, b as scanPlugin, c as EXCLUDE_DIRS$1, d as buildApexTaskInjection, g as buildClaudeMdContext, k as isExcludedSwiftPath, l as PROJECT_INDICATORS, n as missingSeoElements, o as parseEnrichment, p as apexAgentSteps, r as descFromText, s as parseEntry, t as isHtmlLike, v as apexDocName, w as skillTriggerGate, y as harnessHomeSegment, z as evaluateApex } from "./validate-CkmquRDV.mjs";
10
+ import { n as findMarketplacePlugins, r as readPluginMeta, t as resolveSkillPath } from "./skill-path-CDvR4bbF.mjs";
11
11
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
12
12
  import { a as nowStamp, l as throttleMs, n as readRoots, o as readState, s as setStateField, t as addRoot } from "./registry-CymilZiZ.mjs";
13
13
  import { d as loadIndex, i as cacheLookupMeta, n as webfetchCacheWrite, o as cacheLookupSubstringMeta, t as mcpCacheWrite, u as extractText } from "./mcp-store-BkBDmuxN.mjs";
14
14
  import { t as loadRefs } from "./loader-AGz4nK7d.mjs";
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-Bcn08y9m.mjs";
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-nDZ3eLBQ.mjs";
16
16
  import { n as parseApplyPatch, t as isBypassPermissions } from "./permission-mode-BN3MNgbm.mjs";
17
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-51RSspJ1.mjs";
18
18
  import { r as toHermesResponse } from "./hermes-rTmVdhUL.mjs";
19
+ import { r as toKimiResponse } from "./kimi-C7FGprQz.mjs";
19
20
  import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
20
21
  import { appendFileSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, rmdirSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
21
22
  import { homedir } from "node:os";
@@ -598,7 +599,7 @@ function promptSubmitContext(prompt, cwd, id = "claude-code") {
598
599
  const ctx = buildClaudeMdContext(prompt, cwd, id);
599
600
  if (!ctx) return "";
600
601
  if (!oncePerWindow(claudeMdKey(prompt, ctx), 3e3)) return "";
601
- return attachSystemMessage(contextResponse("UserPromptSubmit", ctx), "CLAUDE.md injected");
602
+ return attachSystemMessage(contextResponse("UserPromptSubmit", ctx), `${apexDocName(id)} injected`);
602
603
  }
603
604
  /**
604
605
  * PreToolUse Task context injection: render the APEX sub-agent context as a
@@ -738,9 +739,15 @@ const PURGEABLE = {
738
739
  doc: 48 * 3600,
739
740
  explore: 48 * 3600
740
741
  };
741
- /** Read `~/.claude/CLAUDE.md`, or "" when missing/unreadable. */
742
- function claudeMd(home) {
743
- const path = join(claudeHome(home), "CLAUDE.md");
742
+ /**
743
+ * Read the target's root instructions doc (`~/.claude/CLAUDE.md`,
744
+ * `~/.codex/AGENTS.md`, `~/.kimi-code/AGENTS.md`, ...), or "" when
745
+ * missing/unreadable.
746
+ * @param home - Home dir.
747
+ * @param id - Harness target id (defaults to "claude-code" — zero-regression default).
748
+ */
749
+ function claudeMd(home, id = "claude-code") {
750
+ const path = join(home, harnessHomeSegment(id), apexDocName(id));
744
751
  try {
745
752
  return existsSync(path) ? readFileSync(path, "utf-8") : "";
746
753
  } catch {
@@ -765,14 +772,15 @@ function runSessionStartCleanups(home = homedir(), now = Date.now()) {
765
772
  * @param cwd - Project root for dev-context detection.
766
773
  * @param home - Home dir (defaults to `~`).
767
774
  * @param now - Clock for TTL cleanup (defaults to `Date.now()`).
775
+ * @param id - Harness target id (defaults to "claude-code" — zero-regression default).
768
776
  * @returns The native hook stdout (possibly empty).
769
777
  */
770
- function sessionStartCore(cwd, home = homedir(), now = Date.now()) {
771
- const md = claudeMd(home);
778
+ function sessionStartCore(cwd, home = homedir(), now = Date.now(), id = "claude-code") {
779
+ const md = claudeMd(home, id);
772
780
  const dev = devContext(cwd);
773
781
  runSessionStartCleanups(home, now);
774
782
  const ctx = [md, dev].filter(Boolean).join("\n");
775
- return ctx ? attachSystemMessage(contextResponse("SessionStart", ctx), "CLAUDE.md injected") : "";
783
+ return ctx ? attachSystemMessage(contextResponse("SessionStart", ctx), `${apexDocName(id)} injected`) : "";
776
784
  }
777
785
  //#endregion
778
786
  //#region src/runtime/lifecycle/inject-rules.ts
@@ -1724,6 +1732,7 @@ const RESEARCH_TOOLS = /* @__PURE__ */ new Set([
1724
1732
  "mcp__exa__deep_researcher_start",
1725
1733
  "WebSearch",
1726
1734
  "WebFetch",
1735
+ "FetchURL",
1727
1736
  "mcp__fuse-browser__browser_fetch",
1728
1737
  "mcp__fuse-browser__browser_fetch_batch",
1729
1738
  "mcp__fuse-browser__browser_crawl",
@@ -1808,8 +1817,17 @@ function classifyExplore(tool, input) {
1808
1817
  * session track the freshness gate scans FIRST — sidechain research and
1809
1818
  * Workflow-spawned agents count, unlike the lead-transcript scan.
1810
1819
  */
1811
- /** Tools the existing Task tracking already credits as agent LAUNCHES. */
1812
- const AGENT_LAUNCH_TOOLS = /* @__PURE__ */ new Set(["Task", "Agent"]);
1820
+ /**
1821
+ * Tools the existing Task tracking already credits as agent LAUNCHES.
1822
+ * `AgentSwarm` is Kimi Code's batch launcher (`prompt_template` + `items`,
1823
+ * one `subagent_type` applied to every spawned sub-agent) — same launch
1824
+ * semantics as `Task`/`Agent`, so it is excluded here too (anti-double-count).
1825
+ */
1826
+ const AGENT_LAUNCH_TOOLS = /* @__PURE__ */ new Set([
1827
+ "Task",
1828
+ "Agent",
1829
+ "AgentSwarm"
1830
+ ]);
1813
1831
  /**
1814
1832
  * `JSON.stringify` length of the raw `tool_response` OBJECT (parity Python
1815
1833
  * `len(str(tool_response))`); 0 when absent or unserializable (circular).
@@ -4095,9 +4113,7 @@ async function injectApexSubagentContext(cwd, home = homedir(), id = "claude-cod
4095
4113
  const taskData = await readJsonFile(join(apexDir, "task.json"));
4096
4114
  const completed = taskData ? completedTasks(taskData.tasks) : "none";
4097
4115
  const pending = taskData ? pendingTasks(taskData.tasks) : "none";
4098
- const isCodex = id === "codex";
4099
- const beforeStart = isCodex ? "Use update_plan → mark the active step in_progress before starting" : "Use TaskUpdate(taskId, status: in_progress) before starting";
4100
- const whenDone = isCodex ? "update_plan → mark the step completed when done" : "TaskUpdate(taskId, status: completed) triggers auto-commit";
4116
+ const { beforeStart, whenDone } = apexAgentSteps(id);
4101
4117
  return contextResponse("SubagentStart", capFragment("apex-subagent", `## APEX Sub-Agent Instructions
4102
4118
 
4103
4119
  You are a sub-agent in APEX workflow. Follow these rules:
@@ -5325,7 +5341,7 @@ function sessionStart(input) {
5325
5341
  if (input.scope === "rules") return injectRules(process.env.CLAUDE_PLUGIN_ROOT ?? input.cwd, input.event);
5326
5342
  if (input.scope === "carto") return cartoSessionStart(input.cwd, input.now);
5327
5343
  if (input.scope === "lessons") return dispatchLessons("SessionStart", input.payload, input.cwd, input.now);
5328
- const core = sessionStartCore(input.cwd, void 0, input.now);
5344
+ const core = sessionStartCore(input.cwd, void 0, input.now, input.id ?? "claude-code");
5329
5345
  return input.scope === "core" ? withSnapshot(core, input.cwd, import.meta.url) : core;
5330
5346
  }
5331
5347
  /**
@@ -7071,13 +7087,13 @@ const MCP_TTL_MS = parseEnvInt(process.env.FUSE_MCP_TTL_SEC, MCP_TTL_DEFAULT_SEC
7071
7087
  const WEBFETCH_TTL_MS = parseEnvInt(process.env.FUSE_WEBFETCH_TTL_SEC, WEBFETCH_TTL_DEFAULT_SEC) * 1e3;
7072
7088
  /** WebFetch prompt slice folded into its cache key (parity with Python prompt[:500]). */
7073
7089
  const PROMPT_TRUNC = 500;
7074
- /** True for the WebFetch tool (exact name). */
7090
+ /** True for the WebFetch tool (exact name) or Kimi Code CLI's `FetchURL` equivalent. */
7075
7091
  function isWebFetch(tool) {
7076
- return tool === "WebFetch";
7092
+ return tool === "WebFetch" || tool === "FetchURL";
7077
7093
  }
7078
- /** MCP doc tools + WebFetch whose calls are cached / verbosity-capped. */
7094
+ /** MCP doc tools + WebFetch/FetchURL whose calls are cached / verbosity-capped. */
7079
7095
  function isMcpTool(tool) {
7080
- return /context7|exa|webfetch|web_fetch/i.test(tool) || tool === "WebFetch";
7096
+ return /context7|exa|webfetch|web_fetch/i.test(tool) || isWebFetch(tool);
7081
7097
  }
7082
7098
  /** The query/url that keys the cache. */
7083
7099
  function queryOf(input) {
@@ -7195,6 +7211,12 @@ async function recordActivity(file, activity) {
7195
7211
  * - hermes: delegated to the adapter's `toHermesResponse` — `block` ->
7196
7212
  * `{decision:"block",reason}`; `ask`/`inform` degrade to non-blocking
7197
7213
  * `{context}` (Hermes has no interactive "ask" state).
7214
+ * - kimi: delegated to the adapter's `toKimiResponse` — `block`/`ask` ->
7215
+ * `hookSpecificOutput.permissionDecision:"deny"` (Kimi Code CLI's hooks
7216
+ * contract documents only "deny"; `ask` downgrades with a prefix, mirroring
7217
+ * the codex branch above), `inform` -> raw text on stdout (Kimi appends
7218
+ * stdout to context on exit 0 — no `hookSpecificOutput` envelope documented
7219
+ * for non-blocking context injection).
7198
7220
  *
7199
7221
  * User-visible pass notices (`prompt.userMessage`, Python `hook_output.allow_pass`
7200
7222
  * / `post_pass` parity), by harness:
@@ -7259,6 +7281,7 @@ function respond(id, prompt, event = "PreToolUse") {
7259
7281
  agent_message: message
7260
7282
  });
7261
7283
  case "hermes": return toHermesResponse(prompt);
7284
+ case "kimi": return toKimiResponse(prompt);
7262
7285
  case "cline":
7263
7286
  if (kind === "block") return JSON.stringify({
7264
7287
  cancel: true,
@@ -8163,7 +8186,7 @@ function docSourceOf(tool) {
8163
8186
  * Map a live tool-use to the activity to record, or null when nothing is
8164
8187
  * tracked. Works across harnesses — tool names are globally distinct:
8165
8188
  * - MCP doc calls (`context7` / `exa`, any separator) → `doc`
8166
- * - `Task`/`Agent` + `subagent_type` (Claude/Cursor) → `agent` (bare agent name)
8189
+ * - `Task`/`Agent`/`AgentSwarm` + `subagent_type` (Claude/Cursor/Kimi) → `agent` (bare agent name)
8167
8190
  * - direct exploration/research (Glob/Grep, explore Bash, web, MCP cache reads)
8168
8191
  * → `agent` credited to the matching REQUIRED_AGENTS phase
8169
8192
  * - a read tool opening a `.md` reference → `ref`
@@ -8178,7 +8201,7 @@ function activityFor(event) {
8178
8201
  source: docSource,
8179
8202
  ts: event.now
8180
8203
  });
8181
- if (event.tool === "Task" || event.tool === "Agent") {
8204
+ if (event.tool === "Task" || event.tool === "Agent" || event.tool === "AgentSwarm") {
8182
8205
  const name = String(event.input?.subagent_type ?? event.input?.name ?? "").split(":").pop() ?? "";
8183
8206
  if (name) out.push(agentActivity(name, event.now, qualityFor(event.responseLength, AGENT_QUALITY_MIN)));
8184
8207
  return out;
@@ -31,7 +31,8 @@ const STD_NAMES = {
31
31
  gemini: "gemini-cli",
32
32
  copilot: "copilot",
33
33
  kiro: "kiro",
34
- hermes: "hermes"
34
+ hermes: "hermes",
35
+ kimi: "kimi"
35
36
  };
36
37
  /** Harnesses exposing a native hook system (vs CLI-only integration). */
37
38
  const HOOK_CAPABLE = /* @__PURE__ */ new Set([
@@ -41,7 +42,8 @@ const HOOK_CAPABLE = /* @__PURE__ */ new Set([
41
42
  "cline",
42
43
  "gemini-cli",
43
44
  "opencode",
44
- "hermes"
45
+ "hermes",
46
+ "kimi"
45
47
  ]);
46
48
  /** Integration mode for a harness id. */
47
49
  function modeFor(id) {
@@ -1,6 +1,6 @@
1
1
  //#region src/detect/interfaces/types.d.ts
2
2
  /** Known AI coding harnesses detectable at runtime. */
3
- type HarnessId = "claude-code" | "codex" | "cursor" | "cline" | "gemini-cli" | "opencode" | "windsurf" | "copilot" | "aider" | "kiro" | "goose" | "amp" | "hermes" | "unknown";
3
+ type HarnessId = "claude-code" | "codex" | "cursor" | "cline" | "gemini-cli" | "opencode" | "windsurf" | "copilot" | "aider" | "kiro" | "goose" | "amp" | "hermes" | "kimi" | "unknown";
4
4
  /** Integration mode: `hook` = native lifecycle hooks; `cli` = run as an external step. */
5
5
  type HarnessMode = "hook" | "cli";
6
6
  /** How the harness was identified. */
@@ -1,4 +1,4 @@
1
- import { i as HarnessId } from "./harness-s1Fce_dL.mjs";
1
+ import { i as HarnessId } from "./harness-BQ5_Wnva.mjs";
2
2
 
3
3
  //#region src/config/env.d.ts
4
4
  /**
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as PromptKind, r as formatPrompt, t as Prompt } from "./types-DVbIl9md.mjs";
2
2
  import { _ as queryHash, a as cacheLookupSubstringMeta, c as mcpCacheKey, d as extractText, f as IndexSummary, g as jaccardSimilar, h as compactMarkdown, i as cacheLookupSubstring, l as mcpCacheWrite, m as summarizeIndex, n as cacheLookup, o as cachePath, p as loadIndex, r as cacheLookupMeta, s as cacheStore, t as CacheHit, u as webfetchCacheWrite } from "./index-BUwEmIK-.mjs";
3
- import { _ as parseEnvInt, a as ProjectLayout, c as projectLayout, d as resolveMaxLines, f as splitTarget, g as ttlLabel, h as resolveTtlSec, i as parseEnvFile, l as DEFAULT_MAX_LINES, m as TTL_ENV_KEY, n as envCandidates, o as STATE_GITIGNORE, p as DEFAULT_TTL_SEC, r as loadDotenv, s as STATE_ROOT, t as HOME_DIR, u as MAX_LINES_ENV_KEY } from "./index-jj_EzZRv.mjs";
4
- import { a as HarnessInfo, i as HarnessId, n as detectMode, o as HarnessMode, r as modeFor, s as HarnessVia, t as detectHarness } from "./harness-s1Fce_dL.mjs";
3
+ import { _ as parseEnvInt, a as ProjectLayout, c as projectLayout, d as resolveMaxLines, f as splitTarget, g as ttlLabel, h as resolveTtlSec, i as parseEnvFile, l as DEFAULT_MAX_LINES, m as TTL_ENV_KEY, n as envCandidates, o as STATE_GITIGNORE, p as DEFAULT_TTL_SEC, r as loadDotenv, s as STATE_ROOT, t as HOME_DIR, u as MAX_LINES_ENV_KEY } from "./index-B_VHbsaJ.mjs";
4
+ import { a as HarnessInfo, i as HarnessId, n as detectMode, o as HarnessMode, r as modeFor, s as HarnessVia, t as detectHarness } from "./harness-BQ5_Wnva.mjs";
5
5
  import { a as isDocConsulted, i as formatDocSatisfactionStatus, n as DocSatisfactionStatus, o as resolveSessions, r as formatDocDeny, t as AuthEntry } from "./doc-helpers-CEKzGg2u.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";
package/dist/index.mjs CHANGED
@@ -1,14 +1,14 @@
1
1
  import { a as parseEnvInt, i as splitTarget, n as MAX_LINES_ENV_KEY, r as resolveMaxLines, t as DEFAULT_MAX_LINES } from "./limits-CHn8AIL1.mjs";
2
- import { a as DEFAULT_TTL_SEC, c as ttlLabel, i as parseEnvFile, n as envCandidates, o as TTL_ENV_KEY, r as loadDotenv, s as resolveTtlSec, t as HOME_DIR } from "./dotenv-Jj8aL1FL.mjs";
2
+ import { a as DEFAULT_TTL_SEC, c as ttlLabel, i as parseEnvFile, n as envCandidates, o as TTL_ENV_KEY, r as loadDotenv, s as resolveTtlSec, t as HOME_DIR } from "./dotenv-B26N_uGr.mjs";
3
3
  import { n as STATE_ROOT, r as projectLayout, t as STATE_GITIGNORE } from "./layout-C0jaaCQC.mjs";
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
- import { n as detectMode, r as modeFor, t as detectHarness } from "./harness-Cb9xR8dC.mjs";
6
+ import { n as detectMode, r as modeFor, t as detectHarness } from "./harness-BMuLJ9lm.mjs";
7
7
  import { A as GIT_ASK, B as detectProjectType, C as SESSION_STATE_FRAGMENT, D as ASK_PATTERNS, E as protectedPathGuard, F as isRalphMode, H as requiredArchSkill, I as matchPatterns, L as detectFramework, M as PROJECT_INSTALL, N as RALPH_SAFE, O as CRITICAL_PATTERNS, P as SYSTEM_INSTALL, R as DEV_KEYWORDS, S as SAFE_PREFIXES, T as PROTECTED_GIT_RE, V as isApexCommand, _ as bashWriteGuard, a as registerGuard, b as CODE_REDIRECT, c as GO_DECL_RE, d as PY_MODEL_RE, f as RUST_DECL_RE, h as interfaceSeparationGuard, i as clearUserGuards, j as GIT_BLOCKED, k as securityGuard, l as JAVA_DECL_RE, m as TS_DECL_RE, n as FAIL_CLOSED, o as runGuards, p as SWIFT_PROTO_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as ASK_WRITERS, w as PROTECTED_FRAGMENTS, x as FILE_REDIRECT, y as CODE_MUTATORS, z as detectModularArchitecture } from "./evaluate-ClfbCDiY.mjs";
8
8
  import { d as countFrameworkCodeLines, f as countLines, l as PLUGINS_DIR, p as evaluateFileSize, u as SOLID_REF } from "./home-state-BXf38Zi1.mjs";
9
9
  import { i as resolveSessions, n as formatDocSatisfactionStatus, r as isDocConsulted, t as formatDocDeny } from "./doc-helpers-CWZegVdR.mjs";
10
10
  import { i as parseFrontmatter, n as scoreReferences, r as globToRe, t as routeReferences } from "./router-PKVNBHge.mjs";
11
- import { A as capVerbosity, C as usesTailwindUtilities, F as brainstormGate, I as docConsultedGate, L as evaluateApex, M as APEX_GATES, N as POST_AUTH_GATES, O as MAX_EXA_RESULTS, P as PRE_AUTH_GATES, R as freshnessGate, S as skillTriggerGate, T as frameworkSolidGate, a as firstHeading, b as parseField, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as detectCreationIntent, k as MAX_TOKENS, 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, w as SKILL_TRIGGERS, x as detectRequiredSkills, y as parseBodyDesc, z as solidReadGate } from "./validate-DhOX5hDK.mjs";
11
+ import { A as MAX_EXA_RESULTS, B as freshnessGate, C as detectRequiredSkills, D as frameworkSolidGate, E as SKILL_TRIGGERS, F as POST_AUTH_GATES, I as PRE_AUTH_GATES, L as brainstormGate, M as capVerbosity, N as detectCreationIntent, P as APEX_GATES, R as docConsultedGate, S as parseField, T as usesTailwindUtilities, V as solidReadGate, _ as detectClaudeMdProjectType, a as firstHeading, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as buildClaudeMdContext, h as buildApexInstruction, i as firstComment, j as MAX_TOKENS, l as PROJECT_INDICATORS, m as DEV_VERBS, n as missingSeoElements, o as parseEnrichment, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, w as skillTriggerGate, x as parseBodyDesc, z as evaluateApex } from "./validate-CkmquRDV.mjs";
12
12
  import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
13
13
  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-CymilZiZ.mjs";
14
14
  import { a as cacheLookupSubstring, c as cacheStore, d as loadIndex, f as summarizeIndex, h as queryHash, i as cacheLookupMeta, l as mcpCacheKey, m as jaccardSimilar, n as webfetchCacheWrite, o as cacheLookupSubstringMeta, p as compactMarkdown, r as cacheLookup, s as cachePath, t as mcpCacheWrite, u as extractText } from "./mcp-store-BkBDmuxN.mjs";
@@ -1,4 +1,4 @@
1
- import { i as HarnessId } from "../harness-s1Fce_dL.mjs";
1
+ import { i as HarnessId } from "../harness-BQ5_Wnva.mjs";
2
2
 
3
3
  //#region src/init/templates.d.ts
4
4
  /**
@@ -0,0 +1,80 @@
1
+ import { t as evaluate } from "./evaluate-ClfbCDiY.mjs";
2
+ import { t as formatPrompt } from "./types-ernB1Dy3.mjs";
3
+ import { c as readClaudeInput, v as commandToString } from "./claude-51RSspJ1.mjs";
4
+ //#region src/adapters/kimi/index.ts
5
+ /**
6
+ * Kimi Code CLI adapter (hook-mode). Moonshot AI's Kimi Code CLI (v0.27.0,
7
+ * 2026) configures hooks in `~/.kimi-code/config.toml` (`[[hooks]]`: event,
8
+ * matcher, command, timeout — exactly 4 fields, any extra breaks config
9
+ * loading) and pipes a JSON payload to `command` on stdin, reading JSON back
10
+ * on stdout. Verified against kimi.com/code/docs/en/kimi-code-cli/
11
+ * customization/hooks.html (2026): the INPUT base shape
12
+ * (`hook_event_name`/`session_id`/`cwd`, `PreToolUse`/`Bash` carrying
13
+ * `tool_name` + `tool_input.command`) matches Claude Code's snake_case wire
14
+ * shape, so the Claude reader is reused — verified live against kimi-code
15
+ * v0.27.0 for both `PreToolUse`/`Bash` and `PreToolUse`/`Write`. Tool fields
16
+ * verified: `Bash` takes `command`; `Write` takes `path` + `content`; `Edit`
17
+ * takes `path` + `old_string`/`new_string` (per `docs/en/reference/tools.md`,
18
+ * moonshotai/kimi-code). The path key is `path`, NOT Claude's `file_path`
19
+ * (see interfaces/types.ts).
20
+ *
21
+ * OUTPUT does not match Claude: only `UserPromptSubmit`, `PreToolUse`, `Stop`
22
+ * are blockable, and the only documented decision is
23
+ * `{"hookSpecificOutput":{"permissionDecision":"deny","permissionDecisionReason"}}`
24
+ * (camelCase, despite the snake_case input — a real Kimi inconsistency). No
25
+ * `"ask"`/`"allow"`/`additionalContext` is documented. Verified live against
26
+ * kimi-code v0.27.0: that deny envelope on stdout at exit 0 blocks the call
27
+ * (exit 2 is NOT required) and `permissionDecisionReason` is re-injected to
28
+ * the model; empty stdout at exit 0 lets the call run. Exit 2 = block, stderr
29
+ * = reason; any other exit/timeout/crash fails open (allow). Whether raw-text
30
+ * stdout at exit 0 (the `inform` case) reaches the context is documented only
31
+ * as "may be" — unverified, needs live test.
32
+ */
33
+ /**
34
+ * Downgrade prefix for `ask` — Kimi has no interactive approval channel
35
+ * reachable from a hook. Kimi DOES have an `ask` decision, but only via
36
+ * `[[permission.rules]] decision = "ask"` in config.toml, a separate system
37
+ * a hook's return value cannot invoke.
38
+ */
39
+ const ASK_PREFIX = "[downgraded from ask — Kimi Code has no interactive approval]";
40
+ /** Read & parse the Kimi hook stdin payload (same wire shape as Claude for the fields we consume). */
41
+ async function readKimiInput() {
42
+ return await readClaudeInput();
43
+ }
44
+ /**
45
+ * Render a portable {@link Prompt} as a Kimi hook response string:
46
+ * `block`/`ask` -> `{hookSpecificOutput:{permissionDecision:"deny",...}}`
47
+ * (only `"deny"` is documented; `ask` is downgraded with {@link ASK_PREFIX});
48
+ * `inform` -> raw text (Kimi appends stdout to context on exit 0 — no
49
+ * documented JSON envelope for non-blocking context injection).
50
+ * @param prompt - The portable policy prompt.
51
+ * @returns The native Kimi response string.
52
+ */
53
+ function toKimiResponse(prompt) {
54
+ const msg = formatPrompt(prompt);
55
+ if (prompt.kind === "inform") return msg;
56
+ const res = { hookSpecificOutput: {
57
+ permissionDecision: "deny",
58
+ permissionDecisionReason: prompt.kind === "ask" ? `${ASK_PREFIX}\n${msg}` : msg
59
+ } };
60
+ return JSON.stringify(res);
61
+ }
62
+ /**
63
+ * Run the bundled policy over a Kimi hook payload and return the native
64
+ * response string, or null to allow (the hook then exits 0 with empty stdout).
65
+ * @param input - Parsed hook stdin payload.
66
+ * @returns Native response string, or null when the tool use is allowed.
67
+ */
68
+ function guard(input) {
69
+ const t = input.tool_input;
70
+ const r = evaluate({
71
+ tool: input.tool_name ?? "Write",
72
+ filePath: t?.path ?? t?.file_path,
73
+ content: t?.content ?? t?.new_string,
74
+ command: commandToString(t?.command)
75
+ });
76
+ if (r.decision === "allow" || !r.prompt) return null;
77
+ return toKimiResponse(r.prompt);
78
+ }
79
+ //#endregion
80
+ export { readKimiInput as n, toKimiResponse as r, guard as t };
@@ -1,5 +1,5 @@
1
1
  import { A as GIT_ASK, B as detectProjectType, C as SESSION_STATE_FRAGMENT, D as ASK_PATTERNS, E as protectedPathGuard, F as isRalphMode, H as requiredArchSkill, I as matchPatterns, L as detectFramework, M as PROJECT_INSTALL, N as RALPH_SAFE, O as CRITICAL_PATTERNS, P as SYSTEM_INSTALL, R as DEV_KEYWORDS, S as SAFE_PREFIXES, T as PROTECTED_GIT_RE, V as isApexCommand, _ as bashWriteGuard, a as registerGuard, b as CODE_REDIRECT, c as GO_DECL_RE, d as PY_MODEL_RE, f as RUST_DECL_RE, h as interfaceSeparationGuard, i as clearUserGuards, j as GIT_BLOCKED, k as securityGuard, l as JAVA_DECL_RE, m as TS_DECL_RE, n as FAIL_CLOSED, o as runGuards, p as SWIFT_PROTO_RE, r as GUARDS, s as installGuard, t as evaluate, u as PHP_DECL_RE, v as ASK_WRITERS, w as PROTECTED_FRAGMENTS, x as FILE_REDIRECT, y as CODE_MUTATORS, z as detectModularArchitecture } from "../evaluate-ClfbCDiY.mjs";
2
2
  import { d as countFrameworkCodeLines, f as countLines, l as PLUGINS_DIR, p as evaluateFileSize, u as SOLID_REF } from "../home-state-BXf38Zi1.mjs";
3
- import { A as capVerbosity, C as usesTailwindUtilities, F as brainstormGate, I as docConsultedGate, L as evaluateApex, M as APEX_GATES, N as POST_AUTH_GATES, O as MAX_EXA_RESULTS, P as PRE_AUTH_GATES, R as freshnessGate, S as skillTriggerGate, T as frameworkSolidGate, a as firstHeading, b as parseField, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as detectClaudeMdProjectType, h as buildClaudeMdContext, i as firstComment, j as detectCreationIntent, k as MAX_TOKENS, 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, w as SKILL_TRIGGERS, x as detectRequiredSkills, y as parseBodyDesc, z as solidReadGate } from "../validate-DhOX5hDK.mjs";
3
+ import { A as MAX_EXA_RESULTS, B as freshnessGate, C as detectRequiredSkills, D as frameworkSolidGate, E as SKILL_TRIGGERS, F as POST_AUTH_GATES, I as PRE_AUTH_GATES, L as brainstormGate, M as capVerbosity, N as detectCreationIntent, P as APEX_GATES, R as docConsultedGate, S as parseField, T as usesTailwindUtilities, V as solidReadGate, _ as detectClaudeMdProjectType, a as firstHeading, c as EXCLUDE_DIRS, d as buildApexTaskInjection, f as loadApexTaskState, g as buildClaudeMdContext, h as buildApexInstruction, i as firstComment, j as MAX_TOKENS, l as PROJECT_INDICATORS, m as DEV_VERBS, n as missingSeoElements, o as parseEnrichment, r as descFromText, s as parseEntry, t as isHtmlLike, u as buildApexTaskContext, w as skillTriggerGate, x as parseBodyDesc, z as evaluateApex } from "../validate-CkmquRDV.mjs";
4
4
  import "../policy-la_KkjCS.mjs";
5
5
  export { APEX_GATES, ASK_PATTERNS, ASK_WRITERS, CODE_MUTATORS, CODE_REDIRECT, CRITICAL_PATTERNS, DEV_KEYWORDS, DEV_VERBS, EXCLUDE_DIRS, FAIL_CLOSED, FILE_REDIRECT, GIT_ASK, GIT_BLOCKED, GO_DECL_RE, GUARDS, JAVA_DECL_RE, MAX_EXA_RESULTS, MAX_TOKENS, PHP_DECL_RE, PLUGINS_DIR, POST_AUTH_GATES, PRE_AUTH_GATES, PROJECT_INDICATORS, PROJECT_INSTALL, PROTECTED_FRAGMENTS, PROTECTED_GIT_RE, PY_MODEL_RE, RALPH_SAFE, RUST_DECL_RE, SAFE_PREFIXES, SESSION_STATE_FRAGMENT, SKILL_TRIGGERS, SOLID_REF, SWIFT_PROTO_RE, SYSTEM_INSTALL, TS_DECL_RE, bashWriteGuard, brainstormGate, buildApexInstruction, buildApexTaskContext, buildApexTaskInjection, buildClaudeMdContext, capVerbosity, clearUserGuards, countFrameworkCodeLines, countLines, descFromText, detectClaudeMdProjectType, detectCreationIntent, detectFramework, detectModularArchitecture, detectProjectType, detectRequiredSkills, docConsultedGate, evaluate, evaluateApex, evaluateFileSize, firstComment, firstHeading, frameworkSolidGate, freshnessGate, installGuard, interfaceSeparationGuard, isApexCommand, isHtmlLike, isRalphMode, loadApexTaskState, matchPatterns, missingSeoElements, parseBodyDesc, parseEnrichment, parseEntry, parseField, protectedPathGuard, registerGuard, requiredArchSkill, runGuards, securityGuard, skillTriggerGate, solidReadGate, usesTailwindUtilities };
@@ -75,7 +75,7 @@ interface ToolEvent {
75
75
  * Map a live tool-use to the activity to record, or null when nothing is
76
76
  * tracked. Works across harnesses — tool names are globally distinct:
77
77
  * - MCP doc calls (`context7` / `exa`, any separator) → `doc`
78
- * - `Task`/`Agent` + `subagent_type` (Claude/Cursor) → `agent` (bare agent name)
78
+ * - `Task`/`Agent`/`AgentSwarm` + `subagent_type` (Claude/Cursor/Kimi) → `agent` (bare agent name)
79
79
  * - direct exploration/research (Glob/Grep, explore Bash, web, MCP cache reads)
80
80
  * → `agent` credited to the matching REQUIRED_AGENTS phase
81
81
  * - a read tool opening a `.md` reference → `ref`
@@ -207,6 +207,12 @@ declare function normalizeEvent(id: string, payload: Record<string, unknown>): N
207
207
  * - hermes: delegated to the adapter's `toHermesResponse` — `block` ->
208
208
  * `{decision:"block",reason}`; `ask`/`inform` degrade to non-blocking
209
209
  * `{context}` (Hermes has no interactive "ask" state).
210
+ * - kimi: delegated to the adapter's `toKimiResponse` — `block`/`ask` ->
211
+ * `hookSpecificOutput.permissionDecision:"deny"` (Kimi Code CLI's hooks
212
+ * contract documents only "deny"; `ask` downgrades with a prefix, mirroring
213
+ * the codex branch above), `inform` -> raw text on stdout (Kimi appends
214
+ * stdout to context on exit 0 — no `hookSpecificOutput` envelope documented
215
+ * for non-blocking context injection).
210
216
  *
211
217
  * User-visible pass notices (`prompt.userMessage`, Python `hook_output.allow_pass`
212
218
  * / `post_pass` parity), by harness:
@@ -234,7 +240,7 @@ declare function respond(id: string, prompt: Prompt, event?: string): string;
234
240
  declare const MCP_TTL_MS: number;
235
241
  /** WebFetch freshness (ms) from `FUSE_WEBFETCH_TTL_SEC` (default 24h; pages stale faster than docs). */
236
242
  declare const WEBFETCH_TTL_MS: number;
237
- /** MCP doc tools + WebFetch whose calls are cached / verbosity-capped. */
243
+ /** MCP doc tools + WebFetch/FetchURL whose calls are cached / verbosity-capped. */
238
244
  declare function isMcpTool(tool: string): boolean;
239
245
  /** The query/url that keys the cache. */
240
246
  declare function queryOf(input: Record<string, unknown>): string;
@@ -353,9 +359,10 @@ declare function runSessionStartCleanups(home?: string, now?: number): void;
353
359
  * @param cwd - Project root for dev-context detection.
354
360
  * @param home - Home dir (defaults to `~`).
355
361
  * @param now - Clock for TTL cleanup (defaults to `Date.now()`).
362
+ * @param id - Harness target id (defaults to "claude-code" — zero-regression default).
356
363
  * @returns The native hook stdout (possibly empty).
357
364
  */
358
- declare function sessionStartCore(cwd: string, home?: string, now?: number): string;
365
+ declare function sessionStartCore(cwd: string, home?: string, now?: number, id?: string): string;
359
366
  //#endregion
360
367
  //#region src/runtime/lifecycle/inject-rules.d.ts
361
368
  /** Read & concatenate all `*.md` files (sorted) under `rulesDir`. */
@@ -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-BXf38Zi1.mjs";
3
- import { A as trackMcpResearch, At as defaultStateDir, B as generateProjectMap, C as seoPostToolUse, Ct as trimLogFile, D as securityAdvisoryForPatch, Dt as claudeMdKey, E as securityAdvisory, Et as projectContext, F as dispatchAipilot, Ft as loadSecurityState, G as countFiles, H as writeTree, I as dispatchLessons, It as saveSecurityState, J as lessonsArchiveFileFor, K as getFileDesc, L as cartoSessionStart, Lt as securityStateDir, M as trackEnrichment, Mt as trackFile, N as dispatchLifecycle, Nt as normalizeEvent, O as postTrackingSideEffects, Ot as promptSubmitContext, P as aipilotPostToolUse, Pt as isoUtc, R as generateEcosystemMap, Rt as securityStatePath, S as postEditContext, St as removeOldFiles, T as dispatchMemory, Tt as gitContext, U as loadEnriched, V as isProject, W as mergeLines, X as lessonsStateFileFor, Y as lessonsFileFor, _ as preCommitGate, _t as readRules, a as recordActivity, at as saveApexState, b as extractSymbols, bt as pruneEmptyDirs, c as MCP_TTL_MS, ct as trackAgentMemory, d as isMcpTool, dt as validateSolidGate, f as queryOf, ft as checkFileSize, g as gate, gt as injectRules, h as TRIVIAL_BUDGET, ht as solidDetectStart, i as respond, it as cleanupSession, j as trackSkillRead, jt as projectHash, k as trackWatchResearch, kt as taskContext, l as WEBFETCH_TTL_MS, lt as subagentCacheContext, m as REQUIRED_AGENTS, mt as detectSolidProfile, n as activityFor, nt as trackSessionChanges, o as mcpPostStore, ot as logToolFailure, p as DEFAULT_WINDOW_MS, pt as countLoc, q as listChildren, r as handlePre, rt as validateRulesLoaded, s as mcpPreIntercept, st as validateTeammateOutput, t as handleHook, tt as postEditTypescript, u as cacheQueryOf, ut as validateTailwind, v as detectDuplication, vt as runSessionStartCleanups, w as seoPostToolUseResponse, wt as devContext, x as lifecycleStdout, xt as purgeTtlTree, y as dryGate, yt as sessionStartCore, z as writePluginMap, zt as todayUtc } from "../handle-Dthtlp7Z.mjs";
3
+ import { A as trackMcpResearch, At as defaultStateDir, B as generateProjectMap, C as seoPostToolUse, Ct as trimLogFile, D as securityAdvisoryForPatch, Dt as claudeMdKey, E as securityAdvisory, Et as projectContext, F as dispatchAipilot, Ft as loadSecurityState, G as countFiles, H as writeTree, I as dispatchLessons, It as saveSecurityState, J as lessonsArchiveFileFor, K as getFileDesc, L as cartoSessionStart, Lt as securityStateDir, M as trackEnrichment, Mt as trackFile, N as dispatchLifecycle, Nt as normalizeEvent, O as postTrackingSideEffects, Ot as promptSubmitContext, P as aipilotPostToolUse, Pt as isoUtc, R as generateEcosystemMap, Rt as securityStatePath, S as postEditContext, St as removeOldFiles, T as dispatchMemory, Tt as gitContext, U as loadEnriched, V as isProject, W as mergeLines, X as lessonsStateFileFor, Y as lessonsFileFor, _ as preCommitGate, _t as readRules, a as recordActivity, at as saveApexState, b as extractSymbols, bt as pruneEmptyDirs, c as MCP_TTL_MS, ct as trackAgentMemory, d as isMcpTool, dt as validateSolidGate, f as queryOf, ft as checkFileSize, g as gate, gt as injectRules, h as TRIVIAL_BUDGET, ht as solidDetectStart, i as respond, it as cleanupSession, j as trackSkillRead, jt as projectHash, k as trackWatchResearch, kt as taskContext, l as WEBFETCH_TTL_MS, lt as subagentCacheContext, m as REQUIRED_AGENTS, mt as detectSolidProfile, n as activityFor, nt as trackSessionChanges, o as mcpPostStore, ot as logToolFailure, p as DEFAULT_WINDOW_MS, pt as countLoc, q as listChildren, r as handlePre, rt as validateRulesLoaded, s as mcpPreIntercept, st as validateTeammateOutput, t as handleHook, tt as postEditTypescript, u as cacheQueryOf, ut as validateTailwind, v as detectDuplication, vt as runSessionStartCleanups, w as seoPostToolUseResponse, wt as devContext, x as lifecycleStdout, xt as purgeTtlTree, y as dryGate, yt as sessionStartCore, z as writePluginMap, zt as todayUtc } from "../handle-B7YufFz9.mjs";
4
4
  //#region src/runtime/storage.ts
5
5
  /**
6
6
  * The project's single state dir (`<root>/.harness`) — neutral + harness-agnostic,
@@ -1,5 +1,5 @@
1
- import { t as HOME_DIR } from "./dotenv-Jj8aL1FL.mjs";
2
- import { t as detectHarness } from "./harness-Cb9xR8dC.mjs";
1
+ import { t as HOME_DIR } from "./dotenv-B26N_uGr.mjs";
2
+ import { t as detectHarness } from "./harness-BMuLJ9lm.mjs";
3
3
  import { l as PLUGINS_DIR } from "./home-state-BXf38Zi1.mjs";
4
4
  import { join } from "node:path";
5
5
  import { existsSync, readFileSync, readdirSync } from "node:fs";
@@ -1,9 +1,9 @@
1
- import { c as ttlLabel } from "./dotenv-Jj8aL1FL.mjs";
1
+ import { c as ttlLabel } from "./dotenv-B26N_uGr.mjs";
2
2
  import { n as fuseHarnessHome } from "./home-state-BXf38Zi1.mjs";
3
3
  import { a as writeJsonFile, i as readJsonFile } from "./json-io-DisYd2fb.mjs";
4
4
  import { i as resolveSessions } from "./doc-helpers-CWZegVdR.mjs";
5
5
  import { t as routeReferences } from "./router-PKVNBHge.mjs";
6
- import { t as resolveSkillPath } from "./skill-path-BO2N0XvB.mjs";
6
+ import { t as resolveSkillPath } from "./skill-path-CDvR4bbF.mjs";
7
7
  import { join } from "node:path";
8
8
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
9
9
  import { createHmac, randomBytes } from "node:crypto";
@@ -1,2 +1,2 @@
1
- import { c as recordAgent, d as recordRefRead, f as recordTarget, l as recordBrainstormRequired, m as trivialCount, n as saveTrack, o as agentsFresh, p as recordTrivialEdit, s as emptyTrack, t as loadTrack, u as recordDoc } from "../store-Bcn08y9m.mjs";
1
+ import { c as recordAgent, d as recordRefRead, f as recordTarget, l as recordBrainstormRequired, m as trivialCount, n as saveTrack, o as agentsFresh, p as recordTrivialEdit, s as emptyTrack, t as loadTrack, u as recordDoc } from "../store-nDZ3eLBQ.mjs";
2
2
  export { agentsFresh, emptyTrack, loadTrack, recordAgent, recordBrainstormRequired, recordDoc, recordRefRead, recordTarget, recordTrivialEdit, saveTrack, trivialCount };
@@ -1,10 +1,10 @@
1
1
  import { r as resolveMaxLines } from "./limits-CHn8AIL1.mjs";
2
- import { c as ttlLabel, t as HOME_DIR } from "./dotenv-Jj8aL1FL.mjs";
2
+ import { c as ttlLabel, t as HOME_DIR } from "./dotenv-B26N_uGr.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";
6
6
  import { t as routeReferences } from "./router-PKVNBHge.mjs";
7
- import { n as findMarketplacePlugins, r as readPluginMeta, t as resolveSkillPath } from "./skill-path-BO2N0XvB.mjs";
7
+ import { n as findMarketplacePlugins, r as readPluginMeta, t as resolveSkillPath } from "./skill-path-CDvR4bbF.mjs";
8
8
  import { extname, join } from "node:path";
9
9
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
10
10
  import { homedir } from "node:os";
@@ -1208,24 +1208,29 @@ function harnessHomeSegment(id) {
1208
1208
  return HOME_DIR[id] ?? ".claude";
1209
1209
  }
1210
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).
1211
+ * Root instructions doc name for a harness target: "AGENTS.md" for Codex and
1212
+ * Kimi Code CLI (both documented conventions), "CLAUDE.md" for every other
1213
+ * target (including the default/unknown fallback).
1213
1214
  * @param id - Harness id.
1214
1215
  * @returns The doc file name.
1215
1216
  */
1216
1217
  function apexDocName(id) {
1217
- return id === "codex" ? "AGENTS.md" : "CLAUDE.md";
1218
+ return id === "codex" || id === "kimi" ? "AGENTS.md" : "CLAUDE.md";
1218
1219
  }
1219
1220
  /**
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.
1221
+ * Native plan/track tool name for a harness target: Codex's `update_plan`,
1222
+ * Kimi Code CLI's `TodoList`, or Claude's `TaskCreate` (default). Covers only
1223
+ * the PLAN-step line — other target-specific tool references (`TaskList`,
1224
+ * `TaskUpdate`) are resolved via `apexTaskSteps`/`apexAgentSteps` in
1225
+ * `apex-target-steps.ts` since their surrounding prose differs structurally,
1226
+ * not just by token.
1224
1227
  * @param id - Harness id.
1225
1228
  * @returns The plan-tool name.
1226
1229
  */
1227
1230
  function apexPlanTool(id) {
1228
- return id === "codex" ? "update_plan" : "TaskCreate";
1231
+ if (id === "codex") return "update_plan";
1232
+ if (id === "kimi") return "TodoList";
1233
+ return "TaskCreate";
1229
1234
  }
1230
1235
  //#endregion
1231
1236
  //#region src/policy/detect-claude-md-project-type.ts
@@ -1291,6 +1296,61 @@ function buildClaudeMdContext(prompt, cwd, id = "claude-code") {
1291
1296
  return `${buildApexInstruction(detectClaudeMdProjectType(cwd), resolveMaxLines(), id)}\n\n# ${docName}\n${claudeContent}`;
1292
1297
  }
1293
1298
  //#endregion
1299
+ //#region src/policy/apex-target-steps.ts
1300
+ /** Codex/Kimi step-trio overrides; any other target falls back to {@link DEFAULT_TASK_STEPS}. */
1301
+ const TASK_STEPS = {
1302
+ codex: {
1303
+ step3: "update_plan → review the current plan",
1304
+ step4: "update_plan → mark the active step in_progress before starting",
1305
+ step7: "update_plan → mark the step completed when done"
1306
+ },
1307
+ kimi: {
1308
+ step3: "TodoList → review the current list (omit todos to query)",
1309
+ step4: "TodoList → mark the active item in_progress before starting",
1310
+ step7: "TodoList → mark the item done when finished"
1311
+ }
1312
+ };
1313
+ /** Default (Claude Code) step trio — zero-regression fallback for any unlisted target. */
1314
+ const DEFAULT_TASK_STEPS = {
1315
+ step3: "TaskList → see pending tasks",
1316
+ step4: "TaskUpdate(in_progress) → before starting",
1317
+ step7: "TaskUpdate(completed) → triggers auto-commit"
1318
+ };
1319
+ /**
1320
+ * Resolve the step3/step4/step7 phrasing for a harness target (APEX
1321
+ * task-context injection). Replaces the former `isCodex` binary ternary.
1322
+ * @param id - Harness id.
1323
+ * @returns The {@link ApexTaskSteps} for that target.
1324
+ */
1325
+ function apexTaskSteps(id) {
1326
+ return TASK_STEPS[id] ?? DEFAULT_TASK_STEPS;
1327
+ }
1328
+ /** Codex/Kimi before/done overrides; any other target falls back to {@link DEFAULT_AGENT_STEPS}. */
1329
+ const AGENT_STEPS = {
1330
+ codex: {
1331
+ beforeStart: "Use update_plan → mark the active step in_progress before starting",
1332
+ whenDone: "update_plan → mark the step completed when done"
1333
+ },
1334
+ kimi: {
1335
+ beforeStart: "Use TodoList → mark the active item in_progress before starting",
1336
+ whenDone: "TodoList → mark the item done when finished"
1337
+ }
1338
+ };
1339
+ /** Default (Claude Code) before/done pair — zero-regression fallback for any unlisted target. */
1340
+ const DEFAULT_AGENT_STEPS = {
1341
+ beforeStart: "Use TaskUpdate(taskId, status: in_progress) before starting",
1342
+ whenDone: "TaskUpdate(taskId, status: completed) triggers auto-commit"
1343
+ };
1344
+ /**
1345
+ * Resolve the beforeStart/whenDone phrasing for a harness target (APEX
1346
+ * sub-agent injection). Replaces the former `isCodex` binary ternary.
1347
+ * @param id - Harness id.
1348
+ * @returns The {@link ApexAgentSteps} for that target.
1349
+ */
1350
+ function apexAgentSteps(id) {
1351
+ return AGENT_STEPS[id] ?? DEFAULT_AGENT_STEPS;
1352
+ }
1353
+ //#endregion
1294
1354
  //#region src/policy/apex-task-context.ts
1295
1355
  /**
1296
1356
  * Read the current task state from `task.json`, reproducing the legacy Python
@@ -1330,10 +1390,7 @@ function loadApexTaskState(taskFile) {
1330
1390
  */
1331
1391
  function buildApexTaskContext(state, maxLines, id = "claude-code") {
1332
1392
  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";
1393
+ const { step3, step4, step7 } = apexTaskSteps(id);
1337
1394
  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}`;
1338
1395
  }
1339
1396
  /**
@@ -1591,4 +1648,4 @@ function missingSeoElements(html) {
1591
1648
  return missing;
1592
1649
  }
1593
1650
  //#endregion
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 };
1651
+ export { MAX_EXA_RESULTS as A, freshnessGate as B, detectRequiredSkills as C, frameworkSolidGate as D, SKILL_TRIGGERS as E, POST_AUTH_GATES as F, PRE_AUTH_GATES as I, brainstormGate as L, capVerbosity as M, detectCreationIntent as N, isExcludedJsPath as O, APEX_GATES as P, docConsultedGate as R, parseField as S, usesTailwindUtilities as T, solidReadGate as V, detectClaudeMdProjectType as _, firstHeading as a, scanPlugin as b, EXCLUDE_DIRS as c, buildApexTaskInjection as d, loadApexTaskState as f, buildClaudeMdContext as g, buildApexInstruction as h, firstComment as i, MAX_TOKENS as j, isExcludedSwiftPath as k, PROJECT_INDICATORS as l, DEV_VERBS as m, missingSeoElements as n, parseEnrichment as o, apexAgentSteps as p, descFromText as r, parseEntry as s, isHtmlLike as t, buildApexTaskContext as u, apexDocName as v, skillTriggerGate as w, parseBodyDesc as x, harnessHomeSegment as y, evaluateApex as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusengine/harness",
3
- "version": "0.1.79",
3
+ "version": "0.1.80",
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",
@@ -113,6 +113,11 @@
113
113
  "bun": "./src/adapters/hermes/index.ts",
114
114
  "types": "./dist/adapters/hermes/index.d.mts",
115
115
  "import": "./dist/adapters/hermes/index.mjs"
116
+ },
117
+ "./adapters/kimi": {
118
+ "bun": "./src/adapters/kimi/index.ts",
119
+ "types": "./dist/adapters/kimi/index.d.mts",
120
+ "import": "./dist/adapters/kimi/index.mjs"
116
121
  }
117
122
  },
118
123
  "files": [
@@ -134,7 +139,7 @@
134
139
  "sim": "bun test test/sim/",
135
140
  "typecheck": "tsc --noEmit",
136
141
  "docs:api": "typedoc",
137
- "build": "tsdown src/index.ts src/config/index.ts src/util/index.ts src/detect/index.ts src/policy/index.ts src/prompt/index.ts src/memory/index.ts src/cache/index.ts src/freshness/index.ts src/refs/index.ts src/statusline/index.ts src/cli/index.ts src/cli/bin.ts src/init/index.ts src/tracking/index.ts src/runtime/index.ts src/adapters/claude/index.ts src/adapters/codex/index.ts src/adapters/cursor/index.ts src/adapters/cline/index.ts src/adapters/gemini/index.ts src/adapters/hermes/index.ts --dts --format esm --clean --out-dir dist",
142
+ "build": "tsdown src/index.ts src/config/index.ts src/util/index.ts src/detect/index.ts src/policy/index.ts src/prompt/index.ts src/memory/index.ts src/cache/index.ts src/freshness/index.ts src/refs/index.ts src/statusline/index.ts src/cli/index.ts src/cli/bin.ts src/init/index.ts src/tracking/index.ts src/runtime/index.ts src/adapters/claude/index.ts src/adapters/codex/index.ts src/adapters/cursor/index.ts src/adapters/cline/index.ts src/adapters/gemini/index.ts src/adapters/hermes/index.ts src/adapters/kimi/index.ts --dts --format esm --clean --out-dir dist",
138
143
  "prepublishOnly": "bun test && tsc --noEmit && bun run build"
139
144
  },
140
145
  "publishConfig": {