@4xeoz/re-entry 0.2.17 → 0.2.19
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 +32 -27
- package/package.json +1 -1
- package/src/codex-exec-adapter.mjs +8 -3
- package/src/main.mjs +106 -8
- package/src/terminal-ui.mjs +22 -0
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Requirements: macOS, Node.js 24+, Codex installed and signed in, and an absolute
|
|
|
19
19
|
Codex may read and write.
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
|
-
npx --yes
|
|
22
|
+
npx --yes @4xeoz/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
|
|
@@ -30,8 +30,8 @@ npm install --global @4xeoz/re-entry
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
The package installs both `re-entry` and the older `reentry` spelling; `re-entry` is the documented
|
|
33
|
-
command. If you keep using the temporary `npx` form, run later commands with the same
|
|
34
|
-
prefix, for example `npx --yes
|
|
33
|
+
command. If you keep using the temporary `npx` form, run later commands with the same short
|
|
34
|
+
executable prefix, for example `npx --yes @4xeoz/re-entry status`.
|
|
35
35
|
|
|
36
36
|
The CLI defaults to the current Cloud Receiver v2 preview at
|
|
37
37
|
`https://cloud-receiver-delta.vercel.app`. Override it with `--receiver` or
|
|
@@ -42,13 +42,14 @@ The interactive CLI first offers Desktop, the current folder, or a small folder
|
|
|
42
42
|
with ↑/↓ and Enter. If you want to skip the picker, pass the workspace directly:
|
|
43
43
|
|
|
44
44
|
```sh
|
|
45
|
-
npx --yes
|
|
45
|
+
npx --yes @4xeoz/re-entry install \
|
|
46
46
|
--codex-cd /absolute/path/to/your/project
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
The guided screen stays intentionally small: **Workspace → System check → Connect Re-entry**.
|
|
50
|
-
shows
|
|
51
|
-
|
|
49
|
+
The guided screen stays intentionally small: **Workspace → System check → Connect Re-entry**. On
|
|
50
|
+
success it shows a compact copy-paste command catalog for status, activity, testing, account
|
|
51
|
+
lifecycle, and local diagnostics. Internal Connector IDs, credential paths, and log paths stay out
|
|
52
|
+
of the normal success screen.
|
|
52
53
|
|
|
53
54
|
Run this from the Host project directory, your home directory, or another normal working
|
|
54
55
|
directory—not from a checked-out `runtime/local-connector` package directory. npm can treat that
|
|
@@ -66,7 +67,7 @@ re-entry install \
|
|
|
66
67
|
Use `--receiver` to select an accepted replacement Receiver, such as a local historical preview:
|
|
67
68
|
|
|
68
69
|
```sh
|
|
69
|
-
npx --yes
|
|
70
|
+
npx --yes @4xeoz/re-entry install \
|
|
70
71
|
--receiver http://127.0.0.1:43224 \
|
|
71
72
|
--codex-cd /absolute/path/to/your/project
|
|
72
73
|
```
|
|
@@ -104,12 +105,12 @@ re-entry uninstall
|
|
|
104
105
|
If you used the temporary `npx` invocation:
|
|
105
106
|
|
|
106
107
|
```sh
|
|
107
|
-
npx --yes
|
|
108
|
-
npx --yes
|
|
109
|
-
npx --yes
|
|
110
|
-
npx --yes
|
|
111
|
-
npx --yes
|
|
112
|
-
npx --yes
|
|
108
|
+
npx --yes @4xeoz/re-entry status
|
|
109
|
+
npx --yes @4xeoz/re-entry listen
|
|
110
|
+
npx --yes @4xeoz/re-entry --help
|
|
111
|
+
npx --yes @4xeoz/re-entry stop
|
|
112
|
+
npx --yes @4xeoz/re-entry disconnect
|
|
113
|
+
npx --yes @4xeoz/re-entry uninstall
|
|
113
114
|
```
|
|
114
115
|
|
|
115
116
|
The status view checks the local authorization, background job, Receiver reachability, Node, and
|
|
@@ -119,16 +120,16 @@ the already-running background Connector and displays new activity until you pre
|
|
|
119
120
|
not start a competing second poller. Useful development commands are:
|
|
120
121
|
|
|
121
122
|
```sh
|
|
122
|
-
npx --yes
|
|
123
|
-
npx --yes
|
|
124
|
-
npx --yes
|
|
125
|
-
npx --yes
|
|
123
|
+
npx --yes @4xeoz/re-entry doctor --codex-cd /absolute/path/to/project
|
|
124
|
+
npx --yes @4xeoz/re-entry connect --receiver http://127.0.0.1:43224
|
|
125
|
+
npx --yes @4xeoz/re-entry claim-once --codex-cd /absolute/path/to/project
|
|
126
|
+
npx --yes @4xeoz/re-entry start --codex-cd /absolute/path/to/project
|
|
126
127
|
```
|
|
127
128
|
|
|
128
129
|
Test the local Codex handoff without waiting for Cloud work:
|
|
129
130
|
|
|
130
131
|
```sh
|
|
131
|
-
npx --yes
|
|
132
|
+
npx --yes @4xeoz/re-entry test "Reply with: Re-entry is working."
|
|
132
133
|
```
|
|
133
134
|
|
|
134
135
|
This starts one fresh local Codex process through the same adapter seam used by real deliveries. It
|
|
@@ -137,12 +138,16 @@ underlying direct `codex exec` command. It does not create a Grant, claim Receiv
|
|
|
137
138
|
Desktop UI thread, browser, or WebMCP return path. If it times out, run the equivalent direct
|
|
138
139
|
`codex exec` command to inspect Codex's own output; the test does not contact the Receiver.
|
|
139
140
|
|
|
141
|
+
The one-shot test allows up to one hour by default. Override it with
|
|
142
|
+
`--activation-timeout <milliseconds>` when needed. Background delivery keeps its separate
|
|
143
|
+
60-second adapter bound.
|
|
144
|
+
|
|
140
145
|
To pause or remove the local Connector:
|
|
141
146
|
|
|
142
147
|
```sh
|
|
143
|
-
npx --yes
|
|
144
|
-
npx --yes
|
|
145
|
-
npx --yes
|
|
148
|
+
npx --yes @4xeoz/re-entry stop
|
|
149
|
+
npx --yes @4xeoz/re-entry disconnect
|
|
150
|
+
npx --yes @4xeoz/re-entry uninstall
|
|
146
151
|
```
|
|
147
152
|
|
|
148
153
|
`stop` pauses the macOS background service and keeps the account connection. `uninstall` requires
|
|
@@ -174,10 +179,10 @@ Copy this prompt into a coding-agent task:
|
|
|
174
179
|
|
|
175
180
|
```text
|
|
176
181
|
Install the Re-entry Local Connector on this Mac. First read the package README. Verify Node.js 24
|
|
177
|
-
or newer and locate the Connector executable. Run `npx --yes
|
|
182
|
+
or newer and locate the Connector executable. Run `npx --yes @4xeoz/re-entry install` with an absolute
|
|
178
183
|
project directory. Let the human create or sign in to a Re-entry account, click Pair this Mac, and
|
|
179
184
|
enter the code in the CLI; never copy browser cookies, organization keys, Connector tokens, or private keys
|
|
180
|
-
into chat, logs, source files, or git. Finish by running `npx --yes
|
|
185
|
+
into chat, logs, source files, or git. Finish by running `npx --yes @4xeoz/re-entry status`
|
|
181
186
|
and report the bounded results without claiming Browser/WebMCP or production deployment.
|
|
182
187
|
```
|
|
183
188
|
|
|
@@ -250,9 +255,9 @@ npm publish --access public
|
|
|
250
255
|
NPM versions are immutable: if the target version has already been published, bump it before
|
|
251
256
|
publishing with `npm version patch --no-git-tag-version`.
|
|
252
257
|
|
|
253
|
-
After publishing, users run `npx --yes
|
|
254
|
-
|
|
255
|
-
|
|
258
|
+
After publishing, users run `npx --yes @4xeoz/re-entry install`. The executable itself is still
|
|
259
|
+
named `re-entry`; the short package form works with the scoped package. The command uses the
|
|
260
|
+
built-in preview Receiver unless `--receiver` or
|
|
256
261
|
`REENTRY_RECEIVER_ORIGIN` overrides it.
|
|
257
262
|
|
|
258
263
|
A temporary `npx` invocation does not add `re-entry` to your shell `PATH`. If you prefer the shorter
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@4xeoz/re-entry",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.19",
|
|
4
4
|
"type": "module",
|
|
5
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": {
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
} from "./codex-discovery.mjs";
|
|
11
11
|
|
|
12
12
|
export const CODEX_EXEC_ADAPTER_ID = "codex_exec_local";
|
|
13
|
+
export const DEFAULT_CODEX_PROMPT_TIMEOUT_MS = 3_600_000;
|
|
14
|
+
export const MAX_CODEX_PROMPT_TIMEOUT_MS = 3_600_000;
|
|
13
15
|
|
|
14
16
|
const OPTION_FIELDS = Object.freeze([
|
|
15
17
|
"workingDirectory",
|
|
@@ -89,7 +91,10 @@ export async function runCodexPrompt(options) {
|
|
|
89
91
|
? discoverCodexExecutable()
|
|
90
92
|
: requireReference(options.executable, "Codex executable");
|
|
91
93
|
const prompt = requirePrompt(options.prompt);
|
|
92
|
-
const timeoutMs = requireTimeout(
|
|
94
|
+
const timeoutMs = requireTimeout(
|
|
95
|
+
options.commandTimeoutMs ?? DEFAULT_CODEX_PROMPT_TIMEOUT_MS,
|
|
96
|
+
MAX_CODEX_PROMPT_TIMEOUT_MS,
|
|
97
|
+
);
|
|
93
98
|
const spawnCommand = options.spawnCommand ?? spawn;
|
|
94
99
|
if (typeof spawnCommand !== "function") {
|
|
95
100
|
throw new TypeError("Codex prompt spawnCommand must be a function");
|
|
@@ -216,11 +221,11 @@ function readClock(clock) {
|
|
|
216
221
|
return new Date(value.getTime());
|
|
217
222
|
}
|
|
218
223
|
|
|
219
|
-
function requireTimeout(value) {
|
|
224
|
+
function requireTimeout(value, maximum = MAX_COMMAND_TIMEOUT_MS) {
|
|
220
225
|
if (
|
|
221
226
|
!Number.isSafeInteger(value) ||
|
|
222
227
|
value < MIN_COMMAND_TIMEOUT_MS ||
|
|
223
|
-
value >
|
|
228
|
+
value > maximum
|
|
224
229
|
) {
|
|
225
230
|
throw new TypeError("Codex exec adapter commandTimeoutMs is invalid");
|
|
226
231
|
}
|
package/src/main.mjs
CHANGED
|
@@ -10,7 +10,12 @@ import process from "node:process";
|
|
|
10
10
|
|
|
11
11
|
import { LocalConnectorClient } from "@webmcp-challenge/reentry-core/local-connector-client";
|
|
12
12
|
import { followConnectorActivity } from "./activity-monitor.mjs";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
createCodexExecAdapter,
|
|
15
|
+
DEFAULT_CODEX_PROMPT_TIMEOUT_MS,
|
|
16
|
+
MAX_CODEX_PROMPT_TIMEOUT_MS,
|
|
17
|
+
runCodexPrompt,
|
|
18
|
+
} from "./codex-exec-adapter.mjs";
|
|
14
19
|
import {
|
|
15
20
|
discoverCodexExecutable,
|
|
16
21
|
requireSupportedNode,
|
|
@@ -44,7 +49,7 @@ const DEFAULT_MAX_CONSECUTIVE_ERRORS = 5;
|
|
|
44
49
|
const DEFAULT_PAIRING_REQUEST_TIMEOUT_MS = 20_000;
|
|
45
50
|
const CONNECTOR_VERSION = readConnectorVersion();
|
|
46
51
|
// The npx form is executable even when this CLI was launched from a temporary npx cache.
|
|
47
|
-
const TEMPORARY_CLI_COMMAND = "npx --yes
|
|
52
|
+
const TEMPORARY_CLI_COMMAND = "npx --yes @4xeoz/re-entry";
|
|
48
53
|
|
|
49
54
|
async function main() {
|
|
50
55
|
let ui;
|
|
@@ -139,7 +144,7 @@ Usage:
|
|
|
139
144
|
re-entry test "Reply with hello" Test Codex locally
|
|
140
145
|
|
|
141
146
|
Invocation:
|
|
142
|
-
Temporary npx: npx --yes
|
|
147
|
+
Temporary npx: npx --yes @4xeoz/re-entry <command>
|
|
143
148
|
Global install: npm install --global @4xeoz/re-entry, then re-entry <command>
|
|
144
149
|
|
|
145
150
|
Commands:
|
|
@@ -160,6 +165,8 @@ Common options:
|
|
|
160
165
|
--receiver <url> Accepted Receiver origin (overrides the preview default)
|
|
161
166
|
--codex-cd <path> Workspace for Codex; interactive mode offers a folder picker if omitted
|
|
162
167
|
--codex-binary <path> Explicit Codex executable
|
|
168
|
+
--activation-timeout <ms>
|
|
169
|
+
Codex limit; test defaults to 1 hour, background start to 60 seconds
|
|
163
170
|
--json Machine-readable output
|
|
164
171
|
--yes Confirm uninstall in a non-interactive script
|
|
165
172
|
--help Show this help
|
|
@@ -178,6 +185,96 @@ function cliCommand(command) {
|
|
|
178
185
|
return `${TEMPORARY_CLI_COMMAND} ${command}`;
|
|
179
186
|
}
|
|
180
187
|
|
|
188
|
+
function showInstallGuide(ui, workingDirectory) {
|
|
189
|
+
const workspace = shellQuote(workingDirectory);
|
|
190
|
+
ui.commands("COPY-PASTE COMMANDS", [
|
|
191
|
+
{
|
|
192
|
+
label: "Connect / install",
|
|
193
|
+
command: cliCommand(`install --codex-cd ${workspace}`),
|
|
194
|
+
detail: "run after disconnecting to connect one account on this Mac",
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
label: "Check status",
|
|
198
|
+
command: cliCommand("status"),
|
|
199
|
+
detail: "account, Cloud, background service, Node.js, and Codex",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
label: "Watch activity",
|
|
203
|
+
command: cliCommand("listen"),
|
|
204
|
+
detail: "follow live work; Ctrl+C closes this view",
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
label: "Test Codex",
|
|
208
|
+
command: cliCommand(`test "Reply exactly: Re-entry is working." --codex-cd ${workspace}`),
|
|
209
|
+
detail: "local smoke test; no Cloud work is claimed",
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
label: "Check readiness",
|
|
213
|
+
command: cliCommand(`doctor --codex-cd ${workspace}`),
|
|
214
|
+
detail: "verify Node.js, Codex, and the workspace",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
label: "Start manually",
|
|
218
|
+
command: cliCommand(`start --codex-cd ${workspace}`),
|
|
219
|
+
detail: "foreground delivery loop for development",
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
label: "Check once",
|
|
223
|
+
command: cliCommand(`claim-once --codex-cd ${workspace}`),
|
|
224
|
+
detail: "one delivery check, then exit",
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
label: "Pause",
|
|
228
|
+
command: cliCommand("stop"),
|
|
229
|
+
detail: "stop background delivery; keep the account connected",
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
label: "Sign out",
|
|
233
|
+
command: cliCommand("disconnect"),
|
|
234
|
+
detail: "clear this Mac's saved account connection",
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
label: "Remove setup",
|
|
238
|
+
command: cliCommand("uninstall"),
|
|
239
|
+
detail: "remove the local service, credential, and logs",
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
label: "Show all help",
|
|
243
|
+
command: cliCommand("--help"),
|
|
244
|
+
detail: "all commands, options, and the legacy pairing command",
|
|
245
|
+
},
|
|
246
|
+
]);
|
|
247
|
+
ui.info("Account", "one account connected on this Mac; disconnect before connecting another");
|
|
248
|
+
ui.info("Test timeout", "one-shot Codex tests wait up to 1 hour by default");
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function showTestGuide(ui, workingDirectory, prompt) {
|
|
252
|
+
const workspace = shellQuote(workingDirectory);
|
|
253
|
+
ui.commands("COPY-PASTE COMMANDS", [
|
|
254
|
+
{
|
|
255
|
+
label: "Test again",
|
|
256
|
+
command: cliCommand(`test ${shellQuote(prompt)} --codex-cd ${workspace}`),
|
|
257
|
+
detail: "run another local Codex smoke test",
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
label: "Check readiness",
|
|
261
|
+
command: cliCommand(`doctor --codex-cd ${workspace}`),
|
|
262
|
+
detail: "verify Node.js, Codex, and the workspace",
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
label: "Show all help",
|
|
266
|
+
command: cliCommand("--help"),
|
|
267
|
+
detail: "all commands, options, and account lifecycle actions",
|
|
268
|
+
},
|
|
269
|
+
]);
|
|
270
|
+
ui.info("Scope", "local Codex test only; no account or Cloud work was used");
|
|
271
|
+
ui.info("Test timeout", "one-shot Codex tests wait up to 1 hour by default");
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function shellQuote(value) {
|
|
275
|
+
return `'${String(value).replaceAll("'", "'\\''")}'`;
|
|
276
|
+
}
|
|
277
|
+
|
|
181
278
|
function readConnectorVersion() {
|
|
182
279
|
const packageJson = JSON.parse(
|
|
183
280
|
readFileSync(new URL("../package.json", import.meta.url), "utf8"),
|
|
@@ -523,16 +620,16 @@ async function testCodex(flags, positionals, ui) {
|
|
|
523
620
|
prompt,
|
|
524
621
|
stdio: ui.interactive ? "inherit" : ["ignore", "ignore", "ignore"],
|
|
525
622
|
commandTimeoutMs: readBoundedNumber(
|
|
526
|
-
flags["activation-timeout"] ??
|
|
623
|
+
flags["activation-timeout"] ?? DEFAULT_CODEX_PROMPT_TIMEOUT_MS,
|
|
527
624
|
100,
|
|
528
|
-
|
|
529
|
-
"
|
|
625
|
+
MAX_CODEX_PROMPT_TIMEOUT_MS,
|
|
626
|
+
"connector_test_timeout_invalid",
|
|
530
627
|
),
|
|
531
628
|
});
|
|
532
629
|
if (ui.interactive) {
|
|
533
630
|
ui.stopWait("Codex", "completed the local test");
|
|
534
631
|
ui.complete("Test passed", "The same fresh-session process seam is ready for Re-entry work.");
|
|
535
|
-
ui.
|
|
632
|
+
showTestGuide(ui, readiness.workingDirectory, prompt);
|
|
536
633
|
} else {
|
|
537
634
|
process.stdout.write('{"event":"connector_codex_test_passed"}\n');
|
|
538
635
|
}
|
|
@@ -653,7 +750,7 @@ async function install(flags, ui) {
|
|
|
653
750
|
if (ui.interactive) {
|
|
654
751
|
ui.stopWait("Background", "running at login");
|
|
655
752
|
ui.complete("You're all set", "Re-entry is connected and waiting for approved work.");
|
|
656
|
-
ui
|
|
753
|
+
showInstallGuide(ui, readiness.workingDirectory);
|
|
657
754
|
} else {
|
|
658
755
|
process.stdout.write(`${JSON.stringify({
|
|
659
756
|
event: "connector_service_installed",
|
|
@@ -1133,6 +1230,7 @@ function errorHint(error) {
|
|
|
1133
1230
|
connector_service_stop_failed: `check the Connector status and try \`${cliCommand("stop")}\` again`,
|
|
1134
1231
|
connector_test_prompt_missing: `use \`${cliCommand('test "Reply with: Re-entry is working."')}\``,
|
|
1135
1232
|
connector_test_prompt_invalid: "use one short, single-line prompt inside quotes",
|
|
1233
|
+
connector_test_timeout_invalid: "use a test timeout between 100 and 3600000 milliseconds",
|
|
1136
1234
|
connector_activation_timeout_invalid: "use an activation timeout between 100 and 60000 milliseconds",
|
|
1137
1235
|
};
|
|
1138
1236
|
return hints[error?.code] ?? "check the command output and try again";
|
package/src/terminal-ui.mjs
CHANGED
|
@@ -128,6 +128,28 @@ export function createTerminalUi(options = {}) {
|
|
|
128
128
|
write();
|
|
129
129
|
},
|
|
130
130
|
|
|
131
|
+
commands(title, entries) {
|
|
132
|
+
if (!interactive) return;
|
|
133
|
+
clearSpinnerLine();
|
|
134
|
+
const validEntries = Array.isArray(entries)
|
|
135
|
+
? entries.filter((entry) => (
|
|
136
|
+
entry &&
|
|
137
|
+
typeof entry.label === "string" && entry.label.length > 0 &&
|
|
138
|
+
typeof entry.command === "string" && entry.command.length > 0
|
|
139
|
+
))
|
|
140
|
+
: [];
|
|
141
|
+
if (validEntries.length === 0) return;
|
|
142
|
+
const labelWidth = Math.max(...validEntries.map((entry) => entry.label.length));
|
|
143
|
+
write();
|
|
144
|
+
if (title) write(` ${style(title, CYAN)}`);
|
|
145
|
+
for (const entry of validEntries) {
|
|
146
|
+
const label = entry.label.padEnd(labelWidth);
|
|
147
|
+
write(` ${style(label, BOLD)} ${style("$", CYAN)} ${style(entry.command, BOLD)}`);
|
|
148
|
+
if (entry.detail) write(` ${style(entry.detail, DIM)}`);
|
|
149
|
+
}
|
|
150
|
+
write();
|
|
151
|
+
},
|
|
152
|
+
|
|
131
153
|
error(label, detail, hint) {
|
|
132
154
|
if (!interactive) return;
|
|
133
155
|
clearSpinnerLine();
|