javi-forge 1.35.0 → 1.36.0
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/assets/claude-hooks/javi-forge-skillguard-pre-tool-use.mjs +97 -29
- package/assets/claude-hooks/manifest.json +1 -1
- package/dist/cli/dispatch/hooks.d.ts +9 -2
- package/dist/cli/dispatch/hooks.js +22 -8
- package/dist/commands/codex-hooks.d.ts +26 -0
- package/dist/commands/codex-hooks.js +104 -0
- package/dist/lib/__fixtures__/claude-hook-ownership.d.ts +6 -0
- package/dist/lib/__fixtures__/claude-hook-ownership.js +7 -1
- package/dist/lib/__fixtures__/fake-secure-fs.d.ts +9 -1
- package/dist/lib/__fixtures__/fake-secure-fs.js +15 -0
- package/dist/lib/agent-adapter.d.ts +56 -0
- package/dist/lib/agent-adapter.js +88 -0
- package/dist/lib/claude-hook-manager.js +3 -2
- package/dist/lib/claude-hook-settings.d.ts +3 -3
- package/dist/lib/claude-hook-settings.js +3 -3
- package/dist/lib/codex-hook-manager.d.ts +161 -0
- package/dist/lib/codex-hook-manager.js +531 -0
- package/dist/lib/secure-fs-posix.d.ts +20 -2
- package/dist/lib/secure-fs-posix.js +162 -24
- package/dist/lib/secure-fs-transaction.d.ts +40 -6
- package/dist/lib/secure-fs-transaction.js +60 -22
- package/dist/lib/secure-fs-windows.js +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent adapter registry (agent-agnostic slice 2). One descriptor per host
|
|
3
|
+
* (`claude`, `codex`) capturing the per-agent facts the SkillGuard installer and
|
|
4
|
+
* doctor need: config paths, the protected managed set, the project-root source,
|
|
5
|
+
* the settings-schema validator (SHARED — both hosts use the identical hooks
|
|
6
|
+
* schema), the managed marker, the deny protocol, and the trust model.
|
|
7
|
+
*
|
|
8
|
+
* This descriptor is additive: Codex is routed through it, while Claude keeps its
|
|
9
|
+
* existing, byte-identical runtime path (the descriptor only DESCRIBES Claude; it
|
|
10
|
+
* does not change how the Claude command executes). The CLI dispatch decides the
|
|
11
|
+
* valid `hooks <sub> <agent>` target set through `isAgentId` (backed by the
|
|
12
|
+
* `AGENT_ADAPTERS` keys) — this registry is the single source of agent truth, and
|
|
13
|
+
* a new agent added here cannot be silently dropped: the dispatch's command-loader
|
|
14
|
+
* map is typed `Record<AgentId, …>`, so omitting a loader is a compile error.
|
|
15
|
+
*/
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import { ASSET_NAME } from "./__fixtures__/claude-hook-ownership.js";
|
|
18
|
+
import { validateSettingsShape } from "./claude-hook-settings.js";
|
|
19
|
+
import { codexConfigPaths, codexTrustGrantCommand, hasCodexTrustEntry, } from "./codex-hook-manager.js";
|
|
20
|
+
const CLAUDE_MANAGED_SET = [
|
|
21
|
+
".claude/settings.json",
|
|
22
|
+
".claude/settings.local.json",
|
|
23
|
+
".claude/CLAUDE.md",
|
|
24
|
+
"CLAUDE.md",
|
|
25
|
+
".javi-forge/ci.yaml",
|
|
26
|
+
".claude/hooks/",
|
|
27
|
+
".claude/agents/",
|
|
28
|
+
".claude/skills/",
|
|
29
|
+
];
|
|
30
|
+
const CODEX_MANAGED_SET = [
|
|
31
|
+
".codex/hooks.json",
|
|
32
|
+
".claude/settings.json",
|
|
33
|
+
".claude/settings.local.json",
|
|
34
|
+
".claude/CLAUDE.md",
|
|
35
|
+
"CLAUDE.md",
|
|
36
|
+
".javi-forge/ci.yaml",
|
|
37
|
+
".claude/hooks/",
|
|
38
|
+
".claude/agents/",
|
|
39
|
+
".claude/skills/",
|
|
40
|
+
];
|
|
41
|
+
export const claudeAdapter = {
|
|
42
|
+
id: "claude",
|
|
43
|
+
configPaths(projectDir) {
|
|
44
|
+
return {
|
|
45
|
+
hooksFile: path.join(projectDir, ".claude", "hooks", ASSET_NAME),
|
|
46
|
+
settingsFile: path.join(projectDir, ".claude", "settings.json"),
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
managedSet: CLAUDE_MANAGED_SET,
|
|
50
|
+
projectDir: { envVar: "CLAUDE_PROJECT_DIR" },
|
|
51
|
+
settingsSchema: validateSettingsShape,
|
|
52
|
+
marker: "// javi-forge-managed: claude-pretooluse v1",
|
|
53
|
+
emitDeny: "exit2+stderr",
|
|
54
|
+
trust: null,
|
|
55
|
+
};
|
|
56
|
+
export const codexAdapter = {
|
|
57
|
+
id: "codex",
|
|
58
|
+
configPaths(homeDir) {
|
|
59
|
+
const paths = codexConfigPaths(homeDir);
|
|
60
|
+
return { hooksFile: paths.hooksFile, settingsFile: paths.configFile };
|
|
61
|
+
},
|
|
62
|
+
managedSet: CODEX_MANAGED_SET,
|
|
63
|
+
projectDir: { envVar: null },
|
|
64
|
+
settingsSchema: validateSettingsShape,
|
|
65
|
+
marker: "// javi-forge-managed: codex-pretooluse v1",
|
|
66
|
+
emitDeny: "exit2+stderr",
|
|
67
|
+
trust: {
|
|
68
|
+
detect(configText, hooksFile) {
|
|
69
|
+
return hasCodexTrustEntry(configText, hooksFile)
|
|
70
|
+
? "trusted"
|
|
71
|
+
: "untrusted";
|
|
72
|
+
},
|
|
73
|
+
grantCommand: codexTrustGrantCommand,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
export const AGENT_ADAPTERS = {
|
|
77
|
+
claude: claudeAdapter,
|
|
78
|
+
codex: codexAdapter,
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Whether a raw CLI token names a known agent adapter. Backed by the
|
|
82
|
+
* `AGENT_ADAPTERS` registry so there is ONE source deciding valid targets: adding
|
|
83
|
+
* an adapter to the registry automatically widens the accepted CLI set.
|
|
84
|
+
*/
|
|
85
|
+
export function isAgentId(value) {
|
|
86
|
+
return typeof value === "string" && Object.hasOwn(AGENT_ADAPTERS, value);
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=agent-adapter.js.map
|
|
@@ -14,7 +14,7 @@ import os from "node:os";
|
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
import { CLAUDE_HOOK_ASSETS_DIR } from "../constants.js";
|
|
16
16
|
import { ASSET_MANAGED_MARKER, ASSET_NAME, } from "./__fixtures__/claude-hook-ownership.js";
|
|
17
|
-
import { buildManagedContainer, classifySettingsEntry, isPlainObject, LEGACY_FILE_SHA256, MANAGED_ASSET_ARG, MANAGED_MATCHER, MANAGED_STATUS_PREFIX, planForceReplace, planLegacyCohortExcision, planManagedClaudeHookMerge, scanExecutionFlags, } from "./claude-hook-settings.js";
|
|
17
|
+
import { buildManagedContainer, classifySettingsEntry, isPlainObject, LEGACY_FILE_SHA256, MANAGED_AGENT_ARG, MANAGED_ASSET_ARG, MANAGED_MATCHER, MANAGED_STATUS_PREFIX, planForceReplace, planLegacyCohortExcision, planManagedClaudeHookMerge, scanExecutionFlags, } from "./claude-hook-settings.js";
|
|
18
18
|
import { safeReadFile } from "./safe-read.js";
|
|
19
19
|
import { ACL_DETAIL, probeAclCapability, selectSecureFs, } from "./secure-fs-posix.js";
|
|
20
20
|
import { runTransaction, } from "./secure-fs-transaction.js";
|
|
@@ -174,8 +174,9 @@ function settingsSignals(value, classification, currentAssetSha) {
|
|
|
174
174
|
const commandShapeExact = handler.type === "command" &&
|
|
175
175
|
handler.command === "node" &&
|
|
176
176
|
Array.isArray(args) &&
|
|
177
|
-
args.length ===
|
|
177
|
+
args.length === 2 &&
|
|
178
178
|
args[0] === MANAGED_ASSET_ARG &&
|
|
179
|
+
args[1] === MANAGED_AGENT_ARG &&
|
|
179
180
|
handler.timeout === 30;
|
|
180
181
|
let assetSettingsConsistent = false;
|
|
181
182
|
if (typeof handler.statusMessage === "string" &&
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* removal/merge PLANNING only. Identity is always recomputed from observed
|
|
9
9
|
* structure; a marker only claims ownership, it never proves it.
|
|
10
10
|
*/
|
|
11
|
-
import { ASSET_SHA_PLACEHOLDER, LEGACY_FILE_SHA256, MANAGED_ASSET_ARG, MANAGED_MATCHER, MANAGED_STATUS_PREFIX } from "./__fixtures__/claude-hook-ownership.js";
|
|
12
|
-
export { ASSET_SHA_PLACEHOLDER, LEGACY_FILE_SHA256, MANAGED_ASSET_ARG, MANAGED_MATCHER, MANAGED_STATUS_PREFIX, };
|
|
11
|
+
import { ASSET_SHA_PLACEHOLDER, LEGACY_FILE_SHA256, MANAGED_AGENT_ARG, MANAGED_ASSET_ARG, MANAGED_MATCHER, MANAGED_STATUS_PREFIX } from "./__fixtures__/claude-hook-ownership.js";
|
|
12
|
+
export { ASSET_SHA_PLACEHOLDER, LEGACY_FILE_SHA256, MANAGED_AGENT_ARG, MANAGED_ASSET_ARG, MANAGED_MATCHER, MANAGED_STATUS_PREFIX, };
|
|
13
13
|
/** The nine independent component states (identical for asset and settings). */
|
|
14
14
|
export type ClaudeHookComponentState = "absent" | "managed-current" | "released-outdated" | "exact-legacy" | "edited-managed" | "foreign" | "symlink" | "non-regular" | "malformed";
|
|
15
15
|
/** A released settings-entry identity: version plus placeholder-normalized hash. */
|
|
@@ -149,7 +149,7 @@ export declare function planManagedClaudeHookMerge(parsed: unknown, currentAsset
|
|
|
149
149
|
export interface ManagedHandler {
|
|
150
150
|
type: "command";
|
|
151
151
|
command: "node";
|
|
152
|
-
args: [string];
|
|
152
|
+
args: [string, string];
|
|
153
153
|
timeout: number;
|
|
154
154
|
statusMessage: string;
|
|
155
155
|
}
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* structure; a marker only claims ownership, it never proves it.
|
|
10
10
|
*/
|
|
11
11
|
import { createHash } from "node:crypto";
|
|
12
|
-
import { ASSET_SHA_PLACEHOLDER, LEGACY_COHORT, LEGACY_FILE_SHA256, MANAGED_ASSET_ARG, MANAGED_MATCHER, MANAGED_STATUS_PREFIX, } from "./__fixtures__/claude-hook-ownership.js";
|
|
13
|
-
export { ASSET_SHA_PLACEHOLDER, LEGACY_FILE_SHA256, MANAGED_ASSET_ARG, MANAGED_MATCHER, MANAGED_STATUS_PREFIX, };
|
|
12
|
+
import { ASSET_SHA_PLACEHOLDER, LEGACY_COHORT, LEGACY_FILE_SHA256, MANAGED_AGENT_ARG, MANAGED_ASSET_ARG, MANAGED_MATCHER, MANAGED_STATUS_PREFIX, } from "./__fixtures__/claude-hook-ownership.js";
|
|
13
|
+
export { ASSET_SHA_PLACEHOLDER, LEGACY_FILE_SHA256, MANAGED_AGENT_ARG, MANAGED_ASSET_ARG, MANAGED_MATCHER, MANAGED_STATUS_PREFIX, };
|
|
14
14
|
// Shape helpers
|
|
15
15
|
export function isPlainObject(value) {
|
|
16
16
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -443,7 +443,7 @@ export function buildManagedContainer(currentAssetSha) {
|
|
|
443
443
|
{
|
|
444
444
|
type: "command",
|
|
445
445
|
command: "node",
|
|
446
|
-
args: [MANAGED_ASSET_ARG],
|
|
446
|
+
args: [MANAGED_ASSET_ARG, MANAGED_AGENT_ARG],
|
|
447
447
|
timeout: MANAGED_TIMEOUT,
|
|
448
448
|
statusMessage: `${MANAGED_STATUS_PREFIX}${currentAssetSha}`,
|
|
449
449
|
},
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex PreToolUse ownership manager (agent-agnostic slice 2). Installs the
|
|
3
|
+
* SAME shipped SkillGuard `.mjs` asset as a Codex `PreToolUse` hook by writing
|
|
4
|
+
* `~/.codex/hooks.json` + setting `[features] hooks = true` in
|
|
5
|
+
* `~/.codex/config.toml`, through the identical secure-fs transaction the Claude
|
|
6
|
+
* installer uses (no weaker path). It NEVER modifies the guard asset, the pure
|
|
7
|
+
* `evaluate*` engine, or Claude's observable behavior.
|
|
8
|
+
*
|
|
9
|
+
* TRUST (highest-risk surface — engram id 15743, codex-cli 0.147.0, verified
|
|
10
|
+
* live 2026-08-18): codex hooks are stable + default-ON, but each hook needs a
|
|
11
|
+
* `trusted_hash` recorded in `config.toml` under
|
|
12
|
+
* `[hooks.state."<abs-hook-path>:pre_tool_use:0:0"]`; an UNTRUSTED hook is
|
|
13
|
+
* SILENTLY SKIPPED unless `--dangerously-bypass-hook-trust`. There is NO
|
|
14
|
+
* `codex hooks trust` subcommand (confirmed: `codex --help` has no `hooks`
|
|
15
|
+
* command). So we DO NOT compute-and-write a trusted_hash we cannot prove
|
|
16
|
+
* reproducible (a wrong-but-present hash would leave the hook skipped while
|
|
17
|
+
* making doctor believe it is trusted — the exact fail-open theater this arc
|
|
18
|
+
* exists to kill). Instead: install writes the files + REPORTS the trust step,
|
|
19
|
+
* and the doctor DETECTS the missing trust entry and reports `blocked`
|
|
20
|
+
* (untrusted = NOT running).
|
|
21
|
+
*
|
|
22
|
+
* STALE-HASH INVALIDATION: the trust key path is STABLE across upgrades, so a
|
|
23
|
+
* rewrite of hooks.json (asset/command/timeout change) leaves the recorded
|
|
24
|
+
* `trusted_hash` stale — Codex silently skips the hook while the header
|
|
25
|
+
* persists (doctor would wrongly stay `trusted`). So whenever install/repair
|
|
26
|
+
* REWRITES the managed hooks.json, it REMOVES our `[hooks.state."<hooksFile>:*"]`
|
|
27
|
+
* table(s) in the same transactional config write (foreign rows untouched),
|
|
28
|
+
* reverting the doctor to `untrusted → blocked` until the user re-approves. An
|
|
29
|
+
* idempotent no-op install (unchanged hook content) never touches the table.
|
|
30
|
+
*/
|
|
31
|
+
import { type AssetManifestEntry, type ExecutionReport, type NodeOnPathProbe } from "./claude-hook-manager.js";
|
|
32
|
+
import { type ClaudeHookComponentState } from "./claude-hook-settings.js";
|
|
33
|
+
import { type SpawnFn } from "./secure-fs-posix.js";
|
|
34
|
+
import { type PlatformSecureFs } from "./secure-fs-transaction.js";
|
|
35
|
+
export type { NodeOnPathProbe };
|
|
36
|
+
/** The shipped, in-package guard asset the Codex hook references by ABSOLUTE path. */
|
|
37
|
+
export declare const SHIPPED_CODEX_ASSET: string;
|
|
38
|
+
/** Codex manifest view — only the asset entry is needed for currency. */
|
|
39
|
+
export interface Manifest {
|
|
40
|
+
asset: AssetManifestEntry;
|
|
41
|
+
}
|
|
42
|
+
export interface CodexConfigPaths {
|
|
43
|
+
codexDir: string;
|
|
44
|
+
hooksFile: string;
|
|
45
|
+
configFile: string;
|
|
46
|
+
}
|
|
47
|
+
/** Resolve `~/.codex/{hooks.json,config.toml}` for a given home directory. */
|
|
48
|
+
export declare function codexConfigPaths(homeDir: string): CodexConfigPaths;
|
|
49
|
+
/** The exact `command` string the managed Codex hook runs (single-string form). */
|
|
50
|
+
export declare function expectedCodexCommand(assetPath: string): string;
|
|
51
|
+
/** The interactive step that establishes hook trust (there is no non-interactive subcommand). */
|
|
52
|
+
export declare function codexTrustGrantCommand(hooksFile: string): string;
|
|
53
|
+
/** Read the `[features] hooks` flag: "true" | "false" | "absent". */
|
|
54
|
+
export declare function parseFeaturesHooks(text: string): "true" | "false" | "absent";
|
|
55
|
+
/**
|
|
56
|
+
* True when `config.toml` records a trust table for THIS hook path, i.e. a
|
|
57
|
+
* `[hooks.state."<hooksFile>:pre_tool_use:0:0"]` header. Fail-closed: a trust
|
|
58
|
+
* entry for a different path does not count.
|
|
59
|
+
*
|
|
60
|
+
* NOTE (fail-open the arc kills): presence of the header is NOT proof the hook
|
|
61
|
+
* is still trusted — Codex records a `trusted_hash` under it, and a hook whose
|
|
62
|
+
* content was rewritten (e.g. an asset/command/timeout upgrade) has a STALE hash
|
|
63
|
+
* → Codex silently skips it and re-prompts. We cannot recompute Codex's hash to
|
|
64
|
+
* compare here, so instead the installer INVALIDATES this table whenever it
|
|
65
|
+
* rewrites the managed hooks.json (see `removeCodexTrustEntries`), reverting the
|
|
66
|
+
* doctor to `untrusted → blocked` until the user re-approves in codex.
|
|
67
|
+
*/
|
|
68
|
+
export declare function hasCodexTrustEntry(text: string, hooksFile: string): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Remove every `[hooks.state."<hooksFile>:*"]` table (header + body lines) keyed
|
|
71
|
+
* on OUR managed hooks.json path, preserving all other content — including
|
|
72
|
+
* FOREIGN `hooks.state` rows for other hooks files. Used to invalidate a now-
|
|
73
|
+
* stale `trusted_hash` when the managed hooks.json content is rewritten: the
|
|
74
|
+
* trust-key path is stable across upgrades, so a rewritten hook keeps its old
|
|
75
|
+
* (now wrong) recorded hash and would be silently skipped by Codex while the
|
|
76
|
+
* header persisted. Dropping the table forces the doctor back to `untrusted`
|
|
77
|
+
* until the user re-approves the hook in codex.
|
|
78
|
+
*/
|
|
79
|
+
export declare function removeCodexTrustEntries(text: string, hooksFile: string): string;
|
|
80
|
+
/**
|
|
81
|
+
* Ensure `[features] hooks = true`, preserving all other content and idempotent
|
|
82
|
+
* when already true. Only ever INSERTS a line or flips a `hooks = false` inside
|
|
83
|
+
* `[features]`, so it can never corrupt unrelated TOML.
|
|
84
|
+
*/
|
|
85
|
+
export declare function mergeFeaturesHooksTrue(text: string): string;
|
|
86
|
+
export interface CodexHooksClassification {
|
|
87
|
+
state: ClaudeHookComponentState;
|
|
88
|
+
detail?: string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Classify `hooks.json`. Reuses `validateSettingsShape` (the SAME settings-schema
|
|
92
|
+
* validator the Claude classifier uses — the Codex hooks.json schema is
|
|
93
|
+
* identical) and recognizes our managed handler by its exact command string.
|
|
94
|
+
* - malformed → not a valid hooks container
|
|
95
|
+
* - managed-current → our exact command present
|
|
96
|
+
* - released-outdated→ our guard present but at a stale asset path
|
|
97
|
+
* - foreign → other PreToolUse handlers, none of them ours
|
|
98
|
+
* - absent → no PreToolUse handlers at all (installable)
|
|
99
|
+
*/
|
|
100
|
+
export declare function classifyCodexHooksJson(value: unknown, expectedCommand: string): CodexHooksClassification;
|
|
101
|
+
export type CodexTrustState = "trusted" | "untrusted";
|
|
102
|
+
export interface CodexHookDoctorReport {
|
|
103
|
+
healthy: boolean;
|
|
104
|
+
hooksJson: {
|
|
105
|
+
state: ClaudeHookComponentState;
|
|
106
|
+
detail?: string;
|
|
107
|
+
};
|
|
108
|
+
config: {
|
|
109
|
+
featuresHooks: "true" | "false" | "absent";
|
|
110
|
+
readable: boolean;
|
|
111
|
+
};
|
|
112
|
+
asset: {
|
|
113
|
+
state: ClaudeHookComponentState;
|
|
114
|
+
sha256?: string;
|
|
115
|
+
};
|
|
116
|
+
node: {
|
|
117
|
+
available: boolean;
|
|
118
|
+
version?: string;
|
|
119
|
+
satisfiesMinimum: boolean;
|
|
120
|
+
};
|
|
121
|
+
nodeOnPath: NodeOnPathProbe;
|
|
122
|
+
execution: ExecutionReport;
|
|
123
|
+
trust: {
|
|
124
|
+
state: CodexTrustState;
|
|
125
|
+
grantCommand: string;
|
|
126
|
+
};
|
|
127
|
+
remediation: string[];
|
|
128
|
+
}
|
|
129
|
+
export interface CodexDoctorOptions {
|
|
130
|
+
manifest?: Manifest;
|
|
131
|
+
assetPath?: string;
|
|
132
|
+
nodeVersion?: string;
|
|
133
|
+
nodeProbe?: () => Promise<NodeOnPathProbe>;
|
|
134
|
+
}
|
|
135
|
+
export declare function doctorCodexPreToolUse(homeDir?: string, options?: CodexDoctorOptions): Promise<CodexHookDoctorReport>;
|
|
136
|
+
export interface CodexHookMutationResult {
|
|
137
|
+
ok: boolean;
|
|
138
|
+
changed: string[];
|
|
139
|
+
backups: string[];
|
|
140
|
+
report: CodexHookDoctorReport;
|
|
141
|
+
errors: string[];
|
|
142
|
+
warnings: string[];
|
|
143
|
+
}
|
|
144
|
+
export interface CodexHookRunDeps {
|
|
145
|
+
secureFs?: PlatformSecureFs | null;
|
|
146
|
+
clock?: () => Date;
|
|
147
|
+
nonce?: () => string;
|
|
148
|
+
manifest?: Manifest;
|
|
149
|
+
platform?: NodeJS.Platform;
|
|
150
|
+
assetPath?: string;
|
|
151
|
+
nodeProbe?: () => Promise<NodeOnPathProbe>;
|
|
152
|
+
nodeSpawn?: SpawnFn;
|
|
153
|
+
}
|
|
154
|
+
export declare function _runCodex(homeDir: string, _mode: "install" | "repair", _options: {
|
|
155
|
+
force?: boolean;
|
|
156
|
+
}, deps: CodexHookRunDeps): Promise<CodexHookMutationResult>;
|
|
157
|
+
export declare function installCodexPreToolUse(homeDir?: string): Promise<CodexHookMutationResult>;
|
|
158
|
+
export declare function repairCodexPreToolUse(homeDir?: string, options?: {
|
|
159
|
+
force?: boolean;
|
|
160
|
+
}): Promise<CodexHookMutationResult>;
|
|
161
|
+
//# sourceMappingURL=codex-hook-manager.d.ts.map
|