@neosh/api 0.3.0 → 0.4.1
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/package.json +1 -1
- package/src/generated/ApiCall.ts +114 -0
- package/src/generated/ApiOk.ts +10 -1
- package/src/generated/AscpMessage.ts +2 -0
- package/src/generated/AuthRef.ts +6 -1
- package/src/generated/ChecksState.ts +14 -0
- package/src/generated/CredentialSource.ts +1 -0
- package/src/generated/Direction.ts +6 -0
- package/src/generated/Dock.ts +10 -4
- package/src/generated/FloatConfig.ts +33 -0
- package/src/generated/ModelInfo.ts +16 -0
- package/src/generated/NodeCapabilities.ts +11 -0
- package/src/generated/PaneChild.ts +18 -0
- package/src/generated/PaneId.ts +15 -0
- package/src/generated/PaneNode.ts +17 -0
- package/src/generated/PluginEvent.ts +1 -0
- package/src/generated/PullRequest.ts +30 -0
- package/src/generated/PullState.ts +11 -0
- package/src/generated/RemoteProject.ts +18 -0
- package/src/generated/ScrollAmount.ts +16 -0
- package/src/generated/SplitDir.ts +12 -0
- package/src/generated/TabId.ts +10 -0
- package/src/generated/TabInfo.ts +27 -0
- package/src/generated/UiEvent.ts +4 -0
- package/src/generated/WindowLayout.ts +11 -0
- package/src/index.ts +444 -9
- package/src/ui.ts +403 -70
package/package.json
CHANGED
package/src/generated/ApiCall.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { Capability } from "./Capability";
|
|
|
5
5
|
import type { CursorMotion } from "./CursorMotion";
|
|
6
6
|
import type { CursorShape } from "./CursorShape";
|
|
7
7
|
import type { DiffTarget } from "./DiffTarget";
|
|
8
|
+
import type { Direction } from "./Direction";
|
|
8
9
|
import type { DriverKind } from "./DriverKind";
|
|
9
10
|
import type { ExtmarkId } from "./ExtmarkId";
|
|
10
11
|
import type { ExtmarkOpts } from "./ExtmarkOpts";
|
|
@@ -25,17 +26,20 @@ import type { NodeId } from "./NodeId";
|
|
|
25
26
|
import type { NoticeKind } from "./NoticeKind";
|
|
26
27
|
import type { OptionSpec } from "./OptionSpec";
|
|
27
28
|
import type { OptionValue } from "./OptionValue";
|
|
29
|
+
import type { PaneId } from "./PaneId";
|
|
28
30
|
import type { PermissionMode } from "./PermissionMode";
|
|
29
31
|
import type { ProjectKey } from "./ProjectKey";
|
|
30
32
|
import type { ProviderEvent } from "./ProviderEvent";
|
|
31
33
|
import type { QuotaSnapshot } from "./QuotaSnapshot";
|
|
32
34
|
import type { Rect } from "./Rect";
|
|
35
|
+
import type { ScrollAmount } from "./ScrollAmount";
|
|
33
36
|
import type { SelectShape } from "./SelectShape";
|
|
34
37
|
import type { SessionId } from "./SessionId";
|
|
35
38
|
import type { StatusSegment } from "./StatusSegment";
|
|
36
39
|
import type { StreamId } from "./StreamId";
|
|
37
40
|
import type { SurfaceCell } from "./SurfaceCell";
|
|
38
41
|
import type { SurfaceId } from "./SurfaceId";
|
|
42
|
+
import type { TabId } from "./TabId";
|
|
39
43
|
import type { TextEdit } from "./TextEdit";
|
|
40
44
|
import type { ToolDef } from "./ToolDef";
|
|
41
45
|
import type { UsageResolution } from "./UsageResolution";
|
|
@@ -55,6 +59,7 @@ export type ApiCall =
|
|
|
55
59
|
*/
|
|
56
60
|
kind?: string | null;
|
|
57
61
|
}
|
|
62
|
+
| { "call": "buf_delete"; buf: BufferId }
|
|
58
63
|
| { "call": "buf_line_count"; buf: BufferId }
|
|
59
64
|
| {
|
|
60
65
|
"call": "buf_get_lines";
|
|
@@ -109,7 +114,40 @@ export type ApiCall =
|
|
|
109
114
|
| { "call": "win_set_cursor"; win: WindowId; row: number; col: number }
|
|
110
115
|
| { "call": "win_get_viewport"; win: WindowId }
|
|
111
116
|
| { "call": "win_scroll_to"; win: WindowId; top_line: number | null }
|
|
117
|
+
| { "call": "win_scroll"; win: WindowId; amount: ScrollAmount }
|
|
112
118
|
| { "call": "win_list" }
|
|
119
|
+
| {
|
|
120
|
+
"call": "pane_split";
|
|
121
|
+
pane: PaneId;
|
|
122
|
+
/**
|
|
123
|
+
* Which side of `pane` the new one takes. `Right` and `Down` put it after `pane` in the
|
|
124
|
+
* split; `Left` and `Up` put it before.
|
|
125
|
+
*/
|
|
126
|
+
dir: Direction;
|
|
127
|
+
}
|
|
128
|
+
| { "call": "pane_close"; pane: PaneId }
|
|
129
|
+
| { "call": "pane_focus"; pane: PaneId }
|
|
130
|
+
| { "call": "pane_focus_dir"; view?: ViewId | null; dir: Direction }
|
|
131
|
+
| { "call": "pane_resize"; pane: PaneId; dir: Direction; delta: number }
|
|
132
|
+
| { "call": "pane_swap"; pane: PaneId; with: PaneId }
|
|
133
|
+
| { "call": "pane_move_edge"; pane: PaneId; dir: Direction }
|
|
134
|
+
| { "call": "pane_equalize"; view?: ViewId | null }
|
|
135
|
+
| {
|
|
136
|
+
"call": "tab_new";
|
|
137
|
+
view?: ViewId | null;
|
|
138
|
+
title?: string | null;
|
|
139
|
+
/**
|
|
140
|
+
* Whether to go to it. A tab opened by a key is; a tab opened by an orchestrator putting
|
|
141
|
+
* work somewhere is not, for the same reason `SessionNew { activate: false }` exists.
|
|
142
|
+
*/
|
|
143
|
+
activate: boolean;
|
|
144
|
+
}
|
|
145
|
+
| { "call": "tab_close"; tab: TabId }
|
|
146
|
+
| { "call": "tab_select"; tab: TabId }
|
|
147
|
+
| { "call": "tab_step"; view?: ViewId | null; delta: number }
|
|
148
|
+
| { "call": "tab_move"; tab: TabId; to: number }
|
|
149
|
+
| { "call": "tab_rename"; tab: TabId; title: string | null }
|
|
150
|
+
| { "call": "tab_list"; view?: ViewId | null }
|
|
113
151
|
| {
|
|
114
152
|
"call": "win_motion";
|
|
115
153
|
win: WindowId;
|
|
@@ -370,6 +408,7 @@ export type ApiCall =
|
|
|
370
408
|
| { "call": "swarm_reconnect"; node: NodeId }
|
|
371
409
|
| { "call": "swarm_disconnect"; node: NodeId }
|
|
372
410
|
| { "call": "swarm_strangers" }
|
|
411
|
+
| { "call": "swarm_browse"; node: NodeId; prefix: string }
|
|
373
412
|
| { "call": "quota_list" }
|
|
374
413
|
| { "call": "quota_refresh"; instance?: InstanceId | null }
|
|
375
414
|
| { "call": "quota_report"; snapshot: QuotaSnapshot }
|
|
@@ -441,12 +480,37 @@ export type ApiCall =
|
|
|
441
480
|
| { "call": "git_stage"; paths: Array<string> }
|
|
442
481
|
| { "call": "git_unstage"; paths: Array<string> }
|
|
443
482
|
| { "call": "git_commit"; message: string }
|
|
483
|
+
| {
|
|
484
|
+
"call": "git_fetch";
|
|
485
|
+
/**
|
|
486
|
+
* The repository to fetch in. The conversation's own when absent.
|
|
487
|
+
*/
|
|
488
|
+
cwd?: string | null;
|
|
489
|
+
}
|
|
444
490
|
| {
|
|
445
491
|
"call": "git_pull";
|
|
446
492
|
/**
|
|
447
493
|
* The repository to pull in. The conversation's own when absent.
|
|
448
494
|
*/
|
|
449
495
|
cwd?: string | null;
|
|
496
|
+
/**
|
|
497
|
+
* Replay this branch's own commits on top of what arrived, rather than merging.
|
|
498
|
+
*
|
|
499
|
+
* A flag rather than a call of its own because it is one argument to one command, and the
|
|
500
|
+
* caller that needs it is the one that has just been told the branch diverged — at which
|
|
501
|
+
* point "rebase or merge" is the question being answered, and two entry points for the two
|
|
502
|
+
* answers would be two things to keep in step for no gain.
|
|
503
|
+
*
|
|
504
|
+
* It rewrites local commits, which is why nothing sets it without asking first.
|
|
505
|
+
*/
|
|
506
|
+
rebase: boolean;
|
|
507
|
+
}
|
|
508
|
+
| {
|
|
509
|
+
"call": "forge_pulls";
|
|
510
|
+
/**
|
|
511
|
+
* The repository to ask about. The conversation's own when absent.
|
|
512
|
+
*/
|
|
513
|
+
cwd?: string | null;
|
|
450
514
|
}
|
|
451
515
|
| {
|
|
452
516
|
"call": "git_add_worktree";
|
|
@@ -470,6 +534,32 @@ export type ApiCall =
|
|
|
470
534
|
*/
|
|
471
535
|
cwd?: string | null;
|
|
472
536
|
}
|
|
537
|
+
| {
|
|
538
|
+
"call": "git_clone";
|
|
539
|
+
/**
|
|
540
|
+
* Anything `git clone` takes: an `https://` or `git@` URL, or a local path.
|
|
541
|
+
*/
|
|
542
|
+
url: string;
|
|
543
|
+
/**
|
|
544
|
+
* Where the working tree lands, in full. The caller resolved the root and the name, so
|
|
545
|
+
* that a picker can *show* the destination on the row before anything is written.
|
|
546
|
+
*/
|
|
547
|
+
path: string;
|
|
548
|
+
}
|
|
549
|
+
| {
|
|
550
|
+
"call": "git_move_worktree";
|
|
551
|
+
path: string;
|
|
552
|
+
/**
|
|
553
|
+
* Where it lands, in full. The leaf must not exist; the parent is created.
|
|
554
|
+
*/
|
|
555
|
+
dest: string;
|
|
556
|
+
/**
|
|
557
|
+
* The repository it belongs to. `git worktree move` runs from a checkout, and the
|
|
558
|
+
* conversation the caller is in may be standing in the one being moved — the same reason
|
|
559
|
+
* [`Self::GitRemoveWorktree`] takes one.
|
|
560
|
+
*/
|
|
561
|
+
cwd?: string | null;
|
|
562
|
+
}
|
|
473
563
|
| {
|
|
474
564
|
"call": "gen_complete";
|
|
475
565
|
prompt: string;
|
|
@@ -478,6 +568,30 @@ export type ApiCall =
|
|
|
478
568
|
* Ask for JSON and parse it host-side, tolerating the code fences models wrap it in.
|
|
479
569
|
*/
|
|
480
570
|
json: boolean;
|
|
571
|
+
/**
|
|
572
|
+
* The one key the answer is *about*, when the whole answer is one value.
|
|
573
|
+
*
|
|
574
|
+
* A prompt that says "return `{"branch": …}`" is answered with the object most of the
|
|
575
|
+
* time and with a bare `fix/composer-paste` the rest of it — the model did the work and
|
|
576
|
+
* skipped the envelope, and a caller that only accepts the envelope throws a correct
|
|
577
|
+
* answer away. Measured on this workspace's own history it was two runs in twenty-two:
|
|
578
|
+
* twice a branch was never named, silently, and both times the name was sitting in the
|
|
579
|
+
* reply.
|
|
580
|
+
*
|
|
581
|
+
* So: extraction first, exactly as before, and this is what a *bare* answer means. Named
|
|
582
|
+
* rather than inferred, because only the caller knows which key one value belongs under
|
|
583
|
+
* — and absent, nothing changes, which is what every existing caller wants.
|
|
584
|
+
*
|
|
585
|
+
* Only for a one-value answer. A commit message is a subject *and* a body, and guessing
|
|
586
|
+
* which half a bare paragraph is would be inventing the other one.
|
|
587
|
+
*
|
|
588
|
+
* And only for a value a *wrong* answer is recognisable in. A branch name is checkable
|
|
589
|
+
* and one `git branch -m` from being fixed; a thread title is any short line, which is
|
|
590
|
+
* also what a refusal and a driver's own error message look like — there the envelope is
|
|
591
|
+
* the only evidence the question was answered rather than commented on, and it is worth
|
|
592
|
+
* the one reply in ten that arrives without it.
|
|
593
|
+
*/
|
|
594
|
+
field?: string | null;
|
|
481
595
|
/**
|
|
482
596
|
* Defaults to `gen.model` if set, else the session's own selection.
|
|
483
597
|
*/
|
package/src/generated/ApiOk.ts
CHANGED
|
@@ -20,10 +20,12 @@ import type { ModelSelection } from "./ModelSelection";
|
|
|
20
20
|
import type { NamespaceId } from "./NamespaceId";
|
|
21
21
|
import type { NodeInfo } from "./NodeInfo";
|
|
22
22
|
import type { OptionEntry } from "./OptionEntry";
|
|
23
|
+
import type { PaneId } from "./PaneId";
|
|
23
24
|
import type { PermissionDecision } from "./PermissionDecision";
|
|
24
25
|
import type { PermissionMode } from "./PermissionMode";
|
|
25
26
|
import type { PluginInfo } from "./PluginInfo";
|
|
26
27
|
import type { PointInfo } from "./PointInfo";
|
|
28
|
+
import type { PullRequest } from "./PullRequest";
|
|
27
29
|
import type { QuestionAnswer } from "./QuestionAnswer";
|
|
28
30
|
import type { QuotaSample } from "./QuotaSample";
|
|
29
31
|
import type { QuotaSnapshot } from "./QuotaSnapshot";
|
|
@@ -34,6 +36,8 @@ import type { SurfaceId } from "./SurfaceId";
|
|
|
34
36
|
import type { SwarmAgent } from "./SwarmAgent";
|
|
35
37
|
import type { SwarmNode } from "./SwarmNode";
|
|
36
38
|
import type { SwarmStranger } from "./SwarmStranger";
|
|
39
|
+
import type { TabId } from "./TabId";
|
|
40
|
+
import type { TabInfo } from "./TabInfo";
|
|
37
41
|
import type { ToolDef } from "./ToolDef";
|
|
38
42
|
import type { UpdateOutcome } from "./UpdateOutcome";
|
|
39
43
|
import type { UpdateStatus } from "./UpdateStatus";
|
|
@@ -56,6 +60,9 @@ export type ApiOk =
|
|
|
56
60
|
| { "ok": "views"; views: Array<ViewInfo> }
|
|
57
61
|
| { "ok": "ns"; ns: NamespaceId }
|
|
58
62
|
| { "ok": "mark"; id: ExtmarkId }
|
|
63
|
+
| { "ok": "pane"; pane: PaneId | null }
|
|
64
|
+
| { "ok": "tab"; tab: TabId }
|
|
65
|
+
| { "ok": "tabs"; tabs: Array<TabInfo>; active: TabId }
|
|
59
66
|
| { "ok": "surface"; surface: SurfaceId }
|
|
60
67
|
| { "ok": "lines"; lines: Array<string> }
|
|
61
68
|
| { "ok": "count"; n: number }
|
|
@@ -76,7 +83,7 @@ export type ApiOk =
|
|
|
76
83
|
| { "ok": "focused_win"; win: WindowId | null }
|
|
77
84
|
| { "ok": "option"; entry: OptionEntry | null }
|
|
78
85
|
| { "ok": "options"; options: Array<OptionEntry> }
|
|
79
|
-
| { "ok": "paths"; paths: Array<string
|
|
86
|
+
| { "ok": "paths"; paths: Array<string>; denied?: string | null }
|
|
80
87
|
| { "ok": "viewport"; viewport: Viewport | null }
|
|
81
88
|
| { "ok": "sessions"; sessions: Array<SessionInfo> }
|
|
82
89
|
| { "ok": "credentials"; credentials: Array<CredentialInfo> }
|
|
@@ -86,6 +93,7 @@ export type ApiOk =
|
|
|
86
93
|
| { "ok": "status"; status: RepoStatus }
|
|
87
94
|
| { "ok": "branches"; branches: Array<BranchInfo> }
|
|
88
95
|
| { "ok": "worktrees"; worktrees: Array<WorktreeInfo> }
|
|
96
|
+
| { "ok": "pulls"; pulls: Array<PullRequest> }
|
|
89
97
|
| { "ok": "commits"; commits: Array<CommitInfo> }
|
|
90
98
|
| { "ok": "commit"; commit: CommitInfo }
|
|
91
99
|
| { "ok": "text"; text: string }
|
|
@@ -107,6 +115,7 @@ export type ApiOk =
|
|
|
107
115
|
| { "ok": "swarm_nodes"; nodes: Array<SwarmNode> }
|
|
108
116
|
| { "ok": "swarm_agents"; agents: Array<SwarmAgent> }
|
|
109
117
|
| { "ok": "swarm_strangers"; strangers: Array<SwarmStranger> }
|
|
118
|
+
| { "ok": "swarm_commanded"; session?: SessionId | null }
|
|
110
119
|
| { "ok": "quotas"; quotas: Array<QuotaSnapshot> }
|
|
111
120
|
| { "ok": "quota_history"; samples: Array<QuotaSample> }
|
|
112
121
|
| { "ok": "usage_history"; history: UsageHistory }
|
|
@@ -70,4 +70,6 @@ export type AscpMessage =
|
|
|
70
70
|
session?: SessionId | null;
|
|
71
71
|
}
|
|
72
72
|
| { "type": "refused"; id: string; refusal: Refusal }
|
|
73
|
+
| { "type": "browse"; id: string; prefix: string }
|
|
74
|
+
| { "type": "browsed"; id: string; paths: Array<string> }
|
|
73
75
|
| { "type": "goodbye"; message?: string | null };
|
package/src/generated/AuthRef.ts
CHANGED
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
export type AuthRef =
|
|
10
10
|
| { "kind": "env"; var: string }
|
|
11
11
|
| { "kind": "command"; argv: Array<string> }
|
|
12
|
-
| {
|
|
12
|
+
| {
|
|
13
|
+
"kind": "cli";
|
|
14
|
+
program: string;
|
|
15
|
+
login?: string | null;
|
|
16
|
+
retired?: string | null;
|
|
17
|
+
}
|
|
13
18
|
| { "kind": "inherited" }
|
|
14
19
|
| { "kind": "none" };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What the forge's checks say, folded to the one thing a row has room for.
|
|
5
|
+
*
|
|
6
|
+
* Folded here rather than on the wire as a list, because the question a project row answers is
|
|
7
|
+
* "is anything wrong" and the answer is one glyph. The counts travel beside it for whoever wants
|
|
8
|
+
* to say `✗2`; the full list of check names is a panel's job and a different call.
|
|
9
|
+
*
|
|
10
|
+
* `Pending` and `None` are deliberately different. Nothing has run yet is a state that resolves on
|
|
11
|
+
* its own in a few minutes; there are no checks configured at all is permanent, and drawing a
|
|
12
|
+
* spinner over it for ever is the failure this distinction avoids.
|
|
13
|
+
*/
|
|
14
|
+
export type ChecksState = "none" | "pending" | "passing" | "failing";
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
export type CredentialSource =
|
|
10
10
|
| { "kind": "plan"; via: string }
|
|
11
11
|
| { "kind": "plan_missing"; program: string; hint?: string | null }
|
|
12
|
+
| { "kind": "plan_retired"; program: string; note: string }
|
|
12
13
|
| { "kind": "env"; var: string }
|
|
13
14
|
| { "kind": "keychain" }
|
|
14
15
|
| { "kind": "session" }
|
package/src/generated/Dock.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Which edge of a rectangle a non-floating window sits against.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* The rectangle is the screen, or — when the window names a [`PaneId`] — one pane of the main
|
|
7
|
+
* region. That is the only difference between the two, and it is what let splitting arrive without
|
|
8
|
+
* a second geometry vocabulary: a composer docked `Bottom` in a pane is the same call as a
|
|
9
|
+
* composer docked `Bottom` on the screen, asked about a smaller rectangle.
|
|
10
|
+
*
|
|
11
|
+
* Still not an arbitrary split tree *here*: a window says which edge of which rectangle it wants,
|
|
12
|
+
* and the tree that makes those rectangles is [`PaneNode`], one level up. Keeping the two apart is
|
|
13
|
+
* what stops every plugin from having to reason about nesting to place a status line.
|
|
8
14
|
*/
|
|
9
|
-
export type Dock = "left" | "right" | "bottom" | "main";
|
|
15
|
+
export type Dock = "left" | "right" | "top" | "bottom" | "main";
|
|
@@ -23,6 +23,17 @@ export type FloatConfig = {
|
|
|
23
23
|
*/
|
|
24
24
|
border_hl?: string | null;
|
|
25
25
|
title?: string | null;
|
|
26
|
+
/**
|
|
27
|
+
* A strip on the bottom border: what the keys here do.
|
|
28
|
+
*
|
|
29
|
+
* On the border rather than in the buffer, because a key strip written as a row of content is
|
|
30
|
+
* one that scrolls away exactly when it is wanted, and is the first thing clipped on a terminal
|
|
31
|
+
* too short for the panel. Both of those happened: the picker's strip is the row that says how
|
|
32
|
+
* to get out, and on a sixteen-row screen it was the row that did not fit.
|
|
33
|
+
*
|
|
34
|
+
* Clipped to the border's width like the title, so it is for a legend and not for prose.
|
|
35
|
+
*/
|
|
36
|
+
footer?: string | null;
|
|
26
37
|
/**
|
|
27
38
|
* Close automatically when focus moves elsewhere. The right default for pickers and hovers.
|
|
28
39
|
*/
|
|
@@ -60,4 +71,26 @@ export type FloatConfig = {
|
|
|
60
71
|
* characters through to the composer would be typing into a field you cannot see.
|
|
61
72
|
*/
|
|
62
73
|
modal: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* This panel is a place you can move in when it does not fit.
|
|
76
|
+
*
|
|
77
|
+
* A float asks for a height and the frontend gives it what there is — so on a short terminal
|
|
78
|
+
* every row past the bottom edge is content that exists, is drawn nowhere, and has no key
|
|
79
|
+
* pointed at it. `height: Max { n: 30 }` on a twenty-row screen is not thirty rows of panel, it
|
|
80
|
+
* is ten rows of panel and twenty rows nobody can reach.
|
|
81
|
+
*
|
|
82
|
+
* Setting this adds one scope to the keymap chain while this float has focus —
|
|
83
|
+
* `BufKind { name: "neosh.scroll" }` — which is where the workspace binds the reader's motions:
|
|
84
|
+
* `j`/`k`, `<C-d>`/`<C-u>`, `<C-f>`/`<C-b>`, `gg`/`G`, the arrows and the paging keys. A scope
|
|
85
|
+
* rather than a capture, so all three of the usual rules hold: `^Z` lists the keys, `init.ts`
|
|
86
|
+
* moves them, and a panel that wants `j` for something of its own binds it on *its* kind, which
|
|
87
|
+
* is nearer and wins. It sits below the panel's own kind and above `Global`, so it is a default
|
|
88
|
+
* that never takes a key away from the thing it is scrolling.
|
|
89
|
+
*
|
|
90
|
+
* Off by default, and not for want of ambition: a picker whose filter takes printable
|
|
91
|
+
* characters through a capture would have `j` and `G` resolved out from under it by a scope, so
|
|
92
|
+
* typing a model's name would scroll instead of filtering. A panel that already moves in itself
|
|
93
|
+
* says so by staying quiet here.
|
|
94
|
+
*/
|
|
95
|
+
scroll: boolean;
|
|
63
96
|
};
|
|
@@ -27,4 +27,20 @@ export type ModelInfo = {
|
|
|
27
27
|
* numbers are already columns.
|
|
28
28
|
*/
|
|
29
29
|
tagline?: string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Why this one cannot be chosen here, in a sentence, or nothing when it can.
|
|
32
|
+
*
|
|
33
|
+
* A model a driver lists but will not run — the vendor CLI on this machine is too old for it,
|
|
34
|
+
* most often. Said rather than filtered out, for the reason a missing provider is listed
|
|
35
|
+
* rather than dropped: nothing there and not allowed are the same empty list, and only one of
|
|
36
|
+
* them is fixed by doing something. A model that silently vanishes from the picker is a
|
|
37
|
+
* question with nowhere to ask it — you go looking for the release notes, or for our bug
|
|
38
|
+
* tracker, and the answer was one `claude update` away the whole time.
|
|
39
|
+
*
|
|
40
|
+
* The sentence carries the fix, not just the diagnosis: "needs claude 2.1.251 — run `claude
|
|
41
|
+
* update`" is actionable and "unsupported model" is not. Anything reading a catalogue to
|
|
42
|
+
* *choose* — the startup default, `model.upgrade`, `model.line` — skips these; only a picker
|
|
43
|
+
* draws them, and draws them disabled.
|
|
44
|
+
*/
|
|
45
|
+
unavailable?: string | null;
|
|
30
46
|
};
|
|
@@ -23,6 +23,17 @@ export type NodeCapabilities = {
|
|
|
23
23
|
* Whether [`AscpMessage::Subscribe`] will produce anything.
|
|
24
24
|
*/
|
|
25
25
|
streams: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Whether [`AscpMessage::Browse`] will be answered.
|
|
28
|
+
*
|
|
29
|
+
* Not a permission — it follows `accepts_commands`, for the reason written on `Browse` — but a
|
|
30
|
+
* *compatibility* flag, and that is why it is here rather than derived. A node built before
|
|
31
|
+
* `Browse` existed cannot skip a message it has never heard of: the frame parses or the
|
|
32
|
+
* connection fails, so a new node that sent one on spec would drop an old peer's link every
|
|
33
|
+
* time somebody opened a directory picker. It defaults to `false`, which is exactly what an
|
|
34
|
+
* older node's handshake decodes to, so "does not say" and "cannot" are the same answer.
|
|
35
|
+
*/
|
|
36
|
+
browse: boolean;
|
|
26
37
|
/**
|
|
27
38
|
* The checkouts this node has, for starting something on it.
|
|
28
39
|
*/
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
|
2
|
+
import type { PaneNode } from "./PaneNode";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* One child of a split, and how much of the axis it gets.
|
|
6
|
+
*/
|
|
7
|
+
export type PaneChild = {
|
|
8
|
+
node: PaneNode;
|
|
9
|
+
/**
|
|
10
|
+
* Share of the parent's axis, relative to its siblings.
|
|
11
|
+
*
|
|
12
|
+
* A weight rather than cells, because the terminal is resized by somebody dragging its corner
|
|
13
|
+
* and a layout stored in cells has to be recomputed — badly, and with rounding that
|
|
14
|
+
* accumulates — every time that happens. Weights survive a resize by meaning the same thing at
|
|
15
|
+
* every size. [`WEIGHT`] is what an even split is made of.
|
|
16
|
+
*/
|
|
17
|
+
weight: number;
|
|
18
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* One rectangle of the main region, and everything docked inside it.
|
|
5
|
+
*
|
|
6
|
+
* A pane is *where* rather than *what*: it owns no buffer and draws nothing. A chat pane is a
|
|
7
|
+
* transcript window docked `Main` in it plus a composer docked `Bottom` in it; a pane showing
|
|
8
|
+
* one thing is one window docked `Main`. That is the whole of why splitting did not need a
|
|
9
|
+
* second dock vocabulary — [`Dock`](crate::Dock) already answers "where inside this rectangle",
|
|
10
|
+
* and a pane is just a smaller rectangle to ask it about.
|
|
11
|
+
*
|
|
12
|
+
* Panes live in a tree per tab ([`PaneNode`](crate::PaneNode)). The tree says how the main
|
|
13
|
+
* region is divided; the frontend turns it into rectangles, exactly as it does for docks.
|
|
14
|
+
*/
|
|
15
|
+
export type PaneId = number;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
|
2
|
+
import type { PaneChild } from "./PaneChild";
|
|
3
|
+
import type { PaneId } from "./PaneId";
|
|
4
|
+
import type { SplitDir } from "./SplitDir";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* How the main region of one tab is divided.
|
|
8
|
+
*
|
|
9
|
+
* A tree rather than a list because a split of a split is the thing people actually build — a chat
|
|
10
|
+
* on the left, and on the right a chat above a terminal — and a flat list of rectangles cannot say
|
|
11
|
+
* that without every consumer re-deriving the nesting from coordinates.
|
|
12
|
+
*/
|
|
13
|
+
export type PaneNode = { "kind": "leaf"; pane: PaneId } | {
|
|
14
|
+
"kind": "split";
|
|
15
|
+
dir: SplitDir;
|
|
16
|
+
children: Array<PaneChild>;
|
|
17
|
+
};
|
|
@@ -63,6 +63,7 @@ export type PluginEvent =
|
|
|
63
63
|
| { "type": "composer_changed"; text: string }
|
|
64
64
|
| { "type": "event"; name: string; data?: unknown; from: string }
|
|
65
65
|
| { "type": "var_changed"; scope: VarScope; key: string; value?: unknown }
|
|
66
|
+
| { "type": "project_moved"; from: string; to: string }
|
|
66
67
|
| { "type": "highlight_changed"; names: Array<string> }
|
|
67
68
|
| { "type": "contributions_changed"; point: string }
|
|
68
69
|
| { "type": "swarm_changed" }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
|
2
|
+
import type { ChecksState } from "./ChecksState";
|
|
3
|
+
import type { PullState } from "./PullState";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* One pull request, as much of it as a row can use.
|
|
7
|
+
*
|
|
8
|
+
* **Keyed by `branch`**, which is what makes one call answer for every worktree at once: a
|
|
9
|
+
* repository's pull requests come back together and each checkout finds its own by the branch it
|
|
10
|
+
* has out. Asking per branch would be one network round trip per row in the panel.
|
|
11
|
+
*/
|
|
12
|
+
export type PullRequest = {
|
|
13
|
+
number: number;
|
|
14
|
+
title: string;
|
|
15
|
+
/**
|
|
16
|
+
* For opening it. The forge's own URL, so nothing here has to know how to build one.
|
|
17
|
+
*/
|
|
18
|
+
url: string;
|
|
19
|
+
/**
|
|
20
|
+
* The head branch. What a checkout matches itself against.
|
|
21
|
+
*/
|
|
22
|
+
branch: string;
|
|
23
|
+
state: PullState;
|
|
24
|
+
checks: ChecksState;
|
|
25
|
+
/**
|
|
26
|
+
* How many checks have failed, for a row that wants to say `✗2` rather than `✗`.
|
|
27
|
+
*/
|
|
28
|
+
checks_failed: number;
|
|
29
|
+
checks_total: number;
|
|
30
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Where a pull request has got to.
|
|
5
|
+
*
|
|
6
|
+
* Four states because that is what a person means by "what happened to it": one is a review you
|
|
7
|
+
* are waiting for, one is a review you have not asked for yet, one is done, and one is not going
|
|
8
|
+
* to happen. Draft is its own state rather than a flag on `Open` because on a row it is the whole
|
|
9
|
+
* difference between "somebody should look at this" and "I am still writing it".
|
|
10
|
+
*/
|
|
11
|
+
export type PullState = "open" | "draft" | "merged" | "closed";
|
|
@@ -14,6 +14,24 @@ export type RemoteProject = {
|
|
|
14
14
|
cwd: string;
|
|
15
15
|
/**
|
|
16
16
|
* Whether this node has a conversation open in it now.
|
|
17
|
+
*
|
|
18
|
+
* Meant something for exactly as long as this list was derived from live conversations: every
|
|
19
|
+
* project on it had one, so every one of them said `true` and a board drawing the flag drew
|
|
20
|
+
* one colour. A node now advertises the places it *works in* — which is the list its own panel
|
|
21
|
+
* shows, and includes the project you cleared out this morning — so the two states exist and
|
|
22
|
+
* the flag is worth reading.
|
|
17
23
|
*/
|
|
18
24
|
active: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* How many conversations are open in it there.
|
|
27
|
+
*/
|
|
28
|
+
sessions: number;
|
|
29
|
+
/**
|
|
30
|
+
* How many of those are mid-turn.
|
|
31
|
+
*
|
|
32
|
+
* Separate from `sessions` because they are different questions and a board answers both in
|
|
33
|
+
* one row: `3 conversations · 1 working` is what the sidebar says about a local project, and a
|
|
34
|
+
* remote one should not have to say less.
|
|
35
|
+
*/
|
|
36
|
+
running: number;
|
|
19
37
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* How far to move a window's scroll. See [`crate::ApiCall::WinScroll`].
|
|
5
|
+
*
|
|
6
|
+
* Verbs rather than a row number, for the reason [`CursorMotion`] is: only the core knows how many
|
|
7
|
+
* buffer rows the frontend last drew, so "half a screen" is a question the caller cannot answer and
|
|
8
|
+
* a caller that tried would answer it with a height. Signed, so one variant covers both directions
|
|
9
|
+
* and a binding for `<C-d>` is the binding for `<C-u>` with the sign flipped.
|
|
10
|
+
*/
|
|
11
|
+
export type ScrollAmount =
|
|
12
|
+
| { "kind": "lines"; n: number }
|
|
13
|
+
| { "kind": "half"; n: number }
|
|
14
|
+
| { "kind": "page"; n: number }
|
|
15
|
+
| { "kind": "top" }
|
|
16
|
+
| { "kind": "bottom" };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Which way a split lays its children out.
|
|
5
|
+
*
|
|
6
|
+
* Named for what it does to the screen rather than for the key that made it, because those two
|
|
7
|
+
* disagree in every editor that has ever shipped one: Vim's `:vsplit` produces panes side by side,
|
|
8
|
+
* and a `Vertical` that means "stacked" to the layout code and "side by side" to the user is a
|
|
9
|
+
* bug waiting for its first off-by-one. `Row` is a row of panes; `Column` is a column of them.
|
|
10
|
+
* The *commands* say `right` and `down`, which is the one description nobody can misread.
|
|
11
|
+
*/
|
|
12
|
+
export type SplitDir = "row" | "column";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* One tab of one view: a title, and a tree of panes.
|
|
5
|
+
*
|
|
6
|
+
* Per view rather than per workspace, for the same reason a window is: what the agent produced
|
|
7
|
+
* is the workspace's, and where you are looking is yours. Two terminals attached to one
|
|
8
|
+
* workspace have their own tabs over the same conversations.
|
|
9
|
+
*/
|
|
10
|
+
export type TabId = number;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
|
2
|
+
import type { PaneId } from "./PaneId";
|
|
3
|
+
import type { PaneNode } from "./PaneNode";
|
|
4
|
+
import type { TabId } from "./TabId";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* One tab of one view.
|
|
8
|
+
*/
|
|
9
|
+
export type TabInfo = {
|
|
10
|
+
id: TabId;
|
|
11
|
+
/**
|
|
12
|
+
* What the tab bar calls it.
|
|
13
|
+
*
|
|
14
|
+
* `None` is "name it after what is in it" — the conversation's title, the terminal's command —
|
|
15
|
+
* which is what a tab nobody has renamed should say, and it has to stay `None` to keep saying
|
|
16
|
+
* it: a title resolved once and stored is a tab still called `main` three conversations later.
|
|
17
|
+
*/
|
|
18
|
+
title?: string | null;
|
|
19
|
+
root: PaneNode;
|
|
20
|
+
/**
|
|
21
|
+
* Which pane in this tab has the keyboard when the tab does.
|
|
22
|
+
*
|
|
23
|
+
* Per tab rather than per view, so that leaving a tab and coming back puts you where you were
|
|
24
|
+
* rather than in whichever pane happens to be first.
|
|
25
|
+
*/
|
|
26
|
+
active_pane: PaneId;
|
|
27
|
+
};
|
package/src/generated/UiEvent.ts
CHANGED
|
@@ -8,6 +8,8 @@ import type { NoticeKind } from "./NoticeKind";
|
|
|
8
8
|
import type { Rect } from "./Rect";
|
|
9
9
|
import type { SurfaceCell } from "./SurfaceCell";
|
|
10
10
|
import type { SurfaceId } from "./SurfaceId";
|
|
11
|
+
import type { TabId } from "./TabId";
|
|
12
|
+
import type { TabInfo } from "./TabInfo";
|
|
11
13
|
import type { WindowId } from "./WindowId";
|
|
12
14
|
import type { WindowLayout } from "./WindowLayout";
|
|
13
15
|
|
|
@@ -45,7 +47,9 @@ export type UiEvent =
|
|
|
45
47
|
| { "type": "surface_claimed"; surface: SurfaceId; win: WindowId; rect: Rect }
|
|
46
48
|
| { "type": "surface_cells"; surface: SurfaceId; cells: Array<SurfaceCell> }
|
|
47
49
|
| { "type": "surface_released"; surface: SurfaceId }
|
|
50
|
+
| { "type": "panes_changed"; tabs: Array<TabInfo>; active: TabId }
|
|
48
51
|
| { "type": "focus_changed"; win: WindowId | null }
|
|
52
|
+
| { "type": "home_changed"; win: WindowId | null }
|
|
49
53
|
| {
|
|
50
54
|
"type": "message";
|
|
51
55
|
level: MessageLevel;
|