wkappbot-code 0.3.25 → 0.3.26
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/lib/doctor-path.js +16 -2
- package/lib/hook-wire.js +22 -1
- package/package.json +1 -1
package/lib/doctor-path.js
CHANGED
|
@@ -224,13 +224,19 @@ export function ensureLinks({ home, platform = process.platform, binDir, env = p
|
|
|
224
224
|
// Windows runs the PATH logic even when both shims already existed: the doctor row reads the persistent PATH,
|
|
225
225
|
// so a missing entry is a FAIL whether or not this run wrote a shim. POSIX keeps its old rule (a link was written).
|
|
226
226
|
const pathWanted = needsPath && (created.length > 0 || platform === "win32");
|
|
227
|
+
// POSIX: note whether ~/.profile existed BEFORE addToPath, so uninstall deletes only a profile install created.
|
|
228
|
+
const profilePath = platform === "win32" ? "" : join(home, ".profile");
|
|
229
|
+
const profileExisted = !!profilePath && existsSync(profilePath);
|
|
227
230
|
const pathAdded = pathWanted ? !!addToPath({ dir, home, platform, readRegPath }) : false;
|
|
228
|
-
|
|
231
|
+
const profileCreated = pathAdded && !profileExisted && !!profilePath && existsSync(profilePath) ? profilePath : "";
|
|
232
|
+
return { created, dir, pathAdded, profileCreated };
|
|
229
233
|
}
|
|
230
234
|
|
|
231
235
|
// removeCreatedLinks(created, opts) -> the entries actually removed. Deletes only the listed entries, nothing else.
|
|
232
236
|
// A "PATH:<folder>" entry is the PATH entry install added: it is removed by removePath (exactly that folder),
|
|
233
|
-
// never by unlink.
|
|
237
|
+
// never by unlink. A "PROFILE:<path>" entry is the ~/.profile install created: it is deleted only when its text is
|
|
238
|
+
// blank again (trim() empty), so a profile the user wrote into is never removed. opts: platform, home, and an
|
|
239
|
+
// injectable removePath({dir, home, platform}) -> boolean.
|
|
234
240
|
export function removeCreatedLinks(created = [], { platform = process.platform, home = process.env.HOME || process.env.USERPROFILE || "", removePath = defaultRemovePath } = {}) {
|
|
235
241
|
const removed = [];
|
|
236
242
|
for (const p of created) {
|
|
@@ -238,6 +244,13 @@ export function removeCreatedLinks(created = [], { platform = process.platform,
|
|
|
238
244
|
try { if (removePath({ dir: p.slice(5), home, platform })) removed.push(p); } catch { /* not removed */ }
|
|
239
245
|
continue;
|
|
240
246
|
}
|
|
247
|
+
if (p.startsWith("PROFILE:")) {
|
|
248
|
+
try {
|
|
249
|
+
const f = p.slice(8);
|
|
250
|
+
if (existsSync(f) && readFileSync(f, "utf8").trim() === "") { unlinkSync(f); removed.push(p); }
|
|
251
|
+
} catch { /* not removed */ }
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
241
254
|
try { unlinkSync(p); removed.push(p); } catch { /* already gone */ }
|
|
242
255
|
}
|
|
243
256
|
return removed;
|
|
@@ -259,6 +272,7 @@ export function installBothLinks({ dest, home, platform = process.platform, binD
|
|
|
259
272
|
const r = ensureLinks({ home, platform, binDir: dir, env, targets, addToPath, readRegPath });
|
|
260
273
|
const created = BINS.map(pathOf).filter((p) => r.created.includes(p) || ours.some((bin) => pathOf(bin) === p));
|
|
261
274
|
if (r.pathAdded) created.push("PATH:" + dir); // recorded only when this install wrote the PATH entry
|
|
275
|
+
if (r.profileCreated) created.push("PROFILE:" + r.profileCreated); // right after PATH: the profile install made
|
|
262
276
|
return { created, pathAdded: r.pathAdded, kept, dir };
|
|
263
277
|
}
|
|
264
278
|
|
package/lib/hook-wire.js
CHANGED
|
@@ -61,11 +61,19 @@ function route(cmd, lite) {
|
|
|
61
61
|
return null;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// A dev seat: a harness checkout beside this lite (its .claude/hooks/wkharness-run.sh exists) that is not a web user install
|
|
65
|
+
// (no .wk-user-install marker in the harness folder). Python --wire uses the same two tests (tools/wkharness-lite.sh).
|
|
66
|
+
export function isDevSeat(lite) {
|
|
67
|
+
const kih = dirname(dirname(lite));
|
|
68
|
+
return existsSync(join(kih, ".claude", "hooks", "wkharness-run.sh")) && !existsSync(join(kih, ".wk-user-install"));
|
|
69
|
+
}
|
|
70
|
+
|
|
64
71
|
// The node port of --wire, plus the create step of the web installer. Throws on a settings file that is not JSON.
|
|
65
72
|
export function wireSettings(path, lite) {
|
|
66
73
|
const r = readSettings(path);
|
|
67
74
|
if (!r.ok) throw new Error(path + " is not plain JSON (" + r.err + ")");
|
|
68
75
|
const d = r.json || {};
|
|
76
|
+
const dev = isDevSeat(lite) && harnessHooks(d).some((h) => /wkharness-run\.sh/.test(h.command));
|
|
69
77
|
const out = {};
|
|
70
78
|
for (const [ev, groups] of Object.entries(d.hooks && typeof d.hooks === "object" ? d.hooks : {})) {
|
|
71
79
|
const keep = [];
|
|
@@ -75,6 +83,8 @@ export function wireSettings(path, lite) {
|
|
|
75
83
|
const seen = new Set(), hs = [];
|
|
76
84
|
for (const h of asHooks(g)) {
|
|
77
85
|
const cmd = String((h && h.command) || "");
|
|
86
|
+
// a dev seat runs its full harness and never also the lite one (owner 2026-11-12): lite entries go, the rest stay verbatim
|
|
87
|
+
if (dev) { if (!/wkharness-lite\.sh/.test(cmd)) hs.push(h); continue; }
|
|
78
88
|
const c = HARNESS_HOOK.test(cmd) ? route(cmd, lite) : null; // only a harness hook is ever rewritten
|
|
79
89
|
if (c && !seen.has(c)) { seen.add(c); hs.push({ type: "command", command: c, timeout: 10 }); }
|
|
80
90
|
else if (!c && !HARNESS_HOOK.test(cmd)) hs.push(h); // a user's own hook stays verbatim
|
|
@@ -83,7 +93,8 @@ export function wireSettings(path, lite) {
|
|
|
83
93
|
}
|
|
84
94
|
if (keep.length) out[ev] = keep;
|
|
85
95
|
}
|
|
86
|
-
|
|
96
|
+
// a dev seat gets no lite arm added: its full harness is the only chain
|
|
97
|
+
if (!dev) for (const [ev, arm, matcher] of ARMS) {
|
|
87
98
|
const c = '"' + lite + '" ' + arm;
|
|
88
99
|
if (!(out[ev] || []).some((g) => (g.hooks || []).some((h) => h.command === c)))
|
|
89
100
|
(out[ev] = out[ev] || []).push({ ...(matcher ? { matcher } : {}), hooks: [{ type: "command", command: c, timeout: 10 }] });
|
|
@@ -124,6 +135,16 @@ function wireClaudeHooksInner(o) {
|
|
|
124
135
|
log("hooks: WARN " + o.settings + " is not plain JSON (" + before.err + "); left untouched -- please fix it, then run: wkappbot-code install");
|
|
125
136
|
return res;
|
|
126
137
|
}
|
|
138
|
+
// A dev seat with both its full hook and a lite entry (owner 2026-11-12: two Stop chains fired): drop the lite entries
|
|
139
|
+
// and keep the full hook, whatever state the settings reports as.
|
|
140
|
+
const liteOnDisk = join(o.kih, "tools", "wkharness-lite.sh");
|
|
141
|
+
if (before.hooks.some((h) => /wkharness-run\.sh/.test(h.command)) && before.hooks.some((h) => /wkharness-lite\.sh/.test(h.command)) && isDevSeat(liteOnDisk)) {
|
|
142
|
+
wireSettings(o.settings, liteOnDisk);
|
|
143
|
+
const dev = analyzeHooks(o.settings, o.kih);
|
|
144
|
+
res.after = dev.state; res.changed = true;
|
|
145
|
+
log("hooks: " + o.settings + " runs the full harness on this dev seat; its lite hook entries were removed");
|
|
146
|
+
return res;
|
|
147
|
+
}
|
|
127
148
|
if (before.state === "ours") { log("hooks: " + o.settings + " already runs every harness hook from " + o.kih); return res; }
|
|
128
149
|
// A FULL harness hook (wkharness-run.sh, the pwsh hub of a dev seat) is never rewritten into the lite one where pwsh
|
|
129
150
|
// runs: the rewrite would downgrade the owner's own seats. Leave it and say what to do.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wkappbot-code",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.26",
|
|
4
4
|
"description": "wkappbot-code -- Wisdom Kernel: the pinned OpenCode bridge plus the reflex harness plugin, the wkappbot core, the web harness and the latest public skills in one install",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|