@yaklabs-ai/plugin-sdk 0.13.1 → 0.13.3
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 +13 -13
- package/THIRD-PARTY-INVENTORY.json +1 -1
- package/dist/disclosure.d.ts +38 -6
- package/dist/fs.js +1 -1
- package/dist/jev.d.ts +1 -1
- package/dist/kay-agent-testing.d.ts +36 -4
- package/dist/kay-agent.d.ts +266 -5
- package/dist/kay-agent.js +169 -2
- package/dist/kay-app.d.ts +267 -18
- package/dist/kay-app.js +16 -0
- package/dist/signals.d.ts +2 -2
- package/package.json +1 -1
- package/skills/directory-plugin-authoring/SKILL.md +18 -18
package/dist/kay-app.d.ts
CHANGED
|
@@ -224,6 +224,10 @@ declare interface BackgroundTaskCompletion {
|
|
|
224
224
|
readonly resultDelivery?: BackgroundTaskResultDelivery;
|
|
225
225
|
readonly output?: string;
|
|
226
226
|
readonly error?: string;
|
|
227
|
+
/** The thrown Error's stack, when a failed task threw one. */
|
|
228
|
+
readonly errorStack?: string;
|
|
229
|
+
/** Why a failed AGENT task's run failed, classified from what it threw; absent for other kinds. */
|
|
230
|
+
readonly failureReason?: RunFailureReason;
|
|
227
231
|
}
|
|
228
232
|
|
|
229
233
|
declare type BackgroundTaskInspector = () => Promise<string> | string;
|
|
@@ -431,6 +435,18 @@ export declare function createFallbackOnlyWithJev(): WithJev;
|
|
|
431
435
|
*/
|
|
432
436
|
export declare function createUnavailableSkills(message: string): KayAppSkills;
|
|
433
437
|
|
|
438
|
+
/**
|
|
439
|
+
* The `app.tools` a host that cannot describe tools binds: every call answers `not-available`, so
|
|
440
|
+
* a plugin's code path never depends on host composition.
|
|
441
|
+
*/
|
|
442
|
+
export declare function createUnavailableTools(): KayAppTools;
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* A `KayAppUsage` that answers `unavailable` to every call: what a host with no telemetry lane
|
|
446
|
+
* binds, so `app.usage` stays present on every host.
|
|
447
|
+
*/
|
|
448
|
+
export declare function createUnavailableUsage(message: string): KayAppUsage;
|
|
449
|
+
|
|
434
450
|
declare interface CustomEntry extends EntryBase {
|
|
435
451
|
type: "custom";
|
|
436
452
|
customType: string;
|
|
@@ -759,7 +775,7 @@ export declare interface JevScoreQuestion {
|
|
|
759
775
|
* - The wire. The host serves `classify` over whichever route the user's Jev provider order
|
|
760
776
|
* picks; a plugin never sees a vendor client, a vendor type, or a route.
|
|
761
777
|
* - Credential resolution, the `jev.use` decision, the Jev-branch budget, or usage accounting.
|
|
762
|
-
* Those are host-side (`@
|
|
778
|
+
* Those are host-side (`@bonsai/agent-runtime`'s `kay/jev/`).
|
|
763
779
|
* ---
|
|
764
780
|
*
|
|
765
781
|
* The vocabulary is Bonsai's own (SDK 0.12.0). Before it, `use` received TypeSafe's `TypeSafeClient`
|
|
@@ -1149,6 +1165,24 @@ export declare interface KayAppAgentDefinition {
|
|
|
1149
1165
|
* position: the two are separately compared, so moving a rule between them is a different claim.
|
|
1150
1166
|
*/
|
|
1151
1167
|
readonly permissionsFallback?: readonly PluginAgentDefinitionPermissionRule[];
|
|
1168
|
+
/**
|
|
1169
|
+
* The URI schemes this definition's runs MAINTAIN, e.g. `["memory"]` for a job that curates,
|
|
1170
|
+
* prunes or rewrites the memory notebook. Bare scheme names, lowercase, no `://`.
|
|
1171
|
+
*
|
|
1172
|
+
* What it changes, and only this: a READ under a declared scheme, made by a session of this
|
|
1173
|
+
* definition or by any session in that session's family (its subagents, keyed by root), is not
|
|
1174
|
+
* counted as use of the resource in Bonsai's per-resource read activity (the `uriReadActivity`
|
|
1175
|
+
* metric, `analytics://memory`, and `app.usage`'s answers). A job that keeps a notebook tidy
|
|
1176
|
+
* reads old and irrelevant notes as a matter of course, and counting those reads would make
|
|
1177
|
+
* every note it touches look used. Reads by every other session, including other background
|
|
1178
|
+
* jobs, still count: a job that reads a note to do its own work found the note useful.
|
|
1179
|
+
*
|
|
1180
|
+
* It confers no authority and removes none. The host re-reads it from the live definition at
|
|
1181
|
+
* every activation, like {@link permissions}, and stamps it on the session's activation row.
|
|
1182
|
+
* Adding or removing one scheme here is the whole switch for moving a job between the excluded
|
|
1183
|
+
* and the counted side. Absent means the job maintains nothing. SDK 0.13.3.
|
|
1184
|
+
*/
|
|
1185
|
+
readonly maintains?: readonly string[];
|
|
1152
1186
|
}
|
|
1153
1187
|
|
|
1154
1188
|
/** The inert session-config subset a plugin-authored agent definition may contribute. */
|
|
@@ -1921,8 +1955,8 @@ export declare interface KayAppConfig {
|
|
|
1921
1955
|
/**
|
|
1922
1956
|
* Where a folded config value's winner was defined: the config LEVEL that won and the absolute
|
|
1923
1957
|
* path of the winning file. A JSON-safe twin of the runtime's `KayConfigValueOrigin`
|
|
1924
|
-
* (`@
|
|
1925
|
-
* here and an assignability test in `@
|
|
1958
|
+
* (`@bonsai/product-catalog`) — this SDK cannot import that package, so the shape is re-declared
|
|
1959
|
+
* here and an assignability test in `@bonsai/agent-runtime` pins the two together. The level union
|
|
1926
1960
|
* is the closed, protocol-owned fold precedence stack (`baseline < learned < global < project`).
|
|
1927
1961
|
* `"baseline"` names a host-composed, in-memory, build/channel-scoped default with no file
|
|
1928
1962
|
* behind it (`KayConfigStoreOptions.baselineDefaults`) — a plugin can still be handed one as a
|
|
@@ -2671,8 +2705,8 @@ export declare interface KayAppPermissions {
|
|
|
2671
2705
|
export declare interface KayAppPhaseShiftSessionEvent extends KayAppSessionEventBase {
|
|
2672
2706
|
readonly type: "phase-shift";
|
|
2673
2707
|
/**
|
|
2674
|
-
* The accepted observation, in the SURFACE-FRIENDLY resolved shape (`@
|
|
2675
|
-
* `PhaseShiftTimelineRecord`, re-exported from `@
|
|
2708
|
+
* The accepted observation, in the SURFACE-FRIENDLY resolved shape (`@bonsai/plugin-protocol`'s
|
|
2709
|
+
* `PhaseShiftTimelineRecord`, re-exported from `@bonsai/plugin-sdk/phase-shift`) rather than the
|
|
2676
2710
|
* raw validated one: source timestamps already resolved, total and pure, no entry read needed
|
|
2677
2711
|
* to place it in time. Re-validate its onsets against the branch you actually read — a rewind
|
|
2678
2712
|
* can race between publish and read — the same discipline `resolveClosedPhase` already applies.
|
|
@@ -2863,6 +2897,24 @@ export declare interface KayAppPluginApi {
|
|
|
2863
2897
|
* present, like {@link signals}.
|
|
2864
2898
|
*/
|
|
2865
2899
|
readonly skills: KayAppSkills;
|
|
2900
|
+
/**
|
|
2901
|
+
* What a live session's tools and addresses say to the agent, where each comes from, and whether
|
|
2902
|
+
* each is one of Bonsai's own. Each call is checked against `tools.describe`; a refused grant or
|
|
2903
|
+
* a session that is not live resolves to `{ status: "unavailable" }`, never a rejection, while
|
|
2904
|
+
* the plugin is enabled. After it is disabled, a kept handle's methods throw synchronously.
|
|
2905
|
+
* Always present, like {@link skills}.
|
|
2906
|
+
*/
|
|
2907
|
+
readonly tools: KayAppTools;
|
|
2908
|
+
/**
|
|
2909
|
+
* Read and change activity for the resources under this plugin's OWN URI schemes, counted under
|
|
2910
|
+
* Bonsai's read rule (reads by a job that declares it maintains the scheme never count). Each
|
|
2911
|
+
* call checks, against the live registry, that the asked prefix is under a scheme this plugin's
|
|
2912
|
+
* registered URI modules serve; any other prefix resolves to `{ status: "refused" }`. A host
|
|
2913
|
+
* with no telemetry lane, or a scan that cannot complete, resolves to `{ status: "unavailable" }`.
|
|
2914
|
+
* No call rejects while the plugin is enabled; after it is disabled, a kept handle's method
|
|
2915
|
+
* throws synchronously. Always present, like {@link skills}.
|
|
2916
|
+
*/
|
|
2917
|
+
readonly usage: KayAppUsage;
|
|
2866
2918
|
/** The app-wide endpoint bus (register handlers a consuming surface invokes). */
|
|
2867
2919
|
readonly endpoints: KayAppEndpoints;
|
|
2868
2920
|
/** Publish one event declared by this plugin's `kay.app` manifest target. */
|
|
@@ -3076,6 +3128,17 @@ export declare interface KayAppResolvedCredential {
|
|
|
3076
3128
|
readonly fields?: Readonly<Record<string, string>>;
|
|
3077
3129
|
}
|
|
3078
3130
|
|
|
3131
|
+
/**
|
|
3132
|
+
* What one run produced, as named counts: `{ suggestions: 2, pullRequests: 0 }`. Optional, and
|
|
3133
|
+
* read by Bonsai's own analytics, not shown to a person.
|
|
3134
|
+
*
|
|
3135
|
+
* Keys are your own names, in camelCase (a letter first, then letters and digits, at most 40
|
|
3136
|
+
* characters), at most 16 per run; values are whole numbers of zero or more. Report a zero rather
|
|
3137
|
+
* than leaving a key out: "made nothing" is the answer a reader is usually asking about. A result
|
|
3138
|
+
* that breaks these rules is dropped whole, with the run otherwise recorded as usual.
|
|
3139
|
+
*/
|
|
3140
|
+
export declare type KayAppRunProduced = Readonly<Record<string, number>>;
|
|
3141
|
+
|
|
3079
3142
|
export declare interface KayAppRunSummary {
|
|
3080
3143
|
/** One plain-text line, at most 100 characters. */
|
|
3081
3144
|
readonly headline: string;
|
|
@@ -3086,8 +3149,8 @@ export declare interface KayAppRunSummary {
|
|
|
3086
3149
|
|
|
3087
3150
|
/**
|
|
3088
3151
|
* The session provenance vocabulary, as the plugin protocol declares it. These used to be spelled
|
|
3089
|
-
* out here because the canonical schemas lived in `@
|
|
3090
|
-
* package may not import; they now live in `@
|
|
3152
|
+
* out here because the canonical schemas lived in `@bonsai/agent-runtime-protocol`, which this
|
|
3153
|
+
* package may not import; they now live in `@bonsai/plugin-protocol` (so artifact writers and the
|
|
3091
3154
|
* daemon share one shape), and a mirror here would be exactly the second declaration the
|
|
3092
3155
|
* placement law forbids. Each name is kept as an alias so existing plugin code keeps compiling.
|
|
3093
3156
|
*/
|
|
@@ -3222,6 +3285,12 @@ export declare interface KayAppSessionEventsSubscribeOptions {
|
|
|
3222
3285
|
* immediately.
|
|
3223
3286
|
*/
|
|
3224
3287
|
readonly serialize?: boolean;
|
|
3288
|
+
/**
|
|
3289
|
+
* Your own name for this handler (the id you would grep a log for). The host names it, with
|
|
3290
|
+
* your plugin id, on the record it writes when the handler throws, so a failure says whose it
|
|
3291
|
+
* was. Optional; unnamed handlers are recorded without it.
|
|
3292
|
+
*/
|
|
3293
|
+
readonly handlerId?: string;
|
|
3225
3294
|
readonly handler: (event: KayAppSessionEvent, context: KayAppSessionEventContext) => void | Promise<void>;
|
|
3226
3295
|
}
|
|
3227
3296
|
|
|
@@ -3720,7 +3789,7 @@ export declare type KayAppSignalsAnswerFilter = {
|
|
|
3720
3789
|
*/
|
|
3721
3790
|
export declare interface KayAppSignalsDetectorInput {
|
|
3722
3791
|
/**
|
|
3723
|
-
* Stable identifier, e.g. `memory-
|
|
3792
|
+
* Stable identifier, e.g. `memory-packet`: a lowercase slug (a-z and 0-9 in words joined
|
|
3724
3793
|
* by single hyphens), at most 64 characters, plugin-scoped. It becomes a `signals://` path
|
|
3725
3794
|
* segment.
|
|
3726
3795
|
*/
|
|
@@ -4155,7 +4224,7 @@ export declare interface KayAppTimeSnapshot {
|
|
|
4155
4224
|
* The time zone the user is in, as an IANA id in the spelling ICU resolves (`America/New_York`).
|
|
4156
4225
|
* One zone can have two ids, and ICU picks one: `Asia/Kolkata` comes back as `Asia/Calcutta`. So
|
|
4157
4226
|
* never compare zone ids with `===`. A first-party plugin compares with `sameZone` from
|
|
4158
|
-
* `@
|
|
4227
|
+
* `@bonsai/time`. A plugin that imports only this SDK and node builtins resolves each id with
|
|
4159
4228
|
* `new Intl.DateTimeFormat("en-US", { timeZone: id }).resolvedOptions().timeZone` and compares the
|
|
4160
4229
|
* results. Pass `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a
|
|
4161
4230
|
* time for the user.
|
|
@@ -4202,6 +4271,21 @@ export declare type KayAppToolDefinition<TParams extends ToolParametersWire = To
|
|
|
4202
4271
|
execute(toolCallId: string, params: ToolExecutionAwareParams<TParams>, signal: AbortSignal | undefined, onUpdate: AgentToolUpdateCallback<TDetails> | undefined, ctx: KayAppToolContext): Promise<AgentToolResult<TDetails>>;
|
|
4203
4272
|
};
|
|
4204
4273
|
|
|
4274
|
+
export declare interface KayAppToolDescription {
|
|
4275
|
+
readonly ref: KayAppToolRef;
|
|
4276
|
+
/** `false`: no such tool is registered, or no module owns that address, in this session. */
|
|
4277
|
+
readonly found: boolean;
|
|
4278
|
+
/**
|
|
4279
|
+
* For a tool, its own registered description. For an address, its help rendered as `help <uri>`
|
|
4280
|
+
* renders it for the agent; for `mcp://<server>`, that is the server's tool list in the server's
|
|
4281
|
+
* own words.
|
|
4282
|
+
*/
|
|
4283
|
+
readonly description?: string;
|
|
4284
|
+
readonly origin?: KayAppToolOrigin;
|
|
4285
|
+
/** Whether this is one of Bonsai's own tools or addresses. `false` when not found. */
|
|
4286
|
+
readonly ownedByBonsai: boolean;
|
|
4287
|
+
}
|
|
4288
|
+
|
|
4205
4289
|
/**
|
|
4206
4290
|
* The fine-grained, app-wide per-tool event stream (every session's tool executions). Carries the
|
|
4207
4291
|
* redaction caveat: raw tool args/results are OFF in packaged builds, so a handler must treat
|
|
@@ -4214,6 +4298,20 @@ export declare interface KayAppToolEvents {
|
|
|
4214
4298
|
subscribe(handler: (event: unknown) => void): () => void;
|
|
4215
4299
|
}
|
|
4216
4300
|
|
|
4301
|
+
/** Where a described tool or address comes from. */
|
|
4302
|
+
export declare type KayAppToolOrigin =
|
|
4303
|
+
/** The agent kernel's own (`bash`, `read`, `help`, `skill://`). */
|
|
4304
|
+
{
|
|
4305
|
+
readonly kind: "core";
|
|
4306
|
+
}
|
|
4307
|
+
/** Bonsai's host, outside any plugin (`task_status`, `config://`). */
|
|
4308
|
+
| {
|
|
4309
|
+
readonly kind: "host";
|
|
4310
|
+
} | {
|
|
4311
|
+
readonly kind: "plugin";
|
|
4312
|
+
readonly pluginId: string;
|
|
4313
|
+
};
|
|
4314
|
+
|
|
4217
4315
|
/**
|
|
4218
4316
|
* `app.permissions` — the plugin-facing seam through which a `kay.app` target advertises the
|
|
4219
4317
|
* permission rows for tools it gates DYNAMICALLY, so they show in Bonsai's permission ledger with
|
|
@@ -4264,6 +4362,52 @@ export declare interface KayAppToolPermissionSource {
|
|
|
4264
4362
|
readonly list: () => readonly KayAppToolPermissionDeclaration[] | Promise<readonly KayAppToolPermissionDeclaration[]>;
|
|
4265
4363
|
}
|
|
4266
4364
|
|
|
4365
|
+
/**
|
|
4366
|
+
* The plugin-facing `kay.app` tools contract: for the tools and addresses a live session can use,
|
|
4367
|
+
* the text the agent sees for each, where each comes from, and whether each is one of Bonsai's own.
|
|
4368
|
+
*
|
|
4369
|
+
* Every call is checked against the `tools.describe` claim at the call, so a grant or revocation
|
|
4370
|
+
* takes effect on the next one. Like `app.skills`, the member is ALWAYS present and no call rejects
|
|
4371
|
+
* while the plugin is enabled: a refused grant or a session that is not live resolves to
|
|
4372
|
+
* `{ status: "unavailable" }`. After the plugin is disabled, a kept handle's methods throw
|
|
4373
|
+
* synchronously.
|
|
4374
|
+
*
|
|
4375
|
+
* `ownedByBonsai` is a fact declared where each surface is defined (a bundled plugin's manifest, or
|
|
4376
|
+
* the host's own registration), never a list kept by the host. What a plugin does with it is the
|
|
4377
|
+
* plugin's call.
|
|
4378
|
+
*/
|
|
4379
|
+
/** A tool or an address to describe. */
|
|
4380
|
+
export declare type KayAppToolRef =
|
|
4381
|
+
/** A registered tool by name, e.g. `bash`, `read`, `mcp`, `submit_final`. */
|
|
4382
|
+
{
|
|
4383
|
+
readonly kind: "tool";
|
|
4384
|
+
readonly name: string;
|
|
4385
|
+
}
|
|
4386
|
+
/** A URI address whose `help` is wanted, e.g. `gmail://` or `mcp://linear`. */
|
|
4387
|
+
| {
|
|
4388
|
+
readonly kind: "address";
|
|
4389
|
+
readonly uri: string;
|
|
4390
|
+
};
|
|
4391
|
+
|
|
4392
|
+
/** `app.tools`: what a live session's tools and addresses say, each call checked against `tools.describe`. */
|
|
4393
|
+
export declare interface KayAppTools {
|
|
4394
|
+
describe(sessionId: string, refs: readonly KayAppToolRef[]): Promise<KayAppToolsDescribeResult>;
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
/**
|
|
4398
|
+
* `not-granted`: the user has not granted `tools.describe`. `no-session`: the session is not live
|
|
4399
|
+
* on this host (only live sessions are described). `not-available`: this host cannot describe
|
|
4400
|
+
* tools.
|
|
4401
|
+
*/
|
|
4402
|
+
export declare type KayAppToolsDescribeResult = {
|
|
4403
|
+
readonly status: "ok";
|
|
4404
|
+
/** One per ref, in the order of the refs. */
|
|
4405
|
+
readonly tools: readonly KayAppToolDescription[];
|
|
4406
|
+
} | {
|
|
4407
|
+
readonly status: "unavailable";
|
|
4408
|
+
readonly reason: "not-granted" | "no-session" | "not-available";
|
|
4409
|
+
};
|
|
4410
|
+
|
|
4267
4411
|
/** An eligible settled turn — the generic door's root event. */
|
|
4268
4412
|
export declare interface KayAppTurnSettledSessionEvent extends KayAppSessionEventBase {
|
|
4269
4413
|
readonly type: "turn-settled";
|
|
@@ -4276,7 +4420,7 @@ export declare interface KayAppTurnSettledSessionEvent extends KayAppSessionEven
|
|
|
4276
4420
|
*
|
|
4277
4421
|
* Optional on this SDK-facing type only for fixture leniency (a handcrafted test event may omit
|
|
4278
4422
|
* it); the daemon's own emitter always populates it for a genuine settle — see
|
|
4279
|
-
* `TurnSettledSessionEvent.runId` (`@
|
|
4423
|
+
* `TurnSettledSessionEvent.runId` (`@bonsai/agent-runtime`'s internal twin of this event, which
|
|
4280
4424
|
* DOES require it) for the producer side of that guarantee.
|
|
4281
4425
|
*/
|
|
4282
4426
|
readonly runId?: string;
|
|
@@ -4309,6 +4453,97 @@ export declare interface KayAppUiActionSessionEvent extends KayAppSessionEventBa
|
|
|
4309
4453
|
readonly toolCallId: string;
|
|
4310
4454
|
}
|
|
4311
4455
|
|
|
4456
|
+
/** How one resource under the asked prefix has been read and changed. */
|
|
4457
|
+
export declare interface KayAppUriActivity {
|
|
4458
|
+
/** The canonical URI as the read or change recorded it. */
|
|
4459
|
+
readonly uri: string;
|
|
4460
|
+
/** One entry per window, in `KayAppUriActivityAnswer.windowDays` order. */
|
|
4461
|
+
readonly windows: readonly KayAppUriActivityWindow[];
|
|
4462
|
+
/** The newest counted read, ISO-8601 UTC; absent when none fell inside the scan. */
|
|
4463
|
+
readonly lastReadAt?: string;
|
|
4464
|
+
/** The newest change, ISO-8601 UTC; absent when none fell inside the scan. */
|
|
4465
|
+
readonly lastChangedAt?: string;
|
|
4466
|
+
}
|
|
4467
|
+
|
|
4468
|
+
export declare type KayAppUriActivityAnswer = {
|
|
4469
|
+
readonly status: "ok";
|
|
4470
|
+
/** The instant the windows are measured back from, ISO-8601 UTC. */
|
|
4471
|
+
readonly asOf: string;
|
|
4472
|
+
/** The windows every resource reports, in order. */
|
|
4473
|
+
readonly windowDays: readonly number[];
|
|
4474
|
+
/**
|
|
4475
|
+
* Every resource under the prefix the scan saw read or changed. One read only by a
|
|
4476
|
+
* maintaining job is listed with zero counts and no `lastReadAt`.
|
|
4477
|
+
*/
|
|
4478
|
+
readonly resources: readonly KayAppUriActivity[];
|
|
4479
|
+
} | {
|
|
4480
|
+
/** The prefix is not under a scheme this plugin's registered URI modules serve. */
|
|
4481
|
+
readonly status: "refused";
|
|
4482
|
+
readonly message: string;
|
|
4483
|
+
} | {
|
|
4484
|
+
/** No telemetry lane on this host, or the scan could not complete. */
|
|
4485
|
+
readonly status: "unavailable";
|
|
4486
|
+
readonly message: string;
|
|
4487
|
+
};
|
|
4488
|
+
|
|
4489
|
+
/**
|
|
4490
|
+
* The plugin-facing `kay.app` usage contract: how the resources under a plugin's OWN URI schemes
|
|
4491
|
+
* have been read and changed, as Bonsai's telemetry records it. SDK 0.13.3; a plugin that calls it
|
|
4492
|
+
* declares `compatibility.sdk` `^0.13.3`.
|
|
4493
|
+
*
|
|
4494
|
+
* Scoped, not gated. A plugin may ask only about a prefix under a scheme one of its own registered
|
|
4495
|
+
* URI modules serves; that check runs at every call against the live registry, and a prefix under
|
|
4496
|
+
* any other scheme answers `{ status: "refused" }`. The member is ALWAYS present and no call
|
|
4497
|
+
* rejects while the plugin is enabled: no telemetry lane on this host, a query that could not
|
|
4498
|
+
* complete, or an answer too large to return all resolve to `{ status: "unavailable" }`. After the
|
|
4499
|
+
* plugin is disabled, a kept handle's method throws synchronously.
|
|
4500
|
+
*
|
|
4501
|
+
* ## What counts as a read
|
|
4502
|
+
*
|
|
4503
|
+
* Every executed read counts, from any session (a person's conversation and its subagents,
|
|
4504
|
+
* automations, loops, watches, Dream passes, any other job), EXCEPT a read made by a session whose
|
|
4505
|
+
* agent definition declares that it maintains the read's scheme (`KayAppAgentDefinition.maintains`)
|
|
4506
|
+
* or by any session in that session's family. Each counted read is split by who it serves:
|
|
4507
|
+
* `personReads` when its session tree was started by a person, `jobReads` otherwise. Changes
|
|
4508
|
+
* (writes and edits) count from every session, maintainers included.
|
|
4509
|
+
*
|
|
4510
|
+
* Reads recorded before the host build that stamps the declaration follow the earlier rule until
|
|
4511
|
+
* they leave the 90-day window: such a read counts only when a person started the session that made it (a person's subagents
|
|
4512
|
+
* did not count under that rule).
|
|
4513
|
+
*
|
|
4514
|
+
* ## Zero and unavailable are different answers
|
|
4515
|
+
*
|
|
4516
|
+
* An `ok` answer describes a complete scan: a resource absent from `resources` was neither read
|
|
4517
|
+
* nor changed inside the scan, so it has zero counted reads. When the scan could not complete the answer is `unavailable`,
|
|
4518
|
+
* never a list of zeros, because "nothing read this" and "nothing could tell" are different facts.
|
|
4519
|
+
*/
|
|
4520
|
+
/** One window's activity for one resource. */
|
|
4521
|
+
export declare interface KayAppUriActivityWindow {
|
|
4522
|
+
/** The span, in days, measured back from the answer's `asOf`. */
|
|
4523
|
+
readonly windowDays: number;
|
|
4524
|
+
/** Counted reads: `personReads + jobReads`. */
|
|
4525
|
+
readonly reads: number;
|
|
4526
|
+
/** Counted reads whose session tree a person started. */
|
|
4527
|
+
readonly personReads: number;
|
|
4528
|
+
/** Counted reads by every other session tree (automations, Dream passes, other jobs). */
|
|
4529
|
+
readonly jobReads: number;
|
|
4530
|
+
/** Distinct session trees (keyed by root session) behind the counted reads. */
|
|
4531
|
+
readonly sessions: number;
|
|
4532
|
+
/** Writes and edits of any origin, maintainers included. */
|
|
4533
|
+
readonly changes: number;
|
|
4534
|
+
}
|
|
4535
|
+
|
|
4536
|
+
export declare interface KayAppUsage {
|
|
4537
|
+
/**
|
|
4538
|
+
* Read and change activity for every resource whose URI starts with `prefix`, for example
|
|
4539
|
+
* `memory://` or `memory://projects/`. The prefix must name a scheme (`<scheme>://`) that one of
|
|
4540
|
+
* this plugin's registered URI modules serves.
|
|
4541
|
+
*/
|
|
4542
|
+
uriActivity(input: {
|
|
4543
|
+
readonly prefix: string;
|
|
4544
|
+
}): Promise<KayAppUriActivityAnswer>;
|
|
4545
|
+
}
|
|
4546
|
+
|
|
4312
4547
|
export declare interface KayAppUserFileEntry {
|
|
4313
4548
|
readonly name: string;
|
|
4314
4549
|
/** From the directory entry itself: a symlink is reported as `symlink`, never followed. */
|
|
@@ -4591,6 +4826,7 @@ export declare interface KayAppWorkflowDefinition {
|
|
|
4591
4826
|
}>;
|
|
4592
4827
|
readonly run: (context: KayAppWorkflowContext) => Promise<{
|
|
4593
4828
|
readonly summary: KayAppRunSummary;
|
|
4829
|
+
readonly produced?: KayAppRunProduced;
|
|
4594
4830
|
}>;
|
|
4595
4831
|
}
|
|
4596
4832
|
|
|
@@ -4661,7 +4897,7 @@ export declare interface KayAppWorkspace {
|
|
|
4661
4897
|
/**
|
|
4662
4898
|
* The full workspace arrangement verb catalog: tab lifecycle/reorder/grouping, pane split/close/
|
|
4663
4899
|
* focus/maximize/restore/place, shell panel toggles, and opening a session. A JSON-safe twin of
|
|
4664
|
-
* `KayWorkspaceCommand` in `@
|
|
4900
|
+
* `KayWorkspaceCommand` in `@bonsai/agent-runtime-protocol`.
|
|
4665
4901
|
*/
|
|
4666
4902
|
export declare type KayAppWorkspaceCommand = {
|
|
4667
4903
|
verb: "tabs.open";
|
|
@@ -4739,7 +4975,14 @@ export declare type KayAppWorkspaceCommand = {
|
|
|
4739
4975
|
verb: "shell.togglePanel";
|
|
4740
4976
|
} | {
|
|
4741
4977
|
verb: "shell.toggleInspector";
|
|
4742
|
-
}
|
|
4978
|
+
}
|
|
4979
|
+
/**
|
|
4980
|
+
* Open a session without taking the user's focus. A session no pane shows gets a tab of its own
|
|
4981
|
+
* in the background (`opened`); one some pane already shows is left as it is (`applied`). The
|
|
4982
|
+
* active tab and every focus stay as they were. The wire's `reveal` flag, which asks for a
|
|
4983
|
+
* sidebar-click-style open, is not offered here: it is for Bonsai Desktop's own menus.
|
|
4984
|
+
*/
|
|
4985
|
+
| {
|
|
4743
4986
|
verb: "sessions.open";
|
|
4744
4987
|
sessionId: string;
|
|
4745
4988
|
title?: string | undefined;
|
|
@@ -4747,7 +4990,7 @@ export declare type KayAppWorkspaceCommand = {
|
|
|
4747
4990
|
|
|
4748
4991
|
/**
|
|
4749
4992
|
* The one outcome grammar every {@link KayAppWorkspaceCommand} resolves to. A JSON-safe twin of
|
|
4750
|
-
* `WorkspaceCommandOutcome` in `@
|
|
4993
|
+
* `WorkspaceCommandOutcome` in `@bonsai/agent-runtime-protocol`.
|
|
4751
4994
|
*/
|
|
4752
4995
|
export declare type KayAppWorkspaceCommandOutcome = "applied" | "opened" | "focused-existing" | "no-room" | "no-window" | "not-found" | "invalid";
|
|
4753
4996
|
|
|
@@ -4758,8 +5001,8 @@ export declare interface KayAppWorkspaceExecuteContext {
|
|
|
4758
5001
|
|
|
4759
5002
|
/**
|
|
4760
5003
|
* What one pane item shows. A JSON-safe, hand-copied twin of `WorkspacePaneContent` in
|
|
4761
|
-
* `@
|
|
4762
|
-
* module's own doc comment), so the shape is re-declared here. A parity check in `@
|
|
5004
|
+
* `@bonsai/agent-runtime-protocol` — this package cannot import that protocol package (see this
|
|
5005
|
+
* module's own doc comment), so the shape is re-declared here. A parity check in `@bonsai/agent-runtime`
|
|
4763
5006
|
* asserts `app.workspace` (the runtime's `KayWorkspaceCapability`, built from the protocol types)
|
|
4764
5007
|
* stays structurally assignable to {@link KayAppWorkspace} below.
|
|
4765
5008
|
*
|
|
@@ -5503,14 +5746,14 @@ declare interface ScopeRequirement {
|
|
|
5503
5746
|
* this list. Two consequences worth knowing:
|
|
5504
5747
|
*
|
|
5505
5748
|
* - `sessions.create` and `sessions.run` are the two separately-granted plugin doors
|
|
5506
|
-
* (`@
|
|
5749
|
+
* (`@bonsai/plugin-protocol`'s `permissions.ts`: `create` mints a persisted user-visible session,
|
|
5507
5750
|
* `run` executes a hidden headless one). Each names ITSELF at the site that mints the session;
|
|
5508
5751
|
* neither is inferred from the surface string, which cannot tell them apart.
|
|
5509
5752
|
* - `sessions.create` stamps a plugin creator only for a create that declares a plugin-surfaced
|
|
5510
5753
|
* `system` origin. The SDK `create` door passes no origin today, so its sessions read as the
|
|
5511
5754
|
* ordinary chats they are; the value is still the honest one for that door when it does.
|
|
5512
5755
|
* - `agents.run` (G1, 2026-09) is the generic session-event run door
|
|
5513
|
-
* (`app.agents.run(ref, input, cause, {fork?})`, `@
|
|
5756
|
+
* (`app.agents.run(ref, input, cause, {fork?})`, `@bonsai/plugin-sdk`'s `kay-app/agents.ts`): a
|
|
5514
5757
|
* plugin's `app.sessionEvents.subscribe` handler spins up a bounded agent run in response to a
|
|
5515
5758
|
* published session event. `callerSessionId` carries the cause's `sourceSessionId` — the session
|
|
5516
5759
|
* whose event caused this run — and {@link SessionProvenanceRecord.causedByEvent} carries the
|
|
@@ -6427,6 +6670,12 @@ declare interface UriHelp {
|
|
|
6427
6670
|
readonly templates?: readonly UriTemplate[];
|
|
6428
6671
|
readonly examples?: readonly UriExample[];
|
|
6429
6672
|
readonly notes?: readonly string[];
|
|
6673
|
+
/**
|
|
6674
|
+
* Set when this help, for the address it was asked about, carries text a third party wrote and
|
|
6675
|
+
* the module relays as it received it (an MCP server's own tool names and descriptions), rather
|
|
6676
|
+
* than text the module's author wrote. Absent: the module's own text.
|
|
6677
|
+
*/
|
|
6678
|
+
readonly thirdPartyContent?: true;
|
|
6430
6679
|
}
|
|
6431
6680
|
|
|
6432
6681
|
declare interface UriHintTriggers {
|
|
@@ -7244,7 +7493,7 @@ declare interface UriValidationMessage {
|
|
|
7244
7493
|
* applies label changes"), never wire mechanics or URI shapes. Verbs the
|
|
7245
7494
|
* module does not support are omitted; at runtime a supported verb with no
|
|
7246
7495
|
* entry simply renders undocumented (fail-open metadata) — but for a plugin's
|
|
7247
|
-
* `kay.agent` URI modules, `auditPluginDisclosure` (`@
|
|
7496
|
+
* `kay.agent` URI modules, `auditPluginDisclosure` (`@bonsai/plugin-sdk/
|
|
7248
7497
|
* disclosure`) enforces coverage of every supported verb at authoring/load
|
|
7249
7498
|
* time.
|
|
7250
7499
|
*
|
package/dist/kay-app.js
CHANGED
|
@@ -503,6 +503,13 @@ function createUnavailableSkills(message) {
|
|
|
503
503
|
};
|
|
504
504
|
}
|
|
505
505
|
|
|
506
|
+
// packages/plugin-sdk/dist/kay-app/tools.js
|
|
507
|
+
function createUnavailableTools() {
|
|
508
|
+
return {
|
|
509
|
+
describe: async () => ({ status: "unavailable", reason: "not-available" })
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
506
513
|
// packages/plugin-sdk/dist/kay-app/transcript-text.js
|
|
507
514
|
function transcriptMessageTexts(entries) {
|
|
508
515
|
return entries.flatMap((entry) => {
|
|
@@ -531,6 +538,13 @@ function transcriptRoleLabel(role) {
|
|
|
531
538
|
return role === "user" ? "User" : "Assistant";
|
|
532
539
|
}
|
|
533
540
|
|
|
541
|
+
// packages/plugin-sdk/dist/kay-app/usage.js
|
|
542
|
+
function createUnavailableUsage(message) {
|
|
543
|
+
return {
|
|
544
|
+
uriActivity: async () => ({ status: "unavailable", message })
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
534
548
|
// packages/plugin-sdk/dist/kay-app/workflows.js
|
|
535
549
|
var KayAppWorkflowFailure = class extends Error {
|
|
536
550
|
summary;
|
|
@@ -572,6 +586,8 @@ export {
|
|
|
572
586
|
createFallbackOnlySignals,
|
|
573
587
|
createFallbackOnlyWithJev,
|
|
574
588
|
createUnavailableSkills,
|
|
589
|
+
createUnavailableTools,
|
|
590
|
+
createUnavailableUsage,
|
|
575
591
|
invalidObservation,
|
|
576
592
|
isRetryable,
|
|
577
593
|
parseLineSelector,
|
package/dist/signals.d.ts
CHANGED
|
@@ -86,7 +86,7 @@ declare interface JevScoreQuestion {
|
|
|
86
86
|
* - The wire. The host serves `classify` over whichever route the user's Jev provider order
|
|
87
87
|
* picks; a plugin never sees a vendor client, a vendor type, or a route.
|
|
88
88
|
* - Credential resolution, the `jev.use` decision, the Jev-branch budget, or usage accounting.
|
|
89
|
-
* Those are host-side (`@
|
|
89
|
+
* Those are host-side (`@bonsai/agent-runtime`'s `kay/jev/`).
|
|
90
90
|
* ---
|
|
91
91
|
*
|
|
92
92
|
* The vocabulary is Bonsai's own (SDK 0.12.0). Before it, `use` received TypeSafe's `TypeSafeClient`
|
|
@@ -301,7 +301,7 @@ export declare type KayAppSignalsAnswerFilter = {
|
|
|
301
301
|
*/
|
|
302
302
|
export declare interface KayAppSignalsDetectorInput {
|
|
303
303
|
/**
|
|
304
|
-
* Stable identifier, e.g. `memory-
|
|
304
|
+
* Stable identifier, e.g. `memory-packet`: a lowercase slug (a-z and 0-9 in words joined
|
|
305
305
|
* by single hyphens), at most 64 characters, plugin-scoped. It becomes a `signals://` path
|
|
306
306
|
* segment.
|
|
307
307
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: directory-plugin-authoring
|
|
3
|
-
description: "Author, scaffold, debug, or iterate on a Bonsai directory plugin (one the user writes in ~/.kay/plugins/<name>). Use when creating a new local plugin, when a plugin does not appear in Bonsai after installation, when enabling it fails with 'pluginActivation names a plugin that is not installed', when Settings → Plugins shows 'failed to load' with no toggle, when @
|
|
3
|
+
description: "Author, scaffold, debug, or iterate on a Bonsai directory plugin (one the user writes in ~/.kay/plugins/<name>). Use when creating a new local plugin, when a plugin does not appear in Bonsai after installation, when enabling it fails with 'pluginActivation names a plugin that is not installed', when Settings → Plugins shows 'failed to load' with no toggle, when @bonsai/plugin-sdk imports fail to resolve, when a plugin declares a ui.tsx that nothing typechecks, or when changes to a plugin do not take effect. For installing plugins from a git repository source, use the manage-plugins skill instead; for first-party bundled plugins under plugins/ in the kay repo, use the bundled-plugin guidance there."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Directory plugin authoring
|
|
@@ -14,7 +14,7 @@ keeps an agent on the paved path and out of the known pits.
|
|
|
14
14
|
|
|
15
15
|
`pnpm create-plugin` writes absolute type paths (`tsconfig.json`, `package.json`) pointing at
|
|
16
16
|
whichever Bonsai checkout invoked it, with no staleness warning. A checkout far behind `origin/main`
|
|
17
|
-
— one was 752 commits behind — typechecks the new plugin against stale `@
|
|
17
|
+
— one was 752 commits behind — typechecks the new plugin against stale `@bonsai/plugin-sdk` types,
|
|
18
18
|
and it looks clean: every wrong shape it produced (a `content` object instead of
|
|
19
19
|
`run`/`openBeside` on `PaneActionDescriptor`, `SearchField`'s `onChange` instead of
|
|
20
20
|
`onValueChange`, wrong `PageState` props) typechecked fine against the old types it was
|
|
@@ -27,7 +27,7 @@ git -C <kay-checkout> fetch origin && git -C <kay-checkout> rev-list --count HEA
|
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
A nonzero count means update that checkout first, or scaffold from a fresh `origin/main` worktree
|
|
30
|
-
and rebuild `@
|
|
30
|
+
and rebuild `@bonsai/plugin-sdk` there. A green typecheck against stale types is evidence of nothing.
|
|
31
31
|
The scaffold does the second half of this for you: it prints a warning when the checkout trails
|
|
32
32
|
its last-fetched `origin/main`, and stamps the checkout's commit into the generated
|
|
33
33
|
`tsconfig.json` header. It never fetches, so the `fetch` above is still yours to run; a checkout
|
|
@@ -36,7 +36,7 @@ that has not fetched in a week reads as current to the scaffold.
|
|
|
36
36
|
## Scaffold, never hand-roll
|
|
37
37
|
|
|
38
38
|
```
|
|
39
|
-
pnpm --filter @
|
|
39
|
+
pnpm --filter @bonsai/plugin-sdk build # once per checkout, if not built
|
|
40
40
|
pnpm create-plugin --id com.example.widgets
|
|
41
41
|
```
|
|
42
42
|
|
|
@@ -44,14 +44,14 @@ Run from the root of a Bonsai checkout. It writes a working plugin (manifest, en
|
|
|
44
44
|
README) that already typechecks and loads; `--tier starter` adds a URI module, a bundled skill,
|
|
45
45
|
and a standalone `node --test` test to copy from. Add `--ui` (either tier) when the plugin needs a
|
|
46
46
|
page: it writes `ui.tsx`, declares the `kay.ui` entrypoint, and generates the UI typecheck config
|
|
47
|
-
described below. `--ui` also needs `pnpm --filter @
|
|
47
|
+
described below. `--ui` also needs `pnpm --filter @bonsai/ui build` once per checkout; the scaffold
|
|
48
48
|
stops and says so when that build is missing.
|
|
49
49
|
|
|
50
50
|
Never hand-build a plugin as a tsc-compiled package and copy the output into `~/.kay/plugins/`.
|
|
51
|
-
That path produces a plugin whose built `dist/` imports `@
|
|
51
|
+
That path produces a plugin whose built `dist/` imports `@bonsai/plugin-sdk` through ordinary
|
|
52
52
|
`node_modules` resolution, which cannot work from outside the monorepo — it shipped a
|
|
53
53
|
failed-to-load plugin and a misfiled bug (#7732). The load fails with `ERR_MODULE_NOT_FOUND`,
|
|
54
|
-
and symlinking `node_modules/@
|
|
54
|
+
and symlinking `node_modules/@bonsai` into the copy does not rescue it either: pnpm's `.pnpm`
|
|
55
55
|
layout does not expose workspace packages that way. The scaffold exists precisely so this
|
|
56
56
|
cannot happen.
|
|
57
57
|
|
|
@@ -62,7 +62,7 @@ pnpm plugin:check ~/.kay/plugins/widgets
|
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
Run from the root of a Bonsai checkout, against the plugin directory. It runs the daemon's OWN
|
|
65
|
-
manifest schema and contract resolver (imported from `@
|
|
65
|
+
manifest schema and contract resolver (imported from `@bonsai/plugin-protocol`, not re-implemented),
|
|
66
66
|
so it answers "would Kay accept this manifest?" in about a second instead of after a load cycle.
|
|
67
67
|
Run it after every manifest edit, and before concluding a plugin is broken for some deeper reason.
|
|
68
68
|
|
|
@@ -82,13 +82,13 @@ disclosure audit, or an id another installed plugin already claims.
|
|
|
82
82
|
|
|
83
83
|
## The SDK resolution contract
|
|
84
84
|
|
|
85
|
-
- Plugin source imports `@
|
|
86
|
-
(`@
|
|
85
|
+
- Plugin source imports `@bonsai/plugin-sdk/<subpath>` as a **bare specifier**
|
|
86
|
+
(`@bonsai/plugin-sdk/kay-agent`, `/kay-agent/testing`, `/kay-app`, `/disclosure` — only declared
|
|
87
87
|
exports exist).
|
|
88
88
|
- The daemon's chord loader bundles each declared TypeScript entrypoint and its relative imports.
|
|
89
|
-
It keeps `@
|
|
89
|
+
It keeps `@bonsai/plugin-sdk` imports external and resolves them to the running app's own built SDK.
|
|
90
90
|
Multi-file plugins are supported, and no plugin-local build is needed for Bonsai to load them.
|
|
91
|
-
- Corollary: **bare `node` outside the daemon cannot resolve `@
|
|
91
|
+
- Corollary: **bare `node` outside the daemon cannot resolve `@bonsai/plugin-sdk`** from the plugin
|
|
92
92
|
directory unless the plugin has its own SDK dependency. That failure says nothing about whether
|
|
93
93
|
the plugin will load in Bonsai. The `starter` tier's test setup creates the symlink needed for its
|
|
94
94
|
standalone test; a published SDK dependency is the other standalone option.
|
|
@@ -106,7 +106,7 @@ entrypoint may import other files in the plugin; `kay.agent` runs in the daemon
|
|
|
106
106
|
self-contained module: unlike the daemon targets, `ui.tsx` cannot import sibling files. A
|
|
107
107
|
plugin UI contributes through `api.slots` (`registerPage`, `registerSidebarItem`,
|
|
108
108
|
`registerPaneAction`, and the rest of `buildSlots` in
|
|
109
|
-
`
|
|
109
|
+
`packages/kay-renderer/src/renderer/src/extension-loader/build-extension-api.ts`). A page gets its own
|
|
110
110
|
activity-rail button when a `registerSidebarItem({ pageId, placement: "activityRail" })` from the
|
|
111
111
|
same plugin points at it.
|
|
112
112
|
|
|
@@ -119,17 +119,17 @@ and its rail item borrow each other's glyph, so one declaration covers the desti
|
|
|
119
119
|
precedence: `packages/kay-frontend-sdk/ARCHITECTURE.md`, "Plugin icon".
|
|
120
120
|
|
|
121
121
|
`ui.tsx` has no `node_modules` of its own. The renderer bundles it and rewrites its `react` and
|
|
122
|
-
`@
|
|
122
|
+
`@bonsai/*` imports to the host's `__KAY_UI_RUNTIME__` singletons, so the agent `tsconfig.json`
|
|
123
123
|
cannot cover it, and a plugin whose UI nothing typechecks has shipped three wrong API shapes at
|
|
124
124
|
once. `pnpm create-plugin --ui` generates `tsconfig.ui.json` for exactly this: its `paths` are
|
|
125
|
-
derived from the bundler's own shim set (`uiRuntimeShimModules` in `@
|
|
125
|
+
derived from the bundler's own shim set (`uiRuntimeShimModules` in `@bonsai/ui-app-bundler`), each
|
|
126
126
|
specifier mapped to the type entry the renderer binds it to, and `npm run typecheck` runs both
|
|
127
127
|
configs. Do not hand-write the map; when the bundler's set changes, the scaffold's test fails and
|
|
128
128
|
the generated config follows.
|
|
129
129
|
|
|
130
130
|
Two facts about that config worth knowing when you read errors from it:
|
|
131
131
|
|
|
132
|
-
- The bare `@
|
|
132
|
+
- The bare `@bonsai/frontend-sdk` is typed against the SDK's `ui-runtime` facade, because that is
|
|
133
133
|
what the renderer binds it to. The facade carries the SDK's whole type surface, so
|
|
134
134
|
`KayUiExtensionApi` and every descriptor type import fine; a **value** only the package's main
|
|
135
135
|
entry exports fails to compile there (TS1362, "exported using export type"), which is the
|
|
@@ -210,9 +210,9 @@ a failure class the load would otherwise be the first thing to surface:
|
|
|
210
210
|
|
|
211
211
|
1. **Run `pnpm plugin:check <dir>`** from a Bonsai checkout. It validates `kay-plugin.json` against
|
|
212
212
|
`KayPluginManifestV1` and resolves its contributions with the daemon's own resolver (both from
|
|
213
|
-
`@
|
|
213
|
+
`@bonsai/plugin-protocol`), not just "it is valid JSON": that schema and resolver are the gate the
|
|
214
214
|
scan actually runs. A non-zero exit means the plugin would be refused.
|
|
215
|
-
2. **Run the disclosure audit yourself**: `auditPluginDisclosure` from `@
|
|
215
|
+
2. **Run the disclosure audit yourself**: `auditPluginDisclosure` from `@bonsai/plugin-sdk/disclosure`.
|
|
216
216
|
It is not redundant with typecheck. A plugin shipped a `search` verb with no `verbDocs` entry
|
|
217
217
|
that typechecked clean and would have failed the whole `kay.agent` target.
|
|
218
218
|
3. **Typecheck every target**: `npm run typecheck` runs the agent config and, for a `--ui`
|