@ghl-ai/aw 0.1.38-beta.18 → 0.1.38-beta.19
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/ecc.mjs +62 -0
- package/package.json +1 -1
package/ecc.mjs
CHANGED
|
@@ -134,6 +134,47 @@ function installClaudePlugin(repoDir) {
|
|
|
134
134
|
|
|
135
135
|
run(`claude plugin marketplace add ${repoDir} --scope user`);
|
|
136
136
|
run(`claude plugin install ${PLUGIN_KEY} --scope user`);
|
|
137
|
+
|
|
138
|
+
// Plugin SessionStart hooks have a known issue where Claude Code fires them
|
|
139
|
+
// but silently discards the output. As a workaround, also register the
|
|
140
|
+
// SessionStart hook directly in ~/.claude/settings.json — this path is
|
|
141
|
+
// reliable and bypasses the plugin hook dispatch entirely.
|
|
142
|
+
ensureSessionStartHook(repoDir);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Add a SessionStart hook to ~/.claude/settings.json that calls the
|
|
147
|
+
* using-aw-skills session-start script directly. This is more reliable
|
|
148
|
+
* than the plugin hook path because Claude Code's plugin hook dispatch
|
|
149
|
+
* sometimes silently drops SessionStart output.
|
|
150
|
+
*/
|
|
151
|
+
function ensureSessionStartHook(repoDir) {
|
|
152
|
+
const settingsPath = join(homedir(), ".claude", "settings.json");
|
|
153
|
+
let settings = {};
|
|
154
|
+
try {
|
|
155
|
+
if (existsSync(settingsPath)) {
|
|
156
|
+
settings = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
157
|
+
}
|
|
158
|
+
} catch { /* start fresh */ }
|
|
159
|
+
|
|
160
|
+
const hookCmd = `bash "$HOME/.aw-ecc/skills/using-aw-skills/hooks/session-start.sh"`;
|
|
161
|
+
|
|
162
|
+
// Check if already present
|
|
163
|
+
const existing = settings.hooks?.SessionStart || [];
|
|
164
|
+
const alreadyHas = existing.some((entry) =>
|
|
165
|
+
entry.hooks?.some((h) => h.command === hookCmd),
|
|
166
|
+
);
|
|
167
|
+
if (alreadyHas) return;
|
|
168
|
+
|
|
169
|
+
if (!settings.hooks) settings.hooks = {};
|
|
170
|
+
if (!settings.hooks.SessionStart) settings.hooks.SessionStart = [];
|
|
171
|
+
|
|
172
|
+
settings.hooks.SessionStart.push({
|
|
173
|
+
hooks: [{ type: "command", command: hookCmd }],
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
177
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
137
178
|
}
|
|
138
179
|
|
|
139
180
|
function uninstallClaudePlugin() {
|
|
@@ -141,6 +182,22 @@ function uninstallClaudePlugin() {
|
|
|
141
182
|
try { run(`claude plugin marketplace remove ${MARKETPLACE_NAME}`); } catch { /* not registered */ }
|
|
142
183
|
}
|
|
143
184
|
|
|
185
|
+
function removeSessionStartHook() {
|
|
186
|
+
const settingsPath = join(homedir(), ".claude", "settings.json");
|
|
187
|
+
if (!existsSync(settingsPath)) return;
|
|
188
|
+
try {
|
|
189
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
190
|
+
const hooks = settings.hooks?.SessionStart;
|
|
191
|
+
if (!Array.isArray(hooks)) return;
|
|
192
|
+
settings.hooks.SessionStart = hooks.filter((entry) =>
|
|
193
|
+
!entry.hooks?.some((h) => h.command?.includes(".aw-ecc/")),
|
|
194
|
+
);
|
|
195
|
+
if (settings.hooks.SessionStart.length === 0) delete settings.hooks.SessionStart;
|
|
196
|
+
if (Object.keys(settings.hooks).length === 0) delete settings.hooks;
|
|
197
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
198
|
+
} catch { /* best effort */ }
|
|
199
|
+
}
|
|
200
|
+
|
|
144
201
|
/**
|
|
145
202
|
* Move ecc command files from ~/.cursor/commands/*.md → ~/.cursor/commands/aw/*.md
|
|
146
203
|
* so Cursor exposes them as /aw:tdd, /aw:plan — consistent with Claude Code's plugin namespace.
|
|
@@ -269,6 +326,11 @@ export function uninstallAwEcc({ silent = false } = {}) {
|
|
|
269
326
|
removed++;
|
|
270
327
|
} catch { /* best effort */ }
|
|
271
328
|
|
|
329
|
+
// Remove SessionStart hook from settings.json
|
|
330
|
+
try {
|
|
331
|
+
removeSessionStartHook();
|
|
332
|
+
} catch { /* best effort */ }
|
|
333
|
+
|
|
272
334
|
// Cursor + Codex: remove file-copied content via install-state
|
|
273
335
|
for (const cfg of Object.values(TARGET_STATE)) {
|
|
274
336
|
const statePath = join(HOME, cfg.state);
|