@neosh/api 0.4.0 → 0.4.2
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 +98 -0
- package/src/generated/ApiOk.ts +2 -0
- package/src/generated/ChecksState.ts +14 -0
- package/src/generated/FloatConfig.ts +33 -0
- package/src/generated/ModelInfo.ts +16 -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/ScrollAmount.ts +16 -0
- package/src/generated/TabInfo.ts +16 -0
- package/src/generated/UiEvent.ts +18 -1
- package/src/generated/UpdateStatus.ts +21 -1
- package/src/index.ts +314 -10
- package/src/ui.ts +276 -55
package/package.json
CHANGED
package/src/generated/ApiCall.ts
CHANGED
|
@@ -32,6 +32,7 @@ import type { ProjectKey } from "./ProjectKey";
|
|
|
32
32
|
import type { ProviderEvent } from "./ProviderEvent";
|
|
33
33
|
import type { QuotaSnapshot } from "./QuotaSnapshot";
|
|
34
34
|
import type { Rect } from "./Rect";
|
|
35
|
+
import type { ScrollAmount } from "./ScrollAmount";
|
|
35
36
|
import type { SelectShape } from "./SelectShape";
|
|
36
37
|
import type { SessionId } from "./SessionId";
|
|
37
38
|
import type { StatusSegment } from "./StatusSegment";
|
|
@@ -113,6 +114,7 @@ export type ApiCall =
|
|
|
113
114
|
| { "call": "win_set_cursor"; win: WindowId; row: number; col: number }
|
|
114
115
|
| { "call": "win_get_viewport"; win: WindowId }
|
|
115
116
|
| { "call": "win_scroll_to"; win: WindowId; top_line: number | null }
|
|
117
|
+
| { "call": "win_scroll"; win: WindowId; amount: ScrollAmount }
|
|
116
118
|
| { "call": "win_list" }
|
|
117
119
|
| {
|
|
118
120
|
"call": "pane_split";
|
|
@@ -139,7 +141,18 @@ export type ApiCall =
|
|
|
139
141
|
* work somewhere is not, for the same reason `SessionNew { activate: false }` exists.
|
|
140
142
|
*/
|
|
141
143
|
activate: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Which strip to open it on. See [`TabInfo::group`].
|
|
146
|
+
*
|
|
147
|
+
* `None` inherits the tab you are on, which is what a new tab almost always wants: opened
|
|
148
|
+
* while reading a conversation, it is that conversation's. Saying one is for a caller
|
|
149
|
+
* putting a tab somewhere *else* — and a group nothing is currently showing is a tab that
|
|
150
|
+
* is made and is off the bar, which is a legitimate thing to want and a surprising thing
|
|
151
|
+
* to do by accident.
|
|
152
|
+
*/
|
|
153
|
+
group?: string | null;
|
|
142
154
|
}
|
|
155
|
+
| { "call": "tab_group"; tab: TabId; group: string | null }
|
|
143
156
|
| { "call": "tab_close"; tab: TabId }
|
|
144
157
|
| { "call": "tab_select"; tab: TabId }
|
|
145
158
|
| { "call": "tab_step"; view?: ViewId | null; delta: number }
|
|
@@ -478,12 +491,37 @@ export type ApiCall =
|
|
|
478
491
|
| { "call": "git_stage"; paths: Array<string> }
|
|
479
492
|
| { "call": "git_unstage"; paths: Array<string> }
|
|
480
493
|
| { "call": "git_commit"; message: string }
|
|
494
|
+
| {
|
|
495
|
+
"call": "git_fetch";
|
|
496
|
+
/**
|
|
497
|
+
* The repository to fetch in. The conversation's own when absent.
|
|
498
|
+
*/
|
|
499
|
+
cwd?: string | null;
|
|
500
|
+
}
|
|
481
501
|
| {
|
|
482
502
|
"call": "git_pull";
|
|
483
503
|
/**
|
|
484
504
|
* The repository to pull in. The conversation's own when absent.
|
|
485
505
|
*/
|
|
486
506
|
cwd?: string | null;
|
|
507
|
+
/**
|
|
508
|
+
* Replay this branch's own commits on top of what arrived, rather than merging.
|
|
509
|
+
*
|
|
510
|
+
* A flag rather than a call of its own because it is one argument to one command, and the
|
|
511
|
+
* caller that needs it is the one that has just been told the branch diverged — at which
|
|
512
|
+
* point "rebase or merge" is the question being answered, and two entry points for the two
|
|
513
|
+
* answers would be two things to keep in step for no gain.
|
|
514
|
+
*
|
|
515
|
+
* It rewrites local commits, which is why nothing sets it without asking first.
|
|
516
|
+
*/
|
|
517
|
+
rebase: boolean;
|
|
518
|
+
}
|
|
519
|
+
| {
|
|
520
|
+
"call": "forge_pulls";
|
|
521
|
+
/**
|
|
522
|
+
* The repository to ask about. The conversation's own when absent.
|
|
523
|
+
*/
|
|
524
|
+
cwd?: string | null;
|
|
487
525
|
}
|
|
488
526
|
| {
|
|
489
527
|
"call": "git_add_worktree";
|
|
@@ -507,6 +545,32 @@ export type ApiCall =
|
|
|
507
545
|
*/
|
|
508
546
|
cwd?: string | null;
|
|
509
547
|
}
|
|
548
|
+
| {
|
|
549
|
+
"call": "git_clone";
|
|
550
|
+
/**
|
|
551
|
+
* Anything `git clone` takes: an `https://` or `git@` URL, or a local path.
|
|
552
|
+
*/
|
|
553
|
+
url: string;
|
|
554
|
+
/**
|
|
555
|
+
* Where the working tree lands, in full. The caller resolved the root and the name, so
|
|
556
|
+
* that a picker can *show* the destination on the row before anything is written.
|
|
557
|
+
*/
|
|
558
|
+
path: string;
|
|
559
|
+
}
|
|
560
|
+
| {
|
|
561
|
+
"call": "git_move_worktree";
|
|
562
|
+
path: string;
|
|
563
|
+
/**
|
|
564
|
+
* Where it lands, in full. The leaf must not exist; the parent is created.
|
|
565
|
+
*/
|
|
566
|
+
dest: string;
|
|
567
|
+
/**
|
|
568
|
+
* The repository it belongs to. `git worktree move` runs from a checkout, and the
|
|
569
|
+
* conversation the caller is in may be standing in the one being moved — the same reason
|
|
570
|
+
* [`Self::GitRemoveWorktree`] takes one.
|
|
571
|
+
*/
|
|
572
|
+
cwd?: string | null;
|
|
573
|
+
}
|
|
510
574
|
| {
|
|
511
575
|
"call": "gen_complete";
|
|
512
576
|
prompt: string;
|
|
@@ -515,6 +579,30 @@ export type ApiCall =
|
|
|
515
579
|
* Ask for JSON and parse it host-side, tolerating the code fences models wrap it in.
|
|
516
580
|
*/
|
|
517
581
|
json: boolean;
|
|
582
|
+
/**
|
|
583
|
+
* The one key the answer is *about*, when the whole answer is one value.
|
|
584
|
+
*
|
|
585
|
+
* A prompt that says "return `{"branch": …}`" is answered with the object most of the
|
|
586
|
+
* time and with a bare `fix/composer-paste` the rest of it — the model did the work and
|
|
587
|
+
* skipped the envelope, and a caller that only accepts the envelope throws a correct
|
|
588
|
+
* answer away. Measured on this workspace's own history it was two runs in twenty-two:
|
|
589
|
+
* twice a branch was never named, silently, and both times the name was sitting in the
|
|
590
|
+
* reply.
|
|
591
|
+
*
|
|
592
|
+
* So: extraction first, exactly as before, and this is what a *bare* answer means. Named
|
|
593
|
+
* rather than inferred, because only the caller knows which key one value belongs under
|
|
594
|
+
* — and absent, nothing changes, which is what every existing caller wants.
|
|
595
|
+
*
|
|
596
|
+
* Only for a one-value answer. A commit message is a subject *and* a body, and guessing
|
|
597
|
+
* which half a bare paragraph is would be inventing the other one.
|
|
598
|
+
*
|
|
599
|
+
* And only for a value a *wrong* answer is recognisable in. A branch name is checkable
|
|
600
|
+
* and one `git branch -m` from being fixed; a thread title is any short line, which is
|
|
601
|
+
* also what a refusal and a driver's own error message look like — there the envelope is
|
|
602
|
+
* the only evidence the question was answered rather than commented on, and it is worth
|
|
603
|
+
* the one reply in ten that arrives without it.
|
|
604
|
+
*/
|
|
605
|
+
field?: string | null;
|
|
518
606
|
/**
|
|
519
607
|
* Defaults to `gen.model` if set, else the session's own selection.
|
|
520
608
|
*/
|
|
@@ -562,6 +650,16 @@ export type ApiCall =
|
|
|
562
650
|
* Ask the network again rather than answering from the last check.
|
|
563
651
|
*/
|
|
564
652
|
force: boolean;
|
|
653
|
+
/**
|
|
654
|
+
* Answer from what this machine already knows, and never reach the network.
|
|
655
|
+
*
|
|
656
|
+
* The two are not opposites and are never both set: `local` is checked first and wins.
|
|
657
|
+
* It exists because half of an update status is not about a registry at all —
|
|
658
|
+
* [`UpdateStatus::restart_pending`] is a `stat` of one file — and a caller that wants
|
|
659
|
+
* only that half should not be the reason a workspace makes an HTTP request. Which is
|
|
660
|
+
* what a panel polling for "has something replaced my binary" would otherwise be.
|
|
661
|
+
*/
|
|
662
|
+
local: boolean;
|
|
565
663
|
}
|
|
566
664
|
| { "call": "update_apply" }
|
|
567
665
|
| {
|
package/src/generated/ApiOk.ts
CHANGED
|
@@ -25,6 +25,7 @@ import type { PermissionDecision } from "./PermissionDecision";
|
|
|
25
25
|
import type { PermissionMode } from "./PermissionMode";
|
|
26
26
|
import type { PluginInfo } from "./PluginInfo";
|
|
27
27
|
import type { PointInfo } from "./PointInfo";
|
|
28
|
+
import type { PullRequest } from "./PullRequest";
|
|
28
29
|
import type { QuestionAnswer } from "./QuestionAnswer";
|
|
29
30
|
import type { QuotaSample } from "./QuotaSample";
|
|
30
31
|
import type { QuotaSnapshot } from "./QuotaSnapshot";
|
|
@@ -92,6 +93,7 @@ export type ApiOk =
|
|
|
92
93
|
| { "ok": "status"; status: RepoStatus }
|
|
93
94
|
| { "ok": "branches"; branches: Array<BranchInfo> }
|
|
94
95
|
| { "ok": "worktrees"; worktrees: Array<WorktreeInfo> }
|
|
96
|
+
| { "ok": "pulls"; pulls: Array<PullRequest> }
|
|
95
97
|
| { "ok": "commits"; commits: Array<CommitInfo> }
|
|
96
98
|
| { "ok": "commit"; commit: CommitInfo }
|
|
97
99
|
| { "ok": "text"; text: string }
|
|
@@ -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";
|
|
@@ -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
|
};
|
|
@@ -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";
|
|
@@ -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" };
|
package/src/generated/TabInfo.ts
CHANGED
|
@@ -24,4 +24,20 @@ export type TabInfo = {
|
|
|
24
24
|
* rather than in whichever pane happens to be first.
|
|
25
25
|
*/
|
|
26
26
|
active_pane: PaneId;
|
|
27
|
+
/**
|
|
28
|
+
* Which strip this tab is on — the conversation it belongs to.
|
|
29
|
+
*
|
|
30
|
+
* **A tab belongs to a conversation, and the bar shows one conversation's tabs.** A shell
|
|
31
|
+
* opened while reading one is *that* conversation's shell: it was started in its directory,
|
|
32
|
+
* about its work, and a bar that goes on showing it after you have switched is a bar about
|
|
33
|
+
* the terminal rather than about what you are doing. The tabs of the conversations you are
|
|
34
|
+
* not in are not closed, and nothing in them stops — they are off the strip until you go
|
|
35
|
+
* back, which is what makes leaving a build running and returning to it work.
|
|
36
|
+
*
|
|
37
|
+
* Opaque here and in the editor, which only ever asks whether two of them are equal: the host
|
|
38
|
+
* fills it with a [`crate::SessionId`], and a plugin that grouped its tabs by project would be
|
|
39
|
+
* using it exactly as intended. `None` is a group of its own — where a tab nobody has filed
|
|
40
|
+
* sits, and what every tab was before this existed.
|
|
41
|
+
*/
|
|
42
|
+
group?: string | null;
|
|
27
43
|
};
|
package/src/generated/UiEvent.ts
CHANGED
|
@@ -81,4 +81,21 @@ export type UiEvent =
|
|
|
81
81
|
}
|
|
82
82
|
| { "type": "clipboard"; text: string }
|
|
83
83
|
| { "type": "flush" }
|
|
84
|
-
| {
|
|
84
|
+
| {
|
|
85
|
+
"type": "shutdown";
|
|
86
|
+
/**
|
|
87
|
+
* Whether it is coming straight back, and this terminal should follow it.
|
|
88
|
+
*
|
|
89
|
+
* `neosh stop` and a restart are the same shutdown — conversations flushed, plugins torn
|
|
90
|
+
* down — and they differ entirely in what the *terminal* should do next. Stopping is
|
|
91
|
+
* somebody finishing; a restart is the second half of an update, and a terminal that
|
|
92
|
+
* exits to the shell there has turned "finish updating" into "and now type `neosh`
|
|
93
|
+
* again", which is the step nobody knows is owed. It cannot be worked out at the far end
|
|
94
|
+
* either: from a closed socket, a workspace that stopped and a workspace that is
|
|
95
|
+
* restarting look identical.
|
|
96
|
+
*
|
|
97
|
+
* `#[serde(default)]` so an older terminal reads it as an ordinary stop, which is the
|
|
98
|
+
* behaviour it already has.
|
|
99
|
+
*/
|
|
100
|
+
restarting: boolean;
|
|
101
|
+
};
|
|
@@ -33,7 +33,27 @@ export type UpdateStatus = {
|
|
|
33
33
|
*/
|
|
34
34
|
error?: string | null;
|
|
35
35
|
/**
|
|
36
|
-
* Whether
|
|
36
|
+
* Whether the binary on disk is not the one this process is running.
|
|
37
|
+
*
|
|
38
|
+
* Not "whether neosh downloaded something": most installs are updated by somebody else's
|
|
39
|
+
* package manager, in another terminal, and the workspace goes on executing the inode it
|
|
40
|
+
* started with — which is the whole failure this field exists to name. `brew upgrade neosh`
|
|
41
|
+
* finishes, says so, and leaves a workspace running the old code with nothing on screen to
|
|
42
|
+
* say why the thing you just installed is not there. So this is a `stat` of the running
|
|
43
|
+
* executable against the stamp taken at startup, and it is true for a self-update, a
|
|
44
|
+
* `brew upgrade`, an `npm install -g` and a re-run of `install.sh` alike.
|
|
45
|
+
*
|
|
46
|
+
* Never set when there is no binary left to restart onto: a promise of a restart that cannot
|
|
47
|
+
* come back is worse than saying nothing.
|
|
37
48
|
*/
|
|
38
49
|
restart_pending: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* What is waiting on disk, when it could be read.
|
|
52
|
+
*
|
|
53
|
+
* Asked of the binary itself (`neosh --version`) rather than assumed to be
|
|
54
|
+
* [`latest`](UpdateStatus::latest): somebody who ran `brew upgrade` got whatever Homebrew had,
|
|
55
|
+
* which is not always the newest release, and a row naming the wrong number is a row that
|
|
56
|
+
* teaches you not to read it. `None` means *something* changed and it would not say what.
|
|
57
|
+
*/
|
|
58
|
+
restart_version?: string | null;
|
|
39
59
|
};
|