@fusengine/harness 0.1.7 → 0.1.8

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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as detectHarness } from "../harness-C8Nxxyn_.mjs";
3
3
  import { n as stagedContent, r as stagedFiles, t as checkStaged } from "../run-h_2LNEA8.mjs";
4
- import { n as writeInitFile, t as initFor } from "../run-Cc98348q.mjs";
4
+ import { n as writeInitFile, t as initFor } from "../run-Cdp2Ef9B.mjs";
5
5
  import { t as handleHook } from "../handle-BGe0QZvQ.mjs";
6
6
  //#region src/cli/bin.ts
7
7
  /**
@@ -32,12 +32,13 @@ if (cmd === "hook") {
32
32
  process.exit(outcome.exit);
33
33
  } else if (cmd === "init") {
34
34
  const id = process.argv[3] ?? detectHarness().id;
35
- const file = initFor(id);
36
- if (!file) {
35
+ const files = initFor(id);
36
+ if (!files) {
37
37
  process.stderr.write(`harness: no hook integration for "${id}" — use \`harness check\` in a pre-commit step\n`);
38
38
  process.exit(1);
39
39
  }
40
- process.stdout.write(`harness: wired ${id} -> ${writeInitFile(process.cwd(), file)}\n`);
40
+ const written = files.map((f) => writeInitFile(process.cwd(), f));
41
+ process.stdout.write(`harness: wired ${id} -> ${written.join(", ")}\n`);
41
42
  process.exit(0);
42
43
  } else {
43
44
  const files = stagedFiles();
@@ -2,8 +2,9 @@ import { t as HarnessId } from "../harness-DwJskkz_.mjs";
2
2
 
3
3
  //#region src/init/templates.d.ts
4
4
  /**
5
- * Wiring file templates per harness, to register `harness hook <id>` as a
6
- * tool-use hook. Formats verified against each harness's 2026 hook docs.
5
+ * Wiring file templates per harness, registering `harness hook <id>` for BOTH
6
+ * phases: PRE (gate the edit) and POST (catch-all `activityFor` filters what
7
+ * to record). Formats verified against each harness's 2026 hook docs.
7
8
  */
8
9
  /** A file to write during `harness init`. */
