@clanker-code/c2c 0.8.5 → 0.8.6

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.
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const path = require("node:path");
5
+ const childProcess = require("node:child_process");
6
+ const { resolveC2cBinary } = require("..");
7
+
8
+ function executableForWrapper(argv1) {
9
+ const basename = path.basename(argv1 || "c2c");
10
+ return basename.startsWith("c2c-deliver-inbox") ? "c2c-deliver-inbox" : "c2c";
11
+ }
12
+
13
+ function main() {
14
+ const executable = executableForWrapper(process.argv[1]);
15
+ let binary;
16
+ try {
17
+ binary = resolveC2cBinary({ selfPath: __filename, executable });
18
+ } catch (error) {
19
+ console.error(error.message);
20
+ process.exit(1);
21
+ }
22
+
23
+ const result = childProcess.spawnSync(binary, process.argv.slice(2), {
24
+ stdio: "inherit",
25
+ env: process.env,
26
+ });
27
+
28
+ if (result.error) {
29
+ console.error(`failed to execute ${binary}: ${result.error.message}`);
30
+ process.exit(1);
31
+ }
32
+
33
+ if (result.signal) {
34
+ process.kill(process.pid, result.signal);
35
+ process.exit(1);
36
+ }
37
+
38
+ process.exit(result.status === null ? 1 : result.status);
39
+ }
40
+
41
+ main();
@@ -1,9 +1,41 @@
1
1
  #!/usr/bin/env node
