@cleocode/contracts 2026.6.13 → 2026.6.14

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.
Files changed (128) hide show
  1. package/dist/__tests__/operation-def.test.js +4 -1
  2. package/dist/__tests__/operation-def.test.js.map +1 -1
  3. package/dist/__tests__/provider-def.test.d.ts +12 -0
  4. package/dist/__tests__/provider-def.test.d.ts.map +1 -0
  5. package/dist/__tests__/provider-def.test.js +84 -0
  6. package/dist/__tests__/provider-def.test.js.map +1 -0
  7. package/dist/__tests__/service-provider.test.d.ts +17 -0
  8. package/dist/__tests__/service-provider.test.d.ts.map +1 -0
  9. package/dist/__tests__/service-provider.test.js +108 -0
  10. package/dist/__tests__/service-provider.test.js.map +1 -0
  11. package/dist/boundary.d.ts +52 -0
  12. package/dist/boundary.d.ts.map +1 -1
  13. package/dist/boundary.js +23 -0
  14. package/dist/boundary.js.map +1 -1
  15. package/dist/conduit.d.ts +171 -0
  16. package/dist/conduit.d.ts.map +1 -1
  17. package/dist/config/index.d.ts +23 -0
  18. package/dist/config/index.d.ts.map +1 -0
  19. package/dist/config/index.js +22 -0
  20. package/dist/config/index.js.map +1 -0
  21. package/dist/config.d.ts +2 -1
  22. package/dist/config.d.ts.map +1 -1
  23. package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.d.ts +21 -0
  24. package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.d.ts.map +1 -0
  25. package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.js +84 -0
  26. package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.js.map +1 -0
  27. package/dist/dispatch/identity.d.ts +1 -1
  28. package/dist/dispatch/identity.d.ts.map +1 -1
  29. package/dist/dispatch/identity.js +20 -0
  30. package/dist/dispatch/identity.js.map +1 -1
  31. package/dist/dispatch/operation-def.d.ts +20 -0
  32. package/dist/dispatch/operation-def.d.ts.map +1 -1
  33. package/dist/dispatch/operations-registry.d.ts.map +1 -1
  34. package/dist/dispatch/operations-registry.js +1030 -46
  35. package/dist/dispatch/operations-registry.js.map +1 -1
  36. package/dist/index.d.ts +15 -6
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +15 -2
  39. package/dist/index.js.map +1 -1
  40. package/dist/lease-ipc/__tests__/freeze.test.js +92 -0
  41. package/dist/lease-ipc/__tests__/freeze.test.js.map +1 -1
  42. package/dist/lease-ipc/index.d.ts +2 -2
  43. package/dist/lease-ipc/index.d.ts.map +1 -1
  44. package/dist/lease-ipc/index.js +1 -1
  45. package/dist/lease-ipc/index.js.map +1 -1
  46. package/dist/lease-ipc/messages.d.ts +167 -3
  47. package/dist/lease-ipc/messages.d.ts.map +1 -1
  48. package/dist/lease-ipc/messages.js +93 -0
  49. package/dist/lease-ipc/messages.js.map +1 -1
  50. package/dist/llm/catalog-schema.d.ts +242 -0
  51. package/dist/llm/catalog-schema.d.ts.map +1 -0
  52. package/dist/llm/catalog-schema.js +153 -0
  53. package/dist/llm/catalog-schema.js.map +1 -0
  54. package/dist/llm/catalog-schema.json +139 -0
  55. package/dist/llm/index.d.ts +15 -0
  56. package/dist/llm/index.d.ts.map +1 -0
  57. package/dist/llm/index.js +14 -0
  58. package/dist/llm/index.js.map +1 -0
  59. package/dist/llm/oauth.d.ts +16 -2
  60. package/dist/llm/oauth.d.ts.map +1 -1
  61. package/dist/llm/onboarding.d.ts +126 -0
  62. package/dist/llm/onboarding.d.ts.map +1 -0
  63. package/dist/llm/onboarding.js +34 -0
  64. package/dist/llm/onboarding.js.map +1 -0
  65. package/dist/llm/provider-def.d.ts +254 -0
  66. package/dist/llm/provider-def.d.ts.map +1 -0
  67. package/dist/llm/provider-def.js +93 -0
  68. package/dist/llm/provider-def.js.map +1 -0
  69. package/dist/llm/system-resolver.d.ts +42 -0
  70. package/dist/llm/system-resolver.d.ts.map +1 -1
  71. package/dist/operations/admin.d.ts +124 -1
  72. package/dist/operations/admin.d.ts.map +1 -1
  73. package/dist/operations/entities.d.ts +110 -0
  74. package/dist/operations/entities.d.ts.map +1 -0
  75. package/dist/operations/entities.js +695 -0
  76. package/dist/operations/entities.js.map +1 -0
  77. package/dist/operations/llm.d.ts +15 -0
  78. package/dist/operations/llm.d.ts.map +1 -1
  79. package/dist/operations/output-contracts-data.d.ts.map +1 -1
  80. package/dist/operations/output-contracts-data.js +230 -0
  81. package/dist/operations/output-contracts-data.js.map +1 -1
  82. package/dist/operations/service.d.ts +68 -0
  83. package/dist/operations/service.d.ts.map +1 -0
  84. package/dist/operations/service.js +336 -0
  85. package/dist/operations/service.js.map +1 -0
  86. package/dist/operations/tasks.d.ts +109 -0
  87. package/dist/operations/tasks.d.ts.map +1 -1
  88. package/dist/operations/tasks.js.map +1 -1
  89. package/dist/playbook.d.ts +56 -0
  90. package/dist/playbook.d.ts.map +1 -1
  91. package/dist/release/plan.d.ts +5 -5
  92. package/dist/vault/service-provider.d.ts +343 -0
  93. package/dist/vault/service-provider.d.ts.map +1 -0
  94. package/dist/vault/service-provider.js +857 -0
  95. package/dist/vault/service-provider.js.map +1 -0
  96. package/dist/workgraph.d.ts +12 -12
  97. package/package.json +10 -2
  98. package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
  99. package/src/__tests__/operation-def.test.ts +6 -1
  100. package/src/__tests__/provider-def.test.ts +93 -0
  101. package/src/__tests__/service-provider.test.ts +129 -0
  102. package/src/boundary.ts +69 -0
  103. package/src/conduit.ts +200 -0
  104. package/src/config/index.ts +35 -0
  105. package/src/config.ts +2 -1
  106. package/src/dispatch/__tests__/tasks-gateway-crud-ops.test.ts +99 -0
  107. package/src/dispatch/identity.ts +20 -0
  108. package/src/dispatch/operation-def.ts +21 -0
  109. package/src/dispatch/operations-registry.ts +1062 -36
  110. package/src/index.ts +137 -1
  111. package/src/lease-ipc/__tests__/freeze.test.ts +96 -0
  112. package/src/lease-ipc/index.ts +12 -0
  113. package/src/lease-ipc/messages.ts +117 -0
  114. package/src/llm/catalog-schema.json +139 -0
  115. package/src/llm/catalog-schema.ts +184 -0
  116. package/src/llm/index.ts +29 -0
  117. package/src/llm/oauth.ts +16 -2
  118. package/src/llm/onboarding.ts +131 -0
  119. package/src/llm/provider-def.ts +291 -0
  120. package/src/llm/system-resolver.ts +45 -0
  121. package/src/operations/admin.ts +144 -0
  122. package/src/operations/entities.ts +758 -0
  123. package/src/operations/llm.ts +15 -0
  124. package/src/operations/output-contracts-data.ts +264 -0
  125. package/src/operations/service.ts +360 -0
  126. package/src/operations/tasks.ts +119 -0
  127. package/src/playbook.ts +56 -0
  128. package/src/vault/service-provider.ts +1137 -0
