@yaklabs-ai/plugin-sdk 0.13.2 → 0.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,16 +13,16 @@ it under the name your plugin code actually imports:
13
13
  ```json
14
14
  {
15
15
  "dependencies": {
16
- "@kay/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.13.2"
16
+ "@bonsai/plugin-sdk": "npm:@yaklabs-ai/plugin-sdk@^0.13.4"
17
17
  }
18
18
  }
19
19
  ```
20
20
 
21
21
  **The alias is not cosmetic.** The package is published as
22
22
  `@yaklabs-ai/plugin-sdk`, but Bonsai's daemon resolves the specifier
23
- `@kay/plugin-sdk` when it loads your entrypoint, so that is the name your source
23
+ `@bonsai/plugin-sdk` when it loads your entrypoint, so that is the name your source
24
24
  must import. The alias installs the published package at
25
- `node_modules/@kay/plugin-sdk`, satisfying both.
25
+ `node_modules/@bonsai/plugin-sdk`, satisfying both.
26
26
 
27
27
  <details>
28
28
  <summary>Installing a release older than 0.8.0</summary>
@@ -48,7 +48,7 @@ this.
48
48
  Working with an agent? This package ships the skill that teaches one the whole
49
49
  authoring flow — scaffold, the SDK resolution contract, the reload loop, and
50
50
  the diagnostics to read when a plugin does not load. Point your agent at
51
- `node_modules/@kay/plugin-sdk/skills/directory-plugin-authoring/SKILL.md`
51
+ `node_modules/@bonsai/plugin-sdk/skills/directory-plugin-authoring/SKILL.md`
52
52
  before it writes any plugin code.
53
53
 
54
54
  ```ts
@@ -58,7 +58,7 @@ import {
58
58
  toolParameters,
59
59
  z,
60
60
  type KayAgentActivate,
61
- } from "@kay/plugin-sdk/kay-agent";
61
+ } from "@bonsai/plugin-sdk/kay-agent";
62
62
 
63
63
  const greet = defineTool({
64
64
  name: "widgets_greet",
@@ -79,12 +79,12 @@ export default activate;
79
79
 
80
80
  ## Entrypoints
81
81
 
82
- | Import | What it gives you |
83
- | ----------------------------------- | ---------------------------------------------------------------------------- |
84
- | `@kay/plugin-sdk/kay-agent` | Tools, URI modules, search providers, auth — the per-session agent surface |
85
- | `@kay/plugin-sdk/kay-app` | App-lifetime surface: storage, endpoints, app-scoped URI modules |
86
- | `@kay/plugin-sdk/kay-agent/testing` | `invokeToolForTest`, `fauxAuthContext` — for your own `node --test` runs |
87
- | `@kay/plugin-sdk/disclosure` | The conformance audit Bonsai gates your plugin with — run it before you ship |
82
+ | Import | What it gives you |
83
+ | -------------------------------------- | ---------------------------------------------------------------------------- |
84
+ | `@bonsai/plugin-sdk/kay-agent` | Tools, URI modules, search providers, auth — the per-session agent surface |
85
+ | `@bonsai/plugin-sdk/kay-app` | App-lifetime surface: storage, endpoints, app-scoped URI modules |
86
+ | `@bonsai/plugin-sdk/kay-agent/testing` | `invokeToolForTest`, `fauxAuthContext` — for your own `node --test` runs |
87
+ | `@bonsai/plugin-sdk/disclosure` | The conformance audit Bonsai gates your plugin with — run it before you ship |
88
88
 
89
89
  `kay-agent/host` is intentionally not published; it is Bonsai's own loading
90
90
  machinery, not an authoring API.
@@ -100,7 +100,7 @@ run below is the run Bonsai does.
100
100
  import {
101
101
  auditPluginDisclosure,
102
102
  collectUriModulesFromKayAgentActivate,
103
- } from "@kay/plugin-sdk/disclosure";
103
+ } from "@bonsai/plugin-sdk/disclosure";
104
104
 
105
105
  import activate from "../src/kay-agent.ts";
106
106
  import manifest from "../kay-plugin.json" with { type: "json" };
@@ -152,7 +152,7 @@ Installing this SDK gives you **types, editor completion, and a runtime you can
152
152
  execute in your own tests**. It is not what runs inside Bonsai.
153
153
 
154
154
  When the daemon loads your plugin, chord bundles its declared target and keeps
155
- `@kay/plugin-sdk/*` as a host external. Those imports resolve to the SDK
155
+ `@bonsai/plugin-sdk/*` as a host external. Those imports resolve to the SDK
156
156
  **bundled with the Bonsai app**. The host's copy always wins. That is deliberate —
157
157
  one implementation, the one the daemon is built against — but it has a
158
158
  consequence worth stating plainly:
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "package": "@yaklabs-ai/plugin-sdk",
4
- "version": "0.13.2",
4
+ "version": "0.13.4",
5
5
  "target": "npm",
6
6
  "firstPartyLicense": "MIT",
7
7
  "bundled": [
@@ -271,6 +271,10 @@ declare interface BackgroundTaskCompletion {
271
271
  readonly resultDelivery?: BackgroundTaskResultDelivery;
272
272
  readonly output?: string;
273
273
  readonly error?: string;
274
+ /** The thrown Error's stack, when a failed task threw one. */
275
+ readonly errorStack?: string;
276
+ /** Why a failed AGENT task's run failed, classified from what it threw; absent for other kinds. */
277
+ readonly failureReason?: RunFailureReason;
274
278
  }
