@idapt/cli 1.9.0 → 1.11.0

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/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { HttpContext } from '@idapt/sdk';
2
3
 
3
4
  /**
4
5
  * v1 contract framework — the SINGLE SOURCE of truth for the public API surface.
@@ -36,7 +37,7 @@ type ResponseKind = "single" | "list" | "created" | "deleted" | "binary";
36
37
  /** Wire auth mode — drives the OpenAPI `security` requirement + whether 401 is documented. */
37
38
  type V1AuthMode = "standard" | "optional" | "public" | "bearer-only";
38
39
  /** HTTP error statuses the v1 surface documents. */
39
- type V1ErrorStatus = 401 | 402 | 403 | 404 | 409 | 422 | 429 | 500 | 503;
40
+ type V1ErrorStatus = 401 | 402 | 403 | 404 | 409 | 413 | 422 | 429 | 500 | 503;
40
41
  /**
41
42
  * A bespoke error response. Use instead of a bare {@link V1ErrorStatus} when an
42
43
  * op documents an error with op-specific prose / example / headers that the
@@ -91,6 +92,17 @@ interface V1CommandDocFields {
91
92
  readonly requestExample?: unknown;
92
93
  /** Inline example for the success-response body. */
93
94
  readonly responseExample?: unknown;
95
+ /**
96
+ * Agent-invocation examples — concrete `{action, args}` calls surfaced in the
97
+ * command catalog + `help`. Distinct from `requestExample`/`responseExample`
98
+ * (which document the HTTP bodies for OpenAPI). Helps the model produce
99
+ * well-formed calls (the Anthropic `input_examples` affordance).
100
+ */
101
+ readonly examples?: readonly {
102
+ readonly title?: string;
103
+ readonly action: string;
104
+ readonly args?: Record<string, unknown>;
105
+ }[];
94
106
  /** For `binary` responses — the media types served (+ optional example/description). */
