@tomradex/plugin-sdk 0.2.0 → 0.2.16

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
@@ -60,4 +60,4 @@ export default definePlugin({
60
60
  }
61
61
  ```
62
62
 
63
- Declare what your code does beyond the SDK — the hosts it talks to, whether it touches the disk, whether it starts programs. The store's review compares it with the code. Community lists open-source plugins only, built from your public GitHub repository and reviewed before they are listed.
63
+ Declare what your code does beyond the SDK — the hosts it talks to, whether it touches the disk, whether it starts programs. Whoever installs it sees it beside what the analyzer finds in the code. Community lists open-source plugins only, published from your public GitHub repository; nobody reviews them, so say plainly what yours does.
@@ -0,0 +1,8 @@
1
+ /** SDK 0.2.15: what a CLI agent's hook says happened, in one set of names whichever agent sent it. */
2
+ export type CliHookEvent = "session-start" | "prompt" | "pre-tool" | "post-tool" | "stop" | "session-end";
3
+ export declare const CLI_HOOK_EVENTS: readonly CliHookEvent[];
4
+ export declare const CLI_HOOK_COVERAGE: Readonly<Record<CliHookEvent, {
5
+ answers: readonly string[];
6
+ sees: readonly string[];
7
+ }>>;
8
+ //# sourceMappingURL=cli-hooks.d.ts.map
@@ -0,0 +1,27 @@
1
+ export const CLI_HOOK_EVENTS = ["session-start", "prompt", "pre-tool", "post-tool", "stop", "session-end"];
2
+ /** The agents whose hooks reach Tomrade at all: in sessions it starts, or in repositories it connects. */
3
+ const REPORTING = ["claude-code", "workbuddy", "dsh", "pi", "codex", "cursor", "opencode", "hermes"];
4
+ const ANSWERS = {
5
+ "session-start": ["claude-code", "workbuddy", "dsh"],
6
+ prompt: ["claude-code", "workbuddy", "dsh"],
7
+ "pre-tool": ["claude-code", "workbuddy", "dsh", "pi"],
8
+ "post-tool": ["claude-code", "workbuddy", "dsh", "pi"],
9
+ stop: ["claude-code", "workbuddy", "dsh"],
10
+ "session-end": []
11
+ };
12
+ /**
13
+ * Which agents a CLI hook reaches. `answers`: in a session Tomrade started, the
14
+ * agent acts on the answer. `sees`: the hook hears the event — a connected
15
+ * repository's, or one the agent cannot be answered on — and its answer goes
16
+ * nowhere. Gemini CLI and Antigravity report no hooks at all.
17
+ */
18
+ const reach = (event) => ({ answers: ANSWERS[event], sees: REPORTING.filter((agent) => !ANSWERS[event].includes(agent)) });
19
+ export const CLI_HOOK_COVERAGE = {
20
+ "session-start": reach("session-start"),
21
+ prompt: reach("prompt"),
22
+ "pre-tool": reach("pre-tool"),
23
+ "post-tool": reach("post-tool"),
24
+ stop: reach("stop"),
25
+ "session-end": reach("session-end")
26
+ };
27
+ //# sourceMappingURL=cli-hooks.js.map
@@ -1,4 +1,8 @@
1
1
  import type { z } from "zod";
2
+ import type { ImApi } from "./im.js";
3
+ import type { TerminalsApi } from "./terminals.js";
4
+ import type { WebSearchApi } from "./web-search.js";
5
+ import type { ModelsApi } from "./models.js";
2
6
  import type { Author, Board, CreateItemInput, FieldDef, FieldOption, FieldType, FilterClause, Item, ListItemsFilter, OplogEntity, OplogEntry, OplogOp, Patch, Project, SortKey, View } from "@tomradex/domain";
3
7
  /**
4
8
  * The plugin contract. Everything a plugin reaches returns a Promise, and every
@@ -7,8 +11,24 @@ import type { Author, Board, CreateItemInput, FieldDef, FieldOption, FieldType,
7
11
  * plain data — never a live object of the host's.
8
12
  */
9
13
  export type Disposer = () => void;
14
+ /** A language the app may be speaking: a BCP 47 tag such as "en", "zh", "zh-Hant" or one a language pack adds ("pt-BR"). SDK 0.2.8 widened it from "en" | "zh". */
15
+ export type Locale = string;
16
+ /** Text in the app's language: a plain string, or one per language tag picked each time it is shown (English is the fallback). */
17
+ export type Localized = string | ({
18
+ en: string;
19
+ } & Partial<Record<Locale, string>>);
20
+ /** A settings section's text in one language; fields are keyed by schema property. */
21
+ export interface SectionWords {
22
+ title?: string;
23
+ description?: string;
24
+ fields?: Record<string, {
25
+ title?: string;
26
+ description?: string;
27
+ options?: Record<string, string>;
28
+ }>;
29
+ }
10
30
  /** The services a plugin names in `inject` (required) or `optional`. */
11
- export type ServiceName = "items" | "fields" | "boards" | "views" | "projects" | "db" | "settings" | "tools" | "contributions" | "agent" | "surfaces" | "oplog";
31
+ export type ServiceName = "items" | "fields" | "boards" | "views" | "projects" | "db" | "settings" | "tools" | "contributions" | "agent" | "surfaces" | "alerts" | "oplog" | "im" | "webSearch" | "terminals" | "models";
12
32
  export interface Logger {
13
33
  debug(...args: unknown[]): void;
14
34
  info(...args: unknown[]): void;
@@ -37,6 +57,30 @@ export interface ItemsApi {
37
57
  addRelation(projectId: string, id: string, blockedId: string): Promise<void>;
38
58
  removeRelation(projectId: string, id: string, blockedId: string): Promise<void>;
39
59
  labels(projectId: string): Promise<string[]>;
60
+ /**
61
+ * SDK 0.2.12: a policy over every write before it lands — items, and the workstream and view
62
+ * writes that take the same path — whoever writes. Throw to refuse it. It is asked inside the
63
+ * write's transaction, so it must answer at once: a check that returns a Promise is not waited
64
+ * for, and the write goes on.
65
+ */
66
+ gate(check: (write: PendingWrite) => void): Promise<Disposer>;
67
+ }
68
+ /** SDK 0.2.12: a write about to land, as a write gate sees it. A copy: changing it changes nothing. */
69
+ export interface PendingWrite<T = unknown> {
70
+ projectId: string;
71
+ entity: OplogEntity;
72
+ op: OplogOp;
73
+ id: string;
74
+ by: Author;
75
+ /** The extension making the write, when one is. */
76
+ via: string | null;
77
+ runId: string | null;
78
+ /** The version the writer read, when it asserts one. */
79
+ baseVersion: number | null;
80
+ before: T | null;
81
+ after: T | null;
82
+ /** For an update: only the fields the writer asked to change. */
83
+ patch: Record<string, unknown> | null;
40
84
  }
41
85
  export interface FieldsApi {
42
86
  list(projectId: string): Promise<FieldDef[]>;
@@ -82,17 +126,21 @@ export interface TableSpec {
82
126
  via: string;
83
127
  table: string;
84
128
  };
85
- /** Exported tables travel in the project's folder; `false` keeps them on this machine. */
129
+ /**
130
+ * Exported tables travel in the project's folder; `false` keeps them on this machine.
131
+ * `private` rows (conversations, say) never travel to a remote known to be public.
132
+ */
86
133
  export: {
87
134
  order: string;
88
135
  appendOnly?: boolean;
89
136
  always?: boolean;
137
+ private?: boolean;
90
138
  } | false;
91
139
  }
92
140
  /**
93
141
  * Plain SQL against the caches. The namespace is the plugin's own: tables are
94
142
  * `plugin_<namespace>_*`. Reads of the app's tables are allowed; writing them
95
- * goes around history and undo, and review says so.
143
+ * goes around history and undo, and the install dialog says so.
96
144
  */
97
145
  export interface DbApi {
98
146
  migrate(steps: {
@@ -122,14 +170,23 @@ export interface SettingsSectionSpec<T> {
122
170
  id?: string;
123
171
  title: string;
124
172
  description?: string;
173
+ /** Drawn from its JSON Schema; a field with `.meta({ advanced: true })` is folded under Advanced. */
125
174
  schema: z.ZodType<T>;
126
175
  defaults: T;
127
176
  scope?: "machine" | "user";
177
+ /** What agents may do with it through get_settings / update_settings. Defaults to read; a section holding a password is none. */
178
+ agent?: "write" | "read" | "none";
179
+ /** The card in other languages; `title`, `description` and the schema's own labels are the English. */
180
+ words?: Partial<Record<Locale, SectionWords>>;
128
181
  }
129
182
  export interface SettingsApi {
130
183
  register<T>(section: SettingsSectionSpec<T>): Promise<void>;
131
184
  get<T = unknown>(id?: string): Promise<T>;
132
185
  set<T = unknown>(value: T, id?: string): Promise<void>;
186
+ /** Opens the app's Settings on this plugin's section, bringing the window forward — for a click outside the window. */
187
+ show(id?: string): Promise<void>;
188
+ /** The app's language now. It is a setting: `settings.changed` fires when the person switches it. */
189
+ locale(): Promise<Locale>;
133
190
  }
134
191
  export interface ToolInvocation {
135
192
  projectId?: string;
@@ -143,6 +200,8 @@ export interface ToolSpec<S extends z.ZodObject = z.ZodObject> {
143
200
  title: string;
144
201
  description: string;
145
202
  input: S;
203
+ /** A kit few conversations need: the tool is left out of each request until the model loads the kit. Named like the tool. */
204
+ kit?: string;
146
205
  execute(args: z.output<S>, invocation: ToolInvocation): unknown | Promise<unknown>;
147
206
  }
148
207
  export interface ToolCallInfo {
@@ -154,6 +213,8 @@ export interface ToolCallInfo {
154
213
  }
155
214
  export interface ToolsApi {
156
215
  register<S extends z.ZodObject>(tool: ToolSpec<S>): Promise<Disposer>;
216
+ /** What a kit is for, in a few words the model reads before it loads the kit ("a focus timer"). */
217
+ kit(id: string, purpose: string): Promise<Disposer>;
157
218
  list(): Promise<{
158
219
  name: string;
159
220
  title: string;
@@ -163,9 +224,18 @@ export interface ToolsApi {
163
224
  call(name: string, args: unknown, opts?: {
164
225
  projectId?: string;
165
226
  }): Promise<unknown>;
166
- /** A policy over every tool call: throw to refuse it. */
167
- gate(check: (call: ToolCallInfo) => void | Promise<void>): Promise<Disposer>;
227
+ /**
228
+ * A policy over every tool call: throw to refuse it. SDK 0.2.12: or answer `{ args }` to go on with
229
+ * other arguments (checked against the tool's input again), or `{ result }` to answer in the tool's place.
230
+ */
231
+ gate(check: (call: ToolCallInfo) => ToolGateAnswer | void | Promise<ToolGateAnswer | void>): Promise<Disposer>;
168
232
  }
233
+ /** SDK 0.2.12: what a tool gate may answer besides letting the call through unchanged. `result` wins over `args`. */
234
+ export type ToolGateAnswer = {
235
+ args: unknown;
236
+ } | {
237
+ result: unknown;
238
+ };
169
239
  export type BadgeTone = "faint" | "neutral" | "strong";
170
240
  export interface Badge {
171
241
  id: string;
@@ -189,6 +259,15 @@ export interface SectionRow {
189
259
  href?: string;
190
260
  command?: string;
191
261
  }
262
+ export interface SidebarRow {
263
+ id: string;
264
+ label: string;
265
+ icon?: string;
266
+ detail?: string;
267
+ count?: number | string;
268
+ command?: string;
269
+ href?: string;
270
+ }
192
271
  export interface GraphEdge {
193
272
  from: string;
194
273
  to: string;
@@ -200,8 +279,8 @@ type Maybe<T> = T | Promise<T>;
200
279
  export interface ContributionsApi {
201
280
  command(def: {
202
281
  id: string;
203
- title: string;
204
- group?: string;
282
+ title: Localized;
283
+ group?: Localized;
205
284
  shortcut?: string;
206
285
  run(scope: CommandScope): Maybe<{
207
286
  toast?: string;
@@ -213,15 +292,36 @@ export interface ContributionsApi {
213
292
  projectId: string;
214
293
  }): Maybe<Record<string, Badge[]>>;
215
294
  }): Promise<Disposer>;
295
+ /**
296
+ * A status bar item. `command` (in the plugin's namespace) runs on click, or `menu` lists actions the click
297
+ * opens instead; `until` returns an epoch ms the renderer counts down to after the text, without polling.
298
+ * Everything is re-read when `refresh()` is called.
299
+ */
216
300
  statusItem(def: {
217
301
  id: string;
218
302
  text(scope: {
219
303
  projectId?: string;
220
304
  }): Maybe<string | null>;
305
+ title?: Localized;
306
+ icon?: string;
307
+ align?: "start" | "end";
308
+ command?: string;
309
+ until?(scope: {
310
+ projectId?: string;
311
+ }): Maybe<number | null>;
312
+ menu?(scope: {
313
+ projectId?: string;
314
+ }): Maybe<{
315
+ title: string;
316
+ command: string;
317
+ icon?: string;
318
+ }[] | null>;
221
319
  }): Promise<Disposer>;
320
+ /** Every window re-reads this plugin's contributions — for state that changed outside a command run. */
321
+ refresh(): Promise<void>;
222
322
  section(def: {
223
323
  id: string;
224
- title: string;
324
+ title: Localized;
225
325
  render(item: Item): Maybe<{
226
326
  rows?: SectionRow[];
227
327
  text?: string;
@@ -236,6 +336,16 @@ export interface ContributionsApi {
236
336
  projectId: string;
237
337
  }): Maybe<GraphEdge[]>;
238
338
  }): Promise<Disposer>;
339
+ /** A module in the project sidebar. Without `rows` it is a single door; rows returning null hide it in that project. */
340
+ sidebarModule(def: {
341
+ id: string;
342
+ title: Localized;
343
+ icon?: string;
344
+ command?: string;
345
+ rows?(scope: {
346
+ projectId: string;
347
+ }): Maybe<SidebarRow[] | null>;
348
+ }): Promise<Disposer>;
239
349
  }
240
350
  export interface PlaybookSpec {
241
351
  /** Must start with the namespace. */
@@ -246,26 +356,173 @@ export interface PlaybookSpec {
246
356
  body: string;
247
357
  tools?: string[];
248
358
  }
359
+ /** SDK 0.2.14: one block of a model message, as an in-app conversation sends it. */
360
+ export type ModelContent = {
361
+ type: "text";
362
+ text: string;
363
+ } | {
364
+ type: "media";
365
+ media: {
366
+ mime: string;
367
+ base64: string;
368
+ name: string;
369
+ };
370
+ } | {
371
+ type: "tool_call";
372
+ id: string;
373
+ name: string;
374
+ args: unknown;
375
+ } | {
376
+ type: "tool_result";
377
+ id: string;
378
+ content: string;
379
+ isError?: boolean;
380
+ } | {
381
+ type: "native";
382
+ provider: string;
383
+ data: unknown;
384
+ };
385
+ export interface ModelMessage {
386
+ role: "user" | "assistant";
387
+ content: ModelContent[];
388
+ }
389
+ /** A tool as the model is offered it; `inputSchema` is JSON Schema. */
390
+ export interface ModelTool {
391
+ name: string;
392
+ description: string;
393
+ inputSchema: Record<string, unknown>;
394
+ }
395
+ /** Which turn, step and model profile a request belongs to. */
396
+ export interface TurnInfo {
397
+ runId: string;
398
+ threadId: string;
399
+ projectId: string;
400
+ purpose: string;
401
+ profile: string;
402
+ step: number;
403
+ }
404
+ /** SDK 0.2.14: one model request an in-app conversation is about to send. A copy: what the hook answers is what changes. */
405
+ export interface ModelRequest {
406
+ system: string;
407
+ tools: ModelTool[];
408
+ messages: ModelMessage[];
409
+ turn: TurnInfo;
410
+ }
411
+ export type ModelRequestChange = Partial<Pick<ModelRequest, "system" | "tools" | "messages">>;
412
+ export interface ModelRequestFailure {
413
+ /** What the provider or the network said. */
414
+ message: string;
415
+ request: ModelRequest;
416
+ /** How many times this step was already sent again on a hook's answer. */
417
+ attempt: number;
418
+ }
419
+ /** Send the request again: changed, on another model profile (an id from the person's profiles), or both. */
420
+ export interface ModelRetry {
421
+ request?: ModelRequestChange;
422
+ profile?: string;
423
+ }
424
+ export interface TurnEnding {
425
+ /** What the model said last. */
426
+ text: string;
427
+ turn: TurnInfo;
428
+ /** How many times this turn was already kept going. */
429
+ continued: number;
430
+ }
431
+ /**
432
+ * The agent's in-app conversations. The three hooks (SDK 0.2.14) reach the
433
+ * conversation Tomrade runs itself (`engine-loop`); CLI agents — Claude Code,
434
+ * Codex, dsh and the rest — run their own loop and send nothing through them.
435
+ */
249
436
  export interface AgentApi {
250
437
  playbook(spec: PlaybookSpec): Promise<Disposer>;
438
+ /** Before each model request: answer the parts to send instead, or nothing to leave it as it is. */
439
+ request(hook: (request: ModelRequest) => Maybe<ModelRequestChange | void>): Promise<Disposer>;
440
+ /** A model request failed: answer what to try instead, or nothing to let the failure stand. The first plugin to answer decides. */
441
+ requestError(hook: (failure: ModelRequestFailure) => Maybe<ModelRetry | void>): Promise<Disposer>;
442
+ /** A turn is about to end: answer `{ continue }` with a message to the model to keep it going. Bounded, so it cannot run forever. */
443
+ turnEnding(hook: (ending: TurnEnding) => Maybe<{
444
+ continue: string;
445
+ } | void>): Promise<Disposer>;
446
+ /**
447
+ * SDK 0.2.15: a hook in the CLI agents Tomrade works with — Claude Code, Codex, dsh and the rest. It
448
+ * hears their sessions and, in one Tomrade started, may answer: see `CLI_HOOK_COVERAGE` for which.
449
+ */
450
+ cliHook(spec: CliHookSpec): Promise<Disposer>;
451
+ }
452
+ export type { CliHookEvent } from "./cli-hooks.js";
453
+ /** SDK 0.2.15: what a CLI agent's hook says happened, whichever agent sent it. */
454
+ export interface CliHookCall {
455
+ event: import("./cli-hooks.js").CliHookEvent;
456
+ /** `claude-code`, `codex`, `dsh`, `pi`, `workbuddy`, `cursor`, `opencode`, `hermes`… */
457
+ agent: string;
458
+ /** Whether an answer reaches the agent: a session Tomrade started, by an agent that acts on this event. */
459
+ answerable: boolean;
460
+ projectId: string;
461
+ /** Tomrade's code session the hook belongs to. */
462
+ sessionId: string;
463
+ /** The ticket the session works, when it has one. */
464
+ ticket: string | null;
465
+ cwd: string | null;
466
+ tool?: {
467
+ name: string;
468
+ input: unknown;
469
+ output?: string;
470
+ error?: string;
471
+ };
472
+ /** What the model said last, at `stop`. */
473
+ text?: string;
474
+ /** The hook's own payload, as the agent sent it. */
475
+ raw: Record<string, unknown>;
476
+ }
477
+ /** Refuse the tool (`pre-tool`), add context for the model (`session-start`, `prompt`, `post-tool`), or keep the turn going (`stop`). */
478
+ export interface CliHookAnswer {
479
+ deny?: string;
480
+ context?: string;
481
+ continue?: string;
482
+ }
483
+ export interface CliHookSpec {
484
+ /** The events it hears; all of them when left out. */
485
+ events?: import("./cli-hooks.js").CliHookEvent[];
486
+ /** A regular expression the tool's name must match, for `pre-tool` and `post-tool`. */
487
+ tools?: string;
488
+ /** The agents it hears; all of them when left out. */
489
+ agents?: string[];
490
+ handle(call: CliHookCall): Maybe<CliHookAnswer | void>;
251
491
  }
252
492
  export interface SurfaceSpec {
253
493
  id: string;
254
494
  title: string;
495
+ /**
496
+ * SDK 0.2.11: `"window"` is a working window — title bar, resizable, closable, in the Dock or
497
+ * taskbar, its bounds remembered — and needs `permissions.window`. The default `"widget"` is
498
+ * the fixed, frameless surface it always was. A window's title carries the plugin's own.
499
+ */
500
+ kind?: "widget" | "window";
501
+ /** SDK 0.2.11, windows only: how small the person may make it. */
502
+ minWidth?: number;
503
+ minHeight?: number;
255
504
  /** A document inside the plugin's package, relative to its root. Remote pages are refused. */
256
505
  document: string;
257
506
  width: number;
258
507
  height: number;
259
508
  transparent?: boolean;
260
509
  alwaysOnTop?: boolean;
510
+ /** Allow keyboard input; defaults to false for passive widgets. */
511
+ focusable?: boolean;
261
512
  clickThrough?: boolean;
513
+ /** First placed on top of an app element by name — `"sidebar-foot"`: just above the sidebar's Project settings. */
514
+ anchor?: string;
262
515
  initialState?: unknown;
263
516
  /** Messages the document sends; a person is driving, so writes made here are theirs. */
264
517
  onMessage?(message: unknown): Maybe<void>;
518
+ /** Once, when the window is gone — the person closed it, `close()` did, or the plugin unloaded. The handle's other calls then reject. */
519
+ onClose?(): Maybe<void>;
265
520
  }
266
521
  export interface SurfaceHandle {
267
522
  readonly id: string;
268
523
  setState(state: unknown): Promise<void>;
524
+ /** SDK 0.2.11: one message to the document's `tomradeSurface.onMessage`, for frequent small updates; `setState` replaces the whole state. */
525
+ post(message: unknown): Promise<void>;
269
526
  setPosition(x: number, y: number): Promise<void>;
270
527
  bounds(): Promise<{
271
528
  x: number;
@@ -284,6 +541,25 @@ export interface SurfaceHandle {
284
541
  export interface SurfacesApi {
285
542
  open(spec: SurfaceSpec): Promise<SurfaceHandle>;
286
543
  }
544
+ /** A sound the machine offers: `system:<name>`. A file the person chose is played by its absolute path. */
545
+ export interface AlertSound {
546
+ id: string;
547
+ title: string;
548
+ }
549
+ /** Alerts the system raises for the plugin. The plugin chooses when; it never reads the sound file itself. */
550
+ export interface AlertsApi {
551
+ /** The system sounds on this machine, the system's own alert sound first. */
552
+ sounds(): Promise<AlertSound[]>;
553
+ /** Plays a system sound or an audio file once; volume runs 0–1. */
554
+ play(sound: string, opts?: {
555
+ volume?: number;
556
+ }): Promise<void>;
557
+ /** A silent system notification; clicking it brings Tomrade forward. */
558
+ notify(notice: {
559
+ title: string;
560
+ body?: string;
561
+ }): Promise<void>;
562
+ }
287
563
  export interface OplogApi {
288
564
  recent(projectId: string, limit?: number): Promise<OplogEntry[]>;
289
565
  history(projectId: string, entity: OplogEntity, id: string, limit?: number): Promise<OplogEntry[]>;
@@ -325,8 +601,16 @@ export interface PluginContext {
325
601
  readonly tools: ToolsApi;
326
602
  readonly contributions: ContributionsApi;
327
603
  readonly agent: AgentApi;
604
+ readonly im: ImApi;
328
605
  readonly surfaces: SurfacesApi;
606
+ readonly alerts: AlertsApi;
329
607
  readonly oplog: OplogApi;
608
+ /** SDK 0.2.9: answers the agent's web search, as the app's own providers do. */
609
+ readonly webSearch: WebSearchApi;
610
+ /** SDK 0.2.10: live terminals of the herdr panes code sessions run in. */
611
+ readonly terminals: TerminalsApi;
612
+ /** SDK 0.2.16: model providers, as the app's own are. */
613
+ readonly models: ModelsApi;
330
614
  on<K extends keyof Events>(event: K, listener: Events[K]): Disposer;
331
615
  /** Runs `fn` while an optional service is present; what it returns is disposed when the service goes. */
332
616
  when(name: ServiceName, fn: (ctx: PluginContext) => Maybe<Disposer | void>): Disposer;
@@ -337,5 +621,4 @@ export interface PluginContext {
337
621
  /** A timer cleared with the plugin. */
338
622
  interval(fn: () => Maybe<void>, ms: number): Disposer;
339
623
  }
340
- export {};
341
624
  //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The contract each value the SDK exports first shipped in. A plugin imports
3
+ * the SDK from the Tomrade it runs in, not from its own bundle, so a name the
4
+ * oldest Tomrade its `engines.sdk` accepts does not have fails the plugin as it
5
+ * loads. A new export is listed here under the contract it ships in.
6
+ */
7
+ export declare const SDK_EXPORTS: Readonly<Record<string, string>>;
8
+ /** The oldest contract `range` accepts, up to this SDK's own; null when it accepts none of them. */
9
+ export declare function lowestContract(range: string): string | null;
10
+ //# sourceMappingURL=exports.d.ts.map
@@ -0,0 +1,73 @@
1
+ import { SDK_CONTRACT } from "./manifest.js";
2
+ import { compareVersions, parseVersion, satisfies } from "./semver.js";
3
+ /**
4
+ * The contract each value the SDK exports first shipped in. A plugin imports
5
+ * the SDK from the Tomrade it runs in, not from its own bundle, so a name the
6
+ * oldest Tomrade its `engines.sdk` accepts does not have fails the plugin as it
7
+ * loads. A new export is listed here under the contract it ships in.
8
+ */
9
+ export const SDK_EXPORTS = {
10
+ ContributesSchema: "0.2.0",
11
+ MANIFEST_FILE: "0.2.0",
12
+ ManifestSchema: "0.2.0",
13
+ NAMESPACE: "0.2.0",
14
+ OFFICIAL_PUBLISHER: "0.2.0",
15
+ OSI_LICENSES: "0.2.0",
16
+ PLUGIN_ID: "0.2.0",
17
+ PermissionsSchema: "0.2.0",
18
+ RESERVED_NAMESPACES: "0.2.0",
19
+ SDK_CONTRACT: "0.2.0",
20
+ SDK_PLUGIN: "0.2.0",
21
+ ToolInputError: "0.2.0",
22
+ assertOwned: "0.2.0",
23
+ compareVersions: "0.2.0",
24
+ definePlugin: "0.2.0",
25
+ defineTool: "0.2.0",
26
+ isOpenSource: "0.2.0",
27
+ isSdkPlugin: "0.2.0",
28
+ isVersion: "0.2.0",
29
+ nameOf: "0.2.0",
30
+ namespaceOf: "0.2.0",
31
+ ownsId: "0.2.0",
32
+ parseManifest: "0.2.0",
33
+ parseVersion: "0.2.0",
34
+ publisherOf: "0.2.0",
35
+ requireProjectId: "0.2.0",
36
+ riskOf: "0.2.0",
37
+ satisfies: "0.2.0",
38
+ ImDeliveryError: "0.2.1",
39
+ IM_CAPABILITIES_V2: "0.2.5",
40
+ IM_MARKDOWN_DIALECTS: "0.2.5",
41
+ ImCapabilitiesSchema: "0.2.5",
42
+ resolveImCapabilities: "0.2.5",
43
+ splitImText: "0.2.5",
44
+ toImDialect: "0.2.5",
45
+ isRange: "0.2.7",
46
+ LANGUAGE_PACK_LIMITS: "0.2.8",
47
+ LanguageEntrySchema: "0.2.8",
48
+ LanguagePackFileSchema: "0.2.8",
49
+ languageCoverage: "0.2.8",
50
+ parseLanguagePack: "0.2.8",
51
+ slotsOf: "0.2.8",
52
+ SDK_EXPORTS: "0.2.9",
53
+ lowestContract: "0.2.9",
54
+ pickLanguage: "0.2.9",
55
+ wordsFor: "0.2.9",
56
+ RowSchema: "0.2.13",
57
+ CLI_HOOK_COVERAGE: "0.2.15",
58
+ CLI_HOOK_EVENTS: "0.2.15"
59
+ };
60
+ /** The oldest contract `range` accepts, up to this SDK's own; null when it accepts none of them. */
61
+ export function lowestContract(range) {
62
+ const known = [...Object.values(SDK_EXPORTS), SDK_CONTRACT];
63
+ // Every patch of each minor the SDK has shipped, since a contract that added no export is still one a Tomrade may run.
64
+ const lines = new Map();
65
+ for (const v of known) {
66
+ const p = parseVersion(v);
67
+ if (p)
68
+ lines.set(`${p[0]}.${p[1]}`, Math.max(lines.get(`${p[0]}.${p[1]}`) ?? 0, p[2]));
69
+ }
70
+ const candidates = [...lines].flatMap(([line, last]) => Array.from({ length: last + 1 }, (_, patch) => `${line}.${patch}`)).sort(compareVersions);
71
+ return candidates.find((v) => compareVersions(v, SDK_CONTRACT) <= 0 && satisfies(v, range)) ?? null;
72
+ }
73
+ //# sourceMappingURL=exports.js.map
@@ -0,0 +1,10 @@
1
+ import type { ImMarkdownDialect } from "./im.js";
2
+ /** Converts the common layer's Markdown into an adapter's dialect. */
3
+ export declare function toImDialect(markdown: string, dialect: ImMarkdownDialect): string;
4
+ /**
5
+ * Splits Markdown into messages that each fit `max` once converted, breaking
6
+ * between lines. A code block stays whole when it fits a message; a longer one
7
+ * is closed and reopened with its language rather than cut mid-fence.
8
+ */
9
+ export declare function splitImText(markdown: string, max: number, dialect?: ImMarkdownDialect): string[];
10
+ //# sourceMappingURL=im-markdown.d.ts.map