@relayfile/sdk 0.10.62 → 0.10.64
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/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/relay-cli/cloud-preflight.d.ts +99 -0
- package/dist/relay-cli/cloud-preflight.js +352 -0
- package/dist/relay-cli/command-spec.json +1682 -0
- package/dist/relay-cli/index.d.ts +125 -0
- package/dist/relay-cli/index.js +197 -0
- package/dist/relay-cli/resolve-binary.d.ts +220 -0
- package/dist/relay-cli/resolve-binary.js +565 -0
- package/package.json +21 -8
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* relayfile's CLI surface, mounted by the `agent-relay` CLI as
|
|
3
|
+
* `agent-relay file`.
|
|
4
|
+
*
|
|
5
|
+
* The surface does not reimplement any relayfile command. `commands` is a
|
|
6
|
+
* checked-in snapshot of the Go binary's own command table (emitted by
|
|
7
|
+
* `relayfile __command-spec --json`, regenerated by `npm run gen:command-spec`)
|
|
8
|
+
* and `run` spawns that same binary, so `agent-relay file <cmd>` and
|
|
9
|
+
* `relayfile <cmd>` are the same code path.
|
|
10
|
+
*
|
|
11
|
+
* Structurally typed against `@agent-relay/cli-surface` (a devDependency):
|
|
12
|
+
* this package gains no runtime dependency on relay.
|
|
13
|
+
*/
|
|
14
|
+
import { type EnsureCloudSession } from "./cloud-preflight.js";
|
|
15
|
+
import { type ResolveRelayfileBinaryOptions } from "./resolve-binary.js";
|
|
16
|
+
/** Contract revision implemented here; mirrors `@agent-relay/cli-surface`. */
|
|
17
|
+
export declare const RELAY_CLI_CONTRACT_VERSION = 1;
|
|
18
|
+
/** Exit code for an argv the surface cannot route. */
|
|
19
|
+
export declare const RELAY_CLI_EXIT_UNKNOWN_COMMAND = 2;
|
|
20
|
+
/**
|
|
21
|
+
* Exit code when no relayfile binary could be found. Distinct from an
|
|
22
|
+
* unroutable argv (2) and from any code the binary itself returns, so a host
|
|
23
|
+
* can tell "relayfile is not installed here" from "relayfile ran and failed".
|
|
24
|
+
*/
|
|
25
|
+
export declare const RELAY_CLI_EXIT_BINARY_NOT_FOUND = 127;
|
|
26
|
+
/**
|
|
27
|
+
* Output sink supplied by the host.
|
|
28
|
+
*
|
|
29
|
+
* Chunks are handed over as the raw bytes the binary wrote, not as decoded
|
|
30
|
+
* strings. `relayfile export --format tar --output -` streams a tar archive to
|
|
31
|
+
* stdout, and decoding that as UTF-8 corrupts it silently; a multibyte
|
|
32
|
+
* character split across two reads corrupts the same way in the other
|
|
33
|
+
* direction. Passing the bytes through untouched is correct for both, and
|
|
34
|
+
* matches `RelayCliIo` in `@agent-relay/cli-surface`.
|
|
35
|
+
*/
|
|
36
|
+
export interface RelayCliIo {
|
|
37
|
+
stdout(chunk: string | Uint8Array): void;
|
|
38
|
+
stderr(chunk: string | Uint8Array): void;
|
|
39
|
+
}
|
|
40
|
+
export interface RelayCliArgSpec {
|
|
41
|
+
name: string;
|
|
42
|
+
description: string;
|
|
43
|
+
required: boolean;
|
|
44
|
+
variadic?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface RelayCliOptionSpec {
|
|
47
|
+
flags: string;
|
|
48
|
+
description: string;
|
|
49
|
+
defaultValue?: string | boolean | number;
|
|
50
|
+
}
|
|
51
|
+
export interface RelayCliCommandSpec {
|
|
52
|
+
name: string;
|
|
53
|
+
description: string;
|
|
54
|
+
aliases?: readonly string[];
|
|
55
|
+
args?: readonly RelayCliArgSpec[];
|
|
56
|
+
options?: readonly RelayCliOptionSpec[];
|
|
57
|
+
subcommands?: readonly RelayCliCommandSpec[];
|
|
58
|
+
deprecated?: {
|
|
59
|
+
replacement: string;
|
|
60
|
+
since?: string;
|
|
61
|
+
};
|
|
62
|
+
hidden?: boolean;
|
|
63
|
+
}
|
|
64
|
+
export interface RelayCliSurface {
|
|
65
|
+
id: string;
|
|
66
|
+
version: string;
|
|
67
|
+
contract: 1;
|
|
68
|
+
commands: readonly RelayCliCommandSpec[];
|
|
69
|
+
run(argv: readonly string[], io: RelayCliIo): Promise<number>;
|
|
70
|
+
}
|
|
71
|
+
export interface CreateRelayCliSurfaceOptions {
|
|
72
|
+
/** Binary lookup overrides; forwarded to `resolveRelayfileBinary`. */
|
|
73
|
+
resolve?: ResolveRelayfileBinaryOptions;
|
|
74
|
+
/** Environment for the child process and the Cloud preflight. */
|
|
75
|
+
env?: NodeJS.ProcessEnv;
|
|
76
|
+
/** Working directory for the child process. */
|
|
77
|
+
cwd?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Skip the Cloud sign-in preflight. Only for tests: skipping it makes
|
|
80
|
+
* `agent-relay file setup` behave differently from `relayfile setup`.
|
|
81
|
+
*/
|
|
82
|
+
skipCloudPreflight?: boolean;
|
|
83
|
+
/** Injected Cloud SDK entry point, for tests. */
|
|
84
|
+
ensureCloudSession?: EnsureCloudSession;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Path of the checked-in command-tree snapshot.
|
|
88
|
+
*
|
|
89
|
+
* Lives next to the compiled module so the published package carries it.
|
|
90
|
+
*/
|
|
91
|
+
export declare const COMMAND_SPEC_PATH: string;
|
|
92
|
+
/**
|
|
93
|
+
* Read the snapshot of the Go binary's command tree.
|
|
94
|
+
*
|
|
95
|
+
* Read from disk rather than imported so the module needs no JSON import
|
|
96
|
+
* attributes and stays loadable from both ESM and a CJS `import()`.
|
|
97
|
+
*
|
|
98
|
+
* @returns The command tree the relayfile binary dispatches.
|
|
99
|
+
*/
|
|
100
|
+
export declare function relayfileCommands(): readonly RelayCliCommandSpec[];
|
|
101
|
+
/**
|
|
102
|
+
* Every name and alias the relayfile binary routes at the top level.
|
|
103
|
+
*
|
|
104
|
+
* Includes three tokens the binary routes outside its command table, and so
|
|
105
|
+
* keeps out of its published surface: `help` (the host renders help itself),
|
|
106
|
+
* `__command-spec` (the introspection hook that produces the snapshot), and
|
|
107
|
+
* `version` (handled by the binary's `wantsVersion`, the same path as
|
|
108
|
+
* `--version`). They are routable here but deliberately not declared in
|
|
109
|
+
* `commands`: that tree is a generated snapshot of the Go command table, and
|
|
110
|
+
* the binary's own usage does not advertise `version` either, so declaring it
|
|
111
|
+
* would make `agent-relay file --help` claim a command `relayfile --help`
|
|
112
|
+
* does not.
|
|
113
|
+
*
|
|
114
|
+
* @returns The routable top-level tokens.
|
|
115
|
+
*/
|
|
116
|
+
export declare function routableTopLevelNames(): readonly string[];
|
|
117
|
+
/**
|
|
118
|
+
* Create relayfile's mountable CLI surface.
|
|
119
|
+
*
|
|
120
|
+
* @param options - Optional overrides for binary lookup, env, and cwd.
|
|
121
|
+
* @returns A surface satisfying `@agent-relay/cli-surface`'s `RelayCliSurface`.
|
|
122
|
+
*/
|
|
123
|
+
export declare function createRelayCliSurface(options?: CreateRelayCliSurfaceOptions): RelayCliSurface;
|
|
124
|
+
export { buildGoRunBinary, goRunBinaryPath, GoBuildFailedError, GoToolchainMissingError, RelayfileBinaryNotFoundError, resolveRelayfileBinary, findSourceCheckoutRoot, formatBinaryNotFoundMessage, genericBinaryName, platformBinaryName, platformPackageBinaryName, platformPackageName, platformPackageNames, GO_TOOLCHAIN_MISSING_MESSAGE, RELAYFILE_CLI_BIN_ENV, type BuildGoRunBinaryOptions, type RelayfileBinaryResolution, type RelayfileGoRunResolution, type ResolveRelayfileBinaryOptions } from "./resolve-binary.js";
|
|
125
|
+
export { announceSetupIntent, hasValidSetupArguments, parseGoDurationMilliseconds, parseSetupArguments, prepareCloudSession, shouldPrepareCloudSession, loadCloudSessionSDK, DEFAULT_CLOUD_API_URL, SETUP_INTENT, SETUP_INTENT_PRINTED_ENV, type CloudPreflightOptions, type EnsureCloudSession } from "./cloud-preflight.js";
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* relayfile's CLI surface, mounted by the `agent-relay` CLI as
|
|
3
|
+
* `agent-relay file`.
|
|
4
|
+
*
|
|
5
|
+
* The surface does not reimplement any relayfile command. `commands` is a
|
|
6
|
+
* checked-in snapshot of the Go binary's own command table (emitted by
|
|
7
|
+
* `relayfile __command-spec --json`, regenerated by `npm run gen:command-spec`)
|
|
8
|
+
* and `run` spawns that same binary, so `agent-relay file <cmd>` and
|
|
9
|
+
* `relayfile <cmd>` are the same code path.
|
|
10
|
+
*
|
|
11
|
+
* Structurally typed against `@agent-relay/cli-surface` (a devDependency):
|
|
12
|
+
* this package gains no runtime dependency on relay.
|
|
13
|
+
*/
|
|
14
|
+
import { spawn } from "node:child_process";
|
|
15
|
+
import { readFileSync } from "node:fs";
|
|
16
|
+
import os from "node:os";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import { fileURLToPath } from "node:url";
|
|
19
|
+
import { RELAYFILE_VERSION } from "../package-version.js";
|
|
20
|
+
import { announceSetupIntent, prepareCloudSession } from "./cloud-preflight.js";
|
|
21
|
+
import { buildGoRunBinary, GoBuildFailedError, GoToolchainMissingError, RelayfileBinaryNotFoundError, resolveRelayfileBinary } from "./resolve-binary.js";
|
|
22
|
+
/** Contract revision implemented here; mirrors `@agent-relay/cli-surface`. */
|
|
23
|
+
export const RELAY_CLI_CONTRACT_VERSION = 1;
|
|
24
|
+
/** Exit code for an argv the surface cannot route. */
|
|
25
|
+
export const RELAY_CLI_EXIT_UNKNOWN_COMMAND = 2;
|
|
26
|
+
/**
|
|
27
|
+
* Exit code when no relayfile binary could be found. Distinct from an
|
|
28
|
+
* unroutable argv (2) and from any code the binary itself returns, so a host
|
|
29
|
+
* can tell "relayfile is not installed here" from "relayfile ran and failed".
|
|
30
|
+
*/
|
|
31
|
+
export const RELAY_CLI_EXIT_BINARY_NOT_FOUND = 127;
|
|
32
|
+
/**
|
|
33
|
+
* Path of the checked-in command-tree snapshot.
|
|
34
|
+
*
|
|
35
|
+
* Lives next to the compiled module so the published package carries it.
|
|
36
|
+
*/
|
|
37
|
+
export const COMMAND_SPEC_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "command-spec.json");
|
|
38
|
+
let cachedCommands;
|
|
39
|
+
/**
|
|
40
|
+
* Read the snapshot of the Go binary's command tree.
|
|
41
|
+
*
|
|
42
|
+
* Read from disk rather than imported so the module needs no JSON import
|
|
43
|
+
* attributes and stays loadable from both ESM and a CJS `import()`.
|
|
44
|
+
*
|
|
45
|
+
* @returns The command tree the relayfile binary dispatches.
|
|
46
|
+
*/
|
|
47
|
+
export function relayfileCommands() {
|
|
48
|
+
if (!cachedCommands) {
|
|
49
|
+
cachedCommands = JSON.parse(readFileSync(COMMAND_SPEC_PATH, "utf8"));
|
|
50
|
+
}
|
|
51
|
+
return cachedCommands;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Every name and alias the relayfile binary routes at the top level.
|
|
55
|
+
*
|
|
56
|
+
* Includes three tokens the binary routes outside its command table, and so
|
|
57
|
+
* keeps out of its published surface: `help` (the host renders help itself),
|
|
58
|
+
* `__command-spec` (the introspection hook that produces the snapshot), and
|
|
59
|
+
* `version` (handled by the binary's `wantsVersion`, the same path as
|
|
60
|
+
* `--version`). They are routable here but deliberately not declared in
|
|
61
|
+
* `commands`: that tree is a generated snapshot of the Go command table, and
|
|
62
|
+
* the binary's own usage does not advertise `version` either, so declaring it
|
|
63
|
+
* would make `agent-relay file --help` claim a command `relayfile --help`
|
|
64
|
+
* does not.
|
|
65
|
+
*
|
|
66
|
+
* @returns The routable top-level tokens.
|
|
67
|
+
*/
|
|
68
|
+
export function routableTopLevelNames() {
|
|
69
|
+
const names = new Set(["help", "__command-spec", "version"]);
|
|
70
|
+
for (const command of relayfileCommands()) {
|
|
71
|
+
names.add(command.name);
|
|
72
|
+
for (const alias of command.aliases ?? []) {
|
|
73
|
+
names.add(alias);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return [...names];
|
|
77
|
+
}
|
|
78
|
+
function isFlag(token) {
|
|
79
|
+
return token.startsWith("-");
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Exit code convention for a child killed by a signal: 128 + signal number, so
|
|
83
|
+
* callers can tell user cancellation (130 for SIGINT) from a generic failure.
|
|
84
|
+
*
|
|
85
|
+
* @returns The exit code to report for `signal`.
|
|
86
|
+
*/
|
|
87
|
+
function exitCodeForSignal(signal) {
|
|
88
|
+
const signum = os.constants.signals[signal];
|
|
89
|
+
return typeof signum === "number" ? 128 + signum : 1;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create relayfile's mountable CLI surface.
|
|
93
|
+
*
|
|
94
|
+
* @param options - Optional overrides for binary lookup, env, and cwd.
|
|
95
|
+
* @returns A surface satisfying `@agent-relay/cli-surface`'s `RelayCliSurface`.
|
|
96
|
+
*/
|
|
97
|
+
export function createRelayCliSurface(options = {}) {
|
|
98
|
+
const commands = relayfileCommands();
|
|
99
|
+
return {
|
|
100
|
+
id: "relayfile",
|
|
101
|
+
version: RELAYFILE_VERSION,
|
|
102
|
+
contract: RELAY_CLI_CONTRACT_VERSION,
|
|
103
|
+
commands,
|
|
104
|
+
async run(argv, io) {
|
|
105
|
+
const args = [...argv];
|
|
106
|
+
const env = options.env ?? process.env;
|
|
107
|
+
const first = args[0];
|
|
108
|
+
if (first !== undefined && !isFlag(first) && !routableTopLevelNames().includes(first)) {
|
|
109
|
+
io.stderr(`unknown command "${first}"\n`);
|
|
110
|
+
io.stderr(`run \`agent-relay file --help\` for the relayfile command tree\n`);
|
|
111
|
+
return RELAY_CLI_EXIT_UNKNOWN_COMMAND;
|
|
112
|
+
}
|
|
113
|
+
if (!options.skipCloudPreflight) {
|
|
114
|
+
// Agent Relay's Cloud SDK owns interactive login, token refresh,
|
|
115
|
+
// locking, and the canonical session store; the native runtime reads
|
|
116
|
+
// that same store directly. Running this here keeps
|
|
117
|
+
// `agent-relay file setup` identical to `relayfile setup`.
|
|
118
|
+
announceSetupIntent(args, env, (line) => io.stdout(`${line}\n`));
|
|
119
|
+
await prepareCloudSession(args, {
|
|
120
|
+
env,
|
|
121
|
+
writeLine: (line) => io.stdout(`${line}\n`),
|
|
122
|
+
ensureCloudSession: options.ensureCloudSession
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
let resolution;
|
|
126
|
+
try {
|
|
127
|
+
resolution = resolveRelayfileBinary(options.resolve);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
if (!(error instanceof RelayfileBinaryNotFoundError)) {
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
// The contract says run() resolves to an exit code, so a missing
|
|
134
|
+
// binary is reported through io rather than thrown at the host. The
|
|
135
|
+
// message names the `@relayfile/cli-*` package to install for this
|
|
136
|
+
// platform; a bare ENOENT would send people hunting their PATH.
|
|
137
|
+
io.stderr(`${error.message}\n`);
|
|
138
|
+
return RELAY_CLI_EXIT_BINARY_NOT_FOUND;
|
|
139
|
+
}
|
|
140
|
+
let command = resolution.command;
|
|
141
|
+
let childArgs = [...resolution.args, ...args];
|
|
142
|
+
if (resolution.kind === "go-run") {
|
|
143
|
+
// `go run` would launch relayfile with the checkout as its working
|
|
144
|
+
// directory — `go` only finds the module from there — so every
|
|
145
|
+
// relative path in argv would resolve against the repository instead
|
|
146
|
+
// of wherever the caller ran. Build first, then spawn the result from
|
|
147
|
+
// the caller's directory.
|
|
148
|
+
try {
|
|
149
|
+
command = buildGoRunBinary(resolution, { env });
|
|
150
|
+
childArgs = [...args];
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (error instanceof GoToolchainMissingError ||
|
|
154
|
+
error instanceof GoBuildFailedError) {
|
|
155
|
+
io.stderr(`${error.message}\n`);
|
|
156
|
+
return 1;
|
|
157
|
+
}
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const cwd = options.cwd;
|
|
162
|
+
return await new Promise((resolve, reject) => {
|
|
163
|
+
// stdin is inherited so interactive prompts (setup, login, delete
|
|
164
|
+
// confirmations) still work; stdout/stderr are piped into `io` because
|
|
165
|
+
// the contract forbids writing to the host's streams directly. No
|
|
166
|
+
// signal handlers are installed: the host owns them.
|
|
167
|
+
const child = spawn(command, childArgs, {
|
|
168
|
+
cwd,
|
|
169
|
+
env,
|
|
170
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
171
|
+
});
|
|
172
|
+
// No setEncoding: the bytes go to `io` exactly as the binary wrote
|
|
173
|
+
// them. `export --format tar --output -` streams an archive here.
|
|
174
|
+
child.stdout?.on("data", (chunk) => io.stdout(chunk));
|
|
175
|
+
child.stderr?.on("data", (chunk) => io.stderr(chunk));
|
|
176
|
+
// A missing Go toolchain is reported by buildGoRunBinary above, not
|
|
177
|
+
// here: by this point `command` is always a real binary.
|
|
178
|
+
child.on("error", (error) => {
|
|
179
|
+
reject(error);
|
|
180
|
+
});
|
|
181
|
+
child.on("close", (code, signal) => {
|
|
182
|
+
if (typeof code === "number") {
|
|
183
|
+
resolve(code);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (signal) {
|
|
187
|
+
resolve(exitCodeForSignal(signal));
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
resolve(1);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
export { buildGoRunBinary, goRunBinaryPath, GoBuildFailedError, GoToolchainMissingError, RelayfileBinaryNotFoundError, resolveRelayfileBinary, findSourceCheckoutRoot, formatBinaryNotFoundMessage, genericBinaryName, platformBinaryName, platformPackageBinaryName, platformPackageName, platformPackageNames, GO_TOOLCHAIN_MISSING_MESSAGE, RELAYFILE_CLI_BIN_ENV } from "./resolve-binary.js";
|
|
197
|
+
export { announceSetupIntent, hasValidSetupArguments, parseGoDurationMilliseconds, parseSetupArguments, prepareCloudSession, shouldPrepareCloudSession, loadCloudSessionSDK, DEFAULT_CLOUD_API_URL, SETUP_INTENT, SETUP_INTENT_PRINTED_ENV } from "./cloud-preflight.js";
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one implementation of "find the relayfile binary".
|
|
3
|
+
*
|
|
4
|
+
* The real relayfile CLI is the Go binary (`cmd/relayfile-cli`). Both entry
|
|
5
|
+
* points into it — the `relayfile` npm package's bin shim
|
|
6
|
+
* (`packages/cli/scripts/run.js`) and the `agent-relay file` CLI surface in
|
|
7
|
+
* this directory — resolve it through this module. Nothing else in the repo
|
|
8
|
+
* may reimplement the lookup.
|
|
9
|
+
*
|
|
10
|
+
* The binary reaches a machine two different ways, and the resolver has to
|
|
11
|
+
* cope with both:
|
|
12
|
+
*
|
|
13
|
+
* - As `@relayfile/cli-<platform>-<arch>`, an optional dependency of this
|
|
14
|
+
* package. npm installs only the one matching the host's `os`/`cpu`, so
|
|
15
|
+
* nothing is downloaded at install time, the install works offline and in
|
|
16
|
+
* CI, and integrity comes from the registry. This is the only path that
|
|
17
|
+
* exists for a consumer that depends on `@relayfile/sdk` without depending
|
|
18
|
+
* on `relayfile` — `agent-relay` is exactly that consumer.
|
|
19
|
+
* - Inside the `relayfile` package's own `bin/`, put there by that package's
|
|
20
|
+
* `postinstall` (`packages/cli/scripts/install.js`), which downloads the
|
|
21
|
+
* per-platform build from GitHub Releases.
|
|
22
|
+
*/
|
|
23
|
+
/** Environment variable that pins the binary, bypassing every other step. */
|
|
24
|
+
export declare const RELAYFILE_CLI_BIN_ENV = "RELAYFILE_CLI_BIN";
|
|
25
|
+
/** How the resolver decided to launch relayfile. */
|
|
26
|
+
export type RelayfileBinaryResolution = {
|
|
27
|
+
/** A packaged or locally built binary was found. */
|
|
28
|
+
kind: "binary";
|
|
29
|
+
command: string;
|
|
30
|
+
args: readonly string[];
|
|
31
|
+
/** Absolute path of the binary that matched. */
|
|
32
|
+
binaryPath: string;
|
|
33
|
+
} | {
|
|
34
|
+
/**
|
|
35
|
+
* No binary was found, but we are inside a source checkout, so relayfile
|
|
36
|
+
* runs straight from Go source. `postinstall` intentionally skips
|
|
37
|
+
* building the binary in a checkout; without this fallback the installed
|
|
38
|
+
* `relayfile` command would be unusable there.
|
|
39
|
+
*/
|
|
40
|
+
kind: "go-run";
|
|
41
|
+
command: "go";
|
|
42
|
+
args: readonly string[];
|
|
43
|
+
cwd: string;
|
|
44
|
+
};
|
|
45
|
+
export interface ResolveRelayfileBinaryOptions {
|
|
46
|
+
/**
|
|
47
|
+
* Directories to search for a packaged binary, highest priority first.
|
|
48
|
+
* Defaults to the `bin` directory of the installed `relayfile` package plus
|
|
49
|
+
* the workspace copy when running inside this repo.
|
|
50
|
+
*/
|
|
51
|
+
binDirs?: readonly string[];
|
|
52
|
+
/** Extra directories to start the source-checkout search from. */
|
|
53
|
+
searchFrom?: readonly string[];
|
|
54
|
+
/**
|
|
55
|
+
* Anchors for the `require.resolve` that finds
|
|
56
|
+
* `@relayfile/cli-<platform>-<arch>`. Defaults to this module, the entry
|
|
57
|
+
* script, and the cwd — the three places a consumer's copy of the package
|
|
58
|
+
* can be reached from.
|
|
59
|
+
*/
|
|
60
|
+
resolveFrom?: readonly string[];
|
|
61
|
+
/** `PATH` entries for the last-resort lookup. Defaults to `env.PATH`. */
|
|
62
|
+
pathEntries?: readonly string[];
|
|
63
|
+
/** Environment read for `RELAYFILE_CLI_BIN` and `PATH`. */
|
|
64
|
+
env?: NodeJS.ProcessEnv;
|
|
65
|
+
platform?: string;
|
|
66
|
+
arch?: string;
|
|
67
|
+
/** Injected for tests. */
|
|
68
|
+
fileExists?: (candidate: string) => boolean;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Name of the npm package carrying the prebuilt binary for a target.
|
|
72
|
+
*
|
|
73
|
+
* @param platform - Node platform id; defaults to this host's.
|
|
74
|
+
* @param arch - Node arch id; defaults to this host's.
|
|
75
|
+
* @returns The package name, or null when no package is published for the
|
|
76
|
+
* target (nothing to suggest installing, so callers say "build from source").
|
|
77
|
+
*/
|
|
78
|
+
export declare function platformPackageName(platform?: string, arch?: string): string | null;
|
|
79
|
+
/** Every `@relayfile/cli-*` package name, for tests and release tooling. */
|
|
80
|
+
export declare function platformPackageNames(): readonly string[];
|
|
81
|
+
/**
|
|
82
|
+
* Name of the binary inside a `@relayfile/cli-*` package.
|
|
83
|
+
*
|
|
84
|
+
* It keeps the Go binary's own name (matching `relayfile-mount` inside the
|
|
85
|
+
* `@relayfile/mount-*` packages) rather than the `relayfile` name the CLI
|
|
86
|
+
* package installs, so the two never collide on a machine that has both.
|
|
87
|
+
*
|
|
88
|
+
* @param platform - Node platform id; defaults to this host's.
|
|
89
|
+
* @returns The file name, with `.exe` on Windows.
|
|
90
|
+
*/
|
|
91
|
+
export declare function platformPackageBinaryName(platform?: string): string;
|
|
92
|
+
/** Thrown when neither a binary nor a usable source checkout was found. */
|
|
93
|
+
export declare class RelayfileBinaryNotFoundError extends Error {
|
|
94
|
+
readonly platform: string;
|
|
95
|
+
readonly arch: string;
|
|
96
|
+
/** The `@relayfile/cli-*` package for this target, when one is published. */
|
|
97
|
+
readonly platformPackage: string | null;
|
|
98
|
+
constructor(platform: string, arch: string);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Explain what to install, for this exact platform.
|
|
102
|
+
*
|
|
103
|
+
* A bare ENOENT sends people looking for a bug in their PATH. The prebuilt
|
|
104
|
+
* binary is an optional dependency, so the two things that actually cause this
|
|
105
|
+
* — `--omit=optional` and an unsupported target — both need naming.
|
|
106
|
+
*
|
|
107
|
+
* @param platform - Node platform id.
|
|
108
|
+
* @param arch - Node arch id.
|
|
109
|
+
* @returns The message carried by `RelayfileBinaryNotFoundError`.
|
|
110
|
+
*/
|
|
111
|
+
export declare function formatBinaryNotFoundMessage(platform: string, arch: string): string;
|
|
112
|
+
/**
|
|
113
|
+
* Name of the per-platform binary shipped inside the `relayfile` package.
|
|
114
|
+
*
|
|
115
|
+
* @returns The packaged binary's file name, or null on an unsupported target.
|
|
116
|
+
*/
|
|
117
|
+
export declare function platformBinaryName(platform?: string, arch?: string): string | null;
|
|
118
|
+
/**
|
|
119
|
+
* Name of the binary the CLI package installs and runs, `bin/relayfile`.
|
|
120
|
+
*
|
|
121
|
+
* @param platform - Node platform id; defaults to this host's.
|
|
122
|
+
* @returns The file name, with `.exe` on Windows.
|
|
123
|
+
*/
|
|
124
|
+
export declare function genericBinaryName(platform?: string): string;
|
|
125
|
+
/**
|
|
126
|
+
* Locate a relayfile source checkout: a directory with both `go.mod` and
|
|
127
|
+
* `cmd/relayfile-cli`.
|
|
128
|
+
*
|
|
129
|
+
* @returns The checkout root, or null when there is none above `start`.
|
|
130
|
+
*/
|
|
131
|
+
export declare function findSourceCheckoutRoot(start: string, exists?: (candidate: string) => boolean): string | null;
|
|
132
|
+
/**
|
|
133
|
+
* Resolve how to launch the relayfile CLI on this machine.
|
|
134
|
+
*
|
|
135
|
+
* Search order, and why it is this order:
|
|
136
|
+
* 1. `RELAYFILE_CLI_BIN` — the escape hatch, so a developer or operator can
|
|
137
|
+
* always pin an exact binary.
|
|
138
|
+
* 2. `@relayfile/cli-<platform>-<arch>` — the prebuilt binary npm installed
|
|
139
|
+
* for this host. First because it is the only path that exists for a
|
|
140
|
+
* consumer of `@relayfile/sdk` that does not also depend on `relayfile`
|
|
141
|
+
* (`agent-relay file` is that consumer), and because it needs no network.
|
|
142
|
+
* 3. The `binDirs` chain: a generic `bin/relayfile` (the `relayfile`
|
|
143
|
+
* package's postinstall download, or a local build), then the
|
|
144
|
+
* per-platform `bin/relayfile-cli-<os>-<arch>` that package ships.
|
|
145
|
+
* 4. `make build` / `make release` outputs in an enclosing source checkout.
|
|
146
|
+
* 5. `go run ./cmd/relayfile-cli` from that checkout.
|
|
147
|
+
* 6. `PATH`, for a binary installed outside npm.
|
|
148
|
+
*
|
|
149
|
+
* @param options - Search overrides; all are optional.
|
|
150
|
+
* @returns The command, argv prefix, and cwd to spawn.
|
|
151
|
+
* @throws {RelayfileBinaryNotFoundError} When nothing usable was found.
|
|
152
|
+
*/
|
|
153
|
+
export declare function resolveRelayfileBinary(options?: ResolveRelayfileBinaryOptions): RelayfileBinaryResolution;
|
|
154
|
+
/** Message shown when a source checkout was found but Go is not installed. */
|
|
155
|
+
export declare const GO_TOOLCHAIN_MISSING_MESSAGE: string;
|
|
156
|
+
/** A `go-run` resolution: no binary was found, but a checkout was. */
|
|
157
|
+
export type RelayfileGoRunResolution = Extract<RelayfileBinaryResolution, {
|
|
158
|
+
kind: "go-run";
|
|
159
|
+
}>;
|
|
160
|
+
/** Thrown by `buildGoRunBinary` when there is no `go` on PATH. */
|
|
161
|
+
export declare class GoToolchainMissingError extends Error {
|
|
162
|
+
constructor();
|
|
163
|
+
}
|
|
164
|
+
/** Thrown by `buildGoRunBinary` when `go build` itself fails. */
|
|
165
|
+
export declare class GoBuildFailedError extends Error {
|
|
166
|
+
/** `go build`'s exit code, or null when it was killed by a signal. */
|
|
167
|
+
readonly exitCode: number | null;
|
|
168
|
+
constructor(exitCode: number | null, stderr: string);
|
|
169
|
+
}
|
|
170
|
+
export interface BuildGoRunBinaryOptions {
|
|
171
|
+
/** Environment for `go build`; also supplies the PATH it is found on. */
|
|
172
|
+
env?: NodeJS.ProcessEnv;
|
|
173
|
+
/** Output path override, for tests. */
|
|
174
|
+
outputPath?: string;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Where a source-checkout build is cached: outside the checkout, keyed by it.
|
|
178
|
+
*
|
|
179
|
+
* Not `<checkout>/bin`, which is `make build`'s output — a fallback launch
|
|
180
|
+
* must not write into someone's working tree, and a read-only checkout still
|
|
181
|
+
* has to work.
|
|
182
|
+
*
|
|
183
|
+
* @param checkout - The source checkout root.
|
|
184
|
+
* @param platform - Node platform id; defaults to this host's.
|
|
185
|
+
* @returns The absolute path to build to.
|
|
186
|
+
*/
|
|
187
|
+
export declare function goRunBinaryPath(checkout: string, platform?: string): string;
|
|
188
|
+
/**
|
|
189
|
+
* Turn a `go-run` resolution into an executable binary.
|
|
190
|
+
*
|
|
191
|
+
* `go run` cannot be used directly, because the program it launches inherits
|
|
192
|
+
* the `go` command's own working directory — and `go` only finds the module
|
|
193
|
+
* from that directory, so it has to be the checkout. Every relative path in
|
|
194
|
+
* the caller's argv would then resolve against the repository instead of the
|
|
195
|
+
* directory the caller actually ran in (`--output report.json` writing into
|
|
196
|
+
* the checkout root). `go -C <checkout> run` has the same effect, and passing
|
|
197
|
+
* an absolute package path fails outright outside a module.
|
|
198
|
+
*
|
|
199
|
+
* Building first and spawning the result separates the two: the build runs in
|
|
200
|
+
* the checkout, where the module is, and the binary runs wherever the caller
|
|
201
|
+
* asked for. Go's build cache makes the repeat cost a relink.
|
|
202
|
+
*
|
|
203
|
+
* The build never writes the shared path directly. That path is keyed by the
|
|
204
|
+
* checkout alone, so every process that falls back to source aims at the same
|
|
205
|
+
* file — and a `listen` or `mount` launched from it keeps running for hours.
|
|
206
|
+
* Writing it in place would mean overwriting a binary that is executing
|
|
207
|
+
* (impossible on Windows, and on Unix a window in which a concurrent build has
|
|
208
|
+
* replaced it with a partial file). So `go build` writes a private sibling and
|
|
209
|
+
* the result is published with one rename: atomic on POSIX, and an already
|
|
210
|
+
* running process keeps the inode it started from. If the rename cannot
|
|
211
|
+
* happen — Windows refuses to replace a running `.exe` — the caller gets the
|
|
212
|
+
* private path instead, which is just as runnable.
|
|
213
|
+
*
|
|
214
|
+
* @param resolution - The `go-run` resolution to materialize.
|
|
215
|
+
* @param options - Environment and output overrides.
|
|
216
|
+
* @returns The absolute path of the built binary.
|
|
217
|
+
* @throws {GoToolchainMissingError} When `go` is not on PATH.
|
|
218
|
+
* @throws {GoBuildFailedError} When `go build` exits non-zero.
|
|
219
|
+
*/
|
|
220
|
+
export declare function buildGoRunBinary(resolution: RelayfileGoRunResolution, options?: BuildGoRunBinaryOptions): string;
|