@ceraph/react-native-mcp 0.3.3 → 0.4.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.
- package/README.md +335 -68
- package/dist/babel-plugin/index.cjs +1 -0
- package/dist/babel-plugin/index.js +1 -0
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +1 -47
- package/dist/index.d.ts +106 -1
- package/dist/index.js +2 -1651
- package/dist/shim/async-storage-ops.d.ts +26 -0
- package/dist/shim/async-storage-ops.js +1 -0
- package/dist/shim/boot.d.ts +9 -0
- package/dist/shim/boot.js +1 -141
- package/dist/shim/camera.js +1 -62
- package/dist/shim/command-poll.d.ts +18 -0
- package/dist/shim/command-poll.js +1 -0
- package/dist/shim/config.js +1 -56
- package/dist/shim/console-capture.d.ts +16 -0
- package/dist/shim/console-capture.js +1 -0
- package/dist/shim/deep-link.js +1 -25
- package/dist/shim/dev-guard.js +1 -3
- package/dist/shim/dev-host.d.ts +1 -0
- package/dist/shim/dev-host.js +1 -0
- package/dist/shim/error-handler.js +1 -66
- package/dist/shim/fetch-interceptor.js +1 -93
- package/dist/shim/index.d.ts +3 -0
- package/dist/shim/index.js +1 -6
- package/dist/shim/keep-awake.js +1 -118
- package/dist/shim/network-ownership.d.ts +4 -0
- package/dist/shim/network-ownership.js +1 -0
- package/dist/shim/optimistic-observer.d.ts +29 -0
- package/dist/shim/optimistic-observer.js +1 -0
- package/dist/shim/reload.js +1 -76
- package/dist/shim/reset.d.ts +30 -0
- package/dist/shim/reset.js +1 -0
- package/dist/shim/signal-capture.d.ts +8 -0
- package/dist/shim/signal-capture.js +1 -15
- package/dist/shim/signal-transport.d.ts +14 -1
- package/dist/shim/signal-transport.js +1 -43
- package/dist/shim/xhr-interceptor.d.ts +39 -0
- package/dist/shim/xhr-interceptor.js +1 -0
- package/package.json +40 -11
- package/dist/app-lifecycle.d.ts +0 -50
- package/dist/app-lifecycle.js +0 -487
- package/dist/camera-image-writer.d.ts +0 -43
- package/dist/camera-image-writer.js +0 -280
- package/dist/camera-registry-sync.d.ts +0 -18
- package/dist/camera-registry-sync.js +0 -117
- package/dist/device-autonomy.d.ts +0 -30
- package/dist/device-autonomy.js +0 -117
- package/dist/error-parser.d.ts +0 -51
- package/dist/error-parser.js +0 -275
- package/dist/expo-manager.d.ts +0 -62
- package/dist/expo-manager.js +0 -447
- package/dist/init/ast-camera.d.ts +0 -29
- package/dist/init/ast-camera.js +0 -267
- package/dist/init/ast-layout.d.ts +0 -15
- package/dist/init/ast-layout.js +0 -167
- package/dist/init/claude-hook-constants.d.ts +0 -9
- package/dist/init/claude-hook-constants.js +0 -91
- package/dist/init/lan-ip.d.ts +0 -11
- package/dist/init/lan-ip.js +0 -51
- package/dist/init/monorepo.d.ts +0 -13
- package/dist/init/monorepo.js +0 -185
- package/dist/init/oauth.d.ts +0 -52
- package/dist/init/oauth.js +0 -220
- package/dist/init/package-manager.d.ts +0 -11
- package/dist/init/package-manager.js +0 -60
- package/dist/init/prompt.d.ts +0 -12
- package/dist/init/prompt.js +0 -68
- package/dist/init/shell-profile.d.ts +0 -22
- package/dist/init/shell-profile.js +0 -85
- package/dist/init/steps.d.ts +0 -135
- package/dist/init/steps.js +0 -399
- package/dist/init/url-scheme.d.ts +0 -42
- package/dist/init/url-scheme.js +0 -187
- package/dist/init/walkthrough.d.ts +0 -76
- package/dist/init/walkthrough.js +0 -340
- package/dist/init.d.ts +0 -8
- package/dist/init.js +0 -395
- package/dist/iproxy-manager.d.ts +0 -32
- package/dist/iproxy-manager.js +0 -216
- package/dist/mac-caffeinate.d.ts +0 -10
- package/dist/mac-caffeinate.js +0 -56
- package/dist/permission-interceptor.d.ts +0 -29
- package/dist/permission-interceptor.js +0 -185
- package/dist/prebuild-detector.d.ts +0 -19
- package/dist/prebuild-detector.js +0 -174
- package/dist/preflight.d.ts +0 -34
- package/dist/preflight.js +0 -847
- package/dist/screen.d.ts +0 -184
- package/dist/screen.js +0 -931
- package/dist/signal-listener.d.ts +0 -27
- package/dist/signal-listener.js +0 -135
- package/dist/simulator-boot.d.ts +0 -52
- package/dist/simulator-boot.js +0 -227
- package/dist/target.d.ts +0 -48
- package/dist/target.js +0 -267
- package/dist/uninstall/cli-runner.d.ts +0 -32
- package/dist/uninstall/cli-runner.js +0 -223
- package/dist/uninstall/footprint.d.ts +0 -40
- package/dist/uninstall/footprint.js +0 -288
- package/dist/uninstall/mcp-tools.d.ts +0 -14
- package/dist/uninstall/mcp-tools.js +0 -175
- package/dist/uninstall/revert-auth.d.ts +0 -22
- package/dist/uninstall/revert-auth.js +0 -31
- package/dist/uninstall/revert-boot.d.ts +0 -24
- package/dist/uninstall/revert-boot.js +0 -242
- package/dist/uninstall/revert-camera.d.ts +0 -12
- package/dist/uninstall/revert-camera.js +0 -199
- package/dist/uninstall/revert-ceraph-dir.d.ts +0 -27
- package/dist/uninstall/revert-ceraph-dir.js +0 -38
- package/dist/uninstall/revert-claude-hooks.d.ts +0 -19
- package/dist/uninstall/revert-claude-hooks.js +0 -191
- package/dist/uninstall/revert-gitignore.d.ts +0 -17
- package/dist/uninstall/revert-gitignore.js +0 -43
- package/dist/uninstall/revert-mcp-clients.d.ts +0 -57
- package/dist/uninstall/revert-mcp-clients.js +0 -194
- package/dist/uninstall/revert-package.d.ts +0 -34
- package/dist/uninstall/revert-package.js +0 -98
- package/dist/uninstall/revert-scheme.d.ts +0 -36
- package/dist/uninstall/revert-scheme.js +0 -139
- package/dist/uninstall/revert-signal-host-env.d.ts +0 -31
- package/dist/uninstall/revert-signal-host-env.js +0 -61
- package/dist/uninstall/walkthrough.d.ts +0 -80
- package/dist/uninstall/walkthrough.js +0 -1244
- package/dist/utils/atomic-write.d.ts +0 -1
- package/dist/utils/atomic-write.js +0 -30
- package/dist/wait-for-device.d.ts +0 -68
- package/dist/wait-for-device.js +0 -368
- package/dist/wda-manager.d.ts +0 -38
- package/dist/wda-manager.js +0 -186
- package/dist/wda-simulator.d.ts +0 -28
- package/dist/wda-simulator.js +0 -257
package/dist/target.js
DELETED
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
function runCommand(cmd, args, opts = {}) {
|
|
3
|
-
return new Promise((resolve) => {
|
|
4
|
-
let stdout = "";
|
|
5
|
-
let stderr = "";
|
|
6
|
-
let child;
|
|
7
|
-
try {
|
|
8
|
-
child = spawn(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
9
|
-
}
|
|
10
|
-
catch (err) {
|
|
11
|
-
resolve({
|
|
12
|
-
code: 127,
|
|
13
|
-
stdout: "",
|
|
14
|
-
stderr: err instanceof Error ? err.message : String(err),
|
|
15
|
-
});
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
const timer = setTimeout(() => {
|
|
19
|
-
try {
|
|
20
|
-
child.kill("SIGKILL");
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
}
|
|
24
|
-
}, opts.timeoutMs ?? 8000);
|
|
25
|
-
child.stdout?.on("data", (d) => {
|
|
26
|
-
stdout += d.toString();
|
|
27
|
-
});
|
|
28
|
-
child.stderr?.on("data", (d) => {
|
|
29
|
-
stderr += d.toString();
|
|
30
|
-
});
|
|
31
|
-
let settled = false;
|
|
32
|
-
child.on("error", (err) => {
|
|
33
|
-
if (settled)
|
|
34
|
-
return;
|
|
35
|
-
settled = true;
|
|
36
|
-
clearTimeout(timer);
|
|
37
|
-
resolve({
|
|
38
|
-
code: 127,
|
|
39
|
-
stdout,
|
|
40
|
-
stderr: stderr + (err.message ?? String(err)),
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
child.on("exit", (code) => {
|
|
44
|
-
if (settled)
|
|
45
|
-
return;
|
|
46
|
-
settled = true;
|
|
47
|
-
clearTimeout(timer);
|
|
48
|
-
resolve({ code: code ?? 1, stdout, stderr });
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
export function preferenceFromEnv(raw) {
|
|
53
|
-
const v = (raw ?? "").trim().toLowerCase();
|
|
54
|
-
if (v === "device")
|
|
55
|
-
return "device";
|
|
56
|
-
if (v === "simulator" || v === "sim")
|
|
57
|
-
return "simulator";
|
|
58
|
-
return "auto";
|
|
59
|
-
}
|
|
60
|
-
export async function listBootedSimulators() {
|
|
61
|
-
const res = await runCommand("xcrun", [
|
|
62
|
-
"simctl",
|
|
63
|
-
"list",
|
|
64
|
-
"devices",
|
|
65
|
-
"booted",
|
|
66
|
-
"-j",
|
|
67
|
-
]);
|
|
68
|
-
if (res.code !== 0)
|
|
69
|
-
return [];
|
|
70
|
-
try {
|
|
71
|
-
const parsed = JSON.parse(res.stdout);
|
|
72
|
-
const out = [];
|
|
73
|
-
const devices = parsed.devices ?? {};
|
|
74
|
-
for (const [runtimeKey, list] of Object.entries(devices)) {
|
|
75
|
-
const isIos = runtimeKey.toLowerCase().includes("ios") ||
|
|
76
|
-
runtimeKey.toLowerCase().includes("iphone");
|
|
77
|
-
if (!isIos)
|
|
78
|
-
continue;
|
|
79
|
-
if (!Array.isArray(list))
|
|
80
|
-
continue;
|
|
81
|
-
for (const dev of list) {
|
|
82
|
-
if (!dev.udid)
|
|
83
|
-
continue;
|
|
84
|
-
if ((dev.state ?? "").toLowerCase() !== "booted")
|
|
85
|
-
continue;
|
|
86
|
-
out.push({
|
|
87
|
-
udid: dev.udid,
|
|
88
|
-
name: dev.name ?? dev.udid,
|
|
89
|
-
runtime: dev.runtime ?? runtimeKey,
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return out;
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
return [];
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
export function parseWdaPort(stdout) {
|
|
100
|
-
const re = /ServerURLHere->https?:\/\/[^:/\s]+:(\d{2,5})<-ServerURLHere/;
|
|
101
|
-
const m = re.exec(stdout);
|
|
102
|
-
if (!m)
|
|
103
|
-
return null;
|
|
104
|
-
const port = Number(m[1]);
|
|
105
|
-
if (!Number.isFinite(port) || port < 1 || port > 65535)
|
|
106
|
-
return null;
|
|
107
|
-
return port;
|
|
108
|
-
}
|
|
109
|
-
export const DEFAULT_DEVICE_WDA_BASE_URL = "http://localhost:8100";
|
|
110
|
-
export function simulatorWdaBaseUrl(port) {
|
|
111
|
-
return `http://localhost:${port}`;
|
|
112
|
-
}
|
|
113
|
-
export class TargetResolver {
|
|
114
|
-
apps;
|
|
115
|
-
readPreference;
|
|
116
|
-
cached = null;
|
|
117
|
-
cachedAt = 0;
|
|
118
|
-
cacheTtlMs;
|
|
119
|
-
inflight = null;
|
|
120
|
-
stateVersion = 0;
|
|
121
|
-
simulatorWdaPort = null;
|
|
122
|
-
simulatorWdaUdid = null;
|
|
123
|
-
constructor(opts = {}) {
|
|
124
|
-
this.apps = opts.apps ?? null;
|
|
125
|
-
this.readPreference = opts.readPreference ?? (() => preferenceFromEnv(process.env.CERAPH_TARGET));
|
|
126
|
-
this.cacheTtlMs = opts.cacheTtlMs ?? 5_000;
|
|
127
|
-
}
|
|
128
|
-
setAppLifecycle(apps) {
|
|
129
|
-
this.apps = apps;
|
|
130
|
-
this.cached = null;
|
|
131
|
-
this.stateVersion++;
|
|
132
|
-
}
|
|
133
|
-
setSimulatorWdaPort(port, udid) {
|
|
134
|
-
this.simulatorWdaPort = port;
|
|
135
|
-
this.simulatorWdaUdid = udid;
|
|
136
|
-
this.cached = null;
|
|
137
|
-
this.stateVersion++;
|
|
138
|
-
}
|
|
139
|
-
clearSimulatorWdaPort() {
|
|
140
|
-
this.simulatorWdaPort = null;
|
|
141
|
-
this.simulatorWdaUdid = null;
|
|
142
|
-
this.cached = null;
|
|
143
|
-
this.stateVersion++;
|
|
144
|
-
}
|
|
145
|
-
getSimulatorWdaPort() {
|
|
146
|
-
return this.simulatorWdaPort;
|
|
147
|
-
}
|
|
148
|
-
getSimulatorWdaUdid() {
|
|
149
|
-
return this.simulatorWdaUdid;
|
|
150
|
-
}
|
|
151
|
-
invalidate() {
|
|
152
|
-
this.cached = null;
|
|
153
|
-
this.stateVersion++;
|
|
154
|
-
}
|
|
155
|
-
async getBaseUrl() {
|
|
156
|
-
const info = await this.resolve();
|
|
157
|
-
return info.baseUrl;
|
|
158
|
-
}
|
|
159
|
-
async getTarget() {
|
|
160
|
-
const info = await this.resolve();
|
|
161
|
-
return info.target;
|
|
162
|
-
}
|
|
163
|
-
async resolve() {
|
|
164
|
-
if (this.cached &&
|
|
165
|
-
this.cacheTtlMs > 0 &&
|
|
166
|
-
Date.now() - this.cachedAt < this.cacheTtlMs) {
|
|
167
|
-
return this.cached;
|
|
168
|
-
}
|
|
169
|
-
if (this.inflight)
|
|
170
|
-
return this.inflight;
|
|
171
|
-
const versionAtStart = this.stateVersion;
|
|
172
|
-
const work = (async () => {
|
|
173
|
-
const pref = this.readPreference();
|
|
174
|
-
if (pref === "device") {
|
|
175
|
-
const udid = (await this.apps?.getUdid()) ?? null;
|
|
176
|
-
return {
|
|
177
|
-
target: "device",
|
|
178
|
-
udid,
|
|
179
|
-
baseUrl: DEFAULT_DEVICE_WDA_BASE_URL,
|
|
180
|
-
wdaReady: true,
|
|
181
|
-
reason: "env-override-device",
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
if (pref === "simulator") {
|
|
185
|
-
const sims = await listBootedSimulators();
|
|
186
|
-
const picked = this.simulatorWdaUdid
|
|
187
|
-
? sims.find((s) => s.udid === this.simulatorWdaUdid) ?? sims[0]
|
|
188
|
-
: sims[0];
|
|
189
|
-
const pickedUdid = picked?.udid ?? this.simulatorWdaUdid ?? null;
|
|
190
|
-
const wdaHostStillBooted = this.simulatorWdaUdid !== null &&
|
|
191
|
-
sims.some((s) => s.udid === this.simulatorWdaUdid);
|
|
192
|
-
const portMatchesSim = this.simulatorWdaPort !== null &&
|
|
193
|
-
this.simulatorWdaUdid !== null &&
|
|
194
|
-
wdaHostStillBooted &&
|
|
195
|
-
pickedUdid === this.simulatorWdaUdid;
|
|
196
|
-
return {
|
|
197
|
-
target: "simulator",
|
|
198
|
-
udid: pickedUdid,
|
|
199
|
-
baseUrl: portMatchesSim
|
|
200
|
-
? simulatorWdaBaseUrl(this.simulatorWdaPort)
|
|
201
|
-
: DEFAULT_DEVICE_WDA_BASE_URL,
|
|
202
|
-
wdaReady: portMatchesSim,
|
|
203
|
-
reason: "env-override-simulator",
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
const [deviceUdid, sims] = await Promise.all([
|
|
207
|
-
this.apps?.getUdid() ?? Promise.resolve(null),
|
|
208
|
-
listBootedSimulators(),
|
|
209
|
-
]);
|
|
210
|
-
if (deviceUdid) {
|
|
211
|
-
return {
|
|
212
|
-
target: "device",
|
|
213
|
-
udid: deviceUdid,
|
|
214
|
-
baseUrl: DEFAULT_DEVICE_WDA_BASE_URL,
|
|
215
|
-
wdaReady: true,
|
|
216
|
-
reason: "auto-prefer-device",
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
if (sims.length > 0) {
|
|
220
|
-
const picked = this.simulatorWdaUdid
|
|
221
|
-
? sims.find((s) => s.udid === this.simulatorWdaUdid) ?? sims[0]
|
|
222
|
-
: sims[0];
|
|
223
|
-
const wdaHostStillBooted = this.simulatorWdaUdid !== null &&
|
|
224
|
-
sims.some((s) => s.udid === this.simulatorWdaUdid);
|
|
225
|
-
const portMatchesSim = this.simulatorWdaPort !== null &&
|
|
226
|
-
this.simulatorWdaUdid !== null &&
|
|
227
|
-
wdaHostStillBooted &&
|
|
228
|
-
picked.udid === this.simulatorWdaUdid;
|
|
229
|
-
return {
|
|
230
|
-
target: "simulator",
|
|
231
|
-
udid: picked.udid,
|
|
232
|
-
baseUrl: portMatchesSim
|
|
233
|
-
? simulatorWdaBaseUrl(this.simulatorWdaPort)
|
|
234
|
-
: DEFAULT_DEVICE_WDA_BASE_URL,
|
|
235
|
-
wdaReady: portMatchesSim,
|
|
236
|
-
reason: "auto-only-simulator",
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
return {
|
|
240
|
-
target: "device",
|
|
241
|
-
udid: null,
|
|
242
|
-
baseUrl: DEFAULT_DEVICE_WDA_BASE_URL,
|
|
243
|
-
wdaReady: true,
|
|
244
|
-
reason: "auto-no-target-found",
|
|
245
|
-
};
|
|
246
|
-
})();
|
|
247
|
-
this.inflight = work;
|
|
248
|
-
try {
|
|
249
|
-
const info = await work;
|
|
250
|
-
if (this.stateVersion === versionAtStart) {
|
|
251
|
-
this.cached = info;
|
|
252
|
-
this.cachedAt = Date.now();
|
|
253
|
-
}
|
|
254
|
-
return info;
|
|
255
|
-
}
|
|
256
|
-
finally {
|
|
257
|
-
this.inflight = null;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
reset() {
|
|
261
|
-
this.cached = null;
|
|
262
|
-
this.inflight = null;
|
|
263
|
-
this.simulatorWdaPort = null;
|
|
264
|
-
this.simulatorWdaUdid = null;
|
|
265
|
-
this.stateVersion++;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { type PromptDeps } from "../init/prompt.js";
|
|
2
|
-
import { type UninstallStep, type UninstallWalkthroughResult } from "./walkthrough.js";
|
|
3
|
-
export interface CliRunnerOpts extends PromptDeps {
|
|
4
|
-
argv: string[];
|
|
5
|
-
cwd?: string;
|
|
6
|
-
spawnRemove?: (input: {
|
|
7
|
-
bin: string;
|
|
8
|
-
args: string[];
|
|
9
|
-
cwd: string;
|
|
10
|
-
}) => Promise<{
|
|
11
|
-
exitCode: number;
|
|
12
|
-
}>;
|
|
13
|
-
}
|
|
14
|
-
export interface CliRunnerResult {
|
|
15
|
-
exitCode: 0 | 1;
|
|
16
|
-
walkthrough: UninstallWalkthroughResult | null;
|
|
17
|
-
parsedFlags: ParsedFlags;
|
|
18
|
-
}
|
|
19
|
-
interface ParsedFlags {
|
|
20
|
-
yes: boolean;
|
|
21
|
-
purgeImages: boolean;
|
|
22
|
-
global: boolean;
|
|
23
|
-
dryRun: boolean;
|
|
24
|
-
projectDir: string | null;
|
|
25
|
-
help: boolean;
|
|
26
|
-
unknown: string[];
|
|
27
|
-
}
|
|
28
|
-
export declare function runUninstallCli(opts: CliRunnerOpts): Promise<CliRunnerResult>;
|
|
29
|
-
export declare function formatStepLine(step: UninstallStep): string;
|
|
30
|
-
export declare function formatSummary(result: UninstallWalkthroughResult): string;
|
|
31
|
-
export declare function parseArgs(argv: string[]): ParsedFlags;
|
|
32
|
-
export {};
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { stat } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { confirm, print } from "../init/prompt.js";
|
|
5
|
-
import { runUninstallWalkthrough, } from "./walkthrough.js";
|
|
6
|
-
const USAGE = `Usage: npx @ceraph/react-native-mcp uninstall [flags]
|
|
7
|
-
|
|
8
|
-
Removes Ceraph from the current React Native / Expo project. By default:
|
|
9
|
-
- Reverts source-tree edits (CameraView, layout boot, ceraph URL scheme)
|
|
10
|
-
- Strips MCP client configs (.mcp.json, .cursor/, .vscode/, .codex/)
|
|
11
|
-
- Removes gitignore entries
|
|
12
|
-
- Removes CERAPH_SIGNAL_HOST from your shell rc
|
|
13
|
-
- Removes @ceraph/react-native-mcp from package.json
|
|
14
|
-
- LEAVES .ceraph/ (test images, design snapshots) in place
|
|
15
|
-
- LEAVES ~/.ceraph/auth.json in place (token is user-global)
|
|
16
|
-
|
|
17
|
-
Flags:
|
|
18
|
-
-y, --yes Skip confirmation prompts.
|
|
19
|
-
--purge-images Also delete .ceraph/ (camera images + snapshots).
|
|
20
|
-
--global Also delete ~/.ceraph/auth.json (logs you out of
|
|
21
|
-
every Ceraph install on this machine).
|
|
22
|
-
--dry-run Preview the revert without mutating anything.
|
|
23
|
-
--project-dir <p> Operate on this subpackage. Required when a
|
|
24
|
-
monorepo has more than one RN app.
|
|
25
|
-
-h, --help Print this help and exit.
|
|
26
|
-
`;
|
|
27
|
-
export async function runUninstallCli(opts) {
|
|
28
|
-
const flags = parseArgs(opts.argv);
|
|
29
|
-
if (flags.help) {
|
|
30
|
-
print(USAGE, opts);
|
|
31
|
-
return { exitCode: 0, walkthrough: null, parsedFlags: flags };
|
|
32
|
-
}
|
|
33
|
-
if (flags.unknown.length > 0) {
|
|
34
|
-
print(`Unknown flag(s): ${flags.unknown.join(", ")}\n\n${USAGE}`, opts);
|
|
35
|
-
return { exitCode: 1, walkthrough: null, parsedFlags: flags };
|
|
36
|
-
}
|
|
37
|
-
const projectDir = flags.projectDir ?? opts.cwd ?? process.cwd();
|
|
38
|
-
if (flags.projectDir != null) {
|
|
39
|
-
const validation = await validateProjectDir(flags.projectDir);
|
|
40
|
-
if (validation !== null) {
|
|
41
|
-
print(`${validation}\n`, opts);
|
|
42
|
-
return { exitCode: 1, walkthrough: null, parsedFlags: flags };
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
let purgeImages = flags.purgeImages;
|
|
46
|
-
let global = flags.global;
|
|
47
|
-
if (!flags.yes && !flags.dryRun) {
|
|
48
|
-
print(`\n@ceraph/react-native-mcp uninstall\n`, opts);
|
|
49
|
-
print(` Project: ${projectDir}\n`, opts);
|
|
50
|
-
print(` Mode: live (no --dry-run)\n`, opts);
|
|
51
|
-
print(` Default-safe: leaves .ceraph/ and ~/.ceraph/auth.json untouched.\n\n`, opts);
|
|
52
|
-
const proceed = await confirm("Continue with uninstall?", {
|
|
53
|
-
...opts,
|
|
54
|
-
defaultYes: false,
|
|
55
|
-
});
|
|
56
|
-
if (!proceed) {
|
|
57
|
-
print(`\nAborted — no changes made.\n`, opts);
|
|
58
|
-
return { exitCode: 0, walkthrough: null, parsedFlags: flags };
|
|
59
|
-
}
|
|
60
|
-
if (!purgeImages) {
|
|
61
|
-
purgeImages = await confirm("Also purge camera images + snapshots at .ceraph/?", { ...opts, defaultYes: false });
|
|
62
|
-
}
|
|
63
|
-
if (!global) {
|
|
64
|
-
global = await confirm("Also sign out (delete ~/.ceraph/auth.json)?", { ...opts, defaultYes: false });
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
if (flags.dryRun) {
|
|
68
|
-
print(`\n@ceraph/react-native-mcp uninstall — dry-run preview\n`, opts);
|
|
69
|
-
print(` Project: ${projectDir}\n\n`, opts);
|
|
70
|
-
}
|
|
71
|
-
const walkthrough = await runUninstallWalkthrough({
|
|
72
|
-
projectDir,
|
|
73
|
-
purgeImages,
|
|
74
|
-
global,
|
|
75
|
-
dryRun: flags.dryRun,
|
|
76
|
-
nonInteractive: flags.yes,
|
|
77
|
-
spawnRemove: opts.spawnRemove ?? defaultSpawnRemove,
|
|
78
|
-
onStep: (step) => {
|
|
79
|
-
print(formatStepLine(step), opts);
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
print(formatSummary(walkthrough), opts);
|
|
83
|
-
const hasError = walkthrough.steps.some((s) => s.status === "error" || s.status === "manual");
|
|
84
|
-
return {
|
|
85
|
-
exitCode: hasError ? 1 : 0,
|
|
86
|
-
walkthrough,
|
|
87
|
-
parsedFlags: { ...flags, purgeImages, global },
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
export function formatStepLine(step) {
|
|
91
|
-
const icon = iconFor(step.status);
|
|
92
|
-
const summary = summaryFor(step);
|
|
93
|
-
return ` ${icon} ${step.name.padEnd(13)} ${summary}\n`;
|
|
94
|
-
}
|
|
95
|
-
function iconFor(status) {
|
|
96
|
-
switch (status) {
|
|
97
|
-
case "reverted":
|
|
98
|
-
return "[ok]";
|
|
99
|
-
case "already-reverted":
|
|
100
|
-
return "[--]";
|
|
101
|
-
case "skipped":
|
|
102
|
-
return "[--]";
|
|
103
|
-
case "warning":
|
|
104
|
-
return "[!]";
|
|
105
|
-
case "manual":
|
|
106
|
-
return "[!]";
|
|
107
|
-
case "error":
|
|
108
|
-
return "[X]";
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
function summaryFor(step) {
|
|
112
|
-
switch (step.status) {
|
|
113
|
-
case "reverted":
|
|
114
|
-
return `reverted${step.details?.dryRun ? " (preview)" : ""}`;
|
|
115
|
-
case "already-reverted":
|
|
116
|
-
return `nothing to do${step.details?.dryRun ? " (preview)" : ""}`;
|
|
117
|
-
case "skipped":
|
|
118
|
-
return `skipped — ${step.remediation ?? "gate closed"}`;
|
|
119
|
-
case "warning":
|
|
120
|
-
return `reverted with warning — ${step.remediation ?? ""}`;
|
|
121
|
-
case "manual":
|
|
122
|
-
return `manual action required — ${step.remediation ?? ""}`;
|
|
123
|
-
case "error":
|
|
124
|
-
return `error — ${step.remediation ?? step.details?.error ?? "see details"}`;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
export function formatSummary(result) {
|
|
128
|
-
const { reverted, skipped, warnings, manualSteps } = result.summary;
|
|
129
|
-
const lines = ["\nSummary:\n"];
|
|
130
|
-
lines.push(` Reverted: ${reverted}\n`);
|
|
131
|
-
lines.push(` Skipped/no-op: ${skipped}\n`);
|
|
132
|
-
lines.push(` Warnings: ${warnings.length}\n`);
|
|
133
|
-
lines.push(` Manual actions: ${manualSteps.length}\n`);
|
|
134
|
-
if (warnings.length > 0) {
|
|
135
|
-
lines.push(`\nWarnings:\n`);
|
|
136
|
-
for (const w of warnings)
|
|
137
|
-
lines.push(` - ${w}\n`);
|
|
138
|
-
}
|
|
139
|
-
if (manualSteps.length > 0) {
|
|
140
|
-
lines.push(`\nManual actions needed:\n`);
|
|
141
|
-
for (const m of manualSteps)
|
|
142
|
-
lines.push(` - ${m}\n`);
|
|
143
|
-
}
|
|
144
|
-
return lines.join("");
|
|
145
|
-
}
|
|
146
|
-
export function parseArgs(argv) {
|
|
147
|
-
const flags = {
|
|
148
|
-
yes: false,
|
|
149
|
-
purgeImages: false,
|
|
150
|
-
global: false,
|
|
151
|
-
dryRun: false,
|
|
152
|
-
projectDir: null,
|
|
153
|
-
help: false,
|
|
154
|
-
unknown: [],
|
|
155
|
-
};
|
|
156
|
-
for (let i = 0; i < argv.length; i++) {
|
|
157
|
-
const arg = argv[i];
|
|
158
|
-
switch (arg) {
|
|
159
|
-
case "-y":
|
|
160
|
-
case "--yes":
|
|
161
|
-
flags.yes = true;
|
|
162
|
-
break;
|
|
163
|
-
case "--purge-images":
|
|
164
|
-
flags.purgeImages = true;
|
|
165
|
-
break;
|
|
166
|
-
case "--global":
|
|
167
|
-
flags.global = true;
|
|
168
|
-
break;
|
|
169
|
-
case "--dry-run":
|
|
170
|
-
flags.dryRun = true;
|
|
171
|
-
break;
|
|
172
|
-
case "--project-dir": {
|
|
173
|
-
const next = argv[i + 1];
|
|
174
|
-
if (next == null) {
|
|
175
|
-
flags.unknown.push(`${arg} (missing value)`);
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
flags.projectDir = next;
|
|
179
|
-
i++;
|
|
180
|
-
}
|
|
181
|
-
break;
|
|
182
|
-
}
|
|
183
|
-
case "-h":
|
|
184
|
-
case "--help":
|
|
185
|
-
flags.help = true;
|
|
186
|
-
break;
|
|
187
|
-
default:
|
|
188
|
-
if (arg !== undefined)
|
|
189
|
-
flags.unknown.push(arg);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
return flags;
|
|
193
|
-
}
|
|
194
|
-
async function validateProjectDir(path) {
|
|
195
|
-
let entryStat;
|
|
196
|
-
try {
|
|
197
|
-
entryStat = await stat(path);
|
|
198
|
-
}
|
|
199
|
-
catch {
|
|
200
|
-
return `Error: --project-dir does not exist: ${path}`;
|
|
201
|
-
}
|
|
202
|
-
if (!entryStat.isDirectory()) {
|
|
203
|
-
return `Error: --project-dir is not a directory: ${path}`;
|
|
204
|
-
}
|
|
205
|
-
try {
|
|
206
|
-
await stat(join(path, "package.json"));
|
|
207
|
-
}
|
|
208
|
-
catch {
|
|
209
|
-
return (`Error: --project-dir does not look like an npm/RN project ` +
|
|
210
|
-
`(no package.json at ${join(path, "package.json")})`);
|
|
211
|
-
}
|
|
212
|
-
return null;
|
|
213
|
-
}
|
|
214
|
-
function defaultSpawnRemove(input) {
|
|
215
|
-
return new Promise((resolve) => {
|
|
216
|
-
const child = spawn(input.bin, input.args, {
|
|
217
|
-
cwd: input.cwd,
|
|
218
|
-
stdio: "inherit",
|
|
219
|
-
});
|
|
220
|
-
child.on("error", () => resolve({ exitCode: 127 }));
|
|
221
|
-
child.on("exit", (code) => resolve({ exitCode: code ?? 1 }));
|
|
222
|
-
});
|
|
223
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { detectMonorepoSubpackages } from "../init/monorepo.js";
|
|
2
|
-
import { type PackageManager } from "./revert-package.js";
|
|
3
|
-
export interface InstalledFootprint {
|
|
4
|
-
workingDir: string;
|
|
5
|
-
monorepoConflict: {
|
|
6
|
-
matches: Array<{
|
|
7
|
-
relPath: string;
|
|
8
|
-
absPath: string;
|
|
9
|
-
}>;
|
|
10
|
-
} | null;
|
|
11
|
-
packageInstalled: boolean;
|
|
12
|
-
packageManager: PackageManager;
|
|
13
|
-
appiumPresent: boolean;
|
|
14
|
-
gitignoreEntriesPresent: boolean;
|
|
15
|
-
gitignoreEntries: string[];
|
|
16
|
-
schemeRegistered: boolean | null;
|
|
17
|
-
bootTargetPath: string | null;
|
|
18
|
-
bootInjected: boolean | null;
|
|
19
|
-
ceraphCameraUsageCount: number;
|
|
20
|
-
mcpClientsConfigured: {
|
|
21
|
-
claudeCode: boolean;
|
|
22
|
-
cursor: boolean;
|
|
23
|
-
codex: boolean;
|
|
24
|
-
vscode: boolean;
|
|
25
|
-
windsurf: boolean;
|
|
26
|
-
antigravity: boolean;
|
|
27
|
-
};
|
|
28
|
-
claudeHooksPresent: {
|
|
29
|
-
errorScript: boolean;
|
|
30
|
-
flowProgressScript: boolean;
|
|
31
|
-
settingsEntries: boolean;
|
|
32
|
-
};
|
|
33
|
-
ceraphDirPresent: boolean;
|
|
34
|
-
authPresent: boolean;
|
|
35
|
-
}
|
|
36
|
-
export interface FootprintDeps {
|
|
37
|
-
homeDir?: () => string;
|
|
38
|
-
detectMonorepo?: typeof detectMonorepoSubpackages;
|
|
39
|
-
}
|
|
40
|
-
export declare function getInstalledFootprint(projectDir: string, deps?: FootprintDeps): Promise<InstalledFootprint>;
|