osx-query 0.1.2 → 0.1.4
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 +96 -6
- package/lib/install.js +68 -4
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,21 +1,111 @@
|
|
|
1
1
|
# osx-query
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`osx-query` installs the native `osx` CLI for querying and interacting with macOS Accessibility trees.
|
|
4
|
+
|
|
5
|
+
The npm package is a thin installer. During `npm i -g osx-query`, it downloads the signed and notarized binary that matches your Mac from the project's GitHub Releases.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
4
8
|
|
|
5
9
|
```bash
|
|
6
10
|
npm i -g osx-query
|
|
7
11
|
```
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
After install:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
osx --help
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## What You Get
|
|
20
|
+
|
|
21
|
+
- CSS-like querying of Accessibility trees
|
|
22
|
+
- Actions against matched elements
|
|
23
|
+
- Interactive query mode for exploring app structure
|
|
24
|
+
- Signed and notarized binaries for:
|
|
25
|
+
- macOS `arm64`
|
|
26
|
+
- macOS `x64`
|
|
10
27
|
|
|
11
|
-
|
|
28
|
+
## Examples
|
|
29
|
+
|
|
30
|
+
Query the focused app:
|
|
12
31
|
|
|
13
32
|
```bash
|
|
14
33
|
osx query --app focused "AXWindow AXButton"
|
|
15
34
|
```
|
|
16
35
|
|
|
17
|
-
|
|
36
|
+
Query a specific app:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
osx query --app TextEdit "AXTextArea,AXTextField"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Open the interactive selector UI:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
osx interactive TextEdit
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Requirements
|
|
49
|
+
|
|
50
|
+
- macOS
|
|
51
|
+
- Accessibility permission for the process running `osx`
|
|
52
|
+
|
|
53
|
+
If queries return nothing useful, grant Accessibility access to your terminal app in:
|
|
54
|
+
|
|
55
|
+
`System Settings -> Privacy & Security -> Accessibility`
|
|
56
|
+
|
|
57
|
+
## Optional Codex Skill
|
|
58
|
+
|
|
59
|
+
After install, the package can optionally prompt to run:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx skills add Moulik-Budhiraja/OSX-Query
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
That step is optional and only appears in an interactive terminal. If you skip it during install, you can run it later yourself.
|
|
18
66
|
|
|
19
|
-
|
|
20
|
-
- macOS `x64`
|
|
67
|
+
To suppress the prompt entirely:
|
|
21
68
|
|
|
69
|
+
```bash
|
|
70
|
+
OSX_QUERY_SKIP_SKILLS_PROMPT=1 npm i -g osx-query
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Troubleshooting
|
|
74
|
+
|
|
75
|
+
If `npm i -g osx-query` succeeds but `osx` is not found, the usual cause is that your npm global bin directory is not on `PATH`.
|
|
76
|
+
|
|
77
|
+
Check where npm installs global binaries:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm prefix -g
|
|
81
|
+
npm bin -g
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then make sure that bin directory is on your shell `PATH`.
|
|
85
|
+
|
|
86
|
+
If `osx` exists but it is the wrong one, check for command shadowing:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
which -a osx
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
That will show whether another `osx` binary or symlink is being found before the npm-installed one.
|
|
93
|
+
|
|
94
|
+
If the command is found but macOS blocks it, verify the installed binary directly:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
osx --help
|
|
98
|
+
spctl -a -t exec -vv "$(which osx)"
|
|
99
|
+
codesign -dv "$(which osx)" 2>&1 | head
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
If queries run but return nothing useful, the problem is usually Accessibility permissions, not installation. Grant access to your terminal in:
|
|
103
|
+
|
|
104
|
+
`System Settings -> Privacy & Security -> Accessibility`
|
|
105
|
+
|
|
106
|
+
If you want to reinstall cleanly:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm uninstall -g osx-query
|
|
110
|
+
npm i -g osx-query
|
|
111
|
+
```
|
package/lib/install.js
CHANGED
|
@@ -4,6 +4,7 @@ const fs = require("node:fs");
|
|
|
4
4
|
const os = require("node:os");
|
|
5
5
|
const path = require("node:path");
|
|
6
6
|
const https = require("node:https");
|
|
7
|
+
const readline = require("node:readline/promises");
|
|
7
8
|
const { pipeline } = require("node:stream/promises");
|
|
8
9
|
const { createWriteStream } = require("node:fs");
|
|
9
10
|
const { spawnSync } = require("node:child_process");
|
|
@@ -87,12 +88,72 @@ function installBinary(extractedRoot, vendorDir) {
|
|
|
87
88
|
fs.mkdirSync(vendorDir, { recursive: true });
|
|
88
89
|
fs.copyFileSync(sourceBinary, targetBinary);
|
|
89
90
|
fs.chmodSync(targetBinary, 0o755);
|
|
91
|
+
return targetBinary;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function shouldPromptForSkills() {
|
|
95
|
+
if (process.env.CI) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (process.env.OSX_QUERY_SKIP_SKILLS_PROMPT === "1") {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function maybePromptForSkills() {
|
|
107
|
+
if (!shouldPromptForSkills()) {
|
|
108
|
+
console.log(
|
|
109
|
+
"Optional: run `npx skills add Moulik-Budhiraja/OSX-Query` to install the Codex skill."
|
|
110
|
+
);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const rl = readline.createInterface({
|
|
115
|
+
input: process.stdin,
|
|
116
|
+
output: process.stdout,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const answer = await rl.question(
|
|
121
|
+
"Install the optional Codex skill now? This will run `npx skills add Moulik-Budhiraja/OSX-Query` [y/N]: "
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
if (!/^(y|yes)$/i.test(answer.trim())) {
|
|
125
|
+
console.log(
|
|
126
|
+
"Skipped skill install. You can run `npx skills add Moulik-Budhiraja/OSX-Query` later."
|
|
127
|
+
);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
} finally {
|
|
131
|
+
rl.close();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const command = process.platform === "win32" ? "npx.cmd" : "npx";
|
|
135
|
+
const result = spawnSync(command, ["skills", "add", "Moulik-Budhiraja/OSX-Query"], {
|
|
136
|
+
stdio: "inherit",
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (result.error) {
|
|
140
|
+
console.warn(
|
|
141
|
+
"Skill installer could not be launched. Run `npx skills add Moulik-Budhiraja/OSX-Query` manually."
|
|
142
|
+
);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (result.status !== 0) {
|
|
147
|
+
console.warn(
|
|
148
|
+
"Skill install did not complete successfully. Run `npx skills add Moulik-Budhiraja/OSX-Query` manually."
|
|
149
|
+
);
|
|
150
|
+
}
|
|
90
151
|
}
|
|
91
152
|
|
|
92
153
|
async function main() {
|
|
93
|
-
const
|
|
94
|
-
const assetName = getAssetName(
|
|
95
|
-
const url = `https://github.com/Moulik-Budhiraja/OSX-Query/releases/download/v${
|
|
154
|
+
const binaryVersion = pkg.osxBinaryVersion || pkg.version;
|
|
155
|
+
const assetName = getAssetName(binaryVersion);
|
|
156
|
+
const url = `https://github.com/Moulik-Budhiraja/OSX-Query/releases/download/v${binaryVersion}/${assetName}`;
|
|
96
157
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "osx-query-"));
|
|
97
158
|
const zipPath = path.join(tempDir, assetName);
|
|
98
159
|
const extractDir = path.join(tempDir, "extract");
|
|
@@ -106,7 +167,10 @@ async function main() {
|
|
|
106
167
|
fs.mkdirSync(extractDir, { recursive: true });
|
|
107
168
|
|
|
108
169
|
extract(zipPath, extractDir);
|
|
109
|
-
installBinary(extractDir, vendorDir);
|
|
170
|
+
const installedBinary = installBinary(extractDir, vendorDir);
|
|
171
|
+
console.log(`Installed osx at ${installedBinary}`);
|
|
172
|
+
console.log("Run `osx --help` to get started.");
|
|
173
|
+
await maybePromptForSkills();
|
|
110
174
|
} finally {
|
|
111
175
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
112
176
|
}
|