275
279
 
276
280
  declare type BackgroundTaskInspector = () => Promise<string> | string;
@@ -346,14 +350,14 @@ export declare interface CapturedKayAgentAuthDeclarations {
346
350
  * Api-key schemes declared this run — the `displayName`/`inputLabel`/`setup`/`validate`
347
351
  * runtime declaration a manifest's identity-only scheme row cannot carry. Daemon acquisition
348
352
  * composition maps these onto the connect dispatch's api-key roster the same way
349
- * `oauthPkceSchemes` maps onto the PKCE arm — see `@kay/agent-runtime`'s `kay/composition/`.
353
+ * `oauthPkceSchemes` maps onto the PKCE arm — see `@bonsai/agent-runtime`'s `kay/composition/`.
350
354
  * Empty for a plugin that declares none.
351
355
  */
352
356
  readonly apiKeySchemes: readonly CapturedApiKeyDeclaration[];
353
357
  /**
354
358
  * Delegated schemes declared this run. Daemon acquisition composition maps these onto a
355
359
  * delegated connect-roster entry the same way `oauthPkceSchemes` maps onto the PKCE arm — see
356
- * `@kay/agent-runtime`'s `kay/composition/`. Empty for a plugin that declares none.
360
+ * `@bonsai/agent-runtime`'s `kay/composition/`. Empty for a plugin that declares none.
357
361
  */
358
362
  readonly delegatedSchemes: readonly CapturedDelegatedDeclaration[];
359
363
  }