@@ -0,0 +1,139 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://cleocode.dev/schemas/llm/curated-catalog.json",
4
+ "title": "Curated Models Catalog",
5
+ "description": "The shipped, offline-first provider+model catalog seed (E8 · T11731). One self-contained snapshot of the models.dev wire shape that seeds the global `models_catalog` table and backs offline/degraded reads. NO network access is implied by this file — it is the build-time committed mirror.",
6
+ "type": "object",
7
+ "required": ["version", "lastUpdated", "providers", "models"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "$schema": { "type": "string" },
11
+ "version": {
12
+ "type": "string",
13
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
14
+ "description": "Semver version of this catalog snapshot. Bumped on every regeneration; drives the seeder skip/re-seed decision."
15
+ },
16
+ "lastUpdated": {
17
+ "type": "string",
18
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
19
+ "description": "ISO date (YYYY-MM-DD) the snapshot was generated."
20
+ },
21
+ "providers": {
22
+ "type": "object",
23
+ "description": "Provider records keyed by models.dev provider id (e.g. `anthropic`, `openai`, `google`).",
24
+ "additionalProperties": {
25
+ "type": "object",
26
+ "required": ["id", "endpoint", "authTypes"],
27
+ "additionalProperties": false,
28
+ "properties": {
29
+ "id": { "type": "string", "description": "Provider id (matches the map key)." },
30
+ "endpoint": {
31
+ "type": "string",
32
+ "description": "Provider API base URL (e.g. `https://api.anthropic.com`)."
33
+ },
34
+ "authTypes": {
35
+ "type": "array",
36
+ "description": "Supported auth mechanisms keyed by provider id.",
37
+ "items": { "type": "string", "enum": ["api_key", "oauth", "bedrock", "vertex"] },
38
+ "minItems": 1
39
+ },
40
+ "npm": {
41
+ "type": "string",
42
+ "description": "Provider SDK npm package, when applicable (e.g. `@anthropic-ai/sdk`)."
43
+ }
44
+ }
45
+ }
46
+ },
47
+ "models": {
48
+ "type": "object",
49
+ "description": "Model entries keyed by provider id; each value is a map of model-id → model entry.",
50
+ "additionalProperties": {
51
+ "type": "object",
52
+ "additionalProperties": {
53
+ "$ref": "#/$defs/modelEntry"
54
+ }
55
+ }
56
+ }
57
+ },
58
+ "$defs": {
59
+ "modelEntry": {
60
+ "type": "object",
61
+ "description": "Full models.dev wire capability set for a single model.",
62
+ "required": [
63
+ "id",
64
+ "name",
65
+ "family",
66
+ "attachment",
67
+ "reasoning",
68
+ "temperature",
69
+ "interleaved",
70
+ "tool_call",
71
+ "modalities",
72
+ "cost",
73
+ "limit",
74
+ "status",
75
+ "release_date",
76
+ "provider"
77
+ ],
78
+ "additionalProperties": false,
79
+ "properties": {
80
+ "id": { "type": "string", "description": "Model identifier (e.g. `claude-haiku-4-5`)." },
81
+ "name": { "type": "string", "description": "Human-readable display name." },
82
+ "family": { "type": "string", "description": "Model family (e.g. `claude`, `gpt`, `gemini`)." },
83
+ "attachment": { "type": "boolean", "description": "Supports file/image attachments." },
84
+ "reasoning": { "type": "boolean", "description": "Supports extended reasoning / thinking." },
85
+ "temperature": { "type": "boolean", "description": "Honours a temperature parameter." },
86
+ "interleaved": { "type": "boolean", "description": "Supports interleaved thinking blocks." },
87
+ "tool_call": { "type": "boolean", "description": "Supports tool/function calling." },
88
+ "modalities": {
89
+ "type": "object",
90
+ "required": ["input", "output"],
91
+ "additionalProperties": false,
92
+ "properties": {
93
+ "input": { "type": "array", "items": { "type": "string" } },
94
+ "output": { "type": "array", "items": { "type": "string" } }
95
+ }
96
+ },
97
+ "cost": {
98
+ "type": "object",
99
+ "additionalProperties": false,
100
+ "properties": {
101
+ "input": { "type": "number" },
102
+ "output": { "type": "number" },
103
+ "cache_read": { "type": "number" },
104
+ "cache_write": { "type": "number" },
105
+ "context_over_200k": { "type": "number" }
106
+ }
107
+ },
108
+ "limit": {
109
+ "type": "object",
110
+ "required": ["context", "output"],
111
+ "additionalProperties": false,
112
+ "properties": {
113
+ "context": { "type": "number", "description": "Max context window (tokens)." },
114
+ "output": { "type": "number", "description": "Max output tokens." }
115
+ }
116
+ },
117
+ "status": {
118
+ "type": "string",
119
+ "enum": ["stable", "beta", "preview", "deprecated", "retired"],
120
+ "description": "Availability lifecycle of the model."
121
+ },
122
+ "release_date": {
123
+ "type": "string",
124
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
125
+ "description": "ISO release date (YYYY-MM-DD). The SSoT sort key — latest wins."
126
+ },
127
+ "provider": {
128
+ "type": "object",
129
+ "required": ["npm", "api"],
130
+ "additionalProperties": false,
131
+ "properties": {
132
+ "npm": { "type": "string" },
133
+ "api": { "type": "string" }
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Zod mirror + TypeScript types for the curated models catalog (E8 · T11731).
3
+ *
4
+ * This is the type+validation SSoT for the **shipped, offline-first** provider+model
5
+ * catalog seed that populates the global `models_catalog` table (T11733) and backs
6
+ * offline/degraded catalog reads (T11737). It mirrors the JSON Schema in the sibling
7
+ * `catalog-schema.json` (draft 2020-12) one-to-one.
8
+ *
9
+ * ## Offline-first — NO network is implied by these types
10
+ *
11
+ * The {@link CuratedCatalog} shape describes a committed, build-time snapshot of the
12
+ * models.dev wire shape. Nothing here fetches; the network refresh op
13
+ * (`cleo llm refresh-catalog`) is a SEPARATE leaf. The seeder reads the bundled
14
+ * `curated-catalog.json` (validated against {@link curatedCatalogSchema}) and upserts
15
+ * every row offline.
16
+ *
17
+ * ## models_catalog row parity (AC4)
18
+ *
19
+ * {@link modelsCatalogRowSelectSchema} / {@link modelsCatalogRowInsertSchema} describe the
20
+ * FLATTENED per-row shape persisted in the `models_catalog` DB table — the json/cost/
21
+ * modalities sub-objects serialize to TEXT columns, booleans to `integer({mode:'boolean'})`.
22
+ * {@link flattenCatalogToRows} (in core) maps a {@link CuratedCatalog} → these rows.
23
+ *
24
+ * Contracts-purity (Gate 10): this module exports ONLY zod schemas (values) and
25
+ * `z.infer` types — no bodied runtime helpers. The flatten/seed logic lives in core.
26
+ *
27
+ * @module llm/catalog-schema
28
+ * @task T11731
29
+ * @epic T11694 (E8-CATALOG-CURATION)
30
+ */
31
+
32
+ import { z } from 'zod';
33
+
34
+ /** Legal `models_catalog.status` availability-lifecycle values. */
35
+ export const CATALOG_MODEL_STATUSES = [
36
+ 'stable',
37
+ 'beta',
38
+ 'preview',
39
+ 'deprecated',
40
+ 'retired',
41
+ ] as const;
42
+
43
+ /** TypeScript union of {@link CATALOG_MODEL_STATUSES}. */
44
+ export type CatalogModelStatus = (typeof CATALOG_MODEL_STATUSES)[number];
45
+
46
+ /** Legal provider auth mechanisms carried in a catalog provider entry. */
47
+ export const CATALOG_AUTH_TYPES = ['api_key', 'oauth', 'bedrock', 'vertex'] as const;
48
+
49
+ /** TypeScript union of {@link CATALOG_AUTH_TYPES}. */
50
+ export type CatalogAuthType = (typeof CATALOG_AUTH_TYPES)[number];
51
+
52
+ /** ISO date `YYYY-MM-DD` matcher (the catalog sort/version key shape). */
53
+ const isoDate = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'must be an ISO date (YYYY-MM-DD)');
54
+
55
+ /** Semver `MAJOR.MINOR.PATCH` matcher for the catalog snapshot version. */
56
+ const semver = z.string().regex(/^\d+\.\d+\.\d+$/, 'must be semver (MAJOR.MINOR.PATCH)');
57
+
58
+ /** Input/output modality lists for a model. */
59
+ export const catalogModalitiesSchema = z
60
+ .object({
61
+ input: z.array(z.string()),
62
+ output: z.array(z.string()),
63
+ })
64
+ .strict();
65
+
66
+ /** Per-1M-token cost facets for a model (all optional — providers vary). */
67
+ export const catalogCostSchema = z
68
+ .object({
69
+ input: z.number().optional(),
70
+ output: z.number().optional(),
71
+ cache_read: z.number().optional(),
72
+ cache_write: z.number().optional(),
73
+ context_over_200k: z.number().optional(),
74
+ })
75
+ .strict();
76
+
77
+ /** Context/output token-window limits for a model. */
78
+ export const catalogLimitSchema = z
79
+ .object({
80
+ context: z.number(),
81
+ output: z.number(),
82
+ })
83
+ .strict();
84
+
85
+ /** The provider-of-record (npm package + api protocol) for a model. */
86
+ export const catalogModelProviderSchema = z
87
+ .object({
88
+ npm: z.string(),
89
+ api: z.string(),
90
+ })
91
+ .strict();
92
+
93
+ /** Full models.dev wire capability set for a single model entry. */
94
+ export const catalogModelEntrySchema = z
95
+ .object({
96
+ id: z.string(),
97
+ name: z.string(),
98
+ family: z.string(),
99
+ attachment: z.boolean(),
100
+ reasoning: z.boolean(),
101
+ temperature: z.boolean(),
102
+ interleaved: z.boolean(),
103
+ tool_call: z.boolean(),
104
+ modalities: catalogModalitiesSchema,
105
+ cost: catalogCostSchema,
106
+ limit: catalogLimitSchema,
107
+ status: z.enum(CATALOG_MODEL_STATUSES),
108
+ release_date: isoDate,
109
+ provider: catalogModelProviderSchema,
110
+ })
111
+ .strict();
112
+
113
+ /** A provider record in the catalog envelope. */
114
+ export const catalogProviderSchema = z
115
+ .object({
116
+ id: z.string(),
117
+ endpoint: z.string(),
118
+ authTypes: z.array(z.enum(CATALOG_AUTH_TYPES)).min(1),
119
+ npm: z.string().optional(),
120
+ })
121
+ .strict();
122
+
123
+ /**
124
+ * Top-level shape of the curated catalog seed (`curated-catalog.json`).
125
+ *
126
+ * `providers` is keyed by provider id; `models` is keyed by provider id → model id →
127
+ * {@link catalogModelEntrySchema}.
128
+ */
129
+ export const curatedCatalogSchema = z
130
+ .object({
131
+ $schema: z.string().optional(),
132
+ version: semver,
133
+ lastUpdated: isoDate,
134
+ providers: z.record(z.string(), catalogProviderSchema),
135
+ models: z.record(z.string(), z.record(z.string(), catalogModelEntrySchema)),
136
+ })
137
+ .strict();
138
+
139
+ /** The validated curated catalog seed shape. */
140
+ export type CuratedCatalog = z.infer<typeof curatedCatalogSchema>;
141
+ /** A single model entry from the curated catalog. */
142
+ export type CatalogModelEntry = z.infer<typeof catalogModelEntrySchema>;
143
+ /** A single provider entry from the curated catalog. */
144
+ export type CatalogProvider = z.infer<typeof catalogProviderSchema>;
145
+
146
+ /**
147
+ * INSERT/UPSERT shape for one `models_catalog` row (the flattened persistence form).
148
+ *
149
+ * The catalog's nested `modalities` / `cost` sub-objects are JSON-serialized into the
150
+ * `modalities` / `cost` TEXT columns; booleans persist as `integer({mode:'boolean'})`.
151
+ * `provider_id` is the catalog key; `models_dev_id` mirrors the entry `id`.
152
+ */
153
+ export const modelsCatalogRowInsertSchema = z
154
+ .object({
155
+ id: z.string(),
156
+ providerId: z.string(),
157
+ name: z.string(),
158
+ family: z.string(),
159
+ attachment: z.boolean(),
160
+ reasoning: z.boolean(),
161
+ temperature: z.boolean(),
162
+ interleaved: z.boolean(),
163
+ toolCall: z.boolean(),
164
+ modalities: z.string(),
165
+ cost: z.string(),
166
+ contextLimit: z.number().nullable().optional(),
167
+ outputLimit: z.number().nullable().optional(),
168
+ status: z.enum(CATALOG_MODEL_STATUSES),
169
+ releaseDate: isoDate,
170
+ modelsDevId: z.string(),
171
+ source: z.string(),
172
+ seededAt: z.string().optional(),
173
+ })
174
+ .strict();
175
+
176
+ /** SELECT shape for one `models_catalog` row (adds the always-present `seededAt`). */
177
+ export const modelsCatalogRowSelectSchema = modelsCatalogRowInsertSchema.extend({
178
+ seededAt: z.string(),
179
+ });
180
+
181
+ /** INSERT/UPSERT row type for `models_catalog`. */
182
+ export type ModelsCatalogRowInsert = z.infer<typeof modelsCatalogRowInsertSchema>;
183
+ /** SELECT row type for `models_catalog`. */
184
+ export type ModelsCatalogRowSelect = z.infer<typeof modelsCatalogRowSelectSchema>;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `@cleocode/contracts/llm` — LLM contract subpath barrel.
3
+ *
4
+ * Re-exports the declarative provider contracts so consumers can import from the
5
+ * `./llm` subpath (`@cleocode/contracts/llm`) in addition to the package root.
6
+ * Currently fronts the M3 Provider SSoT {@link ProviderDef} contract (T11702);
7
+ * other `llm/*` modules continue to export from the package root barrel.
8
+ *
9
+ * @module llm
10
+ * @task T11702
11
+ * @epic T11667
12
+ */
13
+
14
+ export type {
15
+ AiSdkEndpoint,
16
+ AnthropicMessagesEndpoint,
17
+ OAuthFlowDef,
18
+ OpenAICompletionsEndpoint,
19
+ OpenAIResponsesEndpoint,
20
+ ProviderDef,
21
+ ProviderEndpoint,
22
+ ProviderTransport,
23
+ RequestQuirk,
24
+ RequestQuirkKind,
25
+ } from './provider-def.js';
26
+ export {
27
+ PROVIDER_TRANSPORTS,
28
+ REQUEST_QUIRK_KINDS,
29
+ } from './provider-def.js';
package/src/llm/oauth.ts CHANGED
@@ -154,8 +154,22 @@ export interface ProviderOAuthConfig {
154
154
  * `code_challenge`/`code_challenge_method`/`state`).
155
155
  *
156
156
  * Used by OpenAI/Codex (`id_token_add_organizations=true`,
157
- * `codex_cli_simplified_flow=true`, `originator=codex_cli_rs`). Anthropic and
158
- * Kimi Code leave this unset.
157
+ * `codex_cli_simplified_flow=true`, `originator=codex_cli_rs`) and Anthropic
158
+ * (`code=true` — makes the hosted callback page display the authorization
159
+ * code for manual paste-back). Kimi Code leaves this unset.
159
160
  */
160
161
  extraAuthParams?: Readonly<Record<string, string>>;
162
+ /**
163
+ * Encoding of the token-endpoint request body (code exchange + refresh).
164
+ *
165
+ * - `'form'` (default) — RFC 6749 §4.1.3 `application/x-www-form-urlencoded`.
166
+ * Used by OpenAI/Codex and every spec-compliant authorization server.
167
+ * - `'json'` — non-standard `application/json` body. Anthropic's token
168
+ * endpoint (`platform.claude.com/v1/oauth/token`) expects JSON and
169
+ * additionally requires the authorize-time `state` echoed in the exchange
170
+ * body (the same wire shape pi-ai, OpenCode, and Claude Code use).
171
+ *
172
+ * @default 'form'
173
+ */
174
+ tokenBodyFormat?: 'form' | 'json';
161
175
  }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Onboarding login engine — typed result envelope (T11724 · M3).
3
+ *
4
+ * The 3-step onboarding login flow (`runOnboardingLogin` in `@cleocode/core`)
5
+ * walks a provider from a cold start to a usable, validated profile binding:
6
+ *
7
+ * 1. **connect** — resolve the provider (alias → canonical) and land a
8
+ * credential (Account) in the multi-credential pool (OAuth token or API
9
+ * key). NO browser interaction in the engine itself: the owner-driven
10
+ * OAuth code/token is passed in, so the flow is non-interactive and
11
+ * testable.
12
+ * 2. **select** — pick a model from the catalog (latest by `release_date`,
13
+ * or an explicit override validated against the catalog).
14
+ * 3. **bind** — write the `llm.default` / `llm.roles[role]` config binding
15
+ * that ties the account + model together.
16
+ * 4. **validate** — round-trip the binding through `resolveLLMForSystem` and
17
+ * confirm the resolved provider/model are consistent. NOT a live LLM call:
18
+ * no token is materialized, only the resolution metadata is asserted.
19
+ *
20
+ * ## Security — NO secret fields (AC2)
21
+ *
22
+ * This module is **types-only** (Gate 10 contracts-purity). The result
23
+ * envelope carries ONLY non-secret identifiers — provider name, account label,
24
+ * model id, profile/role name, and per-step status. It NEVER carries an access
25
+ * token, API key, refresh token, or any token-derived value beyond a redacted
26
+ * preview. The plaintext secret is materialized only at the wire via the
27
+ * {@link SealedCredential} handle — never on this envelope.
28
+ *
29
+ * @module llm/onboarding
30
+ * @task T11724
31
+ * @epic T11671 (E6-ONBOARDING-FRONT-DOOR)
32
+ */
33
+
34
+ import type { ProviderId } from './provider-id.js';
35
+
36
+ /**
37
+ * Discriminant naming each step of the onboarding login flow, in execution
38
+ * order. Surfaced on every {@link OnboardingStepResult} so a UI / CLI can
39
+ * render a deterministic 4-row progress checklist.
40
+ *
41
+ * @task T11724
42
+ */
43
+ export type OnboardingStepName = 'connect' | 'select' | 'bind' | 'validate';
44
+
45
+ /**
46
+ * Outcome of a single onboarding step.
47
+ *
48
+ * - `'ok'` — the step completed successfully.
49
+ * - `'failed'` — the step could not complete (e.g. missing credential,
50
+ * unknown model, config write error). The engine STOPS at the first
51
+ * `'failed'` step and returns the partial envelope; it does NOT throw.
52
+ * - `'skipped'` — the step was intentionally not run because an earlier step
53
+ * failed (downstream steps are short-circuited but still reported so the
54
+ * 4-row shape is stable).
55
+ *
56
+ * @task T11724
57
+ */
58
+ export type OnboardingStepStatus = 'ok' | 'failed' | 'skipped';
59
+
60
+ /**
61
+ * Result of one step in the onboarding login flow.
62
+ *
63
+ * `detail` is a short, human-readable, SECRET-FREE summary of what the step
64
+ * did (e.g. `"account 'work' connected (oauth)"`, `"model 'claude-…' selected
65
+ * from catalog"`). `code` carries a stable `E_*` error code on failure so a
66
+ * caller can branch programmatically without string-matching `detail`.
67
+ *
68
+ * @task T11724
69
+ */
70
+ export interface OnboardingStepResult {
71
+ /** Which step this result describes. */
72
+ readonly step: OnboardingStepName;
73
+ /** Terminal status of the step. */
74
+ readonly status: OnboardingStepStatus;
75
+ /** Human-readable, secret-free summary of the step outcome. */
76
+ readonly detail: string;
77
+ /**
78
+ * Stable `E_*` error code when `status === 'failed'`; omitted otherwise.
79
+ * Never carries a token or other secret.
80
+ */
81
+ readonly code?: string;
82
+ }
83
+
84
+ /**
85
+ * The auth scheme by which the connect step landed a credential in the pool.
86
+ *
87
+ * - `'oauth'` — an OAuth access token (PKCE / device-code) was supplied.
88
+ * - `'api_key'` — a raw API key was supplied (OAuth-less providers fall
89
+ * through to this path — AC4).
90
+ *
91
+ * @task T11724
92
+ */
93
+ export type OnboardingAuthMode = 'oauth' | 'api_key';
94
+
95
+ /**
96
+ * Typed result envelope returned by `runOnboardingLogin` (AC2).
97
+ *
98
+ * Carries NO secret fields — only the per-step trace and the non-secret
99
+ * identifiers needed to render the result and confirm the binding. `validated`
100
+ * is the single boolean a caller checks to know the end-to-end flow succeeded
101
+ * (all four steps `'ok'` AND the round-trip resolution was consistent).
102
+ *
103
+ * @task T11724
104
+ */
105
+ export interface OnboardingResult {
106
+ /** The 4 step traces, always length 4, in execution order. */
107
+ readonly steps: ReadonlyArray<OnboardingStepResult>;
108
+ /** Canonical provider id the flow resolved to (alias → canonical). */
109
+ readonly provider: ProviderId;
110
+ /**
111
+ * Human-readable account/credential label the connect step stored in the
112
+ * pool (e.g. `'oauth-login'`, `'work'`). Names *which* credential the
113
+ * binding points at — safe to log/serialize; NOT a secret.
114
+ */
115
+ readonly accountLabel: string;
116
+ /** The auth scheme used by the connect step, or `null` when connect failed. */
117
+ readonly authMode: OnboardingAuthMode | null;
118
+ /** Catalog model id the select step chose, or `null` when select failed. */
119
+ readonly modelId: string | null;
120
+ /**
121
+ * The profile/role name the bind step wrote (e.g. `'default'` for the global
122
+ * binding or a {@link import('../config.js').RoleName} for a per-role
123
+ * binding), or `null` when bind failed.
124
+ */
125
+ readonly profileName: string | null;
126
+ /**
127
+ * `true` only when all four steps succeeded AND the validate round-trip
128
+ * confirmed the binding resolves to the connected provider + selected model.
129
+ */
130
+ readonly validated: boolean;
131
+ }