@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 +37 -0
- package/bin/idocs.js +45 -0
- package/package.json +41 -0
- package/scripts/link-local.mjs +65 -0
- package/scripts/postinstall.mjs +119 -0
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();
|