@yaklabs-ai/plugin-sdk 0.53.0 → 0.54.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/kay-app.d.ts CHANGED
@@ -1338,6 +1338,21 @@ declare class EncodeBuilder<Type extends TSchema, Encoded extends unknown, Decod
1338
1338
  Encode(callback: TEncodeCallback<Encoded, Decoded>): TCodec<Type, Decoded>;
1339
1339
  }
1340
1340
 
1341
+ export declare const EndpointContribution: z.ZodObject<{
1342
+ localId: z.ZodString;
1343
+ displayName: z.ZodOptional<z.ZodString>;
1344
+ requestSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<authoringCommonSchemas.JsonValue, unknown, z.core.$ZodTypeInternals<authoringCommonSchemas.JsonValue, unknown>>>>;
1345
+ responseSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<authoringCommonSchemas.JsonValue, unknown, z.core.$ZodTypeInternals<authoringCommonSchemas.JsonValue, unknown>>>>;
1346
+ auth: z.ZodOptional<z.ZodObject<{
1347
+ service: z.ZodString;
1348
+ schemes: z.ZodArray<z.ZodString>;
1349
+ purpose: z.ZodString;
1350
+ }, z.core.$strict>>;
1351
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
1352
+ }, z.core.$strict>;
1353
+
1354
+ export declare type EndpointContribution = z.infer<typeof EndpointContribution>;
1355
+
1341
1356
  declare interface EntryBase {
1342
1357
  id: string;
1343
1358
  parentId: string | null;
@@ -2915,11 +2930,45 @@ declare const KAY_PLUGIN_PROTOCOL_VERSION: "kay.plugin.v1";
2915
2930
  * 0.53.0 adds declared working-content layouts, family-root authority, draft projection discovery
2916
2931
  * and session-bound page references. Older customized Whiteboard copies must accept the plugin
2917
2932
  * update before using these interfaces.
2933
+ *
2934
+ * 0.54.0 adds named UI host grants for shared configuration/auth/account reads, retained connection
2935
+ * progress/dismissal and support. Built-in-only page capability scopes are removed; executable
2936
+ * pages declare capabilities on apps[].
2918
2937
  */
2919
- declare const KAY_PLUGIN_SDK_VERSION: "0.53.0";
2938
+ declare const KAY_PLUGIN_SDK_VERSION: "0.54.0";
2920
2939
 
2921
2940
  declare const KAY_PLUGIN_TARGET_NAMES: readonly ["kay.agent", "kay.app", "kay.ui"];
2922
2941
 
2942
+ /**
2943
+ * One process the plugin asks the host to run.
2944
+ *
2945
+ * `argvClass` is required and is NOT decoration: it names the class of argument vector this
2946
+ * invocation belongs to, and it must match a class the plugin declared alongside `command` in its
2947
+ * manifest. Declaring a command alone would authorize `git log` and `git push --force` identically;
2948
+ * the class is what a user can be shown and asked to consent to. The host judges the real `args`
2949
+ * against the named class and refuses with `argv-outside-class` when they do not belong to it.
2950
+ */
2951
+ declare interface KayAgentProcessRunRequest {
2952
+ readonly command: string;
2953
+ readonly argvClass: string;
2954
+ readonly args: readonly string[];
2955
+ /** Abort the run; the host kills the DIRECT child and rejects - a forked descendant may outlive it (#6153). */
2956
+ readonly signal?: AbortSignal;
2957
+ }
2958
+
2959
+ /**
2960
+ * A finished run. `stdout`/`stderr` are decoded text, and the host CAPS them - a truncation flag is
2961
+ * set rather than the output silently ending, so a plugin parsing the stream can tell "the command
2962
+ * printed this" apart from "the command printed more than we kept".
2963
+ */
2964
+ declare interface KayAgentProcessRunResult {
2965
+ readonly exitCode: number;
2966
+ readonly stdout: string;
2967
+ readonly stderr: string;
2968
+ readonly stdoutTruncated?: boolean;
2969
+ readonly stderrTruncated?: boolean;
2970
+ }
2971
+
2923
2972
  declare interface KayAgentWhiteboardCreateInput {
2924
2973
  readonly name: string;
2925
2974
  readonly title: string;
@@ -3479,6 +3528,16 @@ export declare type KayAppArtifactOutputFile = {
3479
3528
  };
3480
3529
 
3481
3530
  export declare interface KayAppArtifactOutputs extends Omit<KayAppKnowledgeSource, "watchRoots"> {
3531
+ /**
3532
+ * One page of canonical output URIs across every chat or, with `sessionId`,
3533
+ * only that chat's outputs. A cursor continues the enumeration it came from.
3534
+ */
3535
+ enumerate(options: {
3536
+ readonly cursor?: JsonValue;
3537
+ readonly limit: number;
3538
+ readonly signal: AbortSignal;
3539
+ readonly sessionId?: string;
3540
+ }): ReturnType<KayAppKnowledgeSource["enumerate"]>;
3482
3541
  subscribe(listener: (change: ArtifactOutputChange) => void): () => void;
3483
3542
  /**
3484
3543
  * The exact bytes of one canonical `output://<session>/<name>` file, at most `maxBytes`
@@ -3494,6 +3553,13 @@ export declare interface KayAppArtifactOutputs extends Omit<KayAppKnowledgeSourc
3494
3553
  export declare interface KayAppArtifacts {
3495
3554
  /** Activation-only request for the public artifacts.read {kind: output} capability. */
3496
3555
  outputs(): KayAppArtifactOutputs;
3556
+ /**
3557
+ * Private API: only plugins Bonsai ships; refused for any other. The absolute path of the file
3558
+ * an address names as `sessionId`'s agent would see it (`output://`, `file://` and the other
3559
+ * file-backed schemes), or `undefined` when it names no readable file. Checked against
3560
+ * `artifacts.resolve-file`; a refused call rejects.
3561
+ */
3562
+ resolveFile?(sessionId: string, uri: string): Promise<string | undefined>;
3497
3563
  }
3498
3564
 
3499
3565
  /** A persisted assistant message, published without waiting for its subscribers. */
@@ -5198,6 +5264,13 @@ export declare interface KayAppPaths {
5198
5264
  * empty directory rather than an error.
5199
5265
  */
5200
5266
  readonly sessionsRoot?: string;
5267
+ /**
5268
+ * Absolute path to the folder holding the scratch working folders of chats started without a
5269
+ * folder of their own (`<chatsRoot>/<id>`). Files written there belong to that one chat. Ask for
5270
+ * this rather than deriving it: Desktop keeps it under the app's user-data root, not beside
5271
+ * {@link sessionsRoot}. Absent when the host composed none.
5272
+ */
5273
+ readonly chatsRoot?: string;
5201
5274
  /**
5202
5275
  * Absolute path to Bonsai's local telemetry directory. The live telemetry lane itself is a
5203
5276
  * Postgres table (`telemetry.usage_events`), not anything under this path; it is never a
@@ -5337,6 +5410,11 @@ export declare interface KayAppPluginApi {
5337
5410
  * which blocks the daemon; see {@link KayAppRepos}.
5338
5411
  */
5339
5412
  readonly repos: KayAppRepos;
5413
+ /**
5414
+ * Private API: only plugins Bonsai ships; refused for any other. Runs a program the host bound
5415
+ * for this plugin; see {@link KayAppProcess}. Absent when the host composed no program bindings.
5416
+ */
5417
+ readonly process?: KayAppProcess;
5340
5418
  /**
5341
5419
  * File I/O in user folders (stat, read, list, walk, realpath, write, mkdir, rename), run by the
5342
5420
  * host on its own worker threads under a deadline and answered as a typed result. Always present
@@ -5601,8 +5679,25 @@ export declare interface KayAppPollResult<Cursor extends JsonValue> {
5601
5679
  readonly summary?: string;
5602
5680
  }
5603
5681
 
5682
+ /**
5683
+ * Private API: only plugins Bonsai ships; refused for any other. Run a program the host bound
5684
+ * for this plugin, the way {@link import("../kay-agent/index.ts").KayAgentProcess} does for an
5685
+ * agent tool: the plugin names a command and an argument class, the host owns the executable,
5686
+ * which arguments belong to the class, the time limit, the output cap, the working directory and
5687
+ * the environment. Each run is checked against `process.run` and then the exact
5688
+ * `process.spawn {command, argvClass}` claim; a refusal rejects with `KayAgentCapabilityError`,
5689
+ * a timeout resolves with exit code 124.
5690
+ */
5691
+ export declare interface KayAppProcess {
5692
+ run(request: KayAppProcessRunRequest): Promise<KayAppProcessRunResult>;
5693
+ }
5694
+
5604
5695
  export declare type KayAppProcessingSpeed = "standard" | "fast";
5605
5696
 
5697
+ export declare type KayAppProcessRunRequest = KayAgentProcessRunRequest;
5698
+
5699
+ export declare type KayAppProcessRunResult = KayAgentProcessRunResult;
5700
+
5606
5701
  /**
5607
5702
  * A gap reason on the run-detail wire: something about the run's work the
5608
5703
  * daemon could not establish from its session transcripts. The vocabulary is
@@ -6265,6 +6360,18 @@ export declare type KayAppSessionPageItem = (Omit<Extract<TranscriptPageItem, {
6265
6360
  readonly unreadable: unknown;
6266
6361
  }>;
6267
6362
 
6363
+ /** One write for {@link KayAppSessions.assignProject}. */
6364
+ export declare interface KayAppSessionProjectAssignment {
6365
+ readonly sessionId: string;
6366
+ /**
6367
+ * The project the session must still hold for the write to land: a project id, `null` for "no
6368
+ * project" chosen on purpose, or absent for a session whose project was never decided.
6369
+ */
6370
+ readonly expectedProjectId?: string | null;
6371
+ /** The project to set; `null` sets "no project". */
6372
+ readonly projectId: string | null;
6373
+ }
6374
+
6268
6375
  export declare type KayAppSessionProvenanceRecord = SessionProvenanceRecord;
6269
6376
 
6270
6377
  export declare type KayAppSessionRelationship = SessionRelationship;
@@ -6605,6 +6712,15 @@ export declare interface KayAppSessions {
6605
6712
  } | {
6606
6713
  readonly kind: "unavailable";
6607
6714
  }>;
6715
+ /**
6716
+ * Private API: only plugins Bonsai ships; refused for any other. Set the project of any stored
6717
+ * sessions, each only while it still holds the project the caller last saw (a compare-and-set,
6718
+ * so a person's own choice made meanwhile always wins). Answers one boolean per assignment, in
6719
+ * order: `false` when the session is gone or its project changed. A written session's project
6720
+ * folder and prompt block are refreshed. Checked against `sessions.assign-project`; a refused
6721
+ * call rejects.
6722
+ */
6723
+ assignProject?(assignments: readonly KayAppSessionProjectAssignment[]): Promise<readonly boolean[]>;
6608
6724
  /**
6609
6725
  * Run one hidden headless system session through Bonsai's harness and resolve
6610
6726
  * with its final output - the sole sanctioned way for a `kay.app` plugin to
@@ -7692,6 +7808,12 @@ export declare interface KayAppSystemPromptFragment {
7692
7808
  * KayAppSystemPromptRegistration.refresh}.
7693
7809
  */
7694
7810
  readonly maxAgeMs?: number;
7811
+ /**
7812
+ * For text about the chat's project. A forked chat starts with its parent's texts unchanged, so
7813
+ * the model's prompt cache still matches; when set, a fork whose project is then chosen drops the
7814
+ * parent's copy of this text and renders its own. Absent: a fork keeps the parent's text.
7815
+ */
7816
+ readonly forksFollowProject?: boolean;
7695
7817
  /** The text, or `undefined` for none. A rejection leaves the text out and is logged. */
7696
7818
  render(request: KayAppSystemPromptRenderRequest): Promise<string | undefined>;
7697
7819
  }
@@ -9012,6 +9134,90 @@ declare type MatchTrueLike = (inferred: TProperties) => unknown;
9012
9134
  /** The most labels a recorded choice question may offer, and so the most one filter names. */
9013
9135
  export declare const MAX_CHOICE_LABELS = 64;
9014
9136
 
9137
+ /** The connection state published for one configured MCP server. */
9138
+ export declare type McpServerConnectionState = "disconnected" | "connecting" | "connected" | "needs-auth" | "failed";
9139
+
9140
+ /** A server mark already resolved into a data URI by its publisher. */
9141
+ export declare interface McpServerIcon {
9142
+ /** A `data:` URI. Consumers may render it directly in an `<img src>`. */
9143
+ readonly src: string;
9144
+ /**
9145
+ * Where the mark came from, because the two are not equally trustworthy.
9146
+ *
9147
+ * `declared` is the server's own `serverInfo.icons` (MCP spec 2025-11-25, SEP-973): evidence.
9148
+ * `favicon` is derived from an HTTP server's origin: still evidence, one step removed.
9149
+ * A name match against Bonsai's brand table is neither, and deliberately does not appear here -
9150
+ * that guess lives in the renderer's existing `BrandIcon` fallback, below both of these.
9151
+ */
9152
+ readonly source: "declared" | "favicon";
9153
+ /** The theme the server nominated this variant for, when it declared more than one. */
9154
+ readonly theme?: "light" | "dark";
9155
+ }
9156
+
9157
+ /** One keyed change to the MCP inventory. */
9158
+ export declare type McpServerInventoryChange = {
9159
+ readonly kind: "upsert";
9160
+ readonly server: McpServerRecord;
9161
+ } | {
9162
+ readonly kind: "remove";
9163
+ readonly name: string;
9164
+ };
9165
+
9166
+ /** One configured MCP server in the app-facing inventory. */
9167
+ export declare interface McpServerRecord {
9168
+ /** The config key, and the id the `mcp.<name>` auth service keys on. */
9169
+ readonly name: string;
9170
+ /**
9171
+ * The auth service that connects this server, when it has one: `mcp.<name>` for a plugins.mcp
9172
+ * server, the shipping plugin's own service for a vendored one. The Plugins page joins a
9173
+ * connection row to its server on THIS id - never by deriving a name from the service id,
9174
+ * which only ever fit the user-config namespace and left every vendored server toolless.
9175
+ */
9176
+ readonly authServiceId?: string;
9177
+ /** The server's own `serverInfo.title`, when it sent one. Display prefers it over `name`. */
9178
+ readonly title?: string;
9179
+ readonly transport: "stdio" | "http";
9180
+ /** What the server launches or connects to: joined command for stdio, url for http. */
9181
+ readonly target: string;
9182
+ /** The config-level switch (`enabled: false` in `plugins.mcp`), not the connection. */
9183
+ readonly enabled: boolean;
9184
+ readonly state: McpServerConnectionState;
9185
+ /** Live when connected, else from the persisted metadata cache. Zero is ordinary. */
9186
+ readonly toolCount: number;
9187
+ /**
9188
+ * What this server offers, for a surface that lists it. Live when connected, else from the
9189
+ * persisted metadata cache, so a server names its tools before it has connected this session
9190
+ * and after a restart.
9191
+ *
9192
+ * NAMES AND DESCRIPTIONS ONLY. The JSON-Schema input declarations stay out: they are by far the
9193
+ * biggest part of a tool list, nothing on this surface renders them, and this snapshot is
9194
+ * re-encoded whenever any server changes state. A surface that genuinely needs a schema is
9195
+ * asking a different question and should ask the agent bridge, which owns tool detail.
9196
+ *
9197
+ * Bounded by the publisher's tool-list limit - {@link toolCount} remains the true count, so a
9198
+ * server past the bound still reports honestly even though the list is clipped.
9199
+ */
9200
+ readonly tools?: readonly McpServerToolSummary[];
9201
+ readonly icon?: McpServerIcon;
9202
+ /**
9203
+ * Why a `failed` server failed, in one human-legible line, when the host knows. A broken row can
9204
+ * then say what went wrong instead of only offering Retry.
9205
+ */
9206
+ readonly failure?: string;
9207
+ }
9208
+
9209
+ /** A complete MCP inventory snapshot. */
9210
+ export declare interface McpServersSnapshot {
9211
+ readonly servers: readonly McpServerRecord[];
9212
+ }
9213
+
9214
+ /** A tool name and optional description for inventory presentation. */
9215
+ export declare interface McpServerToolSummary {
9216
+ readonly name: string;
9217
+ /** The server's own one-line description, trimmed to the publisher's summary limit. */
9218
+ readonly description?: string;
9219
+ }
9220
+
9015
9221
  export declare namespace Memory {
9016
9222
  export {
9017
9223
  Assign,
@@ -10256,6 +10462,33 @@ export declare interface PreparedAccessApproval {
10256
10462
  readonly binding?: unknown;
10257
10463
  }
10258
10464
 
10465
+ export declare const ProjectDirectory: z.ZodObject<{
10466
+ id: z.ZodString;
10467
+ path: z.ZodString;
10468
+ defaultCwd: z.ZodString;
10469
+ ancestorIds: z.ZodArray<z.ZodString>;
10470
+ }, z.core.$strict>;
10471
+
10472
+ export declare type ProjectDirectory = z.infer<typeof ProjectDirectory>;
10473
+
10474
+ export declare const ProjectDirectoryRequest: z.ZodObject<{
10475
+ id: z.ZodString;
10476
+ }, z.core.$strict>;
10477
+
10478
+ export declare type ProjectDirectoryRequest = z.infer<typeof ProjectDirectoryRequest>;
10479
+
10480
+ /** `project` is null when no project has the requested id. */
10481
+ export declare const ProjectDirectoryResponse: z.ZodObject<{
10482
+ project: z.ZodNullable<z.ZodObject<{
10483
+ id: z.ZodString;
10484
+ path: z.ZodString;
10485
+ defaultCwd: z.ZodString;
10486
+ ancestorIds: z.ZodArray<z.ZodString>;
10487
+ }, z.core.$strict>>;
10488
+ }, z.core.$strict>;
10489
+
10490
+ export declare type ProjectDirectoryResponse = z.infer<typeof ProjectDirectoryResponse>;
10491
+
10259
10492
  declare const Properties: (input: string) => [unknown, string] | [];
10260
10493
 
10261
10494
  declare function PropertiesMapping(input: [unknown, unknown, unknown]): unknown;
package/dist/kay-app.js CHANGED
@@ -308,6 +308,31 @@ function createUnavailableUriCaller(message) {
308
308
  };
309
309
  }
310
310
 
311
+ // packages/plugin-protocol/dist/project-directories.js
312
+ import { z as z5 } from "zod";
313
+ var PluginProjectDirectories = z5.strictObject({
314
+ /** An endpoint this plugin's app target declares; called with a {@link ProjectDirectoryRequest}. */
315
+ endpoint: z5.string().min(1),
316
+ /** A scheme this plugin's URI modules serve; a project is addressed as `<scheme>://<id>`. */
317
+ scheme: z5.string().min(1)
318
+ });
319
+ var ProjectDirectoryRequest = z5.strictObject({
320
+ /** The project's stable id. */
321
+ id: z5.string().min(1)
322
+ });
323
+ var ProjectDirectory = z5.strictObject({
324
+ id: z5.string().min(1),
325
+ /** Absolute path of the project's folder. */
326
+ path: z5.string().min(1),
327
+ /** Absolute path a new session in this project starts in. */
328
+ defaultCwd: z5.string().min(1),
329
+ /** Ancestor project ids, root first. */
330
+ ancestorIds: z5.array(z5.string().min(1))
331
+ });
332
+ var ProjectDirectoryResponse = z5.strictObject({
333
+ project: ProjectDirectory.nullable()
334
+ });
335
+
311
336
  // packages/plugin-sdk/dist/endpoints.js
312
337
  function createUnavailablePluginEndpointCaller(message) {
313
338
  return {
@@ -374,41 +399,48 @@ function isCredentialShapedText(value) {
374
399
  return CREDENTIAL_VALUE_PATTERNS.some((pattern) => pattern.test(value));
375
400
  }
376
401
 
402
+ // packages/plugin-protocol/dist/resource-invocation-cursor.js
403
+ import { z as z6 } from "zod";
404
+ var CorpusResourceInvocationCursor = z6.strictObject({
405
+ at: z6.iso.datetime({ offset: true }),
406
+ eventId: z6.string().min(1)
407
+ });
408
+
377
409
  // packages/plugin-protocol/dist/json.js
378
- import { z as z5 } from "zod";
379
- var JsonValue = z5.lazy(() => z5.union([
380
- z5.string(),
381
- z5.number(),
382
- z5.boolean(),
383
- z5.null(),
384
- z5.array(JsonValue),
385
- z5.record(z5.string(), JsonValue)
410
+ import { z as z7 } from "zod";
411
+ var JsonValue = z7.lazy(() => z7.union([
412
+ z7.string(),
413
+ z7.number(),
414
+ z7.boolean(),
415
+ z7.null(),
416
+ z7.array(JsonValue),
417
+ z7.record(z7.string(), JsonValue)
386
418
  ]));
387
- var JsonObject = z5.record(z5.string(), JsonValue);
388
- var JsonSchema = z5.record(z5.string(), JsonValue);
419
+ var JsonObject = z7.record(z7.string(), JsonValue);
420
+ var JsonSchema = z7.record(z7.string(), JsonValue);
389
421
 
390
422
  // packages/plugin-protocol/dist/shell-commands.js
391
- import { z as z6 } from "zod";
392
- var PluginShellCommand = z6.strictObject({
393
- name: z6.string().regex(/^[a-z][a-z0-9-]*$/),
394
- aliases: z6.array(z6.string().regex(/^[a-z][a-z0-9-]*$/)).optional(),
395
- endpoint: z6.string().min(1),
396
- usage: z6.string().min(1)
423
+ import { z as z8 } from "zod";
424
+ var PluginShellCommand = z8.strictObject({
425
+ name: z8.string().regex(/^[a-z][a-z0-9-]*$/),
426
+ aliases: z8.array(z8.string().regex(/^[a-z][a-z0-9-]*$/)).optional(),
427
+ endpoint: z8.string().min(1),
428
+ usage: z8.string().min(1)
397
429
  });
398
- var ShellCommandOutcome = z6.strictObject({
399
- exitCode: z6.number().int(),
430
+ var ShellCommandOutcome = z8.strictObject({
431
+ exitCode: z8.number().int(),
400
432
  envelope: JsonValue,
401
433
  result: JsonValue.optional()
402
434
  });
403
- var ShellCommandRequest = z6.strictObject({
404
- argv: z6.array(z6.string()),
405
- cwd: z6.string(),
406
- outcomes: z6.array(ShellCommandOutcome).max(3)
435
+ var ShellCommandRequest = z8.strictObject({
436
+ argv: z8.array(z8.string()),
437
+ cwd: z8.string(),
438
+ outcomes: z8.array(ShellCommandOutcome).max(3)
407
439
  });
408
- var ShellCommandStep = z6.discriminatedUnion("kind", [
409
- z6.strictObject({
410
- kind: z6.literal("invoke"),
411
- toolName: z6.enum([
440
+ var ShellCommandStep = z8.discriminatedUnion("kind", [
441
+ z8.strictObject({
442
+ kind: z8.literal("invoke"),
443
+ toolName: z8.enum([
412
444
  "read",
413
445
  "list",
414
446
  "search",
@@ -417,13 +449,13 @@ var ShellCommandStep = z6.discriminatedUnion("kind", [
417
449
  "delete",
418
450
  "help"
419
451
  ]),
420
- input: z6.record(z6.string(), JsonValue),
421
- flags: z6.record(z6.string(), z6.string())
452
+ input: z8.record(z8.string(), JsonValue),
453
+ flags: z8.record(z8.string(), z8.string())
422
454
  }),
423
- z6.strictObject({
424
- kind: z6.literal("finish"),
425
- exitCode: z6.number().int(),
426
- stdout: z6.string()
455
+ z8.strictObject({
456
+ kind: z8.literal("finish"),
457
+ exitCode: z8.number().int(),
458
+ stdout: z8.string()
427
459
  })
428
460
  ]);
429
461
 
@@ -487,7 +519,7 @@ function submit(label) {
487
519
  }
488
520
 
489
521
  // packages/plugin-sdk/dist/signals.js
490
- import { z as z7 } from "zod";
522
+ import { z as z9 } from "zod";
491
523
  function createFallbackOnlySignals() {
492
524
  const noStore = { status: "unavailable", reason: "no-store" };
493
525
  return {
@@ -517,23 +549,23 @@ var POINTER = /^[^\s\p{C}/?#]+$/u;
517
549
  var LABEL = /^[^\s,@\p{C}]+(?: [^\s,@\p{C}]+)*$/u;
518
550
  var RUN_ID = /^\P{Cc}+$/u;
519
551
  var POINTER_RULE = `1 to ${MAX_POINTER} characters with no whitespace, \`/\`, \`?\`, \`#\`, or control or invisible character`;
520
- var ObserveShape = z7.looseObject({
521
- detector: z7.looseObject({ id: z7.string(), version: z7.string() }),
522
- subject: z7.looseObject({ kind: z7.string(), key: z7.string().optional() }).optional(),
523
- after: z7.looseObject({ observationId: z7.unknown() }).optional(),
524
- reuse: z7.looseObject({ maxAgeMs: z7.unknown() }).optional(),
525
- source: z7.looseObject({
526
- sessionId: z7.string(),
527
- entryId: z7.string(),
528
- openerEntryId: z7.string().optional(),
529
- runId: z7.string().optional(),
530
- occurredAtMs: z7.unknown().optional()
552
+ var ObserveShape = z9.looseObject({
553
+ detector: z9.looseObject({ id: z9.string(), version: z9.string() }),
554
+ subject: z9.looseObject({ kind: z9.string(), key: z9.string().optional() }).optional(),
555
+ after: z9.looseObject({ observationId: z9.unknown() }).optional(),
556
+ reuse: z9.looseObject({ maxAgeMs: z9.unknown() }).optional(),
557
+ source: z9.looseObject({
558
+ sessionId: z9.string(),
559
+ entryId: z9.string(),
560
+ openerEntryId: z9.string().optional(),
561
+ runId: z9.string().optional(),
562
+ occurredAtMs: z9.unknown().optional()
531
563
  }),
532
- questions: z7.record(z7.string(), z7.unknown())
564
+ questions: z9.record(z9.string(), z9.unknown())
533
565
  });
534
- var ChoiceQuestion = z7.looseObject({
535
- type: z7.literal("choice"),
536
- criteria: z7.record(z7.string(), z7.unknown())
566
+ var ChoiceQuestion = z9.looseObject({
567
+ type: z9.literal("choice"),
568
+ criteria: z9.record(z9.string(), z9.unknown())
537
569
  });
538
570
  var fits = (value, grammar) => value.length <= MAX_NAME && grammar.test(value);
539
571
  var isWhole = (value, min) => typeof value === "number" && Number.isSafeInteger(value) && value >= min && value <= SIGNAL_TIME_MAX_MS;
@@ -613,10 +645,10 @@ function grammarProblem(input) {
613
645
  }
614
646
  return void 0;
615
647
  }
616
- var EchoText = z7.string().catch("");
617
- var Echo = z7.object({
618
- detector: z7.object({ id: EchoText, version: EchoText }).catch({ id: "", version: "" }),
619
- source: z7.object({ sessionId: EchoText, entryId: EchoText }).catch({ sessionId: "", entryId: "" })
648
+ var EchoText = z9.string().catch("");
649
+ var Echo = z9.object({
650
+ detector: z9.object({ id: EchoText, version: EchoText }).catch({ id: "", version: "" }),
651
+ source: z9.object({ sessionId: EchoText, entryId: EchoText }).catch({ sessionId: "", entryId: "" })
620
652
  }).catch({
621
653
  detector: { id: "", version: "" },
622
654
  source: { sessionId: "", entryId: "" }
@@ -1121,6 +1153,7 @@ var KAY_APP_DATA_CHANGE_MAX_BYTES = 256 * 1024;
1121
1153
  var KAY_APP_DATA_READ_REQUEST_MAX_BYTES = 64 * 1024;
1122
1154
  var KAY_APP_DATA_READ_RESULT_MAX_BYTES = 16 * 1024 * 1024;
1123
1155
  export {
1156
+ CorpusResourceInvocationCursor,
1124
1157
  JsonSchema,
1125
1158
  JsonValue,
1126
1159
  KAY_APP_AUTOMATION_CONDITION_KINDS,
@@ -1140,6 +1173,9 @@ export {
1140
1173
  PLUGIN_SIGNAL_RELATED_KEYS,
1141
1174
  PLUGIN_SIGNAL_SNIPPET_MAX,
1142
1175
  PLUGIN_SIGNAL_TITLE_MAX,
1176
+ ProjectDirectory,
1177
+ ProjectDirectoryRequest,
1178
+ ProjectDirectoryResponse,
1143
1179
  SIGNAL_TIME_MAX_MS,
1144
1180
  STORED_TRANSCRIPT_MESSAGE_FILTER,
1145
1181
  STORED_TRANSCRIPT_MESSAGE_KINDS,
@@ -0,0 +1,106 @@
1
+ /** What changed between the texts the card showed and the texts the person sent. */
2
+ export declare function diffDraft(before: DraftTexts, after: DraftTexts): DraftChange;
3
+
4
+ declare interface DiffSegment {
5
+ readonly kind: DiffSegmentKind;
6
+ readonly text: string;
7
+ }
8
+
9
+ declare type DiffSegmentKind = "same" | "removed" | "added";
10
+
11
+ /** Compare two texts word by word. Callers normalize first; this compares what it is given. */
12
+ export declare function diffWords(before: string, after: string): WordDiff;
13
+
14
+ export declare interface DraftChange {
15
+ /** The normalized subject or body differ. A change in whitespace alone counts. */
16
+ readonly edited: boolean;
17
+ readonly subjectChanged: boolean;
18
+ readonly bodyChanged: boolean;
19
+ /** Words across subject and body; zero for an edit that only moved whitespace. */
20
+ readonly wordsAdded: number;
21
+ readonly wordsRemoved: number;
22
+ /**
23
+ * Words across subject and body of the draft as proposed and of the message as sent, counted the
24
+ * way `wordsRemoved` and `wordsAdded` are. `(beforeWords - wordsRemoved) / beforeWords` is the
25
+ * share of the proposed draft that was kept.
26
+ */
27
+ readonly beforeWords: number;
28
+ readonly afterWords: number;
29
+ readonly beforeChars: number;
30
+ readonly afterChars: number;
31
+ /**
32
+ * Either part's changed span was too long to align, so it counts as one removed block and one
33
+ * added block: `wordsRemoved` is then an upper bound and the share kept a lower bound.
34
+ */
35
+ readonly coarse: boolean;
36
+ readonly subjectDiff: WordDiff | undefined;
37
+ readonly bodyDiff: WordDiff | undefined;
38
+ }
39
+
40
+ export declare interface DraftTexts {
41
+ readonly subject: string | undefined;
42
+ readonly body: string;
43
+ }
44
+
45
+ /** Both ends of a text too long to show whole, and how much lay between them. */
46
+ export declare interface HeadAndTail {
47
+ readonly head: string;
48
+ readonly tail: string;
49
+ /** UTF-16 units left out between `head` and `tail`; `0` when the text fit and `head` is all of it. */
50
+ readonly omitted: number;
51
+ }
52
+
53
+ /**
54
+ * The first `headMax` and the last `tailMax` UTF-16 units of `text`, each cut on a character
55
+ * boundary. Text that fits in `headMax + tailMax` comes back whole as `head`, with nothing omitted.
56
+ *
57
+ * For text whose ASK sits at the end (a reply that closes on a question) as well as its framing at
58
+ * the start: a head-only cut keeps the framing and loses the ask.
59
+ */
60
+ export declare function headAndTailChars(text: string, headMax: number, tailMax: number): HeadAndTail;
61
+
62
+ /** At most `max` UTF-16 units from the start of `text`, never ending inside a surrogate pair. */
63
+ export declare function headChars(text: string, max: number): string;
64
+
65
+ /** The most cells the alignment table may hold (about 2,000 tokens a side, 16 MB of Uint32). */
66
+ export declare const MAX_LCS_CELLS = 4000000;
67
+
68
+ /**
69
+ * Line endings, trailing whitespace on each line and trailing blank lines are not edits: a text
70
+ * area and a saved file disagree on them without the person touching a word.
71
+ */
72
+ export declare function normalizeDraftBody(text: string): string;
73
+
74
+ /** A subject is one line: any whitespace run is one space and the ends are trimmed. */
75
+ export declare function normalizeDraftSubject(subject: string | undefined): string | undefined;
76
+
77
+ /**
78
+ * The diff as one marked text: `[-removed-]` and `{+added+}` inside the unchanged words around
79
+ * them, with a long unchanged stretch collapsed to its edges and an ellipsis. The unmarked parts
80
+ * are the original wording, so the result reads as the final text with the edits shown.
81
+ */
82
+ export declare function renderWordDiff(diff: WordDiff, options?: {
83
+ readonly contextWords?: number;
84
+ readonly maxChars?: number;
85
+ }): {
86
+ readonly text: string;
87
+ readonly truncated: boolean;
88
+ };
89
+
90
+ /** The end index of a head that does not end inside a surrogate pair. */
91
+ export declare function safeHeadEnd(text: string, end: number): number;
92
+
93
+ /** The start index of a tail that does not begin inside a surrogate pair. */
94
+ export declare function safeTailStart(text: string, start: number): number;
95
+
96
+ export declare interface WordDiff {
97
+ /** Non-whitespace words present before and gone after. */
98
+ readonly wordsRemoved: number;
99
+ /** Non-whitespace words present after and not before. */
100
+ readonly wordsAdded: number;
101
+ readonly segments: readonly DiffSegment[];
102
+ /** The middle was too large to align, so it is one removed block and one added block. */
103
+ readonly coarse: boolean;
104
+ }
105
+
106
+ export { }