@keydris/cli 0.1.11 → 0.1.13

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
@@ -1,9 +1,9 @@
1
1
  # @keydris/cli
2
2
 
3
- npm distribution for the native Keydris CLI.
3
+ Authority before action. npm distribution for the native Keydris CLI.
4
4
 
5
5
  ```bash
6
- npm install --global @keydris/cli
6
+ npm install --global @keydris/cli --foreground-scripts
7
7
  keydris init
8
8
  ```
9
9
 
@@ -22,3 +22,28 @@ config unchanged. npm's `--ignore-scripts` option skips this config step.
22
22
 
23
23
  The package performs no privileged work during installation. Trust-store changes
24
24
  happen only when explicitly requested through `keydris init --trust-store`.
25
+
26
+ Use [`--foreground-scripts`](https://docs.npmjs.com/cli/v11/using-npm/config/#foreground-scripts) to see the native binary and configuration checks. npm owns download progress; Keydris shows real setup stages in `keydris init`. If lifecycle scripts were disabled, `init` creates missing configuration without replacing an existing file. `KEYDRIS_NO_CONFIG=1` also disables this fallback.
27
+
28
+ The CLI respects `NO_COLOR` and supports `--color auto|always|never`. Use `keydris status` to check readiness and `keydris reset --dry-run` to preview a reset.
29
+
30
+ Interactive CLI banners show the ASCII logo in `#F8F7F4`. Set
31
+ `KEYDRIS_LOGO_COLOR=default` for the terminal's own foreground on light themes.
32
+
33
+ On Windows with **WSL2**, install using Linux Node/npm inside your distribution
34
+ (`node -p 'process.platform'` must print `linux`). Install and run the agent,
35
+ Keydris and proxy there too. Keep certificates and state in the Linux home;
36
+ do not reuse native Windows state. Claude's Linux sandbox requires `bubblewrap`
37
+ and `socat`; `keydris doctor` checks these and namespace availability. WSL1 and
38
+ detected mixed Windows/Linux execution are rejected with recovery guidance.
39
+ After WSL shuts down, run `keydris proxy up` before reopening agent sessions.
40
+
41
+ VS Code integrated terminals use the normal agent launch commands: `claude`
42
+ or `keydris codex` after onboarding. For WSL, open the folder with VS Code's WSL
43
+ extension and run setup in that terminal. Sidebar integration is separate.
44
+
45
+ `keydris init` installs a bundled `keydris-authority` skill and a short session
46
+ briefing explaining delegated authority, approvals and denials. Guidance is
47
+ embedded in the native binary; no additional download is needed. Read it with
48
+ `keydris skill` or `keydris skill --brief`. Rerun `init` after upgrades to refresh
49
+ the installed copy. Existing and user-edited skill files are preserved.
package/bin/keydris.js CHANGED
@@ -6,6 +6,11 @@ import { createRequire } from "node:module";
6
6
 
7
7
  const require = createRequire(import.meta.url);
8
8
 
9
+ if (process.platform === "win32" && (process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP)) {
10
+ console.error("keydris: Windows Node.js is running inside WSL. Install Linux Node/npm and @keydris/cli inside your WSL2 distribution, then retry.");
11
+ process.exit(1);
12
+ }
13
+
9
14
  const nativePackages = new Map([
10
15
  ["win32-x64", "@keydris/cli-win32-x64"],
11
16
  ["win32-arm64", "@keydris/cli-win32-arm64"],
@@ -47,6 +52,21 @@ function launch() {
47
52
  });
48
53
  }
49
54
 
55
+ // Explicit onboarding repairs a missing config when npm lifecycle scripts were
56
+ // disabled. Existing user config is never overwritten by this fallback.
57
+ const setupArgs = process.argv.slice(2);
58
+ if (setupArgs[0] === "--color") setupArgs.splice(0, 2);
59
+ else if (setupArgs[0]?.startsWith("--color=")) setupArgs.shift();
60
+ if (setupArgs[0] === "init" && !setupArgs.includes("--help") && !setupArgs.includes("-h")) {
61
+ try {
62
+ const { installConfig } = await import("../scripts/install-config.mjs");
63
+ await installConfig({ onlyIfMissing: true });
64
+ } catch (error) {
65
+ console.error("keydris: setup could not prepare configuration:", error.message);
66
+ process.exit(1);
67
+ }
68
+ }
69
+
50
70
  let result = launch();
51
71
  if (process.platform !== "win32" && result.error?.code === "EACCES") {
52
72
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keydris/cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Governed, per-session identity and brokered egress for AI agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,12 +20,12 @@
20
20
  "prepublishOnly": "node ../../scripts/prepublish-check.mjs"
21
21
  },
22
22
  "optionalDependencies": {
23
- "@keydris/cli-win32-x64": "0.1.11",
24
- "@keydris/cli-win32-arm64": "0.1.11",
25
- "@keydris/cli-darwin-x64": "0.1.11",
26
- "@keydris/cli-darwin-arm64": "0.1.11",
27
- "@keydris/cli-linux-x64": "0.1.11",
28
- "@keydris/cli-linux-arm64": "0.1.11"
23
+ "@keydris/cli-win32-x64": "0.1.13",
24
+ "@keydris/cli-win32-arm64": "0.1.13",
25
+ "@keydris/cli-darwin-x64": "0.1.13",
26
+ "@keydris/cli-darwin-arm64": "0.1.13",
27
+ "@keydris/cli-linux-x64": "0.1.13",
28
+ "@keydris/cli-linux-arm64": "0.1.13"
29
29
  },
30
30
  "keywords": [
31
31
  "ai",
@@ -1,54 +1,80 @@
1
- import { copyFile, readFile, writeFile } from "node:fs/promises";
1
+ import { access, copyFile, readFile, writeFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
+ import { createRequire } from "node:module";
4
+ import { fileURLToPath } from "node:url";
3
5
  import path from "node:path";
4
6
 
5
- async function installConfig() {
7
+ const require = createRequire(import.meta.url);
8
+ const color = Boolean(process.stdout.isTTY) &&
9
+ process.env.TERM !== "dumb" && !Object.hasOwn(process.env, "NO_COLOR");
10
+ const clean = (value) => String(value).replace(/[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/g, " ");
11
+ function line(state, message) {
12
+ const codes = { ok: 32, warning: 33, inactive: 90 };
13
+ const label = state === "ok" ? "[OK]" : state === "warning" ? "[!]" : "[-]";
14
+ console.log((color ? `\x1b[${codes[state]}m${label}\x1b[0m` : label) + " " + clean(message));
15
+ }
16
+
17
+ // npm downloads the native optional dependency. This script reports only
18
+ // checks/configuration it actually performs; it never fabricates download progress.
19
+ export async function installConfig({ onlyIfMissing = false } = {}) {
20
+ if (process.platform === "win32" && (process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP)) {
21
+ throw new Error("Windows Node.js was launched from WSL; install using Linux Node/npm inside WSL2 to keep Windows and Linux configuration separate");
22
+ }
6
23
  const home = homedir();
7
- if (!home) {
8
- throw new Error("could not resolve the user's home directory");
24
+ if (!home || !path.isAbsolute(home)) {
25
+ throw new Error("could not resolve the user's absolute home directory");
9
26
  }
10
-
11
- const manifest = JSON.parse(
12
- await readFile(new URL("../package.json", import.meta.url), "utf8")
13
- );
14
- const channel = manifest.version.includes("-") ? "dev" : "stable";
15
- const source = new URL(`../config/${channel}.toml`, import.meta.url);
16
- const data = await readFile(source);
17
27
  const destination = path.join(home, ".keydris.toml");
18
-
19
28
  if (process.env.KEYDRIS_NO_CONFIG === "1") {
20
- console.log(
21
- `keydris: KEYDRIS_NO_CONFIG=1; leaving ${destination} unchanged`
22
- );
29
+ if (!onlyIfMissing) line("inactive", `Configuration skipped (KEYDRIS_NO_CONFIG=1): ${destination}`);
23
30
  return;
24
31
  }
25
-
26
32
  let existing;
27
- try {
28
- existing = await readFile(destination);
29
- } catch (error) {
30
- if (error.code !== "ENOENT") {
31
- throw error;
32
- }
33
- }
33
+ try { existing = await readFile(destination); }
34
+ catch (error) { if (error.code !== "ENOENT") throw error; }
35
+ if (existing && onlyIfMissing) return;
34
36
 
37
+ const manifest = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8"));
38
+ const channel = manifest.version.includes("-") ? "dev" : "stable";
39
+ const data = await readFile(new URL(`../config/${channel}.toml`, import.meta.url));
35
40
  if (existing?.equals(data)) {
36
- console.log(`keydris: ${channel} config already up to date at ${destination}`);
41
+ line("ok", `Configuration already current: ${destination}`);
37
42
  return;
38
43
  }
39
-
40
44
  if (existing) {
41
45
  const backup = `${destination}.bak`;
42
46
  await copyFile(destination, backup);
43
- console.log(`keydris: backed up existing config to ${backup}`);
47
+ line("inactive", `Previous configuration backed up: ${backup}`);
44
48
  }
45
-
46
49
  await writeFile(destination, data, { mode: 0o644 });
47
- console.log(`keydris: wrote ${channel} config to ${destination}`);
50
+ line("ok", `${channel} configuration installed: ${destination}`);
51
+ }
52
+
53
+ async function finishInstall() {
54
+ console.log("\nKeydris · Authority before action");
55
+ let binaryReady = false;
56
+ try {
57
+ const packageName = `@keydris/cli-${process.platform}-${process.arch}`;
58
+ const executable = require.resolve(packageName);
59
+ if (!path.isAbsolute(executable)) throw new Error("native binary path is not absolute");
60
+ await access(executable);
61
+ binaryReady = true;
62
+ line("ok", `Native binary available (${process.platform}/${process.arch})`);
63
+ } catch {
64
+ line("warning", "Native binary unavailable. Reinstall @keydris/cli without --omit=optional.");
65
+ }
66
+ let configReady = true;
67
+ try { await installConfig(); }
68
+ catch (error) {
69
+ configReady = false;
70
+ line("warning", `Configuration could not be installed: ${error.message}`);
71
+ }
72
+ if (binaryReady) {
73
+ console.log(configReady ? "\nNext: keydris init" : "\nNext: keydris init (retries missing configuration)");
74
+ console.log("Setup guides you through sign-in, certificates and proxy startup.\n");
75
+ }
48
76
  }
49
77
 
50
- try {
51
- await installConfig();
52
- } catch (error) {
53
- console.warn(`keydris: WARNING: could not install ~/.keydris.toml: ${error.message}`);
78
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
79
+ await finishInstall();
54
80
  }