@codyswann/lisa 2.26.0 → 2.26.1
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/codex/hooks-installer.d.ts +7 -0
- package/dist/codex/hooks-installer.d.ts.map +1 -1
- package/dist/codex/hooks-installer.js +45 -3
- package/dist/codex/hooks-installer.js.map +1 -1
- package/dist/codex/scripts/_extract-edit-paths.sh +49 -0
- package/dist/codex/scripts/block-migration-edits.sh +15 -49
- package/dist/codex/scripts/format-on-edit.sh +26 -21
- package/dist/codex/scripts/lint-on-edit.sh +23 -14
- package/dist/codex/scripts/rubocop-on-edit.sh +23 -14
- package/dist/codex/scripts/sg-scan-on-edit.sh +22 -12
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -2
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -2
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -2
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -2
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/scripts/generate-codex-plugin-artifacts.mjs +17 -129
- package/plugins/lisa/hooks/hooks.json +0 -104
- package/plugins/lisa-nestjs/hooks/hooks.json +0 -15
- package/plugins/lisa-rails/hooks/hooks.json +0 -19
- package/plugins/lisa-typescript/hooks/hooks.json +0 -23
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { ProjectType } from "../core/config.js";
|
|
2
2
|
/** Subdirectory inside `.codex/` for Lisa-managed hook scripts */
|
|
3
3
|
export declare const LISA_HOOKS_SUBDIR: string;
|
|
4
|
+
/**
|
|
5
|
+
* Shared shell helper sourced by every edit-aware hook to resolve the file
|
|
6
|
+
* path(s) a tool touches (handles single-file Edit/Write and multi-file
|
|
7
|
+
* apply_patch). Copied alongside the hook scripts whenever an edit hook is
|
|
8
|
+
* installed so the apply_patch parsing lives in exactly one place.
|
|
9
|
+
*/
|
|
10
|
+
export declare const EDIT_PATHS_LIB = "_extract-edit-paths.sh";
|
|
4
11
|
/** Subdirectory inside `.codex/` for Lisa rules content (read by inject-rules) */
|
|
5
12
|
export declare const LISA_RULES_SUBDIR = "lisa-rules";
|
|
6
13
|
/** Filename of the Codex hooks config file inside `.codex/` */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-installer.d.ts","sourceRoot":"","sources":["../../src/codex/hooks-installer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hooks-installer.d.ts","sourceRoot":"","sources":["../../src/codex/hooks-installer.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAUrD,kEAAkE;AAClE,eAAO,MAAM,iBAAiB,QAA6B,CAAC;AAE5D;;;;;GAKG;AACH,eAAO,MAAM,cAAc,2BAA2B,CAAC;AAEvD,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,eAAe,CAAC;AAE9C,+DAA+D;AAC/D,eAAO,MAAM,cAAc,eAAe,CAAC;AA0H3C,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,SAAS,WAAW,EAAE,GACpC,OAAO,CAAC,kBAAkB,CAAC,CA4D7B"}
|
|
@@ -7,10 +7,24 @@
|
|
|
7
7
|
* 3. For inject-rules: also mirror Lisa rules into `.codex/lisa-rules/`
|
|
8
8
|
* 4. Tagged-merge `.codex/hooks.json`
|
|
9
9
|
*
|
|
10
|
-
* Codex hook event support map (vs. Lisa's existing Claude Code hooks)
|
|
10
|
+
* Codex hook event support map (vs. Lisa's existing Claude Code hooks),
|
|
11
|
+
* verified against codex-cli 0.125.0 by source-read + runtime tests:
|
|
11
12
|
* - SessionStart, PreToolUse, PostToolUse, UserPromptSubmit, Stop ✅
|
|
12
13
|
* - PermissionRequest ✅ (Codex-only)
|
|
13
14
|
* - SubagentStart, SessionEnd, Notification, PreCompact ❌ (Codex doesn't have these)
|
|
15
|
+
*
|
|
16
|
+
* Claude hooks intentionally NOT ported (no Codex equivalent):
|
|
17
|
+
* - enforce-team-first.sh — gates Claude's TeamCreate/Skill/ToolSearch agent-
|
|
18
|
+
* team orchestration; Codex's multi-agent model is different.
|
|
19
|
+
* - inject-flow-context.sh — fires on SubagentStart, which Codex lacks.
|
|
20
|
+
* - the SessionEnd `entire` hook — Codex has no SessionEnd event.
|
|
21
|
+
* inject-rules also fires on SubagentStart under Claude; on Codex only its
|
|
22
|
+
* SessionStart variant applies (Codex has no per-subagent start event).
|
|
23
|
+
*
|
|
24
|
+
* Codex does NOT execute plugin-bundled hooks (a `.codex-plugin` `hooks`
|
|
25
|
+
* pointer / `hooks/hooks.json` never fires), so this installer writes hooks
|
|
26
|
+
* into the project's own `.codex/hooks.json` instead. See
|
|
27
|
+
* scripts/generate-codex-plugin-artifacts.mjs for the build-side counterpart.
|
|
14
28
|
* @module codex/hooks-installer
|
|
15
29
|
*/
|
|
16
30
|
import * as fse from "fs-extra";
|
|
@@ -20,6 +34,13 @@ import { fileURLToPath } from "node:url";
|
|
|
20
34
|
import { mergeLisaHooks, parseHooksFile, serializeHooksFile, } from "./hooks-merger.js";
|
|
21
35
|
/** Subdirectory inside `.codex/` for Lisa-managed hook scripts */
|
|
22
36
|
export const LISA_HOOKS_SUBDIR = path.join("hooks", "lisa");
|
|
37
|
+
/**
|
|
38
|
+
* Shared shell helper sourced by every edit-aware hook to resolve the file
|
|
39
|
+
* path(s) a tool touches (handles single-file Edit/Write and multi-file
|
|
40
|
+
* apply_patch). Copied alongside the hook scripts whenever an edit hook is
|
|
41
|
+
* installed so the apply_patch parsing lives in exactly one place.
|
|
42
|
+
*/
|
|
43
|
+
export const EDIT_PATHS_LIB = "_extract-edit-paths.sh";
|
|
23
44
|
/** Subdirectory inside `.codex/` for Lisa rules content (read by inject-rules) */
|
|
24
45
|
export const LISA_RULES_SUBDIR = "lisa-rules";
|
|
25
46
|
/** Filename of the Codex hooks config file inside `.codex/` */
|
|
@@ -85,6 +106,7 @@ const HOOK_CATALOG = [
|
|
|
85
106
|
matcher: WRITE_MATCHER,
|
|
86
107
|
scriptFilename: "format-on-edit.sh",
|
|
87
108
|
forProjectTypes: ["typescript"],
|
|
109
|
+
needsEditPathLib: true,
|
|
88
110
|
},
|
|
89
111
|
{
|
|
90
112
|
id: "lint-on-edit",
|
|
@@ -92,13 +114,15 @@ const HOOK_CATALOG = [
|
|
|
92
114
|
matcher: WRITE_MATCHER,
|
|
93
115
|
scriptFilename: "lint-on-edit.sh",
|
|
94
116
|
forProjectTypes: ["typescript"],
|
|
117
|
+
needsEditPathLib: true,
|
|
95
118
|
},
|
|
96
119
|
{
|
|
97
120
|
id: "sg-scan-on-edit",
|
|
98
121
|
event: "PostToolUse",
|
|
99
122
|
matcher: WRITE_MATCHER,
|
|
100
123
|
scriptFilename: "sg-scan-on-edit.sh",
|
|
101
|
-
forProjectTypes: ["typescript"],
|
|
124
|
+
forProjectTypes: ["typescript", "rails"],
|
|
125
|
+
needsEditPathLib: true,
|
|
102
126
|
},
|
|
103
127
|
{
|
|
104
128
|
id: "rubocop-on-edit",
|
|
@@ -106,6 +130,7 @@ const HOOK_CATALOG = [
|
|
|
106
130
|
matcher: WRITE_MATCHER,
|
|
107
131
|
scriptFilename: "rubocop-on-edit.sh",
|
|
108
132
|
forProjectTypes: ["rails"],
|
|
133
|
+
needsEditPathLib: true,
|
|
109
134
|
},
|
|
110
135
|
{
|
|
111
136
|
id: "block-migration-edits",
|
|
@@ -113,6 +138,7 @@ const HOOK_CATALOG = [
|
|
|
113
138
|
matcher: WRITE_MATCHER,
|
|
114
139
|
scriptFilename: "block-migration-edits.sh",
|
|
115
140
|
forProjectTypes: ["nestjs"],
|
|
141
|
+
needsEditPathLib: true,
|
|
116
142
|
},
|
|
117
143
|
];
|
|
118
144
|
/**
|
|
@@ -138,6 +164,17 @@ export async function installHooks(lisaDir, destDir, detectedTypes) {
|
|
|
138
164
|
await chmod(scriptDest, 0o755);
|
|
139
165
|
return path.join(LISA_HOOKS_SUBDIR, entry.scriptFilename);
|
|
140
166
|
}));
|
|
167
|
+
// Step 1b: copy the shared edit-path helper when any installed hook sources
|
|
168
|
+
// it. Edit-aware hooks (format/lint/sg-scan/rubocop/block-migration) source
|
|
169
|
+
// this for apply_patch path parsing.
|
|
170
|
+
const libFiles = applicable.some(e => e.needsEditPathLib)
|
|
171
|
+
? await (async () => {
|
|
172
|
+
const libDest = path.join(hooksDir, EDIT_PATHS_LIB);
|
|
173
|
+
await copyFile(resolveBundledScript(EDIT_PATHS_LIB), libDest);
|
|
174
|
+
await chmod(libDest, 0o755);
|
|
175
|
+
return [path.join(LISA_HOOKS_SUBDIR, EDIT_PATHS_LIB)];
|
|
176
|
+
})()
|
|
177
|
+
: [];
|
|
141
178
|
// Step 2: mirror rules from Lisa into .codex/lisa-rules/ (only when
|
|
142
179
|
// inject-rules is being installed — i.e., always, since it's a "*" hook)
|
|
143
180
|
const ruleFiles = applicable.some(e => e.id === "inject-rules")
|
|
@@ -150,7 +187,12 @@ export async function installHooks(lisaDir, destDir, detectedTypes) {
|
|
|
150
187
|
const merged = mergeLisaHooks(existing, lisaHookSpecs);
|
|
151
188
|
await writeFile(hooksFilePath, serializeHooksFile(merged), "utf8");
|
|
152
189
|
return {
|
|
153
|
-
managedFiles: Object.freeze([
|
|
190
|
+
managedFiles: Object.freeze([
|
|
191
|
+
...scriptFiles,
|
|
192
|
+
...libFiles,
|
|
193
|
+
...ruleFiles,
|
|
194
|
+
HOOKS_FILENAME,
|
|
195
|
+
]),
|
|
154
196
|
hookEntries: lisaHookSpecs.length,
|
|
155
197
|
};
|
|
156
198
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-installer.js","sourceRoot":"","sources":["../../src/codex/hooks-installer.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"hooks-installer.js","sourceRoot":"","sources":["../../src/codex/hooks-installer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAIL,cAAc,EACd,cAAc,EACd,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAE3B,kEAAkE;AAClE,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AAEvD,kFAAkF;AAClF,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC;AAE9C,+DAA+D;AAC/D,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAE3C;;;;GAIG;AACH,MAAM,aAAa,GAAG,wBAAwB,CAAC;AAwB/C;;;;;;;;GAQG;AACH,MAAM,YAAY,GAAgC;IAChD;QACE,EAAE,EAAE,cAAc;QAClB,KAAK,EAAE,cAAc;QACrB,OAAO,EAAE,EAAE;QACX,cAAc,EAAE,iBAAiB;QACjC,eAAe,EAAE,CAAC,GAAG,CAAC;QACtB,aAAa,EAAE,2CAA2C;KAC3D;IACD;QACE,EAAE,EAAE,cAAc;QAClB,KAAK,EAAE,cAAc;QACrB,OAAO,EAAE,SAAS;QAClB,cAAc,EAAE,iBAAiB;QACjC,eAAe,EAAE,CAAC,GAAG,CAAC;QACtB,aAAa,EAAE,+BAA+B;KAC/C;IACD;QACE,EAAE,EAAE,gBAAgB;QACpB,KAAK,EAAE,cAAc;QACrB,OAAO,EAAE,EAAE;QACX,cAAc,EAAE,mBAAmB;QACnC,eAAe,EAAE,CAAC,GAAG,CAAC;QACtB,aAAa,EAAE,kCAAkC;KAClD;IACD;QACE,EAAE,EAAE,iBAAiB;QACrB,KAAK,EAAE,YAAY;QACnB,OAAO,EAAE,MAAM;QACf,cAAc,EAAE,oBAAoB;QACpC,eAAe,EAAE,CAAC,GAAG,CAAC;QACtB,aAAa,EAAE,+BAA+B;KAC/C;IACD;QACE,EAAE,EAAE,aAAa;QACjB,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,EAAE;QACX,cAAc,EAAE,gBAAgB;QAChC,eAAe,EAAE,CAAC,GAAG,CAAC;KACvB;IACD;QACE,EAAE,EAAE,gBAAgB;QACpB,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,aAAa;QACtB,cAAc,EAAE,mBAAmB;QACnC,eAAe,EAAE,CAAC,YAAY,CAAC;QAC/B,gBAAgB,EAAE,IAAI;KACvB;IACD;QACE,EAAE,EAAE,cAAc;QAClB,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,aAAa;QACtB,cAAc,EAAE,iBAAiB;QACjC,eAAe,EAAE,CAAC,YAAY,CAAC;QAC/B,gBAAgB,EAAE,IAAI;KACvB;IACD;QACE,EAAE,EAAE,iBAAiB;QACrB,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,aAAa;QACtB,cAAc,EAAE,oBAAoB;QACpC,eAAe,EAAE,CAAC,YAAY,EAAE,OAAO,CAAC;QACxC,gBAAgB,EAAE,IAAI;KACvB;IACD;QACE,EAAE,EAAE,iBAAiB;QACrB,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,aAAa;QACtB,cAAc,EAAE,oBAAoB;QACpC,eAAe,EAAE,CAAC,OAAO,CAAC;QAC1B,gBAAgB,EAAE,IAAI;KACvB;IACD;QACE,EAAE,EAAE,uBAAuB;QAC3B,KAAK,EAAE,YAAY;QACnB,OAAO,EAAE,aAAa;QACtB,cAAc,EAAE,0BAA0B;QAC1C,eAAe,EAAE,CAAC,QAAQ,CAAC;QAC3B,gBAAgB,EAAE,IAAI;KACvB;CACF,CAAC;AAUF;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,OAAe,EACf,aAAqC;IAErC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IACxD,MAAM,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC9B,MAAM,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAE9B,MAAM,UAAU,GAAG,oBAAoB,CAAC,aAAa,CAAC,CAAC;IAEvD,wEAAwE;IACxE,MAAM,WAAW,GAAsB,MAAM,OAAO,CAAC,GAAG,CACtD,UAAU,CAAC,GAAG,CAAC,KAAK,EAAC,KAAK,EAAC,EAAE;QAC3B,MAAM,YAAY,GAAG,oBAAoB,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAChE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;QAC7D,MAAM,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QACzC,MAAM,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAC5D,CAAC,CAAC,CACH,CAAC;IAEF,4EAA4E;IAC5E,4EAA4E;IAC5E,qCAAqC;IACrC,MAAM,QAAQ,GAAsB,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;QAC1E,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;YAChB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;YACpD,MAAM,QAAQ,CAAC,oBAAoB,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC;YAC9D,MAAM,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC,EAAE;QACN,CAAC,CAAC,EAAE,CAAC;IAEP,oEAAoE;IACpE,yEAAyE;IACzE,MAAM,SAAS,GAAsB,UAAU,CAAC,IAAI,CAClD,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,cAAc,CAC7B;QACC,CAAC,CAAC,CAAC,MAAM,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAC/D,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,CACnC;QACH,CAAC,CAAC,EAAE,CAAC;IAEP,kCAAkC;IAClC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,aAAa,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAC3C,kBAAkB,CAAC,KAAK,EAAE,OAAO,CAAC,CACnC,CAAC;IACF,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACvD,MAAM,SAAS,CAAC,aAAa,EAAE,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IAEnE,OAAO;QACL,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC;YAC1B,GAAG,WAAW;YACd,GAAG,QAAQ;YACX,GAAG,SAAS;YACZ,cAAc;SACf,CAAC;QACF,WAAW,EAAE,aAAa,CAAC,MAAM;KAClC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,oBAAoB,CAC3B,aAAqC;IAErC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAS,aAAa,CAAC,CAAC;IACnD,OAAO,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACjC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CACjE,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,kBAAkB,CACzB,KAAuB,EACvB,QAAgB;IAEhB,MAAM,OAAO,GAAG,oEAAoE,iBAAiB,IAAI,KAAK,CAAC,cAAc,GAAG,CAAC;IACjI,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO;QACP,GAAG,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS;YACnC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE;YACxC,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,aAAa,CAAC,aAAqB;IAChD,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;QAC3C,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAClD,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;;GAMG;AACH,SAAS,oBAAoB,CAAC,QAAgB;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,WAAW,CACxB,OAAe,EACf,YAAoB,EACpB,aAAqC;IAErC,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;IAE3E,4DAA4D;IAC5D,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,GAAG,CACrC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAC,UAAU,EAAC,EAAE;QACjC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QACrE,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;YACvC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,EAAc,EAAE,CAAC;QAC9C,CAAC;QACD,MAAM,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CACrD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CACrB,CAAC;QACF,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC,CAAC,CACH,CAAC;IAEF,0DAA0D;IAC1D,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IAC7D,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC/C,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAC7B,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,CAClD,CAAC;QACF,MAAM,IAAI,KAAK,CACb,iCAAiC,SAAS,IAAI,SAAS,oCAAoC,CAC5F,CAAC;IACJ,CAAC;IAED,mEAAmE;IACnE,MAAM,OAAO,CAAC,GAAG,CACf,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,CACzC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CACf,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CACpE,CACF,CACF,CACF,CAAC;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Lisa-managed Codex hook helper (sourced, not executed directly).
|
|
3
|
+
#
|
|
4
|
+
# Provides `lisa_extract_edit_paths`, the single source of truth for turning a
|
|
5
|
+
# Codex Pre/PostToolUse hook envelope into the list of file paths the tool
|
|
6
|
+
# touches. Every edit-aware Lisa hook (format/lint/sg-scan/rubocop/block-
|
|
7
|
+
# migration) sources this so the apply_patch parsing lives in exactly one place.
|
|
8
|
+
#
|
|
9
|
+
# Tool envelope shapes (verified against codex-cli 0.125.0 by capturing real
|
|
10
|
+
# hook stdin):
|
|
11
|
+
# Edit / Write → tool_input.file_path (single string)
|
|
12
|
+
# apply_patch → tool_input.command (a STRING containing the full patch,
|
|
13
|
+
# NOT an array — there is no command[1])
|
|
14
|
+
#
|
|
15
|
+
# An apply_patch patch encodes its targets as header lines:
|
|
16
|
+
# *** Add File: <path>
|
|
17
|
+
# *** Update File: <path>
|
|
18
|
+
# *** Delete File: <path>
|
|
19
|
+
# A single patch may carry MANY files, so callers must loop over the output.
|
|
20
|
+
|
|
21
|
+
# Print, one per line, every file path the tool envelope intends to write.
|
|
22
|
+
# Emits nothing (and returns 0) when jq is unavailable or no path is found, so
|
|
23
|
+
# callers can fail open.
|
|
24
|
+
#
|
|
25
|
+
# $1 - the full hook stdin JSON
|
|
26
|
+
lisa_extract_edit_paths() {
|
|
27
|
+
local json="$1"
|
|
28
|
+
command -v jq >/dev/null 2>&1 || return 0
|
|
29
|
+
|
|
30
|
+
local tool_name
|
|
31
|
+
tool_name="$(printf '%s' "$json" | jq -r '.tool_name // .tool // empty')"
|
|
32
|
+
|
|
33
|
+
if [ "$tool_name" = "apply_patch" ]; then
|
|
34
|
+
local patch_text
|
|
35
|
+
patch_text="$(printf '%s' "$json" | jq -r '.tool_input.command // empty')"
|
|
36
|
+
[ -n "$patch_text" ] || return 0
|
|
37
|
+
# Walk the patch line-by-line with bash-native string ops (NOT grep/sed on
|
|
38
|
+
# JSON — see .claude/rules/PROJECT_RULES.md) to pull out every file header.
|
|
39
|
+
while IFS= read -r line; do
|
|
40
|
+
case "$line" in
|
|
41
|
+
"*** Add File: "* | "*** Update File: "* | "*** Delete File: "*)
|
|
42
|
+
printf '%s\n' "${line#*File: }"
|
|
43
|
+
;;
|
|
44
|
+
esac
|
|
45
|
+
done <<<"$patch_text"
|
|
46
|
+
else
|
|
47
|
+
printf '%s' "$json" | jq -r '.tool_input.file_path // empty'
|
|
48
|
+
fi
|
|
49
|
+
}
|
|
@@ -4,59 +4,23 @@
|
|
|
4
4
|
# to regenerate from entity diffs instead — hand-written migrations drift
|
|
5
5
|
# from entity metadata and break the schema/migration contract.
|
|
6
6
|
#
|
|
7
|
-
# Codex blocks the tool call when
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
# apply_patch → tool_input.command (["apply_patch", "<patch>"])
|
|
13
|
-
#
|
|
14
|
-
# The patch text encodes target file paths via "*** Update File: <path>" /
|
|
15
|
-
# "*** Add File: <path>" / "*** Delete File: <path>" directives. We must
|
|
16
|
-
# extract every such path so apply_patch can't sneak past this guard.
|
|
17
|
-
set -euo pipefail
|
|
7
|
+
# Codex blocks the tool call when the script exits non-zero with a deny message
|
|
8
|
+
# on stderr (exit 2). The shared extractor resolves every target path from the
|
|
9
|
+
# tool envelope — including multi-file apply_patch patches — so an edit can't
|
|
10
|
+
# slip a migration change past this guard.
|
|
11
|
+
set -uo pipefail
|
|
18
12
|
|
|
19
13
|
JSON_INPUT="$(cat)"
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
exit 0
|
|
25
|
-
fi
|
|
26
|
-
|
|
27
|
-
# Determine which tool fired. Codex puts the tool name at .tool_name on
|
|
28
|
-
# every PreToolUse envelope; falling back to .tool just in case.
|
|
29
|
-
TOOL_NAME="$(echo "$JSON_INPUT" | jq -r '.tool_name // .tool // empty')"
|
|
15
|
+
# Without jq we can't reliably parse — fail open (allow the edit). This matches
|
|
16
|
+
# the project rule against grep/sed/cut/awk-based JSON parsing.
|
|
17
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
30
18
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
apply_patch)
|
|
35
|
-
# Pull the full patch string out of tool_input.command[1], then extract
|
|
36
|
-
# every "*** {Update,Add,Delete} File: <path>" header line. jq handles
|
|
37
|
-
# the JSON; we use bash-native string splitting (NOT grep/cut on JSON)
|
|
38
|
-
# to walk the patch text line-by-line.
|
|
39
|
-
PATCH_TEXT="$(echo "$JSON_INPUT" | jq -r '.tool_input.command[1] // empty')"
|
|
40
|
-
if [ -n "${PATCH_TEXT}" ]; then
|
|
41
|
-
while IFS= read -r line; do
|
|
42
|
-
case "$line" in
|
|
43
|
-
"*** Update File: "*|"*** Add File: "*|"*** Delete File: "*)
|
|
44
|
-
CANDIDATE_PATHS+="${line#*: }"$'\n'
|
|
45
|
-
;;
|
|
46
|
-
esac
|
|
47
|
-
done <<<"${PATCH_TEXT}"
|
|
48
|
-
fi
|
|
49
|
-
;;
|
|
50
|
-
*)
|
|
51
|
-
# Edit / Write / anything else: single file under tool_input.file_path
|
|
52
|
-
SINGLE_PATH="$(echo "$JSON_INPUT" | jq -r '.tool_input.file_path // empty')"
|
|
53
|
-
[ -n "${SINGLE_PATH}" ] && CANDIDATE_PATHS="${SINGLE_PATH}"
|
|
54
|
-
;;
|
|
55
|
-
esac
|
|
19
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
20
|
+
# shellcheck source=/dev/null
|
|
21
|
+
. "${SCRIPT_DIR}/_extract-edit-paths.sh"
|
|
56
22
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
# Walk every candidate; deny on the first migration match.
|
|
23
|
+
# Walk every candidate path; deny on the first migration match.
|
|
60
24
|
while IFS= read -r FILE_PATH; do
|
|
61
25
|
[ -n "${FILE_PATH}" ] || continue
|
|
62
26
|
case "${FILE_PATH}" in
|
|
@@ -73,6 +37,8 @@ EOF
|
|
|
73
37
|
exit 2
|
|
74
38
|
;;
|
|
75
39
|
esac
|
|
76
|
-
done
|
|
40
|
+
done <<EOF
|
|
41
|
+
$(lisa_extract_edit_paths "$JSON_INPUT")
|
|
42
|
+
EOF
|
|
77
43
|
|
|
78
44
|
exit 0
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Lisa-managed Codex hook script (PostToolUse Edit|Write|apply_patch).
|
|
3
|
-
# Runs Prettier on
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
# under tool_input.command (an array), not tool_input.file_path. This script
|
|
8
|
-
# only formats single-file Edit/Write tool calls. apply_patch fires get
|
|
9
|
-
# silently skipped (FILE_PATH empty) — that's acceptable here because the
|
|
10
|
-
# next save/edit will still run the formatter, and the user can always run
|
|
11
|
-
# `prettier --write` against modified files manually.
|
|
12
|
-
set -euo pipefail
|
|
3
|
+
# Runs Prettier on every just-edited file. Resolves the target file(s) from the
|
|
4
|
+
# tool envelope via the shared extractor, which handles both single-file
|
|
5
|
+
# Edit/Write (tool_input.file_path) and multi-file apply_patch (tool_input.command).
|
|
6
|
+
set -uo pipefail
|
|
13
7
|
|
|
14
8
|
JSON_INPUT="$(cat)"
|
|
15
9
|
|
|
@@ -17,19 +11,30 @@ JSON_INPUT="$(cat)"
|
|
|
17
11
|
# with grep/sed/cut/awk — always use jq. Fail open without jq so we don't
|
|
18
12
|
# block the agent on missing tooling.
|
|
19
13
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
20
|
-
FILE_PATH="$(echo "$JSON_INPUT" | jq -r '.tool_input.file_path // empty')"
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
# shellcheck source=/dev/null
|
|
17
|
+
. "${SCRIPT_DIR}/_extract-edit-paths.sh"
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
ts|tsx|js|jsx|mjs|cjs|json|md|yaml|yml|css|scss|html) ;;
|
|
27
|
-
*) exit 0 ;;
|
|
28
|
-
esac
|
|
29
|
-
|
|
30
|
-
# Prefer the project-local prettier; fall back to a globally installed one
|
|
19
|
+
# Resolve the formatter once, up front.
|
|
31
20
|
if [ -x "./node_modules/.bin/prettier" ]; then
|
|
32
|
-
./node_modules/.bin/prettier
|
|
21
|
+
PRETTIER="./node_modules/.bin/prettier"
|
|
33
22
|
elif command -v prettier >/dev/null 2>&1; then
|
|
34
|
-
prettier
|
|
23
|
+
PRETTIER="prettier"
|
|
24
|
+
else
|
|
25
|
+
exit 0
|
|
35
26
|
fi
|
|
27
|
+
|
|
28
|
+
while IFS= read -r FILE_PATH; do
|
|
29
|
+
[ -n "${FILE_PATH}" ] || continue
|
|
30
|
+
[ -f "${FILE_PATH}" ] || continue
|
|
31
|
+
case "${FILE_PATH##*.}" in
|
|
32
|
+
ts | tsx | js | jsx | mjs | cjs | json | md | yaml | yml | css | scss | html) ;;
|
|
33
|
+
*) continue ;;
|
|
34
|
+
esac
|
|
35
|
+
"$PRETTIER" --write "${FILE_PATH}" >/dev/null 2>&1 || true
|
|
36
|
+
done <<EOF
|
|
37
|
+
$(lisa_extract_edit_paths "$JSON_INPUT")
|
|
38
|
+
EOF
|
|
39
|
+
|
|
40
|
+
exit 0
|
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Lisa-managed Codex hook script (PostToolUse Edit|Write|apply_patch).
|
|
3
|
-
# Runs ESLint --fix on
|
|
4
|
-
# exits non-zero so Codex sees the failure and the agent self-corrects.
|
|
5
|
-
|
|
3
|
+
# Runs ESLint --fix on every just-edited file. If unfixable errors remain on
|
|
4
|
+
# any file, exits non-zero so Codex sees the failure and the agent self-corrects.
|
|
5
|
+
# Resolves target file(s) via the shared extractor (Edit/Write + apply_patch).
|
|
6
|
+
set -uo pipefail
|
|
6
7
|
|
|
7
8
|
JSON_INPUT="$(cat)"
|
|
8
9
|
|
|
9
10
|
# Project rule (.claude/rules/PROJECT_RULES.md): never parse JSON in shell
|
|
10
11
|
# with grep/sed/cut/awk — always use jq. Fail open without jq.
|
|
11
12
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
12
|
-
FILE_PATH="$(echo "$JSON_INPUT" | jq -r '.tool_input.file_path // empty')"
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
case "${FILE_PATH##*.}" in
|
|
18
|
-
ts|tsx|js|jsx|mjs|cjs) ;;
|
|
19
|
-
*) exit 0 ;;
|
|
20
|
-
esac
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
# shellcheck source=/dev/null
|
|
16
|
+
. "${SCRIPT_DIR}/_extract-edit-paths.sh"
|
|
21
17
|
|
|
22
18
|
if [ -x "./node_modules/.bin/eslint" ]; then
|
|
23
19
|
ESLINT="./node_modules/.bin/eslint"
|
|
@@ -27,6 +23,19 @@ else
|
|
|
27
23
|
exit 0
|
|
28
24
|
fi
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
STATUS=0
|
|
27
|
+
while IFS= read -r FILE_PATH; do
|
|
28
|
+
[ -n "${FILE_PATH}" ] || continue
|
|
29
|
+
[ -f "${FILE_PATH}" ] || continue
|
|
30
|
+
case "${FILE_PATH##*.}" in
|
|
31
|
+
ts | tsx | js | jsx | mjs | cjs) ;;
|
|
32
|
+
*) continue ;;
|
|
33
|
+
esac
|
|
34
|
+
# Auto-fix what we can; surface anything left so the agent fixes it itself.
|
|
35
|
+
"$ESLINT" --fix "${FILE_PATH}" >/dev/null 2>&1 || true
|
|
36
|
+
"$ESLINT" --quiet "${FILE_PATH}" || STATUS=1
|
|
37
|
+
done <<EOF
|
|
38
|
+
$(lisa_extract_edit_paths "$JSON_INPUT")
|
|
39
|
+
EOF
|
|
40
|
+
|
|
41
|
+
exit "$STATUS"
|
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Lisa-managed Codex hook script (PostToolUse Edit|Write|apply_patch).
|
|
3
|
-
# Runs RuboCop -a (safe autocorrect) on
|
|
4
|
-
#
|
|
5
|
-
# the agent to fix.
|
|
6
|
-
|
|
3
|
+
# Runs RuboCop -a (safe autocorrect) on every just-edited Ruby file, then checks
|
|
4
|
+
# for remaining unfixable errors. Blocking — a non-zero exit on any file forces
|
|
5
|
+
# the agent to fix. Resolves target file(s) via the shared extractor
|
|
6
|
+
# (Edit/Write + apply_patch).
|
|
7
|
+
set -uo pipefail
|
|
7
8
|
|
|
8
9
|
JSON_INPUT="$(cat)"
|
|
9
10
|
|
|
10
11
|
# Project rule (.claude/rules/PROJECT_RULES.md): never parse JSON in shell
|
|
11
12
|
# with grep/sed/cut/awk — always use jq. Fail open without jq.
|
|
12
13
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
13
|
-
FILE_PATH="$(echo "$JSON_INPUT" | jq -r '.tool_input.file_path // empty')"
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
case "${FILE_PATH##*.}" in
|
|
19
|
-
rb|rake) ;;
|
|
20
|
-
*) exit 0 ;;
|
|
21
|
-
esac
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
# shellcheck source=/dev/null
|
|
17
|
+
. "${SCRIPT_DIR}/_extract-edit-paths.sh"
|
|
22
18
|
|
|
23
19
|
if command -v bundle >/dev/null 2>&1 && [ -f "./Gemfile" ]; then
|
|
24
20
|
RUBOCOP=(bundle exec rubocop)
|
|
@@ -28,5 +24,18 @@ else
|
|
|
28
24
|
exit 0
|
|
29
25
|
fi
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
STATUS=0
|
|
28
|
+
while IFS= read -r FILE_PATH; do
|
|
29
|
+
[ -n "${FILE_PATH}" ] || continue
|
|
30
|
+
[ -f "${FILE_PATH}" ] || continue
|
|
31
|
+
case "${FILE_PATH##*.}" in
|
|
32
|
+
rb | rake) ;;
|
|
33
|
+
*) continue ;;
|
|
34
|
+
esac
|
|
35
|
+
"${RUBOCOP[@]}" -a "${FILE_PATH}" >/dev/null 2>&1 || true
|
|
36
|
+
"${RUBOCOP[@]}" "${FILE_PATH}" || STATUS=1
|
|
37
|
+
done <<EOF
|
|
38
|
+
$(lisa_extract_edit_paths "$JSON_INPUT")
|
|
39
|
+
EOF
|
|
40
|
+
|
|
41
|
+
exit "$STATUS"
|
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Lisa-managed Codex hook script (PostToolUse Edit|Write|apply_patch).
|
|
3
|
-
# Runs ast-grep scan
|
|
4
|
-
#
|
|
5
|
-
|
|
3
|
+
# Runs ast-grep scan on every just-edited source file (TypeScript/JS or Ruby),
|
|
4
|
+
# reporting only errors involving those files. Blocking — a non-zero exit on any
|
|
5
|
+
# file forces the agent to fix. Resolves target file(s) via the shared extractor
|
|
6
|
+
# (Edit/Write + apply_patch).
|
|
7
|
+
set -uo pipefail
|
|
6
8
|
|
|
7
9
|
JSON_INPUT="$(cat)"
|
|
8
10
|
|
|
9
11
|
# Project rule (.claude/rules/PROJECT_RULES.md): never parse JSON in shell
|
|
10
12
|
# with grep/sed/cut/awk — always use jq. Fail open without jq.
|
|
11
13
|
command -v jq >/dev/null 2>&1 || exit 0
|
|
12
|
-
FILE_PATH="$(echo "$JSON_INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null || true)"
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
case "${FILE_PATH##*.}" in
|
|
18
|
-
ts|tsx|js|jsx|mjs|cjs) ;;
|
|
19
|
-
*) exit 0 ;;
|
|
20
|
-
esac
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
# shellcheck source=/dev/null
|
|
17
|
+
. "${SCRIPT_DIR}/_extract-edit-paths.sh"
|
|
21
18
|
|
|
22
19
|
if [ -x "./node_modules/.bin/ast-grep" ]; then
|
|
23
20
|
AST_GREP="./node_modules/.bin/ast-grep"
|
|
@@ -31,4 +28,17 @@ fi
|
|
|
31
28
|
|
|
32
29
|
[ -f "./sgconfig.yml" ] || exit 0
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
STATUS=0
|
|
32
|
+
while IFS= read -r FILE_PATH; do
|
|
33
|
+
[ -n "${FILE_PATH}" ] || continue
|
|
34
|
+
[ -f "${FILE_PATH}" ] || continue
|
|
35
|
+
case "${FILE_PATH##*.}" in
|
|
36
|
+
ts | tsx | js | jsx | mjs | cjs | rb | rake) ;;
|
|
37
|
+
*) continue ;;
|
|
38
|
+
esac
|
|
39
|
+
"$AST_GREP" scan "${FILE_PATH}" 2>&1 || STATUS=1
|
|
40
|
+
done <<EOF
|
|
41
|
+
$(lisa_extract_edit_paths "$JSON_INPUT")
|
|
42
|
+
EOF
|
|
43
|
+
|
|
44
|
+
exit "$STATUS"
|
package/package.json
CHANGED
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"lodash": ">=4.18.1"
|
|
83
83
|
},
|
|
84
84
|
"name": "@codyswann/lisa",
|
|
85
|
-
"version": "2.26.
|
|
85
|
+
"version": "2.26.1",
|
|
86
86
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
87
87
|
"main": "dist/index.js",
|
|
88
88
|
"exports": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa",
|
|
3
|
-
"version": "2.26.
|
|
3
|
+
"version": "2.26.1",
|
|
4
4
|
"description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"workflow"
|
|
13
13
|
],
|
|
14
14
|
"skills": "./skills/",
|
|
15
|
-
"hooks": "./hooks/hooks.json",
|
|
16
15
|
"interface": {
|
|
17
16
|
"displayName": "Lisa",
|
|
18
17
|
"shortDescription": "Universal project governance workflows",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-nestjs",
|
|
3
|
-
"version": "2.26.
|
|
3
|
+
"version": "2.26.1",
|
|
4
4
|
"description": "NestJS-specific skills and migration write-protection hooks.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"lisa-typescript"
|
|
16
16
|
],
|
|
17
17
|
"skills": "./skills/",
|
|
18
|
-
"hooks": "./hooks/hooks.json",
|
|
19
18
|
"interface": {
|
|
20
19
|
"displayName": "Lisa NestJS",
|
|
21
20
|
"shortDescription": "NestJS workflow guidance",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-rails",
|
|
3
|
-
"version": "2.26.
|
|
3
|
+
"version": "2.26.1",
|
|
4
4
|
"description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"lisa"
|
|
16
16
|
],
|
|
17
17
|
"skills": "./skills/",
|
|
18
|
-
"hooks": "./hooks/hooks.json",
|
|
19
18
|
"interface": {
|
|
20
19
|
"displayName": "Lisa Rails",
|
|
21
20
|
"shortDescription": "Ruby on Rails workflows",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-typescript",
|
|
3
|
-
"version": "2.26.
|
|
3
|
+
"version": "2.26.1",
|
|
4
4
|
"description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
"dependencies": [
|
|
15
15
|
"lisa"
|
|
16
16
|
],
|
|
17
|
-
"hooks": "./hooks/hooks.json",
|
|
18
17
|
"interface": {
|
|
19
18
|
"displayName": "Lisa TypeScript",
|
|
20
19
|
"shortDescription": "TypeScript lifecycle checks",
|
|
@@ -2,9 +2,19 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Generate Codex plugin artifacts from the built Claude plugin directories.
|
|
4
4
|
*
|
|
5
|
-
* Claude remains Lisa's production path; this script
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Claude remains Lisa's production path; this script derives the .codex-plugin
|
|
6
|
+
* metadata (skills + MCP pointers) every time plugins are rebuilt.
|
|
7
|
+
*
|
|
8
|
+
* NOTE ON HOOKS: this script does NOT emit Codex hooks. Codex (codex-cli
|
|
9
|
+
* 0.125.0) does not execute plugin-bundled hooks — its plugin manifest parser
|
|
10
|
+
* only honors `skills`, `mcpServers`, `apps`, and interface fields, and a
|
|
11
|
+
* runtime test confirmed a bundled `hooks/hooks.json` never fires. Lisa's
|
|
12
|
+
* Codex hooks are instead installed into the project's `.codex/hooks.json`
|
|
13
|
+
* by `src/codex/hooks-installer.ts` (run during `lisa` apply). Hooks with no
|
|
14
|
+
* Codex equivalent are intentionally not ported: `enforce-team-first.sh`
|
|
15
|
+
* (Claude-team-specific), `inject-flow-context.sh` and any SubagentStart hook
|
|
16
|
+
* (Codex has no SubagentStart event), and the SessionEnd `entire` hook (Codex
|
|
17
|
+
* has no SessionEnd event).
|
|
8
18
|
*/
|
|
9
19
|
import fs from "node:fs";
|
|
10
20
|
import path from "node:path";
|
|
@@ -29,17 +39,10 @@ if (!fs.existsSync(claudeManifestPath)) {
|
|
|
29
39
|
|
|
30
40
|
const claudeManifest = JSON.parse(fs.readFileSync(claudeManifestPath, "utf8"));
|
|
31
41
|
const pluginName = claudeManifest.name;
|
|
32
|
-
const UNSUPPORTED_CODEX_HOOK_SCRIPTS = new Set([
|
|
33
|
-
"hooks/enforce-team-first.sh",
|
|
34
|
-
"hooks/inject-flow-context.sh",
|
|
35
|
-
"hooks/inject-rules.sh",
|
|
36
|
-
]);
|
|
37
|
-
const codexHooks = convertHooks(pluginName, claudeManifest.hooks ?? {});
|
|
38
42
|
|
|
39
|
-
writeCodexManifest(pluginName, versionArg
|
|
40
|
-
writeCodexHooks(codexHooks);
|
|
43
|
+
writeCodexManifest(pluginName, versionArg);
|
|
41
44
|
|
|
42
|
-
function writeCodexManifest(pluginName, version
|
|
45
|
+
function writeCodexManifest(pluginName, version) {
|
|
43
46
|
const metadata = metadataFor(pluginName);
|
|
44
47
|
const manifest = {
|
|
45
48
|
name: pluginName,
|
|
@@ -50,7 +53,7 @@ function writeCodexManifest(pluginName, version, hooksFile) {
|
|
|
50
53
|
...(claudeManifest.dependencies
|
|
51
54
|
? { dependencies: claudeManifest.dependencies }
|
|
52
55
|
: {}),
|
|
53
|
-
...componentPointers(
|
|
56
|
+
...componentPointers(),
|
|
54
57
|
interface: {
|
|
55
58
|
displayName: metadata.displayName,
|
|
56
59
|
shortDescription: metadata.shortDescription,
|
|
@@ -70,7 +73,7 @@ function writeCodexManifest(pluginName, version, hooksFile) {
|
|
|
70
73
|
);
|
|
71
74
|
}
|
|
72
75
|
|
|
73
|
-
function componentPointers(
|
|
76
|
+
function componentPointers() {
|
|
74
77
|
return {
|
|
75
78
|
...(fs.existsSync(path.join(pluginDir, "skills"))
|
|
76
79
|
? { skills: "./skills/" }
|
|
@@ -78,124 +81,9 @@ function componentPointers(hooksFile) {
|
|
|
78
81
|
...(fs.existsSync(path.join(pluginDir, ".mcp.json"))
|
|
79
82
|
? { mcpServers: "./.mcp.json" }
|
|
80
83
|
: {}),
|
|
81
|
-
...(hooksFile ? { hooks: "./hooks/hooks.json" } : {}),
|
|
82
84
|
};
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
function writeCodexHooks(hooksFile) {
|
|
86
|
-
const hooksDir = path.join(pluginDir, "hooks");
|
|
87
|
-
const hooksPath = path.join(hooksDir, "hooks.json");
|
|
88
|
-
if (!hooksFile) {
|
|
89
|
-
if (fs.existsSync(hooksPath)) {
|
|
90
|
-
fs.rmSync(hooksPath);
|
|
91
|
-
}
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
fs.mkdirSync(hooksDir, { recursive: true });
|
|
95
|
-
fs.writeFileSync(hooksPath, `${JSON.stringify(hooksFile, null, 2)}\n`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function convertHooks(pluginName, claudeHooks) {
|
|
99
|
-
const supportedEvents = new Set([
|
|
100
|
-
"UserPromptSubmit",
|
|
101
|
-
"PostToolUse",
|
|
102
|
-
"PreToolUse",
|
|
103
|
-
"Stop",
|
|
104
|
-
"SessionStart",
|
|
105
|
-
]);
|
|
106
|
-
const entries = Object.entries(claudeHooks)
|
|
107
|
-
.filter(([event]) => supportedEvents.has(event))
|
|
108
|
-
.map(([event, groups]) => [event, convertHookGroups(pluginName, groups)])
|
|
109
|
-
.filter(([, groups]) => groups.length > 0);
|
|
110
|
-
return entries.length > 0
|
|
111
|
-
? { hooks: Object.fromEntries(entries) }
|
|
112
|
-
: undefined;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function convertHookGroups(pluginName, groups) {
|
|
116
|
-
return groups
|
|
117
|
-
.map(group => ({
|
|
118
|
-
...(group.matcher !== undefined
|
|
119
|
-
? { matcher: normalizeMatcher(group.matcher) }
|
|
120
|
-
: {}),
|
|
121
|
-
hooks: (group.hooks ?? [])
|
|
122
|
-
.map(hook => convertHookHandler(pluginName, hook))
|
|
123
|
-
.filter(Boolean),
|
|
124
|
-
}))
|
|
125
|
-
.filter(group => group.hooks.length > 0);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function normalizeMatcher(matcher) {
|
|
129
|
-
const normalized = String(matcher).replaceAll("Write|Edit", "Edit|Write");
|
|
130
|
-
return normalized.includes("apply_patch")
|
|
131
|
-
? normalized
|
|
132
|
-
: normalized.replaceAll("Edit|Write", "Edit|Write|apply_patch");
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function convertHookHandler(pluginName, hook) {
|
|
136
|
-
if (hook.type !== "command" || typeof hook.command !== "string") {
|
|
137
|
-
return undefined;
|
|
138
|
-
}
|
|
139
|
-
const command = convertHookCommand(pluginName, hook.command);
|
|
140
|
-
if (command === undefined) {
|
|
141
|
-
return undefined;
|
|
142
|
-
}
|
|
143
|
-
return {
|
|
144
|
-
type: "command",
|
|
145
|
-
command,
|
|
146
|
-
...(hook.timeout !== undefined ? { timeout: hook.timeout } : {}),
|
|
147
|
-
...(hook.statusMessage !== undefined
|
|
148
|
-
? { statusMessage: hook.statusMessage }
|
|
149
|
-
: {}),
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function convertHookCommand(pluginName, command) {
|
|
154
|
-
const pluginScript = command.match(
|
|
155
|
-
/\$\{CLAUDE_PLUGIN_ROOT\}\/(hooks\/[^ "';]+)/
|
|
156
|
-
);
|
|
157
|
-
if (!pluginScript) {
|
|
158
|
-
return normalizeInlineCommand(command);
|
|
159
|
-
}
|
|
160
|
-
if (UNSUPPORTED_CODEX_HOOK_SCRIPTS.has(pluginScript[1])) {
|
|
161
|
-
return undefined;
|
|
162
|
-
}
|
|
163
|
-
return buildPluginScriptRunner(pluginName, pluginScript[1]);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function normalizeInlineCommand(command) {
|
|
167
|
-
const entireMatch = command.match(
|
|
168
|
-
/^command -v entire >\/dev\/null 2>&1 && entire hooks claude-code ([a-z-]+) \|\| true$/
|
|
169
|
-
);
|
|
170
|
-
if (!entireMatch) {
|
|
171
|
-
return command;
|
|
172
|
-
}
|
|
173
|
-
return `if command -v entire >/dev/null 2>&1; then entire hooks claude-code ${entireMatch[1]}; fi`;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function buildPluginScriptRunner(pluginName, scriptPath) {
|
|
177
|
-
const script = JSON.stringify(scriptPath);
|
|
178
|
-
const plugin = JSON.stringify(pluginName);
|
|
179
|
-
return [
|
|
180
|
-
"bash -lc '",
|
|
181
|
-
`plugin=${shellQuote(plugin)}; script=${shellQuote(script)}; `,
|
|
182
|
-
"repo=$(git rev-parse --show-toplevel 2>/dev/null || pwd); ",
|
|
183
|
-
'for root in "${CODEX_PLUGIN_ROOT:-}" "${CLAUDE_PLUGIN_ROOT:-}" "$repo/plugins/$plugin" "$HOME/.codex/plugins/cache/lisa/$plugin/local"; do ',
|
|
184
|
-
'[ -n "$root" ] || continue; ',
|
|
185
|
-
'if [ -x "$root/$script" ]; then CLAUDE_PLUGIN_ROOT="$root" CODEX_PLUGIN_ROOT="$root" exec "$root/$script"; fi; ',
|
|
186
|
-
"done; ",
|
|
187
|
-
'found=$(find "$HOME/.codex/plugins/cache" -path "*/$plugin/*/$script" -type f -exec ls -t {} + 2>/dev/null | head -n 1); ',
|
|
188
|
-
'[ -n "$found" ] || exit 0; ',
|
|
189
|
-
"root=${found%/$script}; ",
|
|
190
|
-
'CLAUDE_PLUGIN_ROOT="$root" CODEX_PLUGIN_ROOT="$root" exec "$found"',
|
|
191
|
-
"'",
|
|
192
|
-
].join("");
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function shellQuote(jsonStringLiteral) {
|
|
196
|
-
return jsonStringLiteral.replaceAll("'", "'\\''");
|
|
197
|
-
}
|
|
198
|
-
|
|
199
87
|
function metadataFor(pluginName) {
|
|
200
88
|
const map = {
|
|
201
89
|
lisa: {
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"hooks": {
|
|
3
|
-
"UserPromptSubmit": [
|
|
4
|
-
{
|
|
5
|
-
"matcher": "",
|
|
6
|
-
"hooks": [
|
|
7
|
-
{
|
|
8
|
-
"type": "command",
|
|
9
|
-
"command": "if command -v entire >/dev/null 2>&1; then entire hooks claude-code user-prompt-submit; fi"
|
|
10
|
-
}
|
|
11
|
-
]
|
|
12
|
-
}
|
|
13
|
-
],
|
|
14
|
-
"PostToolUse": [
|
|
15
|
-
{
|
|
16
|
-
"matcher": "Task",
|
|
17
|
-
"hooks": [
|
|
18
|
-
{
|
|
19
|
-
"type": "command",
|
|
20
|
-
"command": "if command -v entire >/dev/null 2>&1; then entire hooks claude-code post-task; fi"
|
|
21
|
-
}
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"matcher": "TodoWrite",
|
|
26
|
-
"hooks": [
|
|
27
|
-
{
|
|
28
|
-
"type": "command",
|
|
29
|
-
"command": "if command -v entire >/dev/null 2>&1; then entire hooks claude-code post-todo; fi"
|
|
30
|
-
}
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
],
|
|
34
|
-
"PreToolUse": [
|
|
35
|
-
{
|
|
36
|
-
"matcher": "Task",
|
|
37
|
-
"hooks": [
|
|
38
|
-
{
|
|
39
|
-
"type": "command",
|
|
40
|
-
"command": "if command -v entire >/dev/null 2>&1; then entire hooks claude-code pre-task; fi"
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"matcher": "Bash",
|
|
46
|
-
"hooks": [
|
|
47
|
-
{
|
|
48
|
-
"type": "command",
|
|
49
|
-
"command": "bash -lc 'plugin=\"lisa\"; script=\"hooks/block-no-verify.sh\"; repo=$(git rev-parse --show-toplevel 2>/dev/null || pwd); for root in \"${CODEX_PLUGIN_ROOT:-}\" \"${CLAUDE_PLUGIN_ROOT:-}\" \"$repo/plugins/$plugin\" \"$HOME/.codex/plugins/cache/lisa/$plugin/local\"; do [ -n \"$root\" ] || continue; if [ -x \"$root/$script\" ]; then CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$root/$script\"; fi; done; found=$(find \"$HOME/.codex/plugins/cache\" -path \"*/$plugin/*/$script\" -type f -exec ls -t {} + 2>/dev/null | head -n 1); [ -n \"$found\" ] || exit 0; root=${found%/$script}; CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$found\"'"
|
|
50
|
-
}
|
|
51
|
-
]
|
|
52
|
-
}
|
|
53
|
-
],
|
|
54
|
-
"Stop": [
|
|
55
|
-
{
|
|
56
|
-
"matcher": "",
|
|
57
|
-
"hooks": [
|
|
58
|
-
{
|
|
59
|
-
"type": "command",
|
|
60
|
-
"command": "bash -lc 'plugin=\"lisa\"; script=\"hooks/notify-ntfy.sh\"; repo=$(git rev-parse --show-toplevel 2>/dev/null || pwd); for root in \"${CODEX_PLUGIN_ROOT:-}\" \"${CLAUDE_PLUGIN_ROOT:-}\" \"$repo/plugins/$plugin\" \"$HOME/.codex/plugins/cache/lisa/$plugin/local\"; do [ -n \"$root\" ] || continue; if [ -x \"$root/$script\" ]; then CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$root/$script\"; fi; done; found=$(find \"$HOME/.codex/plugins/cache\" -path \"*/$plugin/*/$script\" -type f -exec ls -t {} + 2>/dev/null | head -n 1); [ -n \"$found\" ] || exit 0; root=${found%/$script}; CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$found\"'"
|
|
61
|
-
}
|
|
62
|
-
]
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
"matcher": "",
|
|
66
|
-
"hooks": [
|
|
67
|
-
{
|
|
68
|
-
"type": "command",
|
|
69
|
-
"command": "if command -v entire >/dev/null 2>&1; then entire hooks claude-code stop; fi"
|
|
70
|
-
}
|
|
71
|
-
]
|
|
72
|
-
}
|
|
73
|
-
],
|
|
74
|
-
"SessionStart": [
|
|
75
|
-
{
|
|
76
|
-
"matcher": "startup",
|
|
77
|
-
"hooks": [
|
|
78
|
-
{
|
|
79
|
-
"type": "command",
|
|
80
|
-
"command": "bash -lc 'plugin=\"lisa\"; script=\"hooks/install-pkgs.sh\"; repo=$(git rev-parse --show-toplevel 2>/dev/null || pwd); for root in \"${CODEX_PLUGIN_ROOT:-}\" \"${CLAUDE_PLUGIN_ROOT:-}\" \"$repo/plugins/$plugin\" \"$HOME/.codex/plugins/cache/lisa/$plugin/local\"; do [ -n \"$root\" ] || continue; if [ -x \"$root/$script\" ]; then CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$root/$script\"; fi; done; found=$(find \"$HOME/.codex/plugins/cache\" -path \"*/$plugin/*/$script\" -type f -exec ls -t {} + 2>/dev/null | head -n 1); [ -n \"$found\" ] || exit 0; root=${found%/$script}; CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$found\"'"
|
|
81
|
-
}
|
|
82
|
-
]
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"matcher": "",
|
|
86
|
-
"hooks": [
|
|
87
|
-
{
|
|
88
|
-
"type": "command",
|
|
89
|
-
"command": "bash -lc 'plugin=\"lisa\"; script=\"hooks/setup-jira-cli.sh\"; repo=$(git rev-parse --show-toplevel 2>/dev/null || pwd); for root in \"${CODEX_PLUGIN_ROOT:-}\" \"${CLAUDE_PLUGIN_ROOT:-}\" \"$repo/plugins/$plugin\" \"$HOME/.codex/plugins/cache/lisa/$plugin/local\"; do [ -n \"$root\" ] || continue; if [ -x \"$root/$script\" ]; then CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$root/$script\"; fi; done; found=$(find \"$HOME/.codex/plugins/cache\" -path \"*/$plugin/*/$script\" -type f -exec ls -t {} + 2>/dev/null | head -n 1); [ -n \"$found\" ] || exit 0; root=${found%/$script}; CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$found\"'"
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
"matcher": "",
|
|
95
|
-
"hooks": [
|
|
96
|
-
{
|
|
97
|
-
"type": "command",
|
|
98
|
-
"command": "if command -v entire >/dev/null 2>&1; then entire hooks claude-code session-start; fi"
|
|
99
|
-
}
|
|
100
|
-
]
|
|
101
|
-
}
|
|
102
|
-
]
|
|
103
|
-
}
|
|
104
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"hooks": {
|
|
3
|
-
"PreToolUse": [
|
|
4
|
-
{
|
|
5
|
-
"matcher": "Edit|Write|apply_patch",
|
|
6
|
-
"hooks": [
|
|
7
|
-
{
|
|
8
|
-
"type": "command",
|
|
9
|
-
"command": "bash -lc 'plugin=\"lisa-nestjs\"; script=\"hooks/block-migration-edits.sh\"; repo=$(git rev-parse --show-toplevel 2>/dev/null || pwd); for root in \"${CODEX_PLUGIN_ROOT:-}\" \"${CLAUDE_PLUGIN_ROOT:-}\" \"$repo/plugins/$plugin\" \"$HOME/.codex/plugins/cache/lisa/$plugin/local\"; do [ -n \"$root\" ] || continue; if [ -x \"$root/$script\" ]; then CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$root/$script\"; fi; done; found=$(find \"$HOME/.codex/plugins/cache\" -path \"*/$plugin/*/$script\" -type f -exec ls -t {} + 2>/dev/null | head -n 1); [ -n \"$found\" ] || exit 0; root=${found%/$script}; CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$found\"'"
|
|
10
|
-
}
|
|
11
|
-
]
|
|
12
|
-
}
|
|
13
|
-
]
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"hooks": {
|
|
3
|
-
"PostToolUse": [
|
|
4
|
-
{
|
|
5
|
-
"matcher": "Edit|Write|apply_patch",
|
|
6
|
-
"hooks": [
|
|
7
|
-
{
|
|
8
|
-
"type": "command",
|
|
9
|
-
"command": "bash -lc 'plugin=\"lisa-rails\"; script=\"hooks/rubocop-on-edit.sh\"; repo=$(git rev-parse --show-toplevel 2>/dev/null || pwd); for root in \"${CODEX_PLUGIN_ROOT:-}\" \"${CLAUDE_PLUGIN_ROOT:-}\" \"$repo/plugins/$plugin\" \"$HOME/.codex/plugins/cache/lisa/$plugin/local\"; do [ -n \"$root\" ] || continue; if [ -x \"$root/$script\" ]; then CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$root/$script\"; fi; done; found=$(find \"$HOME/.codex/plugins/cache\" -path \"*/$plugin/*/$script\" -type f -exec ls -t {} + 2>/dev/null | head -n 1); [ -n \"$found\" ] || exit 0; root=${found%/$script}; CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$found\"'"
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
"type": "command",
|
|
13
|
-
"command": "bash -lc 'plugin=\"lisa-rails\"; script=\"hooks/sg-scan-on-edit.sh\"; repo=$(git rev-parse --show-toplevel 2>/dev/null || pwd); for root in \"${CODEX_PLUGIN_ROOT:-}\" \"${CLAUDE_PLUGIN_ROOT:-}\" \"$repo/plugins/$plugin\" \"$HOME/.codex/plugins/cache/lisa/$plugin/local\"; do [ -n \"$root\" ] || continue; if [ -x \"$root/$script\" ]; then CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$root/$script\"; fi; done; found=$(find \"$HOME/.codex/plugins/cache\" -path \"*/$plugin/*/$script\" -type f -exec ls -t {} + 2>/dev/null | head -n 1); [ -n \"$found\" ] || exit 0; root=${found%/$script}; CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$found\"'"
|
|
14
|
-
}
|
|
15
|
-
]
|
|
16
|
-
}
|
|
17
|
-
]
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"hooks": {
|
|
3
|
-
"PostToolUse": [
|
|
4
|
-
{
|
|
5
|
-
"matcher": "Edit|Write|apply_patch",
|
|
6
|
-
"hooks": [
|
|
7
|
-
{
|
|
8
|
-
"type": "command",
|
|
9
|
-
"command": "bash -lc 'plugin=\"lisa-typescript\"; script=\"hooks/format-on-edit.sh\"; repo=$(git rev-parse --show-toplevel 2>/dev/null || pwd); for root in \"${CODEX_PLUGIN_ROOT:-}\" \"${CLAUDE_PLUGIN_ROOT:-}\" \"$repo/plugins/$plugin\" \"$HOME/.codex/plugins/cache/lisa/$plugin/local\"; do [ -n \"$root\" ] || continue; if [ -x \"$root/$script\" ]; then CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$root/$script\"; fi; done; found=$(find \"$HOME/.codex/plugins/cache\" -path \"*/$plugin/*/$script\" -type f -exec ls -t {} + 2>/dev/null | head -n 1); [ -n \"$found\" ] || exit 0; root=${found%/$script}; CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$found\"'"
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
"type": "command",
|
|
13
|
-
"command": "bash -lc 'plugin=\"lisa-typescript\"; script=\"hooks/sg-scan-on-edit.sh\"; repo=$(git rev-parse --show-toplevel 2>/dev/null || pwd); for root in \"${CODEX_PLUGIN_ROOT:-}\" \"${CLAUDE_PLUGIN_ROOT:-}\" \"$repo/plugins/$plugin\" \"$HOME/.codex/plugins/cache/lisa/$plugin/local\"; do [ -n \"$root\" ] || continue; if [ -x \"$root/$script\" ]; then CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$root/$script\"; fi; done; found=$(find \"$HOME/.codex/plugins/cache\" -path \"*/$plugin/*/$script\" -type f -exec ls -t {} + 2>/dev/null | head -n 1); [ -n \"$found\" ] || exit 0; root=${found%/$script}; CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$found\"'"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"type": "command",
|
|
17
|
-
"command": "bash -lc 'plugin=\"lisa-typescript\"; script=\"hooks/lint-on-edit.sh\"; repo=$(git rev-parse --show-toplevel 2>/dev/null || pwd); for root in \"${CODEX_PLUGIN_ROOT:-}\" \"${CLAUDE_PLUGIN_ROOT:-}\" \"$repo/plugins/$plugin\" \"$HOME/.codex/plugins/cache/lisa/$plugin/local\"; do [ -n \"$root\" ] || continue; if [ -x \"$root/$script\" ]; then CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$root/$script\"; fi; done; found=$(find \"$HOME/.codex/plugins/cache\" -path \"*/$plugin/*/$script\" -type f -exec ls -t {} + 2>/dev/null | head -n 1); [ -n \"$found\" ] || exit 0; root=${found%/$script}; CLAUDE_PLUGIN_ROOT=\"$root\" CODEX_PLUGIN_ROOT=\"$root\" exec \"$found\"'"
|
|
18
|
-
}
|
|
19
|
-
]
|
|
20
|
-
}
|
|
21
|
-
]
|
|
22
|
-
}
|
|
23
|
-
}
|