@agent-relay/cli-surface 12.2.2 → 12.2.4

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.
@@ -0,0 +1,35 @@
1
+ import { type RelayCliSurface } from './types.js';
2
+ /** Inputs for {@link composeSurfaces}. */
3
+ export interface ComposeSurfacesOptions {
4
+ /** Identifier for the combined surface, e.g. `relayhistory`. */
5
+ id: string;
6
+ /** Version reported for the combined surface. */
7
+ version: string;
8
+ /**
9
+ * Surfaces to merge, in precedence order for error messages.
10
+ *
11
+ * Their top-level command names must be disjoint: two parts claiming the same
12
+ * name would make dispatch ambiguous, and silently picking one would route
13
+ * some invocations to the wrong implementation.
14
+ */
15
+ parts: readonly RelayCliSurface[];
16
+ }
17
+ /**
18
+ * Merge several surfaces into one command tree.
19
+ *
20
+ * `agent-relay sessions` spans local history (`ai-hist`), a cloud client, and
21
+ * Relay's own session replay. Presenting those as three mounted groups would
22
+ * leak our package boundaries into the user's command line; composing them
23
+ * keeps one coherent tree while each half stays owned by its repo.
24
+ *
25
+ * Dispatch routes on the first token: the part that declared that top-level
26
+ * command receives the full argv unchanged, so a part cannot tell whether it
27
+ * was composed or mounted directly.
28
+ *
29
+ * @param options - Combined identity and the parts to merge.
30
+ * @returns A surface whose commands are the concatenation of its parts'.
31
+ * @throws When two parts claim the same top-level name (as a command or an
32
+ * alias), or when a part does not itself conform to the contract.
33
+ */
34
+ export declare function composeSurfaces(options: ComposeSurfacesOptions): RelayCliSurface;
35
+ //# sourceMappingURL=compose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAEpB,0CAA0C;AAC1C,MAAM,WAAW,sBAAsB;IACrC,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,KAAK,EAAE,SAAS,eAAe,EAAE,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CAoDhF"}
@@ -0,0 +1,62 @@
1
+ import { assertSurfaceConforms } from './conformance.js';
2
+ import { RELAY_CLI_CONTRACT_VERSION, } from './types.js';
3
+ /**
4
+ * Merge several surfaces into one command tree.
5
+ *
6
+ * `agent-relay sessions` spans local history (`ai-hist`), a cloud client, and
7
+ * Relay's own session replay. Presenting those as three mounted groups would
8
+ * leak our package boundaries into the user's command line; composing them
9
+ * keeps one coherent tree while each half stays owned by its repo.
10
+ *
11
+ * Dispatch routes on the first token: the part that declared that top-level
12
+ * command receives the full argv unchanged, so a part cannot tell whether it
13
+ * was composed or mounted directly.
14
+ *
15
+ * @param options - Combined identity and the parts to merge.
16
+ * @returns A surface whose commands are the concatenation of its parts'.
17
+ * @throws When two parts claim the same top-level name (as a command or an
18
+ * alias), or when a part does not itself conform to the contract.
19
+ */
20
+ export function composeSurfaces(options) {
21
+ const owners = new Map();
22
+ const commands = [];
23
+ const claim = (name, kind, part) => {
24
+ const existing = owners.get(name);
25
+ if (existing) {
26
+ const describe = (c) => `${c.kind} '${name}' from '${c.surface.id}'`;
27
+ throw new Error(`cannot compose surface '${options.id}': ${describe({ surface: part, kind })} ` +
28
+ `collides with ${describe(existing)}`);
29
+ }
30
+ owners.set(name, { surface: part, kind });
31
+ };
32
+ for (const part of options.parts) {
33
+ // Catch a malformed part here rather than at first invocation: a composed
34
+ // surface is usually built at mount time, so this fails fast and names the
35
+ // offending part.
36
+ assertSurfaceConforms(part);
37
+ for (const command of part.commands) {
38
+ claim(command.name, 'command', part);
39
+ for (const alias of command.aliases ?? [])
40
+ claim(alias, 'alias', part);
41
+ commands.push(command);
42
+ }
43
+ }
44
+ return {
45
+ id: options.id,
46
+ version: options.version,
47
+ contract: RELAY_CLI_CONTRACT_VERSION,
48
+ commands,
49
+ async run(argv, io) {
50
+ const first = argv[0];
51
+ const owner = first === undefined ? undefined : owners.get(first)?.surface;
52
+ if (!owner) {
53
+ // The host renders help and unknown-command errors from `commands`, so
54
+ // reaching here means it dispatched something the spec does not cover.
55
+ io.stderr(`error: '${first ?? ''}' is not a command of ${options.id}\n`);
56
+ return 2;
57
+ }
58
+ return owner.run(argv, io);
59
+ },
60
+ };
61
+ }
62
+ //# sourceMappingURL=compose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.js","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EACL,0BAA0B,GAI3B,MAAM,YAAY,CAAC;AAkBpB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe,CAAC,OAA+B;IAO7D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAiB,CAAC;IACxC,MAAM,QAAQ,GAA0B,EAAE,CAAC;IAE3C,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,IAAmB,EAAE,IAAqB,EAAQ,EAAE;QAC/E,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,CAAC,CAAQ,EAAU,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,WAAW,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC;YACpF,MAAM,IAAI,KAAK,CACb,2BAA2B,OAAO,CAAC,EAAE,MAAM,QAAQ,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG;gBAC7E,iBAAiB,QAAQ,CAAC,QAAQ,CAAC,EAAE,CACxC,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,0EAA0E;QAC1E,2EAA2E;QAC3E,kBAAkB;QAClB,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAE5B,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;YACrC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,IAAI,EAAE;gBAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;YACvE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,QAAQ,EAAE,0BAA0B;QACpC,QAAQ;QACR,KAAK,CAAC,GAAG,CAAC,IAAuB,EAAE,EAAc;YAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YACtB,MAAM,KAAK,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;YAC3E,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,uEAAuE;gBACvE,uEAAuE;gBACvE,EAAE,CAAC,MAAM,CAAC,WAAW,KAAK,IAAI,EAAE,yBAAyB,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;gBACzE,OAAO,CAAC,CAAC;YACX,CAAC;YACD,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC7B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { type RelayCliCommandSpec, type RelayCliSurface } from './types.js';
2
+ /** Exit code a surface returns when it cannot route the given argv. */
3
+ export declare const RELAY_CLI_EXIT_UNKNOWN_COMMAND = 2;
4
+ /** A conformance problem found in a surface. */
5
+ export interface RelayCliSurfaceViolation {
6
+ /** Dotted path to the offending node, e.g. `commands.run.options[0]`. */
7
+ path: string;
8
+ message: string;
9
+ }
10
+ /**
11
+ * Check a surface against the structural rules in the contract.
12
+ *
13
+ * This validates the declared shape only. Each product repo pairs it with a
14
+ * drift test proving `commands` and `run` dispatch the same tree.
15
+ *
16
+ * @param surface - The surface to check.
17
+ * @returns Every violation found; empty when the surface conforms.
18
+ */
19
+ export declare function findSurfaceViolations(surface: RelayCliSurface): RelayCliSurfaceViolation[];
20
+ /**
21
+ * Throw unless the surface conforms to the contract.
22
+ *
23
+ * @param surface - The surface to check.
24
+ * @throws When any violation is found; the message lists all of them.
25
+ */
26
+ export declare function assertSurfaceConforms(surface: RelayCliSurface): void;
27
+ /**
28
+ * Walk every command in a surface, deepest-last, with its invocation path.
29
+ *
30
+ * @param commands - The command tree to walk.
31
+ * @returns Each command paired with the argv path that reaches it.
32
+ */
33
+ export declare function walkCommands(commands: readonly RelayCliCommandSpec[], prefix?: readonly string[]): Generator<{
34
+ path: readonly string[];
35
+ command: RelayCliCommandSpec;
36
+ }>;
37
+ //# sourceMappingURL=conformance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformance.d.ts","sourceRoot":"","sources":["../src/conformance.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAExG,uEAAuE;AACvE,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAEhD,gDAAgD;AAChD,MAAM,WAAW,wBAAwB;IACvC,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAkED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe,GAAG,wBAAwB,EAAE,CAyB1F;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAKpE;AAED;;;;;GAKG;AACH,wBAAiB,YAAY,CAC3B,QAAQ,EAAE,SAAS,mBAAmB,EAAE,EACxC,MAAM,GAAE,SAAS,MAAM,EAAO,GAC7B,SAAS,CAAC;IAAE,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,mBAAmB,CAAA;CAAE,CAAC,CAMtE"}
@@ -0,0 +1,118 @@
1
+ import { RELAY_CLI_CONTRACT_VERSION } from './types.js';
2
+ /** Exit code a surface returns when it cannot route the given argv. */
3
+ export const RELAY_CLI_EXIT_UNKNOWN_COMMAND = 2;
4
+ const FLAG_PATTERN = /^(-[A-Za-z0-9], )?--[a-z0-9][a-z0-9-]*( [<[][^>\]]+[>\]])?$/;
5
+ const NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
6
+ function checkCommand(command, path, seen, violations) {
7
+ if (!NAME_PATTERN.test(command.name)) {
8
+ violations.push({
9
+ path: `${path}.name`,
10
+ message: `command name ${JSON.stringify(command.name)} must be lowercase kebab-case`,
11
+ });
12
+ }
13
+ if (seen.has(command.name)) {
14
+ violations.push({ path: `${path}.name`, message: `duplicate command name ${command.name}` });
15
+ }
16
+ seen.add(command.name);
17
+ if (!command.description.trim()) {
18
+ violations.push({ path: `${path}.description`, message: 'description must not be empty' });
19
+ }
20
+ let sawOptional = false;
21
+ command.args?.forEach((arg, index) => {
22
+ // Commander cannot express a required positional after an optional one, and
23
+ // a variadic must be last or it swallows its successors.
24
+ if (arg.required && sawOptional) {
25
+ violations.push({
26
+ path: `${path}.args[${index}]`,
27
+ message: `required arg ${arg.name} cannot follow an optional arg`,
28
+ });
29
+ }
30
+ if (!arg.required)
31
+ sawOptional = true;
32
+ if (arg.variadic && index !== (command.args?.length ?? 0) - 1) {
33
+ violations.push({
34
+ path: `${path}.args[${index}]`,
35
+ message: `variadic arg ${arg.name} must be the last positional`,
36
+ });
37
+ }
38
+ });
39
+ const flags = new Set();
40
+ command.options?.forEach((option, index) => {
41
+ if (!FLAG_PATTERN.test(option.flags)) {
42
+ violations.push({
43
+ path: `${path}.options[${index}]`,
44
+ message: `flags ${JSON.stringify(option.flags)} is not a commander flag string`,
45
+ });
46
+ }
47
+ const long = option.flags.match(/--[a-z0-9][a-z0-9-]*/)?.[0];
48
+ if (long && flags.has(long)) {
49
+ violations.push({ path: `${path}.options[${index}]`, message: `duplicate flag ${long}` });
50
+ }
51
+ if (long)
52
+ flags.add(long);
53
+ });
54
+ const childNames = new Set();
55
+ command.subcommands?.forEach((child) => {
56
+ checkCommand(child, `${path}.${child.name}`, childNames, violations);
57
+ });
58
+ }
59
+ /**
60
+ * Check a surface against the structural rules in the contract.
61
+ *
62
+ * This validates the declared shape only. Each product repo pairs it with a
63
+ * drift test proving `commands` and `run` dispatch the same tree.
64
+ *
65
+ * @param surface - The surface to check.
66
+ * @returns Every violation found; empty when the surface conforms.
67
+ */
68
+ export function findSurfaceViolations(surface) {
69
+ const violations = [];
70
+ if (!NAME_PATTERN.test(surface.id)) {
71
+ violations.push({ path: 'id', message: `surface id ${JSON.stringify(surface.id)} must be kebab-case` });
72
+ }
73
+ if (!surface.version.trim()) {
74
+ violations.push({ path: 'version', message: 'version must not be empty' });
75
+ }
76
+ if (surface.contract !== RELAY_CLI_CONTRACT_VERSION) {
77
+ violations.push({
78
+ path: 'contract',
79
+ message: `contract ${String(surface.contract)} is not supported (expected ${RELAY_CLI_CONTRACT_VERSION})`,
80
+ });
81
+ }
82
+ if (surface.commands.length === 0) {
83
+ violations.push({ path: 'commands', message: 'surface declares no commands' });
84
+ }
85
+ const seen = new Set();
86
+ surface.commands.forEach((command) => {
87
+ checkCommand(command, `commands.${command.name}`, seen, violations);
88
+ });
89
+ return violations;
90
+ }
91
+ /**
92
+ * Throw unless the surface conforms to the contract.
93
+ *
94
+ * @param surface - The surface to check.
95
+ * @throws When any violation is found; the message lists all of them.
96
+ */
97
+ export function assertSurfaceConforms(surface) {
98
+ const violations = findSurfaceViolations(surface);
99
+ if (violations.length === 0)
100
+ return;
101
+ const detail = violations.map((violation) => ` ${violation.path}: ${violation.message}`).join('\n');
102
+ throw new Error(`CLI surface ${surface.id} violates contract v${RELAY_CLI_CONTRACT_VERSION}:\n${detail}`);
103
+ }
104
+ /**
105
+ * Walk every command in a surface, deepest-last, with its invocation path.
106
+ *
107
+ * @param commands - The command tree to walk.
108
+ * @returns Each command paired with the argv path that reaches it.
109
+ */
110
+ export function* walkCommands(commands, prefix = []) {
111
+ for (const command of commands) {
112
+ const path = [...prefix, command.name];
113
+ yield { path, command };
114
+ if (command.subcommands)
115
+ yield* walkCommands(command.subcommands, path);
116
+ }
117
+ }
118
+ //# sourceMappingURL=conformance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformance.js","sourceRoot":"","sources":["../src/conformance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from './types.js';
2
+ export * from './conformance.js';
3
+ export * from './compose.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './types.js';
2
+ export * from './conformance.js';
3
+ export * from './compose.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Contract between the `agent-relay` CLI and the Relay product CLIs it mounts
3
+ * (`relayfile`, `relayflows`, `relayhistory`).
4
+ *
5
+ * A product repo implements {@link RelayCliSurface} and the host CLI mounts it
6
+ * generically. Command implementations live in the product repo and are never
7
+ * copied into `agent-relay`.
8
+ *
9
+ * The surface is structurally typed on purpose: a product package can satisfy
10
+ * it while depending on this package only as a devDependency, so mounting adds
11
+ * no runtime dependency on Relay to the product.
12
+ */
13
+ /** Contract revision. Bumped only for a breaking change to these shapes. */
14
+ export type RelayCliContractVersion = 1;
15
+ /** Current contract revision. */
16
+ export declare const RELAY_CLI_CONTRACT_VERSION: RelayCliContractVersion;
17
+ /**
18
+ * Output sink supplied by the host. A surface writes here instead of touching
19
+ * `process.stdout` / `process.stderr` so the host can capture, prefix, or
20
+ * redirect product output.
21
+ *
22
+ * Chunks may be bytes as well as text. Some product commands stream binary to
23
+ * stdout — `relayfile export --format tar --output -` is the motivating case —
24
+ * and a string-only sink silently corrupts them, because the bytes round-trip
25
+ * through UTF-8 decoding. Passing a `Uint8Array` through untouched is the only
26
+ * way those commands survive being mounted.
27
+ *
28
+ * A product that only ever emits text can keep passing strings; nothing about
29
+ * the simple case changes.
30
+ */
31
+ export interface RelayCliIo {
32
+ stdout(chunk: string | Uint8Array): void;
33
+ stderr(chunk: string | Uint8Array): void;
34
+ }
35
+ /** A positional argument in a product command. */
36
+ export interface RelayCliArgSpec {
37
+ name: string;
38
+ description: string;
39
+ required: boolean;
40
+ variadic?: boolean;
41
+ }
42
+ /** A flag in a product command. */
43
+ export interface RelayCliOptionSpec {
44
+ /** Commander-style flag string, e.g. `--json` or `-w, --workspace <id>`. */
45
+ flags: string;
46
+ description: string;
47
+ defaultValue?: string | boolean | number;
48
+ }
49
+ /** Marks a command as deprecated in favour of another. */
50
+ export interface RelayCliDeprecation {
51
+ /** The command a caller should use instead, e.g. `agent-relay flows run`. */
52
+ replacement: string;
53
+ /** Version the deprecation started, when known. */
54
+ since?: string;
55
+ }
56
+ /** One node in a product command tree. */
57
+ export interface RelayCliCommandSpec {
58
+ name: string;
59
+ description: string;
60
+ aliases?: readonly string[];
61
+ args?: readonly RelayCliArgSpec[];
62
+ options?: readonly RelayCliOptionSpec[];
63
+ subcommands?: readonly RelayCliCommandSpec[];
64
+ /** When present the host prints a deprecation notice naming the replacement. */
65
+ deprecated?: RelayCliDeprecation;
66
+ /** Runnable, but omitted from `--help`. */
67
+ hidden?: boolean;
68
+ }
69
+ /**
70
+ * A mountable product CLI.
71
+ *
72
+ * Implementations must satisfy the following, which the host relies on and the
73
+ * conformance helpers in this package check:
74
+ *
75
+ * - `run` resolves to a process exit code; it never calls `process.exit`.
76
+ * - `run` writes only through the supplied {@link RelayCliIo}.
77
+ * - `run` installs no global signal handlers.
78
+ * - `commands` describes the same tree `run` dispatches (see
79
+ * `assertSurfaceSpecMatchesRouting` in each product repo's drift test).
80
+ * - An unknown command resolves to exit code {@link RELAY_CLI_EXIT_UNKNOWN_COMMAND}.
81
+ */
82
+ export interface RelayCliSurface {
83
+ /** Stable identifier, e.g. `relayfile`. */
84
+ id: string;
85
+ /** Version of the package providing this surface. */
86
+ version: string;
87
+ contract: RelayCliContractVersion;
88
+ /** Full command tree; drives help, completions, and deprecation notices. */
89
+ commands: readonly RelayCliCommandSpec[];
90
+ /**
91
+ * Execute one invocation.
92
+ *
93
+ * @param argv - Arguments after the mounted group name. `agent-relay flows run a.ts`
94
+ * arrives as `['run', 'a.ts']`.
95
+ * @param io - Host-supplied output sink.
96
+ * @returns The process exit code for this invocation.
97
+ */
98
+ run(argv: readonly string[], io: RelayCliIo): Promise<number>;
99
+ }
100
+ /** A surface module's default factory signature. */
101
+ export type RelayCliSurfaceFactory<Options = unknown> = (options?: Options) => RelayCliSurface;
102
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,4EAA4E;AAC5E,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAExC,iCAAiC;AACjC,eAAO,MAAM,0BAA0B,EAAE,uBAA2B,CAAC;AAErE;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IACzC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;CAC1C;AAED,kDAAkD;AAClD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,mCAAmC;AACnC,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;CAC1C;AAED,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,0CAA0C;AAC1C,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAClC,OAAO,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACxC,WAAW,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC7C,gFAAgF;IAChF,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,2CAA2C;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,eAAe;IAC9B,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,uBAAuB,CAAC;IAClC,4EAA4E;IAC5E,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACzC;;;;;;;OAOG;IACH,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/D;AAED,oDAAoD;AACpD,MAAM,MAAM,sBAAsB,CAAC,OAAO,GAAG,OAAO,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,eAAe,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Contract between the `agent-relay` CLI and the Relay product CLIs it mounts
3
+ * (`relayfile`, `relayflows`, `relayhistory`).
4
+ *
5
+ * A product repo implements {@link RelayCliSurface} and the host CLI mounts it
6
+ * generically. Command implementations live in the product repo and are never
7
+ * copied into `agent-relay`.
8
+ *
9
+ * The surface is structurally typed on purpose: a product package can satisfy
10
+ * it while depending on this package only as a devDependency, so mounting adds
11
+ * no runtime dependency on Relay to the product.
12
+ */
13
+ /** Current contract revision. */
14
+ export const RELAY_CLI_CONTRACT_VERSION = 1;
15
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,iCAAiC;AACjC,MAAM,CAAC,MAAM,0BAA0B,GAA4B,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/cli-surface",
3
- "version": "12.2.2",
3
+ "version": "12.2.4",
4
4
  "engines": {
5
5
  "node": ">=22.0.0"
6
6
  },
@@ -21,6 +21,7 @@
21
21
  "scripts": {
22
22
  "build": "tsc",
23
23
  "clean": "rm -rf dist",
24
+ "prepack": "npm run build",
24
25
  "test": "vitest run --passWithNoTests",
25
26
  "test:watch": "vitest"
26
27
  },