holycodex 0.2.1 → 0.3.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/README.md CHANGED
@@ -9,7 +9,7 @@ HolyCodex installs one focused Codex toolkit:
9
9
  - 18 on-demand skills for programming, debugging, frontend, LSP, AST search, TDD, security research, planning, handoffs, goal definition, compression, and related workflows.
10
10
  - Three optional subagents: `explorer` for internal inspection, `librarian` for external research, and `worker` for bounded implementation.
11
11
  - Four MCP defaults: `git_bash`, `lsp`, `grep_app`, and `context7`.
12
- - Small hooks for readiness, OMO-style intent detection, Windows Git Bash guidance, comment checks, targeted LSP diagnostics, and scoped rules.
12
+ - Small command hooks for readiness and scoped rules.
13
13
  - A Node-compatible installer and prebuilt runtime usable through npm or Bun.
14
14
 
15
15
  The primary agent always owns the task and decisions. Subagents exist only to reduce cost on narrow independent work—not to simulate an organization.
@@ -47,6 +47,8 @@ Installation is noninteractive. It:
47
47
  4. Installs the HolyCodex marketplace, plugin, agents, skills, hooks, and MCP definitions.
48
48
  5. Sets `max_concurrent_threads_per_session = 2` and defaults the root model to GPT-5.6 Sol low only when no root preference exists.
49
49
 
50
+ Codex may still ask you to review and trust the installed command hooks. This security review is the only manual installation step.
51
+
50
52
  Options:
51
53
 
52
54
  ```sh
@@ -70,7 +72,7 @@ Cleanup backs up affected files, removes only HolyCodex-owned configuration and
70
72
 
71
73
  - `plugin/skills/` — shipped skill catalogue and on-demand references.
72
74
  - `plugin/agents/` — the three cost-focused subagent definitions.
73
- - `plugin/hooks/` — readiness and lightweight behavior hooks.
75
+ - `plugin/hooks/` — supported command hooks for readiness and scoped rules.
74
76
  - `plugin/.mcp.json` — local and remote MCP defaults.
75
77
  - `plugin/runtime/` — prebuilt Node-compatible CLI, rules, Git Bash, and LSP runtime.
76
78
  - `src/` — installer, cleanup, bootstrap, and scoped-rules source.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "holycodex",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Lean Codex-only agent toolkit for ChatGPT Plus",
5
5
  "keywords": [
6
6
  "agents",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "holycodex",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Lean Codex-only agents, skills, hooks, and MCP defaults.",
5
5
  "author": {
6
6
  "name": "David Basile Filho",
@@ -10,20 +10,14 @@
10
10
  "repository": "https://github.com/davidbasilefilho/holycodex",
11
11
  "license": "SUL-1.0",
12
12
  "skills": "./skills/",
13
- "hooks": [
14
- "./hooks/hooks.json"
15
- ],
16
13
  "mcpServers": "./.mcp.json",
17
14
  "interface": {
18
15
  "displayName": "HolyCodex",
19
16
  "shortDescription": "Codex agents, routed skills, scoped rules, Git Bash, LSP, code search, and docs lookup.",
20
17
  "longDescription": "Use HolyCodex agents only for narrow delegated exploration, research, or isolated implementation. Skills declare their own triggers. Use git_bash for reliable Windows shell execution, lsp for semantic diagnostics and navigation, grep_app for public code examples, and context7 for current library documentation.",
18
+ "defaultPrompt": "Use HolyCodex to implement and verify this task.",
21
19
  "developerName": "David Basile Filho",
22
20
  "category": "Developer Tools",
23
- "capabilities": [
24
- "Hooks",
25
- "MCP Tools",
26
- "Code Intelligence"
27
- ]
21
+ "capabilities": ["Hooks", "MCP Tools", "Code Intelligence"]
28
22
  }
29
23
  }
@@ -4,10 +4,6 @@
4
4
  {
5
5
  "matcher": "*",
6
6
  "hooks": [
7
- {
8
- "type": "prompt",
9
- "prompt": "HolyCodex default: first state `I detect [intent type] - [reason]. [What I'm doing now].` This commits same-turn follow-through. Answer/review/diagnose/plan requests inspect and report; build/fix requests implement and verify. Status reports then continues active work. Work direct by default. Batch discovery. Always use the enabled git_bash MCP for shell commands. Use update_plan for multi-step work. Primary agent keeps control. Subagents only reduce cost; never simulate an organization. Max two narrow independent subagents; never recursive, duplicate, or full-history fork. Preserve user changes. Smallest root fix. Personally exercise artifact through matching surface. After three materially different failures, stop editing and ask one precise question. Load only path-relevant deduplicated rules; never reinject AGENTS.md. Sol/Terra allow low or medium reasoning; Luna allows low, medium, high. Final leads with result and proof."
10
- },
11
7
  {
12
8
  "type": "command",
13
9
  "command": "node \"${PLUGIN_ROOT}/runtime/bootstrap.js\"",
@@ -36,33 +32,7 @@
36
32
  ]
