@rbbtsn0w/idocs 0.1.0-beta.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 ADDED
@@ -0,0 +1,37 @@
1
+ # idocs-cli (npm wrapper)
2
+
3
+ This package distributes the `idocs` Swift CLI through npm.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g idocs-cli
9
+ ```
10
+
11
+ By default, `postinstall` downloads `idocs-darwin-arm64.tar.gz` from:
12
+
13
+ `https://github.com/OWNER/REPO/releases/download/v{version}`
14
+
15
+ Override the release URL if needed:
16
+
17
+ ```bash
18
+ export IDOCS_RELEASE_BASE_URL="https://github.com/<owner>/<repo>/releases/download/v{version}"
19
+ npm install -g idocs-cli
20
+ ```
21
+
22
+ The archive is expected to contain:
23
+ - `idocs-darwin-arm64/idocs`
24
+ - `idocs-darwin-arm64/Frameworks/*.framework`
25
+
26
+ ## Local development
27
+
28
+ ```bash
29
+ ./scripts/tuist-silent.sh build iDocs
30
+ npm --prefix npm run link-local
31
+ npm --prefix npm link
32
+ idocs --help
33
+ ```
34
+
35
+ ## Strict install mode
36
+
37
+ Set `IDOCS_NPM_STRICT_INSTALL=1` to fail install when binary download fails.
package/bin/idocs.js ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync } from "node:fs";
3
+ import { chmodSync } from "node:fs";
4
+ import { dirname, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { spawnSync } from "node:child_process";
7
+
8
+ const here = dirname(fileURLToPath(import.meta.url));
9
+ const binaryPath = resolve(here, "../dist/idocs");
10
+ const frameworksPath = resolve(here, "../dist/Frameworks");
11
+
12
+ if (!existsSync(binaryPath)) {
13
+ console.error("iDocs binary not found at npm/dist/idocs.");
14
+ console.error("Try one of the following:");
15
+ console.error(" 1) npm --prefix npm run fetch-binary");
16
+ console.error(" 2) export IDOCS_RELEASE_BASE_URL='https://github.com/<owner>/<repo>/releases/download/v{version}'");
17
+ console.error(" 3) npm --prefix npm run link-local");
18
+ process.exit(1);
19
+ }
20
+
21
+ try {
22
+ chmodSync(binaryPath, 0o755);
23
+ } catch {
24
+ // Best effort.
25
+ }
26
+
27
+ const frameworkEnv = process.env.DYLD_FRAMEWORK_PATH
28
+ ? `${frameworksPath}:${process.env.DYLD_FRAMEWORK_PATH}`
29
+ : frameworksPath;
30
+
31
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
32
+ stdio: "inherit",
33
+ env: {
34
+ ...process.env,
35
+ DYLD_FRAMEWORK_PATH: frameworkEnv
36
+ }
37
+ });
38
+ if (typeof result.status === "number") {
39
+ process.exit(result.status);
40
+ }
41
+
42
+ if (result.error) {
43
+ console.error(`Failed to execute iDocs binary: ${result.error.message}`);
44
+ }
45
+ process.exit(1);
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@rbbtsn0w/idocs",
3
+ "version": "0.1.0-beta.1",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "npm distribution wrapper for the iDocs Swift CLI",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/RbBtSn0w/Apple-iDocs.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/RbBtSn0w/Apple-iDocs/issues"
14
+ },
15
+ "homepage": "https://github.com/RbBtSn0w/Apple-iDocs#readme",
16
+ "license": "MIT",
17
+ "type": "module",
18
+ "bin": {
19
+ "idocs": "./bin/idocs.js"
20
+ },
21
+ "files": [
22
+ "bin",
23
+ "scripts",
24
+ "README.md"
25
+ ],
26
+ "os": [
27
+ "darwin"
28
+ ],
29
+ "cpu": [
30
+ "arm64"
31
+ ],
32
+ "scripts": {
33
+ "postinstall": "node ./scripts/postinstall.mjs",
34
+ "fetch-binary": "node ./scripts/postinstall.mjs --force",
35
+ "link-local": "node ./scripts/link-local.mjs",
36
+ "smoke": "idocs --help"
37
+ },
38
+ "engines": {
39
+ "node": ">=20"
40
+ }
41
+ }
@@ -0,0 +1,65 @@
1
+ import { chmodSync, copyFileSync, cpSync, existsSync, mkdirSync, readdirSync, rmSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { spawnSync } from "node:child_process";
5
+
6
+ const here = dirname(fileURLToPath(import.meta.url));
7
+ const npmRoot = resolve(here, "..");
8
+ const repoRoot = resolve(npmRoot, "..");
9
+ const distDir = resolve(npmRoot, "dist");
10
+ const targetPath = resolve(distDir, "idocs");
11
+ const frameworksTargetDir = resolve(distDir, "Frameworks");
12
+
13
+ function info(msg) {
14
+ console.log(`[idocs-cli] ${msg}`);
15
+ }
16
+
17
+ function findFromDerivedData() {
18
+ const command = "find \"$HOME/Library/Developer/Xcode/DerivedData\" -path \"*/Build/Products/Debug/idocs\" -type f 2>/dev/null | head -n 1";
19
+ const result = spawnSync("bash", ["-lc", command], { encoding: "utf8" });
20
+ if (result.status !== 0) return null;
21
+ const value = result.stdout.trim();
22
+ return value.length > 0 ? value : null;
23
+ }
24
+
25
+ function resolveLocalBinary() {
26
+ const envPath = process.env.IDOCS_LOCAL_BINARY;
27
+ if (envPath && existsSync(envPath)) return envPath;
28
+
29
+ const candidates = [
30
+ resolve(process.env.HOME ?? "", "Library", "Developer", "Xcode", "DerivedData", "iDocs-codex", "Build", "Products", "Debug", "idocs"),
31
+ resolve(repoRoot, "build", "Debug", "idocs"),
32
+ resolve(repoRoot, ".build", "release", "iDocs"),
33
+ resolve(repoRoot, ".build", "debug", "iDocs")
34
+ ];
35
+
36
+ for (const candidate of candidates) {
37
+ if (existsSync(candidate)) return candidate;
38
+ }
39
+
40
+ return findFromDerivedData();
41
+ }
42
+
43
+ const sourcePath = resolveLocalBinary();
44
+ if (!sourcePath) {
45
+ console.error("[idocs-cli] Could not locate a local iDocs binary.");
46
+ console.error("[idocs-cli] Build first: ./scripts/tuist-silent.sh build iDocs");
47
+ console.error("[idocs-cli] Or set IDOCS_LOCAL_BINARY=/absolute/path/to/idocs");
48
+ process.exit(1);
49
+ }
50
+
51
+ mkdirSync(distDir, { recursive: true });
52
+ copyFileSync(sourcePath, targetPath);
53
+ chmodSync(targetPath, 0o755);
54
+
55
+ const sourceDir = dirname(sourcePath);
56
+ rmSync(frameworksTargetDir, { recursive: true, force: true });
57
+ mkdirSync(frameworksTargetDir, { recursive: true });
58
+
59
+ for (const entry of readdirSync(sourceDir)) {
60
+ if (!entry.endsWith(".framework")) continue;
61
+ cpSync(resolve(sourceDir, entry), resolve(frameworksTargetDir, entry), { recursive: true });
62
+ }
63
+
64
+ info(`Linked local binary: ${sourcePath} -> ${targetPath}`);
65
+ info(`Copied local frameworks from: ${sourceDir} -> ${frameworksTargetDir}`);
@@ -0,0 +1,119 @@
1
+ import { chmodSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { spawnSync } from "node:child_process";
5
+
6
+ const here = dirname(fileURLToPath(import.meta.url));
7
+ const npmRoot = resolve(here, "..");
8
+ const distDir = resolve(npmRoot, "dist");
9
+ const binaryPath = resolve(distDir, "idocs");
10
+ const frameworksPath = resolve(distDir, "Frameworks");
11
+ const tmpArchive = resolve(distDir, "idocs-darwin-arm64.tar.gz");
12
+ const force = process.argv.includes("--force");
13
+ const strictInstall = process.env.IDOCS_NPM_STRICT_INSTALL === "1";
14
+
15
+ function log(msg) {
16
+ console.log(`[@rbbtsn0w/idocs] ${msg}`);
17
+ }
18
+
19
+ function fail(msg, err) {
20
+ console.error(`[@rbbtsn0w/idocs] ${msg}`);
21
+ if (err?.message) {
22
+ console.error(`[@rbbtsn0w/idocs] ${err.message}`);
23
+ }
24
+ if (strictInstall) {
25
+ process.exit(1);
26
+ }
27
+ }
28
+
29
+ function getVersion() {
30
+ const pkg = JSON.parse(readFileSync(resolve(npmRoot, "package.json"), "utf8"));
31
+ return pkg.version;
32
+ }
33
+
34
+ function releaseBaseURL(version) {
35
+ const configured = process.env.IDOCS_RELEASE_BASE_URL;
36
+ if (configured && configured.trim().length > 0) {
37
+ return configured.replaceAll("{version}", version);
38
+ }
39
+ return `https://github.com/RbBtSn0w/Apple-iDocs/releases/download/v${version}`;
40
+ }
41
+
42
+ function normalizeExtractedLayout(root) {
43
+ const bundleDir = resolve(root, "idocs-darwin-arm64");
44
+ if (!existsSync(bundleDir)) {
45
+ return;
46
+ }
47
+
48
+ if (existsSync(resolve(bundleDir, "idocs"))) {
49
+ cpSync(resolve(bundleDir, "idocs"), binaryPath);
50
+ }
51
+
52
+ const frameworksDir = resolve(bundleDir, "Frameworks");
53
+ if (existsSync(frameworksDir)) {
54
+ rmSync(frameworksPath, { recursive: true, force: true });
55
+ cpSync(frameworksDir, frameworksPath, { recursive: true });
56
+ }
57
+
58
+ rmSync(bundleDir, { recursive: true, force: true });
59
+ }
60
+
61
+ async function main() {
62
+ mkdirSync(distDir, { recursive: true });
63
+
64
+ if (process.env.IDOCS_LOCAL_BINARY && existsSync(process.env.IDOCS_LOCAL_BINARY)) {
65
+ log("IDOCS_LOCAL_BINARY found; skipping download.");
66
+ return;
67
+ }
68
+
69
+ if (!force && existsSync(binaryPath)) {
70
+ chmodSync(binaryPath, 0o755);
71
+ log("Binary already present; skipping download.");
72
+ return;
73
+ }
74
+
75
+ const version = getVersion();
76
+ const assetName = "idocs-darwin-arm64.tar.gz";
77
+ const url = `${releaseBaseURL(version)}/${assetName}`;
78
+
79
+ log(`Downloading ${assetName} from ${url}`);
80
+ try {
81
+ const response = await fetch(url);
82
+ if (!response.ok) {
83
+ throw new Error(`HTTP ${response.status} when downloading ${url}`);
84
+ }
85
+
86
+ const data = Buffer.from(await response.arrayBuffer());
87
+ writeFileSync(tmpArchive, data);
88
+
89
+ const extract = spawnSync("tar", ["-xzf", tmpArchive, "-C", distDir], { stdio: "pipe" });
90
+ if (extract.status !== 0) {
91
+ throw new Error(`tar extraction failed: ${extract.stderr.toString("utf8").trim()}`);
92
+ }
93
+
94
+ normalizeExtractedLayout(distDir);
95
+
96
+ if (!existsSync(binaryPath)) {
97
+ throw new Error("archive extracted but npm/dist/idocs not found");
98
+ }
99
+
100
+ if (!existsSync(frameworksPath)) {
101
+ const entries = readdirSync(distDir).filter((item) => item.endsWith(".framework"));
102
+ if (entries.length > 0) {
103
+ mkdirSync(frameworksPath, { recursive: true });
104
+ for (const entry of entries) {
105
+ cpSync(resolve(distDir, entry), resolve(frameworksPath, entry), { recursive: true });
106
+ rmSync(resolve(distDir, entry), { recursive: true, force: true });
107
+ }
108
+ }
109
+ }
110
+
111
+ chmodSync(binaryPath, 0o755);
112
+ unlinkSync(tmpArchive);
113
+ log("Binary installed successfully.");
114
+ } catch (error) {
115
+ fail("Binary download failed. Install will continue in non-strict mode.", error);
116
+ }
117
+ }
118
+
119
+ main();