wkappbot-code 0.3.7 → 0.3.8

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/bin/prepack.js ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ // prepack -- bakes the minimal web harness INTO the npm package (harness/), so `npm install wkappbot-code` wires the
3
+ // Claude Code hooks from the package alone: no kih or WKAppBot checkout and no reach to the harness web page (a
4
+ // Default-environment cloud VM allows the package registries and little else; spokesman order 2026-11-06).
5
+ // harness/ holds the same four files the web page serves: install.sh, wk-harness-min.tar.gz, its .sha256, version.json.
6
+ // The tarball is the manifest bake (tools/wk-harness-min-copy.sh, scrub gate included) minus .git and bin/linux-x64, the
7
+ // core binary the installer fetches on its own (part: bin); 4 MB instead of 35 MB.
8
+ // Env: WKAPPBOT_CODE_HARNESS_STAGE = an already baked tree to pack (selftest.sh bakes once per run; 50 s per pack saved).
9
+ import { spawnSync } from "node:child_process";
10
+ import { createHash } from "node:crypto";
11
+ import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
12
+ import { tmpdir } from "node:os";
13
+ import { dirname, join, resolve } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+
16
+ const PKG_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..");
17
+ const KIH = resolve(PKG_DIR, "..");
18
+ const OUT = join(PKG_DIR, "harness");
19
+ const PKG = JSON.parse(readFileSync(join(PKG_DIR, "package.json"), "utf8"));
20
+ const die = (m) => { console.error("[wkappbot-code prepack] " + m); process.exit(1); };
21
+ const sh = (p) => process.platform === "win32" ? p.replace(/\\/g, "/") : p;
22
+
23
+ let stage = process.env.WKAPPBOT_CODE_HARNESS_STAGE || "";
24
+ let tmp = "";
25
+ const copy = join(KIH, "tools", "wk-harness-min-copy.sh");
26
+ const install = join(KIH, "webvm", "x64-build", "harness-install.sh");
27
+ // A copy of the package packed OUTSIDE a kih checkout (the self-update selftest's tree) has nothing to bake from: it
28
+ // packs without harness/ and its install falls back to the web harness. The publish packs from the checkout, and
29
+ // selftest x16 refuses a tgz that carries no harness/.
30
+ if (!existsSync(install) || (!stage && !existsSync(copy))) {
31
+ console.error("[wkappbot-code prepack] no kih checkout at " + KIH + ": harness/ not baked (install falls back to the web harness)");
32
+ process.exit(0);
33
+ }
34
+ if (!stage) {
35
+ tmp = mkdtempSync(join(tmpdir(), "wkc-prepack-"));
36
+ stage = join(tmp, "h");
37
+ const r = spawnSync("bash", [sh(copy), sh(KIH), sh(stage), sh(join(KIH, "tools", "wk-harness-min-manifest.txt"))],
38
+ { encoding: "utf8", env: { ...process.env, GIT_CONFIG_GLOBAL: "/dev/null" } });
39
+ if (r.status !== 0) die("harness bake rc " + r.status + "\n" + String(r.stderr).slice(-800));
40
+ }
41
+ if (!existsSync(join(stage, "tools", "wkharness-lite.sh"))) die("the baked tree " + stage + " has no tools/wkharness-lite.sh");
42
+
43
+ rmSync(OUT, { recursive: true, force: true });
44
+ mkdirSync(OUT, { recursive: true });
45
+ const tgz = join(OUT, "wk-harness-min.tar.gz");
46
+ const t = spawnSync("tar", ["--exclude=./.git", "--exclude=./bin/linux-x64", "-czf", sh(tgz), "-C", sh(stage), "."], { encoding: "utf8" });
47
+ if (t.status !== 0) die("tar rc " + t.status + " " + t.stderr);
48
+ const sha = createHash("sha256").update(readFileSync(tgz)).digest("hex");
49
+ writeFileSync(tgz + ".sha256", sha + " wk-harness-min.tar.gz\n");
50
+ const count = (d) => readdirSync(d, { withFileTypes: true }).reduce((n, e) => n + (e.isDirectory() ? (e.name === ".git" ? 0 : count(join(d, e.name))) : 1), 0);
51
+ writeFileSync(join(OUT, "version.json"), JSON.stringify({ version: "npm-" + PKG.version + "-" + sha.slice(0, 12), sha256: sha,
52
+ built: new Date().toISOString().replace(/\.\d+Z$/, "Z"), files: count(stage) }) + "\n");
53
+ copyFileSync(install, join(OUT, "install.sh"));
54
+ if (tmp) rmSync(tmp, { recursive: true, force: true });
55
+ console.error("[wkappbot-code prepack] harness/ baked: " + sha.slice(0, 12) + " (" + readFileSync(tgz).length + " bytes)");
@@ -45,7 +45,11 @@ const PKG_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..");
45
45
  const PKG = JSON.parse(readFileSync(join(PKG_DIR, "package.json"), "utf8"));