2
- const { spawnSync } = require("child_process");
3
- const { resolveC2cBinary } = require("../index.js");
4
-
5
- const binary = resolveC2cBinary();
6
- const result = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" });
7
- if (result.error) throw result.error;
8
- if (result.signal) process.kill(process.pid, result.signal);
9
- process.exit(result.status === null ? 1 : result.status);
2
+ "use strict";
3
+
4
+ const path = require("node:path");
5
+ const childProcess = require("node:child_process");
6
+ const { resolveC2cBinary } = require("..");
7
+
8
+ function executableForWrapper(argv1) {
9
+ const basename = path.basename(argv1 || "c2c");
10
+ return basename.startsWith("c2c-deliver-inbox") ? "c2c-deliver-inbox" : "c2c";
11
+ }
12
+
13
+ function main() {
14
+ const executable = executableForWrapper(process.argv[1]);
15
+ let binary;
16
+ try {
17
+ binary = resolveC2cBinary({ selfPath: __filename, executable });
18
+ } catch (error) {
19
+ console.error(error.message);
20
+ process.exit(1);
21
+ }
22
+
23
+ const result = childProcess.spawnSync(binary, process.argv.slice(2), {
24
+ stdio: "inherit",
25
+ env: process.env,
26
+ });
27
+
28
+ if (result.error) {
29
+ console.error(`failed to execute ${binary}: ${result.error.message}`);
30
+ process.exit(1);
31
+ }
32
+
33
+ if (result.signal) {
34
+ process.kill(process.pid, result.signal);
35
+ process.exit(1);
36
+ }
37
+
38
+ process.exit(result.status === null ? 1 : result.status);
39
+ }
40
+
41
+ main();
package/index.js CHANGED
@@ -1,70 +1,186 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
- const { spawnSync } = require("child_process");
4
-
5
- const PACKAGE_BY_PLATFORM = {
6
- "linux-x64": "@clanker-code/c2c-linux-x64",
7
- "linux-arm64": "@clanker-code/c2c-linux-arm64",
8
- "darwin-x64": "@clanker-code/c2c-darwin-x64",
9
- "darwin-arm64": "@clanker-code/c2c-darwin-arm64",
1
+ "use strict";
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+
6
+ const TARGETS = {
7
+ "linux-x64": {
8
+ packageName: "@clanker-code/c2c-linux-x64",
9
+ },
10
+ "linux-arm64": {
11
+ packageName: "@clanker-code/c2c-linux-arm64",
12
+ },
13
+ "darwin-x64": {
14
+ packageName: "@clanker-code/c2c-darwin-x64",
15
+ },
16
+ "darwin-arm64": {
17
+ packageName: "@clanker-code/c2c-darwin-arm64",
18
+ },
10
19
  };
11
20
 
12
- function isExecutable(file) {
21
+ const EXECUTABLES = new Set(["c2c", "c2c-deliver-inbox"]);
22
+
23
+ function normalizeExecutable(executable = "c2c") {
24
+ if (!EXECUTABLES.has(executable)) {
25
+ throw new Error(`unsupported c2c executable: ${executable}`);
26
+ }
27
+ return executable;
28
+ }
29
+
30
+ function envOverrideName(executable) {
31
+ return executable === "c2c-deliver-inbox" ? "C2C_DELIVER_INBOX_BIN" : "C2C_BIN";
32
+ }
33
+
34
+ function canExecute(file) {
13
35
  try {
14
36
  fs.accessSync(file, fs.constants.X_OK);
15
37
  return true;
16
- } catch (_) {
38
+ } catch {
17
39
  return false;
18
40
  }
19
41
  }
20
42
 
21
- function pathEntries() {
22
- return (process.env.PATH || "").split(path.delimiter).filter(Boolean);
43
+ function sameFile(left, right) {
44
+ if (!left || !right) {
45
+ return false;
46
+ }
47
+
48
+ try {
49
+ return fs.realpathSync(left) === fs.realpathSync(right);
50
+ } catch {
51
+ return path.resolve(left) === path.resolve(right);
52
+ }
23
53
  }
24
54
 
25
- function resolveOnPath(name) {
26
- let currentWrapper = null;
55
+ function pathCandidates(env, platform, executable) {
56
+ const pathValue = env.PATH || "";
57
+ const dirs = pathValue.split(path.delimiter).filter(Boolean);
58
+ const names =
59
+ platform === "win32"
60
+ ? [`${executable}.exe`, `${executable}.cmd`, `${executable}.bat`, executable]
61
+ : [executable];
62
+
63
+ return dirs.flatMap((dir) => names.map((name) => path.join(dir, name)));
64
+ }
65
+
66
+ function looksLikeSelfNpmShim(candidate, selfPath) {
67
+ if (!candidate.match(/\.(cmd|bat)$/i)) {
68
+ return false;
69
+ }
70
+
27
71
  try {
28
- currentWrapper = process.argv[1] ? fs.realpathSync(process.argv[1]) : null;
29
- } catch (_) {}
30
- for (const dir of pathEntries()) {
31
- const candidate = path.join(dir, name);
32
- if (!isExecutable(candidate)) continue;
33
- try {
34
- if (currentWrapper && fs.realpathSync(candidate) === currentWrapper) continue;
35
- } catch (_) {}
36
- return candidate;
72
+ const body = fs.readFileSync(candidate, "utf8");
73
+ const normalizedBody = body.replace(/\\/g, "/").toLowerCase();
74
+ const normalizedSelf = selfPath.replace(/\\/g, "/").toLowerCase();
75
+ return normalizedBody.includes(normalizedSelf) || normalizedBody.includes("c2c-js-wrapper.js");
76
+ } catch {
77
+ return false;
78
+ }
79
+ }
80
+
81
+ function findSystemExecutable(env, selfPath, platform, executable) {
82
+ for (const candidate of pathCandidates(env, platform, executable)) {
83
+ if (canExecute(candidate) && !sameFile(candidate, selfPath) && !looksLikeSelfNpmShim(candidate, selfPath)) {
84
+ return candidate;
85
+ }
37
86
  }
38
87
  return null;
39
88
  }
40
89
 
41
- function resolvePlatformPackage() {
42
- const key = `${process.platform}-${process.arch}`;
43
- const pkg = PACKAGE_BY_PLATFORM[key];
44
- if (!pkg) return null;
90
+ function platformTarget(platform, arch) {
91
+ return TARGETS[`${platform}-${arch}`] || null;
92
+ }
93
+
94
+ function platformPackageName(platform = process.platform, arch = process.arch) {
95
+ const target = platformTarget(platform, arch);
96
+ return target ? target.packageName : null;
97
+ }
98
+
99
+ function resolvePlatformPackage(target, requireFrom, executable) {
45
100
  try {
46
- return require.resolve(`${pkg}/bin/${process.platform === "win32" ? "c2c.exe" : "c2c"}`);
47
- } catch (_) {
48
- return null;
101
+ const packageJson = require.resolve(`${target.packageName}/package.json`, {
102
+ paths: [requireFrom],
103
+ });
104
+ return path.join(path.dirname(packageJson), "bin", executable);
105
+ } catch (error) {
106
+ const directRoot = findDirectPackageRoot(requireFrom, target, executable);
107
+ if (directRoot) {
108
+ return path.join(directRoot, "bin", executable);
109
+ }
110
+ throw error;
111
+ }
112
+ }
113
+
114
+ function findDirectPackageRoot(requireFrom, target, executable) {
115
+ let current = path.resolve(requireFrom);
116
+ const parts = target.packageName.split("/");
117
+
118
+ while (true) {
119
+ const candidate = path.join(current, "node_modules", ...parts);
120
+ const bin = path.join(candidate, "bin", executable);
121
+ if (fs.existsSync(bin)) {
122
+ return candidate;
123
+ }
124
+
125
+ const next = path.dirname(current);
126
+ if (next === current) {
127
+ return null;
128
+ }
129
+ current = next;
49
130
  }
50
131
  }
51
132
 
52
- function resolveC2cBinary() {
53
- if (process.env.C2C_BIN) {
54
- if (!isExecutable(process.env.C2C_BIN)) {
55
- throw new Error(`C2C_BIN is set but is not executable: ${process.env.C2C_BIN}`);
133
+ function resolveC2cBinary(options = {}) {
134
+ const executable = normalizeExecutable(options.executable || "c2c");
135
+ const env = options.env || process.env;
136
+ const platform = options.platform || process.platform;
137
+ const arch = options.arch || process.arch;
138
+ const requireFrom = options.requireFrom || __dirname;
139
+ const selfPath = options.selfPath || path.join(__dirname, "bin", "c2c-js-wrapper.js");
140
+ const overrideName = envOverrideName(executable);
141
+
142
+ if (env[overrideName]) {
143
+ if (!canExecute(env[overrideName])) {
144
+ throw new Error(`${overrideName} is set but is not executable: ${env[overrideName]}`);
145
+ }
146
+ return env[overrideName];
147
+ }
148
+
149
+ const target = platformTarget(platform, arch);
150
+ let platformError = null;
151
+
152
+ if (target) {
153
+ try {
154
+ const resolved = resolvePlatformPackage(target, requireFrom, executable);
155
+ if (canExecute(resolved)) {
156
+ return resolved;
157
+ }
158
+ throw new Error(`resolved package binary is not executable: ${resolved}`);
159
+ } catch (error) {
160
+ platformError = error;
56
161
  }
57
- return process.env.C2C_BIN;
58
162
  }
59
- const system = resolveOnPath(process.platform === "win32" ? "c2c.exe" : "c2c");
60
- if (system) return system;
61
- const packaged = resolvePlatformPackage();
62
- if (packaged && isExecutable(packaged)) return packaged;
163
+
164
+ const systemExecutable = findSystemExecutable(env, selfPath, platform, executable);
165
+ if (systemExecutable) {
166
+ return systemExecutable;
167
+ }
168
+
169
+ if (!target) {
170
+ throw new Error(
171
+ `No c2c npm binary package is available for ${platform}-${arch}. ` +
172
+ `Install ${executable} system-wide, choose a supported platform, or set ${overrideName} to a ${executable} executable.`
173
+ );
174
+ }
175
+
63
176
  throw new Error(
64
- `No c2c binary is available for ${process.platform}-${process.arch}. ` +
65
- "Install c2c system-wide, install a supported @clanker-code/c2c platform package, " +
66
- "or set C2C_BIN=/path/to/c2c."
177
+ `Unable to find executable ${executable} in ${target.packageName} for ${platform}-${arch}. ` +
178
+ `Install @clanker-code/c2c with optional dependencies enabled, install ${executable} system-wide, or set ${overrideName}. ` +
179
+ `Cause: ${platformError.message}`
67
180
  );
68
181
  }
69
182
 
70
- module.exports = { resolveC2cBinary };
183
+ module.exports = {
184
+ resolveC2cBinary,
185
+ _platformPackageName: platformPackageName,
186
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clanker-code/c2c",
3
- "version": "0.8.5",
3
+ "version": "0.8.6",
4
4
  "description": "Resolver and CLI wrapper for the c2c agent messaging binary",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -9,16 +9,17 @@
9
9
  },
10
10
  "main": "index.js",
11
11
  "bin": {
12
- "c2c": "bin/c2c-js-wrapper.js"
12
+ "c2c": "bin/c2c-js-wrapper.js",
13
+ "c2c-deliver-inbox": "bin/c2c-deliver-inbox-js-wrapper.js"
13
14
  },
14
15
  "files": [
15
16
  "bin/",
16
17
  "index.js"
17
18
  ],
18
19
  "optionalDependencies": {
19
- "@clanker-code/c2c-linux-x64": "0.8.5",
20
- "@clanker-code/c2c-linux-arm64": "0.8.5",
21
- "@clanker-code/c2c-darwin-x64": "0.8.5",
22
- "@clanker-code/c2c-darwin-arm64": "0.8.5"
20
+ "@clanker-code/c2c-linux-x64": "0.8.6",
21
+ "@clanker-code/c2c-linux-arm64": "0.8.6",
22
+ "@clanker-code/c2c-darwin-x64": "0.8.6",
23
+ "@clanker-code/c2c-darwin-arm64": "0.8.6"
23
24
  }
24
25
  }