@vornrun/connector-sdk 0.7.0-beta.13 → 0.7.0-beta.15
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 +118 -2
- package/dist/{packaging-DFTuP4fr.d.ts → check-Cv6UNBA4.d.ts} +292 -75
- package/dist/{chunk-XOP6JKBX.js → chunk-FHGC7LE7.js} +2061 -945
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +9 -6
- package/dist/index.d.ts +51 -4
- package/dist/index.js +23 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -424,6 +424,121 @@ reads the manifest.
|
|
|
424
424
|
Paths are filled with `currentColor`, so the icon picks up the surrounding
|
|
425
425
|
text color instead of fighting the theme.
|
|
426
426
|
|
|
427
|
+
## Extensions
|
|
428
|
+
|
|
429
|
+
A connector polls a service. An **extension** contributes to a session card
|
|
430
|
+
instead: a footer band under the status bar, a pane beside the terminal, or a
|
|
431
|
+
handler offered when a link in the terminal is clicked. It is the same pack —
|
|
432
|
+
same manifest, same check, same receipt, same catalog — declared with
|
|
433
|
+
`defineExtension` rather than `defineConnector`.
|
|
434
|
+
|
|
435
|
+
```ts
|
|
436
|
+
import { defineExtension } from '@vornrun/connector-sdk'
|
|
437
|
+
|
|
438
|
+
export const connector = defineExtension({
|
|
439
|
+
id: 'review',
|
|
440
|
+
name: 'Review',
|
|
441
|
+
description: 'Reads the session',
|
|
442
|
+
permissions: ['terminal.read'],
|
|
443
|
+
activates: { workspaceContains: ['package.json'] },
|
|
444
|
+
footers: [
|
|
445
|
+
{
|
|
446
|
+
id: 'checks',
|
|
447
|
+
title: 'Checks',
|
|
448
|
+
every: 30,
|
|
449
|
+
async run(context) {
|
|
450
|
+
const output = await context.host.output({ lines: 200 })
|
|
451
|
+
return [{ label: 'tests', value: /FAIL/.test(output) ? 'failing' : 'passing' }]
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
],
|
|
455
|
+
panes: [{ id: 'report', title: 'Report', web: 'web/report/index.html' }]
|
|
456
|
+
})
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
Start one with `vorn-connector new review --extension`.
|
|
460
|
+
|
|
461
|
+
### What it may ask the host for
|
|
462
|
+
|
|
463
|
+
Every method of `context.host` costs one permission, and the manifest has to
|
|
464
|
+
declare it. A call outside what was declared is refused rather than answered —
|
|
465
|
+
by `check` against its stub host, and by Vorn at run time — so what a person
|
|
466
|
+
agreed to when installing is what the extension can reach.
|
|
467
|
+
|
|
468
|
+
| Permission | Host method | What it grants |
|
|
469
|
+
| -------------------- | -------------------- | ------------------------------------ |
|
|
470
|
+
| `git.read` | `diff()`, `status()` | The worktree's diff and status |
|
|
471
|
+
| `terminal.read` | `output()` | The session's recent terminal output |
|
|
472
|
+
| `terminal.selection` | `selection()` | The text selected in the terminal |
|
|
473
|
+
| `terminal.send` | `send(text)` | Typing into the session's terminal |
|
|
474
|
+
| `card.rename` | `rename(name)` | Naming the session card |
|
|
475
|
+
| `agent.usage` | `usage()` | Context and provider allowance |
|
|
476
|
+
|
|
477
|
+
Ask for only what the extension spends: `check` names a permission that was
|
|
478
|
+
declared and never used.
|
|
479
|
+
|
|
480
|
+
### Where it shows
|
|
481
|
+
|
|
482
|
+
`activates` on the extension, and `when` on any one contribution, narrow where
|
|
483
|
+
it appears. Every declared field has to hold, and each is satisfied by any one
|
|
484
|
+
of its values, so an extension is simply absent where it has nothing to say.
|
|
485
|
+
|
|
486
|
+
```ts
|
|
487
|
+
activates: {
|
|
488
|
+
workspaceContains: ['Cargo.toml'], // paths relative to the worktree
|
|
489
|
+
remoteHost: ['github.com'],
|
|
490
|
+
agent: ['claude', 'shell'],
|
|
491
|
+
platform: ['darwin', 'linux']
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### What a pane is drawn from
|
|
496
|
+
|
|
497
|
+
A pane is either a page the pack carries or a program it runs. A page lives
|
|
498
|
+
under `web/` in the package, and the directory it sits in is carried into the
|
|
499
|
+
pack, so its stylesheet and script travel with it. Vorn serves the page and
|
|
500
|
+
answers `bridge/<method>` beside it, on the page's own origin: the page holds no
|
|
501
|
+
token, and Vorn grants the call exactly the permissions the manifest declared,
|
|
502
|
+
knowing from the origin which pane is asking. A program is argv, run in the
|
|
503
|
+
session's worktree and drawn as a terminal.
|
|
504
|
+
|
|
505
|
+
```js
|
|
506
|
+
const response = await fetch('bridge/output', {
|
|
507
|
+
method: 'POST',
|
|
508
|
+
headers: { 'content-type': 'application/json' },
|
|
509
|
+
body: JSON.stringify({ lines: 200 })
|
|
510
|
+
})
|
|
511
|
+
const output = (await response.json()).result
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
```ts
|
|
515
|
+
panes: [
|
|
516
|
+
{ id: 'report', title: 'Report', web: 'web/report/index.html' },
|
|
517
|
+
{ id: 'log', title: 'Log', command: ['./bin/log'], when: { agent: ['shell'] } }
|
|
518
|
+
]
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### What a link handler is offered for
|
|
522
|
+
|
|
523
|
+
A handler names the pattern it matches against clicked text, and one example
|
|
524
|
+
link it is for. The example is what `check` runs the handler on, so a handler is
|
|
525
|
+
proved against a link it will really be offered for rather than a made-up one.
|
|
526
|
+
|
|
527
|
+
```ts
|
|
528
|
+
linkHandlers: [
|
|
529
|
+
{
|
|
530
|
+
id: 'pull-request',
|
|
531
|
+
title: 'Pull request',
|
|
532
|
+
pattern: 'https://github\\.com/[^/]+/[^/]+/pull/\\d+',
|
|
533
|
+
example: 'https://github.com/vorn-run/vorn/pull/1',
|
|
534
|
+
async run(context) {
|
|
535
|
+
await context.host.send(`Look at ${context.url}`)
|
|
536
|
+
return { openPane: 'report' }
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
]
|
|
540
|
+
```
|
|
541
|
+
|
|
427
542
|
## CLI
|
|
428
543
|
|
|
429
544
|
```
|
|
@@ -436,9 +551,10 @@ vorn-connector pack <module> Build an installable .vorn.tgz pack
|
|
|
436
551
|
vorn-connector serve <module> Serve on stdio (what Vorn runs)
|
|
437
552
|
```
|
|
438
553
|
|
|
439
|
-
`new` accepts `--out <dir>`, `--name "Display Name"`,
|
|
554
|
+
`new` accepts `--out <dir>`, `--name "Display Name"`, `--repo-conventions`,
|
|
440
555
|
which shapes the package the way the connectors repository expects it (scoped
|
|
441
|
-
name, changelog, compiler and test settings)
|
|
556
|
+
name, changelog, compiler and test settings), and `--extension`, which
|
|
557
|
+
scaffolds an extension rather than a connector; `pack` accepts `--out <dir>`.
|
|
442
558
|
|
|
443
559
|
`poll` accepts `--since <iso>` and `--limit <n>`, and reads the connector's
|
|
444
560
|
declared config from your shell environment — the fastest way to confirm
|
|
@@ -1,49 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Surviving an upstream's bad minute.
|
|
3
|
-
*
|
|
4
|
-
* Every connector eventually meets the same three answers — a rate limit, a
|
|
5
|
-
* gateway that briefly forgot how to work, a socket that died mid-call — and
|
|
6
|
-
* every author writes the same retry loop for them, usually without the one
|
|
7
|
-
* part that matters: only repeating calls that are safe to repeat. Doing it
|
|
8
|
-
* here means a connector gets it by saying nothing at all.
|
|
9
|
-
*/
|
|
10
|
-
interface RetryPolicy {
|
|
11
|
-
/** Total tries, including the first. Defaults to 3. */
|
|
12
|
-
attempts?: number;
|
|
13
|
-
/** First backoff step; each retry doubles it. Defaults to 250ms. */
|
|
14
|
-
baseDelayMs?: number;
|
|
15
|
-
/** Ceiling for any single wait, including one the server asked for. */
|
|
16
|
-
maxDelayMs?: number;
|
|
17
|
-
}
|
|
18
|
-
interface ResilientFetchOptions {
|
|
19
|
-
fetchImpl: typeof fetch;
|
|
20
|
-
/**
|
|
21
|
-
* Whether repeating the call is safe. A read always is; a write is only when
|
|
22
|
-
* the action said so, because retrying a `create` invents a second one.
|
|
23
|
-
*/
|
|
24
|
-
retryable: boolean;
|
|
25
|
-
retry?: RetryPolicy;
|
|
26
|
-
/** Replaced in tests so backoff costs no real time. */
|
|
27
|
-
sleep?: (ms: number) => Promise<void>;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* How long the server asked us to wait, in milliseconds.
|
|
31
|
-
*
|
|
32
|
-
* `Retry-After` is either a count of seconds or an HTTP date; both are common
|
|
33
|
-
* enough that reading only one of them is how a connector ends up hammering a
|
|
34
|
-
* rate limiter it was politely asked to back off from.
|
|
35
|
-
*/
|
|
36
|
-
declare function retryAfterMs(header: string | null, now: number): number | undefined;
|
|
37
|
-
/** The wait before try number `attempt`, counting the first try as zero. */
|
|
38
|
-
declare function backoffMs(attempt: number, policy?: RetryPolicy): number;
|
|
39
|
-
/**
|
|
40
|
-
* Wrap a fetch so it retries what is worth retrying.
|
|
41
|
-
*
|
|
42
|
-
* The wrapper is the value handed to actions as `context.fetch`, so a
|
|
43
|
-
* hand-written action and a declared request are equally protected.
|
|
44
|
-
*/
|
|
45
|
-
declare function resilientFetch(options: ResilientFetchOptions): typeof fetch;
|
|
46
|
-
|
|
47
1
|
/**
|
|
48
2
|
* Author-facing types for Vorn connectors.
|
|
49
3
|
*
|
|
@@ -511,13 +465,252 @@ interface ConnectorDefinition {
|
|
|
511
465
|
*/
|
|
512
466
|
preflight?(): Promise<PreflightResult> | PreflightResult;
|
|
513
467
|
}
|
|
468
|
+
/** What a pack is: a connector polls a service, an extension contributes to a session card. */
|
|
469
|
+
type ConnectorKind = 'connector' | 'extension';
|
|
514
470
|
/** A validated definition. Every accessor below is guaranteed non-null. */
|
|
515
471
|
interface Connector extends ConnectorDefinition {
|
|
516
472
|
readonly version: string;
|
|
517
473
|
readonly config: ConnectorConfigField[];
|
|
518
474
|
readonly triggers: TriggerDefinition[];
|
|
519
475
|
readonly actions: ActionDefinition[];
|
|
476
|
+
readonly kind: ConnectorKind;
|
|
477
|
+
/** What an extension adds to a card. Absent on a connector. */
|
|
478
|
+
readonly contributes?: ExtensionContributions;
|
|
479
|
+
/** What an extension may ask the host for. Absent on a connector. */
|
|
480
|
+
readonly permissions?: ExtensionPermission[];
|
|
481
|
+
/** Where an extension shows at all. Absent on a connector. */
|
|
482
|
+
readonly activates?: ActivationPredicate;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* What an extension may ask the host for, named by what it grants rather than
|
|
486
|
+
* by the method that spends it.
|
|
487
|
+
*
|
|
488
|
+
* A closed set on purpose: a permission is shown to a person before they
|
|
489
|
+
* install, so every one of them has to be a sentence someone can weigh.
|
|
490
|
+
*/
|
|
491
|
+
type ExtensionPermission = 'git.read' | 'terminal.read' | 'terminal.selection' | 'terminal.send' | 'card.rename' | 'agent.usage';
|
|
492
|
+
/** Session types an extension can name; `shell` is a plain terminal. */
|
|
493
|
+
type ExtensionAgent = 'claude' | 'copilot' | 'codex' | 'opencode' | 'gemini' | 'shell';
|
|
494
|
+
type ExtensionPlatform = 'darwin' | 'linux' | 'win32';
|
|
495
|
+
/**
|
|
496
|
+
* Where a contribution shows.
|
|
497
|
+
*
|
|
498
|
+
* Every declared field must hold for it to show, and each is satisfied by any
|
|
499
|
+
* one of its values: a Rust footer says `workspaceContains: ['Cargo.toml']`
|
|
500
|
+
* and is simply absent everywhere else, rather than reporting nothing.
|
|
501
|
+
*/
|
|
502
|
+
interface ActivationPredicate {
|
|
503
|
+
/** Paths relative to the session's worktree; any one of them existing is enough. */
|
|
504
|
+
workspaceContains?: string[];
|
|
505
|
+
/** Host of the worktree's git remote, e.g. `github.com`. */
|
|
506
|
+
remoteHost?: string[];
|
|
507
|
+
agent?: ExtensionAgent[];
|
|
508
|
+
platform?: ExtensionPlatform[];
|
|
509
|
+
}
|
|
510
|
+
interface ContributionBase {
|
|
511
|
+
/** Stable within the extension; the host addresses the contribution by it. */
|
|
512
|
+
id: string;
|
|
513
|
+
title: string;
|
|
514
|
+
description?: string;
|
|
515
|
+
/** Narrows where this one shows, inside where the extension is active at all. */
|
|
516
|
+
when?: ActivationPredicate;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* A pane the extension adds beside the terminal: either a page it ships or a
|
|
520
|
+
* program it runs, never both — a union, so the invalid pair is a type error
|
|
521
|
+
* while the extension is being written.
|
|
522
|
+
*/
|
|
523
|
+
type PaneContribution = ContributionBase & {
|
|
524
|
+
/** Glyph for the menu row and the pane's own bar; the extension's is used when absent. */
|
|
525
|
+
icon?: ConnectorIcon;
|
|
526
|
+
} & ({
|
|
527
|
+
/** Page inside the pack, under `web/`, rendered in a pane. */
|
|
528
|
+
web: string;
|
|
529
|
+
command?: never;
|
|
530
|
+
} | {
|
|
531
|
+
/** Argv run in the session's worktree, drawn as a terminal. */
|
|
532
|
+
command: string[];
|
|
533
|
+
web?: never;
|
|
534
|
+
});
|
|
535
|
+
/** One reading in a footer band: a label, its value, and how the value reads. */
|
|
536
|
+
interface FooterItem {
|
|
537
|
+
label: string;
|
|
538
|
+
value: string;
|
|
539
|
+
/** `ok` and `danger` colour the value; anything else is ordinary text. */
|
|
540
|
+
tone?: 'default' | 'ok' | 'danger';
|
|
541
|
+
/** Opened when the item is clicked, for a reading that points somewhere. */
|
|
542
|
+
href?: string;
|
|
543
|
+
}
|
|
544
|
+
/** What the agent's provider says is left, for the windows it publishes. */
|
|
545
|
+
interface ExtensionUsageWindow {
|
|
546
|
+
/** The window's own name, e.g. `5h`. */
|
|
547
|
+
window: string;
|
|
548
|
+
/** How much of the allowance is left, 0 to 1. */
|
|
549
|
+
remaining: number;
|
|
550
|
+
resetsAt?: string;
|
|
551
|
+
}
|
|
552
|
+
interface ExtensionUsage {
|
|
553
|
+
contextTokens?: number;
|
|
554
|
+
contextWindow?: number;
|
|
555
|
+
/** Session-cumulative prompt-cache hit rate, 0 to 1. */
|
|
556
|
+
cacheHitRate?: number;
|
|
557
|
+
limits?: ExtensionUsageWindow[];
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* The host, as an extension sees it.
|
|
561
|
+
*
|
|
562
|
+
* Every method costs exactly one permission — `HOST_PERMISSIONS` says which —
|
|
563
|
+
* and calling one the manifest did not declare is refused rather than ignored,
|
|
564
|
+
* so an extension cannot quietly reach past what a person agreed to.
|
|
565
|
+
*/
|
|
566
|
+
interface ExtensionHost {
|
|
567
|
+
/** The worktree's diff against its base. */
|
|
568
|
+
diff(): Promise<string>;
|
|
569
|
+
/** Porcelain status of the worktree. */
|
|
570
|
+
status(): Promise<string>;
|
|
571
|
+
/** The session's recent terminal output, newest last. */
|
|
572
|
+
output(options?: {
|
|
573
|
+
lines?: number;
|
|
574
|
+
}): Promise<string>;
|
|
575
|
+
/** The text selected in the terminal, empty when nothing is selected. */
|
|
576
|
+
selection(): Promise<string>;
|
|
577
|
+
/** Type text into the session's terminal, as a person would. */
|
|
578
|
+
send(text: string): Promise<void>;
|
|
579
|
+
/** Name the session card, until a person names it themselves. */
|
|
580
|
+
rename(name: string): Promise<void>;
|
|
581
|
+
/** Context and provider allowance for the session's agent. */
|
|
582
|
+
usage(): Promise<ExtensionUsage>;
|
|
583
|
+
}
|
|
584
|
+
/** Every method of the host, so the table naming what each one costs stays complete. */
|
|
585
|
+
type ExtensionHostMethod = keyof ExtensionHost;
|
|
586
|
+
/** What a contribution is told about the session it is running for. */
|
|
587
|
+
interface ExtensionContext {
|
|
588
|
+
sessionId: string;
|
|
589
|
+
/** Where the session's work is, so a contribution reads the tree it is about. */
|
|
590
|
+
worktreePath: string;
|
|
591
|
+
agent: ExtensionAgent;
|
|
592
|
+
host: ExtensionHost;
|
|
593
|
+
/** Injectable clock so tests are deterministic. */
|
|
594
|
+
now(): string;
|
|
595
|
+
}
|
|
596
|
+
/** What a link handler is told, on top of the session it was clicked in. */
|
|
597
|
+
interface LinkContext extends ExtensionContext {
|
|
598
|
+
/** The clicked text, which matched this handler's pattern. */
|
|
599
|
+
url: string;
|
|
600
|
+
}
|
|
601
|
+
/** What a link handler asks the app to do once it has run. */
|
|
602
|
+
interface LinkHandled {
|
|
603
|
+
/** Id of one of this extension's panes, opened for the session. */
|
|
604
|
+
openPane?: string;
|
|
605
|
+
}
|
|
606
|
+
/** A band under the card's status bar, recomputed on its own interval. */
|
|
607
|
+
interface FooterContribution extends ContributionBase {
|
|
608
|
+
/** Seconds between calls; the host polls no faster than this. */
|
|
609
|
+
every: number;
|
|
610
|
+
run(context: ExtensionContext): Promise<FooterItem[]> | FooterItem[];
|
|
611
|
+
}
|
|
612
|
+
/** Offers this extension when the clicked text in a terminal matches. */
|
|
613
|
+
interface LinkHandlerContribution extends ContributionBase {
|
|
614
|
+
/** Matched as a regular expression against clicked text, under a bound the app sets. */
|
|
615
|
+
pattern: string;
|
|
616
|
+
/** A link this handler is for, which its pattern must match; `check` runs the handler on it. */
|
|
617
|
+
example: string;
|
|
618
|
+
run(context: LinkContext): Promise<LinkHandled | void> | LinkHandled | void;
|
|
619
|
+
}
|
|
620
|
+
interface ExtensionContributions {
|
|
621
|
+
panes?: PaneContribution[];
|
|
622
|
+
footers?: FooterContribution[];
|
|
623
|
+
linkHandlers?: LinkHandlerContribution[];
|
|
624
|
+
}
|
|
625
|
+
interface ExtensionDefinition {
|
|
626
|
+
/** Stable extension id, e.g. `review`. */
|
|
627
|
+
id: string;
|
|
628
|
+
name: string;
|
|
629
|
+
version?: string;
|
|
630
|
+
description?: string;
|
|
631
|
+
icon?: ConnectorIcon;
|
|
632
|
+
/** Everything this extension may ask the host for, declared rather than inferred. */
|
|
633
|
+
permissions: ExtensionPermission[];
|
|
634
|
+
/** Where the extension shows at all; absent means every session. */
|
|
635
|
+
activates?: ActivationPredicate;
|
|
636
|
+
panes?: PaneContribution[];
|
|
637
|
+
footers?: FooterContribution[];
|
|
638
|
+
linkHandlers?: LinkHandlerContribution[];
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* What a connector must be true of as a *package*, rather than as a definition.
|
|
643
|
+
*
|
|
644
|
+
* Both `check` and `pack` ask these questions — check to fail a pull request
|
|
645
|
+
* early, pack to refuse an artifact — so they live here rather than in either,
|
|
646
|
+
* and neither imports the other.
|
|
647
|
+
*/
|
|
648
|
+
/** Largest pack Vorn will install, matched by the server's own verification. */
|
|
649
|
+
declare const MAX_PACK_BYTES: number;
|
|
650
|
+
interface BundleRequest {
|
|
651
|
+
contents: string;
|
|
652
|
+
resolveDir: string;
|
|
520
653
|
}
|
|
654
|
+
interface BundleOutput {
|
|
655
|
+
code: string;
|
|
656
|
+
/** Specifiers the bundler left for the runtime to resolve. */
|
|
657
|
+
external: string[];
|
|
658
|
+
}
|
|
659
|
+
/** Reject a source package whose install would run code on the user's machine. */
|
|
660
|
+
declare function lifecycleScriptFindings(pkg: unknown): CheckFinding[];
|
|
661
|
+
/** Specifiers left outside a bundle, which would need a registry at launch. */
|
|
662
|
+
declare function bundleDependencyFindings(external: string[]): CheckFinding[];
|
|
663
|
+
declare function bundledRequireFindings(code: string): CheckFinding[];
|
|
664
|
+
/** Nearest package.json at or above a directory, or undefined when there is none. */
|
|
665
|
+
declare function readNearestPackageJson(fromDir: string): Record<string, unknown> | undefined;
|
|
666
|
+
/** The bundler `pack` uses, shared so `check` gates on the same answer. */
|
|
667
|
+
declare function esbuildBundle(request: BundleRequest): Promise<BundleOutput>;
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Surviving an upstream's bad minute.
|
|
671
|
+
*
|
|
672
|
+
* Every connector eventually meets the same three answers — a rate limit, a
|
|
673
|
+
* gateway that briefly forgot how to work, a socket that died mid-call — and
|
|
674
|
+
* every author writes the same retry loop for them, usually without the one
|
|
675
|
+
* part that matters: only repeating calls that are safe to repeat. Doing it
|
|
676
|
+
* here means a connector gets it by saying nothing at all.
|
|
677
|
+
*/
|
|
678
|
+
interface RetryPolicy {
|
|
679
|
+
/** Total tries, including the first. Defaults to 3. */
|
|
680
|
+
attempts?: number;
|
|
681
|
+
/** First backoff step; each retry doubles it. Defaults to 250ms. */
|
|
682
|
+
baseDelayMs?: number;
|
|
683
|
+
/** Ceiling for any single wait, including one the server asked for. */
|
|
684
|
+
maxDelayMs?: number;
|
|
685
|
+
}
|
|
686
|
+
interface ResilientFetchOptions {
|
|
687
|
+
fetchImpl: typeof fetch;
|
|
688
|
+
/**
|
|
689
|
+
* Whether repeating the call is safe. A read always is; a write is only when
|
|
690
|
+
* the action said so, because retrying a `create` invents a second one.
|
|
691
|
+
*/
|
|
692
|
+
retryable: boolean;
|
|
693
|
+
retry?: RetryPolicy;
|
|
694
|
+
/** Replaced in tests so backoff costs no real time. */
|
|
695
|
+
sleep?: (ms: number) => Promise<void>;
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* How long the server asked us to wait, in milliseconds.
|
|
699
|
+
*
|
|
700
|
+
* `Retry-After` is either a count of seconds or an HTTP date; both are common
|
|
701
|
+
* enough that reading only one of them is how a connector ends up hammering a
|
|
702
|
+
* rate limiter it was politely asked to back off from.
|
|
703
|
+
*/
|
|
704
|
+
declare function retryAfterMs(header: string | null, now: number): number | undefined;
|
|
705
|
+
/** The wait before try number `attempt`, counting the first try as zero. */
|
|
706
|
+
declare function backoffMs(attempt: number, policy?: RetryPolicy): number;
|
|
707
|
+
/**
|
|
708
|
+
* Wrap a fetch so it retries what is worth retrying.
|
|
709
|
+
*
|
|
710
|
+
* The wrapper is the value handed to actions as `context.fetch`, so a
|
|
711
|
+
* hand-written action and a declared request are equally protected.
|
|
712
|
+
*/
|
|
713
|
+
declare function resilientFetch(options: ResilientFetchOptions): typeof fetch;
|
|
521
714
|
|
|
522
715
|
interface PollPage {
|
|
523
716
|
items: NormalizedItem[];
|
|
@@ -574,6 +767,10 @@ declare function runAction(connector: Connector, actionType: string, args: Recor
|
|
|
574
767
|
|
|
575
768
|
/** MCP tool name a trigger is served under. */
|
|
576
769
|
declare function pollToolName(triggerType: string): string;
|
|
770
|
+
/** MCP tool name a footer is recomputed under. */
|
|
771
|
+
declare function footerToolName(footerId: string): string;
|
|
772
|
+
/** MCP tool name a link handler is run under. */
|
|
773
|
+
declare function handlerToolName(handlerId: string): string;
|
|
577
774
|
/** Tool that reports the connector's manifest and setup hints. */
|
|
578
775
|
declare const MANIFEST_TOOL = "vorn_connector_manifest";
|
|
579
776
|
/**
|
|
@@ -621,14 +818,43 @@ interface ConnectionSetup {
|
|
|
621
818
|
* strategy — rather than Vorn's timestamp comparison — decide what is new.
|
|
622
819
|
*/
|
|
623
820
|
declare function connectionSetup(connector: Connector, triggerType: string): ConnectionSetup;
|
|
821
|
+
/** A contribution as the manifest carries it: everything but the code that runs it. */
|
|
822
|
+
interface ManifestContribution {
|
|
823
|
+
id: string;
|
|
824
|
+
title: string;
|
|
825
|
+
description?: string;
|
|
826
|
+
when?: ActivationPredicate;
|
|
827
|
+
}
|
|
828
|
+
interface ManifestContributions {
|
|
829
|
+
panes?: Array<ManifestContribution & {
|
|
830
|
+
icon?: ConnectorIcon;
|
|
831
|
+
web?: string;
|
|
832
|
+
command?: string[];
|
|
833
|
+
}>;
|
|
834
|
+
footers?: Array<ManifestContribution & {
|
|
835
|
+
every: number;
|
|
836
|
+
}>;
|
|
837
|
+
linkHandlers?: Array<ManifestContribution & {
|
|
838
|
+
pattern: string;
|
|
839
|
+
example: string;
|
|
840
|
+
}>;
|
|
841
|
+
}
|
|
624
842
|
interface ConnectorManifest {
|
|
625
843
|
id: string;
|
|
626
844
|
name: string;
|
|
627
845
|
version: string;
|
|
846
|
+
/** Absent on a manifest written before extensions, which reads as a connector. */
|
|
847
|
+
kind?: ConnectorKind;
|
|
628
848
|
description?: string;
|
|
629
849
|
icon?: ConnectorIcon;
|
|
630
850
|
/** How the connector signs in, so the app can say so before installing it. */
|
|
631
851
|
auth?: ConnectorAuth;
|
|
852
|
+
/** What an extension adds to a card. Present only on an extension. */
|
|
853
|
+
contributes?: ManifestContributions;
|
|
854
|
+
/** What an extension may ask the host for. Present only on an extension. */
|
|
855
|
+
permissions?: ExtensionPermission[];
|
|
856
|
+
/** Where an extension shows at all. Present only on an extension. */
|
|
857
|
+
activates?: ActivationPredicate;
|
|
632
858
|
triggers: Array<{
|
|
633
859
|
type: string;
|
|
634
860
|
label: string;
|
|
@@ -755,6 +981,24 @@ declare function withMockHttp<T>(routes: MockRoute[], body: () => Promise<T> | T
|
|
|
755
981
|
* spawning anything. Authors get real assertions in a plain unit test.
|
|
756
982
|
*/
|
|
757
983
|
declare function createConnectorHarness(connector: Connector, harnessOptions?: HarnessOptions): ConnectorHarness;
|
|
984
|
+
/** Answers a footer or handler from fixtures, and refuses what the manifest never asked for. */
|
|
985
|
+
interface MockHostRun {
|
|
986
|
+
host: ExtensionHost;
|
|
987
|
+
/** Permissions the run actually spent, so a declared-but-unused one can be named. */
|
|
988
|
+
used: Set<ExtensionPermission>;
|
|
989
|
+
}
|
|
990
|
+
/** Replaces what the stub answers, for a test whose subject is the reading rather than the plumbing. */
|
|
991
|
+
type MockHostAnswers = Partial<{
|
|
992
|
+
[K in ExtensionHostMethod]: ExtensionHost[K];
|
|
993
|
+
}>;
|
|
994
|
+
/**
|
|
995
|
+
* A host that answers from fixtures and enforces the manifest.
|
|
996
|
+
*
|
|
997
|
+
* The check runs every footer and handler against this rather than a real
|
|
998
|
+
* session, which is what lets a conformance run catch an extension reaching
|
|
999
|
+
* for something it never declared — before a person is asked to grant it.
|
|
1000
|
+
*/
|
|
1001
|
+
declare function mockExtensionHost(granted: readonly ExtensionPermission[], answers?: MockHostAnswers): MockHostRun;
|
|
758
1002
|
|
|
759
1003
|
/**
|
|
760
1004
|
* Every finding this SDK can report.
|
|
@@ -763,7 +1007,7 @@ declare function createConnectorHarness(connector: Connector, harnessOptions?: H
|
|
|
763
1007
|
* named check owns is a compile error rather than a receipt quietly vouching
|
|
764
1008
|
* for a check whose failure nothing was watching.
|
|
765
1009
|
*/
|
|
766
|
-
type CheckCode = 'missing-description' | 'auth-undeclared' | 'auth-probe-missing' | 'secret-not-marked' | 'action-no-outputs' | 'input-type-unsupported' | 'missing-idempotent' | 'unverifiable' | 'sample-unusable' | 'poll-failed' | 'no-items' | 'no-cursor' | 'cursor-rejected' | 'redelivers-items' | 'stuck-cursor' | 'lifecycle-scripts' | 'keywords-missing' | 'runtime-dependencies' | 'mock-action-failed' | 'mock-network-escape' | 'mock-not-observed' | 'preflight-failed' | 'live-action-failed' | 'pack-too-large';
|
|
1010
|
+
type CheckCode = 'missing-description' | 'auth-undeclared' | 'auth-probe-missing' | 'secret-not-marked' | 'action-no-outputs' | 'input-type-unsupported' | 'missing-idempotent' | 'unverifiable' | 'sample-unusable' | 'poll-failed' | 'no-items' | 'no-cursor' | 'cursor-rejected' | 'redelivers-items' | 'stuck-cursor' | 'lifecycle-scripts' | 'keywords-missing' | 'runtime-dependencies' | 'mock-action-failed' | 'mock-network-escape' | 'mock-not-observed' | 'preflight-failed' | 'live-action-failed' | 'pack-launch' | 'pack-too-large' | 'web-entry-missing' | 'web-entry-outside-package' | 'footer-failed' | 'footer-items-invalid' | 'handler-failed' | 'permission-undeclared' | 'permission-unused';
|
|
767
1011
|
interface CheckFinding {
|
|
768
1012
|
/** `error` means the connector will misbehave in Vorn; `warn` is advisory. */
|
|
769
1013
|
level: 'error' | 'warn';
|
|
@@ -852,31 +1096,4 @@ declare function runConformance(connector: Connector, options?: CheckOptions): P
|
|
|
852
1096
|
/** Render findings for a terminal. Returns an empty string when all clear. */
|
|
853
1097
|
declare function formatFindings(findings: CheckFinding[]): string;
|
|
854
1098
|
|
|
855
|
-
|
|
856
|
-
* What a connector must be true of as a *package*, rather than as a definition.
|
|
857
|
-
*
|
|
858
|
-
* Both `check` and `pack` ask these questions — check to fail a pull request
|
|
859
|
-
* early, pack to refuse an artifact — so they live here rather than in either,
|
|
860
|
-
* and neither imports the other.
|
|
861
|
-
*/
|
|
862
|
-
/** Largest pack Vorn will install, matched by the server's own verification. */
|
|
863
|
-
declare const MAX_PACK_BYTES: number;
|
|
864
|
-
interface BundleRequest {
|
|
865
|
-
contents: string;
|
|
866
|
-
resolveDir: string;
|
|
867
|
-
}
|
|
868
|
-
interface BundleOutput {
|
|
869
|
-
code: string;
|
|
870
|
-
/** Specifiers the bundler left for the runtime to resolve. */
|
|
871
|
-
external: string[];
|
|
872
|
-
}
|
|
873
|
-
/** Reject a source package whose install would run code on the user's machine. */
|
|
874
|
-
declare function lifecycleScriptFindings(pkg: unknown): CheckFinding[];
|
|
875
|
-
/** Specifiers left outside a bundle, which would need a registry at launch. */
|
|
876
|
-
declare function bundleDependencyFindings(external: string[]): CheckFinding[];
|
|
877
|
-
/** Nearest package.json at or above a directory, or undefined when there is none. */
|
|
878
|
-
declare function readNearestPackageJson(fromDir: string): Record<string, unknown> | undefined;
|
|
879
|
-
/** The bundler `pack` uses, shared so `check` gates on the same answer. */
|
|
880
|
-
declare function esbuildBundle(request: BundleRequest): Promise<BundleOutput>;
|
|
881
|
-
|
|
882
|
-
export { type StatusSuggestion as $, type ActionRequest as A, type BundleRequest as B, type ConnectorDefinition as C, type DedupeStrategy as D, MAX_PACK_BYTES as E, type FetchContext as F, MAX_POLL_PAGES as G, type HarnessOptions as H, type MockCall as I, type MockRoute as J, MockRouteMissError as K, type MockRun as L, MANIFEST_TOOL as M, type NormalizedItem as N, OPTIONS_TOOL as O, type PollContext as P, type OptionsContext as Q, type OptionsLoader as R, PREFLIGHT_TOOL as S, type TriggerDefinition as T, type PaginationStrategy as U, type PollPage as V, type PreflightResult as W, type ResilientFetchOptions as X, type RetryPolicy as Y, type RunActionOptions as Z, type RunPollOptions as _, type BundleOutput as a, backoffMs as a0, bundleDependencyFindings as a1, checkConnector as a2, connectionSetup as a3, connectorManifest as a4, createConnectorHarness as a5, drainPoll as a6, esbuildBundle as a7, escapedMockHttp as a8, formatFindings as a9, lifecycleScriptFindings as aa, pollToolName as ab, readNearestPackageJson as ac, resilientFetch as ad, retryAfterMs as ae, runAction as af, runConformance as ag, runOptions as ah, runPoll as ai, withMockHttp as aj, type Connector as b, type ConnectorConfig as c, type PollOutcome as d, type ConnectorItem as e, type PostReceiveOp as f, type CheckFinding as g, type ActionContext as h, type ActionDefinition as i, type ActionInputField as j, type ActionInputOption as k, type ActionInputType as l, type ActionOutputField as m, type AuthRung as n, CHECK_OWNERS as o, type CheckCode as p, type CheckOptions as q, type ConformanceRun as r, type ConnectionSetup as s, type ConnectorAuth as t, type ConnectorConfigField as u, type ConnectorHarness as v, type ConnectorIcon as w, type ConnectorManifest as x, type ConnectorVerification as y, type DefaultWorkflow as z };
|
|
1099
|
+
export { MAX_PACK_BYTES as $, type ActionRequest as A, type BundleRequest as B, type CheckFinding as C, type ConnectorIcon as D, type ExtensionPermission as E, type ConnectorKind as F, type ConnectorManifest as G, type ConnectorVerification as H, type DedupeStrategy as I, type DefaultWorkflow as J, type ExtensionAgent as K, type ExtensionContext as L, type ExtensionContributions as M, type NormalizedItem as N, type ExtensionPlatform as O, type PollContext as P, type ExtensionUsage as Q, type ExtensionUsageWindow as R, type FetchContext as S, type TriggerDefinition as T, type FooterContribution as U, type FooterItem as V, type HarnessOptions as W, type LinkContext as X, type LinkHandled as Y, type LinkHandlerContribution as Z, MANIFEST_TOOL as _, type BundleOutput as a, MAX_POLL_PAGES as a0, type ManifestContributions as a1, type MockCall as a2, type MockHostAnswers as a3, type MockHostRun as a4, type MockRoute as a5, MockRouteMissError as a6, type MockRun as a7, OPTIONS_TOOL as a8, type OptionsContext as a9, pollToolName as aA, readNearestPackageJson as aB, resilientFetch as aC, retryAfterMs as aD, runAction as aE, runConformance as aF, runOptions as aG, runPoll as aH, withMockHttp as aI, type OptionsLoader as aa, PREFLIGHT_TOOL as ab, type PaginationStrategy as ac, type PaneContribution as ad, type PollPage as ae, type PreflightResult as af, type ResilientFetchOptions as ag, type RetryPolicy as ah, type RunActionOptions as ai, type RunPollOptions as aj, type StatusSuggestion as ak, backoffMs as al, bundleDependencyFindings as am, bundledRequireFindings as an, checkConnector as ao, connectionSetup as ap, connectorManifest as aq, createConnectorHarness as ar, drainPoll as as, esbuildBundle as at, escapedMockHttp as au, footerToolName as av, formatFindings as aw, handlerToolName as ax, lifecycleScriptFindings as ay, mockExtensionHost as az, type ExtensionHostMethod as b, type ConnectorDefinition as c, type Connector as d, type ExtensionDefinition as e, type ConnectorConfig as f, type ExtensionHost as g, type PollOutcome as h, type ConnectorItem as i, type PostReceiveOp as j, type ActionContext as k, type ActionDefinition as l, type ActionInputField as m, type ActionInputOption as n, type ActionInputType as o, type ActionOutputField as p, type ActivationPredicate as q, type AuthRung as r, CHECK_OWNERS as s, type CheckCode as t, type CheckOptions as u, type ConformanceRun as v, type ConnectionSetup as w, type ConnectorAuth as x, type ConnectorConfigField as y, type ConnectorHarness as z };
|