@@ -664,7 +668,7 @@ declare interface ImageContent {
664
668
 
665
669
  /**
666
670
  * The value a Browser Interaction driver sets as `credentialGuard` to declare that every act runs
667
- * the page-side credential guard from `@kay/interaction-page-scripts` (never type into or click a
671
+ * the page-side credential guard from `@bonsai/interaction-page-scripts` (never type into or click a
668
672
  * sign-in form). The engine refuses to register a browser driver without it.
669
673
  */
670
674
  declare const INTERACTION_CREDENTIAL_GUARD = "kay.credential-guard/v1";
@@ -969,7 +973,7 @@ declare interface JevScoreQuestion {
969
973
  * - The wire. The host serves `classify` over whichever route the user's Jev provider order
970
974
  * picks; a plugin never sees a vendor client, a vendor type, or a route.
971
975
  * - Credential resolution, the `jev.use` decision, the Jev-branch budget, or usage accounting.
972
- * Those are host-side (`@kay/agent-runtime`'s `kay/jev/`).
976
+ * Those are host-side (`@bonsai/agent-runtime`'s `kay/jev/`).
973
977
  * ---
974
978
  *
975
979
  * The vocabulary is Bonsai's own (SDK 0.12.0). Before it, `use` received TypeSafe's `TypeSafeClient`
@@ -1515,7 +1519,7 @@ declare interface KayAppTimeSnapshot {
1515
1519
  * The time zone the user is in, as an IANA id in the spelling ICU resolves (`America/New_York`).
1516
1520
  * One zone can have two ids, and ICU picks one: `Asia/Kolkata` comes back as `Asia/Calcutta`. So
1517
1521
  * never compare zone ids with `===`. A first-party plugin compares with `sameZone` from
1518
- * `@kay/time`. A plugin that imports only this SDK and node builtins resolves each id with
1522
+ * `@bonsai/time`. A plugin that imports only this SDK and node builtins resolves each id with
1519
1523
  * `new Intl.DateTimeFormat("en-US", { timeZone: id }).resolvedOptions().timeZone` and compares the
1520
1524
  * results. Pass `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a
1521
1525
  * time for the user.
@@ -2406,6 +2410,28 @@ declare interface ResolveTokenSuccess {
2406
2410
  readonly auth: ResolvedAuth;
2407
2411
  }
2408
2412
 
2413
+ /**
2414
+ * Pure, provider-neutral classification of a failed model run.
2415
+ *
2416
+ * This is a leaf module with no runtime imports, because two callers that
2417
+ * cannot share a bundle must reach the same verdict: the kernel failure path
2418
+ * (`run-error.ts`, which reaches Pi and Node) and the browser-safe interactive
2419
+ * reducer that projects an errored message for a surface to render. Routing the
2420
+ * reducer through `run-error.ts` would drag `pi-agent-core` into the renderer
2421
+ * bundle; duplicating the rules there would let the reason a run was *retried
2422
+ * for* drift from the reason a user is *told about*.
2423
+ *
2424
+ * The leaf rule is why {@link readableFailureText} carries its own small HTML
2425
+ * extractor instead of reaching for `core/web/markdown.ts`. That module imports
2426
+ * `@herd/plugin-primitives`, and the browser-safety guard externalizes bare
2427
+ * specifiers, so it could not prove the import stays renderer-safe. It is also
2428
+ * the wrong tool: it emits markdown into what must remain a plain diagnostic,
2429
+ * and it discards `<head>`, where a gateway page puts the one line naming the
2430
+ * failure.
2431
+ */
2432
+ /** Provider-neutral factual category for a failed model run. */
2433
+ declare type RunFailureReason = "auth" | "content_blocked" | "context_overflow" | "invalid_request" | "model_unavailable" | "network" | "overloaded" | "quota_exhausted" | "rate_limit" | "safeguard_block" | "seat_unpaid" | "server_error" | "stream_interrupted" | "timeout" | "unknown";
2434
+
2409
2435
  /** One all-of arm in an ordered scope requirement. */
2410
2436
  declare interface ScopeAlternative {
2411
2437
  readonly allOf: readonly ScopeNeed[];
@@ -3915,7 +3941,7 @@ declare interface UriValidationMessage {
3915
3941
  * applies label changes"), never wire mechanics or URI shapes. Verbs the
3916
3942
  * module does not support are omitted; at runtime a supported verb with no
3917
3943
  * entry simply renders undocumented (fail-open metadata) — but for a plugin's
3918
- * `kay.agent` URI modules, `auditPluginDisclosure` (`@kay/plugin-sdk/
3944
+ * `kay.agent` URI modules, `auditPluginDisclosure` (`@bonsai/plugin-sdk/
3919
3945
  * disclosure`) enforces coverage of every supported verb at authoring/load
3920
3946
  * time.
3921
3947
  *
package/dist/fs.js CHANGED
@@ -156,7 +156,7 @@ function abortError(signal) {
156
156
  return assignFields(error, { code: "ABORT_ERR" });
157
157
  }
158
158
  function unsupported(syscall, what) {
159
- return kayError(KAY_FS_UNSUPPORTED, `${what} is not supported by @kay/plugin-sdk/fs`, syscall, void 0);
159
+ return kayError(KAY_FS_UNSUPPORTED, `${what} is not supported by @bonsai/plugin-sdk/fs`, syscall, void 0);
160
160
  }
161
161
  function finishedOf(error) {
162
162
  return error?.[FINISHED];
package/dist/jev.d.ts CHANGED
@@ -135,7 +135,7 @@ export declare interface JevScoreQuestion {
135
135
  * - The wire. The host serves `classify` over whichever route the user's Jev provider order
136
136
  * picks; a plugin never sees a vendor client, a vendor type, or a route.
137
137
  * - Credential resolution, the `jev.use` decision, the Jev-branch budget, or usage accounting.
138
- * Those are host-side (`@kay/agent-runtime`'s `kay/jev/`).
138
+ * Those are host-side (`@bonsai/agent-runtime`'s `kay/jev/`).
139
139
  * ---
140
140
  *
141
141
  * The vocabulary is Bonsai's own (SDK 0.12.0). Before it, `use` received TypeSafe's `TypeSafeClient`
@@ -225,6 +225,10 @@ declare interface BackgroundTaskCompletion {
225
225
  readonly resultDelivery?: BackgroundTaskResultDelivery;
226
226
  readonly output?: string;
227
227
  readonly error?: string;
228
+ /** The thrown Error's stack, when a failed task threw one. */
229
+ readonly errorStack?: string;
230
+ /** Why a failed AGENT task's run failed, classified from what it threw; absent for other kinds. */
231
+ readonly failureReason?: RunFailureReason;
228
232
  }
229
233
 
230
234
  declare type BackgroundTaskInspector = () => Promise<string> | string;
@@ -550,7 +554,7 @@ declare interface ImageContent {
550
554
 
551
555
  /**
552
556
  * The value a Browser Interaction driver sets as `credentialGuard` to declare that every act runs
553
- * the page-side credential guard from `@kay/interaction-page-scripts` (never type into or click a
557
+ * the page-side credential guard from `@bonsai/interaction-page-scripts` (never type into or click a
554
558
  * sign-in form). The engine refuses to register a browser driver without it.
555
559
  */
556
560
  declare const INTERACTION_CREDENTIAL_GUARD = "kay.credential-guard/v1";
@@ -873,7 +877,7 @@ declare interface JevScoreQuestion {
873
877
  * - The wire. The host serves `classify` over whichever route the user's Jev provider order
874
878
  * picks; a plugin never sees a vendor client, a vendor type, or a route.
875
879
  * - Credential resolution, the `jev.use` decision, the Jev-branch budget, or usage accounting.
876
- * Those are host-side (`@kay/agent-runtime`'s `kay/jev/`).
880
+ * Those are host-side (`@bonsai/agent-runtime`'s `kay/jev/`).
877
881
  * ---
878
882
  *
879
883
  * The vocabulary is Bonsai's own (SDK 0.12.0). Before it, `use` received TypeSafe's `TypeSafeClient`
@@ -1416,7 +1420,7 @@ declare interface KayAppTimeSnapshot {
1416
1420
  * The time zone the user is in, as an IANA id in the spelling ICU resolves (`America/New_York`).
1417
1421
  * One zone can have two ids, and ICU picks one: `Asia/Kolkata` comes back as `Asia/Calcutta`. So
1418
1422
  * never compare zone ids with `===`. A first-party plugin compares with `sameZone` from
1419
- * `@kay/time`. A plugin that imports only this SDK and node builtins resolves each id with
1423
+ * `@bonsai/time`. A plugin that imports only this SDK and node builtins resolves each id with
1420
1424
  * `new Intl.DateTimeFormat("en-US", { timeZone: id }).resolvedOptions().timeZone` and compares the
1421
1425
  * results. Pass `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a
1422
1426
  * time for the user.
@@ -2304,6 +2308,28 @@ declare interface ResolveTokenSuccess {
2304
2308
  readonly auth: ResolvedAuth;
2305
2309
  }
2306
2310
 
2311
+ /**
2312
+ * Pure, provider-neutral classification of a failed model run.
2313
+ *
2314
+ * This is a leaf module with no runtime imports, because two callers that
2315
+ * cannot share a bundle must reach the same verdict: the kernel failure path
2316
+ * (`run-error.ts`, which reaches Pi and Node) and the browser-safe interactive
2317
+ * reducer that projects an errored message for a surface to render. Routing the
2318
+ * reducer through `run-error.ts` would drag `pi-agent-core` into the renderer
2319
+ * bundle; duplicating the rules there would let the reason a run was *retried
2320
+ * for* drift from the reason a user is *told about*.
2321
+ *
2322
+ * The leaf rule is why {@link readableFailureText} carries its own small HTML
2323
+ * extractor instead of reaching for `core/web/markdown.ts`. That module imports
2324
+ * `@herd/plugin-primitives`, and the browser-safety guard externalizes bare
2325
+ * specifiers, so it could not prove the import stays renderer-safe. It is also
2326
+ * the wrong tool: it emits markdown into what must remain a plain diagnostic,
2327
+ * and it discards `<head>`, where a gateway page puts the one line naming the
2328
+ * failure.
2329
+ */
2330
+ /** Provider-neutral factual category for a failed model run. */
2331
+ declare type RunFailureReason = "auth" | "content_blocked" | "context_overflow" | "invalid_request" | "model_unavailable" | "network" | "overloaded" | "quota_exhausted" | "rate_limit" | "safeguard_block" | "seat_unpaid" | "server_error" | "stream_interrupted" | "timeout" | "unknown";
2332
+
2307
2333
  /** One all-of arm in an ordered scope requirement. */
2308
2334
  declare interface ScopeAlternative {
2309
2335
  readonly allOf: readonly ScopeNeed[];
@@ -3813,7 +3839,7 @@ declare interface UriValidationMessage {
3813
3839
  * applies label changes"), never wire mechanics or URI shapes. Verbs the
3814
3840
  * module does not support are omitted; at runtime a supported verb with no
3815
3841
  * entry simply renders undocumented (fail-open metadata) — but for a plugin's
3816
- * `kay.agent` URI modules, `auditPluginDisclosure` (`@kay/plugin-sdk/
3842
+ * `kay.agent` URI modules, `auditPluginDisclosure` (`@bonsai/plugin-sdk/
3817
3843
  * disclosure`) enforces coverage of every supported verb at authoring/load
3818
3844
  * time.
3819
3845
  *
@@ -244,7 +244,7 @@ export declare function asArray(value: unknown): readonly unknown[];
244
244
  * - {@link asRecord}, {@link asArray}, {@link str}, {@link num}, {@link numLike}.
245
245
  * does_not_own:
246
246
  * - Schema-shaped validation. **Idiom-routing rule (read before reaching for these):** `z`
247
- * (re-exported from this same `@kay/plugin-sdk/kay-agent` module) is the default for
247
+ * (re-exported from this same `@bonsai/plugin-sdk/kay-agent` module) is the default for
248
248
  * anything shape-contractual — a tool's own `parameters` (via `toolParameters`), and any
249
249
  * upstream response you're going to treat as a stable contract going forward. Reach for these
250
250
  * readers only for **tolerant salvage**: pulling one or two fields out of a response whose
@@ -315,6 +315,10 @@ declare interface BackgroundTaskCompletion {
315
315
  readonly resultDelivery?: BackgroundTaskResultDelivery;
316
316
  readonly output?: string;
317
317
  readonly error?: string;
318
+ /** The thrown Error's stack, when a failed task threw one. */
319
+ readonly errorStack?: string;
320
+ /** Why a failed AGENT task's run failed, classified from what it threw; absent for other kinds. */
321
+ readonly failureReason?: RunFailureReason;
318
322
  }
319
323
 
320
324
  declare type BackgroundTaskInspector = () => Promise<string> | string;
@@ -611,6 +615,9 @@ export declare interface CreateJsonApiClientOptions {
611
615
  readonly fetch?: typeof fetch;
612
616
  }
613
617
 
618
+ /** One plugin's runner: its module, its label, and the app-specific failures it names. */
619
+ export declare function createOsascriptRunner(options: OsascriptRunnerOptions): OsascriptRunner;
620
+
614
621
  /** What the module holds at mutation time: a provider revision, the current content, or both. */
615
622
  export declare interface CurrentResourceState {
616
623
  readonly revision?: string;
@@ -831,6 +838,12 @@ declare interface ExtensionPaths {
831
838
  readonly dataDir: string;
832
839
  }
833
840
 
841
+ /**
842
+ * Several lines of text inside a code fence none of its lines can close, so a message body or an
843
+ * invitation's notes cannot pass for a heading or a field of the read around them.
844
+ */
845
+ export declare function fenced(text: string): readonly string[];
846
+
834
847
  export declare function formatIsoDate(value?: string | number | Date): string;
835
848
 
836
849
  export declare function formatNumber(n: number): string;
@@ -881,7 +894,7 @@ declare type InferToolInput<TParams extends ToolParametersWire> = TParams extend
881
894
 
882
895
  /**
883
896
  * The value a Browser Interaction driver sets as `credentialGuard` to declare that every act runs
884
- * the page-side credential guard from `@kay/interaction-page-scripts` (never type into or click a
897
+ * the page-side credential guard from `@bonsai/interaction-page-scripts` (never type into or click a
885
898
  * sign-in form). The engine refuses to register a browser driver without it.
886
899
  */
887
900
  export declare const INTERACTION_CREDENTIAL_GUARD = "kay.credential-guard/v1";
@@ -1221,7 +1234,7 @@ export declare interface JevScoreQuestion {
1221
1234
  * - The wire. The host serves `classify` over whichever route the user's Jev provider order
1222
1235
  * picks; a plugin never sees a vendor client, a vendor type, or a route.
1223
1236
  * - Credential resolution, the `jev.use` decision, the Jev-branch budget, or usage accounting.
1224
- * Those are host-side (`@kay/agent-runtime`'s `kay/jev/`).
1237
+ * Those are host-side (`@bonsai/agent-runtime`'s `kay/jev/`).
1225
1238
  * ---
1226
1239
  *
1227
1240
  * The vocabulary is Bonsai's own (SDK 0.12.0). Before it, `use` received TypeSafe's `TypeSafeClient`
@@ -1875,7 +1888,7 @@ declare interface KayAppTimeSnapshot {
1875
1888
  * The time zone the user is in, as an IANA id in the spelling ICU resolves (`America/New_York`).
1876
1889
  * One zone can have two ids, and ICU picks one: `Asia/Kolkata` comes back as `Asia/Calcutta`. So
1877
1890
  * never compare zone ids with `===`. A first-party plugin compares with `sameZone` from
1878
- * `@kay/time`. A plugin that imports only this SDK and node builtins resolves each id with
1891
+ * `@bonsai/time`. A plugin that imports only this SDK and node builtins resolves each id with
1879
1892
  * `new Intl.DateTimeFormat("en-US", { timeZone: id }).resolvedOptions().timeZone` and compares the
1880
1893
  * results. Pass `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a
1881
1894
  * time for the user.
@@ -2823,6 +2836,35 @@ declare type KnownApi = "openai-completions" | "mistral-conversations" | "openai
2823
2836
 
2824
2837
  declare type KnownProvider = "amazon-bedrock" | "ant-ling" | "anthropic" | "google" | "google-vertex" | "openai" | "azure-openai-responses" | "openai-codex" | "radius" | "typesafe" | "nvidia" | "deepseek" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "zai-coding-cn" | "mistral" | "minimax" | "minimax-cn" | "moonshotai" | "moonshotai-cn" | "huggingface" | "fireworks" | "together" | "baseten" | "opencode" | "opencode-go" | "kimi-coding" | "meta" | "cloudflare-workers-ai" | "cloudflare-ai-gateway" | "qwen-token-plan" | "qwen-token-plan-cn" | "qwen-token-plan-individual" | "xiaomi" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-sgp";
2825
2838
 
2839
+ /**
2840
+ * A one-line label the host prints verbatim, such as an approval card's target. Line breaks,
2841
+ * other control characters, and line or paragraph separators become spaces, and invisible format
2842
+ * characters go: a zero-width joiner inside an emoji, a soft hyphen, a direction mark, a
2843
+ * zero-width space. The host refuses a target holding any of them, and drops the whole approval
2844
+ * card with it (`admitDescription` in herd-agent's `action-summary.ts`).
2845
+ */
2846
+ export declare function labelOf(value: string | null | undefined): string;
2847
+
2848
+ /**
2849
+ * ---
2850
+ * responsibility: The flat authoring-helper layer's untrusted-text surface (decision 002,
2851
+ * kay#11957): render text someone else wrote (a shared calendar's name, a contact card synced
2852
+ * from another account, an email body) into a plugin's Markdown output or an approval card
2853
+ * without it forging structure around it. Apple Mail, Calendar, and Contacts had each grown a
2854
+ * copy.
2855
+ * owns:
2856
+ * - {@link lineOf}, {@link labelOf}, {@link markdownText}, {@link fenced}.
2857
+ * does_not_own:
2858
+ * - Deciding which fields are untrusted. Every value the user does not control is; the plugin
2859
+ * routes each one through these before it reaches output.
2860
+ * ---
2861
+ */
2862
+ /**
2863
+ * A one-line field: every whitespace run, newlines included, becomes one space, so a value can
2864
+ * never open a line of its own (one that passes for an `Account:` line, for instance).
2865
+ */
2866
+ export declare function lineOf(value: string | null | undefined): string;
2867
+
2826
2868
  declare interface LineRange {
2827
2869
  readonly start: number;
2828
2870
  readonly end: number;
@@ -2840,6 +2882,17 @@ export declare function lintUriTemplate(template: UriTemplate): readonly UriTemp
2840
2882
 
2841
2883
  export declare function markdownResource(uri: string, md: string, notes?: string[]): RawResource;
2842
2884
 
2885
+ /**
2886
+ * Text placed mid-line, after a label, that cannot forge a link, an image, an HTML tag, or a
2887
+ * field: a backslash goes before `[`, `]`, `!`, and `<`; before `|`, which a plugin may use to
2888
+ * separate the fields of a one-line summary; and before a backslash, so no escape can be undone.
2889
+ *
2890
+ * It does not neutralize everything Markdown does. Line-start syntax (`#`, `>`, `-`, `1.`),
2891
+ * emphasis, code spans, and bare-URL autolinks still render, so keep the value off the start of a
2892
+ * line (behind a label, after {@link lineOf}) or use {@link fenced} for whole blocks.
2893
+ */
2894
+ export declare function markdownText(text: string): string;
2895
+
2843
2896
  /**
2844
2897
  * The execute-time surface a tool sees. These are the only fields a {@link ToolDefinition.execute}
2845
2898
  * body can read. Runtime-optionals are absent without a live session: a tool invoked from a
@@ -3276,11 +3329,183 @@ declare interface OpenRouterRouting {
3276
3329
  };
3277
3330
  }
3278
3331
 
3332
+ /**
3333
+ * The JXA half of the envelope: paste it into a script's source, then end `run(argv)` with
3334
+ * `return jsonOk(data)` or `return jsonFail(code, message)`. {@link readOsascriptOutput} reads
3335
+ * exactly what these print. Both are total: `jsonOk()` with no value answers `null` (JSON drops an
3336
+ * `undefined` key, which the reader would refuse), and `jsonFail` turns its code and message into
3337
+ * strings, so a thrown non-Error or an Error object passed as the message still reaches the
3338
+ * caller as this script's refusal, under its own code.
3339
+ */
3340
+ export declare const OSASCRIPT_ENVELOPE_JXA = "\nfunction jsonOk(data) {\n return JSON.stringify({ ok: true, data: data === undefined ? null : data });\n}\nfunction jsonFail(code, message) {\n return JSON.stringify({ ok: false, error: { code: String(code), message: String(message) } });\n}\n";
3341
+
3342
+ /** The runner's kill deadline when a call names none. */
3343
+ export declare const OSASCRIPT_TIMEOUT_MS = 30000;
3344
+
3345
+ /**
3346
+ * The argv for one script run: JavaScript, the script as a fixed `-e` constant, then `--` and the
3347
+ * dynamic values. `--` ends osascript's own option parsing: without it, a value in the first argv
3348
+ * slot that starts with `-` (a search for "-budget", a folder named "-Archive") is taken as an
3349
+ * option and the script never runs (the Apple Notes plugin verified this live). User values only
3350
+ * ever travel here, never in the script source: that is the injection boundary.
3351
+ */
3352
+ export declare function osascriptArgs(script: string, argv: readonly string[]): readonly string[];
3353
+
3354
+ /** One script run: what the error names, and the bounds the runner enforces. */
3355
+ export declare interface OsascriptCall {
3356
+ readonly operation: UriOperation;
3357
+ readonly uri: string;
3358
+ readonly signal?: AbortSignal | undefined;
3359
+ readonly maxOutputChars: number;
3360
+ /** The runner's kill deadline; absent means {@link OSASCRIPT_TIMEOUT_MS}. */
3361
+ readonly timeoutMs?: number;
3362
+ /** What to do when the output is too large; absent means "narrow the request". */
3363
+ readonly truncatedAdvice?: string;
3364
+ /**
3365
+ * Set for a script that changes the app: the sentence that ends the error when its run fails
3366
+ * before Bonsai reads its answer, such as "The event may have been created: search
3367
+ * apple-calendar://events before trying again." The script may have saved before the runner
3368
+ * failed, osascript stopped (a timeout or a cancel), or its output became unreadable. A refusal
3369
+ * the script returns itself (`jsonFail`) does not end with this sentence: a script refuses
3370
+ * before it changes anything.
3371
+ */
3372
+ readonly outcomeUnknown?: string;
3373
+ }
3374
+
3375
+ /** The runner a module's verbs use, with a simulator in the host's place when one is set. */
3376
+ export declare interface OsascriptDispatch {
3377
+ /**
3378
+ * {@link OsascriptRunner.requireExternalCli}, then the simulator's runner in the host's place.
3379
+ * The host's runner is required either way: its absence is how a not-connected service fails.
3380
+ */
3381
+ readonly requireExternalCli: (ctx: UriResolveContext, operation: UriOperation, uri: string) => UriExternalCliRunner;
3382
+ /**
3383
+ * The runner for a path that tolerates its absence (an approval card's lookup): `undefined`
3384
+ * when the host injected none, the simulator's when one is set, the host's otherwise.
3385
+ */
3386
+ readonly externalCliOf: (ctx: UriResolveContext) => UriExternalCliRunner | undefined;
3387
+ }
3388
+
3389
+ /** A failure the plugin names: its own code, and the advice that ends the message. */
3390
+ export declare interface OsascriptFailureAdvice {
3391
+ readonly code: string;
3392
+ readonly advice: string;
3393
+ }
3394
+
3395
+ /**
3396
+ * The activation options every osascript plugin's agent factory accepts
3397
+ * (`createAppleCalendarKayAgent(options)`), so the daemon's simulator roster sets each the same
3398
+ * way. Absent `simulator`, the plugin is exactly the shipped one.
3399
+ */
3400
+ export declare interface OsascriptKayAgentOptions {
3401
+ readonly simulator?: OsascriptSimulatorOptions;
3402
+ }
3403
+
3404
+ /** What a script's stdout says, once read. */
3405
+ export declare type OsascriptOutput =
3406
+ /** `jsonOk(data)`. `data` is unchecked: validate it against the script's own shape. */
3407
+ {
3408
+ readonly kind: "data";
3409
+ readonly data: unknown;
3410
+ }
3411
+ /** `jsonFail(code, message)`: the script refused on its own terms. */
3412
+ | {
3413
+ readonly kind: "refused";
3414
+ readonly code: string;
3415
+ readonly message: string;
3416
+ }
3417
+ /**
3418
+ * Not JSON, or JSON that is not an envelope (`null`, `{}`, `42`, `{"ok":false}`, and
3419
+ * `{"ok":true}` with no `data` key, which {@link OSASCRIPT_ENVELOPE_JXA}'s `jsonOk` never prints).
3420
+ */
3421
+ | {
3422
+ readonly kind: "invalid";
3423
+ readonly reason: string;
3424
+ };
3425
+
3426
+ export declare interface OsascriptRunner {
3427
+ /**
3428
+ * The host-injected runner, or the `auth_required` error the host classifies as not
3429
+ * connected: the in-handler twin of the host's pre-dispatch auth resolution.
3430
+ */
3431
+ readonly requireExternalCli: (ctx: UriResolveContext, operation: UriOperation, uri: string) => UriExternalCliRunner;
3432
+ /**
3433
+ * The runners a module's verbs use: the host's exactly when `simulator` is absent, or the
3434
+ * simulator's in its place, per dispatch, after the host's connection gate.
3435
+ */
3436
+ readonly dispatch: (simulator: OsascriptSimulatedRunner | undefined) => OsascriptDispatch;
3437
+ /**
3438
+ * Run `script` with `argv` and return the data it answered (unchecked: validate it). Every
3439
+ * other outcome throws a `UriProviderError`, except a runner that throws on its own: that
3440
+ * error passes through unchanged unless the call sets `outcomeUnknown`.
3441
+ */
3442
+ readonly runScript: (externalCli: UriExternalCliRunner, script: string, argv: readonly string[], call: OsascriptCall) => Promise<unknown>;
3443
+ /** A `UriProviderError` from this plugin's module, never retryable. */
3444
+ readonly providerError: (call: Pick<OsascriptCall, "operation" | "uri">, providerCode: string, message: string) => UriProviderError;
3445
+ /**
3446
+ * The error for a run that exited non-zero, for a caller that reads the runner's result
3447
+ * itself (a send path that reads progress markers from stderr). Ends with the call's
3448
+ * `outcomeUnknown` sentence when it has one.
3449
+ */
3450
+ readonly scriptFailure: (call: OsascriptCall, result: Pick<UriExternalCliRunResult, "stderr" | "stdout">) => UriProviderError;
3451
+ }
3452
+
3453
+ export declare interface OsascriptRunnerOptions {
3454
+ /** The URI module every error names. */
3455
+ readonly moduleId: string;
3456
+ /** The service a missing runner tells the agent to connect. */
3457
+ readonly serviceId: string;
3458
+ /** The product name that opens each message, such as "Apple Calendar". */
3459
+ readonly label: string;
3460
+ /**
3461
+ * What opens the message of a failed run; absent means "<label> automation failed". A plugin
3462
+ * that scripts no app (its JXA calls a framework directly) says "<label> script failed".
3463
+ */
3464
+ readonly failurePrefix?: string;
3465
+ /**
3466
+ * Advice for macOS refusing the Apple Event (`-1743`, "not authorized"): the Automation grant
3467
+ * is missing or revoked. Set, such a run fails `automation-denied` with this advice; absent,
3468
+ * it is an ordinary `script-failed`.
3469
+ */
3470
+ readonly automationDeniedAdvice?: string;
3471
+ /**
3472
+ * The plugin's code and advice for its app quitting mid-run: `-600` (application isn't
3473
+ * running) before the script's first Apple Event, `-609` (connection is invalid) after it.
3474
+ * Absent, such a run is an ordinary `script-failed`. The check a script makes itself
3475
+ * (`running()`, then `jsonFail`) is the plugin's, and comes back as that refusal.
3476
+ */
3477
+ readonly appNotRunning?: OsascriptFailureAdvice;
3478
+ }
3479
+
3480
+ /** A plugin's simulator, as the runner sees it: the runner one dispatch uses in the host's place. */
3481
+ export declare interface OsascriptSimulatedRunner {
3482
+ readonly runnerFor: (ctx: UriResolveContext) => UriExternalCliRunner;
3483
+ }
3484
+
3485
+ /**
3486
+ * How a plugin is told to serve its module from its simulator instead of osascript: the one
3487
+ * option shape every osascript plugin's agent factory accepts as `simulator`. Only the daemon's
3488
+ * URI simulator roster sets it, for evals and dev; an ordinary install never does.
3489
+ */
3490
+ export declare interface OsascriptSimulatorOptions {
3491
+ /** The directory holding the simulator's world; the daemon's process config names it. */
3492
+ readonly stateDir: string;
3493
+ }
3494
+
3279
3495
  export declare function parseLineSelector(input: string): {
3280
3496
  address: string;
3281
3497
  selector: LineSelector;
3282
3498
  };
3283
3499
 
3500
+ /**
3501
+ * The script and argv of a request {@link osascriptArgs} built, or `undefined` for any other
3502
+ * argv. A simulated runner reads requests through this, so the argv layout has one owner.
3503
+ */
3504
+ export declare function parseOsascriptArgs(args: readonly string[]): {
3505
+ readonly script: string;
3506
+ readonly argv: readonly string[];
3507
+ } | undefined;
3508
+
3284
3509
  export declare function parseUriConnectionSelector(input: string): UriConnectionSelectorParse;
3285
3510
 
3286
3511
  /** Parse either dialect into the normalized replacement list. */
@@ -3889,6 +4114,9 @@ declare interface RawResourceMetadata {
3889
4114
  */
3890
4115
  export declare function readBodyWithByteCap(response: Response, maxBytes: number): Promise<ByteCapReadResult | undefined>;
3891
4116
 
4117
+ /** Read a script's stdout. Never throws: anything but a well-formed envelope is `invalid`. */
4118
+ export declare function readOsascriptOutput(stdout: string): OsascriptOutput;
4119
+
3892
4120
  /**
3893
4121
  * The capability⇄service auth binding. A registration carrying this is gated on `serviceId`'s
3894
4122
  * connectivity; the runtime answers "is this capability authorized?" from this plus vault state.
@@ -4003,6 +4231,28 @@ declare interface ResolveTokenSuccess {
4003
4231
  readonly auth: ResolvedAuth;
4004
4232
  }
4005
4233
 
4234
+ /**
4235
+ * Pure, provider-neutral classification of a failed model run.
4236
+ *
4237
+ * This is a leaf module with no runtime imports, because two callers that
4238
+ * cannot share a bundle must reach the same verdict: the kernel failure path
4239
+ * (`run-error.ts`, which reaches Pi and Node) and the browser-safe interactive
4240
+ * reducer that projects an errored message for a surface to render. Routing the
4241
+ * reducer through `run-error.ts` would drag `pi-agent-core` into the renderer
4242
+ * bundle; duplicating the rules there would let the reason a run was *retried
4243
+ * for* drift from the reason a user is *told about*.
4244
+ *
4245
+ * The leaf rule is why {@link readableFailureText} carries its own small HTML
4246
+ * extractor instead of reaching for `core/web/markdown.ts`. That module imports
4247
+ * `@herd/plugin-primitives`, and the browser-safety guard externalizes bare
4248
+ * specifiers, so it could not prove the import stays renderer-safe. It is also
4249
+ * the wrong tool: it emits markdown into what must remain a plain diagnostic,
4250
+ * and it discards `<head>`, where a gateway page puts the one line naming the
4251
+ * failure.
4252
+ */
4253
+ /** Provider-neutral factual category for a failed model run. */
4254
+ declare type RunFailureReason = "auth" | "content_blocked" | "context_overflow" | "invalid_request" | "model_unavailable" | "network" | "overloaded" | "quota_exhausted" | "rate_limit" | "safeguard_block" | "seat_unpaid" | "server_error" | "stream_interrupted" | "timeout" | "unknown";
4255
+
4006
4256
  export declare type SchemaInput = z.ZodType | JsonSchema;
4007
4257
 
4008
4258
  /** One all-of arm in an ordered scope requirement. */
@@ -5808,7 +6058,7 @@ declare interface UriValidationMessage {
5808
6058
  * applies label changes"), never wire mechanics or URI shapes. Verbs the
5809
6059
  * module does not support are omitted; at runtime a supported verb with no
5810
6060
  * entry simply renders undocumented (fail-open metadata) — but for a plugin's
5811
- * `kay.agent` URI modules, `auditPluginDisclosure` (`@kay/plugin-sdk/
6061
+ * `kay.agent` URI modules, `auditPluginDisclosure` (`@bonsai/plugin-sdk/
5812
6062
  * disclosure`) enforces coverage of every supported verb at authoring/load
5813
6063
  * time.
5814
6064
  *