deck-plugin-sdk 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,65 +1,65 @@
1
- // __NAME__ — a Deck plugin.
2
- //
3
- // The default export is the tab. A plugin can export more than that — a footer readout, a
4
- // settings panel, palette commands, a pane view — and `plugins/API.md` in the Deck repository
5
- // lists every slot. One export is enough to start.
6
- import { useState } from "react";
7
- import { Sparkles } from "lucide-react";
8
- import { configRead, configWrite } from "../shim/bridge.js";
9
-
10
- /** Where this plugin's own settings live. The `plugin-` prefix keeps them on this machine. */
11
- const CONFIG = "plugin-__ID__";
12
-
13
- export default function __COMPONENT__() {
14
- const [note, setNote] = useState("");
15
- const [saved, setSaved] = useState(false);
16
-
17
- // Deck's config store, the same one its own modules use. Reading a key that has never been
18
- // written resolves to an empty string rather than throwing.
19
- const load = async () => {
20
- const raw = await configRead(CONFIG).catch(() => "");
21
- setNote(raw.trim() ? (JSON.parse(raw) as { note?: string }).note ?? "" : "");
22
- };
23
-
24
- const save = async () => {
25
- await configWrite(CONFIG, JSON.stringify({ note }));
26
- setSaved(true);
27
- setTimeout(() => setSaved(false), 1500);
28
- };
29
-
30
- return (
31
- <div className="flex h-full flex-col gap-4 p-6">
32
- <header className="flex items-center gap-3">
33
- <Sparkles size={18} style={{ color: "var(--accent)" }} />
34
- <h1 className="text-base font-semibold text-text-primary">__NAME__</h1>
35
- </header>
36
-
37
- <p className="max-w-[60ch] text-sm text-text-secondary">
38
- Edit <code className="rounded bg-elev px-1.5 py-0.5 text-text-primary">src/plugin.tsx</code>,
39
- run <code className="rounded bg-elev px-1.5 py-0.5 text-text-primary">npm run dev</code>,
40
- and Deck reloads the plugin as you save.
41
- </p>
42
-
43
- <div className="flex max-w-md items-center gap-2">
44
- <input
45
- value={note}
46
- onChange={(e) => setNote(e.target.value)}
47
- onFocus={() => void load()}
48
- placeholder="Type something, then save it"
49
- className="min-w-0 flex-1 rounded-lg border border-subtle bg-elev px-3 py-2 text-sm text-text-primary outline-none focus:border-accent"
50
- />
51
- <button
52
- onClick={() => void save()}
53
- className="shrink-0 rounded-lg border border-subtle bg-elev px-3 py-2 text-sm text-text-secondary hover:border-accent hover:text-text-primary"
54
- >
55
- {saved ? "Saved" : "Save"}
56
- </button>
57
- </div>
58
-
59
- <p className="text-xs text-text-muted">
60
- That writes to Deck's config store under <code>{CONFIG}</code>, which stays on this
61
- machine.
62
- </p>
63
- </div>
64
- );
65
- }
1
+ // __NAME__ — a Deck plugin.
2
+ //
3
+ // The default export is the tab. A plugin can export more than that — a footer readout, a
4
+ // settings panel, palette commands, a pane view — and `docs/guide/api.md` in the Deck repository
5
+ // lists every slot. One export is enough to start.
6
+ import { useState } from "react";
7
+ import { Sparkles } from "lucide-react";
8
+ import { configRead, configWrite } from "deck-plugin-sdk/bridge";
9
+
10
+ /** This plugin's own settings. Deck keeps a plugin's configs in its own folder, so a plain name. */
11
+ const CONFIG = "settings";
12
+
13
+ export default function __COMPONENT__() {
14
+ const [note, setNote] = useState("");
15
+ const [saved, setSaved] = useState(false);
16
+
17
+ // Deck's config store, the same one its own modules use. Reading a key that has never been
18
+ // written resolves to an empty string rather than throwing.
19
+ const load = async () => {
20
+ const raw = await configRead(CONFIG).catch(() => "");
21
+ setNote(raw.trim() ? (JSON.parse(raw) as { note?: string }).note ?? "" : "");
22
+ };
23
+
24
+ const save = async () => {
25
+ await configWrite(CONFIG, JSON.stringify({ note }));
26
+ setSaved(true);
27
+ setTimeout(() => setSaved(false), 1500);
28
+ };
29
+
30
+ return (
31
+ <div className="flex h-full flex-col gap-4 p-6">
32
+ <header className="flex items-center gap-3">
33
+ <Sparkles size={18} style={{ color: "var(--accent)" }} />
34
+ <h1 className="text-base font-semibold text-text-primary">__NAME__</h1>
35
+ </header>
36
+
37
+ <p className="max-w-[60ch] text-sm text-text-secondary">
38
+ Edit <code className="rounded bg-elev px-1.5 py-0.5 text-text-primary">src/plugin.tsx</code>,
39
+ run <code className="rounded bg-elev px-1.5 py-0.5 text-text-primary">npm run dev</code>,
40
+ and Deck reloads the plugin as you save.
41
+ </p>
42
+
43
+ <div className="flex max-w-md items-center gap-2">
44
+ <input
45
+ value={note}
46
+ onChange={(e) => setNote(e.target.value)}
47
+ onFocus={() => void load()}
48
+ placeholder="Type something, then save it"
49
+ className="min-w-0 flex-1 rounded-lg border border-subtle bg-elev px-3 py-2 text-sm text-text-primary outline-none focus:border-accent"
50
+ />
51
+ <button
52
+ onClick={() => void save()}
53
+ className="shrink-0 rounded-lg border border-subtle bg-elev px-3 py-2 text-sm text-text-secondary hover:border-accent hover:text-text-primary"
54
+ >
55
+ {saved ? "Saved" : "Save"}
56
+ </button>
57
+ </div>
58
+
59
+ <p className="text-xs text-text-muted">
60
+ That writes to Deck's config store under <code>{CONFIG}</code>, which stays on this
61
+ machine.
62
+ </p>
63
+ </div>
64
+ );
65
+ }
@@ -8,12 +8,22 @@ export interface AppProc {
8
8
  title: string;
9
9
  path: string;
10
10
  }
