@4xeoz/re-entry 0.2.14 → 0.2.16
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 +34 -16
- package/package.json +2 -2
- package/src/macos-service.mjs +37 -7
- package/src/main.mjs +73 -21
package/README.md
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
> **Cloud Receiver dependency notice — 2026-09-02:** The former `re-entry-weld.vercel.app` Cloud
|
|
4
4
|
> Receiver is deprecated and must not be used for new pairing, credentials, or production traffic.
|
|
5
|
-
> This Connector package remains a reusable/local preview surface
|
|
6
|
-
>
|
|
5
|
+
> This Connector package remains a reusable/local preview surface and defaults to the accepted
|
|
6
|
+
> preview origin `https://cloud-receiver-delta.vercel.app`; pass `--receiver` for another accepted
|
|
7
|
+
> Receiver. This preview default is not a production deployment.
|
|
7
8
|
|
|
8
9
|
Install it once on the Mac where Codex should open; after one dashboard pairing code, a macOS
|
|
9
10
|
LaunchAgent keeps the outbound Connector running at login.
|
|
@@ -18,8 +19,7 @@ Requirements: macOS, Node.js 24+, Codex installed and signed in, and an absolute
|
|
|
18
19
|
Codex may read and write.
|
|
19
20
|
|
|
20
21
|
```sh
|
|
21
|
-
npx --yes --package=@4xeoz/re-entry re-entry install
|
|
22
|
-
--receiver https://your-accepted-receiver.example
|
|
22
|
+
npx --yes --package=@4xeoz/re-entry re-entry install
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
`npx` runs a temporary copy, so it does not leave a permanent shell command behind. Install the
|
|
@@ -33,16 +33,16 @@ The package installs both `re-entry` and the older `reentry` spelling; `re-entry
|
|
|
33
33
|
command. If you keep using the temporary `npx` form, run later commands with the same executable
|
|
34
34
|
prefix, for example `npx --yes --package=@4xeoz/re-entry re-entry status`.
|
|
35
35
|
|
|
36
|
-
The CLI
|
|
37
|
-
|
|
38
|
-
`
|
|
36
|
+
The CLI defaults to the current Cloud Receiver v2 preview at
|
|
37
|
+
`https://cloud-receiver-delta.vercel.app`. Override it with `--receiver` or
|
|
38
|
+
`REENTRY_RECEIVER_ORIGIN` when using another accepted Receiver. This preview default is not a
|
|
39
|
+
production deployment.
|
|
39
40
|
|
|
40
41
|
The interactive CLI first offers Desktop, the current folder, or a small folder browser. Choose
|
|
41
42
|
with ↑/↓ and Enter. If you want to skip the picker, pass the workspace directly:
|
|
42
43
|
|
|
43
44
|
```sh
|
|
44
45
|
npx --yes --package=@4xeoz/re-entry re-entry install \
|
|
45
|
-
--receiver https://your-accepted-receiver.example \
|
|
46
46
|
--codex-cd /absolute/path/to/your/project
|
|
47
47
|
```
|
|
48
48
|
|
|
@@ -60,7 +60,6 @@ installation instead:
|
|
|
60
60
|
```sh
|
|
61
61
|
npm install --global @4xeoz/re-entry
|
|
62
62
|
re-entry install \
|
|
63
|
-
--receiver https://your-accepted-receiver.example \
|
|
64
63
|
--codex-cd /absolute/path/to/your/project
|
|
65
64
|
```
|
|
66
65
|
|
|
@@ -98,6 +97,7 @@ re-entry status
|
|
|
98
97
|
re-entry listen
|
|
99
98
|
re-entry --help
|
|
100
99
|
re-entry stop
|
|
100
|
+
re-entry disconnect
|
|
101
101
|
re-entry uninstall
|
|
102
102
|
```
|
|
103
103
|
|
|
@@ -108,14 +108,15 @@ npx --yes --package=@4xeoz/re-entry re-entry status
|
|
|
108
108
|
npx --yes --package=@4xeoz/re-entry re-entry listen
|
|
109
109
|
npx --yes --package=@4xeoz/re-entry re-entry --help
|
|
110
110
|
npx --yes --package=@4xeoz/re-entry re-entry stop
|
|
111
|
+
npx --yes --package=@4xeoz/re-entry re-entry disconnect
|
|
111
112
|
npx --yes --package=@4xeoz/re-entry re-entry uninstall
|
|
112
113
|
```
|
|
113
114
|
|
|
114
115
|
The status view checks the local authorization, background job, Receiver reachability, Node, and
|
|
115
116
|
Codex. If the Receiver rejects a previously saved device credential, the Connector pauses instead
|
|
116
|
-
of retrying forever, and `status`/`listen`
|
|
117
|
-
already-running background Connector and displays new activity until you press Ctrl+C; it does
|
|
118
|
-
start a competing second poller. Useful development commands are:
|
|
117
|
+
of retrying forever, and `status`/`listen` tell you to disconnect before reconnecting. `listen` watches
|
|
118
|
+
the already-running background Connector and displays new activity until you press Ctrl+C; it does
|
|
119
|
+
not start a competing second poller. Useful development commands are:
|
|
119
120
|
|
|
120
121
|
```sh
|
|
121
122
|
npx --yes --package=@4xeoz/re-entry re-entry doctor --codex-cd /absolute/path/to/project
|
|
@@ -137,6 +138,7 @@ To pause or remove the local Connector:
|
|
|
137
138
|
|
|
138
139
|
```sh
|
|
139
140
|
npx --yes --package=@4xeoz/re-entry re-entry stop
|
|
141
|
+
npx --yes --package=@4xeoz/re-entry re-entry disconnect
|
|
140
142
|
npx --yes --package=@4xeoz/re-entry re-entry uninstall
|
|
141
143
|
```
|
|
142
144
|
|
|
@@ -145,9 +147,23 @@ typing `DELETE`, then removes only the LaunchAgent, saved Connector credential,
|
|
|
145
147
|
It does not recursively delete folders or uninstall the npm package. To remove a global npm
|
|
146
148
|
installation separately, run `npm uninstall --global @4xeoz/re-entry`.
|
|
147
149
|
|
|
148
|
-
`
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
`disconnect` is the simple local sign-out: it stops the LaunchAgent, removes the saved Connector
|
|
151
|
+
credential, and leaves the log files in place. It is safe to run again when already disconnected.
|
|
152
|
+
The current CLI does not have a server-side revoke route, so this command does not remove the Mac
|
|
153
|
+
from the account's remote device list; use the account dashboard's revoke/decommission action when
|
|
154
|
+
that Receiver operation is available, or wait for the remote credential to expire. `uninstall` is
|
|
155
|
+
the stronger local cleanup and also removes Connector logs.
|
|
156
|
+
|
|
157
|
+
Each credential file accepts one connection at a time. Repeating `connect` or `install` with the
|
|
158
|
+
same saved connection returns `already connected`; an expired, rejected, or different-Receiver
|
|
159
|
+
connection is not silently replaced. Run `disconnect`, then `install`, to connect this Mac to a
|
|
160
|
+
different account or Receiver. `connect` repeats only account authorization, while `install` is the
|
|
161
|
+
normal product path because it also installs the background job. `claim-once` is the smallest manual
|
|
162
|
+
delivery test. The legacy Host-code `pair` command follows the same one-connection rule and remains
|
|
163
|
+
only for compatibility tests.
|
|
164
|
+
|
|
165
|
+
`Ctrl+C` stops a foreground `start` process or closes the `listen` view. It does not remove the
|
|
166
|
+
saved connection; use `stop` to pause the background service or `disconnect` to clear it.
|
|
151
167
|
|
|
152
168
|
## Give this to a coding agent
|
|
153
169
|
|
|
@@ -222,6 +238,7 @@ the npm account that owns the `4xeoz` scope, publish from this directory:
|
|
|
222
238
|
```sh
|
|
223
239
|
npm login
|
|
224
240
|
npm whoami
|
|
241
|
+
npm view @4xeoz/re-entry version
|
|
225
242
|
npm version patch --no-git-tag-version
|
|
226
243
|
npm run verify
|
|
227
244
|
npm publish --access public
|
|
@@ -232,7 +249,8 @@ publishing with `npm version patch --no-git-tag-version`.
|
|
|
232
249
|
|
|
233
250
|
After publishing, users run `npx --yes --package=@4xeoz/re-entry re-entry install`. The explicit
|
|
234
251
|
`--package` form works across npm versions when the package is scoped; the executable itself is
|
|
235
|
-
still named `re-entry`.
|
|
252
|
+
still named `re-entry`. The command uses the built-in preview Receiver unless `--receiver` or
|
|
253
|
+
`REENTRY_RECEIVER_ORIGIN` overrides it.
|
|
236
254
|
|
|
237
255
|
A temporary `npx` invocation does not add `re-entry` to your shell `PATH`. If you prefer the shorter
|
|
238
256
|
bare commands, run `npm install --global @4xeoz/re-entry` once and then use `re-entry install`
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@4xeoz/re-entry",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.16",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Outbound Local Connector process for Re-entry Core;
|
|
5
|
+
"description": "Outbound Local Connector process for Re-entry Core; uses the Cloud Receiver v2 preview by default with an explicit override for other accepted origins.",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
8
8
|
},
|
package/src/macos-service.mjs
CHANGED
|
@@ -113,6 +113,30 @@ export async function stopMacConnectorService(options = {}) {
|
|
|
113
113
|
return Object.freeze({ ...status, stopped: true, running: false });
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
export async function disconnectMacConnectorService(options = {}) {
|
|
117
|
+
const configuration = requireServiceConfiguration(options, "disconnect");
|
|
118
|
+
if (process.platform !== "darwin" && configuration.allowNonMacForTest !== true) {
|
|
119
|
+
return Object.freeze({ supported: false, disconnected: false, removedPaths: [] });
|
|
120
|
+
}
|
|
121
|
+
const service = await stopMacConnectorService(configuration);
|
|
122
|
+
const stateDirectory = configuration.stateDirectory ?? join(homedir(), ".webmcp-connector");
|
|
123
|
+
const credentialFile = requireAbsolutePath(
|
|
124
|
+
configuration.credentialFile ?? join(stateDirectory, "credentials.json"),
|
|
125
|
+
"Credential file",
|
|
126
|
+
);
|
|
127
|
+
const removedPaths = await removePaths([
|
|
128
|
+
service.plistPath,
|
|
129
|
+
credentialFile,
|
|
130
|
+
`${credentialFile}.reauthorization-required.json`,
|
|
131
|
+
], "disconnect");
|
|
132
|
+
return Object.freeze({
|
|
133
|
+
supported: true,
|
|
134
|
+
disconnected: removedPaths.length > 0,
|
|
135
|
+
removedPaths,
|
|
136
|
+
plistPath: service.plistPath,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
116
140
|
export async function uninstallMacConnectorService(options = {}) {
|
|
117
141
|
const configuration = requireServiceConfiguration(options, "uninstall");
|
|
118
142
|
if (process.platform !== "darwin" && configuration.allowNonMacForTest !== true) {
|
|
@@ -131,22 +155,28 @@ export async function uninstallMacConnectorService(options = {}) {
|
|
|
131
155
|
join(stateDirectory, "connector.log"),
|
|
132
156
|
join(stateDirectory, "connector-error.log"),
|
|
133
157
|
])];
|
|
158
|
+
const removedPaths = await removePaths(paths, "uninstall");
|
|
159
|
+
return Object.freeze({
|
|
160
|
+
supported: true,
|
|
161
|
+
removedPaths,
|
|
162
|
+
plistPath: service.plistPath,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function removePaths(paths, operation) {
|
|
134
167
|
const removedPaths = [];
|
|
135
|
-
for (const path of paths) {
|
|
168
|
+
for (const path of [...new Set(paths)]) {
|
|
169
|
+
if (typeof path !== "string") continue;
|
|
136
170
|
try {
|
|
137
171
|
await unlink(path);
|
|
138
172
|
removedPaths.push(path);
|
|
139
173
|
} catch (error) {
|
|
140
174
|
if (error?.code !== "ENOENT") {
|
|
141
|
-
throw serviceFailure("connector_service_remove_failed",
|
|
175
|
+
throw serviceFailure("connector_service_remove_failed", `Connector data could not be removed during ${operation}`, error);
|
|
142
176
|
}
|
|
143
177
|
}
|
|
144
178
|
}
|
|
145
|
-
return
|
|
146
|
-
supported: true,
|
|
147
|
-
removedPaths,
|
|
148
|
-
plistPath: service.plistPath,
|
|
149
|
-
});
|
|
179
|
+
return removedPaths;
|
|
150
180
|
}
|
|
151
181
|
|
|
152
182
|
export function renderLaunchAgent(options) {
|
package/src/main.mjs
CHANGED
|
@@ -28,15 +28,17 @@ import { LocalConnectorPairingClient, openBrowser } from "./pairing-client.mjs";
|
|
|
28
28
|
import { chooseWorkspaceDirectory } from "./workspace-picker.mjs";
|
|
29
29
|
import {
|
|
30
30
|
inspectMacConnectorService,
|
|
31
|
+
disconnectMacConnectorService,
|
|
31
32
|
installMacConnectorService,
|
|
32
33
|
stopMacConnectorService,
|
|
33
34
|
uninstallMacConnectorService,
|
|
34
35
|
} from "./macos-service.mjs";
|
|
35
36
|
import { createTerminalUi } from "./terminal-ui.mjs";
|
|
36
37
|
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
const
|
|
38
|
+
// This is the current Cloud Receiver v2 preview. A command-line --receiver override remains
|
|
39
|
+
// authoritative, and REENTRY_RECEIVER_ORIGIN can override this built-in preview default.
|
|
40
|
+
const BUILT_IN_RECEIVER_ORIGIN = "https://cloud-receiver-delta.vercel.app";
|
|
41
|
+
const DEFAULT_RECEIVER_ORIGIN = process.env.REENTRY_RECEIVER_ORIGIN?.trim() || BUILT_IN_RECEIVER_ORIGIN;
|
|
40
42
|
const DEFAULT_POLL_INTERVAL_MS = 5_000;
|
|
41
43
|
const DEFAULT_MAX_CONSECUTIVE_ERRORS = 5;
|
|
42
44
|
const DEFAULT_PAIRING_REQUEST_TIMEOUT_MS = 20_000;
|
|
@@ -88,6 +90,10 @@ async function main() {
|
|
|
88
90
|
await stop(flags, ui);
|
|
89
91
|
return;
|
|
90
92
|
}
|
|
93
|
+
if (command === "disconnect") {
|
|
94
|
+
await disconnect(flags, ui);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
91
97
|
if (command === "uninstall") {
|
|
92
98
|
await uninstall(flags, ui);
|
|
93
99
|
return;
|
|
@@ -129,6 +135,7 @@ Connect this Mac once, then receive approved work in Codex in the background.
|
|
|
129
135
|
Usage:
|
|
130
136
|
re-entry install Recommended first run
|
|
131
137
|
re-entry listen Watch live activity
|
|
138
|
+
re-entry disconnect Sign out this Mac locally
|
|
132
139
|
re-entry test "Reply with hello" Test Codex locally
|
|
133
140
|
|
|
134
141
|
Invocation:
|
|
@@ -141,6 +148,7 @@ Commands:
|
|
|
141
148
|
listen Watch the background Connector until you press Ctrl+C
|
|
142
149
|
test Start one fresh local Codex session with the supplied prompt
|
|
143
150
|
stop Stop the background Connector without removing its credential
|
|
151
|
+
disconnect Stop the Connector and clear this Mac's saved connection
|
|
144
152
|
uninstall Stop the Connector and remove its local service data
|
|
145
153
|
connect Open Re-entry, redeem a dashboard pairing code, and connect this Mac
|
|
146
154
|
start Poll for approved work until stopped
|
|
@@ -149,7 +157,7 @@ Commands:
|
|
|
149
157
|
pair Legacy Host-code pairing preview
|
|
150
158
|
|
|
151
159
|
Common options:
|
|
152
|
-
--receiver <url> Accepted Receiver origin (
|
|
160
|
+
--receiver <url> Accepted Receiver origin (overrides the preview default)
|
|
153
161
|
--codex-cd <path> Workspace for Codex; interactive mode offers a folder picker if omitted
|
|
154
162
|
--codex-binary <path> Explicit Codex executable
|
|
155
163
|
--json Machine-readable output
|
|
@@ -157,6 +165,10 @@ Common options:
|
|
|
157
165
|
--help Show this help
|
|
158
166
|
--version Show the installed version
|
|
159
167
|
|
|
168
|
+
Default Receiver:
|
|
169
|
+
https://cloud-receiver-delta.vercel.app
|
|
170
|
+
Override with --receiver or REENTRY_RECEIVER_ORIGIN for another accepted Receiver.
|
|
171
|
+
|
|
160
172
|
Both commands are installed: re-entry and reentry.
|
|
161
173
|
The Connector opens no inbound port. Host keys never belong on this Mac.
|
|
162
174
|
`);
|
|
@@ -239,6 +251,8 @@ async function pair(flags, ui, options = {}) {
|
|
|
239
251
|
}
|
|
240
252
|
const receiver = requireFlag(flags, "receiver");
|
|
241
253
|
const credentialFile = flags["credential-file"] ?? defaultCredentialFile();
|
|
254
|
+
const store = new LocalConnectorCredentialStore({ filename: credentialFile });
|
|
255
|
+
if (await store.load()) throw cliFailure("connector_account_already_connected");
|
|
242
256
|
if (ui.interactive) {
|
|
243
257
|
ui.step("Receiver", receiver);
|
|
244
258
|
}
|
|
@@ -265,7 +279,6 @@ async function pair(flags, ui, options = {}) {
|
|
|
265
279
|
ui.warning("Browser", "did not open automatically; use the URL above");
|
|
266
280
|
}
|
|
267
281
|
}
|
|
268
|
-
const store = new LocalConnectorCredentialStore({ filename: credentialFile });
|
|
269
282
|
await store.save({
|
|
270
283
|
version: 1,
|
|
271
284
|
receiver_origin: receiver,
|
|
@@ -310,9 +323,7 @@ async function connect(flags, ui, options = {}) {
|
|
|
310
323
|
return current;
|
|
311
324
|
}
|
|
312
325
|
|
|
313
|
-
if (
|
|
314
|
-
ui.warning("Receiver changed", `${current.receiver_origin} → ${receiver}; approve this Mac again`);
|
|
315
|
-
}
|
|
326
|
+
if (current) throw cliFailure("connector_account_already_connected");
|
|
316
327
|
|
|
317
328
|
if (ui.interactive) {
|
|
318
329
|
if (!options.guidedInstall) ui.info("Re-entry", displayReceiver(receiver));
|
|
@@ -381,11 +392,15 @@ async function status(flags, ui) {
|
|
|
381
392
|
Date.parse(credentials.connector_expires_at) > Date.now() &&
|
|
382
393
|
!reauthorizationRequired,
|
|
383
394
|
);
|
|
395
|
+
const credentialExpired = Boolean(
|
|
396
|
+
credentials && Date.parse(credentials.connector_expires_at) <= Date.now(),
|
|
397
|
+
);
|
|
384
398
|
if (ui.interactive) {
|
|
385
399
|
ui.section("SYSTEM", "This Mac");
|
|
386
400
|
showReadiness(readiness, ui);
|
|
387
401
|
ui.section("CONNECTION", "Re-entry");
|
|
388
|
-
if (reauthorizationRequired) ui.warning("Account", "
|
|
402
|
+
if (reauthorizationRequired) ui.warning("Account", "disconnect required before reconnecting");
|
|
403
|
+
else if (credentialExpired) ui.warning("Account", "connection expired; disconnect before reconnecting");
|
|
389
404
|
else if (connected) ui.success("Account", "connected");
|
|
390
405
|
else ui.warning("Account", "not connected");
|
|
391
406
|
if (reauthorizationRequired && service.running) ui.warning("Background", "paused until this Mac is reconnected");
|
|
@@ -395,8 +410,8 @@ async function status(flags, ui) {
|
|
|
395
410
|
if (receiverReady) ui.success("Cloud", "online");
|
|
396
411
|
else if (credentials) ui.warning("Cloud", "unavailable");
|
|
397
412
|
|
|
398
|
-
if (reauthorizationRequired) {
|
|
399
|
-
ui.next(cliCommand("
|
|
413
|
+
if (reauthorizationRequired || credentialExpired) {
|
|
414
|
+
ui.next(cliCommand("disconnect"), "Clear this Mac's saved connection, then run install to connect again.");
|
|
400
415
|
} else if (!connected || !service.running) {
|
|
401
416
|
ui.next(cliCommand("install"), "Finish setup and start Re-entry in the background.");
|
|
402
417
|
} else if (!receiverReady) {
|
|
@@ -413,6 +428,7 @@ async function status(flags, ui) {
|
|
|
413
428
|
connector_id: credentials?.connector_id ?? null,
|
|
414
429
|
receiver_origin: credentials?.receiver_origin ?? null,
|
|
415
430
|
receiver_ready: receiverReady,
|
|
431
|
+
credential_expired: credentialExpired,
|
|
416
432
|
service_installed: service.installed,
|
|
417
433
|
service_running: service.running,
|
|
418
434
|
codex_binary: readiness.installation.executable,
|
|
@@ -431,11 +447,18 @@ async function listen(flags, ui) {
|
|
|
431
447
|
filename: defaultCredentialFile(),
|
|
432
448
|
}).load();
|
|
433
449
|
const reauthorizationRequired = await hasConnectorReauthorizationRequired(defaultCredentialFile());
|
|
434
|
-
|
|
450
|
+
const credentialExpired = Boolean(
|
|
451
|
+
credentials && Date.parse(credentials.connector_expires_at) <= Date.now(),
|
|
452
|
+
);
|
|
453
|
+
if (reauthorizationRequired || credentialExpired || !service.running || !credentials) {
|
|
435
454
|
if (ui.interactive) {
|
|
436
455
|
if (reauthorizationRequired) {
|
|
437
|
-
ui.warning("Account", "
|
|
438
|
-
ui.next(cliCommand("
|
|
456
|
+
ui.warning("Account", "disconnect required; the Cloud Receiver rejected this Mac");
|
|
457
|
+
ui.next(cliCommand("disconnect"), "Clear this Mac's saved connection, then run install again.");
|
|
458
|
+
}
|
|
459
|
+
if (credentialExpired) {
|
|
460
|
+
ui.warning("Account", "connection expired");
|
|
461
|
+
ui.next(cliCommand("disconnect"), "Clear this Mac's saved connection, then run install again.");
|
|
439
462
|
}
|
|
440
463
|
if (!credentials) ui.warning("Account", "not connected");
|
|
441
464
|
if (!service.running) ui.warning("Background", "not running");
|
|
@@ -445,6 +468,7 @@ async function listen(flags, ui) {
|
|
|
445
468
|
event: "connector_listener_unavailable",
|
|
446
469
|
connected: Boolean(credentials),
|
|
447
470
|
reauthorization_required: reauthorizationRequired,
|
|
471
|
+
credential_expired: credentialExpired,
|
|
448
472
|
service_running: service.running,
|
|
449
473
|
})}\n`);
|
|
450
474
|
}
|
|
@@ -521,7 +545,7 @@ function reportLiveActivity(event, ui) {
|
|
|
521
545
|
);
|
|
522
546
|
} else if (event.event === "connector_reauthorization_required" || event.code === "connector_identity_invalid") {
|
|
523
547
|
ui.stopWait("Reconnect required", "the Cloud Receiver rejected this Mac's saved connection", "warning");
|
|
524
|
-
ui.next(cliCommand("
|
|
548
|
+
ui.next(cliCommand("disconnect"), "Clear this Mac's saved connection, then run install again.");
|
|
525
549
|
return;
|
|
526
550
|
} else if (event.event === "connector_poll_failed" || event.event === "local_connector_failed") {
|
|
527
551
|
ui.stopWait("Connection interrupted", "Re-entry is retrying", "warning");
|
|
@@ -554,6 +578,32 @@ async function stop(flags, ui) {
|
|
|
554
578
|
}
|
|
555
579
|
}
|
|
556
580
|
|
|
581
|
+
async function disconnect(flags, ui) {
|
|
582
|
+
if (ui.interactive) {
|
|
583
|
+
ui.begin("Disconnect Re-entry", "Stop background delivery and clear this Mac's saved connection");
|
|
584
|
+
}
|
|
585
|
+
const result = await disconnectMacConnectorService({
|
|
586
|
+
credentialFile: flags["credential-file"] ?? defaultCredentialFile(),
|
|
587
|
+
});
|
|
588
|
+
if (ui.interactive) {
|
|
589
|
+
if (!result.supported) {
|
|
590
|
+
ui.warning("Platform", "connection lifecycle control currently supports macOS only");
|
|
591
|
+
} else if (result.disconnected) {
|
|
592
|
+
ui.complete("This Mac is disconnected", "The LaunchAgent and local Connector credential are cleared.");
|
|
593
|
+
} else {
|
|
594
|
+
ui.info("Already disconnected", "No saved local connection or background service was found.");
|
|
595
|
+
}
|
|
596
|
+
if (result.supported) ui.next(cliCommand("install"), "Connect this Mac to one Re-entry account again.");
|
|
597
|
+
} else {
|
|
598
|
+
process.stdout.write(`${JSON.stringify({
|
|
599
|
+
event: "connector_disconnected",
|
|
600
|
+
supported: result.supported,
|
|
601
|
+
disconnected: result.disconnected,
|
|
602
|
+
removed_paths: result.removedPaths,
|
|
603
|
+
})}\n`);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
557
607
|
async function uninstall(flags, ui) {
|
|
558
608
|
if (ui.interactive) {
|
|
559
609
|
ui.begin("Uninstall Re-entry", "Stop the Connector and remove only its local service data");
|
|
@@ -637,8 +687,8 @@ async function start(flags, ui) {
|
|
|
637
687
|
credentials = await connect(runtimeFlags, ui, { quietHeader: true });
|
|
638
688
|
} else if (await hasConnectorReauthorizationRequired(credentialFile)) {
|
|
639
689
|
if (ui.interactive) {
|
|
640
|
-
ui.warning("Account", "this Mac
|
|
641
|
-
ui.next(cliCommand("
|
|
690
|
+
ui.warning("Account", "this Mac must be disconnected before reconnecting");
|
|
691
|
+
ui.next(cliCommand("disconnect"), "Clear the saved connection, then run install again.");
|
|
642
692
|
} else {
|
|
643
693
|
process.stdout.write('{"event":"connector_reauthorization_required"}\n');
|
|
644
694
|
}
|
|
@@ -684,7 +734,7 @@ async function start(flags, ui) {
|
|
|
684
734
|
});
|
|
685
735
|
if (ui.interactive) {
|
|
686
736
|
ui.stopWait("Reconnect required", "the Cloud Receiver rejected this Mac's saved connection", "warning");
|
|
687
|
-
ui.next(cliCommand("
|
|
737
|
+
ui.next(cliCommand("disconnect"), "Clear this Mac's saved connection, then run install again.");
|
|
688
738
|
} else {
|
|
689
739
|
process.stdout.write('{"event":"connector_reauthorization_required"}\n');
|
|
690
740
|
}
|
|
@@ -876,6 +926,7 @@ function validateCommandFlags(command, flags, positionals) {
|
|
|
876
926
|
listen: new Set(["json"]),
|
|
877
927
|
test: new Set(["codex-cd", "codex-binary", "activation-timeout", "json"]),
|
|
878
928
|
stop: new Set(["json"]),
|
|
929
|
+
disconnect: new Set(["credential-file", "json"]),
|
|
879
930
|
uninstall: new Set(["credential-file", "yes", "json"]),
|
|
880
931
|
install: new Set([
|
|
881
932
|
"receiver",
|
|
@@ -1052,10 +1103,11 @@ function errorHint(error) {
|
|
|
1052
1103
|
connector_node_unsupported: "use Node.js 24 or newer, then run the command again",
|
|
1053
1104
|
connector_receiver_missing: "pass --receiver <replacement-receiver-origin> or set REENTRY_RECEIVER_ORIGIN",
|
|
1054
1105
|
connector_credentials_missing: `connect this Mac once with \`${cliCommand("connect")}\``,
|
|
1055
|
-
connector_credentials_expired: `run \`${cliCommand("
|
|
1106
|
+
connector_credentials_expired: `run \`${cliCommand("disconnect")}\`, then \`${cliCommand("install")}\` to authorize this Mac again`,
|
|
1056
1107
|
connector_credentials_already_exists: "use the existing Connector credential or ask for a new pairing code",
|
|
1057
|
-
|
|
1058
|
-
|
|
1108
|
+
connector_account_already_connected: `run \`${cliCommand("disconnect")}\` before connecting a different account or Receiver`,
|
|
1109
|
+
connector_identity_invalid: `run \`${cliCommand("disconnect")}\`, then \`${cliCommand("install")}\` and approve this Mac again`,
|
|
1110
|
+
connector_reauthorization_required: `run \`${cliCommand("disconnect")}\`, then \`${cliCommand("install")}\` and approve this Mac again`,
|
|
1059
1111
|
connector_pairing_code_missing: `ask the Host backend for a new pairing code, then run \`${cliCommand("pair")}\` in a terminal`,
|
|
1060
1112
|
pairing_code_invalid: "use the 16-character code returned by the Host, for example ABCD-EFGH-IJKL-MNOP",
|
|
1061
1113
|
host_subject_already_paired: "use the existing Connector credential or revoke/reset the preview pairing",
|