37
33
  }
38
34
  ],
39
- "PreToolUse": [
40
- {
41
- "matcher": "exec_command",
42
- "hooks": [
43
- { "type": "prompt", "prompt": "Use the enabled git_bash MCP for every shell command." }
44
- ]
45
- }
46
- ],
47
35
  "PostToolUse": [
48
- {
49
- "matcher": "apply_patch|Write|Edit",
50
- "hooks": [
51
- {
52
- "type": "prompt",
53
- "prompt": "Check new comments. Remove stale, redundant, or narrative comments; preserve required directives and rationale."
54
- }
55
- ]
56
- },
57
- {
58
- "matcher": "apply_patch|Write|Edit",
59
- "hooks": [
60
- {
61
- "type": "prompt",
62
- "prompt": "Run targeted LSP diagnostics for edited supported files only."
63
- }
64
- ]
65
- },
66
36
  {
67
37
  "matcher": "^apply_patch$",
68
38
  "hooks": [
@@ -79,7 +49,6 @@
79
49
  {
80
50
  "matcher": "*",
81
51
  "hooks": [
82
- { "type": "prompt", "prompt": "Reset scoped rule and LSP diagnostic caches." },
83
52
  {
84
53
  "type": "command",
85
54
  "command": "node \"${PLUGIN_ROOT}/runtime/rules.js\"",
@@ -120,7 +120,7 @@ function paths(home = process.env.CODEX_HOME ?? join(homedir(), ".codex")) {
120
120
  home,
121
121
  config: join(home, "config.toml"),
122
122
  cacheRoot,
123
- cache: join(cacheRoot, "0.2.1"),
123
+ cache: join(cacheRoot, "0.3.0"),
124
124
  agents: join(home, "holycodex", "agents"),
125
125
  legacy: [
126
126
  join(home, "plugins", "cache", "sisyphuslabs", "omo"),
@@ -208,7 +208,7 @@ async function cleanup(_options) {
208
208
  }
209
209
  //#endregion
210
210
  //#region src/cli.ts
211
- var VERSION = "0.2.1";
211
+ var VERSION = "0.3.0";
212
212
  var HELP = `HolyCodex ${VERSION}\n\nUsage: holycodex <install|cleanup> [options]\n\nOptions:\n --help Show help\n --version Show version\n --no-tui Accepted; commands are noninteractive\n --codex-autonomous Set autonomous Codex permissions\n --json Print machine-readable result\n`;
213
213
  async function main() {
214
214
  const args = process$1.argv.slice(2);
@@ -112,9 +112,10 @@ async function runGitBashCommand(input) {
112
112
  stderr
113
113
  };
114
114
  }
115
+ const env = input.env === void 0 ? void 0 : Object.fromEntries(Object.entries(input.env).filter(([key]) => key.toLowerCase() !== "original_path"));
115
116
  const child = spawn(input.bashPath, ["-lc", input.command], {
116
117
  cwd: input.cwd,
117
- env: input.env,
118
+ env,
118
119
  windowsHide: true,
119
120
  stdio: [
120
121
  "ignore",
@@ -165,7 +166,7 @@ async function handleGitBashMcpRequest(input, options = {}) {
165
166
  capabilities: { tools: { listChanged: false } },
166
167
  serverInfo: {
167
168
  name: "git_bash",
168
- version: "0.2.1"
169
+ version: "0.3.0"
169
170
  },
170
171
  protocolVersion: protocolVersionFromInput(input) ?? "2024-11-05"
171
172
  });
@@ -190,7 +191,7 @@ async function runMcpStdioServer(input, output, options = {}) {
190
191
  });
191
192
  }
192
193
  async function callTool(id, name, args, options) {
193
- if (name === "which_bash") return toolResponse(id, whichBashPayload(resolve$1(options)));
194
+ if (name === "which_bash") return toolResponse(id, JSON.stringify(resolve$1(options), null, 2));
194
195
  if (name === "diagnose") return toolResponse(id, diagnosePayload(resolve$1(options), platformFromOptions(options)));
195
196
  if (name === "run") return await runToolResponse(id, args, options);
196
197
  return toolResponse(id, `Unknown git_bash tool: ${name}`, true);
@@ -204,15 +205,16 @@ async function runToolResponse(id, args, options) {
204
205
  const timeoutMs = parseTimeoutMs(args.timeout ?? args.timeout_ms, options);
205
206
  if (timeoutMs === null) return toolResponse(id, `run.timeout must be an integer between 1 and ${MAX_TIMEOUT_MS}.`, true);
206
207
  const resolution = resolve$1(options);
207
- if (!resolution.found || resolution.path === null) return toolResponse(id, whichBashPayload(resolution), true);
208
+ if (!resolution.found || resolution.path === null) return toolResponse(id, JSON.stringify(resolution, null, 2), true);
208
209
  try {
209
- return toolResponse(id, runPayload(await (options.runGitBash ?? runGitBashCommand)({
210
+ const result = await (options.runGitBash ?? runGitBashCommand)({
210
211
  bashPath: resolution.path,
211
212
  command,
212
213
  cwd,
213
214
  timeoutMs,
214
215
  env: options.env ?? process.env
215
- })));
216
+ });
217
+ return toolResponse(id, JSON.stringify(result, null, 2));
216
218
  } catch (error) {
217
219
  return toolResponse(id, error instanceof Error ? error.message : String(error), true);
218
220
  }
@@ -286,9 +288,6 @@ function resolve$1(options) {
286
288
  function platformFromOptions(options) {
287
289
  return options.platform ?? process.platform;
288
290
  }
289
- function whichBashPayload(resolution) {
290
- return JSON.stringify(resolution, null, 2);
291
- }
292
291
  function diagnosePayload(resolution, platform) {
293
292
  const enabled = platform === "win32" && resolution.found && resolution.path !== null;
294
293
  return JSON.stringify({
@@ -298,9 +297,6 @@ function diagnosePayload(resolution, platform) {
298
297
  resolution
299
298
  }, null, 2);
300
299
  }
301
- function runPayload(result) {
302
- return JSON.stringify(result, null, 2);
303
- }
304
300
  function toolResponse(id, text, isError = false) {
305
301
  return successResponse(id, {
306
302
  content: [{
@@ -2476,14 +2476,11 @@ async function executeLspInstallDecision(params) {
2476
2476
  errorKind: "unknown_server"
2477
2477
  }, true);
2478
2478
  recordInstallDecision(serverId, decision);
2479
- return text(`Recorded install decision for '${serverId}': ${decision}. ${decisionFollowUp(decision)}`, {
2479
+ return text(`Recorded install decision for '${serverId}': ${decision}. ${decision === "declined" ? "Future LSP lookups for this server stay quiet; proceed without LSP." : "Future LSP lookups keep install instructions without asking the user."}`, {
2480
2480
  serverId,
2481
2481
  decision
2482
2482
  });
2483
2483
  }
2484
- function decisionFollowUp(decision) {
2485
- return decision === "declined" ? "Future LSP lookups for this server stay quiet; proceed without LSP." : "Future LSP lookups keep install instructions without asking the user.";
2486
- }
2487
2484
  //#endregion
2488
2485
  //#region packages/lsp-core/src/tools/navigation.ts
2489
2486
  async function executeLspGotoDefinition(params, signal) {
@@ -3065,20 +3062,17 @@ var LSP_MCP_TOOLS = [
3065
3062
  //#endregion
3066
3063
  //#region packages/lsp-core/src/tools/runtime.ts
3067
3064
  async function executeLspTool(name, params, signal) {
3068
- const tool = LSP_MCP_TOOLS.find((candidate) => matchesToolName(candidate, name));
3065
+ const tool = LSP_MCP_TOOLS.find((candidate) => candidate.name === name || (candidate.aliases?.includes(name) ?? false));
3069
3066
  if (!tool) throw new Error(`Unknown LSP tool: ${name}`);
3070
3067
  return tool.execute(params, signal);
3071
3068
  }
3072
- function matchesToolName(tool, name) {
3073
- return tool.name === name || (tool.aliases?.includes(name) ?? false);
3074
- }
3075
3069
  function coerceToolArguments(value) {
3076
3070
  return isRecord(value) ? value : {};
3077
3071
  }
3078
3072
  //#endregion
3079
3073
  //#region packages/lsp-core/src/mcp.ts
3080
3074
  var SERVER_NAME = "lsp";
3081
- var SERVER_VERSION = "0.2.1";
3075
+ var SERVER_VERSION = "0.3.0";
3082
3076
  async function handleLspMcpRequest(input) {
3083
3077
  if (!isPlainRecord(input)) return errorResponse(null, -32600, "Invalid Request");
3084
3078
  const id = jsonRpcId(input["id"]);
@@ -3445,7 +3439,7 @@ function daemonUnreachableResult(paths, error) {
3445
3439
  content: [{
3446
3440
  type: "text",
3447
3441
  text: [
3448
- `LSP daemon unreachable: ${errorText(error)}.`,
3442
+ `LSP daemon unreachable: ${error instanceof Error ? error.message : String(error)}.`,
3449
3443
  "The MCP server is a thin proxy and never runs language servers in-process.",
3450
3444
  `Socket: ${paths.socket}`,
3451
3445
  `Logs: ${paths.log}`,
@@ -3501,9 +3495,6 @@ function toToolResult(message) {
3501
3495
  details: result["details"]
3502
3496
  };
3503
3497
  }
3504
- function errorText(error) {
3505
- return error instanceof Error ? error.message : String(error);
3506
- }
3507
3498
  //#endregion
3508
3499
  //#region packages/lsp-daemon/src/proxy.ts
3509
3500
  async function runMcpStdioProxy(options = {}) {