11
+ /** A config's JSON text, "" when it does not exist yet. The name is its path in Deck's config folder
12
+ * without `.json`, folders and all: `settings/settings`, `state/term-procs`. A plugin names its
13
+ * own configs plainly (`boards`), and they are kept in `data/<plugin id>/`; one of Deck's own it
14
+ * names in full. `config-changed` names configs the same way, a plugin's own as it names them. */
11
15
  export declare const configRead: (name: string) => Promise<string>;
12
16
  /** Raw bytes rather than a JSON argument: a 13.8MB pinboard parsed as JSON on Deck's UI thread
13
17
  * held every other command up for 200ms per save (see config_write in config.rs). */
18
+ /** The name is percent-encoded: it travels in a header, which is ASCII, and a name can be any text
19
+ * (a note's title). */
14
20
  export declare const configWrite: (name: string, json: string) => Promise<void>;
15
- export declare const getVaultRoot: () => Promise<string>;
16
- export declare const setVaultRoot: (path: string) => Promise<void>;
21
+ /** Remove a config or plain file, in order with the writes before it. */
22
+ export declare const configDelete: (name: string) => Promise<void>;
23
+ /** A plugin's own folder in Deck's config folder, `<config dir>\data\<id>`, for listing or
24
+ * renaming the files it keeps there with the fs* calls. A plugin calls it with no argument: its
25
+ * shim knows which plugin it is. */
26
+ export declare const dataDir: (plugin?: string) => Promise<string>;
17
27
  /** The optional readouts in the footer status strip. */
18
28
  /**
19
29
  * A footer readout's id.
@@ -158,9 +168,6 @@ export interface MemUsage {
158
168
  export declare const memUsage: (detail?: boolean) => Promise<MemUsage>;
159
169
  export declare const listApps: () => Promise<AppProc[]>;
160
170
  export declare const listInstalled: () => Promise<AppProc[]>;
161
- export declare const closeApp: (target: string) => Promise<string>;
162
- export declare const openApp: (path: string) => Promise<void>;
163
- export declare const powerAction: (action: string) => Promise<void>;
164
171
  export declare const runScriptNow: (command: string, args: string[], id?: string, name?: string) => Promise<void>;
165
172
  export declare const pickScript: () => Promise<string>;
166
173
  export interface ExecOut {
@@ -174,12 +181,6 @@ export interface ExecOut {
174
181
  * something. A bare name goes through cmd.exe, so PATH and .bat shims (`flutter`, `npm`) work.
175
182
  */
176
183
  export declare const exec: (command: string, args?: string[], cwd?: string) => Promise<ExecOut>;
177
- export declare const notesScope: (cwd: string) => Promise<string>;
178
- export declare const notesList: (scope: string) => Promise<string[]>;
179
- export declare const notesRead: (scope: string, name: string) => Promise<string>;
180
- export declare const notesWrite: (scope: string, name: string, text: string) => Promise<void>;
181
- export declare const notesDelete: (scope: string, name: string) => Promise<void>;
182
- export declare const notesRename: (scope: string, from: string, to: string) => Promise<void>;
183
184
  /** One header, one value. A list rather than a map: order matters, and repeats are legal. */
184
185
  export type HttpHeader = [string, string];