95
107
  readonly binary?: {
96
108
  readonly contentTypes: readonly string[];
@@ -102,6 +114,31 @@ interface V1CommandDocFields {
102
114
  /** Marks the operation `deprecated` in the spec. */
103
115
  readonly deprecated?: boolean;
104
116
  }
117
+ /**
118
+ * Resource type a request field resolves against. The v1 route turns a human
119
+ * reference (resourceId | slug | name | workspace-relative path) into the
120
+ * canonical internal id before the handler runs. This is the contract-level
121
+ * encoding of what the dispatcher's old `TOOL_PATH_PARAMETERS` map did — moved
122
+ * here so resolution is one server-side step shared by chat / CLI / MCP / SDK.
123
+ */
124
+ type V1ResolveType = "file" | "folder" | "parent-folder" | "computer" | "agent" | "script" | "workspace";
125
+ /** How a single request field is resolved + (optionally) context-defaulted. */
126
+ interface V1FieldResolution {
127
+ /** Resource type to resolve this field's value(s) against. */
128
+ readonly type: V1ResolveType;
129
+ /** The field carries an ARRAY of references (e.g. `reference_image_ids`). */
130
+ readonly array?: boolean;
131
+ /**
132
+ * When the field is omitted, default it from request context instead of
133
+ * erroring. `"scopedWorkspace"` fills `workspace_id` from
134
+ * `credential.scopedWorkspaceId` (falling back to the actor's personal
135
+ * workspace) — the single defaulting rule that makes `workspace_id` optional
136
+ * on scope verbs for every caller.
137
+ */
138
+ readonly autoDefault?: "scopedWorkspace";
139
+ }
140
+ /** Steering-policy: how this resource's playbook reaches the in-chat agent. */
141
+ type V1SteeringPolicy = "eager" | "reactive" | "none";
105
142
  interface V1CommandSpec extends V1CommandDocFields {
106
143
  /** Resource group, e.g. "drive". */
107
144
  readonly resource: string;
@@ -127,10 +164,37 @@ interface V1CommandSpec extends V1CommandDocFields {
127
164
  readonly public: boolean;
128
165
  /** Exposed as an agent tool (dispatcher / MCP / `idapt`). */
129
166
  readonly agentExposed: boolean;
167
+ /**
168
+ * Workspace-scope behavior for the IN-APP agent dispatcher only (CLI / MCP
169
+ * always pass `workspace_id` explicitly and are unaffected):
170
+ * - "scope" → `workspace_id` is an operating SCOPE; the dispatcher auto-pins
171
+ * it to the chat's current workspace when the model omits it.
172
+ * - "target" → `workspace_id` is a DESTINATION (move / copy / link); never
173
+ * auto-filled — the model must name it explicitly.
174
+ * Omitted → the dispatcher still auto-pins read (GET) verbs whose request
175
+ * declares `workspace_id`; everything else stays explicit. Cross-workspace
176
+ * targeting is additionally gated by the `cross_workspace_agent` flag.
177
+ */
178
+ readonly workspaceScope?: "scope" | "target";
130
179
  /** Long-running → goes through the async-operation layer. */
131
180
  readonly async: boolean;
132
181
  /** Tier-1 one-line decision hint (≤200 chars). */
133
182
  readonly summary: string;
183
+ /**
184
+ * Per-field reference resolution + workspace defaulting, keyed by the request
185
+ * field name (snake_case wire name). The v1 route resolves each listed field
186
+ * (id | slug | name | path → internal id) using the caller's credential
187
+ * scope, in ONE place shared by every channel. Replaces the dispatcher's
188
+ * `TOOL_PATH_PARAMETERS`. Omit for verbs that take no references.
189
+ */
190
+ readonly fieldResolution?: Readonly<Record<string, V1FieldResolution>>;
191
+ /**
192
+ * How this resource's playbook reaches the in-chat agent (default `reactive`).
193
+ * Set on EVERY command of a resource to the same value (resource-level policy);
194
+ * `eager` for destructive / orchestration resources. Drives the builtin
195
+ * `tool-steering` hook — there is no forced-round-trip gate.
196
+ */
197
+ readonly steeringPolicy?: V1SteeringPolicy;
134
198
  }
135
199
  /**
136
200
  * Resource-level playbook (tier-2b instructions) — the cross-cutting "when /
@@ -193,16 +257,26 @@ declare function autoMode(isTty: boolean, requested?: RenderMode): RenderMode;
193
257
  /**
194
258
  * Transport seam. `execute()` builds a neutral {@link AgentToolsRequest} from a
195
259
  * command spec and hands it to a transport. The default {@link createFetchTransport}
196
- * is a thin bearer-auth fetch wrapper; in the in-chat worker / MCP it is given a
260
+ * sends HTTP **through `@idapt/sdk`'s low-level `requestRaw()`** (bearer auth, URL
261
+ * + body building, fetch-error mapping); in the in-chat worker / MCP it is given a
197
262
  * transport that injects the minted agent-principal token, and tests inject a
198
263
  * mock.
199
264
  *
200
- * This is the single seam where the `@idapt/sdk` low-level `request()` will be
201
- * plugged in once the SDK exports it so cli reuses the SDK's HTTP
202
- * behaviour instead of duplicating it long-term.
265
+ * This is the single seam where the cli, MCP, and in-app dispatcher (which all
266
+ * consume this transport) share ONE HTTP layer with the SDK instead of
267
+ * duplicating fetch — the JS twin of the Go daemon routing through one client.
268
+ *
269
+ * The {@link AgentToolsRequest}/{@link AgentToolsResponse} interface is kept
270
+ * byte-stable so `execute.ts` / MCP / the dispatcher are unaffected: the
271
+ * transport still NEVER throws on an HTTP status — every status (incl. 4xx/5xx)
272
+ * comes back as `{ status, json | text | blob }`. The SDK's `requestRaw()` throws
273
+ * a typed `IdaptError` on non-2xx, so we catch it and rebuild that flat shape
274
+ * from the error's preserved `.status` + `.body`. Only a transport-level failure
275
+ * (network error / abort) propagates as a thrown error, exactly as before.
203
276
  */
277
+
204
278
  interface AgentToolsRequest {
205
- readonly method: "GET" | "POST" | "PATCH" | "DELETE";
279
+ readonly method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
206
280
  /** Absolute-from-origin path, e.g. "/api/v1/drive/files/file_abc". */
207
281
  readonly path: string;
208
282
  readonly query?: Record<string, string | number | boolean | undefined>;
@@ -225,6 +299,15 @@ interface AgentToolsResponse {
225
299
  }
226
300
  interface AgentToolsTransport {
227
301
  request(req: AgentToolsRequest): Promise<AgentToolsResponse>;
302
+ /**
303
+ * The underlying SDK {@link HttpContext} this transport sends through, when it
304
+ * is the default fetch transport. The spec executor delegates request
305
+ * assembly, the HTTP call, envelope unwrap, and operation polling to the SDK's
306
+ * `executeCommand` over THIS context — so the CLI and SDK share ONE executor
307
+ * with zero duplicated logic. Absent only on bespoke (non-fetch) transports,
308
+ * in which case the executor reports the command is not runnable.
309
+ */
310
+ readonly ctx?: HttpContext;
228
311
  }
229
312
  interface FetchTransportOptions {
230
313
  /** Origin, e.g. "https://idapt.app" or "http://localhost:3000". */
@@ -241,17 +324,21 @@ interface FetchTransportOptions {
241
324
  */
242
325
  readonly userAgent?: string;
243
326
  }
244
- /** Default bearer-auth fetch transport. */
327
+ /** Default bearer-auth transport — sends through the SDK's `requestRaw()`. */
245
328
  declare function createFetchTransport(opts: FetchTransportOptions): AgentToolsTransport;
246
329
 
247
330
  /**
248
331
  * Execute an `idapt <resource> <verb> …` command against the v1 API.
249
332
  *
250
- * Pure translation: resolve the command spec, bind path params, validate the
251
- * remaining args against the contract's request schema, build the REST request
252
- * per the spec's `argLocation`, call the transport, unwrap the envelope by
253
- * `responseKind`, and render per the chosen mode. No per-verb code — the spec
254
- * (from `shared/api/v1/contracts`) drives everything.
333
+ * The CLI is the **spec/positional/validation/render adapter** around the SINGLE
334
+ * spec executor that lives in `@idapt/sdk` (`executeCommand`): it resolves the
335
+ * command spec, binds path params from positionals + named args, validates the
336
+ * remaining args against the contract's request schema, then DELEGATES request
337
+ * assembly, the HTTP call, envelope unwrap, and async-operation polling to the
338
+ * SDK over the transport's shared {@link HttpContext}. The CLI layers on what is
339
+ * its own — positional binding, pre-flight validation with repair hints, binary
340
+ * text-detection, render mode, and the soft `ExecuteResult` (it never throws on
341
+ * an HTTP status). One executor, zero duplicated transport logic.
255
342
  */
256
343
 
257
344
  interface ExecuteOptions {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { HttpContext } from '@idapt/sdk';
2
3
 
3
4
  /**
4
5
  * v1 contract framework — the SINGLE SOURCE of truth for the public API surface.
@@ -36,7 +37,7 @@ type ResponseKind = "single" | "list" | "created" | "deleted" | "binary";
36
37
  /** Wire auth mode — drives the OpenAPI `security` requirement + whether 401 is documented. */
37
38
  type V1AuthMode = "standard" | "optional" | "public" | "bearer-only";
38
39
  /** HTTP error statuses the v1 surface documents. */
39
- type V1ErrorStatus = 401 | 402 | 403 | 404 | 409 | 422 | 429 | 500 | 503;
40
+ type V1ErrorStatus = 401 | 402 | 403 | 404 | 409 | 413 | 422 | 429 | 500 | 503;
40
41
  /**
41
42
  * A bespoke error response. Use instead of a bare {@link V1ErrorStatus} when an
42
43
  * op documents an error with op-specific prose / example / headers that the
@@ -91,6 +92,17 @@ interface V1CommandDocFields {
91
92
  readonly requestExample?: unknown;
92
93
  /** Inline example for the success-response body. */
93
94
  readonly responseExample?: unknown;
95
+ /**
96
+ * Agent-invocation examples — concrete `{action, args}` calls surfaced in the
97
+ * command catalog + `help`. Distinct from `requestExample`/`responseExample`
98
+ * (which document the HTTP bodies for OpenAPI). Helps the model produce
99
+ * well-formed calls (the Anthropic `input_examples` affordance).
100
+ */
101
+ readonly examples?: readonly {
102
+ readonly title?: string;
103
+ readonly action: string;
104
+ readonly args?: Record<string, unknown>;
105
+ }[];
94
106
  /** For `binary` responses — the media types served (+ optional example/description). */
95
107
  readonly binary?: {
96
108
  readonly contentTypes: readonly string[];
@@ -102,6 +114,31 @@ interface V1CommandDocFields {
102
114
  /** Marks the operation `deprecated` in the spec. */
103
115
  readonly deprecated?: boolean;
104
116
  }
117
+ /**
118
+ * Resource type a request field resolves against. The v1 route turns a human
119
+ * reference (resourceId | slug | name | workspace-relative path) into the
120
+ * canonical internal id before the handler runs. This is the contract-level
121
+ * encoding of what the dispatcher's old `TOOL_PATH_PARAMETERS` map did — moved
122
+ * here so resolution is one server-side step shared by chat / CLI / MCP / SDK.
123
+ */
124
+ type V1ResolveType = "file" | "folder" | "parent-folder" | "computer" | "agent" | "script" | "workspace";
125
+ /** How a single request field is resolved + (optionally) context-defaulted. */
126
+ interface V1FieldResolution {
127
+ /** Resource type to resolve this field's value(s) against. */
128
+ readonly type: V1ResolveType;
129
+ /** The field carries an ARRAY of references (e.g. `reference_image_ids`). */
130
+ readonly array?: boolean;
131
+ /**
132
+ * When the field is omitted, default it from request context instead of
133
+ * erroring. `"scopedWorkspace"` fills `workspace_id` from
134
+ * `credential.scopedWorkspaceId` (falling back to the actor's personal
135
+ * workspace) — the single defaulting rule that makes `workspace_id` optional
136
+ * on scope verbs for every caller.
137
+ */
138
+ readonly autoDefault?: "scopedWorkspace";
139
+ }
140
+ /** Steering-policy: how this resource's playbook reaches the in-chat agent. */
141
+ type V1SteeringPolicy = "eager" | "reactive" | "none";
105
142
  interface V1CommandSpec extends V1CommandDocFields {
106
143
  /** Resource group, e.g. "drive". */
107
144
  readonly resource: string;
@@ -127,10 +164,37 @@ interface V1CommandSpec extends V1CommandDocFields {
127
164
  readonly public: boolean;
128
165
  /** Exposed as an agent tool (dispatcher / MCP / `idapt`). */
129
166
  readonly agentExposed: boolean;
167
+ /**
168
+ * Workspace-scope behavior for the IN-APP agent dispatcher only (CLI / MCP
169
+ * always pass `workspace_id` explicitly and are unaffected):
170
+ * - "scope" → `workspace_id` is an operating SCOPE; the dispatcher auto-pins
171
+ * it to the chat's current workspace when the model omits it.
172
+ * - "target" → `workspace_id` is a DESTINATION (move / copy / link); never
173
+ * auto-filled — the model must name it explicitly.
174
+ * Omitted → the dispatcher still auto-pins read (GET) verbs whose request
175
+ * declares `workspace_id`; everything else stays explicit. Cross-workspace
176
+ * targeting is additionally gated by the `cross_workspace_agent` flag.
177
+ */
178
+ readonly workspaceScope?: "scope" | "target";
130
179
  /** Long-running → goes through the async-operation layer. */
131
180
  readonly async: boolean;
132
181
  /** Tier-1 one-line decision hint (≤200 chars). */
133
182
  readonly summary: string;
183
+ /**
184
+ * Per-field reference resolution + workspace defaulting, keyed by the request
185
+ * field name (snake_case wire name). The v1 route resolves each listed field
186
+ * (id | slug | name | path → internal id) using the caller's credential
187
+ * scope, in ONE place shared by every channel. Replaces the dispatcher's
188
+ * `TOOL_PATH_PARAMETERS`. Omit for verbs that take no references.
189
+ */
190
+ readonly fieldResolution?: Readonly<Record<string, V1FieldResolution>>;
191
+ /**
192
+ * How this resource's playbook reaches the in-chat agent (default `reactive`).
193
+ * Set on EVERY command of a resource to the same value (resource-level policy);
194
+ * `eager` for destructive / orchestration resources. Drives the builtin
195
+ * `tool-steering` hook — there is no forced-round-trip gate.
196
+ */
197
+ readonly steeringPolicy?: V1SteeringPolicy;
134
198
  }
135
199
  /**
136
200
  * Resource-level playbook (tier-2b instructions) — the cross-cutting "when /
@@ -193,16 +257,26 @@ declare function autoMode(isTty: boolean, requested?: RenderMode): RenderMode;
193
257
  /**
194
258
  * Transport seam. `execute()` builds a neutral {@link AgentToolsRequest} from a
195
259
  * command spec and hands it to a transport. The default {@link createFetchTransport}
196
- * is a thin bearer-auth fetch wrapper; in the in-chat worker / MCP it is given a
260
+ * sends HTTP **through `@idapt/sdk`'s low-level `requestRaw()`** (bearer auth, URL
261
+ * + body building, fetch-error mapping); in the in-chat worker / MCP it is given a
197
262
  * transport that injects the minted agent-principal token, and tests inject a
198
263
  * mock.
199
264
  *
200
- * This is the single seam where the `@idapt/sdk` low-level `request()` will be
201
- * plugged in once the SDK exports it so cli reuses the SDK's HTTP
202
- * behaviour instead of duplicating it long-term.
265
+ * This is the single seam where the cli, MCP, and in-app dispatcher (which all
266
+ * consume this transport) share ONE HTTP layer with the SDK instead of
267
+ * duplicating fetch — the JS twin of the Go daemon routing through one client.
268
+ *
269
+ * The {@link AgentToolsRequest}/{@link AgentToolsResponse} interface is kept
270
+ * byte-stable so `execute.ts` / MCP / the dispatcher are unaffected: the
271
+ * transport still NEVER throws on an HTTP status — every status (incl. 4xx/5xx)
272
+ * comes back as `{ status, json | text | blob }`. The SDK's `requestRaw()` throws
273
+ * a typed `IdaptError` on non-2xx, so we catch it and rebuild that flat shape
274
+ * from the error's preserved `.status` + `.body`. Only a transport-level failure
275
+ * (network error / abort) propagates as a thrown error, exactly as before.
203
276
  */
277
+
204
278
  interface AgentToolsRequest {
205
- readonly method: "GET" | "POST" | "PATCH" | "DELETE";
279
+ readonly method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
206
280
  /** Absolute-from-origin path, e.g. "/api/v1/drive/files/file_abc". */
207
281
  readonly path: string;
208
282
  readonly query?: Record<string, string | number | boolean | undefined>;
@@ -225,6 +299,15 @@ interface AgentToolsResponse {
225
299
  }
226
300
  interface AgentToolsTransport {
227
301
  request(req: AgentToolsRequest): Promise<AgentToolsResponse>;
302
+ /**
303
+ * The underlying SDK {@link HttpContext} this transport sends through, when it
304
+ * is the default fetch transport. The spec executor delegates request
305
+ * assembly, the HTTP call, envelope unwrap, and operation polling to the SDK's
306
+ * `executeCommand` over THIS context — so the CLI and SDK share ONE executor
307
+ * with zero duplicated logic. Absent only on bespoke (non-fetch) transports,
308
+ * in which case the executor reports the command is not runnable.
309
+ */
310
+ readonly ctx?: HttpContext;
228
311
  }
229
312
  interface FetchTransportOptions {
230
313
  /** Origin, e.g. "https://idapt.app" or "http://localhost:3000". */
@@ -241,17 +324,21 @@ interface FetchTransportOptions {
241
324
  */
242
325
  readonly userAgent?: string;
243
326
  }
244
- /** Default bearer-auth fetch transport. */
327
+ /** Default bearer-auth transport — sends through the SDK's `requestRaw()`. */
245
328
  declare function createFetchTransport(opts: FetchTransportOptions): AgentToolsTransport;
246
329
 
247
330
  /**
248
331
  * Execute an `idapt <resource> <verb> …` command against the v1 API.
249
332
  *
250
- * Pure translation: resolve the command spec, bind path params, validate the
251
- * remaining args against the contract's request schema, build the REST request
252
- * per the spec's `argLocation`, call the transport, unwrap the envelope by
253
- * `responseKind`, and render per the chosen mode. No per-verb code — the spec
254
- * (from `shared/api/v1/contracts`) drives everything.
333
+ * The CLI is the **spec/positional/validation/render adapter** around the SINGLE
334
+ * spec executor that lives in `@idapt/sdk` (`executeCommand`): it resolves the
335
+ * command spec, binds path params from positionals + named args, validates the
336
+ * remaining args against the contract's request schema, then DELEGATES request
337
+ * assembly, the HTTP call, envelope unwrap, and async-operation polling to the
338
+ * SDK over the transport's shared {@link HttpContext}. The CLI layers on what is
339
+ * its own — positional binding, pre-flight validation with repair hints, binary
340
+ * text-detection, render mode, and the soft `ExecuteResult` (it never throws on
341
+ * an HTTP status). One executor, zero duplicated transport logic.
255
342
  */
256
343
 
257
344
  interface ExecuteOptions {
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { VERB_OVERRIDES, autoMode, commandsForResource, createFetchTransport, execute, executeCommand, findCommand, getResourcePlaybook, listCommands, listResources, mapArgsToV1, parseInvocation, reconcileToV1, render, renderHelp, renderInstructions, resolveCommand, toSnakeKey } from './chunk-TYSHO65D.js';
1
+ export { VERB_OVERRIDES, autoMode, commandsForResource, createFetchTransport, execute, executeCommand, findCommand, getResourcePlaybook, listCommands, listResources, mapArgsToV1, parseInvocation, reconcileToV1, render, renderHelp, renderInstructions, resolveCommand, toSnakeKey } from './chunk-3CWHRMLZ.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idapt/cli",
3
- "version": "1.9.0",
3
+ "version": "1.11.0",
4
4
  "description": "The idapt CLI — the `idapt <resource> <verb>` grammar, command→REST translation, help/instructions, output formatting, SOTA auth (OAuth 2.1 + PKCE / device-code / API-key) and self-update, over the public v1 API. One implementation shared by the in-chat dispatcher, MCP, and the `idapt` CLI binary.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://idapt.app/cli",
@@ -31,6 +31,7 @@
31
31
  "prepublishOnly": "npm run build"
32
32
  },
33
33
  "dependencies": {
34
+ "@idapt/sdk": "*",
34
35
  "zod": "^4.1.12"
35
36
  },
36
37
  "devDependencies": {