46
46
  const OPENCODE_VERSION = PKG.wkAppbotCode.opencodeVersion;
47
47
  const OWNER_LOGIN = "kiexpert";
48
- const HARNESS_BASE = () => (process.env.WK_HARNESS_BASE || "https://kiexpert.github.io/wkappbot-kih/webvm/x64/harness").replace(/\/+$/, "");
48
+ // The harness this package carries (harness/, baked by bin/prepack.js at pack time) comes first: it needs no checkout
49
+ // and no network (spokesman 2026-11-06, a Default-environment VM). WK_HARNESS_BASE overrides; the web page serves an unbaked tree.
50
+ const BUNDLED_HARNESS = () => join(PKG_DIR, "harness");
51
+ const HARNESS_BASE = () => (process.env.WK_HARNESS_BASE || (existsSync(join(BUNDLED_HARNESS(), "install.sh")) ? pathToFileURL(BUNDLED_HARNESS()).href
52
+ : "https://kiexpert.github.io/wkappbot-kih/webvm/x64/harness")).replace(/\/+$/, "");
49
53
  const HARNESS_DIR = () => process.env.WK_HARNESS_DIR || join(homedir(), ".wk-harness");
50
54
  const HOOKS_DIR = () => join(homedir(), ".wk-harness-hooks"); // tools/wk-global-hooks.sh install default
51
55
  const SETTINGS = () => process.env.WK_SETTINGS || join(homedir(), ".claude", "settings.json");
@@ -485,8 +489,14 @@ function uninstall(o) {
485
489
  if (isSymlink(p) || existsSync(p)) { rmSync(p, { force: true }); log("shim: removed " + p); }
486
490
  }
487
491
  // 4. the harness dirs we created, the plugin entry and our config folder
488
- if (st.harness && st.harness.mode === "web" && pr.harnessDirExisted !== true && existsSync(HARNESS_DIR())) { rmSync(HARNESS_DIR(), { recursive: true, force: true }); log("harness: removed " + HARNESS_DIR()); }
489
- if (pr.hooksDirExisted !== true && existsSync(HOOKS_DIR())) { rmSync(HOOKS_DIR(), { recursive: true, force: true }); log("push-gate: removed " + HOOKS_DIR()); }
492
+ // Windows releases a just-closed handle late (EBUSY/EPERM/ENOTEMPTY), so every tree delete retries and, when it
493
+ // still fails, names the path and goes on with the rest instead of aborting the uninstall half way.
494
+ const rmTree = (p, what) => {
495
+ try { rmSync(p, { recursive: true, force: true, maxRetries: 10, retryDelay: 300 }); if (what) log(what + ": removed " + p); }
496
+ catch (e) { rc = 1; log((what || "remove") + ": could not remove " + p + " (" + (e.code || e.message) + ") -- delete it by hand"); }
497
+ };
498
+ if (st.harness && st.harness.mode === "web" && pr.harnessDirExisted !== true && existsSync(HARNESS_DIR())) rmTree(HARNESS_DIR(), "harness");
499
+ if (pr.hooksDirExisted !== true && existsSync(HOOKS_DIR())) rmTree(HOOKS_DIR(), "push-gate");
490
500
  const cfgFile = join(configDir(o), "opencode.json");
491
501
  try {
492
502
  const c = JSON.parse(readFileSync(cfgFile, "utf8"));
@@ -498,8 +508,8 @@ function uninstall(o) {
498
508
  log("config: plugin entry removed from " + cfgFile);
499
509
  }
500
510
  } catch {}
501
- rmSync(STATE_HOME(), { recursive: true, force: true });
502
- rmSync(join(configDir(o), "wkappbot-code"), { recursive: true, force: true });
511
+ rmTree(STATE_HOME());
512
+ rmTree(join(configDir(o), "wkappbot-code"));
503
513
  log("uninstall done. Kept: opencode-ai, the wkappbot core (" + ((st.bin && st.bin.dest) || binDest(o)) + ") and its skills, and this CLI (npm rm -g wkappbot-code)");
504
514
  return rc;
505
515
  }
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "wkappbot-code",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
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": {
7
+ "prepack": "node bin/prepack.js",
7
8
  "postinstall": "node bin/postinstall.js"
8
9
  },
9
10
  "bin": {
@@ -17,7 +18,8 @@
17
18
  "plugin/*.js",
18
19
  "opencode.json",
19
20
  "install.sh",
20
- "README.md"
21
+ "README.md",
22
+ "harness/*"
21
23
  ],
22
24
  "wkAppbotCode": {
23
25
  "opencodeVersion": "1.19.5"