9
10
  interface InitFile {
@@ -11,23 +12,23 @@ interface InitFile {
11
12
  content: string;
12
13
  executable?: boolean;
13
14
  }
14
- /** Claude Code: PreToolUse(Write|Edit) -> command. Target: `.claude/settings.json`. */
15
- declare function claudeInit(command: string): InitFile;
16
- /** Codex CLI: `.codex/hooks.json` — PreToolUse (Claude-compatible shape). */
17
- declare function codexInit(command: string): InitFile;
18
- /** Cursor: `.cursor/hooks.json` (version 1) — shell + file-edit hooks. */
19
- declare function cursorInit(command: string): InitFile;
20
- /** Gemini CLI: `.gemini/settings.json` — BeforeTool, timeout in ms. */
21
- declare function geminiInit(command: string): InitFile;
22
- /** Cline: an executable `.clinerules/hooks/PreToolUse` that pipes stdin to the command. */
23
- declare function clineInit(command: string): InitFile;
15
+ /** Claude Code: `.claude/settings.json` — PreToolUse(Write|Edit) + PostToolUse(all). */
16
+ declare function claudeInit(command: string): InitFile[];
17
+ /** Codex CLI: `.codex/hooks.json` (Claude-compatible shape). */
18
+ declare function codexInit(command: string): InitFile[];
19
+ /** Cursor: `.cursor/hooks.json` (version 1) — shell + tool gate + file-edit observe. */
20
+ declare function cursorInit(command: string): InitFile[];
21
+ /** Gemini CLI: `.gemini/settings.json` — BeforeTool(edits) + AfterTool(all, regex). */
22
+ declare function geminiInit(command: string): InitFile[];
23
+ /** Cline: executable `.clinerules/hooks/PreToolUse` + `PostToolUse` piping stdin. */
24
+ declare function clineInit(command: string): InitFile[];
24
25
  //#endregion
25
26
  //#region src/init/run.d.ts
26
27
  /**
27
- * Build the wiring file for a harness, or null when it has no hook integration
28
- * (cli-mode harnesses use `harness check` in a pre-commit step instead).
28
+ * Build the wiring file(s) for a harness, or null when it has no hook
29
+ * integration (cli-mode harnesses use `harness check` in a pre-commit step).
29
30
  */
30
- declare function initFor(id: HarnessId, command?: string): InitFile | null;
31
+ declare function initFor(id: HarnessId, command?: string): InitFile[] | null;
31
32
  /** Write an {@link InitFile} under `root` (creates dirs; `chmod +x` when executable). */
32
33
  declare function writeInitFile(root: string, file: InitFile): string;
33
34
  //#endregion
@@ -1,2 +1,2 @@
1
- import { a as codexInit, i as clineInit, n as writeInitFile, o as cursorInit, r as claudeInit, s as geminiInit, t as initFor } from "../run-Cc98348q.mjs";
1
+ import { a as codexInit, i as clineInit, n as writeInitFile, o as cursorInit, r as claudeInit, s as geminiInit, t as initFor } from "../run-Cdp2Ef9B.mjs";
2
2
  export { claudeInit, clineInit, codexInit, cursorInit, geminiInit, initFor, writeInitFile };
@@ -0,0 +1,128 @@
1
+ import { chmodSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ //#region src/init/templates.ts
4
+ function json(obj) {
5
+ return `${JSON.stringify(obj, null, 2)}\n`;
6
+ }
7
+ /** Claude Code: `.claude/settings.json` — PreToolUse(Write|Edit) + PostToolUse(all). */
8
+ function claudeInit(command) {
9
+ return [{
10
+ path: ".claude/settings.json",
11
+ content: json({ hooks: {
12
+ PreToolUse: [{
13
+ matcher: "Write|Edit",
14
+ hooks: [{
15
+ type: "command",
16
+ command
17
+ }]
18
+ }],
19
+ PostToolUse: [{
20
+ matcher: "",
21
+ hooks: [{
22
+ type: "command",
23
+ command
24
+ }]
25
+ }]
26
+ } })
27
+ }];
28
+ }
29
+ /** Codex CLI: `.codex/hooks.json` (Claude-compatible shape). */
30
+ function codexInit(command) {
31
+ return [{
32
+ path: ".codex/hooks.json",
33
+ content: json({ hooks: {
34
+ PreToolUse: [{
35
+ matcher: "Bash|apply_patch",
36
+ hooks: [{
37
+ type: "command",
38
+ command
39
+ }]
40
+ }],
41
+ PostToolUse: [{
42
+ matcher: "",
43
+ hooks: [{
44
+ type: "command",
45
+ command
46
+ }]
47
+ }]
48
+ } })
49
+ }];
50
+ }
51
+ /** Cursor: `.cursor/hooks.json` (version 1) — shell + tool gate + file-edit observe. */
52
+ function cursorInit(command) {
53
+ return [{
54
+ path: ".cursor/hooks.json",
55
+ content: json({
56
+ version: 1,
57
+ hooks: {
58
+ beforeShellExecution: [{ command }],
59
+ preToolUse: [{ command }],
60
+ afterFileEdit: [{ command }]
61
+ }
62
+ })
63
+ }];
64
+ }
65
+ /** Gemini CLI: `.gemini/settings.json` — BeforeTool(edits) + AfterTool(all, regex). */
66
+ function geminiInit(command) {
67
+ return [{
68
+ path: ".gemini/settings.json",
69
+ content: json({ hooks: {
70
+ BeforeTool: [{
71
+ matcher: "write_file|edit_file|replace",
72
+ hooks: [{
73
+ type: "command",
74
+ command,
75
+ timeout: 3e4
76
+ }]
77
+ }],
78
+ AfterTool: [{
79
+ matcher: ".*",
80
+ hooks: [{
81
+ type: "command",
82
+ command,
83
+ timeout: 3e4
84
+ }]
85
+ }]
86
+ } })
87
+ }];
88
+ }
89
+ /** Cline: executable `.clinerules/hooks/PreToolUse` + `PostToolUse` piping stdin. */
90
+ function clineInit(command) {
91
+ const script = (phase) => `#!/usr/bin/env bash\n# fuse-harness Cline ${phase} hook\ncat | ${command}\n`;
92
+ return [{
93
+ path: ".clinerules/hooks/PreToolUse",
94
+ content: script("pre"),
95
+ executable: true
96
+ }, {
97
+ path: ".clinerules/hooks/PostToolUse",
98
+ content: script("post"),
99
+ executable: true
100
+ }];
101
+ }
102
+ //#endregion
103
+ //#region src/init/run.ts
104
+ const RUNNERS = {
105
+ "claude-code": claudeInit,
106
+ codex: codexInit,
107
+ cursor: cursorInit,
108
+ "gemini-cli": geminiInit,
109
+ cline: clineInit
110
+ };
111
+ /**
112
+ * Build the wiring file(s) for a harness, or null when it has no hook
113
+ * integration (cli-mode harnesses use `harness check` in a pre-commit step).
114
+ */
115
+ function initFor(id, command = `npx harness hook ${id}`) {
116
+ const make = RUNNERS[id];
117
+ return make ? make(command) : null;
118
+ }
119
+ /** Write an {@link InitFile} under `root` (creates dirs; `chmod +x` when executable). */
120
+ function writeInitFile(root, file) {
121
+ const full = join(root, file.path);
122
+ mkdirSync(dirname(full), { recursive: true });
123
+ writeFileSync(full, file.content);
124
+ if (file.executable) chmodSync(full, 493);
125
+ return full;
126
+ }
127
+ //#endregion
128
+ export { codexInit as a, clineInit as i, writeInitFile as n, cursorInit as o, claudeInit as r, geminiInit as s, initFor as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusengine/harness",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
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",
@@ -1,94 +0,0 @@
1
- import { chmodSync, mkdirSync, writeFileSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- //#region src/init/templates.ts
4
- function json(obj) {
5
- return `${JSON.stringify(obj, null, 2)}\n`;
6
- }
7
- /** Claude Code: PreToolUse(Write|Edit) -> command. Target: `.claude/settings.json`. */
8
- function claudeInit(command) {
9
- return {
10
- path: ".claude/settings.json",
11
- content: json({ hooks: { PreToolUse: [{
12
- matcher: "Write|Edit",
13
- hooks: [{
14
- type: "command",
15
- command
16
- }]
17
- }] } })
18
- };
19
- }
20
- /** Codex CLI: `.codex/hooks.json` — PreToolUse (Claude-compatible shape). */
21
- function codexInit(command) {
22
- return {
23
- path: ".codex/hooks.json",
24
- content: json({ hooks: { PreToolUse: [{
25
- matcher: "Bash|apply_patch",
26
- hooks: [{
27
- type: "command",
28
- command
29
- }]
30
- }] } })
31
- };
32
- }
33
- /** Cursor: `.cursor/hooks.json` (version 1) — shell + file-edit hooks. */
34
- function cursorInit(command) {
35
- return {
36
- path: ".cursor/hooks.json",
37
- content: json({
38
- version: 1,
39
- hooks: {
40
- beforeShellExecution: [{ command }],
41
- afterFileEdit: [{ command }]
42
- }
43
- })
44
- };
45
- }
46
- /** Gemini CLI: `.gemini/settings.json` — BeforeTool, timeout in ms. */
47
- function geminiInit(command) {
48
- return {
49
- path: ".gemini/settings.json",
50
- content: json({ hooks: { BeforeTool: [{
51
- matcher: "write_file|edit_file|replace",
52
- hooks: [{
53
- type: "command",
54
- command,
55
- timeout: 3e4
56
- }]
57
- }] } })
58
- };
59
- }
60
- /** Cline: an executable `.clinerules/hooks/PreToolUse` that pipes stdin to the command. */
61
- function clineInit(command) {
62
- return {
63
- path: ".clinerules/hooks/PreToolUse",
64
- content: `#!/usr/bin/env bash\n# fuse-harness Cline hook — evaluate each tool use\ncat | ${command}\n`,
65
- executable: true
66
- };
67
- }
68
- //#endregion
69
- //#region src/init/run.ts
70
- const RUNNERS = {
71
- "claude-code": claudeInit,
72
- codex: codexInit,
73
- cursor: cursorInit,
74
- "gemini-cli": geminiInit,
75
- cline: clineInit
76
- };
77
- /**
78
- * Build the wiring file for a harness, or null when it has no hook integration
79
- * (cli-mode harnesses use `harness check` in a pre-commit step instead).
80
- */
81
- function initFor(id, command = `npx harness hook ${id}`) {
82
- const make = RUNNERS[id];
83
- return make ? make(command) : null;
84
- }
85
- /** Write an {@link InitFile} under `root` (creates dirs; `chmod +x` when executable). */
86
- function writeInitFile(root, file) {
87
- const full = join(root, file.path);
88
- mkdirSync(dirname(full), { recursive: true });
89
- writeFileSync(full, file.content);
90
- if (file.executable) chmodSync(full, 493);
91
- return full;
92
- }
93
- //#endregion
94
- export { codexInit as a, clineInit as i, writeInitFile as n, cursorInit as o, claudeInit as r, geminiInit as s, initFor as t };