osx-query 0.1.2 → 0.1.3
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 +72 -6
- package/lib/install.js +65 -3
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,21 +1,87 @@
|
|
|
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`
|
|
27
|
+
|
|
28
|
+
## Examples
|
|
10
29
|
|
|
11
|
-
|
|
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`
|
|
18
56
|
|
|
19
|
-
|
|
20
|
-
- macOS `x64`
|
|
57
|
+
## Optional Codex Skill
|
|
21
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.
|
|
66
|
+
|
|
67
|
+
To suppress the prompt entirely:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
OSX_QUERY_SKIP_SKILLS_PROMPT=1 npm i -g osx-query
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Troubleshooting
|
|
74
|
+
|
|
75
|
+
If the install succeeds but `osx` is not found:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
hash -r
|
|
79
|
+
which osx
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
If you need to reinstall:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm uninstall -g osx-query
|
|
86
|
+
npm i -g osx-query
|
|
87
|
+
```
|
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");
|
|
@@ -89,10 +90,69 @@ function installBinary(extractedRoot, vendorDir) {
|
|
|
89
90
|
fs.chmodSync(targetBinary, 0o755);
|
|
90
91
|
}
|
|
91
92
|
|
|
93
|
+
function shouldPromptForSkills() {
|
|
94
|
+
if (process.env.CI) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (process.env.OSX_QUERY_SKIP_SKILLS_PROMPT === "1") {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function maybePromptForSkills() {
|
|
106
|
+
if (!shouldPromptForSkills()) {
|
|
107
|
+
console.log(
|
|
108
|
+
"Optional: run `npx skills add Moulik-Budhiraja/OSX-Query` to install the Codex skill."
|
|
109
|
+
);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const rl = readline.createInterface({
|
|
114
|
+
input: process.stdin,
|
|
115
|
+
output: process.stdout,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const answer = await rl.question(
|
|
120
|
+
"Install the optional Codex skill now? This will run `npx skills add Moulik-Budhiraja/OSX-Query` [y/N]: "
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (!/^(y|yes)$/i.test(answer.trim())) {
|
|
124
|
+
console.log(
|
|
125
|
+
"Skipped skill install. You can run `npx skills add Moulik-Budhiraja/OSX-Query` later."
|
|
126
|
+
);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
} finally {
|
|
130
|
+
rl.close();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const command = process.platform === "win32" ? "npx.cmd" : "npx";
|
|
134
|
+
const result = spawnSync(command, ["skills", "add", "Moulik-Budhiraja/OSX-Query"], {
|
|
135
|
+
stdio: "inherit",
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (result.error) {
|
|
139
|
+
console.warn(
|
|
140
|
+
"Skill installer could not be launched. Run `npx skills add Moulik-Budhiraja/OSX-Query` manually."
|
|
141
|
+
);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (result.status !== 0) {
|
|
146
|
+
console.warn(
|
|
147
|
+
"Skill install did not complete successfully. Run `npx skills add Moulik-Budhiraja/OSX-Query` manually."
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
92
152
|
async function main() {
|
|
93
|
-
const
|
|
94
|
-
const assetName = getAssetName(
|
|
95
|
-
const url = `https://github.com/Moulik-Budhiraja/OSX-Query/releases/download/v${
|
|
153
|
+
const binaryVersion = pkg.osxBinaryVersion || pkg.version;
|
|
154
|
+
const assetName = getAssetName(binaryVersion);
|
|
155
|
+
const url = `https://github.com/Moulik-Budhiraja/OSX-Query/releases/download/v${binaryVersion}/${assetName}`;
|
|
96
156
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "osx-query-"));
|
|
97
157
|
const zipPath = path.join(tempDir, assetName);
|
|
98
158
|
const extractDir = path.join(tempDir, "extract");
|
|
@@ -107,6 +167,8 @@ async function main() {
|
|
|
107
167
|
|
|
108
168
|
extract(zipPath, extractDir);
|
|
109
169
|
installBinary(extractDir, vendorDir);
|
|
170
|
+
console.log("Installed osx. Run `osx --help` to get started.");
|
|
171
|
+
await maybePromptForSkills();
|
|
110
172
|
} finally {
|
|
111
173
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
112
174
|
}
|