@alpacakit/agents-conventions 0.1.0-beta.36 → 0.1.0-beta.39

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 CHANGED
@@ -1,12 +1,132 @@
1
1
  # @alpacakit/agents-conventions
2
2
 
3
- AlpacaLoop-family conventions for [`@alpacakit/agents`](../agents) machine-local
4
- config: the `ALPACA_AGENTS_HOME` / `~/.alpaca/agents` config root, the
5
- `alpacaloop.agents-home` keyring service, and the managed-home layout shared
6
- by AlpacaLoop-family products (the CLI, promptopt, codehint).
7
-
8
- This package is published with the other `@alpacakit/*` libraries. It is a
9
- plain consumer of the neutral `@alpacakit/agents` public API — the same shape
10
- any third party would write for their own convention. The general library
11
- ships a convention-neutral `@alpacakit/agents/config/xdg` preset; this package
12
- provides the AlpacaLoop-specific instance.
3
+ The AlpacaKit family's **shared agents home**: where it lives, how an agent is
4
+ registered into it, and the `agent` command every family product mounts.
5
+
6
+ This lives outside the neutral [`@alpacakit/agents`](../agents) package on
7
+ purpose. It encodes the family's `ALPACA_AGENTS_HOME` / `~/.alpaca/agents`
8
+ config root, the `alpaca.agents` keychain service, the managed-home layout, and
9
+ — the part that matters most — the **order and failure policy** of registering
10
+ a credential. It is a plain consumer of the agents package's public API: the
11
+ same shape any third party would write for their own convention. The general
12
+ library ships a convention-neutral `@alpacakit/agents/config/xdg` preset; this
13
+ package is the AlpacaKit-specific instance.
14
+
15
+ ## Procedures
16
+
17
+ Every procedure takes `{ homeDir, env }` and opens the same shared home.
18
+ `ports` and `keyring` are injectable so tests drive the real path without a
19
+ subprocess or a real keychain. Expected outcomes come back as a result type
20
+ with a `kind`; only faults throw.
21
+
22
+ | Procedure | Result kinds |
23
+ |---|---|
24
+ | `listAgentsHome` | `{ agentsHome, entries }` — every candidate with its readiness |
25
+ | `loginManagedHome` | `registered` / `profile_exists` / `unknown_agent` / `unsupported` / `login_failed` |
26
+ | `addApiKeyProfile` | `registered` / `profile_exists` / `empty_key` |
27
+ | `addAgentConfig` | `added` / `exists` |
28
+ | `removeAgentsHomeEntry` | `removed_profile` / `removed_agent_config` / `not_found` |
29
+
30
+ Every procedure that takes a record name can also answer `invalid_name`
31
+ (carrying the `rule` in words, so a product need not restate the grammar).
32
+
33
+ The policies these procedures own, so no product re-decides them:
34
+
35
+ - **`listAgentsHome`** probes a profile-backed candidate with that profile's
36
+ environment applied — the same `auth.toEnv` patch a run gets — so it can
37
+ never report the ambient login for a profile that has its own credential. An
38
+ agent that declares no availability probe reports `null`, not a guess.
39
+ - **`loginManagedHome`** writes no profile when the sign-in fails, but keeps
40
+ the managed home so a retry resumes from it. A sign-in that succeeds and then
41
+ cannot be recorded is a **fault**, not a result: discarding a completed
42
+ browser flow would leave a live credential nobody knows about. An id this
43
+ home does not have (`unknown_agent`) is kept apart from a method the agent
44
+ does not offer (`unsupported`) — the two have different fixes.
45
+ - **`addApiKeyProfile`** rejects a blank key (`empty_key`) before touching the
46
+ keychain, stores the key trimmed so a piped newline never reaches the
47
+ provider, then references it — and removes the stored key again if the
48
+ reference cannot be written.
49
+ - **`addAgentConfig`** dispatches on `input.kind`, the same discriminator
50
+ `agent add --kind` carries, so the CLI projection is the input verbatim.
51
+ - **Record names** (profile ids, agent config ids) match
52
+ `^[a-z0-9][a-z0-9._-]{0,63}$`. A name is not free text: it becomes a path
53
+ segment under `managed-homes/` and a segment of a keychain account, so an
54
+ unconstrained one would decide where this package writes and what it deletes.
55
+ `/cli` rejects it at the codec and the procedures repeat the check for
56
+ callers that skip the CLI; `resolveManagedHomePath` throws rather than build
57
+ a path outside the shared home.
58
+ - **`removeAgentsHomeEntry`** removes the record first, then only the artifacts
59
+ this package created. A home the operator pointed at themselves, and a secret
60
+ behind someone else's resolver, are left alone.
61
+
62
+ ```ts
63
+ import { loginManagedHome } from "@alpacakit/agents-conventions";
64
+
65
+ const result = await loginManagedHome({
66
+ homeDir: os.homedir(),
67
+ env: process.env,
68
+ profileId: "judge-codex",
69
+ agentId: "codex",
70
+ method: "oauth",
71
+ onEvent: (event) => render(event),
72
+ });
73
+ ```
74
+
75
+ ## `@alpacakit/agents-conventions/cli`
76
+
77
+ The shared `agent` Endpoint tree — no `bin`, parser, output writer, or startup
78
+ I/O. It owns the command paths, flags, procedure-input projection, and five
79
+ thin procedure handlers, so `alpacaloop agent login` and
80
+ `promptopt agent login` execute the same operation. Collecting the tree and
81
+ rendering help do not open the agents home, keyring, login process, or stdin.
82
+
83
+ ```
84
+ agent list
85
+ agent login <PROFILE> --agent <claude|codex> [--method oauth|device]
86
+ agent credential add <PROFILE> --agent <ID> --stdin (--stdin is required)
87
+ agent add <ID> --kind openai-compatible --base-url <URL> --model <M>
88
+ [--api-key-env <VAR>] [--engine fetch|pi]
89
+ agent remove <NAME>
90
+ ```
91
+
92
+ Mount the node in the product's tree. The host parser passes only explicitly
93
+ supplied canonical parameter names to `parseOptions`; after it succeeds, the
94
+ host supplies an invocation-scoped `AgentEntryContext` and calls the collected
95
+ handler directly:
96
+
97
+ ```ts
98
+ import {
99
+ AGENT_CLI_SURFACE,
100
+ type AgentEntryContext,
101
+ } from "@alpacakit/agents-conventions/cli";
102
+ import { collectCliCommands } from "@alpacakit/channels/cli";
103
+
104
+ const view = collectCliCommands(AGENT_CLI_SURFACE.node);
105
+ // During host action registration, for each collected command:
106
+ const input = command.input.parseOptions(explicitCanonicalValues);
107
+ const outcome = await command.handler(input, context satisfies AgentEntryContext);
108
+ render(outcome); // text, JSON envelope, redaction, and exit status are host-owned
109
+ ```
110
+
111
+ `AgentEntryContext` contains `{ homeDir, env, ports?, keyring?,
112
+ readCredentialSecret, onLoginEvent, signal? }`. `onLoginEvent` receives the
113
+ typed `LoginEvent`; the host decides how to display it. `--stdin` identifies
114
+ the input source: only the credential-add handler calls
115
+ `readCredentialSecret()`, once, after input validation succeeds.
116
+
117
+ Each handler returns `AgentEntryOutcome`, discriminated by the corresponding
118
+ `AGENT_ENTRY_NAME` in `operation`, with the unchanged procedure result in
119
+ `result`. This is not a CLI text/JSON envelope and carries no exit or
120
+ presentation policy. Optional flags stay absent when unset — `--engine` is
121
+ defaulted once by the persisted agent-config payload. The addable kinds
122
+ (`AGENT_ADD_KIND`) remain on the root export beside the procedure that acts on
123
+ them; `/cli` only spells them as a flag.
124
+
125
+ `AGENT_CLI_SURFACE.outputs.<operation>.schema` remains the explicit validator
126
+ for the inner procedure result used by existing projectors. It intentionally
127
+ does not validate the tagged `AgentEntryOutcome` wrapper; presentation code
128
+ selects the operation and validates `outcome.result` when required.
129
+
130
+ `@alpacakit/channels` and `zod` are **peer** dependencies of this package: they
131
+ are needed only by `/cli`, so importing the procedures never drags a CLI
132
+ framework in.
@@ -0,0 +1,209 @@
1
+ /**
2
+ * The JSON shape of every `agent` command result. These are the CONTRACT, not
3
+ * a convenience: an app may render the result any way it likes, but what it
4
+ * emits as data is fixed here so `alpacaloop agent list --json` and
5
+ * `promptopt agent list --json` are the same document.
6
+ */
7
+ import { z } from "zod";
8
+ export declare const profileSchema: z.ZodObject<{
9
+ id: z.ZodString;
10
+ agentId: z.ZodString;
11
+ material: z.ZodDiscriminatedUnion<[z.ZodObject<{
12
+ kind: z.ZodLiteral<"home-dir">;
13
+ path: z.ZodString;
14
+ }, z.core.$strict>, z.ZodObject<{
15
+ kind: z.ZodLiteral<"api-key">;
16
+ secret: z.ZodObject<{
17
+ resolver: z.ZodString;
18
+ id: z.ZodString;
19
+ }, z.core.$strict>;
20
+ }, z.core.$strict>], "kind">;
21
+ }, z.core.$strict>;
22
+ export declare const agentConfigSchema: z.ZodObject<{
23
+ id: z.ZodString;
24
+ kind: z.ZodString;
25
+ enabled: z.ZodBoolean;
26
+ payload: z.ZodRecord<z.ZodString, z.ZodType<import("@alpacakit/agents").JsonValue, unknown, z.core.$ZodTypeInternals<import("@alpacakit/agents").JsonValue, unknown>>>;
27
+ }, z.core.$strict>;
28
+ /** `null` when the agent declares no availability probe at all. */
29
+ export declare const availabilitySchema: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
30
+ status: z.ZodLiteral<"runnable">;
31
+ }, z.core.$strict>, z.ZodObject<{
32
+ status: z.ZodLiteral<"unavailable">;
33
+ reason: z.ZodEnum<{
34
+ command_missing: "command_missing";
35
+ authentication_required: "authentication_required";
36
+ }>;
37
+ remediation: z.ZodNullable<z.ZodObject<{
38
+ detail: z.ZodString;
39
+ command: z.ZodNullable<z.ZodObject<{
40
+ executable: z.ZodString;
41
+ args: z.ZodArray<z.ZodString>;
42
+ }, z.core.$strict>>;
43
+ }, z.core.$strict>>;
44
+ }, z.core.$strict>, z.ZodObject<{
45
+ status: z.ZodLiteral<"indeterminate">;
46
+ reason: z.ZodEnum<{
47
+ probe_timeout: "probe_timeout";
48
+ probe_fault: "probe_fault";
49
+ }>;
50
+ detail: z.ZodString;
51
+ }, z.core.$strict>], "status">>;
52
+ export declare const agentListOutputSchema: z.ZodObject<{
53
+ agentsHome: z.ZodString;
54
+ entries: z.ZodArray<z.ZodObject<{
55
+ agentId: z.ZodString;
56
+ agentConfigId: z.ZodString;
57
+ kind: z.ZodString;
58
+ source: z.ZodEnum<{
59
+ profile: "profile";
60
+ ambient: "ambient";
61
+ configured: "configured";
62
+ }>;
63
+ profileId: z.ZodNullable<z.ZodString>;
64
+ availability: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
65
+ status: z.ZodLiteral<"runnable">;
66
+ }, z.core.$strict>, z.ZodObject<{
67
+ status: z.ZodLiteral<"unavailable">;
68
+ reason: z.ZodEnum<{
69
+ command_missing: "command_missing";
70
+ authentication_required: "authentication_required";
71
+ }>;
72
+ remediation: z.ZodNullable<z.ZodObject<{
73
+ detail: z.ZodString;
74
+ command: z.ZodNullable<z.ZodObject<{
75
+ executable: z.ZodString;
76
+ args: z.ZodArray<z.ZodString>;
77
+ }, z.core.$strict>>;
78
+ }, z.core.$strict>>;
79
+ }, z.core.$strict>, z.ZodObject<{
80
+ status: z.ZodLiteral<"indeterminate">;
81
+ reason: z.ZodEnum<{
82
+ probe_timeout: "probe_timeout";
83
+ probe_fault: "probe_fault";
84
+ }>;
85
+ detail: z.ZodString;
86
+ }, z.core.$strict>], "status">>;
87
+ }, z.core.$strict>>;
88
+ }, z.core.$strict>;
89
+ export declare const agentLoginOutputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
90
+ kind: z.ZodLiteral<"registered">;
91
+ profile: z.ZodObject<{
92
+ id: z.ZodString;
93
+ agentId: z.ZodString;
94
+ material: z.ZodDiscriminatedUnion<[z.ZodObject<{
95
+ kind: z.ZodLiteral<"home-dir">;
96
+ path: z.ZodString;
97
+ }, z.core.$strict>, z.ZodObject<{
98
+ kind: z.ZodLiteral<"api-key">;
99
+ secret: z.ZodObject<{
100
+ resolver: z.ZodString;
101
+ id: z.ZodString;
102
+ }, z.core.$strict>;
103
+ }, z.core.$strict>], "kind">;
104
+ }, z.core.$strict>;
105
+ managedHome: z.ZodString;
106
+ }, z.core.$strict>, z.ZodObject<{
107
+ kind: z.ZodLiteral<"profile_exists">;
108
+ profileId: z.ZodString;
109
+ }, z.core.$strict>, z.ZodObject<{
110
+ kind: z.ZodLiteral<"unknown_agent">;
111
+ agentId: z.ZodString;
112
+ known: z.ZodArray<z.ZodString>;
113
+ }, z.core.$strict>, z.ZodObject<{
114
+ kind: z.ZodLiteral<"unsupported">;
115
+ agentId: z.ZodString;
116
+ method: z.ZodString;
117
+ supported: z.ZodArray<z.ZodString>;
118
+ }, z.core.$strict>, z.ZodObject<{
119
+ kind: z.ZodLiteral<"login_failed">;
120
+ detail: z.ZodString;
121
+ managedHome: z.ZodString;
122
+ }, z.core.$strict>, z.ZodObject<{
123
+ kind: z.ZodLiteral<"invalid_name">;
124
+ name: z.ZodString;
125
+ rule: z.ZodString;
126
+ }, z.core.$strict>], "kind">;
127
+ export declare const agentCredentialAddOutputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
128
+ kind: z.ZodLiteral<"registered">;
129
+ profile: z.ZodObject<{
130
+ id: z.ZodString;
131
+ agentId: z.ZodString;
132
+ material: z.ZodDiscriminatedUnion<[z.ZodObject<{
133
+ kind: z.ZodLiteral<"home-dir">;
134
+ path: z.ZodString;
135
+ }, z.core.$strict>, z.ZodObject<{
136
+ kind: z.ZodLiteral<"api-key">;
137
+ secret: z.ZodObject<{
138
+ resolver: z.ZodString;
139
+ id: z.ZodString;
140
+ }, z.core.$strict>;
141
+ }, z.core.$strict>], "kind">;
142
+ }, z.core.$strict>;
143
+ }, z.core.$strict>, z.ZodObject<{
144
+ kind: z.ZodLiteral<"profile_exists">;
145
+ profileId: z.ZodString;
146
+ }, z.core.$strict>, z.ZodObject<{
147
+ kind: z.ZodLiteral<"empty_key">;
148
+ profileId: z.ZodString;
149
+ }, z.core.$strict>, z.ZodObject<{
150
+ kind: z.ZodLiteral<"invalid_name">;
151
+ name: z.ZodString;
152
+ rule: z.ZodString;
153
+ }, z.core.$strict>], "kind">;
154
+ export declare const agentAddOutputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
155
+ kind: z.ZodLiteral<"added">;
156
+ agentConfig: z.ZodObject<{
157
+ id: z.ZodString;
158
+ kind: z.ZodString;
159
+ enabled: z.ZodBoolean;
160
+ payload: z.ZodRecord<z.ZodString, z.ZodType<import("@alpacakit/agents").JsonValue, unknown, z.core.$ZodTypeInternals<import("@alpacakit/agents").JsonValue, unknown>>>;
161
+ }, z.core.$strict>;
162
+ }, z.core.$strict>, z.ZodObject<{
163
+ kind: z.ZodLiteral<"exists">;
164
+ id: z.ZodString;
165
+ }, z.core.$strict>, z.ZodObject<{
166
+ kind: z.ZodLiteral<"invalid_name">;
167
+ name: z.ZodString;
168
+ rule: z.ZodString;
169
+ }, z.core.$strict>], "kind">;
170
+ export declare const agentRemoveOutputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
171
+ kind: z.ZodLiteral<"removed_profile">;
172
+ profile: z.ZodObject<{
173
+ id: z.ZodString;
174
+ agentId: z.ZodString;
175
+ material: z.ZodDiscriminatedUnion<[z.ZodObject<{
176
+ kind: z.ZodLiteral<"home-dir">;
177
+ path: z.ZodString;
178
+ }, z.core.$strict>, z.ZodObject<{
179
+ kind: z.ZodLiteral<"api-key">;
180
+ secret: z.ZodObject<{
181
+ resolver: z.ZodString;
182
+ id: z.ZodString;
183
+ }, z.core.$strict>;
184
+ }, z.core.$strict>], "kind">;
185
+ }, z.core.$strict>;
186
+ removedManagedHome: z.ZodNullable<z.ZodString>;
187
+ removedSecret: z.ZodBoolean;
188
+ }, z.core.$strict>, z.ZodObject<{
189
+ kind: z.ZodLiteral<"removed_agent_config">;
190
+ agentConfig: z.ZodObject<{
191
+ id: z.ZodString;
192
+ kind: z.ZodString;
193
+ enabled: z.ZodBoolean;
194
+ payload: z.ZodRecord<z.ZodString, z.ZodType<import("@alpacakit/agents").JsonValue, unknown, z.core.$ZodTypeInternals<import("@alpacakit/agents").JsonValue, unknown>>>;
195
+ }, z.core.$strict>;
196
+ }, z.core.$strict>, z.ZodObject<{
197
+ kind: z.ZodLiteral<"not_found">;
198
+ name: z.ZodString;
199
+ }, z.core.$strict>, z.ZodObject<{
200
+ kind: z.ZodLiteral<"invalid_name">;
201
+ name: z.ZodString;
202
+ rule: z.ZodString;
203
+ }, z.core.$strict>], "kind">;
204
+ export type AgentListOutput = z.infer<typeof agentListOutputSchema>;
205
+ export type AgentLoginOutput = z.infer<typeof agentLoginOutputSchema>;
206
+ export type AgentCredentialAddOutput = z.infer<typeof agentCredentialAddOutputSchema>;
207
+ export type AgentAddOutput = z.infer<typeof agentAddOutputSchema>;
208
+ export type AgentRemoveOutput = z.infer<typeof agentRemoveOutputSchema>;
209
+ //# sourceMappingURL=cli-output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-output.d.ts","sourceRoot":"","sources":["../src/cli-output.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA+BxB,eAAO,MAAM,aAAa;;;;;;;;;;;;;kBAMf,CAAC;AAEZ,eAAO,MAAM,iBAAiB;;;;;kBAOnB,CAAC;AAYZ,mEAAmE;AACnE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;+BA0BlB,CAAC;AAWd,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAoBvB,CAAC;AAEZ,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAwClC,CAAC;AAEF,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;4BAuB1C,CAAC;AAEF,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;4BAc/B,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAyBnC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAC5C,OAAO,8BAA8B,CACtC,CAAC;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
@@ -0,0 +1,208 @@
1
+ /**
2
+ * The JSON shape of every `agent` command result. These are the CONTRACT, not
3
+ * a convenience: an app may render the result any way it likes, but what it
4
+ * emits as data is fixed here so `alpacaloop agent list --json` and
5
+ * `promptopt agent list --json` are the same document.
6
+ */
7
+ import { AGENT_AVAILABILITY_STATUS, AGENT_INDETERMINATE_REASON, AGENT_UNAVAILABLE_REASON, AUTH_MATERIAL_KIND, } from "@alpacakit/agents";
8
+ import { CANDIDATE_SOURCE_KIND } from "@alpacakit/agents/config";
9
+ import { jsonValueSchema } from "@alpacakit/core";
10
+ import { z } from "zod";
11
+ import { INVALID_NAME_RESULT_KIND } from "./names.js";
12
+ import { ADD_AGENT_CONFIG_RESULT, ADD_API_KEY_PROFILE_RESULT, LOGIN_MANAGED_HOME_RESULT, } from "./register.js";
13
+ import { REMOVE_AGENTS_HOME_ENTRY_RESULT } from "./remove.js";
14
+ const RESULT_DISCRIMINATOR = "kind";
15
+ const AVAILABILITY_DISCRIMINATOR = "status";
16
+ const secretRefSchema = z
17
+ .object({ resolver: z.string(), id: z.string() })
18
+ .strict();
19
+ const authMaterialSchema = z.discriminatedUnion(RESULT_DISCRIMINATOR, [
20
+ z
21
+ .object({
22
+ kind: z.literal(AUTH_MATERIAL_KIND.homeDir),
23
+ path: z.string(),
24
+ })
25
+ .strict(),
26
+ z
27
+ .object({
28
+ kind: z.literal(AUTH_MATERIAL_KIND.apiKey),
29
+ secret: secretRefSchema,
30
+ })
31
+ .strict(),
32
+ ]);
33
+ export const profileSchema = z
34
+ .object({
35
+ id: z.string(),
36
+ agentId: z.string(),
37
+ material: authMaterialSchema,
38
+ })
39
+ .strict();
40
+ export const agentConfigSchema = z
41
+ .object({
42
+ id: z.string(),
43
+ kind: z.string(),
44
+ enabled: z.boolean(),
45
+ payload: z.record(z.string(), jsonValueSchema),
46
+ })
47
+ .strict();
48
+ const remediationSchema = z
49
+ .object({
50
+ detail: z.string(),
51
+ command: z
52
+ .object({ executable: z.string(), args: z.array(z.string()) })
53
+ .strict()
54
+ .nullable(),
55
+ })
56
+ .strict();
57
+ /** `null` when the agent declares no availability probe at all. */
58
+ export const availabilitySchema = z
59
+ .discriminatedUnion(AVAILABILITY_DISCRIMINATOR, [
60
+ z
61
+ .object({ status: z.literal(AGENT_AVAILABILITY_STATUS.runnable) })
62
+ .strict(),
63
+ z
64
+ .object({
65
+ status: z.literal(AGENT_AVAILABILITY_STATUS.unavailable),
66
+ reason: z.enum([
67
+ AGENT_UNAVAILABLE_REASON.commandMissing,
68
+ AGENT_UNAVAILABLE_REASON.authenticationRequired,
69
+ ]),
70
+ remediation: remediationSchema.nullable(),
71
+ })
72
+ .strict(),
73
+ z
74
+ .object({
75
+ status: z.literal(AGENT_AVAILABILITY_STATUS.indeterminate),
76
+ reason: z.enum([
77
+ AGENT_INDETERMINATE_REASON.probeTimeout,
78
+ AGENT_INDETERMINATE_REASON.probeFault,
79
+ ]),
80
+ detail: z.string(),
81
+ })
82
+ .strict(),
83
+ ])
84
+ .nullable();
85
+ /** The rejection every name-taking command shares (`InvalidNameResult`). */
86
+ const invalidNameSchema = z
87
+ .object({
88
+ kind: z.literal(INVALID_NAME_RESULT_KIND),
89
+ name: z.string(),
90
+ rule: z.string(),
91
+ })
92
+ .strict();
93
+ export const agentListOutputSchema = z
94
+ .object({
95
+ agentsHome: z.string(),
96
+ entries: z.array(z
97
+ .object({
98
+ agentId: z.string(),
99
+ agentConfigId: z.string(),
100
+ kind: z.string(),
101
+ source: z.enum([
102
+ CANDIDATE_SOURCE_KIND.profile,
103
+ CANDIDATE_SOURCE_KIND.ambient,
104
+ CANDIDATE_SOURCE_KIND.configured,
105
+ ]),
106
+ profileId: z.string().nullable(),
107
+ availability: availabilitySchema,
108
+ })
109
+ .strict()),
110
+ })
111
+ .strict();
112
+ export const agentLoginOutputSchema = z.discriminatedUnion(RESULT_DISCRIMINATOR, [
113
+ z
114
+ .object({
115
+ kind: z.literal(LOGIN_MANAGED_HOME_RESULT.registered),
116
+ profile: profileSchema,
117
+ managedHome: z.string(),
118
+ })
119
+ .strict(),
120
+ z
121
+ .object({
122
+ kind: z.literal(LOGIN_MANAGED_HOME_RESULT.profileExists),
123
+ profileId: z.string(),
124
+ })
125
+ .strict(),
126
+ z
127
+ .object({
128
+ kind: z.literal(LOGIN_MANAGED_HOME_RESULT.unknownAgent),
129
+ agentId: z.string(),
130
+ known: z.array(z.string()),
131
+ })
132
+ .strict(),
133
+ z
134
+ .object({
135
+ kind: z.literal(LOGIN_MANAGED_HOME_RESULT.unsupported),
136
+ agentId: z.string(),
137
+ method: z.string(),
138
+ supported: z.array(z.string()),
139
+ })
140
+ .strict(),
141
+ z
142
+ .object({
143
+ kind: z.literal(LOGIN_MANAGED_HOME_RESULT.loginFailed),
144
+ detail: z.string(),
145
+ managedHome: z.string(),
146
+ })
147
+ .strict(),
148
+ invalidNameSchema,
149
+ ]);
150
+ export const agentCredentialAddOutputSchema = z.discriminatedUnion(RESULT_DISCRIMINATOR, [
151
+ z
152
+ .object({
153
+ kind: z.literal(ADD_API_KEY_PROFILE_RESULT.registered),
154
+ profile: profileSchema,
155
+ })
156
+ .strict(),
157
+ z
158
+ .object({
159
+ kind: z.literal(ADD_API_KEY_PROFILE_RESULT.profileExists),
160
+ profileId: z.string(),
161
+ })
162
+ .strict(),
163
+ z
164
+ .object({
165
+ kind: z.literal(ADD_API_KEY_PROFILE_RESULT.emptyKey),
166
+ profileId: z.string(),
167
+ })
168
+ .strict(),
169
+ invalidNameSchema,
170
+ ]);
171
+ export const agentAddOutputSchema = z.discriminatedUnion(RESULT_DISCRIMINATOR, [
172
+ z
173
+ .object({
174
+ kind: z.literal(ADD_AGENT_CONFIG_RESULT.added),
175
+ agentConfig: agentConfigSchema,
176
+ })
177
+ .strict(),
178
+ z
179
+ .object({
180
+ kind: z.literal(ADD_AGENT_CONFIG_RESULT.exists),
181
+ id: z.string(),
182
+ })
183
+ .strict(),
184
+ invalidNameSchema,
185
+ ]);
186
+ export const agentRemoveOutputSchema = z.discriminatedUnion(RESULT_DISCRIMINATOR, [
187
+ z
188
+ .object({
189
+ kind: z.literal(REMOVE_AGENTS_HOME_ENTRY_RESULT.removedProfile),
190
+ profile: profileSchema,
191
+ removedManagedHome: z.string().nullable(),
192
+ removedSecret: z.boolean(),
193
+ })
194
+ .strict(),
195
+ z
196
+ .object({
197
+ kind: z.literal(REMOVE_AGENTS_HOME_ENTRY_RESULT.removedAgentConfig),
198
+ agentConfig: agentConfigSchema,
199
+ })
200
+ .strict(),
201
+ z
202
+ .object({
203
+ kind: z.literal(REMOVE_AGENTS_HOME_ENTRY_RESULT.notFound),
204
+ name: z.string(),
205
+ })
206
+ .strict(),
207
+ invalidNameSchema,
208
+ ]);