185
186
  export interface HttpSendRequest {
@@ -219,19 +220,6 @@ export declare const httpCancel: (id: string) => Promise<void>;
219
220
  * reply under `job`. The Requests plugin listens for the event and does the send.
220
221
  */
221
222
  export declare const httpSendReply: (job: string, body: string) => Promise<void>;
222
- export interface DownloadItem {
223
- id: string;
224
- url: string;
225
- title: string;
226
- quality: string;
227
- format?: string;
228
- filePath?: string;
229
- sizeBytes?: number;
230
- status: "done" | "failed";
231
- at: number;
232
- }
233
- export declare const readDownloads: () => Promise<string>;
234
- export declare const writeDownloads: (json: string) => Promise<void>;
235
223
  export declare const pickFolder: () => Promise<string>;
236
224
  /** Native "save as" dialog. Returns "" when cancelled. */
237
225
  export declare const pickSavePath: (defaultName: string, ext: string) => Promise<string>;
@@ -246,7 +234,8 @@ export declare const pickImage: () => Promise<string>;
246
234
  export declare const setWallpaper: (src: string) => Promise<string>;
247
235
  export declare const clearWallpaper: () => Promise<void>;
248
236
  export declare const revealInFolder: (path: string) => Promise<void>;
249
- export declare const defaultDownloadDir: () => Promise<string>;
237
+ /** Deck's newest log file (`<config dir>\logs\deck-YYYY-MM-DD.log`), or the folder when empty. */
238
+ export declare const logLatest: () => Promise<string>;
250
239
  export declare const openFile: (path: string) => Promise<void>;
251
240
  /** Files Deck was launched with — a double-click through Explorer's "Open with". */
252
241
  export declare const launchFiles: () => Promise<string[]>;
@@ -261,38 +250,7 @@ export interface TrackMeta {
261
250
  art_path: string;
262
251
  }
263
252
  export declare const readTrackMeta: (paths: string[]) => Promise<TrackMeta[]>;
264
- export interface MusicFolder {
265
- id: string;
266
- name: string;
267
- path: string;
268
- }
269
- export interface MusicPlaylist {
270
- id: string;
271
- name: string;
272
- tracks: string[];
273
- }
274
- export interface MusicLibrary {
275
- folders: MusicFolder[];
276
- favorites: string[];
277
- playlists: MusicPlaylist[];
278
- }
279
- export declare const EMPTY_LIBRARY: MusicLibrary;
280
- export declare const readLibrary: () => Promise<MusicLibrary>;
281
- export declare const writeLibrary: (lib: MusicLibrary) => Promise<void>;
282
253
  export { convertFileSrc } from "@tauri-apps/api/core";
283
- export interface SongSuggestion {
284
- id: string;
285
- title: string;
286
- artist: string;
287
- why: string;
288
- }
289
- export interface MusicSuggestions {
290
- generated_at: number;
291
- songs: SongSuggestion[];
292
- }
293
- export declare const readMusicSuggestions: () => Promise<MusicSuggestions | null>;
294
- export declare const readMusicTaste: () => Promise<string>;
295
- export declare const writeMusicTaste: (text: string) => Promise<void>;
296
254
  /** Start a sign-in. Returns the consent URL to open in the browser. */
297
255
  export declare const googleSignIn: () => Promise<string>;
298
256
  /** A valid access token, refreshed if needed. Rejects when not connected. */
@@ -373,8 +331,6 @@ export interface HistoryEntry {
373
331
  timeOfDay?: string;
374
332
  delayMin?: number;
375
333
  }
376
- export declare const historyDelete: (index: number) => Promise<void>;
377
- export declare const historyClear: (module: string) => Promise<void>;
378
334
  export interface StartupProgram {
379
335
  Name: string;
380
336
  Path: string;
@@ -384,11 +340,8 @@ export interface StartupProgram {
384
340
  End: string;
385
341
  Enabled: boolean;
386
342
  }
387
- export declare const startupRead: () => Promise<string>;
388
- export declare const startupWrite: (json: string) => Promise<void>;
389
343
  export declare const pickExe: () => Promise<string>;
390
344
  export declare const readTermLayout: <T>() => Promise<T | null>;
391
- export declare const writeTermLayout: (layout: unknown) => Promise<void>;
392
345
  /** `mtimeMs` is epoch ms, 0 if unreadable — lets a caller tell a settled file from one still being written. */
393
346
  export interface FsEntry {
394
347
  name: string;
@@ -426,7 +379,8 @@ export declare const remoteHome: (host: string, sudo: boolean) => Promise<string
426
379
  /** Host names from ~/.ssh/config, without patterns. */
427
380
  export declare const sshHosts: () => Promise<string[]>;
428
381
  export declare const fsWrite: (path: string, content: string) => Promise<void>;
429
- /** Raw bytes — saving a response that is an image or a PDF, which a string would corrupt. */
382
+ /** Raw bytes — a PDF, an image, a response — which a string would corrupt. Sent as the raw body,
383
+ * the path percent-encoded in a header; a remote path writes over SSH. */
430
384
  export declare const fsWriteBytes: (path: string, bytes: Uint8Array) => Promise<void>;
431
385
  /** Write bytes without ever clobbering: dedupes the name on collision, returns the path used. */
432
386
  export declare const fsSaveUnique: (saveTo: string, defaultName: string, bytes: Uint8Array) => Promise<string>;
@@ -443,12 +397,10 @@ export declare const fsCreateFile: (dir: string, name: string) => Promise<string
443
397
  export declare const fsOpen: (path: string) => Promise<void>;
444
398
  /** The user's Downloads folder (home if there isn't one). */
445
399
  export declare const dirsDownload: () => Promise<string>;
446
- export declare const vaultResolve: (path: string) => Promise<string>;
447
- export declare const vaultRelativize: (path: string) => Promise<string>;
448
- export declare const vaultDataRead: (name: string) => Promise<string>;
449
- export declare const vaultDataWrite: (name: string, text: string) => Promise<void>;
450
400
  /** Relaunch Deck — the same binary, so a dev instance stays dev. Used by the plugin toggle. */
451
401
  export declare const restartApp: () => Promise<void>;
402
+ /** Start a test Deck (`deck.exe --test`) beside this one, or bring the running one forward. */
403
+ export declare const openTestDeck: () => Promise<void>;
452
404
  /** Fetch the VPS's Script Runner run log over SSH into the local run-log-vps config (vpsjobs.rs). */
453
405
  export declare const vpsRunsPull: () => Promise<void>;
454
406
  /** What Rust saw of this launch, as Unix ms: process creation and the setup() span. Null until
@@ -473,8 +425,6 @@ export declare const backupExport: (path: string) => Promise<BackupSummary>;
473
425
  export declare const backupInspect: (path: string) => Promise<BackupSummary>;
474
426
  /** Writes the backup over this machine's copies. Deck should restart afterwards. */
475
427
  export declare const backupRestore: (path: string) => Promise<BackupSummary>;
476
- /** Copy a plugin folder into the plugins directory. Returns its id. Validates before writing. */
477
- export declare const installPlugin: (src: string) => Promise<string>;
478
428
  /** One file of a plugin, as the registry describes it. */
479
429
  export interface RemoteFile {
480
430
  url: string;
@@ -532,33 +482,19 @@ export declare const fsDelete: (path: string) => Promise<void>;
532
482
  export declare const fsTrash: (path: string) => Promise<void>;
533
483
  export declare const fsCopy: (src: string, dstDir: string) => Promise<string>;
534
484
  export declare const fsReveal: (path: string) => Promise<void>;
535
- export declare const installClaudeHooks: () => Promise<void>;
536
- /**
537
- * Deck's MCP server, which lets an agent drive Deck's terminals and HTTP client.
538
- *
539
- * The server ships with Deck as a single bundled file, so there is nothing to clone or install.
540
- * Registering it adds one entry to ~/.claude.json — a file that belongs to Claude Code, so Deck
541
- * backs it up first, merges rather than replaces, and refuses outright if it cannot parse it.
542
- *
543
- * `claudeMcpStatus` is "missing", "current", or "stale" — stale meaning an entry exists but
544
- * points somewhere else, which is what a reinstall to a different folder leaves behind.
545
- */
546
- export declare const claudeMcpStatus: () => Promise<string>;
547
- export declare const claudeMcpEntry: () => Promise<string>;
548
- export declare const installClaudeMcp: () => Promise<string>;
549
- export declare const removeClaudeMcp: () => Promise<void>;
550
485
  /**
551
- * The same for any AI coding agent Deck knows: "claude", "codex", "gemini" or "cursor". Each keeps
552
- * its MCP servers somewhere else (see agentmcp.rs); the status is the same four answers, with
553
- * "no-node" when nothing could run the server whatever the config says.
486
+ * Deck's MCP server, which lets an agent drive Deck's terminals and HTTP client, registered with
487
+ * an AI coding agent: "claude", "codex", "gemini" or "cursor". The server ships with Deck as a
488
+ * single bundled file. Each agent keeps its MCP servers somewhere else (see agentmcp.rs), a file
489
+ * that belongs to that agent, so Deck backs it up first, merges rather than replaces, and refuses
490
+ * outright if it cannot parse it. The status is "missing", "current", "stale" (an entry pointing
491
+ * somewhere else, as a reinstall to another folder leaves) or "no-node" (nothing could run it).
554
492
  */
555
493
  export declare const agentMcpStatus: (agent: string) => Promise<string>;
556
494
  export declare const installAgentMcp: (agent: string) => Promise<string>;
557
- export declare const removeAgentMcp: (agent: string) => Promise<void>;
558
495
  /** Deck's hooks for an agent that has them ("claude", "codex"): what the Agents panel and the
559
496
  * agent notifications hear from. Merged into the agent's own settings, backed up first. */
560
497
  export declare const installAgentHooks: (agent: string) => Promise<void>;
561
- export declare const removeAgentHooks: (agent: string) => Promise<void>;
562
498
  /**
563
499
  * Deck's skills (how to use its MCP tools) for an agent that reads skills: "claude" or "codex".
564
500
  * Each comes back with what happened to it: "installed", "updated", "current", "kept-yours" (a
@@ -571,8 +507,10 @@ export declare const installAgentSkills: (agent: string) => Promise<{
571
507
  }[]>;
572
508
  /** Which agent command-line tools are on PATH: any of claude, codex, gemini, cursor-agent, cursor. */
573
509
  export declare const agentClis: () => Promise<string[]>;
574
- export declare const removeClaudeHooks: () => Promise<void>;
575
510
  export declare const notifyOs: (title: string, body: string) => Promise<void>;
511
+ /** Run `git -C <dir> <args>`: its stdout, or what git said as the error. Never prompts for
512
+ * credentials. What the Git plugin builds its operations on. */
513
+ export declare const gitRun: (dir: string, args: string[]) => Promise<string>;
576
514
  export declare const gitStatus: (dir: string) => Promise<GitStatusRow[]>;
577
515
  /** The repos a folder holds: the one it is inside first, then any below it. Each a repo's top level. */
578
516
  export declare const gitRepos: (dir: string) => Promise<string[]>;
@@ -584,7 +522,6 @@ export interface BlameLine {
584
522
  uncommitted: boolean;
585
523
  }
586
524
  export declare const gitBlameLine: (dir: string, rel: string, line: number, contents: string) => Promise<BlameLine | null>;
587
- export declare const gitHeadFile: (dir: string, rel: string) => Promise<string>;
588
525
  /** A blob's raw bytes. `rev` is "HEAD", or "" for the index. Empty = absent from that revision.
589
526
  * For content the text commands would corrupt: an image, a font. */
590
527
  export declare const gitFileBytes: (dir: string, rev: string, rel: string) => Promise<Uint8Array<ArrayBuffer>>;
@@ -600,10 +537,6 @@ export declare const gitPoll: (dir: string) => Promise<{
600
537
  rows: GitStatusRow[];
601
538
  info: GitInfo;
602
539
  }>;
603
- export declare const gitCommit: (dir: string, message: string) => Promise<string>;
604
- export declare const gitPush: (dir: string) => Promise<string>;
605
- export declare const gitPull: (dir: string) => Promise<string>;
606
- export declare const gitIndexFile: (dir: string, rel: string) => Promise<string>;
607
540
  export declare const gitFileDiff: (dir: string, rel: string) => Promise<string>;
608
541
  export interface ImportedPack {
609
542
  id: string;
@@ -613,9 +546,6 @@ export interface ImportedPack {
613
546
  export declare const importIconPack: (srcDir: string) => Promise<ImportedPack>;
614
547
  export declare const deleteIconPack: (id: string) => Promise<void>;
615
548
  export declare const readIconPackTheme: (path: string) => Promise<string>;
616
- export declare const gitStage: (dir: string, paths: string[]) => Promise<void>;
617
- export declare const gitStageContent: (dir: string, rel: string, content: string) => Promise<void>;
618
- export declare const gitUnstage: (dir: string, paths: string[]) => Promise<void>;
619
549
  export declare const gitDiscard: (dir: string, paths: string[]) => Promise<void>;
620
550
  export interface GraphCommit {
621
551
  hash: string;
@@ -637,14 +567,6 @@ export interface CommitFile {
637
567
  old?: string;
638
568
  }
639
569
  export declare const gitCommitFiles: (dir: string, hash: string) => Promise<CommitFile[]>;
640
- export declare const gitShowFile: (dir: string, rev: string, rel: string) => Promise<string>;
641
- export declare const gitPullRebase: (dir: string) => Promise<string>;
642
- export declare const gitFetch: (dir: string) => Promise<string>;
643
- export interface GitBranch {
644
- name: string;
645
- current: boolean;
646
- }
647
- export declare const gitBranches: (dir: string) => Promise<GitBranch[]>;
648
570
  export interface GitRef {
649
571
  kind: "local" | "remote" | "tag";
650
572
  name: string;
@@ -660,28 +582,6 @@ export declare const gitCheckoutNew: (dir: string, name: string) => Promise<stri
660
582
  export declare const gitCheckoutTrack: (dir: string, remote: string) => Promise<string>;
661
583
  export declare const gitCheckoutDetach: (dir: string, rev: string) => Promise<string>;
662
584
  export declare const gitAiCommitMsg: (dir: string, command: string, args: string, model: string) => Promise<string>;
663
- export declare const gitCommitAmend: (dir: string, message: string) => Promise<string>;
664
- export declare const gitUndoCommit: (dir: string) => Promise<string>;
665
- export declare const gitBranchAt: (dir: string, name: string, rev: string) => Promise<string>;
666
- export declare const gitRevert: (dir: string, rev: string) => Promise<string>;
667
- export declare const gitCherryPick: (dir: string, rev: string) => Promise<string>;
668
- export declare const gitResetTo: (dir: string, rev: string, mode: "soft" | "mixed" | "hard" | "keep") => Promise<string>;
669
- export declare const gitTag: (dir: string, name: string, rev: string, message?: string) => Promise<string>;
670
- export declare const gitMerge: (dir: string, rev: string, noFf?: boolean) => Promise<string>;
671
- /** Rebase the current branch onto `onto`; a conflict leaves it pending (gitPendingOp → "rebase"). */
672
- export declare const gitRebase: (dir: string, onto: string) => Promise<string>;
673
- /** HEAD's commit and branch ("" when detached) — what an undo returns to. */
674
- export declare const gitHead: (dir: string) => Promise<{
675
- hash: string;
676
- branch: string;
677
- }>;
678
- /** Merge `rev` into the current branch: a merge commit always, fast-forward when possible, or squashed into one commit. */
679
- export declare const gitMergeAs: (dir: string, rev: string, style: "no-ff" | "ff" | "squash") => Promise<string>;
680
- /** Finish a merge, rebase, revert or cherry-pick (what gitPendingOp reported) once its conflicts are staged. */
681
- export declare const gitContinueOp: (dir: string, op: string) => Promise<string>;
682
- /** Subjects of the commits on `head` that `base` lacks, oldest first. */
683
- export declare const gitRangeSubjects: (dir: string, base: string, head: string) => Promise<string[]>;
684
- export declare const gitRemoteUrl: (dir: string, name: string) => Promise<string>;
685
585
  /** The GitHub CLI, `gh pr …` or `gh repo view …` only. Rejects with "gh-missing" when gh is not installed. */
686
586
  export declare const ghRun: (dir: string, args: string[]) => Promise<string>;
687
587
  /** Pull request N's review threads, as GitHub's GraphQL JSON (parsed by prs.ts parseThreads). */
@@ -699,30 +599,6 @@ export declare const glabRun: (dir: string, args: string[]) => Promise<string>;
699
599
  export declare const glabApi: (dir: string, method: "GET" | "POST" | "PUT", path: string, fields?: [string, string][], json?: Record<string, object>) => Promise<string>;
700
600
  /** The files that differ between two revisions. */
701
601
  export declare const gitRangeFiles: (dir: string, from: string, to: string) => Promise<CommitFile[]>;
702
- export declare const gitMergeBase: (dir: string, a: string, b: string) => Promise<string>;
703
- /** Fetch pull request N's head from `remote`, so its commits can be diffed here. `gitlab`: a merge request's. */
704
- export declare const gitFetchPr: (dir: string, remote: string, number: number, base: string, gitlab?: boolean) => Promise<string>;
705
- export declare const gitBranchRename: (dir: string, from: string, to: string) => Promise<string>;
706
- export declare const gitPendingOp: (dir: string) => Promise<string>;
707
- export declare const gitAbortOp: (dir: string, op: string) => Promise<string>;
708
- export declare const gitBranchDelete: (dir: string, name: string, force?: boolean) => Promise<string>;
709
- export declare const gitBranchDeleteRemote: (dir: string, remote: string, name: string) => Promise<string>;
710
- export declare const gitTagDelete: (dir: string, name: string) => Promise<string>;
711
- export declare const gitTagPush: (dir: string, remote: string, name: string) => Promise<string>;
712
- export declare const gitTagDeleteRemote: (dir: string, remote: string, name: string) => Promise<string>;
713
- export declare const gitPushBranch: (dir: string, remote: string, name: string) => Promise<string>;
714
- export declare const gitRemotes: (dir: string) => Promise<string[]>;
715
- export interface GitStash {
716
- index: number;
717
- message: string;
718
- }
719
- export declare const gitStash: (dir: string, kind?: "" | "untracked" | "staged", message?: string) => Promise<string>;
720
- export declare const gitStashShow: (dir: string, index: number) => Promise<string>;
721
- export declare const gitStashList: (dir: string) => Promise<GitStash[]>;
722
- export declare const gitStashApply: (dir: string, index?: number) => Promise<string>;
723
- export declare const gitStashPop: (dir: string, index?: number) => Promise<string>;
724
- export declare const gitStashDrop: (dir: string, index?: number) => Promise<string>;
725
- export declare const gitStashClear: (dir: string) => Promise<string>;
726
602
  export interface SearchHit {
727
603
  path: string;
728
604
  rel: string;
@@ -808,7 +684,6 @@ export declare const dbSchema: (handle: number) => Promise<DbSchema>;
808
684
  /** Open a tunnel. `remote` is host:port as seen FROM `host`. Returns [id, local port]. */
809
685
  export declare const sshTunnelOpen: (host: string, remote: string) => Promise<[number, number]>;
810
686
  export declare const sshTunnelClose: (id: number) => Promise<void>;
811
- export declare const sshTunnelList: () => Promise<[number, number][]>;
812
687
  /**
813
688
  * Offer programs to the editor's debugger: a plugin that runs something debuggable (the Flutter
814
689
  * plugin's runs) publishes them here, and the Run and Debug panel lists them to attach to. Pass
@@ -0,0 +1,50 @@
1
+ // GENERATED by sdk/gen-types.mjs from Deck's source — do not edit.
2
+ export interface SessionTab {
3
+ /** Older sessions can also hold "graph" and "pr" tabs, from before git moved to the Git
4
+ * plugin. The Editor skips them on restore. */
5
+ kind: "file" | "media" | "graph" | "pr";
6
+ path: string;
7
+ rel: string | null;
8
+ dirty?: string;
9
+ }
10
+ export interface WorkspaceSession {
11
+ tabs: SessionTab[];
12
+ activeId: string | null;
13
+ expanded: string[];
14
+ /** A typed-but-uncommitted message. Per root, because a message belongs to the repo it
15
+ * describes. Only the active module is mounted, so without this a half-written message is
16
+ * destroyed by switching to a terminal to check something — which is exactly when you switch. */
17
+ commitMsg?: string;
18
+ /** Collapsed Source Control rows: the two section headers, and folders in tree view. Per root
19
+ * because the keys are paths in this repo. A Set on the way in and out; an array here because
20
+ * that is what survives JSON. */
21
+ scmCollapsed?: string[];
22
+ }
23
+ /** A file to open, and optionally where in it to land. */
24
+ export interface PendingFile {
25
+ path: string;
26
+ line?: number;
27
+ }
28
+ export declare function queueOpenFiles(files: (string | PendingFile)[], instance?: EditorInstance): void;
29
+ /** Take everything queued for one editor, leaving its queue empty. */
30
+ export declare function drainOpenFiles(instance?: EditorInstance): PendingFile[];
31
+ /**
32
+ * Which editor is asking.
33
+ *
34
+ * There are two: the Editor tab, which opens whatever folder you point it at, and the one inside
35
+ * Terminals, which follows that workspace's cwd. They are separate windows onto different work,
36
+ * so their open folder and their UI prefs are stored per instance. Open TABS already separate on
37
+ * their own — loadSession is keyed by root, and the two rarely share one.
38
+ */
39
+ export type EditorInstance = "tab" | "terminals";
40
+ export declare function loadEditorRoot(instance: EditorInstance): string;
41
+ export declare function saveEditorRoot(instance: EditorInstance, root: string): void;
42
+ export interface GlobalUi {
43
+ mdMode: "edit" | "live" | "split" | "preview";
44
+ panel: "explorer" | "search" | "debug" | "scm";
45
+ sidebarW: number;
46
+ }
47
+ export declare function loadSession(root: string): WorkspaceSession | null;
48
+ export declare function saveSession(root: string, s: WorkspaceSession): void;
49
+ export declare function loadUi(instance: EditorInstance): Partial<GlobalUi>;
50
+ export declare function saveUi(instance: EditorInstance, ui: GlobalUi): void;
@@ -0,0 +1,35 @@
1
+ // GENERATED by sdk/gen-types.mjs from Deck's source — do not edit.
2
+ /** The view showing `path` in plugin `pluginId`'s pane view. */
3
+ export declare const fileView: (pluginId: string, path: string) => string;
4
+ /** A view id's own part, and the file it was opened on if any. */
5
+ export declare function splitView(view: string): {
6
+ base: string;
7
+ file?: string;
8
+ };
9
+ /**
10
+ * What two views are compared by, so one file is one tab however its path was spelled: the file
11
+ * tree, a terminal link and Quick Open can each give the same file with other slashes or case
12
+ * (Windows paths are case-insensitive). The stored view keeps the path as given, for the title.
13
+ */
14
+ export declare function viewKey(view: string): string;
15
+ /** A path's extension, lowercased with its dot (".pdf"), or "" when it has none. */
16
+ export declare const extOf: (path: string) => string;
17
+ /** The last part of a path, for a tab's title. */
18
+ export declare const fileName: (path: string) => string;
19
+ /** Extensions as a plugin wrote them (".pdf", "PDF", "pdf"), as extOf returns them. */
20
+ export declare const normaliseExts: (exts: unknown) => string[];
21
+ /**
22
+ * Which loaded plugin opens which file types, from each plugin's `opens` export. Filled by the
23
+ * plugin loader (plugins.ts) on every load; here so that anything can ask without importing it.
24
+ */
25
+ export declare const fileOpeners: {
26
+ id: string;
27
+ exts: string[];
28
+ }[];
29
+ /** The id of the plugin that opens `path` (by its extension), or undefined: the Editor's. */
30
+ export declare function pluginForFile(path: string): string | undefined;
31
+ /**
32
+ * Open `path` in the plugin that claims its type, as a tab of its own. False when no plugin does,
33
+ * so the caller opens it in the Editor as before. Every way Deck opens a file asks this first.
34
+ */
35
+ export declare function openWithPlugin(path: string): boolean;
@@ -300,6 +300,11 @@ export declare function moveWorkspace(id: string, toIndex: number): void;
300
300
  * Empty for a pane that has not spawned yet, which is the honest answer — there is nothing in it.
301
301
  */
302
302
  export declare function paneLines(id: string, max?: number): string[];
303
+ /**
304
+ * Open a file in Deck the way its file tree does: in the plugin that opens its type (a .pdf in the
305
+ * PDF plugin), otherwise in this workspace's Editor, at `line` when given.
306
+ */
307
+ export declare function openFile(path: string, line?: number): void;
303
308
  export declare function getInstance(id: string): Instance;
304
309
  /**
305
310
  * Wrap pasted text in bracketed-paste markers, so the receiving app can tell one paste from
@@ -0,0 +1,19 @@
1
+ // GENERATED by sdk/gen-types.mjs from Deck's source — do not edit.
2
+ import { type RefObject } from "react";
3
+ import { monaco } from "../../core/monaco";
4
+ import { type DirtyRange } from "./hunks";
5
+ /**
6
+ * The peek, for the editor in `edRef` showing `path` with the gutter's `ranges`. Returns what to
7
+ * render (a portal into the overlay), or null while closed.
8
+ *
9
+ * `clean` is whether the editor holds what is on disk: the changes are git's, read from disk, so
10
+ * their line numbers only fit the buffer when it has no unsaved edits. Staging and reverting wait
11
+ * for a save otherwise. `readBase` gives the text a change is against: the index's copy of the
12
+ * file for a change in the working tree, HEAD's for a staged one.
13
+ */
14
+ export declare function useDiffPeek(edRef: RefObject<monaco.editor.IStandaloneCodeEditor | null>, path: string, ranges: DirtyRange[] | undefined, opts: {
15
+ clean: boolean;
16
+ onStage: (r: DirtyRange) => Promise<void>;
17
+ onUnstage: (r: DirtyRange) => Promise<void>;
18
+ readBase: (staged: boolean) => Promise<string>;
19
+ }): import("react").ReactPortal | null;
@@ -1,8 +1,8 @@
1
1
  // GENERATED by sdk/gen-types.mjs from Deck's source — do not edit.
2
2
  import { monaco } from "../../core/monaco";
3
3
  import { type EditorSettings } from "../../core/editorsettings";
4
- import type { DirtyRange } from "./tree";
5
- declare function MonacoEditorInner({ path, rel, value, onChange, onSave, gotoLine, gotoCol, gotoNonce, highlight, dirty, settings, onEditor }: {
4
+ import type { DirtyRange } from "./hunks";
5
+ declare function MonacoEditorInner({ path, rel, value, onChange, onSave, gotoLine, gotoCol, gotoNonce, highlight, dirty, settings, onEditor, clean, onStageChange, onUnstageChange, onReadBase }: {
6
6
  path: string;
7
7
  rel?: string | null;
8
8
  value: string;
@@ -22,6 +22,13 @@ declare function MonacoEditorInner({ path, rel, value, onChange, onSave, gotoLin
22
22
  /** Hands the live editor out, and null on unmount. For a formatting toolbar, which has to
23
23
  * dispatch into this instance rather than rewrite the string around it. */
24
24
  onEditor?: (e: monaco.editor.IStandaloneCodeEditor | null) => void;
25
+ /** The buffer matches the file on disk, which the gutter's changes were read from. */
26
+ clean?: boolean;
27
+ /** Stage or unstage one change from the gutter's peek (DiffPeek.tsx). */
28
+ onStageChange?: (r: DirtyRange) => Promise<void>;
29
+ onUnstageChange?: (r: DirtyRange) => Promise<void>;
30
+ /** The text the file's changes are against: the index's copy, or HEAD's for a staged change. */
31
+ onReadBase?: (staged: boolean) => Promise<string>;
25
32
  }): import("react").JSX.Element;
26
33
  /**
27
34
  * Monaco owns its buffer, so this component re-rendering achieves nothing on its own — yet it was
@@ -35,13 +42,19 @@ declare function MonacoEditorInner({ path, rel, value, onChange, onSave, gotoLin
35
42
  */
36
43
  export declare const MonacoEditor: import("react").MemoExoticComponent<typeof MonacoEditorInner>;
37
44
  export declare function applyLineChanges(original: monaco.editor.ITextModel, modified: monaco.editor.ITextModel, diffs: monaco.editor.ILineChange[]): string;
45
+ type HunkRun = (change: monaco.editor.ILineChange, models: {
46
+ original: monaco.editor.ITextModel;
47
+ modified: monaco.editor.ITextModel;
48
+ }) => void;
49
+ /**
50
+ * Per-change buttons in a diff's gutter: stage (or unstage) one change, and, given `revert`, put
51
+ * one change back to the left side's text. Each change gets them at its first line.
52
+ */
38
53
  export interface HunkAction {
39
54
  label: string;
40
55
  unstage: boolean;
41
- run: (change: monaco.editor.ILineChange, models: {
42
- original: monaco.editor.ITextModel;
43
- modified: monaco.editor.ITextModel;
44
- }) => void;
56
+ run: HunkRun;
57
+ revert?: HunkRun;
45
58
  }
46
59
  /** A side of a diff: LEFT the old version, RIGHT the new — GitHub's names, which line comments use. */
47
60
  export type DiffSide = "LEFT" | "RIGHT";