relayrun 0.1.0 → 0.1.1
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 +7 -1
- package/dist/agent/run.js +1 -2
- package/dist/cli.js +13 -0
- package/dist/login.js +81 -0
- package/dist/runner.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,6 +48,7 @@ rather than wedging the session.
|
|
|
48
48
|
|---|---|
|
|
49
49
|
| `--repo <path>` | Repository to work in (default: current directory) |
|
|
50
50
|
| `--api-key <key>` | Bill runs to this key instead of your Claude Code login |
|
|
51
|
+
| `--model <id>` | Model to run (default: `claude-sonnet-5`) |
|
|
51
52
|
| `--mock` | Scripted offline agent — see below |
|
|
52
53
|
| `--session <id>` | Reattach to an existing session (needs `--token`) |
|
|
53
54
|
| `--token <tok>` | Runner token for `--session` |
|
|
@@ -92,7 +93,12 @@ relayrun --session 8M2zrrx9Ng --token <runner-token>
|
|
|
92
93
|
|
|
93
94
|
- Node.js >= 20.9.0
|
|
94
95
|
- `git`, and a repository to run in
|
|
95
|
-
- A Claude Code login or an Anthropic API key (unless using `--mock`)
|
|
96
|
+
- **A Claude Code login or an Anthropic API key** (unless using `--mock`)
|
|
97
|
+
|
|
98
|
+
A claude.ai browser session or the Claude Desktop app will *not* work — those
|
|
99
|
+
are separate logins from Claude Code. If no credential is found, `relayrun`
|
|
100
|
+
says so and exits before opening a session, rather than failing later in front
|
|
101
|
+
of whoever you invited.
|
|
96
102
|
|
|
97
103
|
## License
|
|
98
104
|
|
package/dist/agent/run.js
CHANGED
|
@@ -4,9 +4,8 @@ import { detailForCall } from "./diff.js";
|
|
|
4
4
|
import { resultText, summarizeToolCall, summarizeToolResult } from "./summarize.js";
|
|
5
5
|
import { orientation } from "./orient.js";
|
|
6
6
|
export async function runRealAgent(opts) {
|
|
7
|
-
const { emit, instruction, workingDir, signal, resume, apiKeyHelper } = opts;
|
|
7
|
+
const { emit, instruction, workingDir, signal, resume, apiKeyHelper, model } = opts;
|
|
8
8
|
const pending = new Map();
|
|
9
|
-
const model = process.env.RELAY_MODEL ?? "claude-haiku-4-5";
|
|
10
9
|
// The SDK wants an AbortController, but ownership of stopping a run belongs
|
|
11
10
|
// to the runner, which already holds one. Bridge the two.
|
|
12
11
|
const abort = new AbortController();
|
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
|
+
import { findClaudeLogin, hasClaudeCli, noLoginGuidance } from "./login.js";
|
|
5
6
|
import { createRepo } from "./repo.js";
|
|
6
7
|
import { startRunner } from "./runner.js";
|
|
7
8
|
import { apiKeyHelperPath, keyHint, looksLikeApiKey, SESSION_KEY_ENV, verifyApiKey, } from "./sessionKey.js";
|
|
@@ -16,6 +17,7 @@ const run = promisify(execFile);
|
|
|
16
17
|
*/
|
|
17
18
|
const DEFAULT_SERVER = process.env.RELAY_SERVER ?? "https://relay-production-c9bd.up.railway.app";
|
|
18
19
|
const DEFAULT_WEB = process.env.RELAY_WEB ?? "https://relay-web-green.vercel.app";
|
|
20
|
+
const DEFAULT_MODEL = process.env.RELAY_MODEL ?? "claude-sonnet-5";
|
|
19
21
|
const USAGE = `relayrun — run a Relay session against a repository on this machine
|
|
20
22
|
|
|
21
23
|
relayrun [options]
|
|
@@ -27,6 +29,7 @@ const USAGE = `relayrun — run a Relay session against a repository on this mac
|
|
|
27
29
|
Costs nothing, but ignores what you type and replays
|
|
28
30
|
a fixed script. For UI work, not for real answers.
|
|
29
31
|
--api-key <key> Bill runs to this key instead of your Claude Code login
|
|
32
|
+
--model <id> Model to run (default: ${DEFAULT_MODEL})
|
|
30
33
|
--session <id> Reattach to an existing session (requires --token)
|
|
31
34
|
--token <token> Runner token for --session
|
|
32
35
|
--github-repo <o/n> Open a PR here on publish
|
|
@@ -123,6 +126,14 @@ async function resolveCredentials(args) {
|
|
|
123
126
|
if (!key) {
|
|
124
127
|
// No explicit key: the SDK uses whatever this machine is already logged in
|
|
125
128
|
// with, exactly as Claude Code does.
|
|
129
|
+
//
|
|
130
|
+
// Checked now rather than left to fail on the first instruction. By then a
|
|
131
|
+
// link has been printed and shared, so the failure lands in front of
|
|
132
|
+
// whoever was invited — and reads as "this tool is broken" rather than
|
|
133
|
+
// "you need to log in".
|
|
134
|
+
if ((await findClaudeLogin()) === "missing") {
|
|
135
|
+
throw new Error(noLoginGuidance(await hasClaudeCli()));
|
|
136
|
+
}
|
|
126
137
|
return { mode: "real", keySource: "oauth", keyHint: null };
|
|
127
138
|
}
|
|
128
139
|
if (!looksLikeApiKey(key)) {
|
|
@@ -171,6 +182,7 @@ async function main() {
|
|
|
171
182
|
console.log(`\n repo ${path.basename(sourcePath)} (${sourcePath})`);
|
|
172
183
|
console.log(` agent ${billing}`);
|
|
173
184
|
console.log(` session ${id}`);
|
|
185
|
+
console.log(` shared transcript only — code, keys and files stay on this machine`);
|
|
174
186
|
console.log(`\n Share this link:\n ${new URL(`/session/${id}`, webUrl)}\n`);
|
|
175
187
|
if (!existing) {
|
|
176
188
|
console.log(` To reattach after a restart:\n relayrun --session ${id} --token ${runnerToken}\n`);
|
|
@@ -184,6 +196,7 @@ async function main() {
|
|
|
184
196
|
keySource: credentials.keySource,
|
|
185
197
|
keyHint: credentials.keyHint,
|
|
186
198
|
apiKeyHelper: credentials.apiKeyHelper,
|
|
199
|
+
model: str(args, "model") ?? DEFAULT_MODEL,
|
|
187
200
|
});
|
|
188
201
|
}
|
|
189
202
|
main().catch((err) => {
|
package/dist/login.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
const run = promisify(execFile);
|
|
7
|
+
// Probed for existence only. `security` prints the secret itself just for -w,
|
|
8
|
+
// which is deliberately not passed — nothing here needs the credential, only
|
|
9
|
+
// the knowledge that one exists.
|
|
10
|
+
const KEYCHAIN_SERVICE = "Claude Code-credentials";
|
|
11
|
+
const PROBE_TIMEOUT_MS = 5_000;
|
|
12
|
+
export async function findClaudeLogin() {
|
|
13
|
+
if (process.platform === "darwin") {
|
|
14
|
+
try {
|
|
15
|
+
await run("security", ["find-generic-password", "-s", KEYCHAIN_SERVICE], {
|
|
16
|
+
timeout: PROBE_TIMEOUT_MS,
|
|
17
|
+
});
|
|
18
|
+
return "found";
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return "missing";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (process.platform === "linux") {
|
|
25
|
+
return existsSync(path.join(homedir(), ".claude", ".credentials.json"))
|
|
26
|
+
? "found"
|
|
27
|
+
: "missing";
|
|
28
|
+
}
|
|
29
|
+
return "unknown";
|
|
30
|
+
}
|
|
31
|
+
/** Whether the Claude Code CLI is on PATH, so the advice can skip an install step. */
|
|
32
|
+
export async function hasClaudeCli() {
|
|
33
|
+
try {
|
|
34
|
+
await run("command", ["-v", "claude"], { shell: true, timeout: PROBE_TIMEOUT_MS });
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Printed instead of a session link when no credential is found.
|
|
43
|
+
*
|
|
44
|
+
* Line one carries no indent because the caller's error handler adds it; the
|
|
45
|
+
* rest is indented here.
|
|
46
|
+
*
|
|
47
|
+
* Two variants because the install step is noise for the many people who
|
|
48
|
+
* already have the CLI and simply are not signed in — telling them to install
|
|
49
|
+
* something they have reads as advice that hasn't looked at their machine.
|
|
50
|
+
*
|
|
51
|
+
* There is deliberately no "click here to log in" link: the sign-in is an
|
|
52
|
+
* OAuth flow the CLI has to start itself, since it generates the challenge and
|
|
53
|
+
* receives the callback that writes the credential. No static URL can do it.
|
|
54
|
+
*/
|
|
55
|
+
export function noLoginGuidance(cliInstalled) {
|
|
56
|
+
const signIn = cliInstalled
|
|
57
|
+
? ` 1 Sign in to Claude Code (recommended)
|
|
58
|
+
claude → sign in, then re-run relayrun
|
|
59
|
+
The CLI is already installed here — it just isn't signed in.`
|
|
60
|
+
: ` 1 Install and sign in to Claude Code (recommended)
|
|
61
|
+
npm i -g @anthropic-ai/claude-code
|
|
62
|
+
claude → sign in, then re-run relayrun
|
|
63
|
+
Setup guide: https://docs.claude.com/en/docs/claude-code/setup`;
|
|
64
|
+
return `No Claude credential found on this machine
|
|
65
|
+
|
|
66
|
+
relayrun ships no credentials of its own. It runs Claude on your machine,
|
|
67
|
+
with your access, billed to your account — so it needs one of these first:
|
|
68
|
+
|
|
69
|
+
${signIn}
|
|
70
|
+
|
|
71
|
+
2 Use an Anthropic API key
|
|
72
|
+
relayrun --api-key sk-ant-...
|
|
73
|
+
Create one at https://console.anthropic.com/settings/keys
|
|
74
|
+
|
|
75
|
+
3 See how it works without spending anything
|
|
76
|
+
relayrun --mock → scripted demo, ignores your instructions
|
|
77
|
+
|
|
78
|
+
Signing in through the Claude Code VS Code extension works too — it shares
|
|
79
|
+
the same credential. A claude.ai browser session or the Claude Desktop app
|
|
80
|
+
does not.`;
|
|
81
|
+
}
|
package/dist/runner.js
CHANGED
package/package.json
CHANGED