@linxiraos/main 1.2.0 → 1.3.1

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,26 +1,60 @@
1
- # zeta — the Zeta workspace
1
+ # zetawork — the Zeta workspace
2
2
 
3
- One terminal, many tools: `zeta` opens a nested-terminal workbench — top-level
4
- tabs, tiled panes of real embedded terminals (PTY children), and a menu of the
5
- Zeta suite. Type `zeta` in a project directory and everything is one key away:
3
+ One terminal, many tools: `zetawork` opens a nested-terminal workbench —
4
+ top-level tabs, tiled panes of real embedded terminals (PTY children), and a
5
+ menu of the Zeta suite. Type `zetawork` in a project directory and everything
6
+ is one key away:
6
7
 
7
- - `Alt+C` — a pane running `zeta-c` (the coding agent)
8
- - `Alt+E` — a pane running `zeta-e` (the terminal editor)
8
+ - `Alt+C` — a pane running `zetacode` (the coding agent)
9
+ - `Alt+E` — the built-in editor pane (no separate editor command exists)
9
10
  - `Alt+N` / `Alt+S` — a plain shell pane
10
11
  - `Alt+T` / `Alt+1..9` — new tab / jump between tabs (each tab keeps its own
11
12
  layout)
12
13
  - `Alt+L` — cycle the pane layout (1x1, side-by-side, 2x2)
13
- - `F1` — in-app help; `zeta --help` — the same map on the command line
14
+ - `F1` — in-app help; `zetawork --help` — the same map on the command line
14
15
 
15
- Every tool also runs standalone (`zeta-c`, `zeta-editor`/`zeta-e`,
16
- `zeta-ide`/`zeta-i`, each with its own `--help`).
16
+ A bare `zeta` is the suite index: it prints the help that lists `zetawork`,
17
+ `zetacode`, and `zetaide`. `zetawork web` serves the full Web UI on loopback
18
+ for your browser. Every command also runs standalone (`zetawork`, `zetacode`,
19
+ `zetaide`, each with its own `--help`).
17
20
 
18
21
  The workspace is Rust (ratatui + portable-pty via the vendored TermIDE panel
19
22
  crates). This tree is its own Cargo workspace — `cargo build` inside `main/`.
20
23
 
21
24
  ## npm distribution
22
25
 
