wkappbot-code 0.3.1 → 0.3.3

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/README.md CHANGED
@@ -31,7 +31,7 @@ Get the CLI by one of three roads, then run `wkappbot-code install` once:
31
31
  ```bash
32
32
  npm i -g https://kiexpert.github.io/wkappbot-kih/wkappbot-code/wkappbot-code.tgz # web: the scrub-gated tgz the SDK workflow ships daily (SHA256SUMS + version.json beside it)
33
33
  npm i -g wkappbot-code # registry (published only when the SDK has NPM_TOKEN)
34
- npm pack ./wkappbot-code && npm i -g ./wkappbot-code-0.3.1.tgz # from a checkout
34
+ npm pack ./wkappbot-code && npm i -g ./wkappbot-code-0.3.3.tgz # from a checkout
35
35
 
36
36
  wkappbot-code install # every part below, idempotent
37
37
  wkappbot-code doctor # one PASS/WARN/FAIL/SKIP row per part
@@ -44,6 +44,16 @@ const OWNER_LOGIN = "kiexpert";
44
44
  const HARNESS_BASE = () => (process.env.WK_HARNESS_BASE || "https://kiexpert.github.io/wkappbot-kih/webvm/x64/harness").replace(/\/+$/, "");
45
45
  const HARNESS_DIR = () => process.env.WK_HARNESS_DIR || join(homedir(), ".wk-harness");
46
46
  const IS_WIN = process.platform === "win32";
47
+ // Windows: the sh and tar this CLI starts are Git Bash's (MSYS). They read "D:\a\x" as host "D" plus a remote path
48
+ // ("tar: Cannot connect to C: resolve failed", SDK all-OS QA 2026-11-06), so a path handed to them is the MSYS form /d/a/x.
49
+ const shPath = (p) => (IS_WIN && /^[A-Za-z]:[\\/]/.test(p) ? "/" + p[0].toLowerCase() + p.slice(2).replace(/\\/g, "/") : p);
50
+ let _gnuTar = null;
51
+ const tarArgs = (tgz, dir) => {
52
+ if (!IS_WIN) return ["-xzf", tgz, "-C", dir];
53
+ if (_gnuTar === null) _gnuTar = /GNU tar/.test(spawnSync("tar", ["--version"], { encoding: "utf8" }).stdout || "");
54
+ // GNU (MSYS) tar takes MSYS paths; Windows' own bsdtar takes D:/ paths.
55
+ return _gnuTar ? ["--force-local", "-xzf", shPath(tgz), "-C", shPath(dir)] : ["-xzf", tgz.replace(/\\/g, "/"), "-C", dir.replace(/\\/g, "/")];
56
+ };
47
57
 
48
58
  function parseArgs(argv) {
49
59
  const o = { cmd: argv[0] || "help", npm: true, bin: true, harness: true, skills: true, webHarness: false,
@@ -92,7 +102,7 @@ function kihDir(o) {
92
102
  }
93
103
 
94
104
  function opencodeVersion() {
95
- try { return execFileSync("opencode", ["--version"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim(); }
105
+ try { return execFileSync("opencode", ["--version"], { shell: process.platform === "win32", encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim(); }
96
106
  catch { return ""; }
97
107
  }
98
108
 
@@ -141,7 +151,7 @@ function installBin(o) {
141
151
  const co = kihCheckout(o);
142
152
  const script = co && existsSync(join(co, "tools", "wk-bin-acquire.sh")) ? join(co, "tools", "wk-bin-acquire.sh") : join(PKG_DIR, "lib", "wk-bin-acquire.sh");
143
153
  log("bin: bash " + script + " acquire --dest " + dest);
144
- const r = spawnSync("bash", [script, "acquire", "--dest", dest], { encoding: "utf8", env: process.env });
154
+ const r = spawnSync("bash", [shPath(script), "acquire", "--dest", shPath(dest)], { encoding: "utf8", env: process.env });
145
155
  for (const line of ((r.stdout || "") + (r.stderr || "")).split("\n").filter(Boolean)) log(" " + line);
146
156
  if (r.status !== 0) return { ok: false, dest, note: "wk-bin-acquire rc " + r.status };
147
157
  // Put `wkappbot` on PATH beside wkappbot-code itself, unless that name is already taken by someone else.
@@ -180,8 +190,8 @@ function installHarness(o) {
180
190
  const err = curl(HARNESS_BASE() + "/install.sh", join(tmp, "install.sh"));
181
191
  if (err) return { ok: false, mode: "web", dir: HARNESS_DIR(), note: err };
182
192
  log("harness: sh " + HARNESS_BASE() + "/install.sh (to " + HARNESS_DIR() + ")");
183
- const r = spawnSync("sh", [join(tmp, "install.sh")], { encoding: "utf8",
184
- env: { ...process.env, WK_HARNESS_BASE: HARNESS_BASE(), WK_HARNESS_DIR: HARNESS_DIR() } });
193
+ const r = spawnSync("sh", [shPath(join(tmp, "install.sh"))], { encoding: "utf8",
194
+ env: { ...process.env, WK_HARNESS_BASE: HARNESS_BASE(), WK_HARNESS_DIR: shPath(HARNESS_DIR()) } });
185
195
  for (const line of ((r.stdout || "") + (r.stderr || "")).split("\n").filter(Boolean)) log(" " + line);
186
196
  const ok = r.status === 0 && hasHook(HARNESS_DIR());
187
197
  return { ok, mode: "web", dir: HARNESS_DIR(), note: ok ? "" : "harness install rc " + r.status };
@@ -252,7 +262,7 @@ function installSkills(o, dest) {
252
262
  const got = sha256File(tgz);
253
263
  if (got !== want) return { ok: false, hq, note: "sha256 MISMATCH for wk-harness-min.tar.gz: expected " + want + ", got " + got + "; no skill was copied" };
254
264
  mkdirSync(join(tmp, "x"));
255
- const r = spawnSync("tar", ["-xzf", tgz, "-C", join(tmp, "x")], { encoding: "utf8" });
265
+ const r = spawnSync("tar", tarArgs(tgz, join(tmp, "x")), { encoding: "utf8" });
256
266
  if (r.status !== 0 || !existsSync(join(tmp, "x", "skills"))) return { ok: false, hq, note: "unpack failed or no skills/ in the tarball: " + (r.stderr || "") };
257
267
  src = join(tmp, "x", "skills"); from = base + "/wk-harness-min.tar.gz (sha256 ok, version " + (vj.version || "?") + ")";
258
268
  }
@@ -321,7 +331,7 @@ function install(o) {
321
331
  if (have === OPENCODE_VERSION) log("opencode " + have + " already installed");
322
332
  else {
323
333
  log("npm install -g opencode-ai@" + OPENCODE_VERSION + " (was: " + (have || "none") + ")");
324
- execFileSync("npm", ["install", "-g", "opencode-ai@" + OPENCODE_VERSION, "--no-audit", "--no-fund"], { stdio: "inherit" });
334
+ execFileSync("npm", ["install", "-g", "opencode-ai@" + OPENCODE_VERSION, "--no-audit", "--no-fund"], { shell: process.platform === "win32", stdio: "inherit" });
325
335
  }
326
336
  }
327
337
  const dest = binDest(o);
@@ -335,7 +345,7 @@ function install(o) {
335
345
  // A user's own absolute global core.hooksPath is kept (the script WARNs). Skipped with --no-harness.
336
346
  st.pushGate = { skipped: true };
337
347
  if (o.harness && kih && existsSync(join(kih, "tools", "wk-global-hooks.sh"))) {
338
- const r = spawnSync("bash", [join(kih, "tools", "wk-global-hooks.sh"), "install", "--gate-dir", join(kih, ".githooks", "lib")], { encoding: "utf8" });
348
+ const r = spawnSync("bash", [shPath(join(kih, "tools", "wk-global-hooks.sh")), "install", "--gate-dir", shPath(join(kih, ".githooks", "lib"))], { encoding: "utf8" });
339
349
  for (const line of ((r.stdout || "") + (r.stderr || "")).split("\n").filter(Boolean)) log("push-gate: " + line);
340
350
  st.pushGate = { ok: r.status === 0, kih };
341
351
  }
package/lib/update.js CHANGED
@@ -57,7 +57,7 @@ export function readRemote(secs = 20) {
57
57
  // WKAPPBOT_CODE_NO_REGISTRY=1 skips it (tests).
58
58
  export function readRegistry(secs = 15) {
59
59
  if (process.env.WKAPPBOT_CODE_NO_REGISTRY === "1") return { ok: false, err: "registry check off" };
60
- const r = spawnSync("npm", ["view", "wkappbot-code", "version"], { encoding: "utf8", timeout: secs * 1000 });
60
+ const r = spawnSync("npm", ["view", "wkappbot-code", "version"], { shell: process.platform === "win32", encoding: "utf8", timeout: secs * 1000 });
61
61
  const v = (r.stdout || "").trim().split("\n").pop();
62
62
  return r.status === 0 && /^\d+\.\d+\.\d+/.test(v) ? { ok: true, version: v, source: "registry" } : { ok: false, err: "npm view rc " + r.status };
63
63
  }
@@ -73,7 +73,7 @@ export function runUpdate({ current, cliPath, installArgs = [], log = console.lo
73
73
  if (r.source === "registry") {
74
74
  // npm verifies the registry tarball's own integrity hash.
75
75
  log("PASS update: " + r.version + " available (installed " + current + ") on the npm registry");
76
- const g = spawnSync("npm", ["install", "-g", "wkappbot-code@" + r.version, "--no-audit", "--no-fund", "--silent"], { encoding: "utf8" });
76
+ const g = spawnSync("npm", ["install", "-g", "wkappbot-code@" + r.version, "--no-audit", "--no-fund", "--silent"], { shell: process.platform === "win32", encoding: "utf8" });
77
77
  if (g.status !== 0) { log("FAIL update: npm install -g wkappbot-code@" + r.version + " rc " + g.status); return 1; }
78
78
  log("PASS update: npm install -g wkappbot-code " + r.version);
79
79
  return reinstall(cliPath, installArgs, log);
@@ -88,7 +88,7 @@ export function runUpdate({ current, cliPath, installArgs = [], log = console.lo
88
88
  const got = createHash("sha256").update(readFileSync(tgz)).digest("hex");
89
89
  if (got !== r.sha256) { log("FAIL update: sha256 MISMATCH (expected " + r.sha256 + ", got " + got + "); nothing changed"); return 1; }
90
90
  log("PASS update: sha256 ok " + got);
91
- const n = spawnSync("npm", ["install", "-g", tgz, "--no-audit", "--no-fund", "--silent"], { encoding: "utf8" });
91
+ const n = spawnSync("npm", ["install", "-g", tgz, "--no-audit", "--no-fund", "--silent"], { shell: process.platform === "win32", encoding: "utf8" });
92
92
  if (n.status !== 0) { log("FAIL update: npm install -g rc " + n.status + " " + (n.stderr || "").trim()); return 1; }
93
93
  log("PASS update: npm install -g wkappbot-code " + r.version);
94
94
  } finally { rmSync(tmp, { recursive: true, force: true }); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wkappbot-code",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
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
  "bin": {