@ghl-ai/aw 0.1.38-beta.17 → 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 +71 -1
- package/package.json +1 -1
package/ecc.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import * as fmt from "./fmt.mjs";
|
|
|
9
9
|
|
|
10
10
|
const AW_ECC_REPO_SSH = "git@github.com:shreyansh-ghl/aw-ecc.git";
|
|
11
11
|
const AW_ECC_REPO_HTTPS = "https://github.com/shreyansh-ghl/aw-ecc.git";
|
|
12
|
-
const AW_ECC_TAG = "v1.4.
|
|
12
|
+
const AW_ECC_TAG = "v1.4.28";
|
|
13
13
|
|
|
14
14
|
const MARKETPLACE_NAME = "aw-marketplace";
|
|
15
15
|
const PLUGIN_KEY = `aw@${MARKETPLACE_NAME}`;
|
|
@@ -124,8 +124,57 @@ function installClaudePlugin(repoDir) {
|
|
|
124
124
|
// previously-registered path, which may point to a stale/wrong directory.
|
|
125
125
|
try { run(`claude plugin uninstall ${PLUGIN_KEY} --scope user`); } catch { /* not installed */ }
|
|
126
126
|
try { run(`claude plugin marketplace remove ${MARKETPLACE_NAME}`); } catch { /* not registered */ }
|
|
127
|
+
|
|
128
|
+
// Purge stale plugin cache — Claude Code caches by package.json version,
|
|
129
|
+
// so old entries with outdated hooks can shadow a fresh install.
|
|
130
|
+
const cacheDir = join(homedir(), ".claude", "plugins", "cache", MARKETPLACE_NAME);
|
|
131
|
+
if (existsSync(cacheDir)) {
|
|
132
|
+
try { rmSync(cacheDir, { recursive: true, force: true }); } catch { /* best effort */ }
|
|
133
|
+
}
|
|
134
|
+
|
|
127
135
|
run(`claude plugin marketplace add ${repoDir} --scope user`);
|
|
128
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));
|
|
129
178
|
}
|
|
130
179
|
|
|
131
180
|
function uninstallClaudePlugin() {
|
|
@@ -133,6 +182,22 @@ function uninstallClaudePlugin() {
|
|
|
133
182
|
try { run(`claude plugin marketplace remove ${MARKETPLACE_NAME}`); } catch { /* not registered */ }
|
|
134
183
|
}
|
|
135
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
|
+
|
|
136
201
|
/**
|
|
137
202
|
* Move ecc command files from ~/.cursor/commands/*.md → ~/.cursor/commands/aw/*.md
|
|
138
203
|
* so Cursor exposes them as /aw:tdd, /aw:plan — consistent with Claude Code's plugin namespace.
|
|
@@ -261,6 +326,11 @@ export function uninstallAwEcc({ silent = false } = {}) {
|
|
|
261
326
|
removed++;
|
|
262
327
|
} catch { /* best effort */ }
|
|
263
328
|
|
|
329
|
+
// Remove SessionStart hook from settings.json
|
|
330
|
+
try {
|
|
331
|
+
removeSessionStartHook();
|
|
332
|
+
} catch { /* best effort */ }
|
|
333
|
+
|
|
264
334
|
// Cursor + Codex: remove file-copied content via install-state
|
|
265
335
|
for (const cfg of Object.values(TARGET_STATE)) {
|
|
266
336
|
const statePath = join(HOME, cfg.state);
|