23
- `@linxiraos/main` (bin `zeta`) with `@linxiraos/main-windows-x64` /
24
- `@linxiraos/main-linux-x64` platform leaves, mirroring the editor and ide
25
- packages. Platform binaries are built locally and committed into the leaf
26
- `bin/` directories before a release.
26
+ `@linxiraos/main` (bins `zetawork` and `zeta`) with
27
+ `@linxiraos/main-windows-x64` / `@linxiraos/main-linux-x64` platform leaves,
28
+ mirroring the editor and ide packages. Platform binaries are built locally and
29
+ committed into the leaf `bin/` directories before a release.
30
+
31
+ ### Companions: zetacode and zetaide ship with zetawork
32
+
33
+ Installing the workbench installs the whole suite: the same
34
+ `optionalDependencies` block that pins the platform leaves also pins
35
+ `@linxiraos/zeta` (bin `zetacode`) and `@linxiraos/ide` (bin `zetaide`) at this
36
+ package's own version. npm therefore materializes all three products under
37
+ `node_modules/@linxiraos/`:
38
+
39
+ | Product | npm package / binary |
40
+ | ---------- | ---------------------------------------------------------------------- |
41
+ | `zetawork` | `@linxiraos/main-windows-x64/bin/zeta.exe` · `@linxiraos/main-linux-x64/bin/zeta-linux-x64` |
42
+ | `zetacode` | `@linxiraos/zeta` (published bin `zetacode` → `dist/cli.js`) |
43
+ | `zetaide` | `@linxiraos/ide-windows-x64/bin/termide.exe` · `@linxiraos/ide-linux-x64/bin/termide-linux-x64` |
44
+
45
+ **Why `optionalDependencies` and not `dependencies`.** Two reasons, and they
46
+ are the same two that govern the platform leaves:
47
+
48
+ - the companions are pinned to an **exact** version, so make no sense as a
49
+ range; the repo's one-version-line rule makes an exact pin the honest form;
50
+ - an install must never fail because one companion is unavailable for the
51
+ host. The companion packages carry their own `os`/`cpu`-gated leaves
52
+ (`os: ["win32"]` / `os: ["linux"]`, `cpu: ["x64"]`), so npm skips the
53
+ foreign binary — a Linux install never drags a Windows `.exe` — and a
54
+ registry/skip failure degrades to a missing command with a resolver message
55
+ instead of aborting the whole workbench install.
56
+
57
+ No binary is duplicated into a leaf: the workbench binary stays in
58
+ `main-<platform>-x64`, `zetacode` stays in `@linxiraos/zeta`, `zetaide` stays in
59
+ `@linxiraos/ide-<platform>-x64`. `scripts/check-workbench-bundles.ts` guards the
60
+ declaration and the release/packaging steps that carry it.
package/bin/launch.js ADDED
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ // Shared launcher for the workbench's two bins (`zetawork`, `zeta`): unified
3
+ // binary discovery, npm-form face:
4
+ // ① explicit env — ZETA_BIN_DIR (delimiter-separated dirs, probed first)
5
+ // ② PATH — a *native* zetawork/zeta binary (distro pacman install
6
+ // or a real .exe); PATH hits are used as-is, with no
7
+ // cross-component version validation
8
+ // ③ npm vendored — the platform-leaf binary shipped as
9
+ // @linxiraos/main-<platform>-<arch> (same pattern as the
10
+ // zetaide launcher), then the repo target/release location
11
+ // for source checkouts
12
+ //
13
+ // The two bins exec the same native binary, and only the *entry* differs: a
14
+ // bare `zetawork` opens the workspace, a bare `zeta` prints the suite index
15
+ // (`--help`). The entry therefore travels as an explicit argv token
16
+ // (`--zeta-entry=<name>`) the binary strips before any other parsing — npm's
17
+ // shims all exec one file, so argv[0] cannot carry it.
18
+ // Node-only, no Bun needed.
19
+
20
+ const fs = require("node:fs");
21
+ const path = require("node:path");
22
+ const { spawn } = require("node:child_process");
23
+
24
+ // npm package names use "windows"; Node's process.platform is "win32".
25
+ const PKG_PLATFORM = process.platform === "win32" ? "windows" : process.platform;
26
+ const PKG_PREFIX = "@linxiraos/main-";
27
+ const EXE = process.platform === "win32" ? "zeta.exe" : "zeta-linux-x64";
28
+ const NATIVE_BINS = ["zetawork", "zeta"];
29
+
30
+ /** Entry tokens the native binary understands (see main.rs `entry_of`). */
31
+ const ENTRY_WORKBENCH = "workbench";
32
+ const ENTRY_INDEX = "zeta";
33
+
34
+ function die(msg) {
35
+ process.stderr.write(`zetawork: ${msg}\n`);
36
+ process.exit(1);
37
+ }
38
+
39
+ /** Native-executable test so PATH probes never pick up another JS shim
40
+ * (npm's .cmd/.ps1/sh launchers for this very package live on PATH —
41
+ * re-executing them would recurse into this script). POSIX also demands
42
+ * the exec bit: a non-executable ELF (broken extract, cache artifact)
43
+ * would only die later with a raw spawn EACCES. */
44
+ function isNativeBinary(candidate) {
45
+ let stat;
46
+ try {
47
+ stat = fs.statSync(candidate);
48
+ } catch {
49
+ return false;
50
+ }
51
+ if (!stat.isFile()) return false;
52
+ if (process.platform === "win32") {
53
+ return candidate.toLowerCase().endsWith(".exe");
54
+ }
55
+ if (!isExecutable(candidate)) return false;
56
+ let head;
57
+ try {
58
+ const fd = fs.openSync(candidate, "r");
59
+ const buf = Buffer.alloc(4);
60
+ const read = fs.readSync(fd, buf, 0, 4, 0);
61
+ fs.closeSync(fd);
62
+ head = read === 4 ? buf : null;
63
+ } catch {
64
+ return false;
65
+ }
66
+ return head !== null && head.equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46])); // \x7fELF
67
+ }
68
+
69
+ /** POSIX exec-bit probe; Windows access(X_OK) always succeeds, which is
70
+ * fine there — a named .exe is the platform's native form. */
71
+ function isExecutable(candidate) {
72
+ try {
73
+ fs.accessSync(candidate, fs.constants.X_OK);
74
+ return true;
75
+ } catch {
76
+ return false;
77
+ }
78
+ }
79
+
80
+ /** Native executable candidates for one bin name per directory entry:
81
+ * `name.exe` on Windows, the bare ELF name elsewhere. */
82
+ function nativeCandidates(dir, name) {
83
+ return process.platform === "win32" ? [path.join(dir, `${name}.exe`)] : [path.join(dir, name)];
84
+ }
85
+
86
+ /** First native hit for the workbench bins inside `dirs`, or null. */
87
+ function findNativeIn(dirs) {
88
+ for (const dir of dirs) {
89
+ if (!dir) continue;
90
+ for (const name of NATIVE_BINS) {
91
+ for (const candidate of nativeCandidates(dir, name)) {
92
+ if (isNativeBinary(candidate)) return candidate;
93
+ }
94
+ }
95
+ }
96
+ return null;
97
+ }
98
+
99
+ function explicitDirs() {
100
+ const raw = process.env.ZETA_BIN_DIR;
101
+ if (!raw) return [];
102
+ return raw.split(path.delimiter).map((dir) => dir.trim()).filter((dir) => dir.length > 0);
103
+ }
104
+
105
+ /** Windows env blocks carry `Path`, POSIX `PATH` — accept either spelling. */
106
+ function pathDirs() {
107
+ const raw = process.env.PATH ?? process.env.Path;
108
+ return (raw || "").split(path.delimiter);
109
+ }
110
+
111
+ /** Resolve the native binary, or exit with the install hint. */
112
+ function resolveBinary() {
113
+ // ① explicit env → ② PATH (native binaries only)
114
+ const fromNative = findNativeIn([...explicitDirs(), ...pathDirs()]);
115
+ if (fromNative) return fromNative;
116
+
117
+ // ③ npm vendored platform leaf. A resolved but non-executable leaf
118
+ // (broken extract, cache artifact) must fall through to the install
119
+ // hint instead of dying later with a raw spawn EACCES.
120
+ try {
121
+ const leaf = require.resolve(`${PKG_PREFIX}${PKG_PLATFORM}-${process.arch}/bin/${EXE}`);
122
+ if (process.platform === "win32" || isExecutable(leaf)) return leaf;
123
+ } catch {
124
+ // Fall back to a repo-layout location (dev / source checkout):
125
+ // <repo>/main/target/release/<exe> next to this package.
126
+ const local = path.join(__dirname, "..", "..", "..", "target", "release", EXE);
127
+ if (fs.existsSync(local) && (process.platform === "win32" || isExecutable(local))) return local;
128
+ }
129
+
130
+ die(
131
+ `no native zetawork/zeta on PATH and no binary for ${process.platform}-${process.arch}; ` +
132
+ `install @linxiraos/main (supported: windows-x64, linux-x64) ` +
133
+ `or build from source with \`cargo build --release\` in the main/ workspace`,
134
+ );
135
+ }
136
+
137
+ /** Exec the workspace binary for one entry name (`workbench` | `zeta`),
138
+ * forwarding `argv` and the entry token. */
139
+ function launch(entry, argv) {
140
+ if (entry !== ENTRY_WORKBENCH && entry !== ENTRY_INDEX) {
141
+ die(`unknown entry \`${entry}\` (expected ${ENTRY_WORKBENCH} or ${ENTRY_INDEX})`);
142
+ }
143
+ const bin = resolveBinary();
144
+ const args = [`--zeta-entry=${entry}`, ...argv];
145
+ const child = spawn(bin, args, { stdio: "inherit" });
146
+ child.on("error", (err) => die(String(err)));
147
+ child.on("close", (code, signal) => {
148
+ if (signal) {
149
+ process.kill(process.pid, signal);
150
+ } else {
151
+ process.exit(code ?? 0);
152
+ }
153
+ });
154
+ }
155
+
156
+ module.exports = { launch, ENTRY_INDEX, ENTRY_WORKBENCH, NATIVE_BINS };
package/bin/zeta.js CHANGED
@@ -1,135 +1,8 @@
1
1
  #!/usr/bin/env node
