nori-ai-cli 0.0.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/bin/nori.js ADDED
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env node
2
+ // Unified entry point for the Codex CLI.
3
+
4
+ import { spawn } from "node:child_process";
5
+ import { existsSync } from "fs";
6
+ import path from "path";
7
+ import { fileURLToPath } from "url";
8
+
9
+ // __dirname equivalent in ESM
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ const { platform, arch } = process;
14
+
15
+ let targetTriple = null;
16
+ switch (platform) {
17
+ case "linux":
18
+ case "android":
19
+ switch (arch) {
20
+ case "x64":
21
+ targetTriple = "x86_64-unknown-linux-musl";
22
+ break;
23
+ case "arm64":
24
+ targetTriple = "aarch64-unknown-linux-musl";
25
+ break;
26
+ default:
27
+ break;
28
+ }
29
+ break;
30
+ case "darwin":
31
+ switch (arch) {
32
+ case "x64":
33
+ targetTriple = "x86_64-apple-darwin";
34
+ break;
35
+ case "arm64":
36
+ targetTriple = "aarch64-apple-darwin";
37
+ break;
38
+ default:
39
+ break;
40
+ }
41
+ break;
42
+ case "win32":
43
+ switch (arch) {
44
+ case "x64":
45
+ targetTriple = "x86_64-pc-windows-msvc";
46
+ break;
47
+ case "arm64":
48
+ targetTriple = "aarch64-pc-windows-msvc";
49
+ break;
50
+ default:
51
+ break;
52
+ }
53
+ break;
54
+ default:
55
+ break;
56
+ }
57
+
58
+ if (!targetTriple) {
59
+ throw new Error(`Unsupported platform: ${platform} (${arch})`);
60
+ }
61
+
62
+ const vendorRoot = path.join(__dirname, "..", "vendor");
63
+ const archRoot = path.join(vendorRoot, targetTriple);
64
+ const codexBinaryName = process.platform === "win32" ? "codex.exe" : "codex";
65
+ const binaryPath = path.join(archRoot, "codex", codexBinaryName);
66
+
67
+ // Use an asynchronous spawn instead of spawnSync so that Node is able to
68
+ // respond to signals (e.g. Ctrl-C / SIGINT) while the native binary is
69
+ // executing. This allows us to forward those signals to the child process
70
+ // and guarantees that when either the child terminates or the parent
71
+ // receives a fatal signal, both processes exit in a predictable manner.
72
+
73
+ function getUpdatedPath(newDirs) {
74
+ const pathSep = process.platform === "win32" ? ";" : ":";
75
+ const existingPath = process.env.PATH || "";
76
+ const updatedPath = [
77
+ ...newDirs,
78
+ ...existingPath.split(pathSep).filter(Boolean),
79
+ ].join(pathSep);
80
+ return updatedPath;
81
+ }
82
+
83
+ /**
84
+ * Use heuristics to detect the package manager that was used to install Codex
85
+ * in order to give the user a hint about how to update it.
86
+ */
87
+ function detectPackageManager() {
88
+ const userAgent = process.env.npm_config_user_agent || "";
89
+ if (/\bbun\//.test(userAgent)) {
90
+ return "bun";
91
+ }
92
+
93
+ const execPath = process.env.npm_execpath || "";
94
+ if (execPath.includes("bun")) {
95
+ return "bun";
96
+ }
97
+
98
+ if (
99
+ process.env.BUN_INSTALL ||
100
+ process.env.BUN_INSTALL_GLOBAL_DIR ||
101
+ process.env.BUN_INSTALL_BIN_DIR
102
+ ) {
103
+ return "bun";
104
+ }
105
+
106
+ return userAgent ? "npm" : null;
107
+ }
108
+
109
+ const additionalDirs = [];
110
+ const pathDir = path.join(archRoot, "path");
111
+ if (existsSync(pathDir)) {
112
+ additionalDirs.push(pathDir);
113
+ }
114
+ const updatedPath = getUpdatedPath(additionalDirs);
115
+
116
+ const env = { ...process.env, PATH: updatedPath };
117
+ const packageManagerEnvVar =
118
+ detectPackageManager() === "bun"
119
+ ? "CODEX_MANAGED_BY_BUN"
120
+ : "CODEX_MANAGED_BY_NPM";
121
+ env[packageManagerEnvVar] = "1";
122
+
123
+ const child = spawn(binaryPath, process.argv.slice(2), {
124
+ stdio: "inherit",
125
+ env,
126
+ });
127
+
128
+ child.on("error", (err) => {
129
+ // Typically triggered when the binary is missing or not executable.
130
+ // Re-throwing here will terminate the parent with a non-zero exit code
131
+ // while still printing a helpful stack trace.
132
+ // eslint-disable-next-line no-console
133
+ console.error(err);
134
+ process.exit(1);
135
+ });
136
+
137
+ // Forward common termination signals to the child so that it shuts down
138
+ // gracefully. In the handler we temporarily disable the default behavior of
139
+ // exiting immediately; once the child has been signaled we simply wait for
140
+ // its exit event which will in turn terminate the parent (see below).
141
+ const forwardSignal = (signal) => {
142
+ if (child.killed) {
143
+ return;
144
+ }
145
+ try {
146
+ child.kill(signal);
147
+ } catch {
148
+ /* ignore */
149
+ }
150
+ };
151
+
152
+ ["SIGINT", "SIGTERM", "SIGHUP"].forEach((sig) => {
153
+ process.on(sig, () => forwardSignal(sig));
154
+ });
155
+
156
+ // When the child exits, mirror its termination reason in the parent so that
157
+ // shell scripts and other tooling observe the correct exit status.
158
+ // Wrap the lifetime of the child process in a Promise so that we can await
159
+ // its termination in a structured way. The Promise resolves with an object
160
+ // describing how the child exited: either via exit code or due to a signal.
161
+ const childResult = await new Promise((resolve) => {
162
+ child.on("exit", (code, signal) => {
163
+ if (signal) {
164
+ resolve({ type: "signal", signal });
165
+ } else {
166
+ resolve({ type: "code", exitCode: code ?? 1 });
167
+ }
168
+ });
169
+ });
170
+
171
+ if (childResult.type === "signal") {
172
+ // Re-emit the same signal so that the parent terminates with the expected
173
+ // semantics (this also sets the correct exit code of 128 + n).
174
+ process.kill(process.pid, childResult.signal);
175
+ } else {
176
+ process.exit(childResult.exitCode);
177
+ }
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "nori-ai-cli",
3
+ "version": "0.0.1",
4
+ "description": "Nori AI CLI",
5
+ "license": "Apache-2.0",
6
+ "bin": {
7
+ "nori": "bin/nori.js",
8
+ "nori-ai-cli": "bin/nori.js"
9
+ },
10
+ "type": "module",
11
+ "engines": {
12
+ "node": ">=16"
13
+ },
14
+ "files": [
15
+ "bin",
16
+ "vendor"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/tilework-tech/nori-cli.git"
21
+ },
22
+ "os": ["linux"],
23
+ "cpu": ["x64"]
24
+ }