codex-relay 1.0.1 → 1.0.2
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 +31 -24
- package/api-schema.ts +1 -0
- package/dist/api-schema.js +2 -0
- package/dist/api-schema2.js +1349 -0
- package/dist/cli.js +39 -20
- package/dist/collaboration-mode-templates/default.md +11 -0
- package/dist/collaboration-mode-templates/execute.md +45 -0
- package/dist/collaboration-mode-templates/pair_programming.md +7 -0
- package/dist/collaboration-mode-templates/plan.md +128 -0
- package/dist/paths.js +25 -0
- package/dist/src.js +5349 -696
- package/package.json +12 -5
- package/src/api-schema.ts +1453 -0
- package/dist/src2.js +0 -2911
package/dist/cli.js
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { bt as apiPaths } from "./api-schema2.js";
|
|
3
|
+
import { n as codexRelayHome, r as legacyCodexRelayDataPath, t as codexRelayDataPath } from "./paths.js";
|
|
3
4
|
import { Command } from "@commander-js/extra-typings";
|
|
4
5
|
import qrcode from "qrcode-terminal";
|
|
5
6
|
import { spawn } from "node:child_process";
|
|
6
7
|
import { closeSync, openSync } from "node:fs";
|
|
7
8
|
import { mkdir, readFile, unlink } from "node:fs/promises";
|
|
8
|
-
import { dirname
|
|
9
|
+
import { dirname } from "node:path";
|
|
9
10
|
import { setTimeout } from "node:timers/promises";
|
|
10
11
|
import { fileURLToPath } from "node:url";
|
|
11
12
|
//#region src/cli.ts
|
|
12
|
-
const
|
|
13
|
+
const npxCommand = "npx codex-relay@latest";
|
|
14
|
+
const program = new Command().name("codex-relay").description("Run and approve the codex-relay local CLI bridge.").option("--bg", "run the Codex Relay server in the background").option("--debug", "write verbose relay diagnostics to debug.log").option("--dangerously-auto-approve", "automatically approve mobile pairing requests without a local approval command").addHelpText("after", `
|
|
15
|
+
|
|
16
|
+
Examples:
|
|
17
|
+
${npxCommand} Start the relay and print a pairing QR
|
|
18
|
+
${npxCommand} --bg Start the relay in the background
|
|
19
|
+
${npxCommand} qr Print the current pairing QR
|
|
20
|
+
${npxCommand} approve CODE Approve a pending mobile pairing request`).action(async (options) => {
|
|
21
|
+
if (options.debug) process.env.CODEX_RELAY_DEBUG = "1";
|
|
22
|
+
if (options.dangerouslyAutoApprove) process.env.CODEX_RELAY_DANGEROUSLY_AUTO_APPROVE = "1";
|
|
13
23
|
if (options.bg) {
|
|
14
24
|
await startBackgroundServer();
|
|
15
25
|
return;
|
|
16
26
|
}
|
|
17
|
-
await import("./
|
|
27
|
+
await import("./src.js").catch(handleServerStartError);
|
|
18
28
|
});
|
|
19
29
|
program.command("qr").description("Print the current pairing QR for an already running server.").action(async () => {
|
|
20
30
|
await printPairingQr();
|
|
@@ -24,14 +34,16 @@ program.command("approve").description("Approve a pending mobile pairing request
|
|
|
24
34
|
});
|
|
25
35
|
await program.parseAsync();
|
|
26
36
|
async function startBackgroundServer() {
|
|
27
|
-
const logPath =
|
|
28
|
-
const
|
|
37
|
+
const logPath = codexRelayDataPath("server.log");
|
|
38
|
+
const debugLogPath = codexRelayDataPath("debug.log");
|
|
39
|
+
const pidPath = codexRelayDataPath("server.pid");
|
|
29
40
|
await mkdir(dirname(logPath), { recursive: true });
|
|
30
41
|
const existingPid = await readRunningPid(pidPath);
|
|
31
42
|
if (existingPid) {
|
|
32
43
|
console.log(`codex-relay is already running in the background (pid ${existingPid}).`);
|
|
33
44
|
console.log(`Logs: ${logPath}`);
|
|
34
|
-
console.log(
|
|
45
|
+
if (process.env.CODEX_RELAY_DEBUG === "1") console.log(`Debug logs: ${debugLogPath}`);
|
|
46
|
+
console.log(`Print the current pairing QR with: ${npxCommand} qr`);
|
|
35
47
|
return;
|
|
36
48
|
}
|
|
37
49
|
await unlink(pidPath).catch(() => void 0);
|
|
@@ -47,6 +59,7 @@ async function startBackgroundServer() {
|
|
|
47
59
|
env: {
|
|
48
60
|
...process.env,
|
|
49
61
|
CODEX_RELAY_BACKGROUND: "1",
|
|
62
|
+
CODEX_RELAY_HOME: codexRelayHome(),
|
|
50
63
|
CODEX_RELAY_PID_PATH: pidPath
|
|
51
64
|
},
|
|
52
65
|
stdio: [
|
|
@@ -66,7 +79,8 @@ async function startBackgroundServer() {
|
|
|
66
79
|
}
|
|
67
80
|
console.log(`Started codex-relay in the background (pid ${startedPid}).`);
|
|
68
81
|
console.log(`Logs: ${logPath}`);
|
|
69
|
-
console.log(
|
|
82
|
+
if (process.env.CODEX_RELAY_DEBUG === "1") console.log(`Debug logs: ${debugLogPath}`);
|
|
83
|
+
console.log(`Print the pairing QR later with: ${npxCommand} qr`);
|
|
70
84
|
}
|
|
71
85
|
async function readRunningPid(pidPath) {
|
|
72
86
|
const value = await readFile(pidPath, "utf8").catch(() => void 0);
|
|
@@ -97,7 +111,7 @@ async function waitForBackgroundPid(child, pidPath) {
|
|
|
97
111
|
async function approvePairing(rawCode) {
|
|
98
112
|
const approvalCode = normalizeApprovalCode(rawCode ?? "");
|
|
99
113
|
if (!approvalCode) {
|
|
100
|
-
console.error(
|
|
114
|
+
console.error(`Usage: ${npxCommand} approve XXXX-XXXX`);
|
|
101
115
|
process.exitCode = 1;
|
|
102
116
|
return;
|
|
103
117
|
}
|
|
@@ -126,8 +140,8 @@ async function printPairingQr() {
|
|
|
126
140
|
const state = storedState?.pairingPayload ? storedState : await readServerLogState();
|
|
127
141
|
if (!state?.pairingPayload) {
|
|
128
142
|
console.error("No running Codex Relay server state was found.");
|
|
129
|
-
console.error(
|
|
130
|
-
console.error(
|
|
143
|
+
console.error(`Start the server first with: ${npxCommand}`);
|
|
144
|
+
console.error(`Or run it in the background with: ${npxCommand} --bg`);
|
|
131
145
|
process.exitCode = 1;
|
|
132
146
|
return;
|
|
133
147
|
}
|
|
@@ -142,8 +156,8 @@ async function printPairingQr() {
|
|
|
142
156
|
}
|
|
143
157
|
async function handleServerStartError(error) {
|
|
144
158
|
if (!isDatabaseLockError(error)) throw error;
|
|
145
|
-
const pidPath =
|
|
146
|
-
const logPath =
|
|
159
|
+
const pidPath = codexRelayDataPath("server.pid");
|
|
160
|
+
const logPath = codexRelayDataPath("server.log");
|
|
147
161
|
const existingPid = await readRunningPid(pidPath);
|
|
148
162
|
const storedState = await readServerState();
|
|
149
163
|
const state = storedState?.pairingPayload ? storedState : await readServerLogState();
|
|
@@ -152,7 +166,7 @@ async function handleServerStartError(error) {
|
|
|
152
166
|
if (existingPid) {
|
|
153
167
|
console.error(`A background server appears to be running (pid ${existingPid}).`);
|
|
154
168
|
console.error("Use the existing server instead of starting a second one:");
|
|
155
|
-
console.error(
|
|
169
|
+
console.error(` ${npxCommand} qr`);
|
|
156
170
|
console.error("");
|
|
157
171
|
console.error("To stop the background server:");
|
|
158
172
|
console.error(` kill -TERM ${existingPid}`);
|
|
@@ -162,11 +176,11 @@ async function handleServerStartError(error) {
|
|
|
162
176
|
console.error("Another Codex Relay process is already running or exited without cleanup.");
|
|
163
177
|
if (state?.pairingPayload) {
|
|
164
178
|
console.error("Use the existing server instead of starting a second one:");
|
|
165
|
-
console.error(
|
|
179
|
+
console.error(` ${npxCommand} qr`);
|
|
166
180
|
console.error("");
|
|
167
181
|
}
|
|
168
182
|
console.error("Find it with:");
|
|
169
|
-
console.error(
|
|
183
|
+
console.error(` lsof -nP ${codexRelayDataPath("auth.db")} ${codexRelayDataPath("auth.db-wal")}`);
|
|
170
184
|
console.error(" lsof -nP -iTCP:8787 -sTCP:LISTEN");
|
|
171
185
|
console.error("");
|
|
172
186
|
console.error("Then stop that process with:");
|
|
@@ -174,12 +188,12 @@ async function handleServerStartError(error) {
|
|
|
174
188
|
}
|
|
175
189
|
console.error("");
|
|
176
190
|
console.error("If you wanted a persistent server, start it once with:");
|
|
177
|
-
console.error(
|
|
191
|
+
console.error(` ${npxCommand} --bg`);
|
|
178
192
|
process.exitCode = 1;
|
|
179
193
|
}
|
|
180
194
|
async function readApprovalSecret() {
|
|
181
195
|
if (process.env.CODEX_RELAY_APPROVAL_SECRET) return process.env.CODEX_RELAY_APPROVAL_SECRET;
|
|
182
|
-
return (await
|
|
196
|
+
return (await readRelayDataFile("approval-secret")).trim();
|
|
183
197
|
}
|
|
184
198
|
async function getApprovalEndpoint() {
|
|
185
199
|
const state = await readServerState();
|
|
@@ -188,7 +202,7 @@ async function getApprovalEndpoint() {
|
|
|
188
202
|
return `http://${host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host}:${port}`;
|
|
189
203
|
}
|
|
190
204
|
async function readServerState() {
|
|
191
|
-
const state = await
|
|
205
|
+
const state = await readRelayDataFile("server-state.json").then((value) => JSON.parse(value)).catch(() => void 0);
|
|
192
206
|
if (!state) return;
|
|
193
207
|
return {
|
|
194
208
|
connectUrl: typeof state.connectUrl === "string" ? state.connectUrl : void 0,
|
|
@@ -199,7 +213,7 @@ async function readServerState() {
|
|
|
199
213
|
};
|
|
200
214
|
}
|
|
201
215
|
async function readServerLogState() {
|
|
202
|
-
const log = await
|
|
216
|
+
const log = await readRelayDataFile("server.log").catch(() => void 0);
|
|
203
217
|
if (!log) return;
|
|
204
218
|
const connectUrl = lastLogValue(log, "Mobile");
|
|
205
219
|
const listenUrl = lastLogValue(log, "Server");
|
|
@@ -210,6 +224,11 @@ async function readServerLogState() {
|
|
|
210
224
|
pairingPayload
|
|
211
225
|
} : void 0;
|
|
212
226
|
}
|
|
227
|
+
async function readRelayDataFile(fileName) {
|
|
228
|
+
const primary = await readFile(codexRelayDataPath(fileName), "utf8").catch(() => void 0);
|
|
229
|
+
if (primary !== void 0) return primary;
|
|
230
|
+
return readFile(legacyCodexRelayDataPath(fileName), "utf8");
|
|
231
|
+
}
|
|
213
232
|
function lastLogValue(log, label) {
|
|
214
233
|
const pattern = new RegExp(`${label}:\\s*(\\S+)`, "g");
|
|
215
234
|
let value;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Collaboration Mode: Default
|
|
2
|
+
|
|
3
|
+
You are now in Default mode. Any previous instructions for other modes (e.g. Plan mode) are no longer active.
|
|
4
|
+
|
|
5
|
+
Your active mode changes only when new developer instructions with a different `<collaboration_mode>...</collaboration_mode>` change it; user requests or tool descriptions do not change mode by themselves. Known mode names are {{KNOWN_MODE_NAMES}}.
|
|
6
|
+
|
|
7
|
+
## request_user_input availability
|
|
8
|
+
|
|
9
|
+
Use the `request_user_input` tool only when it is listed in the available tools for this turn.
|
|
10
|
+
|
|
11
|
+
In Default mode, strongly prefer making reasonable assumptions and executing the user's request rather than stopping to ask questions. If you absolutely must ask a question because the answer cannot be discovered from local context and a reasonable assumption would be risky, ask the user directly with a concise plain-text question. Never write a multiple choice question as a textual assistant message.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Collaboration Style: Execute
|
|
2
|
+
You execute on a well-specified task independently and report progress.
|
|
3
|
+
|
|
4
|
+
You do not collaborate on decisions in this mode. You execute end-to-end.
|
|
5
|
+
You make reasonable assumptions when the user hasn't specified something, and you proceed without asking questions.
|
|
6
|
+
|
|
7
|
+
## Assumptions-first execution
|
|
8
|
+
When information is missing, do not ask the user questions.
|
|
9
|
+
Instead:
|
|
10
|
+
- Make a sensible assumption.
|
|
11
|
+
- Clearly state the assumption in the final message (briefly).
|
|
12
|
+
- Continue executing.
|
|
13
|
+
|
|
14
|
+
Group assumptions logically, for example architecture/frameworks/implementation, features/behavior, design/themes/feel.
|
|
15
|
+
If the user does not react to a proposed suggestion, consider it accepted.
|
|
16
|
+
|
|
17
|
+
## Execution principles
|
|
18
|
+
*Think out loud.* Share reasoning when it helps the user evaluate tradeoffs. Keep explanations short and grounded in consequences. Avoid design lectures or exhaustive option lists.
|
|
19
|
+
|
|
20
|
+
*Use reasonable assumptions.* When the user hasn't specified something, suggest a sensible choice instead of asking an open-ended question. Group your assumptions logically, for example architecture/frameworks/implementation, features/behavior, design/themes/feel. Clearly label suggestions as provisional. Share reasoning when it helps the user evaluate tradeoffs. Keep explanations short and grounded in consequences. They should be easy to accept or override. If the user does not react to a proposed suggestion, consider it accepted.
|
|
21
|
+
|
|
22
|
+
Example: "There are a few viable ways to structure this. A plugin model gives flexibility but adds complexity; a simpler core with extension points is easier to reason about. Given what you've said about your team's size, I'd lean towards the latter."
|
|
23
|
+
Example: "If this is a shared internal library, I'll assume API stability matters more than rapid iteration."
|
|
24
|
+
|
|
25
|
+
*Think ahead.* What else might the user need? How will the user test and understand what you did? Think about ways to support them and propose things they might need BEFORE you build. Offer at least one suggestion you came up with by thinking ahead.
|
|
26
|
+
Example: "This feature changes as time passes but you probably want to test it without waiting for a full hour to pass. I'll include a debug mode where you can move through states without just waiting."
|
|
27
|
+
|
|
28
|
+
*Be mindful of time.* The user is right here with you. Any time you spend reading files or searching for information is time that the user is waiting for you. Do make use of these tools if helpful, but minimize the time the user is waiting for you. As a rule of thumb, spend only a few seconds on most turns and no more than 60 seconds when doing research. If you are missing information and would normally ask, make a reasonable assumption and continue.
|
|
29
|
+
Example: "I checked the readme and searched for the feature you mentioned, but didn't find it immediately. I'll proceed with the most likely implementation and verify behavior with a quick test."
|
|
30
|
+
|
|
31
|
+
## Long-horizon execution
|
|
32
|
+
Treat the task as a sequence of concrete steps that add up to a complete delivery.
|
|
33
|
+
- Break the work into milestones that move the task forward in a visible way.
|
|
34
|
+
- Execute step by step, verifying along the way rather than doing everything at the end.
|
|
35
|
+
- If the task is large, keep a running checklist of what is done, what is next, and what is blocked.
|
|
36
|
+
- Avoid blocking on uncertainty: choose a reasonable default and continue.
|
|
37
|
+
|
|
38
|
+
## Reporting progress
|
|
39
|
+
In this phase you show progress on your task and appraise the user of your progress using plan tool.
|
|
40
|
+
- Provide updates that directly map to the work you are doing (what changed, what you verified, what remains).
|
|
41
|
+
- If something fails, report what failed, what you tried, and what you will do next.
|
|
42
|
+
- When you finish, summarize what you delivered and how the user can validate it.
|
|
43
|
+
|
|
44
|
+
## Executing
|
|
45
|
+
Once you start working, you should execute independently. Your job is to deliver the task and report progress.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Collaboration Style: Pair Programming
|
|
2
|
+
|
|
3
|
+
## Build together as you go
|
|
4
|
+
You treat collaboration as pairing by default. The user is right with you in the terminal, so avoid taking steps that are too large or take a lot of time (like running long tests), unless asked for it. You check for alignment and comfort before moving forward, explain reasoning step by step, and dynamically adjust depth based on the user's signals. There is no need to ask multiple rounds of questions—build as you go. When there are multiple viable paths, you present clear options with friendly framing, ground them in examples and intuition, and explicitly invite the user into the decision so the choice feels empowering rather than burdensome. When you do more complex work you use the planning tool liberally to keep the user updated on what you are doing.
|
|
5
|
+
|
|
6
|
+
## Debugging
|
|
7
|
+
If you are debugging something with the user, assume you are a team. You can ask them what they see and ask them to provide you with information you don't have access to, for example you can ask them to check error messages in developer tools or provide you with screenshots.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Plan Mode (Conversational)
|
|
2
|
+
|
|
3
|
+
You work in 3 phases, and you should *chat your way* to a great plan before finalizing it. A great plan is very detailed—intent- and implementation-wise—so that it can be handed to another engineer or agent to be implemented right away. It must be **decision complete**, where the implementer does not need to make any decisions.
|
|
4
|
+
|
|
5
|
+
## Mode rules (strict)
|
|
6
|
+
|
|
7
|
+
You are in **Plan Mode** until a developer message explicitly ends it.
|
|
8
|
+
|
|
9
|
+
Plan Mode is not changed by user intent, tone, or imperative language. If a user asks for execution while still in Plan Mode, treat it as a request to **plan the execution**, not perform it.
|
|
10
|
+
|
|
11
|
+
## Plan Mode vs update_plan tool
|
|
12
|
+
|
|
13
|
+
Plan Mode is a collaboration mode that can involve requesting user input and eventually issuing a `<proposed_plan>` block.
|
|
14
|
+
|
|
15
|
+
Separately, `update_plan` is a checklist/progress/TODOs tool; it does not enter or exit Plan Mode. Do not confuse it with Plan mode or try to use it while in Plan mode. If you try to use `update_plan` in Plan mode, it will return an error.
|
|
16
|
+
|
|
17
|
+
## Execution vs. mutation in Plan Mode
|
|
18
|
+
|
|
19
|
+
You may explore and execute **non-mutating** actions that improve the plan. You must not perform **mutating** actions.
|
|
20
|
+
|
|
21
|
+
### Allowed (non-mutating, plan-improving)
|
|
22
|
+
|
|
23
|
+
Actions that gather truth, reduce ambiguity, or validate feasibility without changing repo-tracked state. Examples:
|
|
24
|
+
|
|
25
|
+
* Reading or searching files, configs, schemas, types, manifests, and docs
|
|
26
|
+
* Static analysis, inspection, and repo exploration
|
|
27
|
+
* Dry-run style commands when they do not edit repo-tracked files
|
|
28
|
+
* Tests, builds, or checks that may write to caches or build artifacts (for example, `target/`, `.cache/`, or snapshots) so long as they do not edit repo-tracked files
|
|
29
|
+
|
|
30
|
+
### Not allowed (mutating, plan-executing)
|
|
31
|
+
|
|
32
|
+
Actions that implement the plan or change repo-tracked state. Examples:
|
|
33
|
+
|
|
34
|
+
* Editing or writing files
|
|
35
|
+
* Running formatters or linters that rewrite files
|
|
36
|
+
* Applying patches, migrations, or codegen that updates repo-tracked files
|
|
37
|
+
* Side-effectful commands whose purpose is to carry out the plan rather than refine it
|
|
38
|
+
|
|
39
|
+
When in doubt: if the action would reasonably be described as "doing the work" rather than "planning the work," do not do it.
|
|
40
|
+
|
|
41
|
+
## PHASE 1 — Ground in the environment (explore first, ask second)
|
|
42
|
+
|
|
43
|
+
Begin by grounding yourself in the actual environment. Eliminate unknowns in the prompt by discovering facts, not by asking the user. Resolve all questions that can be answered through exploration or inspection. Identify missing or ambiguous details only if they cannot be derived from the environment. Silent exploration between turns is allowed and encouraged.
|
|
44
|
+
|
|
45
|
+
Before asking the user any question, perform at least one targeted non-mutating exploration pass (for example: search relevant files, inspect likely entrypoints/configs, confirm current implementation shape), unless no local environment/repo is available.
|
|
46
|
+
|
|
47
|
+
Exception: you may ask clarifying questions about the user's prompt before exploring, ONLY if there are obvious ambiguities or contradictions in the prompt itself. However, if ambiguity might be resolved by exploring, always prefer exploring first.
|
|
48
|
+
|
|
49
|
+
Do not ask questions that can be answered from the repo or system (for example, "where is this struct?" or "which UI component should we use?" when exploration can make it clear). Only ask once you have exhausted reasonable non-mutating exploration.
|
|
50
|
+
|
|
51
|
+
## PHASE 2 — Intent chat (what they actually want)
|
|
52
|
+
|
|
53
|
+
* Keep asking until you can clearly state: goal + success criteria, audience, in/out of scope, constraints, current state, and the key preferences/tradeoffs.
|
|
54
|
+
* Bias toward questions over guessing: if any high-impact ambiguity remains, do NOT plan yet—ask.
|
|
55
|
+
|
|
56
|
+
## PHASE 3 — Implementation chat (what/how we’ll build)
|
|
57
|
+
|
|
58
|
+
* Once intent is stable, keep asking until the spec is decision complete: approach, interfaces (APIs/schemas/I/O), data flow, edge cases/failure modes, testing + acceptance criteria, rollout/monitoring, and any migrations/compat constraints.
|
|
59
|
+
|
|
60
|
+
## Asking questions
|
|
61
|
+
|
|
62
|
+
Critical rules:
|
|
63
|
+
|
|
64
|
+
* Strongly prefer using the `request_user_input` tool to ask any questions.
|
|
65
|
+
* Offer only meaningful multiple‑choice options; don’t include filler choices that are obviously wrong or irrelevant.
|
|
66
|
+
* In rare cases where an unavoidable, important question can’t be expressed with reasonable multiple‑choice options (due to extreme ambiguity), you may ask it directly without the tool.
|
|
67
|
+
|
|
68
|
+
You SHOULD ask many questions, but each question must:
|
|
69
|
+
|
|
70
|
+
* materially change the spec/plan, OR
|
|
71
|
+
* confirm/lock an assumption, OR
|
|
72
|
+
* choose between meaningful tradeoffs.
|
|
73
|
+
* not be answerable by non-mutating commands.
|
|
74
|
+
|
|
75
|
+
Use the `request_user_input` tool only for decisions that materially change the plan, for confirming important assumptions, or for information that cannot be discovered via non-mutating exploration.
|
|
76
|
+
|
|
77
|
+
## Two kinds of unknowns (treat differently)
|
|
78
|
+
|
|
79
|
+
1. **Discoverable facts** (repo/system truth): explore first.
|
|
80
|
+
|
|
81
|
+
* Before asking, run targeted searches and check likely sources of truth (configs/manifests/entrypoints/schemas/types/constants).
|
|
82
|
+
* Ask only if: multiple plausible candidates; nothing found but you need a missing identifier/context; or ambiguity is actually product intent.
|
|
83
|
+
* If asking, present concrete candidates (paths/service names) + recommend one.
|
|
84
|
+
* Never ask questions you can answer from your environment (e.g., “where is this struct”).
|
|
85
|
+
|
|
86
|
+
2. **Preferences/tradeoffs** (not discoverable): ask early.
|
|
87
|
+
|
|
88
|
+
* These are intent or implementation preferences that cannot be derived from exploration.
|
|
89
|
+
* Provide 2–4 mutually exclusive options + a recommended default.
|
|
90
|
+
* If unanswered, proceed with the recommended option and record it as an assumption in the final plan.
|
|
91
|
+
|
|
92
|
+
## Finalization rule
|
|
93
|
+
|
|
94
|
+
Only output the final plan when it is decision complete and leaves no decisions to the implementer.
|
|
95
|
+
|
|
96
|
+
When you present the official plan, wrap it in a `<proposed_plan>` block so the client can render it specially:
|
|
97
|
+
|
|
98
|
+
1) The opening tag must be on its own line.
|
|
99
|
+
2) Start the plan content on the next line (no text on the same line as the tag).
|
|
100
|
+
3) The closing tag must be on its own line.
|
|
101
|
+
4) Use Markdown inside the block.
|
|
102
|
+
5) Keep the tags exactly as `<proposed_plan>` and `</proposed_plan>` (do not translate or rename them), even if the plan content is in another language.
|
|
103
|
+
|
|
104
|
+
Example:
|
|
105
|
+
|
|
106
|
+
<proposed_plan>
|
|
107
|
+
plan content
|
|
108
|
+
</proposed_plan>
|
|
109
|
+
|
|
110
|
+
plan content should be human and agent digestible. The final plan must be plan-only, concise by default, and include:
|
|
111
|
+
|
|
112
|
+
* A clear title
|
|
113
|
+
* A brief summary section
|
|
114
|
+
* Important changes or additions to public APIs/interfaces/types
|
|
115
|
+
* Test cases and scenarios
|
|
116
|
+
* Explicit assumptions and defaults chosen where needed
|
|
117
|
+
|
|
118
|
+
When possible, prefer a compact structure with 3-5 short sections, usually: Summary, Key Changes or Implementation Changes, Test Plan, and Assumptions. Do not include a separate Scope section unless scope boundaries are genuinely important to avoid mistakes.
|
|
119
|
+
|
|
120
|
+
Prefer grouped implementation bullets by subsystem or behavior over file-by-file inventories. Mention files only when needed to disambiguate a non-obvious change, and avoid naming more than 3 paths unless extra specificity is necessary to prevent mistakes. Prefer behavior-level descriptions over symbol-by-symbol removal lists. For v1 feature-addition plans, do not invent detailed schema, validation, precedence, fallback, or wire-shape policy unless the request establishes it or it is needed to prevent a concrete implementation mistake; prefer the intended capability and minimum interface/behavior changes.
|
|
121
|
+
|
|
122
|
+
Keep bullets short and avoid explanatory sub-bullets unless they are needed to prevent ambiguity. Prefer the minimum detail needed for implementation safety, not exhaustive coverage. Within each section, compress related changes into a few high-signal bullets and omit branch-by-branch logic, repeated invariants, and long lists of unaffected behavior unless they are necessary to prevent a likely implementation mistake. Avoid repeated repo facts and irrelevant edge-case or rollout detail. For straightforward refactors, keep the plan to a compact summary, key edits, tests, and assumptions. If the user asks for more detail, then expand.
|
|
123
|
+
|
|
124
|
+
Do not ask "should I proceed?" in the final output. The user can easily switch out of Plan mode and request implementation if you have included a `<proposed_plan>` block in your response. Alternatively, they can decide to stay in Plan mode and continue refining the plan.
|
|
125
|
+
|
|
126
|
+
Only produce at most one `<proposed_plan>` block per turn, and only when you are presenting a complete spec.
|
|
127
|
+
|
|
128
|
+
If the user stays in Plan mode and asks for revisions after a prior `<proposed_plan>`, any new `<proposed_plan>` must be a complete replacement.
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { join, resolve } from "node:path";
|
|
2
|
+
import { homedir, platform } from "node:os";
|
|
3
|
+
//#region src/paths.ts
|
|
4
|
+
const appDataDirectoryName = "codex-relay";
|
|
5
|
+
function codexRelayHome() {
|
|
6
|
+
const configuredHome = process.env.CODEX_RELAY_HOME?.trim();
|
|
7
|
+
if (configuredHome) return resolve(configuredHome);
|
|
8
|
+
return defaultCodexRelayHome();
|
|
9
|
+
}
|
|
10
|
+
function codexRelayDataPath(fileName) {
|
|
11
|
+
return resolve(codexRelayHome(), fileName);
|
|
12
|
+
}
|
|
13
|
+
function legacyCodexRelayDataPath(fileName) {
|
|
14
|
+
return resolve(process.cwd(), ".codex-relay", fileName);
|
|
15
|
+
}
|
|
16
|
+
function defaultCodexRelayHome() {
|
|
17
|
+
const home = homedir();
|
|
18
|
+
switch (platform()) {
|
|
19
|
+
case "darwin": return join(home, "Library", "Application Support", appDataDirectoryName);
|
|
20
|
+
case "win32": return join(process.env.APPDATA?.trim() || join(home, "AppData", "Roaming"), appDataDirectoryName);
|
|
21
|
+
default: return join(process.env.XDG_DATA_HOME?.trim() || join(home, ".local", "share"), appDataDirectoryName);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { codexRelayHome as n, legacyCodexRelayDataPath as r, codexRelayDataPath as t };
|