2
- // zeta launcher — unified binary discovery, npm-form face:
3
- // ① explicit env — ZETA_BIN_DIR (delimiter-separated dirs, probed first)
4
- // ② PATH — a *native* zetawork/zeta binary (distro pacman install
5
- // or a real .exe); PATH hits are used as-is, with no
6
- // cross-component version validation
7
- // ③ npm vendored — the platform-leaf binary shipped as
8
- // @linxiraos/main-<platform>-<arch> (same pattern as the
9
- // zeta-ide / zeta-editor launchers), then the repo
10
- // target/release location for source checkouts
11
- // Node-only, no Bun needed.
2
+ "use strict";
3
+ // `zeta` — the suite index bin: a bare invocation prints the help that lists
4
+ // `zetawork`, `zetacode` and `zetaide` (the workspace itself opens with
5
+ // `zetawork`).
6
+ const { launch, ENTRY_INDEX } = require("./launch");
12
7
 
13
- const fs = require("node:fs");
14
- const path = require("node:path");
15
- const { spawn } = require("node:child_process");
16
-
17
- // npm package names use "windows"; Node's process.platform is "win32".
18
- const PKG_PLATFORM = process.platform === "win32" ? "windows" : process.platform;
19
- const PKG_PREFIX = "@linxiraos/main-";
20
- const EXE = process.platform === "win32" ? "zeta.exe" : "zeta-linux-x64";
21
- const NATIVE_BINS = ["zetawork", "zeta", "zeta-work"];
22
-
23
- function die(msg) {
24
- process.stderr.write(`zeta: ${msg}\n`);
25
- process.exit(1);
26
- }
27
-
28
- /** Native-executable test so PATH probes never pick up another JS shim
29
- * (npm's .cmd/.ps1/sh launchers for this very package live on PATH —
30
- * re-executing them would recurse into this script). POSIX also demands
31
- * the exec bit: a non-executable ELF (broken extract, cache artifact)
32
- * would only die later with a raw spawn EACCES. */
33
- function isNativeBinary(candidate) {
34
- let stat;
35
- try {
36
- stat = fs.statSync(candidate);
37
- } catch {
38
- return false;
39
- }
40
- if (!stat.isFile()) return false;
41
- if (process.platform === "win32") {
42
- return candidate.toLowerCase().endsWith(".exe");
43
- }
44
- if (!isExecutable(candidate)) return false;
45
- let head;
46
- try {
47
- const fd = fs.openSync(candidate, "r");
48
- const buf = Buffer.alloc(4);
49
- const read = fs.readSync(fd, buf, 0, 4, 0);
50
- fs.closeSync(fd);
51
- head = read === 4 ? buf : null;
52
- } catch {
53
- return false;
54
- }
55
- return head !== null && head.equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46])); // \x7fELF
56
- }
57
-
58
- /** POSIX exec-bit probe; Windows access(X_OK) always succeeds, which is
59
- * fine there — a named .exe is the platform's native form. */
60
- function isExecutable(candidate) {
61
- try {
62
- fs.accessSync(candidate, fs.constants.X_OK);
63
- return true;
64
- } catch {
65
- return false;
66
- }
67
- }
68
-
69
- /** Native executable candidates for one bin name per directory entry:
70
- * `name.exe` on Windows, the bare ELF name elsewhere. */
71
- function nativeCandidates(dir, name) {
72
- return process.platform === "win32" ? [path.join(dir, `${name}.exe`)] : [path.join(dir, name)];
73
- }
74
-
75
- /** First native hit for the workbench bins inside `dirs`, or null. */
76
- function findNativeIn(dirs) {
77
- for (const dir of dirs) {
78
- if (!dir) continue;
79
- for (const name of NATIVE_BINS) {
80
- for (const candidate of nativeCandidates(dir, name)) {
81
- if (isNativeBinary(candidate)) return candidate;
82
- }
83
- }
84
- }
85
- return null;
86
- }
87
-
88
- function explicitDirs() {
89
- const raw = process.env.ZETA_BIN_DIR;
90
- if (!raw) return [];
91
- return raw.split(path.delimiter).map((dir) => dir.trim()).filter((dir) => dir.length > 0);
92
- }
93
-
94
- /** Windows env blocks carry `Path`, POSIX `PATH` — accept either spelling. */
95
- function pathDirs() {
96
- const raw = process.env.PATH ?? process.env.Path;
97
- return (raw || "").split(path.delimiter);
98
- }
99
-
100
- // ① explicit env → ② PATH (native binaries only)
101
- const fromNative = findNativeIn([...explicitDirs(), ...pathDirs()]);
102
-
103
- let bin = fromNative;
104
- if (!bin) {
105
- // ③ npm vendored platform leaf. A resolved but non-executable leaf
106
- // (broken extract, cache artifact) must fall through to the install
107
- // hint instead of dying later with a raw spawn EACCES.
108
- try {
109
- const leaf = require.resolve(`${PKG_PREFIX}${PKG_PLATFORM}-${process.arch}/bin/${EXE}`);
110
- if (process.platform === "win32" || isExecutable(leaf)) bin = leaf;
111
- } catch {
112
- // Fall back to a repo-layout location (dev / source checkout):
113
- // <repo>/main/target/release/<exe> next to this package.
114
- const local = path.join(__dirname, "..", "..", "..", "target", "release", EXE);
115
- if (fs.existsSync(local) && (process.platform === "win32" || isExecutable(local))) bin = local;
116
- }
117
- }
118
-
119
- if (!bin) {
120
- die(
121
- `no native zetawork/zeta on PATH and no binary for ${process.platform}-${process.arch}; ` +
122
- `install @linxiraos/main (supported: windows-x64, linux-x64) ` +
123
- `or build from source with \`cargo build --release\` in the main/ workspace`,
124
- );
125
- }
126
-
127
- const child = spawn(bin, process.argv.slice(2), { stdio: "inherit" });
128
- child.on("error", (err) => die(String(err)));
129
- child.on("close", (code, signal) => {
130
- if (signal) {
131
- process.kill(process.pid, signal);
132
- } else {
133
- process.exit(code ?? 0);
134
- }
135
- });
8
+ launch(ENTRY_INDEX, process.argv.slice(2));
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ // `zetawork` — the workbench bin: a bare invocation opens the workspace.
4
+ const { launch, ENTRY_WORKBENCH } = require("./launch");
5
+
6
+ launch(ENTRY_WORKBENCH, process.argv.slice(2));
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@linxiraos/main",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "zeta — the Zeta workspace: a nested-terminal workbench with tabs, panes, and the Zeta tool suite",
5
- "license": "MIT",
5
+ "license": "AGPL-3.0-only",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
@@ -12,9 +12,8 @@
12
12
  "directory": "main"
13
13
  },
14
14
  "bin": {
15
- "zeta": "bin/zeta.js",
16
- "zetawork": "bin/zeta.js",
17
- "zeta-work": "bin/zeta.js"
15
+ "zetawork": "bin/zetawork.js",
16
+ "zeta": "bin/zeta.js"
18
17
  },
19
18
  "files": [
20
19
  "bin/",
@@ -22,8 +21,10 @@
22
21
  "README.md"
23
22
  ],
24
23
  "optionalDependencies": {
25
- "@linxiraos/main-windows-x64": "1.2.0",
26
- "@linxiraos/main-linux-x64": "1.2.0"
24
+ "@linxiraos/main-windows-x64": "1.3.1",
25
+ "@linxiraos/main-linux-x64": "1.3.1",
26
+ "@linxiraos/zeta": "1.3.1",
27
+ "@linxiraos/ide": "1.3.1"
27
28
  },
28
29
  "engines": {
29
30
  "node": ">=18"